@adea-ai/ui 0.104.3 → 0.106.0

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.
Files changed (191) hide show
  1. package/README.md +44 -8
  2. package/dist/components/composites/action-button/action-button.d.ts.map +1 -1
  3. package/dist/components/composites/action-button/action-button.js +6 -8
  4. package/dist/components/composites/action-button/action-button.js.map +1 -1
  5. package/dist/components/composites/appearance-editor/accent-swatch-groups.d.ts +16 -0
  6. package/dist/components/composites/appearance-editor/accent-swatch-groups.d.ts.map +1 -0
  7. package/dist/components/composites/appearance-editor/accent-swatch-groups.js +151 -0
  8. package/dist/components/composites/appearance-editor/accent-swatch-groups.js.map +1 -0
  9. package/dist/components/composites/appearance-editor/appearance-choices.d.ts.map +1 -1
  10. package/dist/components/composites/appearance-editor/appearance-choices.js +24 -84
  11. package/dist/components/composites/appearance-editor/appearance-choices.js.map +1 -1
  12. package/dist/components/composites/appearance-editor/appearance-editor.d.ts +2 -2
  13. package/dist/components/composites/appearance-editor/appearance-editor.d.ts.map +1 -1
  14. package/dist/components/composites/appearance-editor/appearance-editor.js +25 -7
  15. package/dist/components/composites/appearance-editor/appearance-editor.js.map +1 -1
  16. package/dist/components/composites/appearance-editor/appearance-types.d.ts +9 -0
  17. package/dist/components/composites/appearance-editor/appearance-types.d.ts.map +1 -1
  18. package/dist/components/composites/appearance-editor/font-settings-group.d.ts +10 -0
  19. package/dist/components/composites/appearance-editor/font-settings-group.d.ts.map +1 -0
  20. package/dist/components/composites/appearance-editor/font-settings-group.js +310 -0
  21. package/dist/components/composites/appearance-editor/font-settings-group.js.map +1 -0
  22. package/dist/components/composites/appearance-editor/index.d.ts +2 -0
  23. package/dist/components/composites/appearance-editor/index.d.ts.map +1 -1
  24. package/dist/components/composites/appearance-editor/index.js +3 -1
  25. package/dist/components/composites/update-dialog/update-dialog.js +2 -2
  26. package/dist/components/composites/update-dialog/update-dialog.js.map +1 -1
  27. package/dist/components/conversation/message-row.d.ts.map +1 -1
  28. package/dist/components/conversation/message-row.js +3 -3
  29. package/dist/components/conversation/message-row.js.map +1 -1
  30. package/dist/components/conversation/paste-token-editor.js +1 -1
  31. package/dist/components/conversation/paste-token-editor.js.map +1 -1
  32. package/dist/components/layout/side-rail/side-rail.js +2 -2
  33. package/dist/components/layout/side-rail/side-rail.js.map +1 -1
  34. package/dist/components/layout/top-bar/top-bar.js +1 -1
  35. package/dist/components/layout/top-bar/top-bar.js.map +1 -1
  36. package/dist/components/theme/appearance-panel.d.ts +1 -1
  37. package/dist/components/theme/appearance-panel.d.ts.map +1 -1
  38. package/dist/components/theme/appearance-panel.js +45 -105
  39. package/dist/components/theme/appearance-panel.js.map +1 -1
  40. package/dist/components/theme/theme-provider.d.ts +5 -2
  41. package/dist/components/theme/theme-provider.d.ts.map +1 -1
  42. package/dist/components/theme/theme-provider.js +38 -19
  43. package/dist/components/theme/theme-provider.js.map +1 -1
  44. package/dist/components/ui/code-block/code-block.d.ts +3 -3
  45. package/dist/components/ui/code-block/code-block.js +6 -6
  46. package/dist/components/ui/code-block/code-block.js.map +1 -1
  47. package/dist/components/ui/command/command.js +1 -1
  48. package/dist/components/ui/command/command.js.map +1 -1
  49. package/dist/components/ui/context-menu/context-menu.js +1 -1
  50. package/dist/components/ui/context-menu/context-menu.js.map +1 -1
  51. package/dist/components/ui/diff-block/diff-block.js +5 -5
  52. package/dist/components/ui/diff-block/diff-block.js.map +1 -1
  53. package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts.map +1 -1
  54. package/dist/components/ui/dropdown-menu/dropdown-menu.js +101 -8
  55. package/dist/components/ui/dropdown-menu/dropdown-menu.js.map +1 -1
  56. package/dist/components/ui/kbd/index.d.ts +1 -1
  57. package/dist/components/ui/kbd/index.d.ts.map +1 -1
  58. package/dist/components/ui/kbd/index.js +2 -2
  59. package/dist/components/ui/kbd/kbd.d.ts +40 -2
  60. package/dist/components/ui/kbd/kbd.d.ts.map +1 -1
  61. package/dist/components/ui/kbd/kbd.js +74 -7
  62. package/dist/components/ui/kbd/kbd.js.map +1 -1
  63. package/dist/components/ui/menubar/menubar.js +1 -1
  64. package/dist/components/ui/menubar/menubar.js.map +1 -1
  65. package/dist/components/ui/typography/typography.d.ts +3 -5
  66. package/dist/components/ui/typography/typography.d.ts.map +1 -1
  67. package/dist/components/ui/typography/typography.js +6 -8
  68. package/dist/components/ui/typography/typography.js.map +1 -1
  69. package/dist/index.js +7 -4
  70. package/dist/lib/appearance-font-settings.d.ts +53 -0
  71. package/dist/lib/appearance-font-settings.d.ts.map +1 -0
  72. package/dist/lib/appearance-font-settings.js +160 -0
  73. package/dist/lib/appearance-font-settings.js.map +1 -0
  74. package/dist/lib/font-catalog.d.ts +72 -0
  75. package/dist/lib/font-catalog.d.ts.map +1 -0
  76. package/dist/lib/font-catalog.js +71 -0
  77. package/dist/lib/font-catalog.js.map +1 -0
  78. package/dist/lib/safe-script.d.ts +3 -0
  79. package/dist/lib/safe-script.d.ts.map +1 -0
  80. package/dist/lib/safe-script.js +9 -0
  81. package/dist/lib/safe-script.js.map +1 -0
  82. package/dist/lib/tokens.d.ts +2 -19
  83. package/dist/lib/tokens.d.ts.map +1 -1
  84. package/dist/lib/tokens.js +63 -39
  85. package/dist/lib/tokens.js.map +1 -1
  86. package/dist/r/about-dialog.json +1 -1
  87. package/dist/r/accordion.json +1 -1
  88. package/dist/r/account-menu.json +1 -1
  89. package/dist/r/alert.json +1 -1
  90. package/dist/r/appearance-editor.json +13 -2
  91. package/dist/r/breadcrumb.json +1 -1
  92. package/dist/r/calendar.json +1 -1
  93. package/dist/r/carousel.json +1 -1
  94. package/dist/r/catalog-browser.json +1 -1
  95. package/dist/r/checkbox.json +1 -1
  96. package/dist/r/code-block.json +1 -1
  97. package/dist/r/combobox.json +1 -1
  98. package/dist/r/command.json +1 -1
  99. package/dist/r/context-menu.json +1 -1
  100. package/dist/r/conversation.json +1 -1
  101. package/dist/r/detail-panel.json +1 -1
  102. package/dist/r/dialog.json +1 -1
  103. package/dist/r/dropdown-menu.json +1 -1
  104. package/dist/r/empty.json +1 -1
  105. package/dist/r/floating-preview.json +1 -1
  106. package/dist/r/help-center.json +1 -1
  107. package/dist/r/lib.json +16 -1
  108. package/dist/r/menubar.json +1 -1
  109. package/dist/r/native-select.json +1 -1
  110. package/dist/r/navigation-menu.json +1 -1
  111. package/dist/r/pagination.json +1 -1
  112. package/dist/r/radio-group.json +1 -1
  113. package/dist/r/registry.json +75 -42
  114. package/dist/r/resizable.json +1 -1
  115. package/dist/r/scene-controls.json +1 -1
  116. package/dist/r/select.json +1 -1
  117. package/dist/r/sheet.json +1 -1
  118. package/dist/r/sidebar-nav.json +1 -1
  119. package/dist/r/spinner.json +1 -1
  120. package/dist/r/split-layout.json +1 -1
  121. package/dist/r/src/components/composites/action-button/action-button.tsx +2 -1
  122. package/dist/r/src/components/composites/appearance-editor/accent-swatch-groups.tsx +147 -0
  123. package/dist/r/src/components/composites/appearance-editor/appearance-choices.tsx +17 -74
  124. package/dist/r/src/components/composites/appearance-editor/appearance-editor.tsx +19 -6
  125. package/dist/r/src/components/composites/appearance-editor/appearance-types.ts +9 -0
  126. package/dist/r/src/components/composites/appearance-editor/font-settings-group.tsx +350 -0
  127. package/dist/r/src/components/composites/appearance-editor/index.ts +19 -0
  128. package/dist/r/src/components/composites/update-dialog/update-dialog.tsx +2 -2
  129. package/dist/r/src/components/conversation/message-row.tsx +7 -3
  130. package/dist/r/src/components/conversation/paste-token-editor.tsx +1 -1
  131. package/dist/r/src/components/layout/side-rail/side-rail.tsx +3 -3
  132. package/dist/r/src/components/layout/top-bar/top-bar.tsx +1 -1
  133. package/dist/r/src/components/theme/appearance-panel.tsx +34 -83
  134. package/dist/r/src/components/theme/theme-provider.tsx +50 -20
  135. package/dist/r/src/components/ui/code-block/code-block.tsx +6 -6
  136. package/dist/r/src/components/ui/command/command.tsx +1 -1
  137. package/dist/r/src/components/ui/context-menu/context-menu.tsx +1 -1
  138. package/dist/r/src/components/ui/diff-block/diff-block.tsx +7 -7
  139. package/dist/r/src/components/ui/dropdown-menu/dropdown-menu.tsx +145 -7
  140. package/dist/r/src/components/ui/kbd/index.ts +10 -1
  141. package/dist/r/src/components/ui/kbd/kbd.tsx +77 -14
  142. package/dist/r/src/components/ui/menubar/menubar.tsx +1 -1
  143. package/dist/r/src/components/ui/typography/typography.tsx +6 -8
  144. package/dist/r/src/lib/appearance-font-settings.ts +233 -0
  145. package/dist/r/src/lib/font-catalog.ts +80 -0
  146. package/dist/r/src/lib/safe-script.ts +7 -0
  147. package/dist/r/src/lib/tokens.ts +64 -59
  148. package/dist/r/src/styles/appearance-font-settings.css +110 -0
  149. package/dist/r/src/styles/fonts.css +4 -5
  150. package/dist/r/src/styles/globals.css +4 -1
  151. package/dist/r/src/styles/theme.css +14 -0
  152. package/dist/r/stat.json +1 -1
  153. package/dist/r/theme.json +5 -0
  154. package/dist/r/theming.json +4 -2
  155. package/dist/r/toast.json +1 -1
  156. package/dist/r/top-bar.json +1 -1
  157. package/dist/r/tree.json +1 -1
  158. package/dist/r/update-dialog.json +1 -1
  159. package/package.json +7 -6
  160. package/registry.json +75 -42
  161. package/src/components/composites/action-button/action-button.tsx +2 -1
  162. package/src/components/composites/appearance-editor/accent-swatch-groups.tsx +147 -0
  163. package/src/components/composites/appearance-editor/appearance-choices.tsx +17 -74
  164. package/src/components/composites/appearance-editor/appearance-editor.tsx +19 -6
  165. package/src/components/composites/appearance-editor/appearance-types.ts +9 -0
  166. package/src/components/composites/appearance-editor/font-settings-group.tsx +350 -0
  167. package/src/components/composites/appearance-editor/index.ts +19 -0
  168. package/src/components/composites/update-dialog/update-dialog.tsx +2 -2
  169. package/src/components/conversation/message-row.tsx +7 -3
  170. package/src/components/conversation/paste-token-editor.tsx +1 -1
  171. package/src/components/layout/side-rail/side-rail.tsx +3 -3
  172. package/src/components/layout/top-bar/top-bar.tsx +1 -1
  173. package/src/components/theme/appearance-panel.tsx +34 -83
  174. package/src/components/theme/theme-provider.tsx +50 -20
  175. package/src/components/ui/code-block/code-block.tsx +6 -6
  176. package/src/components/ui/command/command.tsx +1 -1
  177. package/src/components/ui/context-menu/context-menu.tsx +1 -1
  178. package/src/components/ui/diff-block/diff-block.tsx +7 -7
  179. package/src/components/ui/dropdown-menu/dropdown-menu.tsx +145 -7
  180. package/src/components/ui/kbd/index.ts +10 -1
  181. package/src/components/ui/kbd/kbd.tsx +77 -14
  182. package/src/components/ui/menubar/menubar.tsx +1 -1
  183. package/src/components/ui/typography/typography.tsx +6 -8
  184. package/src/lib/appearance-font-settings.ts +233 -0
  185. package/src/lib/font-catalog.ts +80 -0
  186. package/src/lib/safe-script.ts +7 -0
  187. package/src/lib/tokens.ts +64 -59
  188. package/src/styles/appearance-font-settings.css +110 -0
  189. package/src/styles/fonts.css +4 -5
  190. package/src/styles/globals.css +4 -1
  191. package/src/styles/theme.css +14 -0
