@adea-ai/ui 0.62.0 → 0.63.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -0
- package/dist/NOTICE +51 -0
- package/dist/components/composites/appearance-editor/appearance-choices.d.ts +5 -0
- package/dist/components/composites/appearance-editor/appearance-choices.d.ts.map +1 -0
- package/dist/components/composites/appearance-editor/appearance-choices.js +211 -0
- package/dist/components/composites/appearance-editor/appearance-choices.js.map +1 -0
- package/dist/components/composites/appearance-editor/appearance-editor.d.ts +15 -0
- package/dist/components/composites/appearance-editor/appearance-editor.d.ts.map +1 -0
- package/dist/components/composites/appearance-editor/appearance-editor.js +280 -0
- package/dist/components/composites/appearance-editor/appearance-editor.js.map +1 -0
- package/dist/components/composites/appearance-editor/appearance-rows.d.ts +18 -0
- package/dist/components/composites/appearance-editor/appearance-rows.d.ts.map +1 -0
- package/dist/components/composites/appearance-editor/appearance-rows.js +101 -0
- package/dist/components/composites/appearance-editor/appearance-rows.js.map +1 -0
- package/dist/components/composites/appearance-editor/appearance-types.d.ts +42 -0
- package/dist/components/composites/appearance-editor/appearance-types.d.ts.map +1 -0
- package/dist/components/composites/appearance-editor/index.d.ts +4 -0
- package/dist/components/composites/appearance-editor/index.d.ts.map +1 -0
- package/dist/components/composites/appearance-editor/index.js +3 -0
- package/dist/components/composites/appearance-editor/theme-preview.d.ts +17 -0
- package/dist/components/composites/appearance-editor/theme-preview.d.ts.map +1 -0
- package/dist/components/composites/appearance-editor/theme-preview.js +158 -0
- package/dist/components/composites/appearance-editor/theme-preview.js.map +1 -0
- package/dist/components/ui/select/select.d.ts +5 -1
- package/dist/components/ui/select/select.d.ts.map +1 -1
- package/dist/components/ui/select/select.js +24 -20
- package/dist/components/ui/select/select.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/r/appearance-editor.json +51 -0
- package/dist/r/registry.json +51 -0
- package/dist/r/src/components/composites/appearance-editor/appearance-choices.tsx +173 -0
- package/dist/r/src/components/composites/appearance-editor/appearance-editor.tsx +239 -0
- package/dist/r/src/components/composites/appearance-editor/appearance-rows.tsx +122 -0
- package/dist/r/src/components/composites/appearance-editor/appearance-types.ts +40 -0
- package/dist/r/src/components/composites/appearance-editor/index.ts +12 -0
- package/dist/r/src/components/composites/appearance-editor/theme-preview.tsx +128 -0
- package/dist/r/src/components/ui/select/select.tsx +8 -3
- package/package.json +3 -2
- package/registry.json +51 -0
- package/src/components/composites/appearance-editor/appearance-choices.tsx +173 -0
- package/src/components/composites/appearance-editor/appearance-editor.tsx +239 -0
- package/src/components/composites/appearance-editor/appearance-rows.tsx +122 -0
- package/src/components/composites/appearance-editor/appearance-types.ts +40 -0
- package/src/components/composites/appearance-editor/index.ts +12 -0
- package/src/components/composites/appearance-editor/theme-preview.tsx +128 -0
- package/src/components/ui/select/select.tsx +8 -3
- package/src/index.ts +1 -0
package/README.md
CHANGED
|
@@ -156,3 +156,53 @@ one theme.
|
|
|
156
156
|
## Licence
|
|
157
157
|
|
|
158
158
|
Apache-2.0.
|
|
159
|
+
|
|
160
|
+
### Controlled appearance editor
|
|
161
|
+
|
|
162
|
+
`AppearanceEditor` and `AppearancePopover` retain the accepted Zeron-derived
|
|
163
|
+
System/Light/Dark miniature cards, independent light/dark theme rows, palette
|
|
164
|
+
swatches, default/preset/custom accent choices and Theme default/Frosted/Opaque
|
|
165
|
+
surface choices. The popup supports live host preview and Save/Cancel/Reset;
|
|
166
|
+
Kobalte owns radio, menu, focus and dismissal behavior. `SelectContent.portalMount`
|
|
167
|
+
lets a nested menu remain within its enclosing modal's accessible subtree.
|
|
168
|
+
|
|
169
|
+
Supply canonical `AdeaTheme` previews and `AdeaThemeRecord` choices from
|
|
170
|
+
`@adea-ai/themes`, including any validated accent overlay. The editor imports
|
|
171
|
+
only their types. Hosts own saved-ID recovery, validation, draft snapshots,
|
|
172
|
+
System appearance resolution, native transparency, live application tokens,
|
|
173
|
+
Save persistence and restoration on Cancel/dismissal. `saving`,
|
|
174
|
+
`saveDisabledReason`, `recoveryNotice`, `customAccentError`, and
|
|
175
|
+
`surfaceCapability` expose those outcomes; an unavailable import or Frosted
|
|
176
|
+
capability stays visibly unavailable. App-specific persisted versions and the
|
|
177
|
+
legacy `translucent` value need an app-owned adapter to the editor's `theme`
|
|
178
|
+
surface selection. The library does not silently migrate stored preferences.
|
|
179
|
+
|
|
180
|
+
The component browser lane uses a real Vite/Solid/Tailwind build in headless
|
|
181
|
+
Chromium without an app server. It checks keyboard mode selection, nested menu
|
|
182
|
+
accessibility and Escape, live-preview rollback, valid/invalid custom accents,
|
|
183
|
+
Save pending state, mobile selection and 320/768/1024/1440px layouts. A separate native Node server-render fixture verifies the composed editor without
|
|
184
|
+
browser or application globals. These checks
|
|
185
|
+
are component integration evidence; they do not certify application persistence,
|
|
186
|
+
native effects, packaged applications or manual assistive technology acceptance.
|
|
187
|
+
|
|
188
|
+
### Packed appearance contract
|
|
189
|
+
|
|
190
|
+
`bun run check:packed-appearance` installs the actual tarball without optional
|
|
191
|
+
Chart/Carousel engines, then reuses all appearance interactions in Chromium and
|
|
192
|
+
WebKit against compiled and Solid entries (60 cases). The same fixture verifies
|
|
193
|
+
Solid source SSR in native Node. Keyboard choices, live preview, save/cancel/reset,
|
|
194
|
+
nested dismissal, validation, pending save, narrow layouts with reachable footer actions, and automated accessibility
|
|
195
|
+
are covered. Production persistence, native transparency, hydration and manual AT
|
|
196
|
+
remain application acceptance gates.
|
|
197
|
+
|
|
198
|
+
The disposable host explicitly imports four isolated canonical theme records plus
|
|
199
|
+
color/CSS adapters from published `@adea-ai/themes`; the UI composition imports only
|
|
200
|
+
theme types. Both conditions retain one Solid runtime and one JS chunk, external CSS,
|
|
201
|
+
no fonts or unrelated engines, and full donor attribution. The combined host/editor
|
|
202
|
+
budgets are 64 KiB gzip JS and 50 KiB raw CSS; measured baselines are 62,203/62,643
|
|
203
|
+
gzip JS bytes and 50,060 raw CSS bytes with complete discovery of nested controls and shared helpers. This includes host theme-preview behavior,
|
|
204
|
+
not just the editor primitive.
|
|
205
|
+
|
|
206
|
+
Local packed interaction gates require `bunx playwright install chromium webkit`
|
|
207
|
+
after dependency installation. On Linux, use `--with-deps` when the required
|
|
208
|
+
system libraries are absent. All automation runs headless with disposable profiles.
|
package/dist/NOTICE
CHANGED
|
@@ -48,3 +48,54 @@ shadcn-storybook-template (MIT), Kibo UI (MIT), and Dice UI (MIT) projects.
|
|
|
48
48
|
Origin UI / coss (AGPL-3.0-or-later) was consulted for visual ideas only. No
|
|
49
49
|
code, class string, or asset from that project is reproduced here, because its
|
|
50
50
|
licence is incompatible with this distribution.
|
|
51
|
+
|
|
52
|
+
## Appearance editor translated from Zeron
|
|
53
|
+
|
|
54
|
+
The System/Light/Dark miniature composition, palette bands, theme selectors,
|
|
55
|
+
compact divided settings rows, accent helper and surface helper treatment in
|
|
56
|
+
`packages/ui/src/components/composites/appearance-editor/` are substantially
|
|
57
|
+
translated from Zeron (https://github.com/zeronsh/zeron), pinned at:
|
|
58
|
+
|
|
59
|
+
30a9a9537c5ec96226c87f4bf349b6f77c5dfb59
|
|
60
|
+
crates/ui/src/settings/appearance.rs
|
|
61
|
+
crates/ui/src/settings/widgets.rs
|
|
62
|
+
|
|
63
|
+
This preserves Adea's previously accepted Zeron port. Rust/GPUI rendering is
|
|
64
|
+
re-expressed in Solid and Kobalte with semantic design-system tokens and palettes
|
|
65
|
+
supplied by the host from @adea-ai/themes. The library imports theme types only;
|
|
66
|
+
it does not acquire GPUI, global theme storage, normalization or native effects.
|
|
67
|
+
Save/Cancel/Reset, custom accent validation, reduced transparency and capability
|
|
68
|
+
reporting preserve accepted Adea issue #425 amendments. Typeface controls are
|
|
69
|
+
outside that accepted surface. The accent row stacks to retain readable helper
|
|
70
|
+
copy in a narrow popup; both theme selectors remain independently visible.
|
|
71
|
+
|
|
72
|
+
Relevant donor tests for three mode cards, both appearance catalogues, and accent
|
|
73
|
+
and surface helper copy are translated into browser assertions alongside
|
|
74
|
+
keyboard, nested-menu, snapshot, pending-save and responsive accessibility checks.
|
|
75
|
+
Font-specific donor tests are excluded with the corresponding controls. Catalogue
|
|
76
|
+
counts are host data, so tests retain both appearance lanes without hard-coding
|
|
77
|
+
Zeron's catalogue sizes.
|
|
78
|
+
|
|
79
|
+
Zeron's MIT notice applies to the translated portions:
|
|
80
|
+
|
|
81
|
+
MIT License
|
|
82
|
+
|
|
83
|
+
Copyright (c) 2026 Wing
|
|
84
|
+
|
|
85
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
86
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
87
|
+
in the Software without restriction, including without limitation the rights
|
|
88
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
89
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
90
|
+
furnished to do so, subject to the following conditions:
|
|
91
|
+
|
|
92
|
+
The above copyright notice and this permission notice shall be included in all
|
|
93
|
+
copies or substantial portions of the Software.
|
|
94
|
+
|
|
95
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
96
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
97
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
98
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
99
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
100
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
101
|
+
SOFTWARE.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AppearanceEditorProps } from './appearance-types';
|
|
2
|
+
export declare function ModeChoices(props: AppearanceEditorProps): import("solid-js").JSX.Element;
|
|
3
|
+
export declare function AccentChoices(props: AppearanceEditorProps): import("solid-js").JSX.Element;
|
|
4
|
+
export declare function GlassChoices(props: AppearanceEditorProps): import("solid-js").JSX.Element;
|
|
5
|
+
//# sourceMappingURL=appearance-choices.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appearance-choices.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/appearance-editor/appearance-choices.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAc/D,wBAAgB,WAAW,CAAC,KAAK,EAAE,qBAAqB,kCAyCvD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,qBAAqB,kCAyDzD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,qBAAqB,kCA6BxD"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { ThemeMiniature, ThemeMiniatureSplit } from "./theme-preview.js";
|
|
2
|
+
import { createComponent, effect, insert, memo, setStyleProperty, template } from "solid-js/web";
|
|
3
|
+
import { For, Show } from "solid-js";
|
|
4
|
+
import { RadioGroup } from "@kobalte/core/radio-group";
|
|
5
|
+
//#region src/components/composites/appearance-editor/appearance-choices.tsx
|
|
6
|
+
var _tmpl$ = /*#__PURE__*/ template(`<span class="block h-20 w-full">`);
|
|
7
|
+
var _tmpl$2 = /*#__PURE__*/ template(`<span>`);
|
|
8
|
+
var _tmpl$3 = /*#__PURE__*/ template(`<span class="block size-full rounded-full"aria-hidden=true>`);
|
|
9
|
+
var _tmpl$4 = /*#__PURE__*/ template(`<span class=sr-only>`);
|
|
10
|
+
var MODES = [
|
|
11
|
+
{
|
|
12
|
+
value: "system",
|
|
13
|
+
label: "System"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
value: "light",
|
|
17
|
+
label: "Light"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
value: "dark",
|
|
21
|
+
label: "Dark"
|
|
22
|
+
}
|
|
23
|
+
];
|
|
24
|
+
var SURFACES = [
|
|
25
|
+
{
|
|
26
|
+
value: "theme",
|
|
27
|
+
label: "Theme default"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
value: "frosted",
|
|
31
|
+
label: "Frosted"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
value: "opaque",
|
|
35
|
+
label: "Opaque"
|
|
36
|
+
}
|
|
37
|
+
];
|
|
38
|
+
function ModeChoices(props) {
|
|
39
|
+
return createComponent(RadioGroup, {
|
|
40
|
+
get value() {
|
|
41
|
+
return props.draft.mode;
|
|
42
|
+
},
|
|
43
|
+
get disabled() {
|
|
44
|
+
return props.saving;
|
|
45
|
+
},
|
|
46
|
+
orientation: "horizontal",
|
|
47
|
+
"aria-label": "Appearance mode",
|
|
48
|
+
onChange: (mode) => {
|
|
49
|
+
const option = MODES.find((candidate) => candidate.value === mode);
|
|
50
|
+
if (option) props.onChange({ mode: option.value });
|
|
51
|
+
},
|
|
52
|
+
"class": "grid grid-cols-1 gap-3 px-4 py-4 sm:grid-cols-3",
|
|
53
|
+
get children() {
|
|
54
|
+
return createComponent(For, {
|
|
55
|
+
each: MODES,
|
|
56
|
+
children: (option) => createComponent(RadioGroup.Item, {
|
|
57
|
+
get value() {
|
|
58
|
+
return option.value;
|
|
59
|
+
},
|
|
60
|
+
get ["data-mode"]() {
|
|
61
|
+
return option.value;
|
|
62
|
+
},
|
|
63
|
+
"class": "min-w-0 rounded-lg focus-within:ring-3 focus-within:ring-ring/50",
|
|
64
|
+
get children() {
|
|
65
|
+
return [createComponent(RadioGroup.ItemInput, {}), createComponent(RadioGroup.ItemLabel, {
|
|
66
|
+
"class": "flex cursor-pointer flex-col gap-2 rounded-lg border p-2 text-center text-xs data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
|
|
67
|
+
get children() {
|
|
68
|
+
return [(() => {
|
|
69
|
+
var _el$ = _tmpl$();
|
|
70
|
+
insert(_el$, createComponent(Show, {
|
|
71
|
+
get when() {
|
|
72
|
+
return option.value === "system";
|
|
73
|
+
},
|
|
74
|
+
get fallback() {
|
|
75
|
+
return createComponent(ThemeMiniature, { get theme() {
|
|
76
|
+
return memo(() => option.value === "light")() ? props.lightTheme : props.darkTheme;
|
|
77
|
+
} });
|
|
78
|
+
},
|
|
79
|
+
get children() {
|
|
80
|
+
return createComponent(ThemeMiniatureSplit, {
|
|
81
|
+
get light() {
|
|
82
|
+
return props.lightTheme;
|
|
83
|
+
},
|
|
84
|
+
get dark() {
|
|
85
|
+
return props.darkTheme;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}));
|
|
90
|
+
return _el$;
|
|
91
|
+
})(), (() => {
|
|
92
|
+
var _el$2 = _tmpl$2();
|
|
93
|
+
insert(_el$2, () => option.label);
|
|
94
|
+
return _el$2;
|
|
95
|
+
})()];
|
|
96
|
+
}
|
|
97
|
+
})];
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
function AccentChoices(props) {
|
|
105
|
+
const custom = () => props.draft.accent !== "theme" && !props.accentOptions.some((option) => option.id === props.draft.accent);
|
|
106
|
+
const accentSelection = () => custom() ? "custom" : props.draft.accent;
|
|
107
|
+
return createComponent(RadioGroup, {
|
|
108
|
+
get value() {
|
|
109
|
+
return accentSelection();
|
|
110
|
+
},
|
|
111
|
+
get disabled() {
|
|
112
|
+
return props.saving;
|
|
113
|
+
},
|
|
114
|
+
orientation: "horizontal",
|
|
115
|
+
"aria-label": "Accent",
|
|
116
|
+
"class": "flex flex-wrap items-center gap-2",
|
|
117
|
+
onChange: (accent) => props.onChange({ accent: accent === "custom" ? props.customAccentValue ?? "" : accent }),
|
|
118
|
+
get children() {
|
|
119
|
+
return [
|
|
120
|
+
createComponent(RadioGroup.Item, {
|
|
121
|
+
value: "theme",
|
|
122
|
+
get children() {
|
|
123
|
+
return [createComponent(RadioGroup.ItemInput, {}), createComponent(RadioGroup.ItemLabel, {
|
|
124
|
+
"class": "flex h-7 cursor-pointer items-center rounded-md border px-2 text-xs data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary",
|
|
125
|
+
children: "Theme default"
|
|
126
|
+
})];
|
|
127
|
+
}
|
|
128
|
+
}),
|
|
129
|
+
createComponent(For, {
|
|
130
|
+
get each() {
|
|
131
|
+
return props.accentOptions;
|
|
132
|
+
},
|
|
133
|
+
children: (option) => createComponent(RadioGroup.Item, {
|
|
134
|
+
get value() {
|
|
135
|
+
return option.id;
|
|
136
|
+
},
|
|
137
|
+
"class": "rounded-full focus-within:ring-3 focus-within:ring-ring/50",
|
|
138
|
+
get children() {
|
|
139
|
+
return [createComponent(RadioGroup.ItemInput, {}), createComponent(RadioGroup.ItemLabel, {
|
|
140
|
+
"class": "block size-7 cursor-pointer rounded-full border p-0.5 data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary",
|
|
141
|
+
get children() {
|
|
142
|
+
return [(() => {
|
|
143
|
+
var _el$3 = _tmpl$3();
|
|
144
|
+
effect((_$p) => setStyleProperty(_el$3, "background-color", (props.draft.mode === "system" ? props.resolvedAppearance : props.draft.mode) === "light" ? option.light : option.dark));
|
|
145
|
+
return _el$3;
|
|
146
|
+
})(), (() => {
|
|
147
|
+
var _el$4 = _tmpl$4();
|
|
148
|
+
insert(_el$4, () => option.label);
|
|
149
|
+
return _el$4;
|
|
150
|
+
})()];
|
|
151
|
+
}
|
|
152
|
+
})];
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
}),
|
|
156
|
+
createComponent(RadioGroup.Item, {
|
|
157
|
+
value: "custom",
|
|
158
|
+
get children() {
|
|
159
|
+
return [createComponent(RadioGroup.ItemInput, {}), createComponent(RadioGroup.ItemLabel, {
|
|
160
|
+
"class": "flex h-7 cursor-pointer items-center rounded-md border px-2 text-xs data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary",
|
|
161
|
+
children: "Custom"
|
|
162
|
+
})];
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
];
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function GlassChoices(props) {
|
|
170
|
+
return createComponent(RadioGroup, {
|
|
171
|
+
get value() {
|
|
172
|
+
return props.draft.surface;
|
|
173
|
+
},
|
|
174
|
+
get disabled() {
|
|
175
|
+
return props.saving;
|
|
176
|
+
},
|
|
177
|
+
orientation: "horizontal",
|
|
178
|
+
"aria-label": "Glass",
|
|
179
|
+
"class": "flex flex-wrap gap-1",
|
|
180
|
+
onChange: (surface) => {
|
|
181
|
+
const option = SURFACES.find((candidate) => candidate.value === surface);
|
|
182
|
+
if (option) props.onChange({ surface: option.value });
|
|
183
|
+
},
|
|
184
|
+
get children() {
|
|
185
|
+
return createComponent(For, {
|
|
186
|
+
each: SURFACES,
|
|
187
|
+
children: (option) => createComponent(RadioGroup.Item, {
|
|
188
|
+
get value() {
|
|
189
|
+
return option.value;
|
|
190
|
+
},
|
|
191
|
+
get disabled() {
|
|
192
|
+
return memo(() => option.value === "frosted")() && !props.surfaceCapability.frosted;
|
|
193
|
+
},
|
|
194
|
+
"class": "rounded-md focus-within:ring-3 focus-within:ring-ring/50",
|
|
195
|
+
get children() {
|
|
196
|
+
return [createComponent(RadioGroup.ItemInput, {}), createComponent(RadioGroup.ItemLabel, {
|
|
197
|
+
"class": "flex h-7 cursor-pointer items-center rounded-md border px-2 text-xs data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
|
|
198
|
+
get children() {
|
|
199
|
+
return option.label;
|
|
200
|
+
}
|
|
201
|
+
})];
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
//#endregion
|
|
209
|
+
export { AccentChoices, GlassChoices, ModeChoices };
|
|
210
|
+
|
|
211
|
+
//# sourceMappingURL=appearance-choices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appearance-choices.js","names":["RadioGroup","Radio","For","Show","AppearanceEditorProps","ThemeMiniature","ThemeMiniatureSplit","MODES","value","label","const","SURFACES","ModeChoices","props","_$createComponent","draft","mode","disabled","saving","orientation","onChange","option","find","candidate","children","each","Item","data-mode","ItemInput","ItemLabel","_el$","_tmpl$","_$insert","when","fallback","theme","_$memo","lightTheme","darkTheme","light","dark","_el$2","_tmpl$2","AccentChoices","custom","accent","accentOptions","some","id","accentSelection","customAccentValue","_el$3","_tmpl$3","_$effect","_$p","_$setStyleProperty","resolvedAppearance","_el$4","_tmpl$4","GlassChoices","surface","surfaceCapability","frosted","_$createComponent","Radio","_$memo","_$setStyleProperty"],"sources":["../../../../src/components/composites/appearance-editor/appearance-choices.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// Pinned mode-card, accent-swatch, and glass-chip composition. Kobalte replaces\n// the app port's manual roving focus; it does not replace the donor hierarchy.\nimport { RadioGroup as Radio } from '@kobalte/core/radio-group'\nimport { For, Show } from 'solid-js'\nimport type { AppearanceEditorProps } from './appearance-types'\nimport { ThemeMiniature, ThemeMiniatureSplit } from './theme-preview'\n\nconst MODES = [\n { value: 'system', label: 'System' },\n { value: 'light', label: 'Light' },\n { value: 'dark', label: 'Dark' },\n] as const\nconst SURFACES = [\n { value: 'theme', label: 'Theme default' },\n { value: 'frosted', label: 'Frosted' },\n { value: 'opaque', label: 'Opaque' },\n] as const\n\nexport function ModeChoices(props: AppearanceEditorProps) {\n return (\n <Radio\n value={props.draft.mode}\n disabled={props.saving}\n orientation=\"horizontal\"\n aria-label=\"Appearance mode\"\n onChange={(mode) => {\n const option = MODES.find((candidate) => candidate.value === mode)\n if (option) props.onChange({ mode: option.value })\n }}\n class=\"grid grid-cols-1 gap-3 px-4 py-4 sm:grid-cols-3\"\n >\n <For each={MODES}>\n {(option) => (\n <Radio.Item\n value={option.value}\n data-mode={option.value}\n class=\"min-w-0 rounded-lg focus-within:ring-3 focus-within:ring-ring/50\"\n >\n <Radio.ItemInput />\n <Radio.ItemLabel class=\"flex cursor-pointer flex-col gap-2 rounded-lg border p-2 text-center text-xs data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50\">\n <span class=\"block h-20 w-full\">\n <Show\n when={option.value === 'system'}\n fallback={\n <ThemeMiniature\n theme={option.value === 'light' ? props.lightTheme : props.darkTheme}\n />\n }\n >\n <ThemeMiniatureSplit light={props.lightTheme} dark={props.darkTheme} />\n </Show>\n </span>\n <span>{option.label}</span>\n </Radio.ItemLabel>\n </Radio.Item>\n )}\n </For>\n </Radio>\n )\n}\n\nexport function AccentChoices(props: AppearanceEditorProps) {\n const custom = () =>\n props.draft.accent !== 'theme' &&\n !props.accentOptions.some((option) => option.id === props.draft.accent)\n const accentSelection = () => (custom() ? 'custom' : props.draft.accent)\n return (\n <Radio\n value={accentSelection()}\n disabled={props.saving}\n orientation=\"horizontal\"\n aria-label=\"Accent\"\n class=\"flex flex-wrap items-center gap-2\"\n onChange={(accent) =>\n props.onChange({\n accent: accent === 'custom' ? (props.customAccentValue ?? '') : accent,\n })\n }\n >\n <Radio.Item value=\"theme\">\n <Radio.ItemInput />\n <Radio.ItemLabel class=\"flex h-7 cursor-pointer items-center rounded-md border px-2 text-xs data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary\">\n Theme default\n </Radio.ItemLabel>\n </Radio.Item>\n <For each={props.accentOptions}>\n {(option) => (\n <Radio.Item\n value={option.id}\n class=\"rounded-full focus-within:ring-3 focus-within:ring-ring/50\"\n >\n <Radio.ItemInput />\n <Radio.ItemLabel class=\"block size-7 cursor-pointer rounded-full border p-0.5 data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary\">\n <span\n class=\"block size-full rounded-full\"\n aria-hidden=\"true\"\n style={{\n 'background-color':\n (props.draft.mode === 'system'\n ? props.resolvedAppearance\n : props.draft.mode) === 'light'\n ? option.light\n : option.dark,\n }}\n />\n <span class=\"sr-only\">{option.label}</span>\n </Radio.ItemLabel>\n </Radio.Item>\n )}\n </For>\n <Radio.Item value=\"custom\">\n <Radio.ItemInput />\n <Radio.ItemLabel class=\"flex h-7 cursor-pointer items-center rounded-md border px-2 text-xs data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary\">\n Custom\n </Radio.ItemLabel>\n </Radio.Item>\n </Radio>\n )\n}\n\nexport function GlassChoices(props: AppearanceEditorProps) {\n return (\n <Radio\n value={props.draft.surface}\n disabled={props.saving}\n orientation=\"horizontal\"\n aria-label=\"Glass\"\n class=\"flex flex-wrap gap-1\"\n onChange={(surface) => {\n const option = SURFACES.find((candidate) => candidate.value === surface)\n if (option) props.onChange({ surface: option.value })\n }}\n >\n <For each={SURFACES}>\n {(option) => (\n <Radio.Item\n value={option.value}\n disabled={option.value === 'frosted' && !props.surfaceCapability.frosted}\n class=\"rounded-md focus-within:ring-3 focus-within:ring-ring/50\"\n >\n <Radio.ItemInput />\n <Radio.ItemLabel class=\"flex h-7 cursor-pointer items-center rounded-md border px-2 text-xs data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50\">\n {option.label}\n </Radio.ItemLabel>\n </Radio.Item>\n )}\n </For>\n </Radio>\n )\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AppearanceEditorProps, AppearancePopoverProps } from './appearance-types';
|
|
2
|
+
/**
|
|
3
|
+
* A live editor whose persistence and preview authority belong to its host.
|
|
4
|
+
* No ThemeProvider is required, and no catalogue, renderer engine or storage is
|
|
5
|
+
* imported. Hosts normalize unknown IDs and custom colors, report recovery,
|
|
6
|
+
* snapshot on open, preview on changes, commit on Save, and restore on dismissal.
|
|
7
|
+
* Both theme rows remain mounted when mode changes. Typeface/density axes are
|
|
8
|
+
* deliberately absent from Adea #425's accepted surface.
|
|
9
|
+
*/
|
|
10
|
+
export declare function AppearanceEditor(props: AppearanceEditorProps): import("solid-js").JSX.Element;
|
|
11
|
+
/** Modal anchoring/dismissal and nested-listbox behavior come from Kobalte.
|
|
12
|
+
* Its measured available height also bounds scrolling, keeping footer actions
|
|
13
|
+
* reachable when a narrow popup begins below its trigger. */
|
|
14
|
+
export declare function AppearancePopover(props: AppearancePopoverProps): import("solid-js").JSX.Element;
|
|
15
|
+
//# sourceMappingURL=appearance-editor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appearance-editor.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/appearance-editor/appearance-editor.tsx"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAIvF;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,kCAqJ5D;AAED;;6DAE6D;AAC7D,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,kCAyB9D"}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { cn } from "../../../lib/utils.js";
|
|
2
|
+
import { Button } from "../../ui/button/button.js";
|
|
3
|
+
import { Input } from "../../ui/input/input.js";
|
|
4
|
+
import { Popover, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger } from "../../ui/popover/popover.js";
|
|
5
|
+
import { Switch } from "../../ui/switch/switch.js";
|
|
6
|
+
import { AccentChoices, GlassChoices, ModeChoices } from "./appearance-choices.js";
|
|
7
|
+
import { SettingsRow, ThemeRow } from "./appearance-rows.js";
|
|
8
|
+
import { className, createComponent, effect, insert, memo, setAttribute, template } from "solid-js/web";
|
|
9
|
+
import { EyeOff, Palette, PanelsTopLeft, SlidersHorizontal } from "lucide-solid";
|
|
10
|
+
import { Show, createUniqueId } from "solid-js";
|
|
11
|
+
//#region src/components/composites/appearance-editor/appearance-editor.tsx
|
|
12
|
+
var _tmpl$ = /*#__PURE__*/ template(`<p role=status class="px-4 py-2 text-sm text-muted-foreground">`);
|
|
13
|
+
var _tmpl$2 = /*#__PURE__*/ template(`<p role=alert class="mt-1 text-xs text-destructive">`);
|
|
14
|
+
var _tmpl$3 = /*#__PURE__*/ template(`<div class="px-4 py-3"><label class="mb-2 block text-xs font-medium">Custom accent`);
|
|
15
|
+
var _tmpl$4 = /*#__PURE__*/ template(`<p role=status class="px-4 py-2 text-xs text-muted-foreground">`);
|
|
16
|
+
var _tmpl$5 = /*#__PURE__*/ template(`<p role=status class="px-4 pt-3 text-xs text-muted-foreground">`);
|
|
17
|
+
var _tmpl$6 = /*#__PURE__*/ template(`<div data-appearance-editor><div class="divide-y divide-border rounded-lg border"></div><div class="flex flex-wrap items-center gap-2 px-4 py-4"><div class="ml-auto flex gap-2">`);
|
|
18
|
+
/**
|
|
19
|
+
* A live editor whose persistence and preview authority belong to its host.
|
|
20
|
+
* No ThemeProvider is required, and no catalogue, renderer engine or storage is
|
|
21
|
+
* imported. Hosts normalize unknown IDs and custom colors, report recovery,
|
|
22
|
+
* snapshot on open, preview on changes, commit on Save, and restore on dismissal.
|
|
23
|
+
* Both theme rows remain mounted when mode changes. Typeface/density axes are
|
|
24
|
+
* deliberately absent from Adea #425's accepted surface.
|
|
25
|
+
*/
|
|
26
|
+
function AppearanceEditor(props) {
|
|
27
|
+
const errorId = createUniqueId();
|
|
28
|
+
const saveReasonId = createUniqueId();
|
|
29
|
+
const custom = () => props.draft.accent !== "theme" && !props.accentOptions.some((option) => option.id === props.draft.accent);
|
|
30
|
+
const accentDescription = () => {
|
|
31
|
+
if (props.draft.accent === "theme") return "Theme default · Uses the palette's intended color.";
|
|
32
|
+
return `${props.accentOptions.find((option) => option.id === props.draft.accent)?.label ?? "Custom"} · Controls, glyphs, selections, code, and activity.`;
|
|
33
|
+
};
|
|
34
|
+
const glassDescription = () => props.draft.surface === "opaque" ? "Solid surfaces for every theme." : props.draft.surface === "frosted" ? "Theme-colored glass where supported." : props.surfaceCapability.themeDefaultDescription ?? "Uses this theme's default surface.";
|
|
35
|
+
return (() => {
|
|
36
|
+
var _el$ = _tmpl$6(), _el$3 = _el$.firstChild, _el$9 = _el$3.nextSibling, _el$0 = _el$9.firstChild;
|
|
37
|
+
insert(_el$, createComponent(Show, {
|
|
38
|
+
get when() {
|
|
39
|
+
return props.recoveryNotice;
|
|
40
|
+
},
|
|
41
|
+
get children() {
|
|
42
|
+
var _el$2 = _tmpl$();
|
|
43
|
+
insert(_el$2, () => props.recoveryNotice);
|
|
44
|
+
return _el$2;
|
|
45
|
+
}
|
|
46
|
+
}), _el$3);
|
|
47
|
+
insert(_el$, createComponent(ModeChoices, props), _el$3);
|
|
48
|
+
insert(_el$3, createComponent(ThemeRow, {
|
|
49
|
+
appearance: "light",
|
|
50
|
+
get selectedId() {
|
|
51
|
+
return props.draft.lightThemeId;
|
|
52
|
+
},
|
|
53
|
+
get preview() {
|
|
54
|
+
return props.lightTheme;
|
|
55
|
+
},
|
|
56
|
+
get themes() {
|
|
57
|
+
return props.themes;
|
|
58
|
+
},
|
|
59
|
+
get disabled() {
|
|
60
|
+
return props.saving;
|
|
61
|
+
},
|
|
62
|
+
onSelect: (lightThemeId) => props.onChange({ lightThemeId })
|
|
63
|
+
}), null);
|
|
64
|
+
insert(_el$3, createComponent(ThemeRow, {
|
|
65
|
+
appearance: "dark",
|
|
66
|
+
get selectedId() {
|
|
67
|
+
return props.draft.darkThemeId;
|
|
68
|
+
},
|
|
69
|
+
get preview() {
|
|
70
|
+
return props.darkTheme;
|
|
71
|
+
},
|
|
72
|
+
get themes() {
|
|
73
|
+
return props.themes;
|
|
74
|
+
},
|
|
75
|
+
get disabled() {
|
|
76
|
+
return props.saving;
|
|
77
|
+
},
|
|
78
|
+
onSelect: (darkThemeId) => props.onChange({ darkThemeId })
|
|
79
|
+
}), null);
|
|
80
|
+
insert(_el$3, createComponent(SettingsRow, {
|
|
81
|
+
stacked: true,
|
|
82
|
+
title: "Accent",
|
|
83
|
+
get icon() {
|
|
84
|
+
return createComponent(SlidersHorizontal, {});
|
|
85
|
+
},
|
|
86
|
+
get description() {
|
|
87
|
+
return accentDescription();
|
|
88
|
+
},
|
|
89
|
+
get children() {
|
|
90
|
+
return createComponent(AccentChoices, props);
|
|
91
|
+
}
|
|
92
|
+
}), null);
|
|
93
|
+
insert(_el$3, createComponent(Show, {
|
|
94
|
+
get when() {
|
|
95
|
+
return custom();
|
|
96
|
+
},
|
|
97
|
+
get children() {
|
|
98
|
+
var _el$4 = _tmpl$3(), _el$5 = _el$4.firstChild;
|
|
99
|
+
setAttribute(_el$5, "for", `${errorId}-input`);
|
|
100
|
+
insert(_el$4, createComponent(Input, {
|
|
101
|
+
id: `${errorId}-input`,
|
|
102
|
+
get value() {
|
|
103
|
+
return props.draft.accent;
|
|
104
|
+
},
|
|
105
|
+
get disabled() {
|
|
106
|
+
return props.saving;
|
|
107
|
+
},
|
|
108
|
+
get ["aria-invalid"]() {
|
|
109
|
+
return !!props.customAccentError;
|
|
110
|
+
},
|
|
111
|
+
get ["aria-describedby"]() {
|
|
112
|
+
return props.customAccentError ? errorId : void 0;
|
|
113
|
+
},
|
|
114
|
+
onInput: (event) => props.onChange({ accent: event.currentTarget.value })
|
|
115
|
+
}), null);
|
|
116
|
+
insert(_el$4, createComponent(Show, {
|
|
117
|
+
get when() {
|
|
118
|
+
return props.customAccentError;
|
|
119
|
+
},
|
|
120
|
+
get children() {
|
|
121
|
+
var _el$6 = _tmpl$2();
|
|
122
|
+
setAttribute(_el$6, "id", errorId);
|
|
123
|
+
insert(_el$6, () => props.customAccentError);
|
|
124
|
+
return _el$6;
|
|
125
|
+
}
|
|
126
|
+
}), null);
|
|
127
|
+
return _el$4;
|
|
128
|
+
}
|
|
129
|
+
}), null);
|
|
130
|
+
insert(_el$3, createComponent(SettingsRow, {
|
|
131
|
+
title: "Glass",
|
|
132
|
+
get icon() {
|
|
133
|
+
return createComponent(PanelsTopLeft, {});
|
|
134
|
+
},
|
|
135
|
+
get description() {
|
|
136
|
+
return glassDescription();
|
|
137
|
+
},
|
|
138
|
+
get children() {
|
|
139
|
+
return createComponent(GlassChoices, props);
|
|
140
|
+
}
|
|
141
|
+
}), null);
|
|
142
|
+
insert(_el$3, createComponent(Show, {
|
|
143
|
+
get when() {
|
|
144
|
+
return memo(() => !!!props.surfaceCapability.frosted)() && props.surfaceCapability.reason;
|
|
145
|
+
},
|
|
146
|
+
get children() {
|
|
147
|
+
var _el$7 = _tmpl$4();
|
|
148
|
+
insert(_el$7, () => props.surfaceCapability.reason);
|
|
149
|
+
return _el$7;
|
|
150
|
+
}
|
|
151
|
+
}), null);
|
|
152
|
+
insert(_el$3, createComponent(SettingsRow, {
|
|
153
|
+
title: "Reduce transparency",
|
|
154
|
+
get icon() {
|
|
155
|
+
return createComponent(EyeOff, {});
|
|
156
|
+
},
|
|
157
|
+
description: "Prefer solid surfaces, including during live preview.",
|
|
158
|
+
get children() {
|
|
159
|
+
return createComponent(Switch, {
|
|
160
|
+
get checked() {
|
|
161
|
+
return props.draft.reduceTransparency;
|
|
162
|
+
},
|
|
163
|
+
get disabled() {
|
|
164
|
+
return props.saving;
|
|
165
|
+
},
|
|
166
|
+
onChange: (reduceTransparency) => props.onChange({ reduceTransparency }),
|
|
167
|
+
"aria-label": "Reduce transparency"
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}), null);
|
|
171
|
+
insert(_el$3, createComponent(SettingsRow, {
|
|
172
|
+
title: "Theme library",
|
|
173
|
+
get icon() {
|
|
174
|
+
return createComponent(Palette, {});
|
|
175
|
+
},
|
|
176
|
+
get description() {
|
|
177
|
+
return props.onManageThemes ? "Manage themes through the application." : "Theme import is unavailable.";
|
|
178
|
+
},
|
|
179
|
+
get children() {
|
|
180
|
+
return createComponent(Button, {
|
|
181
|
+
type: "button",
|
|
182
|
+
size: "sm",
|
|
183
|
+
variant: "outline",
|
|
184
|
+
get disabled() {
|
|
185
|
+
return !props.onManageThemes || props.saving;
|
|
186
|
+
},
|
|
187
|
+
onClick: () => props.onManageThemes?.(),
|
|
188
|
+
children: "Manage themes"
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}), null);
|
|
192
|
+
insert(_el$, createComponent(Show, {
|
|
193
|
+
get when() {
|
|
194
|
+
return props.saveDisabledReason;
|
|
195
|
+
},
|
|
196
|
+
get children() {
|
|
197
|
+
var _el$8 = _tmpl$5();
|
|
198
|
+
setAttribute(_el$8, "id", saveReasonId);
|
|
199
|
+
insert(_el$8, () => props.saveDisabledReason);
|
|
200
|
+
return _el$8;
|
|
201
|
+
}
|
|
202
|
+
}), _el$9);
|
|
203
|
+
insert(_el$9, createComponent(Button, {
|
|
204
|
+
type: "button",
|
|
205
|
+
size: "sm",
|
|
206
|
+
variant: "ghost",
|
|
207
|
+
get disabled() {
|
|
208
|
+
return props.saving;
|
|
209
|
+
},
|
|
210
|
+
onClick: () => props.onReset(),
|
|
211
|
+
children: "Reset"
|
|
212
|
+
}), _el$0);
|
|
213
|
+
insert(_el$0, createComponent(Button, {
|
|
214
|
+
type: "button",
|
|
215
|
+
size: "sm",
|
|
216
|
+
variant: "outline",
|
|
217
|
+
get disabled() {
|
|
218
|
+
return props.saving;
|
|
219
|
+
},
|
|
220
|
+
onClick: () => props.onCancel(),
|
|
221
|
+
children: "Cancel"
|
|
222
|
+
}), null);
|
|
223
|
+
insert(_el$0, createComponent(Button, {
|
|
224
|
+
type: "button",
|
|
225
|
+
size: "sm",
|
|
226
|
+
get disabled() {
|
|
227
|
+
return props.saving || !!props.customAccentError || !!props.saveDisabledReason;
|
|
228
|
+
},
|
|
229
|
+
get ["aria-busy"]() {
|
|
230
|
+
return props.saving;
|
|
231
|
+
},
|
|
232
|
+
get ["aria-describedby"]() {
|
|
233
|
+
return props.saveDisabledReason ? saveReasonId : void 0;
|
|
234
|
+
},
|
|
235
|
+
onClick: () => props.onSave(),
|
|
236
|
+
get children() {
|
|
237
|
+
return props.saving ? "Saving…" : "Save";
|
|
238
|
+
}
|
|
239
|
+
}), null);
|
|
240
|
+
effect(() => className(_el$, cn("min-w-0", props.class)));
|
|
241
|
+
return _el$;
|
|
242
|
+
})();
|
|
243
|
+
}
|
|
244
|
+
/** Modal anchoring/dismissal and nested-listbox behavior come from Kobalte.
|
|
245
|
+
* Its measured available height also bounds scrolling, keeping footer actions
|
|
246
|
+
* reachable when a narrow popup begins below its trigger. */
|
|
247
|
+
function AppearancePopover(props) {
|
|
248
|
+
return createComponent(Popover, {
|
|
249
|
+
get open() {
|
|
250
|
+
return props.open;
|
|
251
|
+
},
|
|
252
|
+
modal: true,
|
|
253
|
+
onOpenChange: (open) => open ? props.onOpen() : props.onDismiss(),
|
|
254
|
+
get children() {
|
|
255
|
+
return [createComponent(PopoverTrigger, {
|
|
256
|
+
as: Button,
|
|
257
|
+
type: "button",
|
|
258
|
+
variant: "ghost",
|
|
259
|
+
size: "icon-sm",
|
|
260
|
+
"aria-label": "Appearance settings",
|
|
261
|
+
get children() {
|
|
262
|
+
return createComponent(Palette, {});
|
|
263
|
+
}
|
|
264
|
+
}), createComponent(PopoverContent, {
|
|
265
|
+
"class": "w-lg max-w-[calc(100vw-2rem)] max-h-(--kb-popper-content-available-height) overflow-y-auto",
|
|
266
|
+
get children() {
|
|
267
|
+
return [
|
|
268
|
+
createComponent(PopoverTitle, { children: "Appearance" }),
|
|
269
|
+
createComponent(PopoverDescription, { children: "Changes preview immediately. Save keeps them; Cancel restores the previous appearance." }),
|
|
270
|
+
createComponent(AppearanceEditor, props)
|
|
271
|
+
];
|
|
272
|
+
}
|
|
273
|
+
})];
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
//#endregion
|
|
278
|
+
export { AppearanceEditor, AppearancePopover };
|
|
279
|
+
|
|
280
|
+
//# sourceMappingURL=appearance-editor.js.map
|