refactor(gui): copy-free settings shell; ui-settings-general owns ownerless copy
The shell is now a pure composition face: no dictionaries, no locale dependency, and three new chrome content seats (settings.trigger / settings.header / settings.close) whose slot content also carries the accessible names (trigger text, dialog aria-labelledby, visually hidden close label). ui-settings-general returns as the owner of copy that belongs to no single feature: chrome content, the General section with its item slot, and the settings dictionaries. Slot types split homes — trigger/header/close/section live in the shell contract; the settings.general.item entry moves to the locale package (the common dependency of every item registrant), with ui-theme consuming it through a re-export seam; the verbatim duplicate merges are gone and the dependency graph is a clean DAG.
This commit is contained in:
@@ -15,6 +15,7 @@ import { createLanguageRowStore } from './settings-store.ts'
|
||||
|
||||
export type { LanguageRowComponentProps, LanguageRowInjected } from './LanguageRow.tsx'
|
||||
export type { LanguageOptionRow, LanguageRowState } from './settings-store.ts'
|
||||
export type { SettingsGeneralItemOwnerProps } from './settings-contract.ts'
|
||||
|
||||
/** Translate a key with optional params. */
|
||||
export type Translate = (key: string, params?: Record<string, unknown>) => string
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
/**
|
||||
* Settings-surface slot merge consumed by this package's Language row. The
|
||||
* AUTHORITATIVE home for 'settings.general.item' is the ui-settings contract
|
||||
* (declaring is claiming: the shell's General entry declares the slot); this
|
||||
* file repeats the entry verbatim because the shell consumes ctx.locale
|
||||
* (project reference ui-settings -> locale), so importing the shell's types
|
||||
* from here would close a reference cycle. TypeScript declaration merging
|
||||
* rejects diverging duplicates, so every program that sees both copies (the
|
||||
* shell's own build, the client aggregate) enforces identity.
|
||||
* The `settings.general.item` slot type — one preference row inside the
|
||||
* settings General section, contributed by the feature plugin that owns the
|
||||
* preference (locale → Language, ui-theme → Appearance). Options: `id` (row
|
||||
* key), `order` (row position). Rows draw their own internals (row layout,
|
||||
* separators via CSS); the section column only stacks them.
|
||||
*
|
||||
* TYPE HOME RATIONALE: the slot is declared at runtime by
|
||||
* ui-settings-general's General entry, but its type lives here — this
|
||||
* package is the common dependency of every item registrant (any settings
|
||||
* row carries copy, so every registrant already depends on locale), whereas
|
||||
* the declarer's own contract is unreachable for locale/ui-theme without a
|
||||
* reference cycle.
|
||||
*/
|
||||
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
||||
interface SlotMap {
|
||||
/** One preference row inside the General section (duplicate-identical merge; authority: ui-settings contract). */
|
||||
'settings.general.item': { kind: 'list'; scope: 'root'; owner: { children?: never } }
|
||||
/** One preference row inside the settings General section (see module JSDoc). */
|
||||
'settings.general.item': { kind: 'list'; scope: 'root'; owner: SettingsGeneralItemOwnerProps }
|
||||
}
|
||||
}
|
||||
|
||||
export {}
|
||||
/** Owner share of a General preference row (the section supplies nothing). */
|
||||
export interface SettingsGeneralItemOwnerProps {
|
||||
/** Marker field: item owner props are intentionally empty. */
|
||||
children?: never
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user