@adea-ai/ui 0.97.1 → 0.97.3

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 (37) hide show
  1. package/dist/components/composites/about-dialog/about-dialog.d.ts.map +1 -1
  2. package/dist/components/composites/about-dialog/about-dialog.js +2 -1
  3. package/dist/components/composites/about-dialog/about-dialog.js.map +1 -1
  4. package/dist/components/composites/account-menu/account-menu.d.ts.map +1 -1
  5. package/dist/components/composites/account-menu/account-menu.js +95 -99
  6. package/dist/components/composites/account-menu/account-menu.js.map +1 -1
  7. package/dist/components/composites/appearance-editor/appearance-choices.d.ts.map +1 -1
  8. package/dist/components/composites/appearance-editor/appearance-choices.js +44 -42
  9. package/dist/components/composites/appearance-editor/appearance-choices.js.map +1 -1
  10. package/dist/components/composites/appearance-editor/appearance-editor.d.ts.map +1 -1
  11. package/dist/components/composites/appearance-editor/appearance-editor.js +23 -1
  12. package/dist/components/composites/appearance-editor/appearance-editor.js.map +1 -1
  13. package/dist/components/composites/appearance-editor/appearance-rows.d.ts +22 -5
  14. package/dist/components/composites/appearance-editor/appearance-rows.d.ts.map +1 -1
  15. package/dist/components/composites/appearance-editor/appearance-rows.js +249 -152
  16. package/dist/components/composites/appearance-editor/appearance-rows.js.map +1 -1
  17. package/dist/components/composites/appearance-editor/appearance-types.d.ts +7 -0
  18. package/dist/components/composites/appearance-editor/appearance-types.d.ts.map +1 -1
  19. package/dist/components/composites/appearance-editor/theme-preview.d.ts +10 -0
  20. package/dist/components/composites/appearance-editor/theme-preview.d.ts.map +1 -1
  21. package/dist/components/composites/appearance-editor/theme-preview.js +61 -12
  22. package/dist/components/composites/appearance-editor/theme-preview.js.map +1 -1
  23. package/dist/r/src/components/composites/about-dialog/about-dialog.tsx +6 -1
  24. package/dist/r/src/components/composites/account-menu/account-menu.tsx +2 -1
  25. package/dist/r/src/components/composites/appearance-editor/appearance-choices.tsx +19 -14
  26. package/dist/r/src/components/composites/appearance-editor/appearance-editor.tsx +13 -1
  27. package/dist/r/src/components/composites/appearance-editor/appearance-rows.tsx +270 -160
  28. package/dist/r/src/components/composites/appearance-editor/appearance-types.ts +7 -0
  29. package/dist/r/src/components/composites/appearance-editor/theme-preview.tsx +58 -0
  30. package/package.json +1 -1
  31. package/src/components/composites/about-dialog/about-dialog.tsx +6 -1
  32. package/src/components/composites/account-menu/account-menu.tsx +2 -1
  33. package/src/components/composites/appearance-editor/appearance-choices.tsx +19 -14
  34. package/src/components/composites/appearance-editor/appearance-editor.tsx +13 -1
  35. package/src/components/composites/appearance-editor/appearance-rows.tsx +270 -160
  36. package/src/components/composites/appearance-editor/appearance-types.ts +7 -0
  37. package/src/components/composites/appearance-editor/theme-preview.tsx +58 -0