@@ -3,25 +3,27 @@ import { Button } from "../../ui/button/button.js";
3
3
  import { Input } from "../../ui/input/input.js";
4
4
  import { Popover, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger } from "../../ui/popover/popover.js";
5
5
  import { Switch } from "../../ui/switch/switch.js";
6
- import { AccentChoices, GlassChoices, ModeChoices, isCustomAccent } from "./appearance-choices.js";
6
+ import { DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS } from "../../../lib/appearance-font-settings.js";
7
7
  import { SettingsRow, TerminalRow, ThemeRow } from "./appearance-rows.js";
8
- import { className, createComponent, effect, insert, memo, setAttribute, template } from "solid-js/web";
8
+ import { AppearanceFontSettingsGroup } from "./font-settings-group.js";
9
+ import { AccentChoices, GlassChoices, ModeChoices, isCustomAccent } from "./appearance-choices.js";
10
+ import { className, createComponent, effect, insert, memo, mergeProps, setAttribute, template } from "solid-js/web";
9
11
  import { EyeOff, Palette, PanelsTopLeft, SlidersHorizontal } from "lucide-solid";
10
- import { Show, createUniqueId } from "solid-js";
12
+ import { Show, createSignal, createUniqueId } from "solid-js";
11
13
  //#region src/components/composites/appearance-editor/appearance-editor.tsx
12
14
  var _tmpl$ = /*#__PURE__*/ template(`<p role=status class="px-4 py-2 text-sm text-muted-foreground">`);
13
15
  var _tmpl$2 = /*#__PURE__*/ template(`<p role=alert class="mt-1 text-xs text-foreground">`);
14
16
  var _tmpl$3 = /*#__PURE__*/ template(`<div class="px-4 py-3"><label class="mb-2 block text-xs font-medium">Custom accent`);
15
17
  var _tmpl$4 = /*#__PURE__*/ template(`<p role=status class="px-4 py-2 text-xs text-muted-foreground">`);
16
18
  var _tmpl$5 = /*#__PURE__*/ template(`<p role=status class="px-4 pt-3 text-xs text-muted-foreground">`);
17
- var _tmpl$6 = /*#__PURE__*/ template(`<div data-appearance-editor><div class="divide-y divide-border rounded-lg border"></div><div class="sticky bottom-0 z-10 mt-2 flex flex-wrap items-center gap-2 border-t bg-background px-4 py-3"><div class="ml-auto flex gap-2">`);
19
+ var _tmpl$6 = /*#__PURE__*/ template(`<div data-appearance-editor><div class="divide-y divide-border rounded-lg border"></div><div class="global-appearance-editor-actions sticky bottom-0 z-10 mt-2 flex flex-wrap items-center gap-2 border-t bg-background px-4 py-3"><div class="ml-auto flex gap-2">`);
18
20
  /**
19
21
  * A live editor whose persistence and preview authority belong to its host.
20
22
  * No ThemeProvider is required, and no catalogue, renderer engine or storage is
21
23
  * imported. Hosts normalize unknown IDs and custom colors, report recovery,
22
24
  * snapshot on open, preview on changes, commit on Save, and restore on dismissal.
23
- * Both theme rows remain mounted when mode changes. Typeface/density axes are
24
- * deliberately absent from Adea #425's accepted surface.
25
+ * Both theme rows remain mounted when mode changes. Density remains outside the
26
+ * accepted appearance surface; typeface settings are shared and host-persisted.
25
27
  */
26
28
  function AppearanceEditor(props) {
27
29
  const errorId = createUniqueId();
@@ -152,6 +154,18 @@ function AppearanceEditor(props) {
152
154
  return _el$4;
153
155
  }
154
156
  }), null);
