@qilin-agent/client-ui-theme 3.1.4 → 3.1.6

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/lib/index.js CHANGED
@@ -21,20 +21,115 @@ const FONT_SIZE_MIN = 10;
21
21
  const FONT_SIZE_MAX = 22;
22
22
  /** Content font size when the user-settings document has no override (px). */
23
23
  const DEFAULT_FONT_SIZE = 14;
24
- /** Durable theme schema; also the wire envelope the browser scope validates against. */
25
- const ThemeSettingsSchema = z.object({
24
+ /** Independently configurable font roles. */
25
+ const FONT_ROLES = [
26
+ "text",
27
+ "code",
28
+ "terminal"
29
+ ];
30
+ /**
31
+ * Font sizes by role. `text` is the conversation content size; `code` is the
32
+ * code-block size (inline code stays 1px larger); `terminal` is the sidebar
33
+ * terminal cell font size.
34
+ */
35
+ const FONT_SIZE_SPECS = {
36
+ text: {
37
+ field: FONT_SIZE_FIELD,
38
+ variable: "--qilin-content-font-size",
39
+ min: 10,
40
+ max: 22,
41
+ default: 14
42
+ },
43
+ code: {
44
+ field: "codeFontSize",
45
+ variable: "--qilin-code-font-size",
46
+ min: 10,
47
+ max: 16,
48
+ default: 11
49
+ },
50
+ terminal: {
51
+ field: "terminalFontSize",
52
+ variable: "--qilin-terminal-font-size",
53
+ min: 10,
54
+ max: 20,
55
+ default: 13
56
+ }
57
+ };
58
+ /** Default font sizes by role. */
59
+ const DEFAULT_FONT_SIZES = Object.freeze({
60
+ text: FONT_SIZE_SPECS.text.default,
61
+ code: FONT_SIZE_SPECS.code.default,
62
+ terminal: FONT_SIZE_SPECS.terminal.default
63
+ });
64
+ /** Settings field carrying each role's font-family list. */
65
+ const FONT_FAMILY_FIELDS = {
66
+ text: "textFontFamily",
67
+ code: "codeFontFamily",
68
+ terminal: "terminalFontFamily"
69
+ };
70
+ /**
71
+ * Body variable carrying one role's normalized font list; the token sheet
72
+ * places it ahead of that role's built-in stack.
73
+ * @param kind - font role.
74
+ * @returns the CSS custom property name.
75
+ */
76
+ function fontFamilyVariable(kind) {
77
+ return `--qilin-font-family-${kind}`;
78
+ }
79
+ /**
80
+ * Integer px schema for one role's font size.
81
+ * @param spec - the role's range and default.
82
+ * @returns the validated number schema.
83
+ */
84
+ function fontSizeSchema(spec) {
85
+ return z.number().step(1).min(spec.min).max(spec.max).default(spec.default);
86
+ }
87
+ z.object({
26
88
  [THEME_PREFERENCE_FIELD]: z.union([...THEME_PREFERENCES]).default(DEFAULT_PREFERENCE),
27
- [FONT_SIZE_FIELD]: z.number().step(1).min(10).max(22).default(14)
89
+ [FONT_SIZE_FIELD]: fontSizeSchema(FONT_SIZE_SPECS.text),
90
+ [FONT_SIZE_SPECS.code.field]: fontSizeSchema(FONT_SIZE_SPECS.code),
91
+ [FONT_SIZE_SPECS.terminal.field]: fontSizeSchema(FONT_SIZE_SPECS.terminal),
92
+ [FONT_FAMILY_FIELDS.text]: z.string().default(""),
93
+ [FONT_FAMILY_FIELDS.code]: z.string().default(""),
94
+ [FONT_FAMILY_FIELDS.terminal]: z.string().default("")
28
95
  });
96
+ /** CSS Fonts generic and system family keywords, which must stay unquoted. */
97
+ const GENERIC_FAMILIES = new Set([
98
+ "serif",
99
+ "sans-serif",
100
+ "monospace",
101
+ "cursive",
102
+ "fantasy",
103
+ "system-ui",
104
+ "ui-serif",
105
+ "ui-sans-serif",
106
+ "ui-monospace",
107
+ "ui-rounded",
108
+ "emoji",
109
+ "math",
110
+ "fangsong",
111
+ "-apple-system",
112
+ "blinkmacsystemfont"
113
+ ]);
114
+ /**
115
+ * Normalize user input into a CSS font-family list. Names are comma separated;
116
+ * quotes, backslashes, angle brackets, and control characters are dropped, and
117
+ * every non-generic name is double-quoted, so the result is always a valid list
118
+ * safe to embed in inline CSS and boot scripts. Normalizing a result returns it unchanged.
119
+ * @param value - user-entered or stored font list.
120
+ * @returns the normalized list, or `''` when no family name remains.
121
+ */
122
+ function normalizeFontFamily(value) {
123
+ return value.split(",").map((name) => name.replace(/["'\\<>\u0000-\u001f\u007f]/gu, "").replace(/\s+/gu, " ").trim()).filter((name) => name !== "").map((name) => GENERIC_FAMILIES.has(name.toLowerCase()) ? name : `"${name}"`).join(", ");
124
+ }
29
125
  //#endregion
30
126
  //#region lib/types/boot-theme.js
31
127
  /**
32
128
  * Theme bootstrap row for the browser's pre-plugin interval. Each index
33
- * render embeds the current durable built-in preference, content font size,
34
- * and content font size. Head CSS colors the document canvas before script
35
- * execution; the body script installs the palette selector and both content
36
- * axes that ui-layout's ThemePresenter adopts after the client plugin tree
37
- * activates.
129
+ * render embeds the current durable built-in preference, font sizes, and
130
+ * font-family lists. Head CSS colors the document canvas before script
131
+ * execution; the body script installs the palette selector and font variables
132
+ * that the client presenters adopt.
38
133
  */
39
134
  const LIGHT_BACKGROUND = "#fff";
40
135
  const DARK_BACKGROUND = "#151517";
@@ -46,8 +141,13 @@ function bootThemeStyle(preference) {
46
141
  if (preference === "dark") return dark;
47
142
  return `${light}@media(prefers-color-scheme:dark){${dark}}`;
48
143
  }
49
- /** Build the body script that installs the palette selector, font size, and leading. */
50
- function bootThemeBodyScript(preference, fontSize) {
144
+ /** Build the body script that installs the palette selector and font variables. */
145
+ function bootThemeBodyScript(preference, fontSizes, fontFamilies) {
146
+ const sizes = FONT_ROLES.map((role) => `\n document.body.style.setProperty(${JSON.stringify(FONT_SIZE_SPECS[role].variable)}, ${JSON.stringify(`${fontSizes[role]}px`)})`).join("");
147
+ const families = FONT_ROLES.flatMap((kind) => {
148
+ const list = normalizeFontFamily(fontFamilies[kind]);
149
+ return list === "" ? [] : [`\n document.body.style.setProperty(${JSON.stringify(fontFamilyVariable(kind))}, ${JSON.stringify(list)})`];
150
+ }).join("");
51
151
  return `(() => {
52
152
  const preference = ${JSON.stringify(preference)}
53
153
  const systemDark = preference === 'system'
@@ -55,58 +155,71 @@ function bootThemeBodyScript(preference, fontSize) {
55
155
  && matchMedia('(prefers-color-scheme: dark)').matches
56
156
  const dark = preference === 'dark' || systemDark
57
157
  document.documentElement.dataset.dsThemeSource = preference
58
- document.body.toggleAttribute('data-ds-dark-theme', dark)
59
- document.body.style.setProperty('--qilin-content-font-size', ${JSON.stringify(`${fontSize}px`)})
158
+ document.body.toggleAttribute('data-ds-dark-theme', dark)${sizes}${families}
60
159
  })()`;
61
160
  }
62
161
  /**
63
162
  * Theme bootstrap rows: head CSS colors the document canvas before
64
- * first paint, then the body script installs the palette selector and the
65
- * content font size and leading before the shell mount and module script.
163
+ * first paint, then the body script installs the palette selector and font
164
+ * size and font families before the shell mount and module script.
66
165
  * @param preference - Current Host-backed built-in preference.
67
- * @param fontSize - Current Host-backed content font size in px.
68
- * @returns head style and body script rows in execution order.
166
+ * @param fontSizes - Current Host-backed font sizes in px by role.
167
+ * @param fontFamilies - Current Host-backed font lists; each is normalized before embedding.
168
+ * @returns head and body script rows in execution order.
69
169
  */
70
- function bootThemeInjections(preference = DEFAULT_PREFERENCE, fontSize = 14) {
170
+ function bootThemeInjections(preference = DEFAULT_PREFERENCE, fontSizes = DEFAULT_FONT_SIZES, fontFamilies = {
171
+ text: "",
172
+ code: "",
173
+ terminal: ""
174
+ }) {
71
175
  return [{
72
176
  kind: "style",
73
177
  text: bootThemeStyle(preference)
74
178
  }, {
75
179
  kind: "script",
76
180
  placement: "body",
77
- text: bootThemeBodyScript(preference, fontSize)
181
+ text: bootThemeBodyScript(preference, fontSizes, fontFamilies)
78
182
  }];
79
183
  }
80
184
  //#endregion
81
185
  //#region lib/types/index.js
82
- /** Host registration for the browser theme preference and pre-plugin palette. */
83
- const THEME_NAMESPACE = THEME_SETTINGS_NAMESPACE;
84
- /** Read the registered theme section or the schema defaults without a settings provider. */
85
- function readSection(ctx) {
86
- const fallback = {
87
- preference: DEFAULT_PREFERENCE,
88
- fontSize: 14
89
- };
90
- const settings = ctx.get("settings");
91
- if (settings === void 0) return fallback;
92
- const section = settings.get(THEME_NAMESPACE);
93
- if (section === void 0) return fallback;
94
- return section;
95
- }
96
186
  /**
97
- * Register the durable theme section when the optional settings service is
98
- * composed, and answer every index injection collection with the current
99
- * theme bootstrap row.
100
- * @param ctx - Host context that may acquire the settings service.
187
+ * Font-family lists read from the live config, keyed by role.
188
+ * @param families - the detached per-role lists.
189
+ * @returns the frozen per-role font-family lists.
190
+ */
191
+ function sectionFontFamilies(families) {
192
+ return Object.freeze({ ...families });
193
+ }
194
+ /** Live theme and typography preferences. */
195
+ const Config = z.object({
196
+ preference: z.union([...THEME_PREFERENCES]).default(DEFAULT_PREFERENCE).volatile(),
197
+ fontSize: fontSizeSchema(FONT_SIZE_SPECS.text).volatile(),
198
+ codeFontSize: fontSizeSchema(FONT_SIZE_SPECS.code).volatile(),
199
+ terminalFontSize: fontSizeSchema(FONT_SIZE_SPECS.terminal).volatile(),
200
+ textFontFamily: z.string().default("").volatile(),
201
+ codeFontFamily: z.string().default("").volatile(),
202
+ terminalFontFamily: z.string().default("").volatile()
203
+ });
204
+ /** Supply the current palette before browser plugins start.
205
+ * @param ctx Host plugin context.
206
+ * @param config Validated live theme preferences.
101
207
  */
102
- function apply(ctx) {
103
- ctx.inject(["settings"], (settingsCtx) => {
104
- settingsCtx.settings.register(THEME_NAMESPACE, ThemeSettingsSchema);
208
+ function apply(ctx, config) {
209
+ ctx.inject(["settings"], (child) => {
210
+ child.effect(() => child.settings.configure({ auto: false }, ctx.fiber));
105
211
  });
106
212
  ctx.on("webserver/index-inject", (table) => {
107
- const section = readSection(ctx);
108
- table.push(...bootThemeInjections(section.preference, section.fontSize));
213
+ table.push(...bootThemeInjections(config.preference.get(), {
214
+ text: config.fontSize.get(),
215
+ code: config.codeFontSize.get(),
216
+ terminal: config.terminalFontSize.get()
217
+ }, sectionFontFamilies({
218
+ text: config.textFontFamily.get(),
219
+ code: config.codeFontFamily.get(),
220
+ terminal: config.terminalFontFamily.get()
221
+ })));
109
222
  }, { prepend: true });
110
223
  }
111
224
  //#endregion
112
- export { DEFAULT_FONT_SIZE, DEFAULT_PREFERENCE, FONT_SIZE_FIELD, FONT_SIZE_MAX, FONT_SIZE_MIN, THEME_PREFERENCES, THEME_PREFERENCE_FIELD, THEME_SETTINGS_NAMESPACE, apply };
225
+ export { Config, DEFAULT_FONT_SIZE, DEFAULT_PREFERENCE, FONT_FAMILY_FIELDS, FONT_ROLES, FONT_SIZE_FIELD, FONT_SIZE_MAX, FONT_SIZE_MIN, FONT_SIZE_SPECS, THEME_PREFERENCES, THEME_PREFERENCE_FIELD, THEME_SETTINGS_NAMESPACE, apply, sectionFontFamilies };
@@ -1,20 +1,20 @@
1
1
  /**
2
2
  * Theme bootstrap row for the browser's pre-plugin interval. Each index
3
- * render embeds the current durable built-in preference, content font size,
4
- * and content font size. Head CSS colors the document canvas before script
5
- * execution; the body script installs the palette selector and both content
6
- * axes that ui-layout's ThemePresenter adopts after the client plugin tree
7
- * activates.
3
+ * render embeds the current durable built-in preference, font sizes, and
4
+ * font-family lists. Head CSS colors the document canvas before script
5
+ * execution; the body script installs the palette selector and font variables
6
+ * that the client presenters adopt.
8
7
  */
9
8
  import type { IndexInjection } from '@qilin-agent/host-webserver';
10
- import { type ThemePreference } from './theme-settings.ts';
9
+ import { type FontFamilies, type FontSizes, type ThemePreference } from './theme-settings.ts';
11
10
  /**
12
11
  * Theme bootstrap rows: head CSS colors the document canvas before
13
- * first paint, then the body script installs the palette selector and the
14
- * content font size and leading before the shell mount and module script.
12
+ * first paint, then the body script installs the palette selector and font
13
+ * size and font families before the shell mount and module script.
15
14
  * @param preference - Current Host-backed built-in preference.
16
- * @param fontSize - Current Host-backed content font size in px.
17
- * @returns head style and body script rows in execution order.
15
+ * @param fontSizes - Current Host-backed font sizes in px by role.
16
+ * @param fontFamilies - Current Host-backed font lists; each is normalized before embedding.
17
+ * @returns head and body script rows in execution order.
18
18
  */
19
- export declare function bootThemeInjections(preference?: ThemePreference, fontSize?: number): IndexInjection[];
19
+ export declare function bootThemeInjections(preference?: ThemePreference, fontSizes?: FontSizes, fontFamilies?: FontFamilies): IndexInjection[];
20
20
  //# sourceMappingURL=boot-theme.d.ts.map
@@ -0,0 +1,19 @@
1
+ import type { PropsLocale, PropsRuntime, PropsStore } from '@qilin-agent/client-ui-slots';
2
+ import { type FontRole } from '../theme-settings.ts';
3
+ import type { createFontRowStore } from './settings-store.ts';
4
+ /** Injected business face: the row's font role and its write. */
5
+ export interface FontFamilyRowInjected {
6
+ /** Font role this row edits. */
7
+ role: FontRole;
8
+ /** Change this role's font list (normalized by the theme service). */
9
+ setFontFamily: (value: string) => void;
10
+ }
11
+ /** Full component props: runtime share + store share + locale seat + injected face. */
12
+ export type FontFamilyRowComponentProps = PropsRuntime<'settings.general.item'> & PropsStore<ReturnType<typeof createFontRowStore>> & PropsLocale<'settings.theme'> & FontFamilyRowInjected;
13
+ /**
14
+ * Render one font-family row.
15
+ * @param props - composed slot props.
16
+ * @returns the row element tree.
17
+ */
18
+ export declare function FontFamilyRow({ t, role, setFontFamily, useStore }: FontFamilyRowComponentProps): import("react").JSX.Element;
19
+ //# sourceMappingURL=FontFamilyRow.d.ts.map
@@ -0,0 +1,19 @@
1
+ import type { PropsLocale, PropsRuntime, PropsStore } from '@qilin-agent/client-ui-slots';
2
+ import type { FontRole } from '../theme-settings.ts';
3
+ import type { createFontRowStore } from './settings-store.ts';
4
+ /** Injected business face: font writes by role. */
5
+ export interface FontSettingsInjected {
6
+ /** Change one role's font list (normalized by the theme service). */
7
+ setFontFamily: (role: FontRole, value: string) => void;
8
+ /** Change one role's font size (integer px within its FONT_SIZE_SPECS range). */
9
+ setFontSize: (role: FontRole, px: number) => void;
10
+ }
11
+ /** Full component props: runtime share + store share + locale seat + injected face. */
12
+ export type FontSettingsGroupProps = PropsRuntime<'settings.general.item'> & PropsStore<ReturnType<typeof createFontRowStore>> & PropsLocale<'settings.theme'> & FontSettingsInjected;
13
+ /**
14
+ * Render the text font-size row and its expandable font settings.
15
+ * @param props - composed slot props.
16
+ * @returns the text size row and, when expanded, the font rows.
17
+ */
18
+ export declare function FontSettingsGroup({ setFontFamily, setFontSize, ...shared }: FontSettingsGroupProps): import("react").JSX.Element;
19
+ //# sourceMappingURL=FontSettingsGroup.d.ts.map
@@ -1,16 +1,31 @@
1
1
  import type { PropsLocale, PropsRuntime, PropsStore } from '@qilin-agent/client-ui-slots';
2
- import type { createTypographyRowStore } from './settings-store.ts';
3
- /** Injected business face: the preference write (t rides the standard locale seat). */
2
+ import { type FontRole } from '../theme-settings.ts';
3
+ import type { createFontRowStore } from './settings-store.ts';
4
+ /** Injected business face: the row's font role and its write (t rides the standard locale seat). */
4
5
  export interface FontSizeRowInjected {
5
- /** Change the content font size (integer px within FONT_SIZE_MIN..FONT_SIZE_MAX). */
6
+ /** Font role this row edits. */
7
+ role: FontRole;
8
+ /** Change this role's font size (integer px within its FONT_SIZE_SPECS range). */
6
9
  setFontSize: (px: number) => void;
7
10
  }
8
11
  /** Full component props: runtime share + store share + locale seat + injected face. */
9
- export type FontSizeRowComponentProps = PropsRuntime<'settings.general.item'> & PropsStore<ReturnType<typeof createTypographyRowStore>> & PropsLocale<'settings.theme'> & FontSizeRowInjected;
12
+ export type FontSizeRowComponentProps = PropsRuntime<'settings.general.item'> & PropsStore<ReturnType<typeof createFontRowStore>> & PropsLocale<'settings.theme'> & FontSizeRowInjected & {
13
+ /** Disclosure button after the unit label; the font settings group passes it for the text row. */
14
+ expander?: FontSizeRowExpander | undefined;
15
+ };
16
+ /** Controlled disclosure state for the button that expands more font settings. */
17
+ export interface FontSizeRowExpander {
18
+ /** Whether the controlled region is shown. */
19
+ open: boolean;
20
+ /** Id of the controlled region. */
21
+ controls: string;
22
+ /** Toggle the region. */
23
+ onToggle: () => void;
24
+ }
10
25
  /**
11
26
  * Render the font-size row.
12
27
  * @param props - composed slot props.
13
28
  * @returns the row element tree.
14
29
  */
15
- export declare function FontSizeRow({ t, setFontSize, useStore }: FontSizeRowComponentProps): import("react").JSX.Element;
30
+ export declare function FontSizeRow({ t, role, setFontSize, useStore, expander }: FontSizeRowComponentProps): import("react").JSX.Element;
16
31
  //# sourceMappingURL=FontSizeRow.d.ts.map
@@ -0,0 +1,13 @@
1
+ /** Desktop keyboard shortcuts that step all three font sizes together. */
2
+ import type { Context as ClientContext } from '@qilin-agent/kylin';
3
+ /**
4
+ * Register the desktop font-size keys and consume their gestures.
5
+ * The web client keeps the browser's own zoom for these keys, so the
6
+ * registration exists only where the keyboard service reports the desktop
7
+ * runtime.
8
+ * @param ctx - client cordis context owning the registration effects.
9
+ * @param namespace - locale namespace carrying the shortcut labels (this package's own).
10
+ * @param adjust - applies one +1 or -1 px step to every font-size role.
11
+ */
12
+ export declare function installFontSizeShortcuts(ctx: ClientContext, namespace: 'settings.theme', adjust: (delta: 1 | -1) => void): void;
13
+ //# sourceMappingURL=font-size-shortcuts.d.ts.map
@@ -1,21 +1,22 @@
1
1
  /**
2
- * Browser theme registry over the `--qilin-*` token stylesheets. The service
2
+ * Browser theme registry over the `--dsw-*` token stylesheets. The service
3
3
  * owns the live theme preference (light/dark/system), resolves `system` through
4
4
  * `prefers-color-scheme`, and publishes immutable snapshots; it never touches
5
5
  * the DOM — ui-layout's presenter consumes the resolved snapshot. The Host
6
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.
7
+ * document. The plugin also registers the Appearance and font settings rows
8
+ * into the settings General section — the theme feature owns its own settings
9
+ * surface.
9
10
  */
10
11
  import type { Context as ClientContext } from '@qilin-agent/kylin';
11
12
  import type { ConfigForm } from '@qilin-agent/client-ui-settings/client';
12
13
  import { type ThemeKey } from './locales.ts';
13
- import { type ThemePreference, type ThemeSettings } from '../theme-settings.ts';
14
- export type { FontSizeRowComponentProps, FontSizeRowInjected } from './FontSizeRow.tsx';
14
+ import { type FontFamilies, type FontRole, type FontSizes, type ThemePreference, type ThemeSettings } from '../theme-settings.ts';
15
15
  export type { AppearanceRowComponentProps, AppearanceRowInjected } from './AppearanceRow.tsx';
16
- export type { AppearanceRowState, TypographyRowState } from './settings-store.ts';
16
+ export type { FontSettingsGroupProps, FontSettingsInjected } from './FontSettingsGroup.tsx';
17
+ export type { AppearanceRowState, FontRowState } from './settings-store.ts';
17
18
  export type { ThemeKey } from './locales.ts';
18
- export type { ThemePreference, ThemeSettings } from '../theme-settings.ts';
19
+ export type { FontFamilies, FontRole, FontSizes, ThemePreference, ThemeSettings } from '../theme-settings.ts';
19
20
  /** Namespace owning this feature's settings-row copy. */
20
21
  export declare const SETTINGS_NS = "settings.theme";
21
22
  declare module '@qilin-agent/client-ui-slots' {
@@ -24,7 +25,7 @@ declare module '@qilin-agent/client-ui-slots' {
24
25
  'settings.theme': ThemeKey;
25
26
  }
26
27
  }
27
- /** Theme token dictionary: --qilin-alias-* overrides keyed by variable name. */
28
+ /** Theme token dictionary: --dsw-alias-* overrides keyed by variable name. */
28
29
  export type ThemeTokens = Record<string, string>;
29
30
  /**
30
31
  * One override-layer token value: both palette modes are mandatory (repeat
@@ -55,8 +56,10 @@ export interface ThemeDefinition {
55
56
  export interface ThemeSnapshot {
56
57
  /** The persisted preference (may be `system`). */
57
58
  preference: ThemePreference;
58
- /** Conversation content font size in px (integer within FONT_SIZE_MIN..FONT_SIZE_MAX). */
59
- fontSize: number;
59
+ /** Integer px font sizes by role, each within its `FONT_SIZE_SPECS` range (`text` is the conversation content size). */
60
+ fontSizes: FontSizes;
61
+ /** Normalized user font lists by role; `''` selects the role's built-in stack. */
62
+ fontFamilies: FontFamilies;
60
63
  /**
61
64
  * The resolved active theme (`system` resolved via prefers-color-scheme)
62
65
  * with override layers folded into its tokens (seq order, later layers win
@@ -111,8 +114,11 @@ export declare class ThemeRuntime {
111
114
  private readonly host;
112
115
  private themes;
113
116
  private preference;
114
- private fontSize;
117
+ private fontSizes;
118
+ private fontFamilies;
115
119
  private revision;
120
+ /** Own settings writes not yet settled; adoption waits for zero so a Host echo of an earlier write cannot revert a later local change. */
121
+ private pendingWrites;
116
122
  private snapshot;
117
123
  private readonly media;
118
124
  /** Override layers by source; seq (monotonic) is the stacking order. */
@@ -142,12 +148,28 @@ export declare class ThemeRuntime {
142
148
  */
143
149
  setTheme(id: string): void;
144
150
  /**
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.
151
+ * Change one role's font size — the only font-size write entry. Accepted
152
+ * values are written through the settings scope and emit `theme/change`.
153
+ * @param role - font role.
154
+ * @param px - integer px within the role's `FONT_SIZE_SPECS` range; out-of-range or fractional values throw.
149
155
  */
150
- setFontSize(px: number): void;
156
+ setFontSize(role: FontRole, px: number): void;
157
+ /**
158
+ * Step all font sizes within their own ranges and save changed fields in one mutation.
159
+ * Emits one `theme/change`; no write or event occurs when every role is at its limit.
160
+ * @param delta - one pixel to add or remove from each role's current size.
161
+ */
162
+ private adjustFontSizes;
163
+ /**
164
+ * Change one role's font list — the only font-family write entry. The value
165
+ * is normalized, written through the settings scope, and emits `theme/change`
166
+ * when the normalized list differs.
167
+ * @param role - font role.
168
+ * @param value - comma-separated family names; a value without names restores the built-in stack.
169
+ */
170
+ setFontFamily(role: FontRole, value: string): void;
171
+ /** Queue one settings write, then adopt the durable section once no own write remains. */
172
+ private write;
151
173
  /** Adopt the scope's accepted durable preference without writing it back. */
152
174
  private adopt;
153
175
  /**
@@ -194,8 +216,8 @@ export declare class ThemeRuntime {
194
216
  export declare const inject: string[];
195
217
  /**
196
218
  * Client plugin body: provide the theme service and register the
197
- * feature-owned Appearance, font-size, and line-spacing preference rows into
198
- * the General section's item slot (a feature owns its settings surface).
219
+ * feature-owned Appearance and font settings rows into the General section's item
220
+ * slot (a feature owns its settings surface).
199
221
  * @param ctx - client cordis context.
200
222
  */
201
223
  export declare function apply(ctx: ClientContext): void;
@@ -1,15 +1,31 @@
1
- /** `settings.theme` namespace dictionaries (the Appearance, font-size, and line-spacing rows' copy). */
1
+ /** `settings.theme` namespace dictionaries (the Appearance and font settings rows' copy). */
2
2
  /** Simplified Chinese dictionary (the key-set source of truth). */
3
3
  export declare const zh: {
4
4
  'appearance.title': string;
5
5
  'appearance.light': string;
6
6
  'appearance.dark': string;
7
7
  'appearance.system': string;
8
- 'fontSize.title': string;
9
- 'fontSize.description': string;
8
+ 'fontSize.text.title': string;
9
+ 'fontSize.text.description': string;
10
+ 'fontSize.text.increase': string;
11
+ 'fontSize.text.decrease': string;
12
+ 'fontSize.code.title': string;
13
+ 'fontSize.code.description': string;
14
+ 'fontSize.code.increase': string;
15
+ 'fontSize.code.decrease': string;
16
+ 'fontSize.terminal.title': string;
17
+ 'fontSize.terminal.description': string;
18
+ 'fontSize.terminal.increase': string;
19
+ 'fontSize.terminal.decrease': string;
10
20
  'fontSize.unit': string;
11
- 'fontSize.increase': string;
12
- 'fontSize.decrease': string;
21
+ 'fontFamily.text.title': string;
22
+ 'fontFamily.text.description': string;
23
+ 'fontFamily.code.title': string;
24
+ 'fontFamily.code.description': string;
25
+ 'fontFamily.terminal.title': string;
26
+ 'fontFamily.terminal.description': string;
27
+ 'fontFamily.placeholder': string;
28
+ 'fontSize.more': string;
13
29
  };
14
30
  /** The settings.theme namespace key union. */
15
31
  export type ThemeKey = keyof typeof zh;
@@ -19,10 +35,26 @@ export declare const en: {
19
35
  'appearance.light': string;
20
36
  'appearance.dark': string;
21
37
  'appearance.system': string;
22
- 'fontSize.title': string;
23
- 'fontSize.description': string;
38
+ 'fontSize.text.title': string;
39
+ 'fontSize.text.description': string;
40
+ 'fontSize.text.increase': string;
41
+ 'fontSize.text.decrease': string;
42
+ 'fontSize.code.title': string;
43
+ 'fontSize.code.description': string;
44
+ 'fontSize.code.increase': string;
45
+ 'fontSize.code.decrease': string;
46
+ 'fontSize.terminal.title': string;
47
+ 'fontSize.terminal.description': string;
48
+ 'fontSize.terminal.increase': string;
49
+ 'fontSize.terminal.decrease': string;
24
50
  'fontSize.unit': string;
25
- 'fontSize.increase': string;
26
- 'fontSize.decrease': string;
51
+ 'fontFamily.text.title': string;
52
+ 'fontFamily.text.description': string;
53
+ 'fontFamily.code.title': string;
54
+ 'fontFamily.code.description': string;
55
+ 'fontFamily.terminal.title': string;
56
+ 'fontFamily.terminal.description': string;
57
+ 'fontFamily.placeholder': string;
58
+ 'fontSize.more': string;
27
59
  };
28
60
  //# sourceMappingURL=locales.d.ts.map
@@ -1,11 +1,11 @@
1
1
  /**
2
- * Appearance and typography settings-row slot stores: mirrors of the theme
3
- * service snapshot. The plugin's apply-world change listener is the only
4
- * writer; the rows read their fields via props.useStore.
2
+ * Appearance and font 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
5
  */
6
6
  import { type EngineStoreHandle } from '@qilin-agent/client-store';
7
- import { type ThemePreference } from '../theme-settings.ts';
8
- /** Store state mirrored from the theme snapshot's appearance preference. */
7
+ import { type FontFamilies, type FontSizes, type ThemePreference } from '../theme-settings.ts';
8
+ /** Store state mirrored from the theme snapshot. */
9
9
  export interface AppearanceRowState {
10
10
  /** Persisted preference (selection state reads this, never the resolved active theme). */
11
11
  preference: ThemePreference;
@@ -21,21 +21,23 @@ type AppearanceRowActions = {
21
21
  * @returns the store handle.
22
22
  */
23
23
  export declare function createAppearanceRowStore(): EngineStoreHandle<AppearanceRowState, AppearanceRowActions>;
24
- /** Store state mirrored from the theme snapshot's typography fields. */
25
- export interface TypographyRowState {
26
- /** Persisted content font size in px. */
27
- fontSize: number;
24
+ /** Store state mirrored from the theme snapshot's fonts (shared by the font-size row and the font settings group). */
25
+ export interface FontRowState {
26
+ /** Persisted font sizes in px by role. */
27
+ fontSizes: FontSizes;
28
+ /** Persisted normalized font lists by role. */
29
+ fontFamilies: FontFamilies;
28
30
  /** Service revision; -1 until first sync so revision 0 lands as a change. */
29
31
  revision: number;
30
32
  }
31
33
  /** Declared action shape giving the exported factory a stable return type. */
32
- type TypographyRowActions = {
33
- sync: (draft: TypographyRowState, fontSize: number, revision: number) => void;
34
+ type FontRowActions = {
35
+ sync: (draft: FontRowState, fontSizes: FontSizes, fontFamilies: FontFamilies, revision: number) => void;
34
36
  };
35
37
  /**
36
- * Declares the shared typography-row state and write surface.
38
+ * Declares the font rows' state and write surface.
37
39
  * @returns the store handle.
38
40
  */
39
- export declare function createTypographyRowStore(): EngineStoreHandle<TypographyRowState, TypographyRowActions>;
41
+ export declare function createFontRowStore(): EngineStoreHandle<FontRowState, FontRowActions>;
40
42
  export {};
41
43
  //# sourceMappingURL=settings-store.d.ts.map