@@ -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","SettingsRow","ThemeRow","AppearanceEditor","props","errorId","saveReasonId","custom","draft","accent","accentOptions","some","option","id","accentDescription","name","find","label","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","title","icon","description","_el$4","_tmpl$3","_el$5","_$setAttribute","value","aria-invalid","customAccentError","aria-describedby","undefined","onInput","event","currentTarget","_el$6","_tmpl$2","_$memo","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 } from './appearance-choices'\nimport { SettingsRow, 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 = () =>\n props.draft.accent !== 'theme' &&\n !props.accentOptions.some((option) => option.id === props.draft.accent)\n const accentDescription = () => {\n if (props.draft.accent === 'theme') return \"Theme default · Uses the palette's intended color.\"\n const name = props.accentOptions.find((option) => option.id === props.draft.accent)?.label\n return `${name ?? 'Custom'} · Controls, glyphs, selections, code, and activity.`\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 <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","createUniqueId","cn","Button","Input","Switch","Popover","PopoverContent","PopoverDescription","PopoverTitle","PopoverTrigger","AppearanceEditorProps","AppearancePopoverProps","ModeChoices","AccentChoices","GlassChoices","SettingsRow","TerminalRow","ThemeRow","AppearanceEditor","props","errorId","saveReasonId","custom","draft","accent","accentOptions","some","option","id","accentDescription","name","find","label","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 } 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 = () =>\n props.draft.accent !== 'theme' &&\n !props.accentOptions.some((option) => option.id === props.draft.accent)\n const accentDescription = () => {\n if (props.draft.accent === 'theme') return \"Theme default · Uses the palette's intended color.\"\n const name = props.accentOptions.find((option) => option.id === props.draft.accent)?.label\n return `${name ?? 'Custom'} · Controls, glyphs, selections, code, and activity.`\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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"}
@@ -7,12 +7,15 @@ export declare function SettingsRow(props: {
7
7
  stacked?: boolean;
8
8
  children: JSX.Element;
9
9
  }): JSX.Element;
10
+ /** One selectable palette in a theme menu. */
11
+ export type ThemeOption = {
12
+ id: string;
13
+ name: string;
14
+ description?: string;
15
+ preview: AdeaTheme;
16
+ };
10
17
  /**
11
- * A compact persistent theme choice. Kobalte handles menu navigation and
12
- * dismissal; this row moves Tab to the adjacent browser-reported stop because
13
- * menus consume Tab by default. Enumerating elements and checking their native
14
- * tabIndex keeps details summaries in the order while preserving explicit
15
- * tabindex overrides.
18
+ * A compact persistent theme choice for one appearance.
16
19
  */
17
20
  export declare function ThemeRow(props: {
18
21
  appearance: 'light' | 'dark';
@@ -22,4 +25,18 @@ export declare function ThemeRow(props: {
22
25
  disabled?: boolean;
23
26
  onSelect: (id: string) => void;
24
27
  }): JSX.Element;
28
+ /**
29
+ * A terminal palette choice independent of the light/dark rows. The first
30
+ * option (`'theme'`) follows the interface theme, painted with the resolved
31
+ * preview; every catalogue record follows, both appearances, because the
32
+ * terminal paints one fixed ANSI palette rather than an appearance axis.
33
+ */
34
+ export declare function TerminalRow(props: {
35
+ selectedId: string;
36
+ /** Resolved interface theme: the `theme` option's palette and the fallback. */
37
+ preview: AdeaTheme;
38
+ themes: readonly AdeaThemeRecord[];
39
+ disabled?: boolean;
40
+ onSelect: (id: string) => void;
41
+ }): JSX.Element;
25
42
  //# sourceMappingURL=appearance-rows.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"appearance-rows.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/appearance-editor/appearance-rows.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EAAkD,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AA2BnF,wBAAgB,WAAW,CAAC,KAAK,EAAE;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,GAAG,CAAC,OAAO,CAAA;IACjB,WAAW,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACzB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;CACtB,eA4BA;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE;IAC9B,UAAU,EAAE,OAAO,GAAG,MAAM,CAAA;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,SAAS,CAAA;IAClB,MAAM,EAAE,SAAS,eAAe,EAAE,CAAA;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAC/B,eA6NA"}
1
+ {"version":3,"file":"appearance-rows.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/appearance-editor/appearance-rows.tsx"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EAAkD,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AA2BnF,wBAAgB,WAAW,CAAC,KAAK,EAAE;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,GAAG,CAAC,OAAO,CAAA;IACjB,WAAW,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACzB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;CACtB,eA4BA;AAED,8CAA8C;AAC9C,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,SAAS,CAAA;CACnB,CAAA;AA+PD;;GAEG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE;IAC9B,UAAU,EAAE,OAAO,GAAG,MAAM,CAAA;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,SAAS,CAAA;IAClB,MAAM,EAAE,SAAS,eAAe,EAAE,CAAA;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAC/B,eAwBA;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,+EAA+E;IAC/E,OAAO,EAAE,SAAS,CAAA;IAClB,MAAM,EAAE,SAAS,eAAe,EAAE,CAAA;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAC/B,eAgCA"}
@@ -1,16 +1,17 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
2
  import { Button } from "../../ui/button/button.js";
3
3
  import { DropdownMenu, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger } from "../../ui/dropdown-menu/dropdown-menu.js";
4
- import { PalettePreview } from "./theme-preview.js";
4
+ import { PalettePreview, ThemeMenuPreview } from "./theme-preview.js";
5
5
  import { className, createComponent, effect, insert, template, use } from "solid-js/web";
6
- import { ChevronDown, Palette } from "lucide-solid";
6
+ import { ChevronDown, Palette, SquareTerminal } from "lucide-solid";
7
7
  import { For, Show, createMemo, createSignal, onCleanup } from "solid-js";
8
8
  //#region src/components/composites/appearance-editor/appearance-rows.tsx
9
9
  var _tmpl$ = /*#__PURE__*/ template(`<div class="mt-0.5 text-xs text-muted-foreground">`);
10
10
  var _tmpl$2 = /*#__PURE__*/ template(`<section><div><span class="flex size-9 shrink-0 items-center justify-center rounded-lg border bg-foreground/5 text-muted-foreground [&amp;_svg]:size-4"aria-hidden=true></span><div class=min-w-0><h3 class="text-sm font-medium"></h3></div></div><div class="min-w-0 max-w-full shrink-0">`);
11
11
  var _tmpl$3 = /*#__PURE__*/ template(`<span class="flex min-w-0 flex-1 items-center gap-2"><span class="min-w-0 flex-1 truncate">`);
12
12
  var _tmpl$4 = /*#__PURE__*/ template(`<div>`);
13
- var _tmpl$5 = /*#__PURE__*/ template(`<span class="min-w-0 flex-1 truncate">`);
13
+ var _tmpl$5 = /*#__PURE__*/ template(`<span aria-hidden=true class="line-clamp-2 max-w-44 text-2xs text-muted-foreground">`);
14
+ var _tmpl$6 = /*#__PURE__*/ template(`<span class="flex min-w-0 flex-1 flex-col gap-0.5"><span class=truncate>`);
14
15
  var POINTER_FOCUS_TARGET_SELECTOR = "a[href], area[href], button, input, select, textarea, iframe, [tabindex], [contenteditable], details > summary:first-of-type";
15
16
  function isTabStop(element) {
16
17
  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;
@@ -47,13 +48,15 @@ function SettingsRow(props) {
47
48
  })();
48
49
  }
49
50
  /**
50
- * A compact persistent theme choice. Kobalte handles menu navigation and
51
- * dismissal; this row moves Tab to the adjacent browser-reported stop because
51
+ * The shared theme picker. Kobalte handles menu navigation and dismissal;
52
+ * this component moves Tab to the adjacent browser-reported stop because
52
53
  * menus consume Tab by default. Enumerating elements and checking their native
53
54
  * tabIndex keeps details summaries in the order while preserving explicit
54
- * tabindex overrides.
55
+ * tabindex overrides. The menu width follows its content (bounded by the
56
+ * popper's available width) so a long theme name and its description render
57
+ * fully instead of truncating at the trigger's width.
55
58
  */
56
- function ThemeRow(props) {
59
+ function ThemeSelectMenu(props) {
57
60
  const [portalMount, setPortalMount] = createSignal();
58
61
  const [triggerElement, setTriggerElement] = createSignal();
59
62
  const [menuOpen, setMenuOpen] = createSignal(false);
@@ -64,9 +67,7 @@ function ThemeRow(props) {
64
67
  onCleanup(() => {
65
68
  focusLifecycleVersion += 1;
66
69
  });
67
- const options = createMemo(() => props.themes.filter((theme) => theme.appearance === props.appearance));
68
- const selected = createMemo(() => options().find((theme) => theme.id === props.selectedId) ?? options().find((theme) => theme.id === props.preview.id));
69
- const label = () => props.appearance === "light" ? "Light theme" : "Dark theme";
70
+ const selected = createMemo(() => props.options.find((option) => option.id === props.selectedId) ?? props.options.find((option) => option.id === props.triggerPreview.id));
70
71
  const closeMenu = () => {
71
72
  if (menuOpen()) focusLifecycleVersion += 1;
72
73
  setMenuOpen(false);
@@ -97,6 +98,176 @@ function ThemeRow(props) {
97
98
  closeMenu();
98
99
  }
99
100
  };
101
+ return (() => {
102
+ var _el$8 = _tmpl$4();
103
+ use(setPortalMount, _el$8);
104
+ insert(_el$8, createComponent(DropdownMenu, {
105
+ modal: false,
106
+ get open() {
107
+ return menuOpen();
108
+ },
109
+ onOpenChange: (open) => {
110
+ if (open !== menuOpen()) focusLifecycleVersion += 1;
111
+ setMenuOpen(open);
112
+ if (open) {
113
+ focusTargetAfterTab = void 0;
114
+ setFocusOutsideTarget(void 0);
115
+ setRestoreTriggerFocus(false);
116
+ }
117
+ },
118
+ get children() {
119
+ return [createComponent(DropdownMenuTrigger, {
120
+ ref: setTriggerElement,
121
+ as: Button,
122
+ variant: "outline",
123
+ size: "sm",
124
+ get ["aria-label"]() {
125
+ return props.label;
126
+ },
127
+ get disabled() {
128
+ return props.disabled || props.options.length === 0;
129
+ },
130
+ "class": "w-full justify-between sm:w-52",
131
+ get children() {
132
+ return [(() => {
133
+ var _el$9 = _tmpl$3(), _el$0 = _el$9.firstChild;
134
+ insert(_el$9, createComponent(PalettePreview, { get theme() {
135
+ return props.triggerPreview;
136
+ } }), _el$0);
137
+ insert(_el$0, () => selected()?.name ?? props.triggerPreview.name);
138
+ return _el$9;
139
+ })(), createComponent(ChevronDown, {
140
+ "aria-hidden": "true",
141
+ "class": "shrink-0 text-muted-foreground"
142
+ })];
143
+ }
144
+ }), createComponent(DropdownMenuContent, {
145
+ get portalMount() {
146
+ return portalMount();
147
+ },
148
+ "class": "max-h-(--kb-popper-content-available-height) w-max min-w-(--kb-popper-anchor-width) max-w-(--kb-popper-content-available-width) overflow-x-hidden overflow-y-auto",
149
+ onInteractOutside: (event) => {
150
+ if (event.detail.originalEvent.type !== "pointerdown") return;
151
+ const focusScope = portalMount()?.closest("[role=\"dialog\"]") ?? portalMount()?.ownerDocument.body;
152
+ const target = event.detail.originalEvent.target;
153
+ if (!(target instanceof Element) || !focusScope?.contains(target)) return;
154
+ const focusTarget = target.closest(POINTER_FOCUS_TARGET_SELECTOR);
155
+ if (focusTarget && isTabStop(focusTarget)) {
156
+ setRestoreTriggerFocus(false);
157
+ setFocusOutsideTarget(focusTarget);
158
+ } else setRestoreTriggerFocus(true);
159
+ },
160
+ onFocusOutside: (event) => {
161
+ const focusScope = portalMount()?.closest("[role=\"dialog\"]") ?? portalMount()?.ownerDocument.body;
162
+ const target = event.detail.originalEvent.target;
163
+ if (target === focusScope) event.preventDefault();
164
+ else if (target instanceof HTMLElement && focusScope?.contains(target)) {
165
+ setRestoreTriggerFocus(false);
166
+ setFocusOutsideTarget(target);
167
+ }
168
+ },
169
+ onEscapeKeyDown: () => setRestoreTriggerFocus(true),
170
+ onCloseAutoFocus: (event) => {
171
+ if (menuOpen()) {
172
+ event.preventDefault();
173
+ return;
174
+ }
175
+ const lifecycleVersion = focusLifecycleVersion;
176
+ const shouldRestore = restoreTriggerFocus();
177
+ const focusTarget = focusTargetAfterTab ?? focusOutsideTarget();
178
+ focusTargetAfterTab = void 0;
179
+ setFocusOutsideTarget(void 0);
180
+ setRestoreTriggerFocus(false);
181
+ if (shouldRestore) {
182
+ event.preventDefault();
183
+ triggerElement()?.focus({ preventScroll: true });
184
+ return;
185
+ }
186
+ const focusScope = portalMount()?.closest("[role=\"dialog\"]") ?? portalMount()?.ownerDocument.body;
187
+ if (focusTarget?.isConnected && focusScope?.contains(focusTarget)) {
188
+ event.preventDefault();
189
+ queueMicrotask(() => {
190
+ if (lifecycleVersion !== focusLifecycleVersion || menuOpen()) return;
191
+ const activeElement = document.activeElement;
192
+ const isMenuFocus = activeElement instanceof HTMLElement && activeElement.closest("[role=\"menu\"]") !== null;
193
+ const isTriggerFocus = activeElement === triggerElement();
194
+ if (activeElement !== focusTarget && (activeElement === document.body || activeElement === focusScope || isMenuFocus || isTriggerFocus)) focusTarget.focus({ preventScroll: true });
195
+ });
196
+ return;
197
+ }
198
+ const activeElement = document.activeElement;
199
+ if (focusScope && activeElement instanceof HTMLElement && activeElement !== focusScope && focusScope.contains(activeElement) && activeElement.closest("[role=\"menu\"]") === null) event.preventDefault();
200
+ },
201
+ get children() {
202
+ return createComponent(DropdownMenuRadioGroup, {
203
+ get value() {
204
+ return selected()?.id ?? "";
205
+ },
206
+ get ["aria-label"]() {
207
+ return `${props.label} options`;
208
+ },
209
+ "on:keydown": moveFocusOnTab,
210
+ onChange: (id) => {
211
+ if (!props.disabled && typeof id === "string") props.onSelect(id);
212
+ },
213
+ get children() {
214
+ return createComponent(For, {
215
+ get each() {
216
+ return props.options;
217
+ },
218
+ children: (option) => createComponent(DropdownMenuRadioItem, {
219
+ get value() {
220
+ return option.id;
221
+ },
222
+ get textValue() {
223
+ return option.name;
224
+ },
225
+ closeOnSelect: true,
226
+ get disabled() {
227
+ return props.disabled;
228
+ },
229
+ onSelect: () => setRestoreTriggerFocus(true),
230
+ get children() {
231
+ return [createComponent(ThemeMenuPreview, { get theme() {
232
+ return option.preview;
233
+ } }), (() => {
234
+ var _el$1 = _tmpl$6(), _el$10 = _el$1.firstChild;
235
+ insert(_el$10, () => option.name);
236
+ insert(_el$1, createComponent(Show, {
237
+ get when() {
238
+ return option.description;
239
+ },
240
+ get children() {
241
+ var _el$11 = _tmpl$5();
242
+ insert(_el$11, () => option.description);
243
+ return _el$11;
244
+ }
245
+ }), null);
246
+ return _el$1;
247
+ })()];
248
+ }
249
+ })
250
+ });
251
+ }
252
+ });
253
+ }
254
+ })];
255
+ }
256
+ }));
257
+ return _el$8;
258
+ })();
259
+ }
260
+ /**
261
+ * A compact persistent theme choice for one appearance.
262
+ */
263
+ function ThemeRow(props) {
264
+ const label = () => props.appearance === "light" ? "Light theme" : "Dark theme";
265
+ const options = createMemo(() => props.themes.filter((theme) => theme.appearance === props.appearance).map((theme) => ({
266
+ id: theme.id,
267
+ name: theme.name,
268
+ description: theme.description,
269
+ preview: theme
270
+ })));
100
271
  return createComponent(SettingsRow, {
101
272
  get title() {
102
273
  return label();
@@ -105,154 +276,80 @@ function ThemeRow(props) {
105
276
  return createComponent(Palette, {});
106
277
  },
107
278
  get children() {
108
- var _el$8 = _tmpl$4();
109
- use(setPortalMount, _el$8);
110
- insert(_el$8, createComponent(DropdownMenu, {
111
- modal: false,
112
- get open() {
113
- return menuOpen();
279
+ return createComponent(ThemeSelectMenu, {
280
+ get label() {
281
+ return label();
114
282
  },
115
- onOpenChange: (open) => {
116
- if (open !== menuOpen()) focusLifecycleVersion += 1;
117
- setMenuOpen(open);
118
- if (open) {
119
- focusTargetAfterTab = void 0;
120
- setFocusOutsideTarget(void 0);
121
- setRestoreTriggerFocus(false);
122
- }
283
+ get selectedId() {
284
+ return props.selectedId;
123
285
  },
124
- get children() {
125
- return [createComponent(DropdownMenuTrigger, {
126
- ref: setTriggerElement,
127
- as: Button,
128
- variant: "outline",
129
- size: "sm",
130
- get ["aria-label"]() {
131
- return label();
132
- },
133
- get disabled() {
134
- return props.disabled || options().length === 0;
135
- },
136
- "class": "w-full justify-between sm:w-52",
137
- get children() {
138
- return [(() => {
139
- var _el$9 = _tmpl$3(), _el$0 = _el$9.firstChild;
140
- insert(_el$9, createComponent(PalettePreview, { get theme() {
141
- return props.preview;
142
- } }), _el$0);
143
- insert(_el$0, () => selected()?.name ?? props.preview.name);
144
- return _el$9;
145
- })(), createComponent(ChevronDown, {
146
- "aria-hidden": "true",
147
- "class": "shrink-0 text-muted-foreground"
148
- })];
149
- }
150
- }), createComponent(DropdownMenuContent, {
151
- get portalMount() {
152
- return portalMount();
153
- },
154
- "class": "max-h-(--kb-popper-content-available-height) w-(--kb-popper-anchor-width) min-w-32 overflow-x-hidden overflow-y-auto",
155
- onInteractOutside: (event) => {
156
- if (event.detail.originalEvent.type !== "pointerdown") return;
157
- const focusScope = portalMount()?.closest("[role=\"dialog\"]") ?? portalMount()?.ownerDocument.body;
158
- const target = event.detail.originalEvent.target;
159
- if (!(target instanceof Element) || !focusScope?.contains(target)) return;
160
- const focusTarget = target.closest(POINTER_FOCUS_TARGET_SELECTOR);
161
- if (focusTarget && isTabStop(focusTarget)) {
162
- setRestoreTriggerFocus(false);
163
- setFocusOutsideTarget(focusTarget);
164
- } else setRestoreTriggerFocus(true);
165
- },
166
- onFocusOutside: (event) => {
167
- const focusScope = portalMount()?.closest("[role=\"dialog\"]") ?? portalMount()?.ownerDocument.body;
168
- const target = event.detail.originalEvent.target;
169
- if (target === focusScope) event.preventDefault();
170
- else if (target instanceof HTMLElement && focusScope?.contains(target)) {
171
- setRestoreTriggerFocus(false);
172
- setFocusOutsideTarget(target);
173
- }
174
- },
175
- onEscapeKeyDown: () => setRestoreTriggerFocus(true),
176
- onCloseAutoFocus: (event) => {
177
- if (menuOpen()) {
178
- event.preventDefault();
179
- return;
180
- }
181
- const lifecycleVersion = focusLifecycleVersion;
182
- const shouldRestore = restoreTriggerFocus();
183
- const focusTarget = focusTargetAfterTab ?? focusOutsideTarget();
184
- focusTargetAfterTab = void 0;
185
- setFocusOutsideTarget(void 0);
186
- setRestoreTriggerFocus(false);
187
- if (shouldRestore) {
188
- event.preventDefault();
189
- triggerElement()?.focus({ preventScroll: true });
190
- return;
191
- }
192
- const focusScope = portalMount()?.closest("[role=\"dialog\"]") ?? portalMount()?.ownerDocument.body;
193
- if (focusTarget?.isConnected && focusScope?.contains(focusTarget)) {
194
- event.preventDefault();
195
- queueMicrotask(() => {
196
- if (lifecycleVersion !== focusLifecycleVersion || menuOpen()) return;
197
- const activeElement = document.activeElement;
198
- const isMenuFocus = activeElement instanceof HTMLElement && activeElement.closest("[role=\"menu\"]") !== null;
199
- const isTriggerFocus = activeElement === triggerElement();
200
- if (activeElement !== focusTarget && (activeElement === document.body || activeElement === focusScope || isMenuFocus || isTriggerFocus)) focusTarget.focus({ preventScroll: true });
201
- });
202
- return;
203
- }
204
- const activeElement = document.activeElement;
205
- if (focusScope && activeElement instanceof HTMLElement && activeElement !== focusScope && focusScope.contains(activeElement) && activeElement.closest("[role=\"menu\"]") === null) event.preventDefault();
206
- },
207
- get children() {
208
- return createComponent(DropdownMenuRadioGroup, {
209
- get value() {
210
- return selected()?.id ?? "";
211
- },
212
- get ["aria-label"]() {
213
- return `${label()} options`;
214
- },
215
- "on:keydown": moveFocusOnTab,
216
- onChange: (id) => {
217
- if (!props.disabled && typeof id === "string") props.onSelect(id);
218
- },
219
- get children() {
220
- return createComponent(For, {
221
- get each() {
222
- return options();
223
- },
224
- children: (theme) => createComponent(DropdownMenuRadioItem, {
225
- get value() {
226
- return theme.id;
227
- },
228
- get textValue() {
229
- return theme.name;
230
- },
231
- closeOnSelect: true,
232
- get disabled() {
233
- return props.disabled;
234
- },
235
- onSelect: () => setRestoreTriggerFocus(true),
236
- get children() {
237
- return [createComponent(PalettePreview, { theme }), (() => {
238
- var _el$1 = _tmpl$5();
239
- insert(_el$1, () => theme.name);
240
- return _el$1;
241
- })()];
242
- }
243
- })
244
- });
245
- }
246
- });
247
- }
248
- })];
286
+ get triggerPreview() {
287
+ return props.preview;
288
+ },
289
+ get options() {
290
+ return options();
291
+ },
292
+ get disabled() {
293
+ return props.disabled;
294
+ },
295
+ get onSelect() {
296
+ return props.onSelect;
297
+ }
298
+ });
299
+ }
300
+ });
301
+ }
302
+ /**
303
+ * A terminal palette choice independent of the light/dark rows. The first
304
+ * option (`'theme'`) follows the interface theme, painted with the resolved
305
+ * preview; every catalogue record follows, both appearances, because the
306
+ * terminal paints one fixed ANSI palette rather than an appearance axis.
307
+ */
308
+ function TerminalRow(props) {
309
+ const options = createMemo(() => [{
310
+ id: "theme",
311
+ name: "UI theme",
312
+ description: "Uses the interface theme.",
313
+ preview: props.preview
314
+ }, ...props.themes.map((theme) => ({
315
+ id: theme.id,
316
+ name: theme.name,
317
+ description: theme.description,
318
+ preview: theme
319
+ }))]);
320
+ const selectedOption = () => options().find((option) => option.id === props.selectedId);
321
+ const description = () => selectedOption() && selectedOption()?.id !== "theme" ? `The terminal follows ${selectedOption()?.name}.` : "The terminal follows the interface theme.";
322
+ return createComponent(SettingsRow, {
323
+ title: "Terminal",
324
+ get icon() {
325
+ return createComponent(SquareTerminal, {});
326
+ },
327
+ get description() {
328
+ return description();
329
+ },
330
+ get children() {
331
+ return createComponent(ThemeSelectMenu, {
332
+ label: "Terminal",
333
+ get selectedId() {
334
+ return props.selectedId;
335
+ },
336
+ get triggerPreview() {
337
+ return selectedOption()?.preview ?? props.preview;
338
+ },
339
+ get options() {
340
+ return options();
341
+ },
342
+ get disabled() {
343
+ return props.disabled;
344
+ },
345
+ get onSelect() {
346
+ return props.onSelect;
249
347
  }
250
- }));
251
- return _el$8;
348
+ });
252
349
  }
253
350
  });
254
351
  }
255
352
  //#endregion
256
- export { SettingsRow, ThemeRow };
353
+ export { SettingsRow, TerminalRow, ThemeRow };
257
354
 
258
355
  //# sourceMappingURL=appearance-rows.js.map