157
+ insert(_el$3, createComponent(AppearanceFontSettingsGroup, {
158
+ get settings() {
159
+ return props.draft.fonts ?? DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS;
160
+ },
161
+ get menuPortalMount() {
162
+ return props.menuPortalMount;
163
+ },
164
+ get disabled() {
165
+ return props.saving;
166
+ },
167
+ onChange: (fonts) => props.onChange({ fonts })
168
+ }), null);
155
169
  insert(_el$3, createComponent(SettingsRow, {
156
170
  title: "Glass",
157
171
  get icon() {
@@ -270,6 +284,7 @@ function AppearanceEditor(props) {
270
284
  * Its measured available height also bounds scrolling, keeping footer actions
271
285
  * reachable when a narrow popup begins below its trigger. */
272
286
  function AppearancePopover(props) {
287
+ const [menuPortalMount, setMenuPortalMount] = createSignal();
273
288
  return createComponent(Popover, {
274
289
  get open() {
275
290
  return props.open;
@@ -287,12 +302,15 @@ function AppearancePopover(props) {
287
302
  return createComponent(Palette, {});
288
303
  }
289
304
  }), createComponent(PopoverContent, {
305
+ ref: setMenuPortalMount,
290
306
  "class": "w-lg max-w-[calc(100vw-2rem)] max-h-(--kb-popper-content-available-height) overflow-y-auto",
291
307
  get children() {
292
308
  return [
293
309
  createComponent(PopoverTitle, { children: "Appearance" }),
294
310
  createComponent(PopoverDescription, { children: "Changes preview immediately. Save keeps them; Cancel restores the previous appearance." }),
295
- createComponent(AppearanceEditor, props)
311
+ createComponent(AppearanceEditor, mergeProps(props, { get menuPortalMount() {
312
+ return menuPortalMount();
313
+ } }))
296
314
  ];
297
315
  }
298
316
  })];
@@ -1 +1 @@
1
- {"version":3,"file":"appearance-editor.js","names":["EyeOff","Palette","PanelsTopLeft","SlidersHorizontal","Show","createUniqueId","cn","Button","Input","Switch","Popover","PopoverContent","PopoverDescription","PopoverTitle","PopoverTrigger","AppearanceEditorProps","AppearancePopoverProps","ModeChoices","AccentChoices","GlassChoices","isCustomAccent","SettingsRow","TerminalRow","ThemeRow","AppearanceEditor","props","errorId","saveReasonId","custom","accentDescription","draft","accent","preset","accentOptions","find","option","id","label","offered","themeAccentOptions","toLowerCase","glassDescription","surface","surfaceCapability","themeDefaultDescription","_el$","_tmpl$6","_el$3","firstChild","_el$9","nextSibling","_el$0","_$insert","_$createComponent","when","recoveryNotice","children","_el$2","_tmpl$","appearance","selectedId","lightThemeId","preview","lightTheme","themes","disabled","saving","onSelect","onChange","darkThemeId","darkTheme","terminalThemeId","undefined","_$memo","resolvedAppearance","title","icon","description","_el$4","_tmpl$3","_el$5","_$setAttribute","value","aria-invalid","customAccentError","aria-describedby","onInput","event","currentTarget","_el$6","_tmpl$2","frosted","reason","_el$7","_tmpl$4","checked","reduceTransparency","onManageThemes","type","size","variant","onClick","saveDisabledReason","_el$8","_tmpl$5","onReset","onCancel","aria-busy","onSave","_$effect","_$className","class","AppearancePopover","open","modal","onOpenChange","onOpen","onDismiss","as","_$createComponent","_$memo","_$className"],"sources":["../../../../src/components/composites/appearance-editor/appearance-editor.tsx"],"sourcesContent":["/*\n * MIT License\n *\n * Copyright (c) 2026 Wing\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n/*\n * Composition substantially translated from Zeron settings/appearance.rs and\n * settings/widgets.rs, pinned at 30a9a9537c5ec96226c87f4bf349b6f77c5dfb59,\n * preserving Adea's existing appearance-surface.tsx port: System/Light/Dark\n * miniatures, compact independent theme rows, accent swatches and helper copy,\n * glass chips, and theme library affordance. Kobalte replaces the port's manual\n * radio keyboard model. The controlled draft and explicit action ports replace\n * GPUI globals and app-specific storage/native authority. Save/Cancel/Reset and\n * custom accent/reduced-transparency are accepted Adea divergences (#425).\n */\nimport { EyeOff, Palette, PanelsTopLeft, SlidersHorizontal } from 'lucide-solid'\nimport { Show, createUniqueId } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport { Button } from '../../ui/button/button'\nimport { Input } from '../../ui/input/input'\n\nimport { Switch } from '../../ui/switch/switch'\nimport {\n Popover,\n PopoverContent,\n PopoverDescription,\n PopoverTitle,\n PopoverTrigger,\n} from '../../ui/popover/popover'\nimport type { AppearanceEditorProps, AppearancePopoverProps } from './appearance-types'\nimport { ModeChoices, AccentChoices, GlassChoices, isCustomAccent } from './appearance-choices'\nimport { SettingsRow, TerminalRow, ThemeRow } from './appearance-rows'\n\n/**\n * A live editor whose persistence and preview authority belong to its host.\n * No ThemeProvider is required, and no catalogue, renderer engine or storage is\n * imported. Hosts normalize unknown IDs and custom colors, report recovery,\n * snapshot on open, preview on changes, commit on Save, and restore on dismissal.\n * Both theme rows remain mounted when mode changes. Typeface/density axes are\n * deliberately absent from Adea #425's accepted surface.\n */\nexport function AppearanceEditor(props: AppearanceEditorProps) {\n const errorId = createUniqueId()\n const saveReasonId = createUniqueId()\n const custom = () => isCustomAccent(props)\n const accentDescription = () => {\n if (props.draft.accent === 'theme') return \"Theme default · Uses the palette's intended color.\"\n const preset = props.accentOptions.find((option) => option.id === props.draft.accent)\n if (preset) return `${preset.label} · Controls, glyphs, selections, code, and activity.`\n if (custom()) return 'Custom · Controls, glyphs, selections, code, and activity.'\n const offered = props.themeAccentOptions?.find((option) => option.id === props.draft.accent)\n // A stored theme accent survives a theme switch by id; when the new pair\n // cannot offer that slot the host falls back to the theme's own primary,\n // and the description says so rather than naming a colour not on screen.\n return offered\n ? `Theme ${offered.label.toLowerCase()} · The theme's own color, on controls and activity.`\n : \"Theme default · This theme does not carry that accent, so it uses the palette's intended color.\"\n }\n const glassDescription = () =>\n props.draft.surface === 'opaque'\n ? 'Solid surfaces for every theme.'\n : props.draft.surface === 'frosted'\n ? 'Theme-colored glass where supported.'\n : (props.surfaceCapability.themeDefaultDescription ?? \"Uses this theme's default surface.\")\n return (\n <div data-appearance-editor class={cn('min-w-0', props.class)}>\n <Show when={props.recoveryNotice}>\n <p role=\"status\" class=\"px-4 py-2 text-sm text-muted-foreground\">\n {props.recoveryNotice}\n </p>\n </Show>\n <ModeChoices {...props} />\n <div class=\"divide-y divide-border rounded-lg border\">\n <ThemeRow\n appearance=\"light\"\n selectedId={props.draft.lightThemeId}\n preview={props.lightTheme}\n themes={props.themes}\n disabled={props.saving}\n onSelect={(lightThemeId) => props.onChange({ lightThemeId })}\n />\n <ThemeRow\n appearance=\"dark\"\n selectedId={props.draft.darkThemeId}\n preview={props.darkTheme}\n themes={props.themes}\n disabled={props.saving}\n onSelect={(darkThemeId) => props.onChange({ darkThemeId })}\n />\n {/* The row exists only when the host carries a terminal preference:\n the draft field is the show/hide switch, so the editor can never\n render a terminal row that writes nothing. */}\n <Show when={props.draft.terminalThemeId !== undefined}>\n <TerminalRow\n selectedId={props.draft.terminalThemeId ?? 'theme'}\n preview={props.resolvedAppearance === 'dark' ? props.darkTheme : props.lightTheme}\n themes={props.themes}\n disabled={props.saving}\n onSelect={(terminalThemeId) => props.onChange({ terminalThemeId })}\n />\n </Show>\n <SettingsRow title=\"Accent\" icon={<SlidersHorizontal />} description={accentDescription()}>\n <AccentChoices {...props} />\n </SettingsRow>\n <Show when={custom()}>\n <div class=\"px-4 py-3\">\n <label class=\"mb-2 block text-xs font-medium\" for={`${errorId}-input`}>\n Custom accent\n </label>\n <Input\n id={`${errorId}-input`}\n value={props.draft.accent}\n disabled={props.saving}\n aria-invalid={!!props.customAccentError}\n aria-describedby={props.customAccentError ? errorId : undefined}\n onInput={(event) => props.onChange({ accent: event.currentTarget.value })}\n />\n <Show when={props.customAccentError}>\n <p id={errorId} role=\"alert\" class=\"mt-1 text-xs text-foreground\">\n {props.customAccentError}\n </p>\n </Show>\n </div>\n </Show>\n <SettingsRow title=\"Glass\" icon={<PanelsTopLeft />} description={glassDescription()}>\n <GlassChoices {...props} />\n </SettingsRow>\n <Show when={!props.surfaceCapability.frosted && props.surfaceCapability.reason}>\n <p role=\"status\" class=\"px-4 py-2 text-xs text-muted-foreground\">\n {props.surfaceCapability.reason}\n </p>\n </Show>\n <SettingsRow\n title=\"Reduce transparency\"\n icon={<EyeOff />}\n description=\"Prefer solid surfaces, including during live preview.\"\n >\n <Switch\n checked={props.draft.reduceTransparency}\n disabled={props.saving}\n onChange={(reduceTransparency: boolean) => props.onChange({ reduceTransparency })}\n aria-label=\"Reduce transparency\"\n />\n </SettingsRow>\n <SettingsRow\n title=\"Theme library\"\n icon={<Palette />}\n description={\n props.onManageThemes\n ? 'Manage themes through the application.'\n : 'Theme import is unavailable.'\n }\n >\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={!props.onManageThemes || props.saving}\n onClick={() => props.onManageThemes?.()}\n >\n Manage themes\n </Button>\n </SettingsRow>\n </div>\n <Show when={props.saveDisabledReason}>\n <p id={saveReasonId} role=\"status\" class=\"px-4 pt-3 text-xs text-muted-foreground\">\n {props.saveDisabledReason}\n </p>\n </Show>\n {/* Sticky so Save/Cancel stay reachable in a tall scroll container: the\n editor scrolls with its host panel, and actions parked at the bottom\n of a long form were unreachable without scrolling past every row. */}\n <div class=\"sticky bottom-0 z-10 mt-2 flex flex-wrap items-center gap-2 border-t bg-background px-4 py-3\">\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n disabled={props.saving}\n onClick={() => props.onReset()}\n >\n Reset\n </Button>\n <div class=\"ml-auto flex gap-2\">\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={props.saving}\n onClick={() => props.onCancel()}\n >\n Cancel\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={props.saving || !!props.customAccentError || !!props.saveDisabledReason}\n aria-busy={props.saving}\n aria-describedby={props.saveDisabledReason ? saveReasonId : undefined}\n onClick={() => props.onSave()}\n >\n {props.saving ? 'Saving…' : 'Save'}\n </Button>\n </div>\n </div>\n </div>\n )\n}\n\n/** Modal anchoring/dismissal and nested-menu behavior come from Kobalte.\n * Its measured available height also bounds scrolling, keeping footer actions\n * reachable when a narrow popup begins below its trigger. */\nexport function AppearancePopover(props: AppearancePopoverProps) {\n return (\n <Popover\n open={props.open}\n modal\n onOpenChange={(open) => (open ? props.onOpen() : props.onDismiss())}\n >\n <PopoverTrigger\n as={Button}\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label=\"Appearance settings\"\n >\n <Palette />\n </PopoverTrigger>\n <PopoverContent class=\"w-lg max-w-[calc(100vw-2rem)] max-h-(--kb-popper-content-available-height) overflow-y-auto\">\n <PopoverTitle>Appearance</PopoverTitle>\n <PopoverDescription>\n Changes preview immediately. Save keeps them; Cancel restores the previous appearance.\n </PopoverDescription>\n <AppearanceEditor {...props} />\n </PopoverContent>\n </Popover>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"appearance-editor.js","names":["EyeOff","Palette","PanelsTopLeft","SlidersHorizontal","Show","createSignal","createUniqueId","cn","Button","Input","AppearanceFontSettingsGroup","DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS","Switch","Popover","PopoverContent","PopoverDescription","PopoverTitle","PopoverTrigger","AppearanceEditorProps","AppearancePopoverProps","ModeChoices","AccentChoices","GlassChoices","isCustomAccent","SettingsRow","TerminalRow","ThemeRow","AppearanceEditor","props","errorId","saveReasonId","custom","accentDescription","draft","accent","preset","accentOptions","find","option","id","label","offered","themeAccentOptions","toLowerCase","glassDescription","surface","surfaceCapability","themeDefaultDescription","_el$","_tmpl$6","_el$3","firstChild","_el$9","nextSibling","_el$0","_$insert","_$createComponent","when","recoveryNotice","children","_el$2","_tmpl$","appearance","selectedId","lightThemeId","preview","lightTheme","themes","disabled","saving","onSelect","onChange","darkThemeId","darkTheme","terminalThemeId","undefined","_$memo","resolvedAppearance","title","icon","description","_el$4","_tmpl$3","_el$5","_$setAttribute","value","aria-invalid","customAccentError","aria-describedby","onInput","event","currentTarget","_el$6","_tmpl$2","settings","fonts","menuPortalMount","frosted","reason","_el$7","_tmpl$4","checked","reduceTransparency","onManageThemes","type","size","variant","onClick","saveDisabledReason","_el$8","_tmpl$5","onReset","onCancel","aria-busy","onSave","_$effect","_$className","class","AppearancePopover","setMenuPortalMount","HTMLElement","open","modal","onOpenChange","onOpen","onDismiss","as","ref","_$mergeProps","_$createComponent","_$memo","_$className","_$mergeProps"],"sources":["../../../../src/components/composites/appearance-editor/appearance-editor.tsx"],"sourcesContent":["/*\n * MIT License\n *\n * Copyright (c) 2026 Wing\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n/*\n * Composition substantially translated from Zeron settings/appearance.rs and\n * settings/widgets.rs, pinned at 30a9a9537c5ec96226c87f4bf349b6f77c5dfb59,\n * preserving Adea's existing appearance-surface.tsx port: System/Light/Dark\n * miniatures, compact independent theme rows, accent swatches and helper copy,\n * glass chips, and theme library affordance. Kobalte replaces the port's manual\n * radio keyboard model. The controlled draft and explicit action ports replace\n * GPUI globals and app-specific storage/native authority. Save/Cancel/Reset and\n * custom accent/reduced-transparency are accepted Adea divergences (#425).\n */\nimport { EyeOff, Palette, PanelsTopLeft, SlidersHorizontal } from 'lucide-solid'\nimport { Show, createSignal, createUniqueId } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport { Button } from '../../ui/button/button'\nimport { Input } from '../../ui/input/input'\nimport { AppearanceFontSettingsGroup } from './font-settings-group'\nimport { DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS } from '#lib/appearance-font-settings'\n\nimport { Switch } from '../../ui/switch/switch'\nimport {\n Popover,\n PopoverContent,\n PopoverDescription,\n PopoverTitle,\n PopoverTrigger,\n} from '../../ui/popover/popover'\nimport type { AppearanceEditorProps, AppearancePopoverProps } from './appearance-types'\nimport { ModeChoices, AccentChoices, GlassChoices, isCustomAccent } from './appearance-choices'\nimport { SettingsRow, TerminalRow, ThemeRow } from './appearance-rows'\n\n/**\n * A live editor whose persistence and preview authority belong to its host.\n * No ThemeProvider is required, and no catalogue, renderer engine or storage is\n * imported. Hosts normalize unknown IDs and custom colors, report recovery,\n * snapshot on open, preview on changes, commit on Save, and restore on dismissal.\n * Both theme rows remain mounted when mode changes. Density remains outside the\n * accepted appearance surface; typeface settings are shared and host-persisted.\n */\nexport function AppearanceEditor(props: AppearanceEditorProps) {\n const errorId = createUniqueId()\n const saveReasonId = createUniqueId()\n const custom = () => isCustomAccent(props)\n const accentDescription = () => {\n if (props.draft.accent === 'theme') return \"Theme default · Uses the palette's intended color.\"\n const preset = props.accentOptions.find((option) => option.id === props.draft.accent)\n if (preset) return `${preset.label} · Controls, glyphs, selections, code, and activity.`\n if (custom()) return 'Custom · Controls, glyphs, selections, code, and activity.'\n const offered = props.themeAccentOptions?.find((option) => option.id === props.draft.accent)\n // A stored theme accent survives a theme switch by id; when the new pair\n // cannot offer that slot the host falls back to the theme's own primary,\n // and the description says so rather than naming a colour not on screen.\n return offered\n ? `Theme ${offered.label.toLowerCase()} · The theme's own color, on controls and activity.`\n : \"Theme default · This theme does not carry that accent, so it uses the palette's intended color.\"\n }\n const glassDescription = () =>\n props.draft.surface === 'opaque'\n ? 'Solid surfaces for every theme.'\n : props.draft.surface === 'frosted'\n ? 'Theme-colored glass where supported.'\n : (props.surfaceCapability.themeDefaultDescription ?? \"Uses this theme's default surface.\")\n return (\n <div data-appearance-editor class={cn('min-w-0', props.class)}>\n <Show when={props.recoveryNotice}>\n <p role=\"status\" class=\"px-4 py-2 text-sm text-muted-foreground\">\n {props.recoveryNotice}\n </p>\n </Show>\n <ModeChoices {...props} />\n <div class=\"divide-y divide-border rounded-lg border\">\n <ThemeRow\n appearance=\"light\"\n selectedId={props.draft.lightThemeId}\n preview={props.lightTheme}\n themes={props.themes}\n disabled={props.saving}\n onSelect={(lightThemeId) => props.onChange({ lightThemeId })}\n />\n <ThemeRow\n appearance=\"dark\"\n selectedId={props.draft.darkThemeId}\n preview={props.darkTheme}\n themes={props.themes}\n disabled={props.saving}\n onSelect={(darkThemeId) => props.onChange({ darkThemeId })}\n />\n {/* The row exists only when the host carries a terminal preference:\n the draft field is the show/hide switch, so the editor can never\n render a terminal row that writes nothing. */}\n <Show when={props.draft.terminalThemeId !== undefined}>\n <TerminalRow\n selectedId={props.draft.terminalThemeId ?? 'theme'}\n preview={props.resolvedAppearance === 'dark' ? props.darkTheme : props.lightTheme}\n themes={props.themes}\n disabled={props.saving}\n onSelect={(terminalThemeId) => props.onChange({ terminalThemeId })}\n />\n </Show>\n <SettingsRow title=\"Accent\" icon={<SlidersHorizontal />} description={accentDescription()}>\n <AccentChoices {...props} />\n </SettingsRow>\n <Show when={custom()}>\n <div class=\"px-4 py-3\">\n <label class=\"mb-2 block text-xs font-medium\" for={`${errorId}-input`}>\n Custom accent\n </label>\n <Input\n id={`${errorId}-input`}\n value={props.draft.accent}\n disabled={props.saving}\n aria-invalid={!!props.customAccentError}\n aria-describedby={props.customAccentError ? errorId : undefined}\n onInput={(event) => props.onChange({ accent: event.currentTarget.value })}\n />\n <Show when={props.customAccentError}>\n <p id={errorId} role=\"alert\" class=\"mt-1 text-xs text-foreground\">\n {props.customAccentError}\n </p>\n </Show>\n </div>\n </Show>\n <AppearanceFontSettingsGroup\n settings={props.draft.fonts ?? DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS}\n menuPortalMount={props.menuPortalMount}\n disabled={props.saving}\n onChange={(fonts) => props.onChange({ fonts })}\n />\n <SettingsRow title=\"Glass\" icon={<PanelsTopLeft />} description={glassDescription()}>\n <GlassChoices {...props} />\n </SettingsRow>\n <Show when={!props.surfaceCapability.frosted && props.surfaceCapability.reason}>\n <p role=\"status\" class=\"px-4 py-2 text-xs text-muted-foreground\">\n {props.surfaceCapability.reason}\n </p>\n </Show>\n <SettingsRow\n title=\"Reduce transparency\"\n icon={<EyeOff />}\n description=\"Prefer solid surfaces, including during live preview.\"\n >\n <Switch\n checked={props.draft.reduceTransparency}\n disabled={props.saving}\n onChange={(reduceTransparency: boolean) => props.onChange({ reduceTransparency })}\n aria-label=\"Reduce transparency\"\n />\n </SettingsRow>\n <SettingsRow\n title=\"Theme library\"\n icon={<Palette />}\n description={\n props.onManageThemes\n ? 'Manage themes through the application.'\n : 'Theme import is unavailable.'\n }\n >\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={!props.onManageThemes || props.saving}\n onClick={() => props.onManageThemes?.()}\n >\n Manage themes\n </Button>\n </SettingsRow>\n </div>\n <Show when={props.saveDisabledReason}>\n <p id={saveReasonId} role=\"status\" class=\"px-4 pt-3 text-xs text-muted-foreground\">\n {props.saveDisabledReason}\n </p>\n </Show>\n {/* Sticky so Save/Cancel stay reachable in a tall scroll container: the\n editor scrolls with its host panel, and actions parked at the bottom\n of a long form were unreachable without scrolling past every row. */}\n <div class=\"global-appearance-editor-actions sticky bottom-0 z-10 mt-2 flex flex-wrap items-center gap-2 border-t bg-background px-4 py-3\">\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n disabled={props.saving}\n onClick={() => props.onReset()}\n >\n Reset\n </Button>\n <div class=\"ml-auto flex gap-2\">\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={props.saving}\n onClick={() => props.onCancel()}\n >\n Cancel\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={props.saving || !!props.customAccentError || !!props.saveDisabledReason}\n aria-busy={props.saving}\n aria-describedby={props.saveDisabledReason ? saveReasonId : undefined}\n onClick={() => props.onSave()}\n >\n {props.saving ? 'Saving…' : 'Save'}\n </Button>\n </div>\n </div>\n </div>\n )\n}\n\n/** Modal anchoring/dismissal and nested-menu behavior come from Kobalte.\n * Its measured available height also bounds scrolling, keeping footer actions\n * reachable when a narrow popup begins below its trigger. */\nexport function AppearancePopover(props: AppearancePopoverProps) {\n const [menuPortalMount, setMenuPortalMount] = createSignal<HTMLElement>()\n\n return (\n <Popover\n open={props.open}\n modal\n onOpenChange={(open) => (open ? props.onOpen() : props.onDismiss())}\n >\n <PopoverTrigger\n as={Button}\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label=\"Appearance settings\"\n >\n <Palette />\n </PopoverTrigger>\n <PopoverContent\n ref={setMenuPortalMount}\n class=\"w-lg max-w-[calc(100vw-2rem)] max-h-(--kb-popper-content-available-height) overflow-y-auto\"\n >\n <PopoverTitle>Appearance</PopoverTitle>\n <PopoverDescription>\n Changes preview immediately. Save keeps them; Cancel restores the previous appearance.\n </PopoverDescription>\n <AppearanceEditor {...props} menuPortalMount={menuPortalMount()} />\n </PopoverContent>\n </Popover>\n )\n}\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { AccentPreset, AdeaTheme, AdeaThemeRecord } from '@adea-ai/themes';
2
+ import type { AppearanceEditorFontSettings } from '#lib/appearance-font-settings';
2
3
  export type AppearanceDraft = Readonly<{
3
4
  mode: 'system' | 'light' | 'dark';
4
5
  lightThemeId: string;
@@ -12,6 +13,12 @@ export type AppearanceDraft = Readonly<{
12
13
  terminalThemeId?: string;
13
14
  /** Theme default, a canonical preset id, or the host's custom accent draft. */
14
15
  accent: string;
16
+ /**
17
+ * The UI, content and code typeface axes. Optional for compatibility with
18
+ * hosts upgrading from the earlier appearance contract; omitted means the
19
+ * shared System defaults.
20
+ */
21
+ fonts?: AppearanceEditorFontSettings;
15
22
  surface: 'theme' | 'frosted' | 'opaque';
16
23
  reduceTransparency: boolean;
17
24
  }>;
@@ -47,6 +54,8 @@ export type AppearanceEditorProps = {
47
54
  };
48
55
  /** Undefined means theme import is unavailable, never a working-looking action. */
49
56
  onManageThemes?: () => void;
57
+ /** Mount nested font menus inside the containing overlay when one exists. */
58
+ menuPortalMount?: HTMLElement;
50
59
  class?: string;
51
60
  };
52
61
  export type AppearancePopoverProps = AppearanceEditorProps & {
@@ -1 +1 @@
1
- {"version":3,"file":"appearance-types.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/appearance-editor/appearance-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAE/E,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAA;IACjC,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAA;IACvC,kBAAkB,EAAE,OAAO,CAAA;CAC5B,CAAC,CAAA;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,eAAe,CAAA;IACtB,8EAA8E;IAC9E,UAAU,EAAE,SAAS,CAAA;IACrB,SAAS,EAAE,SAAS,CAAA;IACpB,kBAAkB,EAAE,OAAO,GAAG,MAAM,CAAA;IACpC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAA;IAClC,aAAa,EAAE,SAAS,YAAY,EAAE,CAAA;IACtC;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAC5C,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,eAAe,CAAC,KAAK,IAAI,CAAA;IACnD,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iBAAiB,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,uBAAuB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1F,mFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG,qBAAqB,GAAG;IAC3D,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,SAAS,EAAE,MAAM,IAAI,CAAA;CACtB,CAAA"}
1
+ {"version":3,"file":"appearance-types.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/appearance-editor/appearance-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAC/E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,+BAA+B,CAAA;AAEjF,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAA;IACjC,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,KAAK,CAAC,EAAE,4BAA4B,CAAA;IACpC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAA;IACvC,kBAAkB,EAAE,OAAO,CAAA;CAC5B,CAAC,CAAA;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,eAAe,CAAA;IACtB,8EAA8E;IAC9E,UAAU,EAAE,SAAS,CAAA;IACrB,SAAS,EAAE,SAAS,CAAA;IACpB,kBAAkB,EAAE,OAAO,GAAG,MAAM,CAAA;IACpC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAA;IAClC,aAAa,EAAE,SAAS,YAAY,EAAE,CAAA;IACtC;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAC5C,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,eAAe,CAAC,KAAK,IAAI,CAAA;IACnD,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iBAAiB,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,uBAAuB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1F,mFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;IAC3B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,WAAW,CAAA;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG,qBAAqB,GAAG;IAC3D,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,SAAS,EAAE,MAAM,IAAI,CAAA;CACtB,CAAA"}
@@ -0,0 +1,10 @@
1
+ import { type AppearanceEditorFontSettings } from '#lib/appearance-font-settings';
2
+ export type AppearanceFontSettingsGroupProps = {
3
+ settings: AppearanceEditorFontSettings;
4
+ menuPortalMount?: HTMLElement;
5
+ onChange: (settings: AppearanceEditorFontSettings) => void;
6
+ disabled?: boolean;
7
+ };
8
+ /** Controlled font controls shared by AppearanceEditor and host-owned settings. */
9
+ export declare function AppearanceFontSettingsGroup(props: AppearanceFontSettingsGroupProps): import("solid-js").JSX.Element;
10
+ //# sourceMappingURL=font-settings-group.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font-settings-group.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/appearance-editor/font-settings-group.tsx"],"names":[],"mappings":"AAcA,OAAO,EAOL,KAAK,4BAA4B,EAClC,MAAM,+BAA+B,CAAA;AAEtC,MAAM,MAAM,gCAAgC,GAAG;IAC7C,QAAQ,EAAE,4BAA4B,CAAA;IACtC,eAAe,CAAC,EAAE,WAAW,CAAA;IAC7B,QAAQ,EAAE,CAAC,QAAQ,EAAE,4BAA4B,KAAK,IAAI,CAAA;IAC1D,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAyND,mFAAmF;AACnF,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,gCAAgC,kCAsGlF"}
@@ -0,0 +1,310 @@
1
+ import { Button } from "../../ui/button/button.js";
2
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger } from "../../ui/dropdown-menu/dropdown-menu.js";
3
+ import { InputControl } from "../../ui/input/input-control.js";
4
+ import { fontOptions } from "../../../lib/font-catalog.js";
5
+ import { normalizeAppearanceEditorFontSettings, normalizeAppearanceEditorFontSize } from "../../../lib/appearance-font-settings.js";
6
+ import { SettingsRow } from "./appearance-rows.js";
7
+ import { createComponent, insert, setAttribute, template } from "solid-js/web";
8
+ import { BookOpen, ChevronDown, Code2, PanelsTopLeft } from "lucide-solid";
9
+ import { For, createMemo, createSignal, createUniqueId } from "solid-js";
10
+ //#region src/components/composites/appearance-editor/font-settings-group.tsx
11
+ var _tmpl$ = /*#__PURE__*/ template(`<span class=truncate>`);
12
+ var _tmpl$2 = /*#__PURE__*/ template(`<div class=global-appearance-font-settings>`);
13
+ var _tmpl$3 = /*#__PURE__*/ template(`<div class="flex min-w-0 max-w-full flex-wrap items-center gap-2"><div class="flex shrink-0 items-center gap-1"><span aria-hidden=true class="text-xs text-muted-foreground">px</span></div><span class=sr-only>Enter a whole number from <!> to <!> pixels.`);
14
+ var FONT_ROWS = [
15
+ {
16
+ axis: "ui",
17
+ label: "UI",
18
+ description: "Controls and interface labels.",
19
+ icon: PanelsTopLeft
20
+ },
21
+ {
22
+ axis: "content",
23
+ label: "Content",
24
+ description: "Reading and long-form text.",
25
+ icon: BookOpen
26
+ },
27
+ {
28
+ axis: "code",
29
+ label: "Code",
30
+ description: "Code, terminals, and file paths.",
31
+ icon: Code2
32
+ }
33
+ ];
34
+ var catalogFontOptions = fontOptions.filter((option) => option.id !== "system");
35
+ var MENU_FOCUS_TARGET_SELECTOR = "a[href], area[href], button, input, select, textarea, iframe, [tabindex], [contenteditable], details > summary:first-of-type";
36
+ function isMenuTabStop(element) {
37
+ return (element.tabIndex >= 0 || element.matches("details > summary:first-of-type") && !element.hasAttribute("tabindex")) && !element.matches(":disabled") && element.getAttribute("aria-disabled") !== "true" && element.closest("[hidden], [inert], [aria-hidden=\"true\"]") === null && element.getClientRects().length > 0;
38
+ }
39
+ function FontFamilyMenu(props) {
40
+ const [menuOpen, setMenuOpen] = createSignal(false);
41
+ const [restoreTriggerFocus, setRestoreTriggerFocus] = createSignal(false);
42
+ const [triggerElement, setTriggerElement] = createSignal();
43
+ let focusTargetAfterTab;
44
+ const moveFocusOnTab = (event) => {
45
+ if (event.key !== "Tab" || event.isComposing) return;
46
+ const trigger = triggerElement();
47
+ const owner = props.menuPortalMount;
48
+ const parentDialog = owner?.closest("[role=\"dialog\"]");
49
+ const focusScope = parentDialog ?? owner?.ownerDocument.body;
50
+ if (!trigger || !parentDialog || !focusScope) return;
51
+ const focusStops = Array.from(focusScope.querySelectorAll("*")).filter((element) => isMenuTabStop(element) && element.closest("[role=\"menu\"], [hidden], [inert], [aria-hidden=\"true\"]") === null);
52
+ const orderedFocusStops = [...focusStops.filter((element) => element.tabIndex > 0).toSorted((a, b) => a.tabIndex - b.tabIndex), ...focusStops.filter((element) => element.tabIndex <= 0)];
53
+ const triggerIndex = orderedFocusStops.indexOf(trigger);
54
+ if (triggerIndex < 0) return;
55
+ const direction = event.shiftKey ? -1 : 1;
56
+ const adjacent = orderedFocusStops[triggerIndex + direction] ?? (direction > 0 ? orderedFocusStops[0] : orderedFocusStops.at(-1));
57
+ event.stopPropagation();
58
+ setRestoreTriggerFocus(false);
59
+ if (adjacent) {
60
+ event.preventDefault();
61
+ focusTargetAfterTab = adjacent;
62
+ setMenuOpen(false);
63
+ adjacent.focus({ preventScroll: true });
64
+ } else {
65
+ focusTargetAfterTab = void 0;
66
+ setMenuOpen(false);
67
+ }
68
+ };
69
+ const selectedLabel = () => fontOptions.find((option) => option.id === props.family)?.label ?? fontOptions.find((option) => option.id === "system")?.label ?? "System";
70
+ return createComponent(DropdownMenu, {
71
+ modal: false,
72
+ get open() {
73
+ return menuOpen();
74
+ },
75
+ onOpenChange: (open) => {
76
+ setMenuOpen(open);
77
+ if (open) setRestoreTriggerFocus(false);
78
+ },
79
+ get children() {
80
+ return [createComponent(DropdownMenuTrigger, {
81
+ ref: setTriggerElement,
82
+ as: Button,
83
+ variant: "outline",
84
+ size: "sm",
85
+ get ["aria-label"]() {
86
+ return `${props.label} font family`;
87
+ },
88
+ get disabled() {
89
+ return props.disabled;
90
+ },
91
+ "class": "w-40 max-w-full justify-between",
92
+ get children() {
93
+ return [(() => {
94
+ var _el$ = _tmpl$();
95
+ insert(_el$, selectedLabel);
96
+ return _el$;
97
+ })(), createComponent(ChevronDown, {
98
+ "aria-hidden": "true",
99
+ "class": "ms-2 size-4 shrink-0 text-muted-foreground"
100
+ })];
101
+ }
102
+ }), createComponent(DropdownMenuContent, {
103
+ hideArrow: true,
104
+ get portalMount() {
105
+ return props.menuPortalMount;
106
+ },
107
+ "class": "min-w-48",
108
+ onFocusOutside: (event) => {
109
+ if (!event.defaultPrevented && props.menuPortalMount && event.detail.originalEvent.target === props.menuPortalMount) {
110
+ setRestoreTriggerFocus(true);
111
+ event.preventDefault();
112
+ } else if (event.detail.originalEvent.target instanceof HTMLElement && props.menuPortalMount?.contains(event.detail.originalEvent.target)) setRestoreTriggerFocus(false);
113
+ },
114
+ onInteractOutside: (event) => {
115
+ if (event.detail.originalEvent.type !== "pointerdown") return;
116
+ const owner = props.menuPortalMount;
117
+ const target = event.detail.originalEvent.target;
118
+ if (!(target instanceof Element) || !owner?.contains(target)) return;
119
+ const focusTarget = target.closest(MENU_FOCUS_TARGET_SELECTOR);
120
+ setRestoreTriggerFocus(!focusTarget || !isMenuTabStop(focusTarget));
121
+ },
122
+ onKeyDown: moveFocusOnTab,
123
+ onEscapeKeyDown: () => setRestoreTriggerFocus(true),
124
+ onCloseAutoFocus: (event) => {
125
+ if (menuOpen()) {
126
+ event.preventDefault();
127
+ return;
128
+ }
129
+ if (focusTargetAfterTab) {
130
+ const focusTarget = focusTargetAfterTab;
131
+ focusTargetAfterTab = void 0;
132
+ event.preventDefault();
133
+ queueMicrotask(() => {
134
+ if (!menuOpen() && focusTarget.isConnected) focusTarget.focus({ preventScroll: true });
135
+ });
136
+ return;
137
+ }
138
+ if (!restoreTriggerFocus()) return;
139
+ event.preventDefault();
140
+ setRestoreTriggerFocus(false);
141
+ const trigger = triggerElement();
142
+ if (trigger?.isConnected && !trigger.disabled && trigger.closest("[hidden], [inert], [aria-hidden=\"true\"]") === null && trigger.getClientRects().length > 0) trigger.focus({ preventScroll: true });
143
+ },
144
+ get children() {
145
+ return [
146
+ createComponent(DropdownMenuRadioGroup, {
147
+ get value() {
148
+ return props.family;
149
+ },
150
+ get ["aria-label"]() {
151
+ return `${props.label} system font`;
152
+ },
153
+ onChange: (family) => {
154
+ if (family === "system") props.onSelect("system");
155
+ },
156
+ get children() {
157
+ return createComponent(DropdownMenuRadioItem, {
158
+ value: "system",
159
+ closeOnSelect: true,
160
+ children: "System"
161
+ });
162
+ }
163
+ }),
164
+ createComponent(DropdownMenuSeparator, {}),
165
+ createComponent(DropdownMenuRadioGroup, {
166
+ get value() {
167
+ return props.family;
168
+ },
169
+ get ["aria-label"]() {
170
+ return `${props.label} available fonts`;
171
+ },
172
+ onChange: (family) => {
173
+ const option = fontOptions.find((candidate) => candidate.id === family);
174
+ if (option && option.id !== "system") props.onSelect(option.id);
175
+ },
176
+ get children() {
177
+ return createComponent(For, {
178
+ each: catalogFontOptions,
179
+ children: (option) => createComponent(DropdownMenuRadioItem, {
180
+ get value() {
181
+ return option.id;
182
+ },
183
+ closeOnSelect: true,
184
+ get children() {
185
+ return option.label;
186
+ }
187
+ })
188
+ });
189
+ }
190
+ })
191
+ ];
192
+ }
193
+ })];
194
+ }
195
+ });
196
+ }
197
+ /** Controlled font controls shared by AppearanceEditor and host-owned settings. */
198
+ function AppearanceFontSettingsGroup(props) {
199
+ const [sizeDrafts, setSizeDrafts] = createSignal({});
200
+ const sizeHintPrefix = createUniqueId();
201
+ const settings = createMemo(() => normalizeAppearanceEditorFontSettings(props.settings).settings);
202
+ const updateAxis = (axis, patch) => {
203
+ const current = settings();
204
+ props.onChange({
205
+ ...current,
206
+ [axis]: {
207
+ ...current[axis],
208
+ ...patch
209
+ }
210
+ });
211
+ };
212
+ const commitSize = (axis) => {
213
+ const input = sizeDrafts()[axis];
214
+ if (input === void 0) return;
215
+ const size = normalizeAppearanceEditorFontSize(input, settings()[axis].size);
216
+ setSizeDrafts((current) => {
217
+ const next = { ...current };
218
+ delete next[axis];
219
+ return next;
220
+ });
221
+ if (size !== settings()[axis].size) updateAxis(axis, { size });
222
+ };
223
+ return (() => {
224
+ var _el$2 = _tmpl$2();
225
+ insert(_el$2, createComponent(For, {
226
+ each: FONT_ROWS,
227
+ children: (row) => {
228
+ const Icon = row.icon;
229
+ const value = () => settings()[row.axis];
230
+ const inputValue = () => sizeDrafts()[row.axis] ?? String(value().size);
231
+ const sizeHintId = `${sizeHintPrefix}-${row.axis}-font-size-help`;
232
+ const sizeIsInvalid = () => {
233
+ const draft = sizeDrafts()[row.axis];
234
+ if (draft === void 0 || draft.trim() === "") return false;
235
+ const parsed = Number(draft);
236
+ return !Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed < 10 || parsed > 32;
237
+ };
238
+ return createComponent(SettingsRow, {
239
+ get title() {
240
+ return row.label;
241
+ },
242
+ get icon() {
243
+ return createComponent(Icon, {});
244
+ },
245
+ get description() {
246
+ return row.description;
247
+ },
248
+ get children() {
249
+ var _el$3 = _tmpl$3(), _el$4 = _el$3.firstChild, _el$5 = _el$4.firstChild, _el$6 = _el$4.nextSibling, _el$1 = _el$6.firstChild.nextSibling, _el$10 = _el$1.nextSibling.nextSibling;
250
+ _el$10.nextSibling;
251
+ insert(_el$3, createComponent(FontFamilyMenu, {
252
+ get label() {
253
+ return row.label;
254
+ },
255
+ get family() {
256
+ return value().family;
257
+ },
258
+ get menuPortalMount() {
259
+ return props.menuPortalMount;
260
+ },
261
+ get disabled() {
262
+ return props.disabled;
263
+ },
264
+ onSelect: (family) => updateAxis(row.axis, { family })
265
+ }), _el$4);
266
+ insert(_el$4, createComponent(InputControl, {
267
+ type: "number",
268
+ min: 10,
269
+ max: 32,
270
+ step: 1,
271
+ get value() {
272
+ return inputValue();
273
+ },
274
+ get disabled() {
275
+ return props.disabled;
276
+ },
277
+ get ["aria-label"]() {
278
+ return `${row.label} font size in pixels`;
279
+ },
280
+ "aria-describedby": sizeHintId,
281
+ get ["aria-invalid"]() {
282
+ return sizeIsInvalid();
283
+ },
284
+ "class": "w-16",
285
+ onInput: (event) => setSizeDrafts((current) => ({
286
+ ...current,
287
+ [row.axis]: event.currentTarget.value
288
+ })),
289
+ onBlur: () => commitSize(row.axis),
290
+ onKeyDown: (event) => {
291
+ if (event.key !== "Enter") return;
292
+ event.preventDefault();
293
+ commitSize(row.axis);
294
+ }
295
+ }), _el$5);
296
+ setAttribute(_el$6, "id", sizeHintId);
297
+ insert(_el$6, 10, _el$1);
298
+ insert(_el$6, 32, _el$10);
299
+ return _el$3;
300
+ }
301
+ });
302
+ }
303
+ }));
304
+ return _el$2;
305
+ })();
306
+ }
307
+ //#endregion
308
+ export { AppearanceFontSettingsGroup };
309
+
310
+ //# sourceMappingURL=font-settings-group.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font-settings-group.js","names":["BookOpen","ChevronDown","Code2","PanelsTopLeft","For","createMemo","createSignal","createUniqueId","fontOptions","Button","DropdownMenu","DropdownMenuContent","DropdownMenuRadioGroup","DropdownMenuRadioItem","DropdownMenuSeparator","DropdownMenuTrigger","InputControl","SettingsRow","APPEARANCE_EDITOR_FONT_SIZE_MAX","APPEARANCE_EDITOR_FONT_SIZE_MIN","normalizeAppearanceEditorFontSettings","normalizeAppearanceEditorFontSize","AppearanceEditorFontAxis","AppearanceEditorFontFamilyId","AppearanceEditorFontSettings","AppearanceFontSettingsGroupProps","settings","menuPortalMount","HTMLElement","onChange","disabled","FONT_ROWS","axis","label","description","icon","const","catalogFontOptions","filter","option","id","MENU_FOCUS_TARGET_SELECTOR","isMenuTabStop","element","tabIndex","matches","hasAttribute","getAttribute","closest","getClientRects","length","FontFamilyMenu","props","family","onSelect","menuOpen","setMenuOpen","restoreTriggerFocus","setRestoreTriggerFocus","triggerElement","setTriggerElement","HTMLButtonElement","focusTargetAfterTab","moveFocusOnTab","event","KeyboardEvent","key","isComposing","trigger","owner","parentDialog","focusScope","ownerDocument","body","focusStops","Array","from","querySelectorAll","orderedFocusStops","toSorted","a","b","triggerIndex","indexOf","direction","shiftKey","adjacent","at","stopPropagation","preventDefault","focus","preventScroll","undefined","selectedLabel","find","_$createComponent","modal","open","onOpenChange","children","ref","as","variant","size","aria-label","_el$","_tmpl$","_$insert","hideArrow","portalMount","onFocusOutside","defaultPrevented","detail","originalEvent","target","contains","onInteractOutside","type","Element","focusTarget","onKeyDown","onEscapeKeyDown","onCloseAutoFocus","queueMicrotask","isConnected","value","closeOnSelect","candidate","each","AppearanceFontSettingsGroup","sizeDrafts","setSizeDrafts","Partial","Record","sizeHintPrefix","updateAxis","patch","current","commitSize","input","next","_el$2","_tmpl$2","row","Icon","inputValue","String","sizeHintId","sizeIsInvalid","draft","trim","parsed","Number","isFinite","isInteger","title","_el$3","_tmpl$3","_el$4","firstChild","_el$5","_el$6","nextSibling","_el$7","_el$1","_el$8","_el$10","_el$0","min","max","step","aria-invalid","onInput","currentTarget","onBlur","_$setAttribute","_$createComponent"],"sources":["../../../../src/components/composites/appearance-editor/font-settings-group.tsx"],"sourcesContent":["import { BookOpen, ChevronDown, Code2, PanelsTopLeft } from 'lucide-solid'\nimport { For, createMemo, createSignal, createUniqueId } from 'solid-js'\nimport { fontOptions } from '#lib/font-catalog'\nimport { Button } from '../../ui/button/button'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../../ui/dropdown-menu/dropdown-menu'\nimport { InputControl } from '../../ui/input/input-control'\nimport { SettingsRow } from './appearance-rows'\nimport {\n APPEARANCE_EDITOR_FONT_SIZE_MAX,\n APPEARANCE_EDITOR_FONT_SIZE_MIN,\n normalizeAppearanceEditorFontSettings,\n normalizeAppearanceEditorFontSize,\n type AppearanceEditorFontAxis,\n type AppearanceEditorFontFamilyId,\n type AppearanceEditorFontSettings,\n} from '#lib/appearance-font-settings'\n\nexport type AppearanceFontSettingsGroupProps = {\n settings: AppearanceEditorFontSettings\n menuPortalMount?: HTMLElement\n onChange: (settings: AppearanceEditorFontSettings) => void\n disabled?: boolean\n}\n\nconst FONT_ROWS = [\n {\n axis: 'ui',\n label: 'UI',\n description: 'Controls and interface labels.',\n icon: PanelsTopLeft,\n },\n {\n axis: 'content',\n label: 'Content',\n description: 'Reading and long-form text.',\n icon: BookOpen,\n },\n {\n axis: 'code',\n label: 'Code',\n description: 'Code, terminals, and file paths.',\n icon: Code2,\n },\n] as const satisfies readonly {\n axis: AppearanceEditorFontAxis\n label: string\n description: string\n icon: typeof PanelsTopLeft\n}[]\n\nconst catalogFontOptions = fontOptions.filter((option) => option.id !== 'system')\nconst MENU_FOCUS_TARGET_SELECTOR =\n 'a[href], area[href], button, input, select, textarea, iframe, [tabindex], [contenteditable], details > summary:first-of-type'\n\nfunction isMenuTabStop(element: HTMLElement) {\n return (\n (element.tabIndex >= 0 ||\n (element.matches('details > summary:first-of-type') && !element.hasAttribute('tabindex'))) &&\n !element.matches(':disabled') &&\n element.getAttribute('aria-disabled') !== 'true' &&\n element.closest('[hidden], [inert], [aria-hidden=\"true\"]') === null &&\n element.getClientRects().length > 0\n )\n}\n\nfunction FontFamilyMenu(props: {\n label: string\n family: AppearanceEditorFontFamilyId\n menuPortalMount?: HTMLElement\n disabled?: boolean\n onSelect: (family: AppearanceEditorFontFamilyId) => void\n}) {\n const [menuOpen, setMenuOpen] = createSignal(false)\n const [restoreTriggerFocus, setRestoreTriggerFocus] = createSignal(false)\n const [triggerElement, setTriggerElement] = createSignal<HTMLButtonElement>()\n let focusTargetAfterTab: HTMLElement | undefined\n\n const moveFocusOnTab = (event: KeyboardEvent) => {\n if (event.key !== 'Tab' || event.isComposing) return\n\n const trigger = triggerElement()\n const owner = props.menuPortalMount\n const parentDialog = owner?.closest<HTMLElement>('[role=\"dialog\"]')\n const focusScope = parentDialog ?? owner?.ownerDocument.body\n if (!trigger || !parentDialog || !focusScope) return\n\n const focusStops = Array.from(focusScope.querySelectorAll<HTMLElement>('*')).filter(\n (element) =>\n isMenuTabStop(element) &&\n element.closest('[role=\"menu\"], [hidden], [inert], [aria-hidden=\"true\"]') === null\n )\n const orderedFocusStops = [\n ...focusStops\n .filter((element) => element.tabIndex > 0)\n .toSorted((a, b) => a.tabIndex - b.tabIndex),\n ...focusStops.filter((element) => element.tabIndex <= 0),\n ]\n const triggerIndex = orderedFocusStops.indexOf(trigger)\n if (triggerIndex < 0) return\n const direction = event.shiftKey ? -1 : 1\n const adjacent =\n orderedFocusStops[triggerIndex + direction] ??\n (direction > 0 ? orderedFocusStops[0] : orderedFocusStops.at(-1))\n\n event.stopPropagation()\n setRestoreTriggerFocus(false)\n if (adjacent) {\n event.preventDefault()\n focusTargetAfterTab = adjacent\n setMenuOpen(false)\n adjacent.focus({ preventScroll: true })\n } else {\n focusTargetAfterTab = undefined\n setMenuOpen(false)\n }\n }\n const selectedLabel = () =>\n fontOptions.find((option) => option.id === props.family)?.label ??\n fontOptions.find((option) => option.id === 'system')?.label ??\n 'System'\n\n return (\n <DropdownMenu\n modal={false}\n open={menuOpen()}\n onOpenChange={(open) => {\n setMenuOpen(open)\n if (open) setRestoreTriggerFocus(false)\n }}\n >\n <DropdownMenuTrigger\n ref={setTriggerElement}\n as={Button}\n variant=\"outline\"\n size=\"sm\"\n aria-label={`${props.label} font family`}\n disabled={props.disabled}\n class=\"w-40 max-w-full justify-between\"\n >\n <span class=\"truncate\">{selectedLabel()}</span>\n <ChevronDown aria-hidden=\"true\" class=\"ms-2 size-4 shrink-0 text-muted-foreground\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent\n hideArrow\n portalMount={props.menuPortalMount}\n class=\"min-w-48\"\n onFocusOutside={(event) => {\n // WebKit may briefly focus the owning Popover root while the menu's\n // focus scope starts. Keep the menu open for that transient target;\n // genuine focus moves to another control still dismiss it.\n if (\n !event.defaultPrevented &&\n props.menuPortalMount &&\n event.detail.originalEvent.target === props.menuPortalMount\n ) {\n setRestoreTriggerFocus(true)\n event.preventDefault()\n } else if (\n event.detail.originalEvent.target instanceof HTMLElement &&\n props.menuPortalMount?.contains(event.detail.originalEvent.target)\n ) {\n setRestoreTriggerFocus(false)\n }\n }}\n onInteractOutside={(event) => {\n if (event.detail.originalEvent.type !== 'pointerdown') return\n const owner = props.menuPortalMount\n const target = event.detail.originalEvent.target\n if (!(target instanceof Element) || !owner?.contains(target)) return\n\n const focusTarget = target.closest<HTMLElement>(MENU_FOCUS_TARGET_SELECTOR)\n setRestoreTriggerFocus(!focusTarget || !isMenuTabStop(focusTarget))\n }}\n onKeyDown={moveFocusOnTab}\n onEscapeKeyDown={() => setRestoreTriggerFocus(true)}\n onCloseAutoFocus={(event) => {\n if (menuOpen()) {\n event.preventDefault()\n return\n }\n if (focusTargetAfterTab) {\n const focusTarget = focusTargetAfterTab\n focusTargetAfterTab = undefined\n event.preventDefault()\n queueMicrotask(() => {\n if (!menuOpen() && focusTarget.isConnected) {\n focusTarget.focus({ preventScroll: true })\n }\n })\n return\n }\n if (!restoreTriggerFocus()) return\n\n event.preventDefault()\n setRestoreTriggerFocus(false)\n const trigger = triggerElement()\n if (\n trigger?.isConnected &&\n !trigger.disabled &&\n trigger.closest('[hidden], [inert], [aria-hidden=\"true\"]') === null &&\n trigger.getClientRects().length > 0\n ) {\n trigger.focus({ preventScroll: true })\n }\n }}\n >\n <DropdownMenuRadioGroup\n value={props.family}\n aria-label={`${props.label} system font`}\n onChange={(family) => {\n if (family === 'system') props.onSelect('system')\n }}\n >\n <DropdownMenuRadioItem value=\"system\" closeOnSelect>\n System\n </DropdownMenuRadioItem>\n </DropdownMenuRadioGroup>\n <DropdownMenuSeparator />\n <DropdownMenuRadioGroup\n value={props.family}\n aria-label={`${props.label} available fonts`}\n onChange={(family) => {\n const option = fontOptions.find((candidate) => candidate.id === family)\n if (option && option.id !== 'system') props.onSelect(option.id)\n }}\n >\n <For each={catalogFontOptions}>\n {(option) => (\n <DropdownMenuRadioItem value={option.id} closeOnSelect>\n {option.label}\n </DropdownMenuRadioItem>\n )}\n </For>\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n\n/** Controlled font controls shared by AppearanceEditor and host-owned settings. */\nexport function AppearanceFontSettingsGroup(props: AppearanceFontSettingsGroupProps) {\n const [sizeDrafts, setSizeDrafts] = createSignal<\n Partial<Record<AppearanceEditorFontAxis, string>>\n >({})\n const sizeHintPrefix = createUniqueId()\n const settings = createMemo(() => normalizeAppearanceEditorFontSettings(props.settings).settings)\n\n const updateAxis = (\n axis: AppearanceEditorFontAxis,\n patch: { family?: AppearanceEditorFontFamilyId; size?: number }\n ) => {\n const current = settings()\n props.onChange({\n ...current,\n [axis]: {\n ...current[axis],\n ...patch,\n },\n })\n }\n\n const commitSize = (axis: AppearanceEditorFontAxis) => {\n const input = sizeDrafts()[axis]\n if (input === undefined) return\n const size = normalizeAppearanceEditorFontSize(input, settings()[axis].size)\n setSizeDrafts((current) => {\n const next = { ...current }\n delete next[axis]\n return next\n })\n if (size !== settings()[axis].size) updateAxis(axis, { size })\n }\n\n return (\n <div class=\"global-appearance-font-settings\">\n <For each={FONT_ROWS}>\n {(row) => {\n const Icon = row.icon\n const value = () => settings()[row.axis]\n const inputValue = () => sizeDrafts()[row.axis] ?? String(value().size)\n const sizeHintId = `${sizeHintPrefix}-${row.axis}-font-size-help`\n const sizeIsInvalid = () => {\n const draft = sizeDrafts()[row.axis]\n if (draft === undefined || draft.trim() === '') return false\n const parsed = Number(draft)\n return (\n !Number.isFinite(parsed) ||\n !Number.isInteger(parsed) ||\n parsed < APPEARANCE_EDITOR_FONT_SIZE_MIN ||\n parsed > APPEARANCE_EDITOR_FONT_SIZE_MAX\n )\n }\n return (\n <SettingsRow title={row.label} icon={<Icon />} description={row.description}>\n <div class=\"flex min-w-0 max-w-full flex-wrap items-center gap-2\">\n <FontFamilyMenu\n label={row.label}\n family={value().family}\n menuPortalMount={props.menuPortalMount}\n disabled={props.disabled}\n onSelect={(family) => updateAxis(row.axis, { family })}\n />\n <div class=\"flex shrink-0 items-center gap-1\">\n <InputControl\n type=\"number\"\n min={APPEARANCE_EDITOR_FONT_SIZE_MIN}\n max={APPEARANCE_EDITOR_FONT_SIZE_MAX}\n step={1}\n value={inputValue()}\n disabled={props.disabled}\n aria-label={`${row.label} font size in pixels`}\n aria-describedby={sizeHintId}\n aria-invalid={sizeIsInvalid()}\n class=\"w-16\"\n onInput={(event) =>\n setSizeDrafts((current) => ({\n ...current,\n [row.axis]: event.currentTarget.value,\n }))\n }\n onBlur={() => commitSize(row.axis)}\n onKeyDown={(event) => {\n if (event.key !== 'Enter') return\n event.preventDefault()\n commitSize(row.axis)\n }}\n />\n <span aria-hidden=\"true\" class=\"text-xs text-muted-foreground\">\n px\n </span>\n </div>\n <span id={sizeHintId} class=\"sr-only\">\n Enter a whole number from {APPEARANCE_EDITOR_FONT_SIZE_MIN} to{' '}\n {APPEARANCE_EDITOR_FONT_SIZE_MAX} pixels.\n </span>\n </div>\n </SettingsRow>\n )\n }}\n </For>\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AA+BA,IAAM+B,YAAY;CAChB;EACEC,MAAM;EACNC,OAAO;EACPC,aAAa;EACbC,MAAMhC;CACR;CACA;EACE6B,MAAM;EACNC,OAAO;EACPC,aAAa;EACbC,MAAMnC;CACR;CACA;EACEgC,MAAM;EACNC,OAAO;EACPC,aAAa;EACbC,MAAMjC;CACR;AAAC;AAQH,IAAMmC,qBAAqB7B,YAAY8B,QAAQC,WAAWA,OAAOC,OAAO,QAAQ;AAChF,IAAMC,6BACJ;AAEF,SAASC,cAAcC,SAAsB;CAC3C,QACGA,QAAQC,YAAY,KAClBD,QAAQE,QAAQ,iCAAiC,KAAK,CAACF,QAAQG,aAAa,UAAU,MACzF,CAACH,QAAQE,QAAQ,WAAW,KAC5BF,QAAQI,aAAa,eAAe,MAAM,UAC1CJ,QAAQK,QAAQ,2CAAyC,MAAM,QAC/DL,QAAQM,eAAe,CAAC,CAACC,SAAS;AAEtC;AAEA,SAASC,eAAeC,OAMrB;CACD,MAAM,CAACG,UAAUC,eAAelD,aAAa,KAAK;CAClD,MAAM,CAACmD,qBAAqBC,0BAA0BpD,aAAa,KAAK;CACxE,MAAM,CAACqD,gBAAgBC,qBAAqBtD,aAAgC;CAC5E,IAAIwD;CAEJ,MAAMC,kBAAkBC,UAAyB;EAC/C,IAAIA,MAAME,QAAQ,SAASF,MAAMG,aAAa;EAE9C,MAAMC,UAAUT,eAAe;EAC/B,MAAMU,QAAQjB,MAAMzB;EACpB,MAAM2C,eAAeD,OAAOrB,QAAqB,mBAAiB;EAClE,MAAMuB,aAAaD,gBAAgBD,OAAOG,cAAcC;EACxD,IAAI,CAACL,WAAW,CAACE,gBAAgB,CAACC,YAAY;EAE9C,MAAMG,aAAaC,MAAMC,KAAKL,WAAWM,iBAA8B,GAAG,CAAC,CAAC,CAACvC,QAC1EK,YACCD,cAAcC,OAAO,KACrBA,QAAQK,QAAQ,4DAAwD,MAAM,IAClF;EACA,MAAM8B,oBAAoB,CACxB,GAAGJ,WACApC,QAAQK,YAAYA,QAAQC,WAAW,CAAC,CAAC,CACzCmC,UAAUC,GAAGC,MAAMD,EAAEpC,WAAWqC,EAAErC,QAAQ,GAC7C,GAAG8B,WAAWpC,QAAQK,YAAYA,QAAQC,YAAY,CAAC,CAAC;EAE1D,MAAMsC,eAAeJ,kBAAkBK,QAAQf,OAAO;EACtD,IAAIc,eAAe,GAAG;EACtB,MAAME,YAAYpB,MAAMqB,WAAW,KAAK;EACxC,MAAMC,WACJR,kBAAkBI,eAAeE,eAChCA,YAAY,IAAIN,kBAAkB,KAAKA,kBAAkBS,GAAG,EAAE;EAEjEvB,MAAMwB,gBAAgB;EACtB9B,uBAAuB,KAAK;EAC5B,IAAI4B,UAAU;GACZtB,MAAMyB,eAAe;GACrB3B,sBAAsBwB;GACtB9B,YAAY,KAAK;GACjB8B,SAASI,MAAM,EAAEC,eAAe,KAAK,CAAC;EACxC,OAAO;GACL7B,sBAAsB8B,KAAAA;GACtBpC,YAAY,KAAK;EACnB;CACF;CACA,MAAMqC,sBACJrF,YAAYsF,MAAMvD,WAAWA,OAAOC,OAAOY,MAAMC,MAAM,CAAC,EAAEpB,SAC1DzB,YAAYsF,MAAMvD,WAAWA,OAAOC,OAAO,QAAQ,CAAC,EAAEP,SACtD;CAEF,OAAA8D,gBACGrF,cAAY;EACXsF,OAAO;EAAK,IACZC,OAAI;GAAA,OAAE1C,SAAS;EAAC;EAChB2C,eAAeD,SAAS;GACtBzC,YAAYyC,IAAI;GAChB,IAAIA,MAAMvC,uBAAuB,KAAK;EACxC;EAAC,IAAAyC,WAAA;GAAA,OAAA,CAAAJ,gBAEAhF,qBAAmB;IAAAqF,KACbxC;IACLyC,IAAI5F;IACJ6F,SAAO;IACPC,MAAI;IAAA,KAAA,gBAAA;KAAA,OACQ,GAAGnD,MAAMnB,MAAK;IAAc;IAAA,IACxCH,WAAQ;KAAA,OAAEsB,MAAMtB;IAAQ;IAAA,SAAA;IAAA,IAAAqE,WAAA;KAAA,OAAA,QAAA;MAAA,IAAAM,OAAAC,OAAA;MAAAC,OAAAF,MAGAZ,aAAa;MAAA,OAAAY;KAAA,EAAA,CAAA,GAAAV,gBACpC9F,aAAW;MAAA,eAAA;MAAA,SAAA;KAAA,CAAA,CAAA;IAAA;GAAA,CAAA,GAAA8F,gBAEbpF,qBAAmB;IAClBiG,WAAS;IAAA,IACTC,cAAW;KAAA,OAAEzD,MAAMzB;IAAe;IAAA,SAAA;IAElCmF,iBAAiB9C,UAAU;KAIzB,IACE,CAACA,MAAM+C,oBACP3D,MAAMzB,mBACNqC,MAAMgD,OAAOC,cAAcC,WAAW9D,MAAMzB,iBAC5C;MACA+B,uBAAuB,IAAI;MAC3BM,MAAMyB,eAAe;KACvB,OAAO,IACLzB,MAAMgD,OAAOC,cAAcC,kBAAkBtF,eAC7CwB,MAAMzB,iBAAiBwF,SAASnD,MAAMgD,OAAOC,cAAcC,MAAM,GAEjExD,uBAAuB,KAAK;IAEhC;IACA0D,oBAAoBpD,UAAU;KAC5B,IAAIA,MAAMgD,OAAOC,cAAcI,SAAS,eAAe;KACvD,MAAMhD,QAAQjB,MAAMzB;KACpB,MAAMuF,SAASlD,MAAMgD,OAAOC,cAAcC;KAC1C,IAAI,EAAEA,kBAAkBI,YAAY,CAACjD,OAAO8C,SAASD,MAAM,GAAG;KAE9D,MAAMK,cAAcL,OAAOlE,QAAqBP,0BAA0B;KAC1EiB,uBAAuB,CAAC6D,eAAe,CAAC7E,cAAc6E,WAAW,CAAC;IACpE;IACAC,WAAWzD;IACX0D,uBAAuB/D,uBAAuB,IAAI;IAClDgE,mBAAmB1D,UAAU;KAC3B,IAAIT,SAAS,GAAG;MACdS,MAAMyB,eAAe;MACrB;KACF;KACA,IAAI3B,qBAAqB;MACvB,MAAMyD,cAAczD;MACpBA,sBAAsB8B,KAAAA;MACtB5B,MAAMyB,eAAe;MACrBkC,qBAAqB;OACnB,IAAI,CAACpE,SAAS,KAAKgE,YAAYK,aAC7BL,YAAY7B,MAAM,EAAEC,eAAe,KAAK,CAAC;MAE7C,CAAC;MACD;KACF;KACA,IAAI,CAAClC,oBAAoB,GAAG;KAE5BO,MAAMyB,eAAe;KACrB/B,uBAAuB,KAAK;KAC5B,MAAMU,UAAUT,eAAe;KAC/B,IACES,SAASwD,eACT,CAACxD,QAAQtC,YACTsC,QAAQpB,QAAQ,2CAAyC,MAAM,QAC/DoB,QAAQnB,eAAe,CAAC,CAACC,SAAS,GAElCkB,QAAQsB,MAAM,EAAEC,eAAe,KAAK,CAAC;IAEzC;IAAC,IAAAQ,WAAA;KAAA,OAAA;MAAAJ,gBAEAnF,wBAAsB;OAAA,IACrBiH,QAAK;QAAA,OAAEzE,MAAMC;OAAM;OAAA,KAAA,gBAAA;QAAA,OACP,GAAGD,MAAMnB,MAAK;OAAc;OACxCJ,WAAWwB,WAAW;QACpB,IAAIA,WAAW,UAAUD,MAAME,SAAS,QAAQ;OAClD;OAAC,IAAA6C,WAAA;QAAA,OAAAJ,gBAEAlF,uBAAqB;SAACgH,OAAK;SAAUC,eAAa;SAAA3B,UAAA;QAAA,CAAA;OAAA;MAAA,CAAA;MAAAJ,gBAIpDjF,uBAAqB,CAAA,CAAA;MAAAiF,gBACrBnF,wBAAsB;OAAA,IACrBiH,QAAK;QAAA,OAAEzE,MAAMC;OAAM;OAAA,KAAA,gBAAA;QAAA,OACP,GAAGD,MAAMnB,MAAK;OAAkB;OAC5CJ,WAAWwB,WAAW;QACpB,MAAMd,SAAS/B,YAAYsF,MAAMiC,cAAcA,UAAUvF,OAAOa,MAAM;QACtE,IAAId,UAAUA,OAAOC,OAAO,UAAUY,MAAME,SAASf,OAAOC,EAAE;OAChE;OAAC,IAAA2D,WAAA;QAAA,OAAAJ,gBAEA3F,KAAG;SAAC4H,MAAM3F;SAAkB8D,WACzB5D,WAAMwD,gBACLlF,uBAAqB;UAAA,IAACgH,QAAK;WAAA,OAAEtF,OAAOC;UAAE;UAAEsF,eAAa;UAAA,IAAA3B,WAAA;WAAA,OACnD5D,OAAON;UAAK;SAAA,CAAA;QAEhB,CAAA;OAAA;MAAA,CAAA;KAAA;IAAA;GAAA,CAAA,CAAA;EAAA;CAAA,CAAA;AAMb;;AAGA,SAAgBgG,4BAA4B7E,OAAyC;CACnF,MAAM,CAAC8E,YAAYC,iBAAiB7H,aAElC,CAAC,CAAC;CACJ,MAAMgI,iBAAiB/H,eAAe;CACtC,MAAMmB,WAAWrB,iBAAiBe,sCAAsCgC,MAAM1B,QAAQ,CAAC,CAACA,QAAQ;CAEhG,MAAM6G,cACJvG,MACAwG,UACG;EACH,MAAMC,UAAU/G,SAAS;EACzB0B,MAAMvB,SAAS;GACb,GAAG4G;IACFzG,OAAO;IACN,GAAGyG,QAAQzG;IACX,GAAGwG;GACL;EACF,CAAC;CACH;CAEA,MAAME,cAAc1G,SAAmC;EACrD,MAAM2G,QAAQT,WAAW,CAAC,CAAClG;EAC3B,IAAI2G,UAAU/C,KAAAA,GAAW;EACzB,MAAMW,OAAOlF,kCAAkCsH,OAAOjH,SAAS,CAAC,CAACM,KAAK,CAACuE,IAAI;EAC3E4B,eAAeM,YAAY;GACzB,MAAMG,OAAO,EAAE,GAAGH,QAAQ;GAC1B,OAAOG,KAAK5G;GACZ,OAAO4G;EACT,CAAC;EACD,IAAIrC,SAAS7E,SAAS,CAAC,CAACM,KAAK,CAACuE,MAAMgC,WAAWvG,MAAM,EAAEuE,KAAK,CAAC;CAC/D;CAEA,cAAA;EAAA,IAAAsC,QAAAC,QAAA;EAAAnC,OAAAkC,OAAA9C,gBAEK3F,KAAG;GAAC4H,MAAMjG;GAASoE,WAChB4C,QAAQ;IACR,MAAMC,OAAOD,IAAI5G;IACjB,MAAM0F,cAAcnG,SAAS,CAAC,CAACqH,IAAI/G;IACnC,MAAMiH,mBAAmBf,WAAW,CAAC,CAACa,IAAI/G,SAASkH,OAAOrB,MAAM,CAAC,CAACtB,IAAI;IACtE,MAAM4C,aAAa,GAAGb,eAAc,GAAIS,IAAI/G,KAAI;IAChD,MAAMoH,sBAAsB;KAC1B,MAAMC,QAAQnB,WAAW,CAAC,CAACa,IAAI/G;KAC/B,IAAIqH,UAAUzD,KAAAA,KAAayD,MAAMC,KAAK,MAAM,IAAI,OAAO;KACvD,MAAMC,SAASC,OAAOH,KAAK;KAC3B,OACE,CAACG,OAAOC,SAASF,MAAM,KACvB,CAACC,OAAOE,UAAUH,MAAM,KACxBA,SAAAA,MACAA,SAAAA;IAEJ;IACA,OAAAxD,gBACG9E,aAAW;KAAA,IAAC0I,QAAK;MAAA,OAAEZ,IAAI9G;KAAK;KAAA,IAAEE,OAAI;MAAA,OAAA4D,gBAAGiD,MAAI,CAAA,CAAA;KAAA;KAAA,IAAK9G,cAAW;MAAA,OAAE6G,IAAI7G;KAAW;KAAA,IAAAiE,WAAA;MAAA,IAAAyD,QAAAC,QAAA,GAAAC,QAAAF,MAAAG,YAAAC,QAAAF,MAAAC,YAAAE,QAAAH,MAAAI,aAAAE,QAAAH,MAAAF,WAAAG,aAAAI,SAAAF,MAAAF,YAAAA;MAAAI,OAAAJ;MAAAvD,OAAAiD,OAAA7D,gBAEtE5C,gBAAc;OAAA,IACblB,QAAK;QAAA,OAAE8G,IAAI9G;OAAK;OAAA,IAChBoB,SAAM;QAAA,OAAEwE,MAAM,CAAC,CAACxE;OAAM;OAAA,IACtB1B,kBAAe;QAAA,OAAEyB,MAAMzB;OAAe;OAAA,IACtCG,WAAQ;QAAA,OAAEsB,MAAMtB;OAAQ;OACxBwB,WAAWD,WAAWkF,WAAWQ,IAAI/G,MAAM,EAAEqB,OAAO,CAAC;MAAC,CAAA,GAAAyG,KAAA;MAAAnD,OAAAmD,OAAA/D,gBAGrD/E,cAAY;OACXqG,MAAI;OACJmD,KAAAA;OACAC,KAAAA;OACAC,MAAM;OAAC,IACP7C,QAAK;QAAA,OAAEoB,WAAW;OAAC;OAAA,IACnBnH,WAAQ;QAAA,OAAEsB,MAAMtB;OAAQ;OAAA,KAAA,gBAAA;QAAA,OACZ,GAAGiH,IAAI9G,MAAK;OAAsB;OAAA,oBAC5BkH;OAAU,KAAA,kBAAA;QAAA,OACdC,cAAc;OAAC;OAAA,SAAA;OAE7BwB,UAAU5G,UACRmE,eAAeM,aAAa;QAC1B,GAAGA;SACFM,IAAI/G,OAAOgC,MAAM6G,cAAchD;OAClC,EAAE;OAEJiD,cAAcpC,WAAWK,IAAI/G,IAAI;OACjCwF,YAAYxD,UAAU;QACpB,IAAIA,MAAME,QAAQ,SAAS;QAC3BF,MAAMyB,eAAe;QACrBiD,WAAWK,IAAI/G,IAAI;OACrB;MAAC,CAAA,GAAAgI,KAAA;MAAAe,aAAAd,OAAA,MAMKd,UAAU;MAAAxC,OAAAsD,OAAAA,IACwCG,KAAA;MAAAzD,OAAAsD,OAAAA,IAC1BK,MAAA;MAAA,OAAAV;KAAA;IAAA,CAAA;GAK1C;EAAC,CAAA,CAAA;EAAA,OAAAf;CAAA,EAAA,CAAA;AAIT"}
@@ -1,4 +1,6 @@
1
1
  export { AppearanceEditor, AppearancePopover } from './appearance-editor';
2
+ export { AppearanceFontSettingsGroup, type AppearanceFontSettingsGroupProps, } from './font-settings-group';
3
+ export { APPEARANCE_EDITOR_FONT_AXES, APPEARANCE_EDITOR_FONT_SIZE_MAX, APPEARANCE_EDITOR_FONT_SIZE_MIN, DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS, applyAppearanceFontSettings, fontSettingsBootstrapScript, normalizeAppearanceEditorFontSettings, normalizeAppearanceEditorFontSize, type AppearanceEditorFontAxis, type AppearanceEditorFontFamilyId, type AppearanceEditorFontSetting, type AppearanceEditorFontSettings, type NormalizedAppearanceEditorFontSettings, } from '#lib/appearance-font-settings';
2
4
  export type { AppearanceDraft, AppearanceEditorProps, AppearancePopoverProps, } from './appearance-types';
3
5
  export { ThemeMiniature, ThemeMiniatureSplit, PalettePreview, type ThemeMiniatureProps, } from './theme-preview';
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/appearance-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACzE,YAAY,EACV,eAAe,EACf,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,KAAK,mBAAmB,GACzB,MAAM,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/appearance-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACzE,OAAO,EACL,2BAA2B,EAC3B,KAAK,gCAAgC,GACtC,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,2BAA2B,EAC3B,+BAA+B,EAC/B,+BAA+B,EAC/B,uCAAuC,EACvC,2BAA2B,EAC3B,2BAA2B,EAC3B,qCAAqC,EACrC,iCAAiC,EACjC,KAAK,wBAAwB,EAC7B,KAAK,4BAA4B,EACjC,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EACjC,KAAK,sCAAsC,GAC5C,MAAM,+BAA+B,CAAA;AACtC,YAAY,EACV,eAAe,EACf,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,KAAK,mBAAmB,GACzB,MAAM,iBAAiB,CAAA"}
@@ -1,3 +1,5 @@
1
+ import { APPEARANCE_EDITOR_FONT_AXES, APPEARANCE_EDITOR_FONT_SIZE_MAX, APPEARANCE_EDITOR_FONT_SIZE_MIN, DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS, applyAppearanceFontSettings, fontSettingsBootstrapScript, normalizeAppearanceEditorFontSettings, normalizeAppearanceEditorFontSize } from "../../../lib/appearance-font-settings.js";
1
2
  import { PalettePreview, ThemeMiniature, ThemeMiniatureSplit } from "./theme-preview.js";
3
+ import { AppearanceFontSettingsGroup } from "./font-settings-group.js";
2
4
  import { AppearanceEditor, AppearancePopover } from "./appearance-editor.js";
3
- export { AppearanceEditor, AppearancePopover, PalettePreview, ThemeMiniature, ThemeMiniatureSplit };
5
+ export { APPEARANCE_EDITOR_FONT_AXES, APPEARANCE_EDITOR_FONT_SIZE_MAX, APPEARANCE_EDITOR_FONT_SIZE_MIN, AppearanceEditor, AppearanceFontSettingsGroup, AppearancePopover, DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS, PalettePreview, ThemeMiniature, ThemeMiniatureSplit, applyAppearanceFontSettings, fontSettingsBootstrapScript, normalizeAppearanceEditorFontSettings, normalizeAppearanceEditorFontSize };