@adea-ai/ui 0.69.0 → 0.70.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.
- package/README.md +14 -9
- package/dist/components/composites/appearance-editor/appearance-editor.d.ts +1 -1
- package/dist/components/composites/appearance-editor/appearance-editor.js +1 -1
- package/dist/components/composites/appearance-editor/appearance-editor.js.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-rows.d.ts +7 -0
- package/dist/components/composites/appearance-editor/appearance-rows.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-rows.js +187 -41
- package/dist/components/composites/appearance-editor/appearance-rows.js.map +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts +6 -4
- package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu.js +21 -15
- package/dist/components/ui/dropdown-menu/dropdown-menu.js.map +1 -1
- package/dist/r/appearance-editor.json +1 -1
- package/dist/r/registry.json +1 -1
- package/dist/r/src/components/composites/appearance-editor/appearance-editor.tsx +1 -1
- package/dist/r/src/components/composites/appearance-editor/appearance-rows.tsx +231 -34
- package/dist/r/src/components/ui/dropdown-menu/dropdown-menu.tsx +8 -6
- package/package.json +1 -1
- package/registry.json +1 -1
- package/src/components/composites/appearance-editor/appearance-editor.tsx +1 -1
- package/src/components/composites/appearance-editor/appearance-rows.tsx +231 -34
- package/src/components/ui/dropdown-menu/dropdown-menu.tsx +8 -6
package/README.md
CHANGED
|
@@ -457,8 +457,10 @@ and publication; textarea editing and production adoption remain separate gates.
|
|
|
457
457
|
System/Light/Dark miniature cards, independent light/dark theme rows, palette
|
|
458
458
|
swatches, default/preset/custom accent choices and Theme default/Frosted/Opaque
|
|
459
459
|
surface choices. The popup supports live host preview and Save/Cancel/Reset;
|
|
460
|
-
Kobalte
|
|
461
|
-
|
|
460
|
+
Kobalte provides radio navigation, selection, dismissal and focus restoration. Since
|
|
461
|
+
its menus prevent Tab, the theme row carries Tab and Shift+Tab through the enclosing
|
|
462
|
+
dialog's focus order. `DropdownMenuContent.portalMount` keeps the theme menu within
|
|
463
|
+
its enclosing modal's accessible subtree.
|
|
462
464
|
|
|
463
465
|
Supply canonical `AdeaTheme` previews and `AdeaThemeRecord` choices from
|
|
464
466
|
`@adea-ai/themes`, including any validated accent overlay. The editor imports
|
|
@@ -473,8 +475,9 @@ surface selection. The library does not silently migrate stored preferences.
|
|
|
473
475
|
|
|
474
476
|
The component browser lane uses a real Vite/Solid/Tailwind build in headless
|
|
475
477
|
Chromium without an app server. It checks keyboard mode selection, nested menu
|
|
476
|
-
accessibility and Escape, live-preview rollback,
|
|
477
|
-
Save pending state, mobile selection and
|
|
478
|
+
accessibility, focus and pointer dismissal, Escape, live-preview rollback,
|
|
479
|
+
valid/invalid custom accents, Save pending state, mobile selection and
|
|
480
|
+
320/768/1024/1440px layouts. A separate native Node server-render fixture verifies the composed editor without
|
|
478
481
|
browser or application globals. These checks
|
|
479
482
|
are component integration evidence; they do not certify application persistence,
|
|
480
483
|
native effects, packaged applications or manual assistive technology acceptance.
|
|
@@ -482,8 +485,9 @@ native effects, packaged applications or manual assistive technology acceptance.
|
|
|
482
485
|
### Packed appearance contract
|
|
483
486
|
|
|
484
487
|
`bun run check:packed-appearance` installs the actual tarball without optional
|
|
485
|
-
Chart/Carousel engines, then
|
|
486
|
-
|
|
488
|
+
Chart/Carousel engines, then runs all 25 component cases in Chromium and WebKit
|
|
489
|
+
against compiled and Solid entries (100 execution runs total).
|
|
490
|
+
The same fixture verifies
|
|
487
491
|
Solid source SSR in native Node. Keyboard choices, live preview, save/cancel/reset,
|
|
488
492
|
nested dismissal, validation, pending save, narrow layouts with reachable footer actions, and automated accessibility
|
|
489
493
|
are covered. Production persistence, native transparency, hydration and manual AT
|
|
@@ -493,9 +497,10 @@ The disposable host explicitly imports four isolated canonical theme records plu
|
|
|
493
497
|
color/CSS adapters from published `@adea-ai/themes`; the UI composition imports only
|
|
494
498
|
theme types. Both conditions retain one Solid runtime and one JS chunk, external CSS,
|
|
495
499
|
no fonts or unrelated engines, and full donor attribution. The combined host/editor
|
|
496
|
-
budgets are 64 KiB gzip JS and 50 KiB raw CSS; measured baselines are
|
|
497
|
-
|
|
498
|
-
|
|
500
|
+
budgets are 64 KiB gzip JS and 50 KiB raw CSS; measured baselines are 63,599 gzip
|
|
501
|
+
JS / 50,059 raw CSS bytes for compiled and 64,126 gzip JS / 50,059 raw CSS bytes
|
|
502
|
+
for Solid, with complete discovery of nested controls and shared helpers. This
|
|
503
|
+
includes host theme-preview behavior, not just the editor primitive.
|
|
499
504
|
|
|
500
505
|
Local packed interaction gates require `bunx playwright install chromium webkit`
|
|
501
506
|
after dependency installation. On Linux, use `--with-deps` when the required
|
|
@@ -8,7 +8,7 @@ import type { AppearanceEditorProps, AppearancePopoverProps } from './appearance
|
|
|
8
8
|
* deliberately absent from Adea #425's accepted surface.
|
|
9
9
|
*/
|
|
10
10
|
export declare function AppearanceEditor(props: AppearanceEditorProps): import("solid-js").JSX.Element;
|
|
11
|
-
/** Modal anchoring/dismissal and nested-
|
|
11
|
+
/** Modal anchoring/dismissal and nested-menu behavior come from Kobalte.
|
|
12
12
|
* Its measured available height also bounds scrolling, keeping footer actions
|
|
13
13
|
* reachable when a narrow popup begins below its trigger. */
|
|
14
14
|
export declare function AppearancePopover(props: AppearancePopoverProps): import("solid-js").JSX.Element;
|
|
@@ -241,7 +241,7 @@ function AppearanceEditor(props) {
|
|
|
241
241
|
return _el$;
|
|
242
242
|
})();
|
|
243
243
|
}
|
|
244
|
-
/** Modal anchoring/dismissal and nested-
|
|
244
|
+
/** Modal anchoring/dismissal and nested-menu behavior come from Kobalte.
|
|
245
245
|
* Its measured available height also bounds scrolling, keeping footer actions
|
|
246
246
|
* reachable when a narrow popup begins below its trigger. */
|
|
247
247
|
function AppearancePopover(props) {
|
|
@@ -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","stacked","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\n stacked\n title=\"Accent\"\n icon={<SlidersHorizontal />}\n description={accentDescription()}\n >\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-destructive\">\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 <div class=\"flex flex-wrap items-center gap-2 px-4 py-4\">\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-listbox 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","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","stacked","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\n stacked\n title=\"Accent\"\n icon={<SlidersHorizontal />}\n description={accentDescription()}\n >\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-destructive\">\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 <div class=\"flex flex-wrap items-center gap-2 px-4 py-4\">\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,6 +7,13 @@ export declare function SettingsRow(props: {
|
|
|
7
7
|
stacked?: boolean;
|
|
8
8
|
children: JSX.Element;
|
|
9
9
|
}): JSX.Element;
|
|
10
|
+
/**
|
|
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.
|
|
16
|
+
*/
|
|
10
17
|
export declare function ThemeRow(props: {
|
|
11
18
|
appearance: 'light' | 'dark';
|
|
12
19
|
selectedId: string;
|
|
@@ -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,
|
|
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,eAsBA;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,14 +1,20 @@
|
|
|
1
1
|
import { cn } from "../../../lib/utils.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Button } from "../../ui/button/button.js";
|
|
3
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger } from "../../ui/dropdown-menu/dropdown-menu.js";
|
|
3
4
|
import { PalettePreview } from "./theme-preview.js";
|
|
4
|
-
import { className, createComponent, effect, insert,
|
|
5
|
-
import { Palette } from "lucide-solid";
|
|
6
|
-
import { Show, createMemo, createSignal } from "solid-js";
|
|
5
|
+
import { className, createComponent, effect, insert, template, use } from "solid-js/web";
|
|
6
|
+
import { ChevronDown, Palette } from "lucide-solid";
|
|
7
|
+
import { For, Show, createMemo, createSignal, onCleanup } from "solid-js";
|
|
7
8
|
//#region src/components/composites/appearance-editor/appearance-rows.tsx
|
|
8
9
|
var _tmpl$ = /*#__PURE__*/ template(`<div class="mt-0.5 text-xs text-muted-foreground">`);
|
|
9
10
|
var _tmpl$2 = /*#__PURE__*/ template(`<section><div class="flex min-w-0 flex-1 items-center gap-3"><span class="flex size-9 shrink-0 items-center justify-center rounded-lg border bg-foreground/5 text-muted-foreground [&_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 shrink-0">`);
|
|
10
|
-
var _tmpl$3 = /*#__PURE__*/ template(`<
|
|
11
|
-
var _tmpl$4 = /*#__PURE__*/ template(`<
|
|
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
|
+
var _tmpl$4 = /*#__PURE__*/ template(`<div>`);
|
|
13
|
+
var _tmpl$5 = /*#__PURE__*/ template(`<span class="min-w-0 flex-1 truncate">`);
|
|
14
|
+
var POINTER_FOCUS_TARGET_SELECTOR = "a[href], area[href], button, input, select, textarea, iframe, [tabindex], [contenteditable], details > summary:first-of-type";
|
|
15
|
+
function isTabStop(element) {
|
|
16
|
+
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;
|
|
17
|
+
}
|
|
12
18
|
function SettingsRow(props) {
|
|
13
19
|
return (() => {
|
|
14
20
|
var _el$ = _tmpl$2(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling, _el$5 = _el$4.firstChild, _el$7 = _el$2.nextSibling;
|
|
@@ -29,11 +35,57 @@ function SettingsRow(props) {
|
|
|
29
35
|
return _el$;
|
|
30
36
|
})();
|
|
31
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* A compact persistent theme choice. Kobalte handles menu navigation and
|
|
40
|
+
* dismissal; this row moves Tab to the adjacent browser-reported stop because
|
|
41
|
+
* menus consume Tab by default. Enumerating elements and checking their native
|
|
42
|
+
* tabIndex keeps details summaries in the order while preserving explicit
|
|
43
|
+
* tabindex overrides.
|
|
44
|
+
*/
|
|
32
45
|
function ThemeRow(props) {
|
|
33
46
|
const [portalMount, setPortalMount] = createSignal();
|
|
47
|
+
const [triggerElement, setTriggerElement] = createSignal();
|
|
48
|
+
const [menuOpen, setMenuOpen] = createSignal(false);
|
|
49
|
+
const [focusOutsideTarget, setFocusOutsideTarget] = createSignal();
|
|
50
|
+
const [restoreTriggerFocus, setRestoreTriggerFocus] = createSignal(false);
|
|
51
|
+
let focusTargetAfterTab;
|
|
52
|
+
let focusLifecycleVersion = 0;
|
|
53
|
+
onCleanup(() => {
|
|
54
|
+
focusLifecycleVersion += 1;
|
|
55
|
+
});
|
|
34
56
|
const options = createMemo(() => props.themes.filter((theme) => theme.appearance === props.appearance));
|
|
35
57
|
const selected = createMemo(() => options().find((theme) => theme.id === props.selectedId) ?? options().find((theme) => theme.id === props.preview.id));
|
|
36
58
|
const label = () => props.appearance === "light" ? "Light theme" : "Dark theme";
|
|
59
|
+
const closeMenu = () => {
|
|
60
|
+
if (menuOpen()) focusLifecycleVersion += 1;
|
|
61
|
+
setMenuOpen(false);
|
|
62
|
+
};
|
|
63
|
+
const moveFocusOnTab = (event) => {
|
|
64
|
+
if (event.key !== "Tab" || event.isComposing) return;
|
|
65
|
+
const trigger = triggerElement();
|
|
66
|
+
if (!trigger) return;
|
|
67
|
+
const parentDialog = portalMount()?.closest("[role=\"dialog\"]");
|
|
68
|
+
const focusScope = parentDialog ?? portalMount()?.ownerDocument.body;
|
|
69
|
+
if (!focusScope) return;
|
|
70
|
+
const focusStops = Array.from(focusScope.querySelectorAll("*")).filter((element) => isTabStop(element) && element.closest("[role=\"menu\"], [hidden], [inert], [aria-hidden=\"true\"]") === null);
|
|
71
|
+
const orderedFocusStops = [...focusStops.filter((element) => element.tabIndex > 0).toSorted((a, b) => a.tabIndex - b.tabIndex), ...focusStops.filter((element) => element.tabIndex <= 0)];
|
|
72
|
+
const triggerIndex = orderedFocusStops.indexOf(trigger);
|
|
73
|
+
const direction = event.shiftKey ? -1 : 1;
|
|
74
|
+
const adjacent = orderedFocusStops[triggerIndex + direction] ?? (parentDialog ? direction > 0 ? orderedFocusStops[0] : orderedFocusStops.at(-1) : void 0);
|
|
75
|
+
event.stopPropagation();
|
|
76
|
+
setRestoreTriggerFocus(false);
|
|
77
|
+
if (adjacent) {
|
|
78
|
+
event.preventDefault();
|
|
79
|
+
focusTargetAfterTab = adjacent;
|
|
80
|
+
setFocusOutsideTarget(adjacent);
|
|
81
|
+
closeMenu();
|
|
82
|
+
adjacent.focus({ preventScroll: true });
|
|
83
|
+
} else {
|
|
84
|
+
focusTargetAfterTab = void 0;
|
|
85
|
+
setFocusOutsideTarget(void 0);
|
|
86
|
+
closeMenu();
|
|
87
|
+
}
|
|
88
|
+
};
|
|
37
89
|
return createComponent(SettingsRow, {
|
|
38
90
|
get title() {
|
|
39
91
|
return label();
|
|
@@ -42,53 +94,147 @@ function ThemeRow(props) {
|
|
|
42
94
|
return createComponent(Palette, {});
|
|
43
95
|
},
|
|
44
96
|
get children() {
|
|
45
|
-
var _el$8 = _tmpl$
|
|
97
|
+
var _el$8 = _tmpl$4();
|
|
46
98
|
use(setPortalMount, _el$8);
|
|
47
|
-
insert(_el$8, createComponent(
|
|
99
|
+
insert(_el$8, createComponent(DropdownMenu, {
|
|
48
100
|
modal: false,
|
|
49
|
-
get
|
|
50
|
-
return
|
|
51
|
-
},
|
|
52
|
-
get value() {
|
|
53
|
-
return selected();
|
|
101
|
+
get open() {
|
|
102
|
+
return menuOpen();
|
|
54
103
|
},
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
},
|
|
63
|
-
itemComponent: (item) => createComponent(SelectItem, {
|
|
64
|
-
get item() {
|
|
65
|
-
return item.item;
|
|
66
|
-
},
|
|
67
|
-
get children() {
|
|
68
|
-
return [createComponent(PalettePreview, { get theme() {
|
|
69
|
-
return item.item.rawValue;
|
|
70
|
-
} }), memo(() => item.item.rawValue.name)];
|
|
104
|
+
onOpenChange: (open) => {
|
|
105
|
+
if (open !== menuOpen()) focusLifecycleVersion += 1;
|
|
106
|
+
setMenuOpen(open);
|
|
107
|
+
if (open) {
|
|
108
|
+
focusTargetAfterTab = void 0;
|
|
109
|
+
setFocusOutsideTarget(void 0);
|
|
110
|
+
setRestoreTriggerFocus(false);
|
|
71
111
|
}
|
|
72
|
-
}
|
|
112
|
+
},
|
|
73
113
|
get children() {
|
|
74
|
-
return [createComponent(
|
|
114
|
+
return [createComponent(DropdownMenuTrigger, {
|
|
115
|
+
ref: setTriggerElement,
|
|
116
|
+
as: Button,
|
|
117
|
+
variant: "outline",
|
|
75
118
|
size: "sm",
|
|
76
119
|
get ["aria-label"]() {
|
|
77
120
|
return label();
|
|
78
121
|
},
|
|
79
|
-
|
|
122
|
+
get disabled() {
|
|
123
|
+
return props.disabled || options().length === 0;
|
|
124
|
+
},
|
|
125
|
+
"class": "w-full justify-between sm:w-52",
|
|
80
126
|
get children() {
|
|
81
|
-
return
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
127
|
+
return [(() => {
|
|
128
|
+
var _el$9 = _tmpl$3(), _el$0 = _el$9.firstChild;
|
|
129
|
+
insert(_el$9, createComponent(PalettePreview, { get theme() {
|
|
130
|
+
return props.preview;
|
|
131
|
+
} }), _el$0);
|
|
132
|
+
insert(_el$0, () => selected()?.name ?? props.preview.name);
|
|
86
133
|
return _el$9;
|
|
87
|
-
})()
|
|
134
|
+
})(), createComponent(ChevronDown, {
|
|
135
|
+
"aria-hidden": "true",
|
|
136
|
+
"class": "shrink-0 text-muted-foreground"
|
|
137
|
+
})];
|
|
138
|
+
}
|
|
139
|
+
}), createComponent(DropdownMenuContent, {
|
|
140
|
+
get portalMount() {
|
|
141
|
+
return portalMount();
|
|
142
|
+
},
|
|
143
|
+
"class": "max-h-(--kb-popper-content-available-height) w-(--kb-popper-anchor-width) min-w-32 overflow-x-hidden overflow-y-auto",
|
|
144
|
+
onInteractOutside: (event) => {
|
|
145
|
+
if (event.detail.originalEvent.type !== "pointerdown") return;
|
|
146
|
+
const focusScope = portalMount()?.closest("[role=\"dialog\"]") ?? portalMount()?.ownerDocument.body;
|
|
147
|
+
const target = event.detail.originalEvent.target;
|
|
148
|
+
if (!(target instanceof Element) || !focusScope?.contains(target)) return;
|
|
149
|
+
const focusTarget = target.closest(POINTER_FOCUS_TARGET_SELECTOR);
|
|
150
|
+
if (focusTarget && isTabStop(focusTarget)) {
|
|
151
|
+
setRestoreTriggerFocus(false);
|
|
152
|
+
setFocusOutsideTarget(focusTarget);
|
|
153
|
+
} else setRestoreTriggerFocus(true);
|
|
154
|
+
},
|
|
155
|
+
onFocusOutside: (event) => {
|
|
156
|
+
const focusScope = portalMount()?.closest("[role=\"dialog\"]") ?? portalMount()?.ownerDocument.body;
|
|
157
|
+
const target = event.detail.originalEvent.target;
|
|
158
|
+
if (target === focusScope) event.preventDefault();
|
|
159
|
+
else if (target instanceof HTMLElement && focusScope?.contains(target)) {
|
|
160
|
+
setRestoreTriggerFocus(false);
|
|
161
|
+
setFocusOutsideTarget(target);
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
onEscapeKeyDown: () => setRestoreTriggerFocus(true),
|
|
165
|
+
onCloseAutoFocus: (event) => {
|
|
166
|
+
if (menuOpen()) {
|
|
167
|
+
event.preventDefault();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const lifecycleVersion = focusLifecycleVersion;
|
|
171
|
+
const shouldRestore = restoreTriggerFocus();
|
|
172
|
+
const focusTarget = focusTargetAfterTab ?? focusOutsideTarget();
|
|
173
|
+
focusTargetAfterTab = void 0;
|
|
174
|
+
setFocusOutsideTarget(void 0);
|
|
175
|
+
setRestoreTriggerFocus(false);
|
|
176
|
+
if (shouldRestore) {
|
|
177
|
+
event.preventDefault();
|
|
178
|
+
triggerElement()?.focus({ preventScroll: true });
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const focusScope = portalMount()?.closest("[role=\"dialog\"]") ?? portalMount()?.ownerDocument.body;
|
|
182
|
+
if (focusTarget?.isConnected && focusScope?.contains(focusTarget)) {
|
|
183
|
+
event.preventDefault();
|
|
184
|
+
queueMicrotask(() => {
|
|
185
|
+
if (lifecycleVersion !== focusLifecycleVersion || menuOpen()) return;
|
|
186
|
+
const activeElement = document.activeElement;
|
|
187
|
+
const isMenuFocus = activeElement instanceof HTMLElement && activeElement.closest("[role=\"menu\"]") !== null;
|
|
188
|
+
const isTriggerFocus = activeElement === triggerElement();
|
|
189
|
+
if (activeElement !== focusTarget && (activeElement === document.body || activeElement === focusScope || isMenuFocus || isTriggerFocus)) focusTarget.focus({ preventScroll: true });
|
|
190
|
+
});
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const activeElement = document.activeElement;
|
|
194
|
+
if (focusScope && activeElement instanceof HTMLElement && activeElement !== focusScope && focusScope.contains(activeElement) && activeElement.closest("[role=\"menu\"]") === null) event.preventDefault();
|
|
195
|
+
},
|
|
196
|
+
get children() {
|
|
197
|
+
return createComponent(DropdownMenuRadioGroup, {
|
|
198
|
+
get value() {
|
|
199
|
+
return selected()?.id ?? "";
|
|
200
|
+
},
|
|
201
|
+
get ["aria-label"]() {
|
|
202
|
+
return `${label()} options`;
|
|
203
|
+
},
|
|
204
|
+
"on:keydown": moveFocusOnTab,
|
|
205
|
+
onChange: (id) => {
|
|
206
|
+
if (!props.disabled && typeof id === "string") props.onSelect(id);
|
|
207
|
+
},
|
|
208
|
+
get children() {
|
|
209
|
+
return createComponent(For, {
|
|
210
|
+
get each() {
|
|
211
|
+
return options();
|
|
212
|
+
},
|
|
213
|
+
children: (theme) => createComponent(DropdownMenuRadioItem, {
|
|
214
|
+
get value() {
|
|
215
|
+
return theme.id;
|
|
216
|
+
},
|
|
217
|
+
get textValue() {
|
|
218
|
+
return theme.name;
|
|
219
|
+
},
|
|
220
|
+
closeOnSelect: true,
|
|
221
|
+
get disabled() {
|
|
222
|
+
return props.disabled;
|
|
223
|
+
},
|
|
224
|
+
onSelect: () => setRestoreTriggerFocus(true),
|
|
225
|
+
get children() {
|
|
226
|
+
return [createComponent(PalettePreview, { theme }), (() => {
|
|
227
|
+
var _el$1 = _tmpl$5();
|
|
228
|
+
insert(_el$1, () => theme.name);
|
|
229
|
+
return _el$1;
|
|
230
|
+
})()];
|
|
231
|
+
}
|
|
232
|
+
})
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
});
|
|
88
236
|
}
|
|
89
|
-
})
|
|
90
|
-
return portalMount();
|
|
91
|
-
} })];
|
|
237
|
+
})];
|
|
92
238
|
}
|
|
93
239
|
}));
|
|
94
240
|
return _el$8;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appearance-rows.js","names":["AdeaTheme","AdeaThemeRecord","Show","createMemo","createSignal","JSX","Palette","cn","Select","SelectContent","SelectItem","SelectTrigger","SelectValue","PalettePreview","SettingsRow","props","title","icon","Element","description","stacked","children","_el$","_tmpl$2","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_el$7","_$insert","_$createComponent","when","_el$6","_tmpl$","_$effect","_$className","ThemeRow","appearance","selectedId","preview","themes","disabled","onSelect","id","portalMount","setPortalMount","HTMLDivElement","options","filter","theme","selected","find","label","_el$8","_tmpl$3","_$use","modal","value","optionValue","optionTextValue","length","onChange","itemComponent","item","rawValue","_$memo","name","size","aria-label","_el$9","_tmpl$4","_$createComponent","_$className","_$memo"],"sources":["../../../../src/components/composites/appearance-editor/appearance-rows.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// Retains the compact divided row and palette-preview selector from the pinned\n// Zeron/Adea composition; Kobalte owns option navigation and nested dismissal.\nimport type { AdeaTheme, AdeaThemeRecord } from '@adea-ai/themes'\nimport { Show, createMemo, createSignal, type JSX } from 'solid-js'\nimport { Palette } from 'lucide-solid'\nimport { cn } from '#lib/utils'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '../../ui/select/select'\nimport { PalettePreview } from './theme-preview'\n\nexport function SettingsRow(props: {\n title: string\n icon: JSX.Element\n description?: JSX.Element\n stacked?: boolean\n children: JSX.Element\n}) {\n return (\n <section\n class={cn('flex flex-col gap-3 px-4 py-4', { 'sm:flex-row sm:items-center': !props.stacked })}\n >\n <div class=\"flex min-w-0 flex-1 items-center gap-3\">\n <span\n class=\"flex size-9 shrink-0 items-center justify-center rounded-lg border bg-foreground/5 text-muted-foreground [&_svg]:size-4\"\n aria-hidden=\"true\"\n >\n {props.icon}\n </span>\n <div class=\"min-w-0\">\n <h3 class=\"text-sm font-medium\">{props.title}</h3>\n <Show when={props.description}>\n <div class=\"mt-0.5 text-xs text-muted-foreground\">{props.description}</div>\n </Show>\n </div>\n </div>\n <div class=\"min-w-0 shrink-0\">{props.children}</div>\n </section>\n )\n}\n\nexport function ThemeRow(props: {\n appearance: 'light' | 'dark'\n selectedId: string\n preview: AdeaTheme\n themes: readonly AdeaThemeRecord[]\n disabled?: boolean\n onSelect: (id: string) => void\n}) {\n const [portalMount, setPortalMount] = createSignal<HTMLDivElement>()\n const options = createMemo(() =>\n props.themes.filter((theme) => theme.appearance === props.appearance)\n )\n const selected = createMemo(\n () =>\n options().find((theme) => theme.id === props.selectedId) ??\n options().find((theme) => theme.id === props.preview.id)\n )\n const label = () => (props.appearance === 'light' ? 'Light theme' : 'Dark theme')\n return (\n <SettingsRow title={label()} icon={<Palette />}>\n <div ref={setPortalMount}>\n <Select\n modal={false}\n options={options()}\n value={selected()}\n optionValue=\"id\"\n optionTextValue=\"name\"\n disabled={props.disabled || options().length === 0}\n onChange={(theme) => {\n if (theme) props.onSelect(theme.id)\n }}\n itemComponent={(item) => (\n <SelectItem item={item.item}>\n <PalettePreview theme={item.item.rawValue} />\n {item.item.rawValue.name}\n </SelectItem>\n )}\n >\n <SelectTrigger size=\"sm\" aria-label={label()} class=\"w-full sm:w-52\">\n <SelectValue>\n {() => (\n <>\n <PalettePreview theme={props.preview} />\n <span>{selected()?.name ?? props.preview.name}</span>\n </>\n )}\n </SelectValue>\n </SelectTrigger>\n <SelectContent portalMount={portalMount()} />\n </Select>\n </div>\n </SettingsRow>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"appearance-rows.js","names":["AdeaTheme","AdeaThemeRecord","For","Show","createMemo","createSignal","onCleanup","JSX","ChevronDown","Palette","cn","Button","DropdownMenu","DropdownMenuContent","DropdownMenuRadioGroup","DropdownMenuRadioItem","DropdownMenuTrigger","PalettePreview","POINTER_FOCUS_TARGET_SELECTOR","isTabStop","element","HTMLElement","tabIndex","matches","hasAttribute","getAttribute","closest","getClientRects","length","SettingsRow","props","title","icon","Element","description","stacked","children","_el$","_tmpl$2","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_el$7","_$insert","_$createComponent","when","_el$6","_tmpl$","_$effect","_$className","ThemeRow","appearance","selectedId","preview","themes","disabled","onSelect","id","portalMount","setPortalMount","HTMLDivElement","triggerElement","setTriggerElement","HTMLButtonElement","menuOpen","setMenuOpen","focusOutsideTarget","setFocusOutsideTarget","restoreTriggerFocus","setRestoreTriggerFocus","focusTargetAfterTab","focusLifecycleVersion","options","filter","theme","selected","find","label","closeMenu","moveFocusOnTab","event","KeyboardEvent","key","isComposing","trigger","parentDialog","focusScope","ownerDocument","body","focusStops","Array","from","querySelectorAll","orderedFocusStops","toSorted","a","b","triggerIndex","indexOf","direction","shiftKey","adjacent","at","undefined","stopPropagation","preventDefault","focus","preventScroll","_el$8","_tmpl$4","_$use","modal","open","onOpenChange","ref","as","variant","size","aria-label","_el$9","_tmpl$3","_el$0","name","onInteractOutside","detail","originalEvent","type","target","contains","focusTarget","onFocusOutside","onEscapeKeyDown","onCloseAutoFocus","lifecycleVersion","shouldRestore","isConnected","queueMicrotask","activeElement","document","isMenuFocus","isTriggerFocus","value","onChange","each","textValue","closeOnSelect","_el$1","_tmpl$5","_$createComponent","_$className"],"sources":["../../../../src/components/composites/appearance-editor/appearance-rows.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// Retains the compact divided row and palette-preview selector from the pinned\n// Zeron/Adea composition; Kobalte owns option navigation and nested dismissal.\nimport type { AdeaTheme, AdeaThemeRecord } from '@adea-ai/themes'\nimport { For, Show, createMemo, createSignal, onCleanup, type JSX } from 'solid-js'\nimport { ChevronDown, Palette } from 'lucide-solid'\nimport { cn } from '#lib/utils'\nimport { Button } from '../../ui/button/button'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuTrigger,\n} from '../../ui/dropdown-menu/dropdown-menu'\nimport { PalettePreview } from './theme-preview'\n\nconst POINTER_FOCUS_TARGET_SELECTOR =\n 'a[href], area[href], button, input, select, textarea, iframe, [tabindex], [contenteditable], details > summary:first-of-type'\n\nfunction isTabStop(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\nexport function SettingsRow(props: {\n title: string\n icon: JSX.Element\n description?: JSX.Element\n stacked?: boolean\n children: JSX.Element\n}) {\n return (\n <section\n class={cn('flex flex-col gap-3 px-4 py-4', { 'sm:flex-row sm:items-center': !props.stacked })}\n >\n <div class=\"flex min-w-0 flex-1 items-center gap-3\">\n <span\n class=\"flex size-9 shrink-0 items-center justify-center rounded-lg border bg-foreground/5 text-muted-foreground [&_svg]:size-4\"\n aria-hidden=\"true\"\n >\n {props.icon}\n </span>\n <div class=\"min-w-0\">\n <h3 class=\"text-sm font-medium\">{props.title}</h3>\n <Show when={props.description}>\n <div class=\"mt-0.5 text-xs text-muted-foreground\">{props.description}</div>\n </Show>\n </div>\n </div>\n <div class=\"min-w-0 shrink-0\">{props.children}</div>\n </section>\n )\n}\n\n/**\n * A compact persistent theme choice. Kobalte handles menu navigation and\n * dismissal; this row moves Tab to the adjacent browser-reported stop because\n * menus consume Tab by default. Enumerating elements and checking their native\n * tabIndex keeps details summaries in the order while preserving explicit\n * tabindex overrides.\n */\nexport function ThemeRow(props: {\n appearance: 'light' | 'dark'\n selectedId: string\n preview: AdeaTheme\n themes: readonly AdeaThemeRecord[]\n disabled?: boolean\n onSelect: (id: string) => void\n}) {\n const [portalMount, setPortalMount] = createSignal<HTMLDivElement>()\n const [triggerElement, setTriggerElement] = createSignal<HTMLButtonElement>()\n const [menuOpen, setMenuOpen] = createSignal(false)\n const [focusOutsideTarget, setFocusOutsideTarget] = createSignal<HTMLElement>()\n const [restoreTriggerFocus, setRestoreTriggerFocus] = createSignal(false)\n let focusTargetAfterTab: HTMLElement | undefined\n let focusLifecycleVersion = 0\n onCleanup(() => {\n focusLifecycleVersion += 1\n })\n const options = createMemo(() =>\n props.themes.filter((theme) => theme.appearance === props.appearance)\n )\n const selected = createMemo(\n () =>\n options().find((theme) => theme.id === props.selectedId) ??\n options().find((theme) => theme.id === props.preview.id)\n )\n const label = () => (props.appearance === 'light' ? 'Light theme' : 'Dark theme')\n const closeMenu = () => {\n if (menuOpen()) focusLifecycleVersion += 1\n setMenuOpen(false)\n }\n const moveFocusOnTab = (event: KeyboardEvent) => {\n if (event.key !== 'Tab' || event.isComposing) return\n\n const trigger = triggerElement()\n if (!trigger) return\n const parentDialog = portalMount()?.closest<HTMLElement>('[role=\"dialog\"]')\n const focusScope = parentDialog ?? portalMount()?.ownerDocument.body\n if (!focusScope) return\n\n const focusStops = Array.from(focusScope.querySelectorAll<HTMLElement>('*')).filter(\n (element) =>\n isTabStop(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 const direction = event.shiftKey ? -1 : 1\n const adjacent =\n orderedFocusStops[triggerIndex + direction] ??\n (parentDialog ? (direction > 0 ? orderedFocusStops[0] : orderedFocusStops.at(-1)) : undefined)\n\n event.stopPropagation()\n setRestoreTriggerFocus(false)\n if (adjacent) {\n event.preventDefault()\n focusTargetAfterTab = adjacent\n setFocusOutsideTarget(adjacent)\n closeMenu()\n adjacent.focus({ preventScroll: true })\n } else {\n focusTargetAfterTab = undefined\n setFocusOutsideTarget(undefined)\n closeMenu()\n }\n }\n return (\n <SettingsRow title={label()} icon={<Palette />}>\n <div ref={setPortalMount}>\n <DropdownMenu\n modal={false}\n open={menuOpen()}\n onOpenChange={(open) => {\n if (open !== menuOpen()) focusLifecycleVersion += 1\n setMenuOpen(open)\n if (open) {\n focusTargetAfterTab = undefined\n setFocusOutsideTarget(undefined)\n setRestoreTriggerFocus(false)\n }\n }}\n >\n <DropdownMenuTrigger\n ref={setTriggerElement}\n as={Button}\n variant=\"outline\"\n size=\"sm\"\n aria-label={label()}\n disabled={props.disabled || options().length === 0}\n class=\"w-full justify-between sm:w-52\"\n >\n <span class=\"flex min-w-0 flex-1 items-center gap-2\">\n <PalettePreview theme={props.preview} />\n <span class=\"min-w-0 flex-1 truncate\">{selected()?.name ?? props.preview.name}</span>\n </span>\n <ChevronDown aria-hidden=\"true\" class=\"shrink-0 text-muted-foreground\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent\n portalMount={portalMount()}\n class=\"max-h-(--kb-popper-content-available-height) w-(--kb-popper-anchor-width) min-w-32 overflow-x-hidden overflow-y-auto\"\n onInteractOutside={(event) => {\n if (event.detail.originalEvent.type !== 'pointerdown') return\n const parentDialog = portalMount()?.closest<HTMLElement>('[role=\"dialog\"]')\n const focusScope = parentDialog ?? portalMount()?.ownerDocument.body\n const target = event.detail.originalEvent.target\n if (!(target instanceof Element) || !focusScope?.contains(target)) return\n\n const focusTarget = target.closest<HTMLElement>(POINTER_FOCUS_TARGET_SELECTOR)\n if (focusTarget && isTabStop(focusTarget)) {\n setRestoreTriggerFocus(false)\n setFocusOutsideTarget(focusTarget)\n } else {\n setRestoreTriggerFocus(true)\n }\n }}\n onFocusOutside={(event) => {\n // The containing dialog or document body can briefly reclaim\n // focus when the menu opens. Keep that handoff from dismissing\n // it; focus moving to another descendant still closes the menu.\n const parentDialog = portalMount()?.closest<HTMLElement>('[role=\"dialog\"]')\n const focusScope = parentDialog ?? portalMount()?.ownerDocument.body\n const target = event.detail.originalEvent.target\n if (target === focusScope) {\n event.preventDefault()\n } else if (target instanceof HTMLElement && focusScope?.contains(target)) {\n setRestoreTriggerFocus(false)\n setFocusOutsideTarget(target)\n }\n }}\n onEscapeKeyDown={() => setRestoreTriggerFocus(true)}\n onCloseAutoFocus={(event) => {\n // A prior menu instance can finish its focus cleanup after this\n // row has already reopened. Do not let that cleanup steal focus.\n if (menuOpen()) {\n event.preventDefault()\n return\n }\n\n const lifecycleVersion = focusLifecycleVersion\n const shouldRestore = restoreTriggerFocus()\n const focusTarget = focusTargetAfterTab ?? focusOutsideTarget()\n focusTargetAfterTab = undefined\n setFocusOutsideTarget(undefined)\n setRestoreTriggerFocus(false)\n if (shouldRestore) {\n // The saved focus may be the containing dialog rather than\n // the trigger when WebKit opens this menu from a pointer click.\n event.preventDefault()\n triggerElement()?.focus({ preventScroll: true })\n return\n }\n\n const parentDialog = portalMount()?.closest<HTMLElement>('[role=\"dialog\"]')\n const focusScope = parentDialog ?? portalMount()?.ownerDocument.body\n if (focusTarget?.isConnected && focusScope?.contains(focusTarget)) {\n // Preserve the intended in-scope destination across\n // Kobalte's deferred stale-focus restore.\n event.preventDefault()\n queueMicrotask(() => {\n if (lifecycleVersion !== focusLifecycleVersion || menuOpen()) return\n\n const activeElement = document.activeElement\n const isMenuFocus =\n activeElement instanceof HTMLElement &&\n activeElement.closest('[role=\"menu\"]') !== null\n const isTriggerFocus = activeElement === triggerElement()\n if (\n activeElement !== focusTarget &&\n (activeElement === document.body ||\n activeElement === focusScope ||\n isMenuFocus ||\n isTriggerFocus)\n ) {\n focusTarget.focus({ preventScroll: true })\n }\n })\n return\n }\n\n const activeElement = document.activeElement\n if (\n focusScope &&\n activeElement instanceof HTMLElement &&\n activeElement !== focusScope &&\n focusScope.contains(activeElement) &&\n activeElement.closest('[role=\"menu\"]') === null\n ) {\n // Preserve a real focus target in this scope instead of\n // restoring the stale element captured when the menu mounted. A\n // focused menu item is about to unmount, so Kobalte must restore\n // focus to the trigger instead.\n event.preventDefault()\n }\n }}\n >\n <DropdownMenuRadioGroup\n value={selected()?.id ?? ''}\n aria-label={`${label()} options`}\n on:keydown={moveFocusOnTab}\n onChange={(id) => {\n if (!props.disabled && typeof id === 'string') props.onSelect(id)\n }}\n >\n <For each={options()}>\n {(theme) => (\n <DropdownMenuRadioItem\n value={theme.id}\n textValue={theme.name}\n closeOnSelect={true}\n disabled={props.disabled}\n onSelect={() => setRestoreTriggerFocus(true)}\n >\n <PalettePreview theme={theme} />\n <span class=\"min-w-0 flex-1 truncate\">{theme.name}</span>\n </DropdownMenuRadioItem>\n )}\n </For>\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </SettingsRow>\n )\n}\n"],"mappings":"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"}
|
|
@@ -3,10 +3,10 @@ import type { ComponentProps } from 'solid-js';
|
|
|
3
3
|
/**
|
|
4
4
|
* DropdownMenu.
|
|
5
5
|
*
|
|
6
|
-
* A list of actions on a trigger
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* A list of actions on a trigger, with radio groups for persistent choices
|
|
7
|
+
* that fit naturally in a compact menu. Use Select for form inputs whose
|
|
8
|
+
* selected value needs the field-style control, and Popover for arbitrary
|
|
9
|
+
* content.
|
|
10
10
|
*
|
|
11
11
|
* Kobalte supplies the full menu contract — arrow keys, typeahead, the roving
|
|
12
12
|
* highlight, Escape to close and return focus — which is exactly what a
|
|
@@ -20,6 +20,8 @@ export declare function DropdownMenuTrigger(props: ComponentProps<typeof Kobalte
|
|
|
20
20
|
export declare function DropdownMenuPortal(props: ComponentProps<typeof KobalteDropdownMenu.Portal>): import("solid-js").JSX.Element;
|
|
21
21
|
export type DropdownMenuContentProps = ComponentProps<typeof KobalteDropdownMenu.Content> & {
|
|
22
22
|
hideArrow?: boolean;
|
|
23
|
+
/** Mount under an owner element such as a modal, keeping the menu in its accessible subtree. */
|
|
24
|
+
portalMount?: HTMLElement;
|
|
23
25
|
};
|
|
24
26
|
export declare function DropdownMenuContent(props: DropdownMenuContentProps): import("solid-js").JSX.Element;
|
|
25
27
|
export declare function DropdownMenuItem(props: ComponentProps<typeof KobalteDropdownMenu.Item> & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-menu.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/dropdown-menu/dropdown-menu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,IAAI,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEjF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAa9C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,kCAE7E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,OAAO,CAAC,kCAE5F;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,MAAM,CAAC,kCAE1F;AAED,MAAM,MAAM,wBAAwB,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,OAAO,CAAC,GAAG;IAC1F,SAAS,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"dropdown-menu.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/dropdown-menu/dropdown-menu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,IAAI,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEjF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAa9C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,kCAE7E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,OAAO,CAAC,kCAE5F;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,MAAM,CAAC,kCAE1F;AAED,MAAM,MAAM,wBAAwB,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,OAAO,CAAC,GAAG;IAC1F,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,gGAAgG;IAChG,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B,CAAA;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,kCAoBlE;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,IAAI,CAAC,GAAG;IACvD,qEAAqE;IACrE,OAAO,CAAC,EAAE,SAAS,GAAG,aAAa,CAAA;IACnC,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,kCAwBF;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,kCASjE;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,YAAY,CAAC,kCAY/D;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,UAAU,CAAC,kCAG7D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,SAAS,CAAC,kCAWhG;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,UAAU,CAAC,kCAG7F;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,KAAK,CAAC,kCAExF;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,SAAS,CAAC,kCAGhG;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,GAAG,CAAC,kCAEpF;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,UAAU,CAAC,kCAU7D;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,cAAc,CAAC,OAAO,mBAAmB,CAAC,UAAU,CAAC,kCAkB7D"}
|
|
@@ -10,10 +10,10 @@ var _tmpl$2 = /*#__PURE__*/ template(`<span data-slot=dropdown-menu-shortcut>`);
|
|
|
10
10
|
/**
|
|
11
11
|
* DropdownMenu.
|
|
12
12
|
*
|
|
13
|
-
* A list of actions on a trigger
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* A list of actions on a trigger, with radio groups for persistent choices
|
|
14
|
+
* that fit naturally in a compact menu. Use Select for form inputs whose
|
|
15
|
+
* selected value needs the field-style control, and Popover for arbitrary
|
|
16
|
+
* content.
|
|
17
17
|
*
|
|
18
18
|
* Kobalte supplies the full menu contract — arrow keys, typeahead, the roving
|
|
19
19
|
* highlight, Escape to close and return focus — which is exactly what a
|
|
@@ -35,18 +35,24 @@ function DropdownMenuContent(props) {
|
|
|
35
35
|
const [local, rest] = splitProps(props, [
|
|
36
36
|
"class",
|
|
37
37
|
"hideArrow",
|
|
38
|
-
"children"
|
|
38
|
+
"children",
|
|
39
|
+
"portalMount"
|
|
39
40
|
]);
|
|
40
|
-
return createComponent(DropdownMenu.Portal, {
|
|
41
|
-
|
|
42
|
-
return
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
return createComponent(DropdownMenu.Portal, {
|
|
42
|
+
get mount() {
|
|
43
|
+
return local.portalMount;
|
|
44
|
+
},
|
|
45
|
+
get children() {
|
|
46
|
+
return createComponent(DropdownMenu.Content, mergeProps({ get ["class"]() {
|
|
47
|
+
return cn(overlaySurface, overlayMotion, "z-(--z-menu) min-w-[10rem] origin-(--kb-menu-content-transform-origin) overflow-hidden", "p-1", local.class);
|
|
48
|
+
} }, rest, { get children() {
|
|
49
|
+
return [memo(() => memo(() => !!!local.hideArrow)() && createComponent(DropdownMenu.Arrow, {
|
|
50
|
+
"aria-hidden": "true",
|
|
51
|
+
"class": "fill-popover stroke-border"
|
|
52
|
+
})), memo(() => local.children)];
|
|
53
|
+
} }));
|
|
54
|
+
}
|
|
55
|
+
});
|
|
50
56
|
}
|
|
51
57
|
function DropdownMenuItem(props) {
|
|
52
58
|
const [local, rest] = splitProps(props, [
|