@prettier-ai/dsh-client-ui-theme 0.1.2-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.i18n.yaml +6 -0
- package/README.md +110 -0
- package/README.zh.md +110 -0
- package/lib/client.js +1523 -0
- package/lib/index.js +97 -0
- package/lib/invariant.js +25 -0
- package/lib/types/boot-theme.d.ts +17 -0
- package/lib/types/client/AppearanceRow.d.ts +17 -0
- package/lib/types/client/FontSizeRow.d.ts +16 -0
- package/lib/types/client/index.d.ts +202 -0
- package/lib/types/client/locales.d.ts +28 -0
- package/lib/types/client/settings-store.d.ts +41 -0
- package/lib/types/client/styles.d.ts +7 -0
- package/lib/types/index.d.ts +11 -0
- package/lib/types/invariant.d.ts +16 -0
- package/lib/types/theme-settings.d.ts +36 -0
- package/package.json +89 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { settingsNamespace } from "@prettier-ai/dsh-settings";
|
|
2
|
+
import z from "@prettier-ai/schemastery";
|
|
3
|
+
//#region lib/types/theme-settings.js
|
|
4
|
+
/** Theme preferences stored in the Host user-settings document. */
|
|
5
|
+
/** Built-in preferences accepted at the registry and settings boundaries. */
|
|
6
|
+
const THEME_PREFERENCES = [
|
|
7
|
+
"light",
|
|
8
|
+
"dark",
|
|
9
|
+
"system"
|
|
10
|
+
];
|
|
11
|
+
/** Settings namespace owned by the theme plugin. */
|
|
12
|
+
const THEME_SETTINGS_NAMESPACE = "ui-theme";
|
|
13
|
+
/** Field carrying the selected built-in theme preference. */
|
|
14
|
+
const THEME_PREFERENCE_FIELD = "preference";
|
|
15
|
+
/** Field carrying the conversation content font size. */
|
|
16
|
+
const FONT_SIZE_FIELD = "fontSize";
|
|
17
|
+
/** Default preference when the user-settings document has no override. */
|
|
18
|
+
const DEFAULT_PREFERENCE = "system";
|
|
19
|
+
/** Smallest accepted content font size (px). */
|
|
20
|
+
const FONT_SIZE_MIN = 12;
|
|
21
|
+
/** Largest accepted content font size (px). */
|
|
22
|
+
const FONT_SIZE_MAX = 17;
|
|
23
|
+
/** Content font size when the user-settings document has no override (px). */
|
|
24
|
+
const DEFAULT_FONT_SIZE = 14;
|
|
25
|
+
/** Durable theme schema; also the wire envelope the browser scope validates against. */
|
|
26
|
+
const ThemeSettingsSchema = z.object({
|
|
27
|
+
[THEME_PREFERENCE_FIELD]: z.union([...THEME_PREFERENCES]).default(DEFAULT_PREFERENCE),
|
|
28
|
+
[FONT_SIZE_FIELD]: z.number().step(1).min(12).max(17).default(14)
|
|
29
|
+
});
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region lib/types/boot-theme.js
|
|
32
|
+
/**
|
|
33
|
+
* Theme bootstrap row for the browser's pre-plugin interval. Each index
|
|
34
|
+
* render embeds the current durable built-in preference and content font size;
|
|
35
|
+
* the browser resolves only `system`, then writes the same DOM fields
|
|
36
|
+
* ui-layout's ThemePresenter owns after the client plugin tree activates.
|
|
37
|
+
*/
|
|
38
|
+
/** Build the inline script body for one schema-validated durable theme section. */
|
|
39
|
+
function bootThemeScript(preference, fontSize) {
|
|
40
|
+
return `(() => {
|
|
41
|
+
const preference = ${JSON.stringify(preference)}
|
|
42
|
+
const systemDark = preference === 'system'
|
|
43
|
+
&& typeof matchMedia !== 'undefined'
|
|
44
|
+
&& matchMedia('(prefers-color-scheme: dark)').matches
|
|
45
|
+
const dark = preference === 'dark' || systemDark
|
|
46
|
+
document.documentElement.style.colorScheme = dark ? 'dark' : 'light'
|
|
47
|
+
document.body.toggleAttribute('data-ds-dark-theme', dark)
|
|
48
|
+
document.body.style.setProperty('--dsh-content-font-size', ${JSON.stringify(`${fontSize}px`)})
|
|
49
|
+
})()`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The theme bootstrap as an injection row: an inline script immediately after
|
|
53
|
+
* the opening body tag, before the shell mount and module script.
|
|
54
|
+
* @param preference - Current Host-backed built-in preference.
|
|
55
|
+
* @param fontSize - Current Host-backed content font size in px.
|
|
56
|
+
* @returns the body script row.
|
|
57
|
+
*/
|
|
58
|
+
function bootThemeInjection(preference = DEFAULT_PREFERENCE, fontSize = 14) {
|
|
59
|
+
return {
|
|
60
|
+
kind: "script",
|
|
61
|
+
placement: "body",
|
|
62
|
+
text: bootThemeScript(preference, fontSize)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region lib/types/index.js
|
|
67
|
+
/** Host registration for the browser theme preference and pre-plugin palette. */
|
|
68
|
+
const THEME_NAMESPACE = settingsNamespace(THEME_SETTINGS_NAMESPACE);
|
|
69
|
+
/** Read the registered theme section or the schema defaults without a settings provider. */
|
|
70
|
+
function readSection(ctx) {
|
|
71
|
+
const fallback = {
|
|
72
|
+
preference: DEFAULT_PREFERENCE,
|
|
73
|
+
fontSize: 14
|
|
74
|
+
};
|
|
75
|
+
const settings = ctx.get("settings");
|
|
76
|
+
if (settings === void 0) return fallback;
|
|
77
|
+
const section = settings.get(THEME_NAMESPACE);
|
|
78
|
+
if (section === void 0) return fallback;
|
|
79
|
+
return section;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Register the durable theme section when the optional settings service is
|
|
83
|
+
* composed, and answer every index injection collection with the current
|
|
84
|
+
* theme bootstrap row.
|
|
85
|
+
* @param ctx - Host context that may acquire the settings service.
|
|
86
|
+
*/
|
|
87
|
+
function apply(ctx) {
|
|
88
|
+
ctx.inject(["settings"], (settingsCtx) => {
|
|
89
|
+
settingsCtx.settings.register(THEME_NAMESPACE, ThemeSettingsSchema);
|
|
90
|
+
});
|
|
91
|
+
ctx.on("webserver/index-inject", (table) => {
|
|
92
|
+
const section = readSection(ctx);
|
|
93
|
+
table.push(bootThemeInjection(section.preference, section.fontSize));
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
export { DEFAULT_FONT_SIZE, DEFAULT_PREFERENCE, FONT_SIZE_FIELD, FONT_SIZE_MAX, FONT_SIZE_MIN, THEME_PREFERENCES, THEME_PREFERENCE_FIELD, THEME_SETTINGS_NAMESPACE, apply };
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
/**
|
|
3
|
+
* Package-owned invariant companion for `@prettier-ai/dsh-client-ui-theme`.
|
|
4
|
+
* @module @prettier-ai/dsh-client-ui-theme/invariant
|
|
5
|
+
*/
|
|
6
|
+
const PACKAGE_NAME = "@prettier-ai/dsh-client-ui-theme";
|
|
7
|
+
/** Cordis companion plugin name. */
|
|
8
|
+
const name = "client-ui-theme-invariant";
|
|
9
|
+
/** Service required before the companion can reserve package ownership. */
|
|
10
|
+
const inject = ["invariants"];
|
|
11
|
+
/**
|
|
12
|
+
* No runtime invariant: the settings scope validates and publishes the durable
|
|
13
|
+
* theme section, while the registry emits `theme/change` synchronously with
|
|
14
|
+
* its own mutations. Store/registry agreement is covered directly by this
|
|
15
|
+
* package's Host, scope, and service behavior specs.
|
|
16
|
+
*/
|
|
17
|
+
const install = () => {};
|
|
18
|
+
/**
|
|
19
|
+
* Register this package's invariant companion.
|
|
20
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
21
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
22
|
+
*/
|
|
23
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
24
|
+
//#endregion
|
|
25
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme bootstrap row for the browser's pre-plugin interval. Each index
|
|
3
|
+
* render embeds the current durable built-in preference and content font size;
|
|
4
|
+
* the browser resolves only `system`, then writes the same DOM fields
|
|
5
|
+
* ui-layout's ThemePresenter owns after the client plugin tree activates.
|
|
6
|
+
*/
|
|
7
|
+
import type { IndexInjection } from '@prettier-ai/dsh-host-webserver';
|
|
8
|
+
import { type ThemePreference } from './theme-settings.ts';
|
|
9
|
+
/**
|
|
10
|
+
* The theme bootstrap as an injection row: an inline script immediately after
|
|
11
|
+
* the opening body tag, before the shell mount and module script.
|
|
12
|
+
* @param preference - Current Host-backed built-in preference.
|
|
13
|
+
* @param fontSize - Current Host-backed content font size in px.
|
|
14
|
+
* @returns the body script row.
|
|
15
|
+
*/
|
|
16
|
+
export declare function bootThemeInjection(preference?: ThemePreference, fontSize?: number): IndexInjection;
|
|
17
|
+
//# sourceMappingURL=boot-theme.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { PropsLocale, PropsRuntime, PropsStore } from '@prettier-ai/dsh-client-ui-slots';
|
|
2
|
+
import type { ThemePreference } from '../theme-settings.ts';
|
|
3
|
+
import type { createAppearanceRowStore } from './settings-store.ts';
|
|
4
|
+
/** Injected business face: the preference write (t rides the standard locale seat). */
|
|
5
|
+
export interface AppearanceRowInjected {
|
|
6
|
+
/** Switch the theme preference. */
|
|
7
|
+
setTheme: (id: ThemePreference) => void;
|
|
8
|
+
}
|
|
9
|
+
/** Full component props: runtime share + store share + locale seat + injected face. */
|
|
10
|
+
export type AppearanceRowComponentProps = PropsRuntime<'settings.general.item'> & PropsStore<ReturnType<typeof createAppearanceRowStore>> & PropsLocale<'settings.theme'> & AppearanceRowInjected;
|
|
11
|
+
/**
|
|
12
|
+
* Render the Appearance row.
|
|
13
|
+
* @param props - composed slot props.
|
|
14
|
+
* @returns the row element tree.
|
|
15
|
+
*/
|
|
16
|
+
export declare function AppearanceRow({ t, setTheme, useStore }: AppearanceRowComponentProps): import("react").JSX.Element;
|
|
17
|
+
//# sourceMappingURL=AppearanceRow.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PropsLocale, PropsRuntime, PropsStore } from '@prettier-ai/dsh-client-ui-slots';
|
|
2
|
+
import type { createFontSizeRowStore } from './settings-store.ts';
|
|
3
|
+
/** Injected business face: the preference write (t rides the standard locale seat). */
|
|
4
|
+
export interface FontSizeRowInjected {
|
|
5
|
+
/** Change the content font size (integer px within FONT_SIZE_MIN..FONT_SIZE_MAX). */
|
|
6
|
+
setFontSize: (px: number) => void;
|
|
7
|
+
}
|
|
8
|
+
/** Full component props: runtime share + store share + locale seat + injected face. */
|
|
9
|
+
export type FontSizeRowComponentProps = PropsRuntime<'settings.general.item'> & PropsStore<ReturnType<typeof createFontSizeRowStore>> & PropsLocale<'settings.theme'> & FontSizeRowInjected;
|
|
10
|
+
/**
|
|
11
|
+
* Render the font-size row.
|
|
12
|
+
* @param props - composed slot props.
|
|
13
|
+
* @returns the row element tree.
|
|
14
|
+
*/
|
|
15
|
+
export declare function FontSizeRow({ t, setFontSize, useStore }: FontSizeRowComponentProps): import("react").JSX.Element;
|
|
16
|
+
//# sourceMappingURL=FontSizeRow.d.ts.map
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser theme registry over the `--dsw-*` token stylesheets. The service
|
|
3
|
+
* owns the live theme preference (light/dark/system), resolves `system` through
|
|
4
|
+
* `prefers-color-scheme`, and publishes immutable snapshots; it never touches
|
|
5
|
+
* the DOM — ui-layout's presenter consumes the resolved snapshot. The Host
|
|
6
|
+
* settings scope loads and stores the preference in the user-settings
|
|
7
|
+
* document. The plugin also registers the Appearance preference row into the
|
|
8
|
+
* settings General section — the theme feature owns its own settings surface.
|
|
9
|
+
*/
|
|
10
|
+
import type { Context as ClientContext } from '@prettier-ai/cordis';
|
|
11
|
+
import type { SettingsScope } from '@prettier-ai/dsh-client-ui-settings/client';
|
|
12
|
+
import { type ThemeKey } from './locales.ts';
|
|
13
|
+
import { type ThemePreference, type ThemeSettings } from '../theme-settings.ts';
|
|
14
|
+
export type { AppearanceRowComponentProps, AppearanceRowInjected } from './AppearanceRow.tsx';
|
|
15
|
+
export type { FontSizeRowComponentProps, FontSizeRowInjected } from './FontSizeRow.tsx';
|
|
16
|
+
export type { AppearanceRowState, FontSizeRowState } from './settings-store.ts';
|
|
17
|
+
export type { ThemeKey } from './locales.ts';
|
|
18
|
+
export type { ThemePreference, ThemeSettings } from '../theme-settings.ts';
|
|
19
|
+
/** Namespace owning this feature's settings-row copy. */
|
|
20
|
+
export declare const SETTINGS_NS = "settings.theme";
|
|
21
|
+
declare module '@prettier-ai/dsh-client-ui-slots' {
|
|
22
|
+
interface LocaleNamespaceMap {
|
|
23
|
+
/** The Appearance settings row's copy. */
|
|
24
|
+
'settings.theme': ThemeKey;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** Theme token dictionary: --dsw-alias-* overrides keyed by variable name. */
|
|
28
|
+
export type ThemeTokens = Record<string, string>;
|
|
29
|
+
/**
|
|
30
|
+
* One override-layer token value: both palette modes are mandatory (repeat
|
|
31
|
+
* the same value when the token is scheme-invariant) so an override never
|
|
32
|
+
* goes illegible when the user switches to the other scheme.
|
|
33
|
+
*/
|
|
34
|
+
export interface ThemeTokenModes {
|
|
35
|
+
/** Value applied while the light base palette is active. */
|
|
36
|
+
light: string;
|
|
37
|
+
/** Value applied while the dark base palette is active. */
|
|
38
|
+
dark: string;
|
|
39
|
+
}
|
|
40
|
+
/** Override-layer dictionary: token names to per-mode value pairs. */
|
|
41
|
+
export type ThemeTokenOverrides = Record<string, ThemeTokenModes>;
|
|
42
|
+
/** One selectable theme: id, dark/light semantics, and alias-token overrides. */
|
|
43
|
+
export interface ThemeDefinition {
|
|
44
|
+
/** Theme id (the setTheme argument for concrete themes). */
|
|
45
|
+
id: string;
|
|
46
|
+
/**
|
|
47
|
+
* Which base palette this theme builds on. The presenter switches
|
|
48
|
+
* `body[data-ds-dark-theme]` from this field — never from the id.
|
|
49
|
+
*/
|
|
50
|
+
colorScheme: 'light' | 'dark';
|
|
51
|
+
/** Alias-layer overrides applied as inline CSS variables over the base palette. */
|
|
52
|
+
tokens: ThemeTokens;
|
|
53
|
+
}
|
|
54
|
+
/** Immutable theme state published on every change. */
|
|
55
|
+
export interface ThemeSnapshot {
|
|
56
|
+
/** The persisted preference (may be `system`). */
|
|
57
|
+
preference: ThemePreference;
|
|
58
|
+
/** Conversation content font size in px (integer within FONT_SIZE_MIN..FONT_SIZE_MAX). */
|
|
59
|
+
fontSize: number;
|
|
60
|
+
/**
|
|
61
|
+
* The resolved active theme (`system` resolved via prefers-color-scheme)
|
|
62
|
+
* with override layers folded into its tokens (seq order, later layers win
|
|
63
|
+
* per-token; each value picked for the active color scheme).
|
|
64
|
+
*/
|
|
65
|
+
active: ThemeDefinition;
|
|
66
|
+
/** Registered themes in registration order. */
|
|
67
|
+
themes: readonly ThemeDefinition[];
|
|
68
|
+
/** Monotonic change counter (registry or active changes). */
|
|
69
|
+
revision: number;
|
|
70
|
+
}
|
|
71
|
+
/** One theme token exposed to pre-definition Cordis inspection. */
|
|
72
|
+
export interface ThemeTokenInspection {
|
|
73
|
+
/** Token name accepted by {@link ThemeService.overrideTokens}. */
|
|
74
|
+
name: string;
|
|
75
|
+
/** Intended visual role. */
|
|
76
|
+
description: string;
|
|
77
|
+
/** CSS value category. */
|
|
78
|
+
valueType: string;
|
|
79
|
+
/** Whether override layers must supply both palette modes. */
|
|
80
|
+
requiresLightAndDark: boolean;
|
|
81
|
+
/** CSS custom property consumed by UI styles. */
|
|
82
|
+
cssVariable?: string;
|
|
83
|
+
}
|
|
84
|
+
declare module '@prettier-ai/cordis' {
|
|
85
|
+
interface Context {
|
|
86
|
+
theme: ThemeRuntime;
|
|
87
|
+
}
|
|
88
|
+
interface Events {
|
|
89
|
+
/**
|
|
90
|
+
* Theme state changed (preference switched, registry updated, or the OS
|
|
91
|
+
* color scheme changed while the preference is `system`).
|
|
92
|
+
* @param snapshot - Current immutable theme snapshot.
|
|
93
|
+
* @mode emit
|
|
94
|
+
*/
|
|
95
|
+
'theme/change'(snapshot: ThemeSnapshot): void;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Theme registry and preference owner. `light`/`dark` are built in (the base
|
|
100
|
+
* stylesheets carry both palettes); third-party themes register alias-layer
|
|
101
|
+
* overrides. Reads go through {@link getTheme}; preference writes only
|
|
102
|
+
* through {@link setTheme}; continuous sync only through the `theme/change`
|
|
103
|
+
* event. {@link overrideTokens} stacks partial token layers over the active
|
|
104
|
+
* theme without touching the registry.
|
|
105
|
+
* The service holds the `prefers-color-scheme` media query (environment
|
|
106
|
+
* sensing, not presentation) and re-emits when the OS scheme flips while the
|
|
107
|
+
* preference is `system`.
|
|
108
|
+
*/
|
|
109
|
+
export declare class ThemeRuntime {
|
|
110
|
+
private readonly ctx;
|
|
111
|
+
private readonly host;
|
|
112
|
+
private themes;
|
|
113
|
+
private preference;
|
|
114
|
+
private fontSize;
|
|
115
|
+
private revision;
|
|
116
|
+
private snapshot;
|
|
117
|
+
private readonly media;
|
|
118
|
+
/** Override layers by source; seq (monotonic) is the stacking order. */
|
|
119
|
+
private readonly overrides;
|
|
120
|
+
private overrideSeq;
|
|
121
|
+
/**
|
|
122
|
+
* @param ctx - owning context (change events are emitted on it; the
|
|
123
|
+
* media-query and scope listeners are released through ctx.effect on dispose).
|
|
124
|
+
* @param host - durable preference scope owned by the same plugin.
|
|
125
|
+
*/
|
|
126
|
+
constructor(ctx: ClientContext, host: SettingsScope<ThemeSettings>);
|
|
127
|
+
/**
|
|
128
|
+
* Read the current immutable theme snapshot.
|
|
129
|
+
* @returns the current snapshot (stable reference until the next change).
|
|
130
|
+
*/
|
|
131
|
+
getTheme(): ThemeSnapshot;
|
|
132
|
+
/**
|
|
133
|
+
* Export the current token directory without reading DOM or computed styles.
|
|
134
|
+
* @returns stable JSON-safe token descriptions, including registered and override-only names.
|
|
135
|
+
*/
|
|
136
|
+
exportInspectTokens(): ThemeTokenInspection[];
|
|
137
|
+
/**
|
|
138
|
+
* Switch the theme preference — the only user preference write entry.
|
|
139
|
+
* Built-in preferences are written through the settings scope and every
|
|
140
|
+
* accepted value emits `theme/change`.
|
|
141
|
+
* @param id - a registered theme id or `system`; unknown ids throw.
|
|
142
|
+
*/
|
|
143
|
+
setTheme(id: string): void;
|
|
144
|
+
/**
|
|
145
|
+
* Change the conversation content font size — the only font-size write
|
|
146
|
+
* entry. Accepted values are written through the settings scope and emit
|
|
147
|
+
* `theme/change`.
|
|
148
|
+
* @param px - integer px within FONT_SIZE_MIN..FONT_SIZE_MAX; out-of-range or fractional values throw.
|
|
149
|
+
*/
|
|
150
|
+
setFontSize(px: number): void;
|
|
151
|
+
/** Adopt the scope's accepted durable preference without writing it back. */
|
|
152
|
+
private adopt;
|
|
153
|
+
/**
|
|
154
|
+
* Register a theme. Duplicate id throws (single occupant per id; the
|
|
155
|
+
* built-in pair counts; `system` is a preference, not a registrable id).
|
|
156
|
+
* @param definition - theme id, colorScheme, and alias-token overrides.
|
|
157
|
+
* @returns disposer. Disposing the theme backing the active preference
|
|
158
|
+
* resets the preference to the default so the UI never keeps tokens of an
|
|
159
|
+
* unregistered theme.
|
|
160
|
+
*/
|
|
161
|
+
register(definition: ThemeDefinition): () => void;
|
|
162
|
+
/**
|
|
163
|
+
* Stack a token override layer on top of the active theme — the token-level
|
|
164
|
+
* analogue of slot shading: the base theme stays untouched, layers compose
|
|
165
|
+
* in seq order with later layers winning per-token, and removing a layer
|
|
166
|
+
* restores whatever it covered. Calling again with the same source replaces
|
|
167
|
+
* that source's whole layer and restacks it on top (effect re-registration
|
|
168
|
+
* semantics). Emits `theme/change` with the recomposed snapshot.
|
|
169
|
+
* @param source - layer identity; one layer per source (dynamic packages
|
|
170
|
+
* pass their package id — the façade pins it, so it also names the layer's
|
|
171
|
+
* origin for inspection).
|
|
172
|
+
* @param tokens - token-name → `{ light, dark }` value pairs. Validated at
|
|
173
|
+
* runtime (model-authored callers reach this boundary with untyped JS);
|
|
174
|
+
* a bare string value throws a teaching error.
|
|
175
|
+
* @returns disposer removing exactly the layer this call created; a no-op
|
|
176
|
+
* once the source has re-overridden (the newer layer is not torn down).
|
|
177
|
+
*/
|
|
178
|
+
overrideTokens(source: string, tokens: ThemeTokenOverrides): () => void;
|
|
179
|
+
private buildSnapshot;
|
|
180
|
+
/**
|
|
181
|
+
* Fold the override layers into the active definition: seq order, later
|
|
182
|
+
* layers win per-token, each value picked for the active color scheme (the
|
|
183
|
+
* presenter consumes the composed snapshot and needs no override awareness).
|
|
184
|
+
* Without layers the registered definition passes through by identity.
|
|
185
|
+
*/
|
|
186
|
+
private composeActive;
|
|
187
|
+
private publish;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Required services: settings transport plus slots/locale for the Appearance
|
|
191
|
+
* row. `remote` carries the forwarded settings invalidation that
|
|
192
|
+
* `ctx.settingsScope.bind(spec)` subscribes to on this context.
|
|
193
|
+
*/
|
|
194
|
+
export declare const inject: string[];
|
|
195
|
+
/**
|
|
196
|
+
* Client plugin body: provide the theme service and register the
|
|
197
|
+
* feature-owned Appearance preference row into the General section's item
|
|
198
|
+
* slot (a feature owns its settings surface).
|
|
199
|
+
* @param ctx - client cordis context.
|
|
200
|
+
*/
|
|
201
|
+
export declare function apply(ctx: ClientContext): void;
|
|
202
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** `settings.theme` namespace dictionaries (the Appearance and font-size rows' copy). */
|
|
2
|
+
/** Simplified Chinese dictionary (the key-set source of truth). */
|
|
3
|
+
export declare const zh: {
|
|
4
|
+
'appearance.title': string;
|
|
5
|
+
'appearance.light': string;
|
|
6
|
+
'appearance.dark': string;
|
|
7
|
+
'appearance.system': string;
|
|
8
|
+
'fontSize.title': string;
|
|
9
|
+
'fontSize.description': string;
|
|
10
|
+
'fontSize.unit': string;
|
|
11
|
+
'fontSize.increase': string;
|
|
12
|
+
'fontSize.decrease': string;
|
|
13
|
+
};
|
|
14
|
+
/** The settings.theme namespace key union. */
|
|
15
|
+
export type ThemeKey = keyof typeof zh;
|
|
16
|
+
/** English dictionary, checked complete against the zh key set. */
|
|
17
|
+
export declare const en: {
|
|
18
|
+
'appearance.title': string;
|
|
19
|
+
'appearance.light': string;
|
|
20
|
+
'appearance.dark': string;
|
|
21
|
+
'appearance.system': string;
|
|
22
|
+
'fontSize.title': string;
|
|
23
|
+
'fontSize.description': string;
|
|
24
|
+
'fontSize.unit': string;
|
|
25
|
+
'fontSize.increase': string;
|
|
26
|
+
'fontSize.decrease': string;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=locales.d.ts.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Appearance and font-size row slot stores: mirrors of the theme service
|
|
3
|
+
* snapshot. The plugin's apply-world change listener is the only writer; the
|
|
4
|
+
* row components read via props.useStore.
|
|
5
|
+
*/
|
|
6
|
+
import { type EngineStoreHandle } from '@prettier-ai/dsh-client-store';
|
|
7
|
+
import { type ThemePreference } from '../theme-settings.ts';
|
|
8
|
+
/** Store state mirrored from the theme snapshot. */
|
|
9
|
+
export interface AppearanceRowState {
|
|
10
|
+
/** Persisted preference (selection state reads this, never the resolved active theme). */
|
|
11
|
+
preference: ThemePreference;
|
|
12
|
+
/** Service revision; -1 until first sync so revision 0 lands as a change. */
|
|
13
|
+
revision: number;
|
|
14
|
+
}
|
|
15
|
+
/** Declared action shape giving the exported factory a stable return type. */
|
|
16
|
+
type AppearanceRowActions = {
|
|
17
|
+
sync: (draft: AppearanceRowState, preference: ThemePreference, revision: number) => void;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Declares the Appearance row state and write surface.
|
|
21
|
+
* @returns the store handle.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createAppearanceRowStore(): EngineStoreHandle<AppearanceRowState, AppearanceRowActions>;
|
|
24
|
+
/** Store state mirrored from the theme snapshot's font size. */
|
|
25
|
+
export interface FontSizeRowState {
|
|
26
|
+
/** Persisted content font size in px. */
|
|
27
|
+
fontSize: number;
|
|
28
|
+
/** Service revision; -1 until first sync so revision 0 lands as a change. */
|
|
29
|
+
revision: number;
|
|
30
|
+
}
|
|
31
|
+
/** Declared action shape giving the exported factory a stable return type. */
|
|
32
|
+
type FontSizeRowActions = {
|
|
33
|
+
sync: (draft: FontSizeRowState, fontSize: number, revision: number) => void;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Declares the font-size row state and write surface.
|
|
37
|
+
* @returns the store handle.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createFontSizeRowStore(): EngineStoreHandle<FontSizeRowState, FontSizeRowActions>;
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=settings-store.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Context } from '@prettier-ai/cordis';
|
|
2
|
+
/**
|
|
3
|
+
* Mount the global theme sheets for exactly the owning plugin lifetime.
|
|
4
|
+
* @param ctx - Owning plugin context.
|
|
5
|
+
*/
|
|
6
|
+
export declare function installThemeStyles(ctx: Context): void;
|
|
7
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Host registration for the browser theme preference and pre-plugin palette. */
|
|
2
|
+
import type { Context } from '@prettier-ai/cordis';
|
|
3
|
+
export { DEFAULT_FONT_SIZE, DEFAULT_PREFERENCE, FONT_SIZE_FIELD, FONT_SIZE_MAX, FONT_SIZE_MIN, THEME_PREFERENCE_FIELD, THEME_PREFERENCES, THEME_SETTINGS_NAMESPACE, type ThemePreference, type ThemeSettings, } from './theme-settings.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Register the durable theme section when the optional settings service is
|
|
6
|
+
* composed, and answer every index injection collection with the current
|
|
7
|
+
* theme bootstrap row.
|
|
8
|
+
* @param ctx - Host context that may acquire the settings service.
|
|
9
|
+
*/
|
|
10
|
+
export declare function apply(ctx: Context): void;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `@prettier-ai/dsh-client-ui-theme`.
|
|
3
|
+
* @module @prettier-ai/dsh-client-ui-theme/invariant
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@prettier-ai/cordis';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export declare const name = "client-ui-theme-invariant";
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Register this package's invariant companion.
|
|
12
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
+
*/
|
|
15
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
+
//# sourceMappingURL=invariant.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Theme preferences stored in the Host user-settings document. */
|
|
2
|
+
import z from '@prettier-ai/schemastery';
|
|
3
|
+
/** Built-in preferences accepted at the registry and settings boundaries. */
|
|
4
|
+
export declare const THEME_PREFERENCES: readonly ["light", "dark", "system"];
|
|
5
|
+
/** Settings namespace owned by the theme plugin. */
|
|
6
|
+
export declare const THEME_SETTINGS_NAMESPACE = "ui-theme";
|
|
7
|
+
/** Field carrying the selected built-in theme preference. */
|
|
8
|
+
export declare const THEME_PREFERENCE_FIELD = "preference";
|
|
9
|
+
/** Field carrying the conversation content font size. */
|
|
10
|
+
export declare const FONT_SIZE_FIELD = "fontSize";
|
|
11
|
+
/** Theme preference persisted by the product Appearance row. */
|
|
12
|
+
export type ThemePreference = typeof THEME_PREFERENCES[number];
|
|
13
|
+
/** Default preference when the user-settings document has no override. */
|
|
14
|
+
export declare const DEFAULT_PREFERENCE: ThemePreference;
|
|
15
|
+
/** Smallest accepted content font size (px). */
|
|
16
|
+
export declare const FONT_SIZE_MIN = 12;
|
|
17
|
+
/** Largest accepted content font size (px). */
|
|
18
|
+
export declare const FONT_SIZE_MAX = 17;
|
|
19
|
+
/** Content font size when the user-settings document has no override (px). */
|
|
20
|
+
export declare const DEFAULT_FONT_SIZE = 14;
|
|
21
|
+
/** Durable theme section shared by the Host schema and the browser scope. */
|
|
22
|
+
export interface ThemeSettings {
|
|
23
|
+
/** Selected built-in preference. */
|
|
24
|
+
preference: ThemePreference;
|
|
25
|
+
/** Conversation content font size in px (integer within {@link FONT_SIZE_MIN}..{@link FONT_SIZE_MAX}). */
|
|
26
|
+
fontSize: number;
|
|
27
|
+
}
|
|
28
|
+
/** Durable theme schema; also the wire envelope the browser scope validates against. */
|
|
29
|
+
export declare const ThemeSettingsSchema: z<ThemeSettings>;
|
|
30
|
+
/**
|
|
31
|
+
* Narrow one wire or registry value to a persistable preference.
|
|
32
|
+
* @param value - value crossing the settings or registry boundary.
|
|
33
|
+
* @returns whether the value is a built-in preference.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isThemePreference(value: unknown): value is ThemePreference;
|
|
36
|
+
//# sourceMappingURL=theme-settings.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prettier-ai/dsh-client-ui-theme",
|
|
3
|
+
"description": "Theme plugin: Host bootstrap for the pre-plugin palette; DOM-free ThemeRuntime for light/dark/system state; --dsw-* token styles and Appearance settings row",
|
|
4
|
+
"version": "0.1.2-alpha.1",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
|
11
|
+
"directory": "packages/client/ui-theme"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./invariant": {
|
|
22
|
+
"types": "./lib/types/invariant.d.ts",
|
|
23
|
+
"default": "./lib/invariant.js"
|
|
24
|
+
},
|
|
25
|
+
"./client": {
|
|
26
|
+
"types": "./lib/types/client/index.d.ts",
|
|
27
|
+
"default": "./lib/client.js"
|
|
28
|
+
},
|
|
29
|
+
"./src/*": "./src/*",
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
"dsh": {
|
|
33
|
+
"client": {
|
|
34
|
+
"inject": [
|
|
35
|
+
"@prettier-ai/dsh-client-connection",
|
|
36
|
+
"@prettier-ai/dsh-client-locale",
|
|
37
|
+
"@prettier-ai/dsh-client-ui-renderer",
|
|
38
|
+
"@prettier-ai/dsh-client-ui-settings",
|
|
39
|
+
"@prettier-ai/dsh-api-remotes"
|
|
40
|
+
],
|
|
41
|
+
"platform": "web",
|
|
42
|
+
"immediately": true
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"@prettier-ai/dsh-client-connection": "^0.1.2-alpha.1",
|
|
48
|
+
"@prettier-ai/dsh-api-remotes": "^0.1.2-alpha.1",
|
|
49
|
+
"@prettier-ai/cordis": "^4.0.1",
|
|
50
|
+
"@prettier-ai/dsh-client-locale": "^0.1.2-alpha.1",
|
|
51
|
+
"@prettier-ai/dsh-client-ui-renderer": "^0.1.2-alpha.1",
|
|
52
|
+
"@prettier-ai/dsh-client-ui-settings": "^0.1.2-alpha.1",
|
|
53
|
+
"@prettier-ai/dsh-host-webserver": "^0.1.2-alpha.1",
|
|
54
|
+
"@prettier-ai/dsh-invariants": "^0.1.2-alpha.1",
|
|
55
|
+
"@prettier-ai/dsh-settings": "^0.1.2-alpha.1"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@types/react": "~18.3.1",
|
|
59
|
+
"react": "^18.2.0",
|
|
60
|
+
"@prettier-ai/cordis": "^4.0.1",
|
|
61
|
+
"@prettier-ai/dsh-api-remotes": "^0.1.2-alpha.1",
|
|
62
|
+
"@prettier-ai/dsh-client-connection": "^0.1.2-alpha.1",
|
|
63
|
+
"@prettier-ai/dsh-client-store": "^0.1.2-alpha.1",
|
|
64
|
+
"@prettier-ai/dsh-client-locale": "^0.1.2-alpha.1",
|
|
65
|
+
"@prettier-ai/dsh-client-test-runtime": "^0.1.2-alpha.1",
|
|
66
|
+
"@prettier-ai/dsh-client-ui-primitives": "^0.1.2-alpha.1",
|
|
67
|
+
"@prettier-ai/dsh-client-ui-renderer": "^0.1.2-alpha.1",
|
|
68
|
+
"@prettier-ai/dsh-client-ui-settings": "^0.1.2-alpha.1",
|
|
69
|
+
"@prettier-ai/dsh-host-webserver": "^0.1.2-alpha.1",
|
|
70
|
+
"@prettier-ai/dsh-invariants": "^0.1.2-alpha.1",
|
|
71
|
+
"@prettier-ai/dsh-settings": "^0.1.2-alpha.1",
|
|
72
|
+
"@prettier-ai/dsh-client-ui-slots": "^0.1.2-alpha.1"
|
|
73
|
+
},
|
|
74
|
+
"files": [
|
|
75
|
+
"lib/index.js",
|
|
76
|
+
"lib/invariant.js",
|
|
77
|
+
"lib/client.js",
|
|
78
|
+
"lib/styles",
|
|
79
|
+
"lib/types/**/*.d.ts"
|
|
80
|
+
],
|
|
81
|
+
"dependencies": {
|
|
82
|
+
"clsx": "^2.0.0",
|
|
83
|
+
"@prettier-ai/schemastery": "^3.18.1"
|
|
84
|
+
},
|
|
85
|
+
"scripts": {
|
|
86
|
+
"bundle": "tsdown",
|
|
87
|
+
"watch": "tsdown --watch"
|
|
88
|
+
}
|
|
89
|
+
}
|