@povio/ui 5.0.0-rc.11 → 5.0.0-rc.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +6 -0
  2. package/dist/{AppCanvasPage-BTmt8poT.d.ts → AppCanvasPage-BZ2mrKY4.d.ts} +3 -1
  3. package/dist/{AppCanvasPage-BsQrZ8q7.js → AppCanvasPage-DtWEvs_Y.js} +1065 -316
  4. package/dist/{CanvasComponentsFrame-C0Sf9RcC.js → CanvasComponentsFrame-CbgJJv-3.js} +1 -1
  5. package/dist/{ComponentGallery-DDSqnm9f.js → ComponentGallery-COqEqqN6.js} +2 -2
  6. package/dist/{Form-DmcByQts.d.ts → Form-DAtj2szV.d.ts} +1 -1
  7. package/dist/{Inputs-C0sUmuPv.d.ts → Inputs-C_6dVwC7.d.ts} +1 -1
  8. package/dist/{Table-BN2_J_Ne.js → Table-piX1SWvN.js} +54 -1
  9. package/dist/{UIConfigurator-C_2kgJtm.js → UIConfigurator-DekPXjv9.js} +1290 -406
  10. package/dist/config/app-canvas-tanstack.d.ts +1 -1
  11. package/dist/config/app-canvas-tanstack.js +1 -1
  12. package/dist/config/app-canvas.d.ts +2 -2
  13. package/dist/config/app-canvas.js +1 -1
  14. package/dist/config/ui-config.d.ts +1 -1
  15. package/dist/config/ui-configurator-vite.d.ts +9 -0
  16. package/dist/config/ui-configurator-vite.js +449 -10
  17. package/dist/config/ui-configurator.d.ts +14 -2
  18. package/dist/config/ui-configurator.js +2 -2
  19. package/dist/{configuration.context-qdjDwQJj.d.ts → configuration.context-3I7-wBII.d.ts} +4 -1
  20. package/dist/{dynamicInputs-DdcsSoYu.d.ts → dynamicInputs-R5i7AT_C.d.ts} +1 -1
  21. package/dist/index.d.ts +2 -2
  22. package/dist/index.js +3 -3
  23. package/dist/rhf/inputs.d.ts +1 -1
  24. package/dist/rhf.d.ts +2 -2
  25. package/dist/rhf.js +3 -3
  26. package/dist/styles/app-canvas.css +402 -18
  27. package/dist/styles/configurator.css +251 -92
  28. package/dist/{table.cva-D5oQ-QvA.js → table.cva-DlMT-zLD.js} +1 -54
  29. package/dist/tanstack/form.d.ts +1 -1
  30. package/dist/tanstack/inputs.d.ts +2 -2
  31. package/dist/tanstack/table.js +2 -2
  32. package/dist/tanstack.d.ts +4 -4
  33. package/dist/tanstack.js +3 -3
  34. package/dist/{uiConfig.context-BqKWd_MO.d.ts → uiConfig.context-BksnNQyw.d.ts} +1 -1
  35. package/dist/{useTableColumnConfig-6zn3zKl3.js → useTableColumnConfig-CNJ_ZvIN.js} +1 -1
  36. package/package.json +1 -1
  37. package/src/configurator/README.md +18 -1
@@ -3,7 +3,6 @@ import { t as UIConfig } from "./uiConfig.context-BS3r_kTS.js";
3
3
  import { t as Check } from "./check-DYMBkp_Z.js";
4
4
  import { t as ChevronDown } from "./chevron-down-B4Pr8bD3.js";
5
5
  import { t as ChevronRight } from "./chevron-right-3nKJR5Bb.js";
6
- import { a as tableHeaderTextDefinition, c as GripVertical, i as tableHeadRowDefinition, n as tableDataDefinition, o as tableRowDefinition, r as tableHeadDataDefinition, s as theadDefinition, t as tableCellTextDefinition } from "./table.cva-D5oQ-QvA.js";
7
6
  import { t as Info } from "./info-iUmX3uDk.js";
8
7
  import { a as checkboxDefinition, i as checkboxContentWrapperDefinition, o as checkboxGroupLabelDefinition, r as checkboxContentRowDefinition, s as checkboxIconDefinition, u as Minus } from "./CheckboxCheckmark-FwKjPVbV.js";
9
8
  import { i as Search, n as selectListBoxItemDefinition, r as selectInputTagsContentWrapperDefinition, t as selectPopoverDefinition } from "./selectDesktop.cva-CHAMxhfO.js";
@@ -19,6 +18,7 @@ import { t as $2ec61d1d4f780267$export$a8a3e93435678ff9 } from "./Heading-nI1_VO
19
18
  import { t as $efe09c6d1c304b50$export$9afb8bc826b033ea } from "./Text-D2MPZ3sY.js";
20
19
  import { n as $1f3c3b1a70cec653$export$ff05c3ac10437e03, t as $cdaed739b1139372$export$c24727297075ec6a } from "./Form-DlQcyN1f.js";
21
20
  import { t as Checkbox } from "./Checkbox-D3f2Plbc.js";
21
+ import { t as $aa5f63badbfee5df$exports } from "./intlStrings-chfsan9H.js";
22
22
  import { a as $928221da08ecbc62$export$dca12b0bb56e4fc, i as $928221da08ecbc62$export$a11e76429ed99b4, n as $928221da08ecbc62$export$7c5906fe4f1f2af2, r as $928221da08ecbc62$export$7ff8f37d2d81a48d, t as $928221da08ecbc62$export$41f133550aa26f48 } from "./ListBox-CL8Ar4Q_.js";
23
23
  import { n as $8b8d26808cb8cb53$export$8948f78d83984c69, t as $8b8d26808cb8cb53$export$2b77a92f1a5ad772 } from "./Modal-w60dVQcb.js";
24
24
  import { i as radioDefinition, n as radioContentRowDefinition, r as radioContentWrapperDefinition, t as RadioGroup } from "./RadioGroup-efBKgTYA.js";
@@ -46,10 +46,11 @@ import { a as stepperSeparatorDefinition, i as stepperNumberDefinition, n as ste
46
46
  import { i as dialogOverlayDefinition, n as dialogMainDefinition, t as dialogContentDefinition } from "./dialog.cva-COhDZaVl.js";
47
47
  import { i as alertDefinition, n as statusIconDefinition, r as statusSeparatorDefinition, t as Alert } from "./Alert-CnvEb1D_.js";
48
48
  import { a as toastDefinition, i as toastContainerDefinition } from "./toast.cva-C_L_RffH.js";
49
+ import { a as tableHeaderTextDefinition, i as tableHeadRowDefinition, n as tableDataDefinition, o as tableRowDefinition, r as tableHeadDataDefinition, s as theadDefinition, t as tableCellTextDefinition } from "./table.cva-DlMT-zLD.js";
49
50
  import { t as linkDefinition } from "./link.cva-DMTHZiJG.js";
50
51
  import { t as tooltipWrapperTriggerDefinition } from "./tooltipWrapper.cva-BBQ4ic3D.js";
51
- import { C as toRgb, S as toHex, _ as listedLayoutToken, a as generateShades, b as runtimeCss, c as isEditableToken, d as labelFor, f as layoutKindFor, g as linkedLayoutTokens, h as layoutScales, i as exportCss, l as isFontSizeToken, m as layoutLevelFor, n as controlHeightCounterpart, o as groupFor, p as layoutKinds, r as emptyTheme, s as groups, t as baseColorNames, u as isRgb, w as validToken, x as spacingLevels, y as previewTokens } from "./theme-model-DtTsIxou.js";
52
- import $ahdqC$react, { Fragment, Suspense, createContext, lazy, use, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
52
+ import { C as toRgb, S as toHex, _ as listedLayoutToken, a as generateShades, b as runtimeCss, c as isEditableToken, d as labelFor, f as layoutKindFor, g as linkedLayoutTokens, h as layoutScales, i as exportCss, l as isFontSizeToken, m as layoutLevelFor, n as controlHeightCounterpart, o as groupFor, p as layoutKinds, r as emptyTheme, s as groups, t as baseColorNames, u as isRgb, v as parseThemeCss, w as validToken, x as spacingLevels, y as previewTokens } from "./theme-model-DtTsIxou.js";
53
+ import $ahdqC$react, { Fragment, Suspense, createContext, lazy, use, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
53
54
  import { c } from "react/compiler-runtime";
54
55
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
55
56
  import { mergeProps } from "react-aria/mergeProps";
@@ -58,8 +59,8 @@ import { filterDOMProps } from "react-aria/filterDOMProps";
58
59
  import { useFocusRing } from "react-aria/useFocusRing";
59
60
  import { createHideableComponent } from "react-aria/private/collections/Hidden";
60
61
  import { createPortal } from "react-dom";
61
- import "react-aria/useLocalizedStringFormatter";
62
- import "react-aria/useListFormatter";
62
+ import { useLocalizedStringFormatter } from "react-aria/useLocalizedStringFormatter";
63
+ import { useListFormatter } from "react-aria/useListFormatter";
63
64
  import { HiddenSelect, useSelect } from "react-aria/useSelect";
64
65
  import { useSelectState } from "react-stately/useSelectState";
65
66
  import { UNSAFE_PortalProvider } from "react-aria";
@@ -70,7 +71,7 @@ import { UNSAFE_PortalProvider } from "react-aria";
70
71
  * This source code is licensed under the ISC license.
71
72
  * See the LICENSE file in the root directory of this source tree.
72
73
  */
73
- const __iconData$9 = {
74
+ const __iconData$10 = {
74
75
  name: "arrow-down-to-line",
75
76
  size: 24,
76
77
  node: [
@@ -88,8 +89,8 @@ const __iconData$9 = {
88
89
  }]
89
90
  ]
90
91
  };
91
- __iconData$9.node;
92
- const ArrowDownToLine = createLucideIcon(__iconData$9);
92
+ __iconData$10.node;
93
+ const ArrowDownToLine = createLucideIcon(__iconData$10);
93
94
  //#endregion
94
95
  //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/chevrons-up-down.mjs
95
96
  /**
@@ -98,7 +99,7 @@ const ArrowDownToLine = createLucideIcon(__iconData$9);
98
99
  * This source code is licensed under the ISC license.
99
100
  * See the LICENSE file in the root directory of this source tree.
100
101
  */
101
- const __iconData$8 = {
102
+ const __iconData$9 = {
102
103
  name: "chevrons-up-down",
103
104
  size: 24,
104
105
  node: [["path", {
@@ -109,8 +110,8 @@ const __iconData$8 = {
109
110
  key: "sgt6xg"
110
111
  }]]
111
112
  };
112
- __iconData$8.node;
113
- const ChevronsUpDown = createLucideIcon(__iconData$8);
113
+ __iconData$9.node;
114
+ const ChevronsUpDown = createLucideIcon(__iconData$9);
114
115
  //#endregion
115
116
  //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/external-link.mjs
116
117
  /**
@@ -119,7 +120,7 @@ const ChevronsUpDown = createLucideIcon(__iconData$8);
119
120
  * This source code is licensed under the ISC license.
120
121
  * See the LICENSE file in the root directory of this source tree.
121
122
  */
122
- const __iconData$7 = {
123
+ const __iconData$8 = {
123
124
  name: "external-link",
124
125
  size: 24,
125
126
  node: [
@@ -137,8 +138,8 @@ const __iconData$7 = {
137
138
  }]
138
139
  ]
139
140
  };
140
- __iconData$7.node;
141
- const ExternalLink = createLucideIcon(__iconData$7);
141
+ __iconData$8.node;
142
+ const ExternalLink = createLucideIcon(__iconData$8);
142
143
  //#endregion
143
144
  //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/moon.mjs
144
145
  /**
@@ -147,7 +148,7 @@ const ExternalLink = createLucideIcon(__iconData$7);
147
148
  * This source code is licensed under the ISC license.
148
149
  * See the LICENSE file in the root directory of this source tree.
149
150
  */
150
- const __iconData$6 = {
151
+ const __iconData$7 = {
151
152
  name: "moon",
152
153
  size: 24,
153
154
  node: [["path", {
@@ -155,8 +156,8 @@ const __iconData$6 = {
155
156
  key: "kfwtm"
156
157
  }]]
157
158
  };
158
- __iconData$6.node;
159
- const Moon = createLucideIcon(__iconData$6);
159
+ __iconData$7.node;
160
+ const Moon = createLucideIcon(__iconData$7);
160
161
  //#endregion
161
162
  //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/panel-top.mjs
162
163
  /**
@@ -165,7 +166,7 @@ const Moon = createLucideIcon(__iconData$6);
165
166
  * This source code is licensed under the ISC license.
166
167
  * See the LICENSE file in the root directory of this source tree.
167
168
  */
168
- const __iconData$5 = {
169
+ const __iconData$6 = {
169
170
  name: "panel-top",
170
171
  size: 24,
171
172
  node: [["rect", {
@@ -180,8 +181,29 @@ const __iconData$5 = {
180
181
  key: "1pudct"
181
182
  }]]
182
183
  };
184
+ __iconData$6.node;
185
+ const PanelTop = createLucideIcon(__iconData$6);
186
+ //#endregion
187
+ //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/pencil.mjs
188
+ /**
189
+ * @license lucide-react v1.43.0 - ISC
190
+ *
191
+ * This source code is licensed under the ISC license.
192
+ * See the LICENSE file in the root directory of this source tree.
193
+ */
194
+ const __iconData$5 = {
195
+ name: "pencil",
196
+ size: 24,
197
+ node: [["path", {
198
+ d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",
199
+ key: "1a8usu"
200
+ }], ["path", {
201
+ d: "m15 5 4 4",
202
+ key: "1mk7zo"
203
+ }]]
204
+ };
183
205
  __iconData$5.node;
184
- const PanelTop = createLucideIcon(__iconData$5);
206
+ const Pencil = createLucideIcon(__iconData$5);
185
207
  //#endregion
186
208
  //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/pin.mjs
187
209
  /**
@@ -246,58 +268,6 @@ const __iconData$2 = {
246
268
  __iconData$2.node;
247
269
  const RotateCcw = createLucideIcon(__iconData$2);
248
270
  //#endregion
249
- //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/sliders-horizontal.mjs
250
- /**
251
- * @license lucide-react v1.43.0 - ISC
252
- *
253
- * This source code is licensed under the ISC license.
254
- * See the LICENSE file in the root directory of this source tree.
255
- */
256
- const __iconData$1 = {
257
- name: "sliders-horizontal",
258
- size: 24,
259
- node: [
260
- ["path", {
261
- d: "M10 5H3",
262
- key: "1qgfaw"
263
- }],
264
- ["path", {
265
- d: "M12 19H3",
266
- key: "yhmn1j"
267
- }],
268
- ["path", {
269
- d: "M14 3v4",
270
- key: "1sua03"
271
- }],
272
- ["path", {
273
- d: "M16 17v4",
274
- key: "1q0r14"
275
- }],
276
- ["path", {
277
- d: "M21 12h-9",
278
- key: "1o4lsq"
279
- }],
280
- ["path", {
281
- d: "M21 19h-5",
282
- key: "1rlt1p"
283
- }],
284
- ["path", {
285
- d: "M21 5h-7",
286
- key: "1oszz2"
287
- }],
288
- ["path", {
289
- d: "M8 10v4",
290
- key: "tgpxqk"
291
- }],
292
- ["path", {
293
- d: "M8 12H3",
294
- key: "a7s4jb"
295
- }]
296
- ]
297
- };
298
- __iconData$1.node;
299
- const SlidersHorizontal = createLucideIcon(__iconData$1);
300
- //#endregion
301
271
  //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/sun.mjs
302
272
  /**
303
273
  * @license lucide-react v1.43.0 - ISC
@@ -305,7 +275,7 @@ const SlidersHorizontal = createLucideIcon(__iconData$1);
305
275
  * This source code is licensed under the ISC license.
306
276
  * See the LICENSE file in the root directory of this source tree.
307
277
  */
308
- const __iconData = {
278
+ const __iconData$1 = {
309
279
  name: "sun",
310
280
  size: 24,
311
281
  node: [
@@ -349,10 +319,50 @@ const __iconData = {
349
319
  }]
350
320
  ]
351
321
  };
322
+ __iconData$1.node;
323
+ const Sun = createLucideIcon(__iconData$1);
324
+ //#endregion
325
+ //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/trash.mjs
326
+ /**
327
+ * @license lucide-react v1.43.0 - ISC
328
+ *
329
+ * This source code is licensed under the ISC license.
330
+ * See the LICENSE file in the root directory of this source tree.
331
+ */
332
+ const __iconData = {
333
+ name: "trash",
334
+ size: 24,
335
+ node: [
336
+ ["path", {
337
+ d: "M10 11v6",
338
+ key: "nco0om"
339
+ }],
340
+ ["path", {
341
+ d: "M14 11v6",
342
+ key: "outv1u"
343
+ }],
344
+ ["path", {
345
+ d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",
346
+ key: "miytrc"
347
+ }],
348
+ ["path", {
349
+ d: "M3 6h18",
350
+ key: "d0wm0j"
351
+ }],
352
+ ["path", {
353
+ d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",
354
+ key: "e791ji"
355
+ }]
356
+ ],
357
+ aliases: ["trash-2"]
358
+ };
352
359
  __iconData.node;
353
- const Sun = createLucideIcon(__iconData);
360
+ const Trash = createLucideIcon(__iconData);
354
361
  //#endregion
355
362
  //#region ../../node_modules/.bun/react-aria-components@1.21.1+67f6792bdf102c28/node_modules/react-aria-components/dist/private/Select.mjs
363
+ function $parcel$interopDefault(a) {
364
+ return a && a.__esModule ? a.default : a;
365
+ }
356
366
  const $c8bb816105474884$export$7540cee5be7dc19b = /*#__PURE__*/ createContext(null);
357
367
  const $c8bb816105474884$export$ef445b55be0601bd = /*#__PURE__*/ createContext(null);
358
368
  const $c8bb816105474884$export$ef9b1a59e592288f = /*#__PURE__*/ createHideableComponent(function Select(props, ref) {
@@ -473,6 +483,68 @@ function $c8bb816105474884$var$SelectInner({ props, selectRef: ref, collection }
473
483
  })));
474
484
  }
475
485
  const $c8bb816105474884$export$f8f745c04421623f = /*#__PURE__*/ createContext(null);
486
+ const $c8bb816105474884$export$e288731fd71264f0 = /*#__PURE__*/ createHideableComponent(function SelectValue(props, ref) {
487
+ [props, ref] = $7230ffa83bc0c2cf$export$29f1550f4b0d4415(props, ref, $c8bb816105474884$export$f8f745c04421623f);
488
+ let state = useContext($c8bb816105474884$export$ef445b55be0601bd);
489
+ let { placeholder } = $7230ffa83bc0c2cf$export$fabf2dc03a41866e($c8bb816105474884$export$7540cee5be7dc19b);
490
+ let rendered = state.selectedItems.map((item) => {
491
+ let rendered = item.props?.children;
492
+ if (typeof rendered === "function") rendered = rendered({
493
+ isHovered: false,
494
+ isPressed: false,
495
+ isSelected: false,
496
+ isFocused: false,
497
+ isFocusVisible: false,
498
+ isDisabled: false,
499
+ selectionMode: "single",
500
+ selectionBehavior: "toggle"
501
+ });
502
+ return rendered;
503
+ });
504
+ let formatter = useListFormatter();
505
+ let textValue = useMemo(() => state.selectedItems.map((item) => item?.textValue), [state.selectedItems]);
506
+ let selectionMode = state.selectionManager.selectionMode;
507
+ let selectedText = useMemo(() => selectionMode === "single" ? textValue[0] ?? "" : formatter.format(textValue), [
508
+ selectionMode,
509
+ formatter,
510
+ textValue
511
+ ]);
512
+ let defaultChildren = useMemo(() => {
513
+ if (selectionMode === "single") return rendered[0];
514
+ let parts = formatter.formatToParts(textValue);
515
+ if (parts.length === 0) return null;
516
+ let index = 0;
517
+ return parts.map((part) => {
518
+ if (part.type === "element") return /*#__PURE__*/ $ahdqC$react.createElement(Fragment, { key: index }, rendered[index++]);
519
+ else return part.value;
520
+ });
521
+ }, [
522
+ selectionMode,
523
+ formatter,
524
+ textValue,
525
+ rendered
526
+ ]);
527
+ let stringFormatter = useLocalizedStringFormatter($parcel$interopDefault($aa5f63badbfee5df$exports), "react-aria-components");
528
+ let renderProps = $7230ffa83bc0c2cf$export$4d86445c2cf5e3({
529
+ ...props,
530
+ defaultChildren: defaultChildren ?? placeholder ?? stringFormatter.format("selectPlaceholder"),
531
+ defaultClassName: "react-aria-SelectValue",
532
+ values: {
533
+ selectedItem: state.selectedItems[0]?.value ?? null,
534
+ selectedItems: useMemo(() => state.selectedItems.map((item) => item.value ?? null), [state.selectedItems]),
535
+ selectedText,
536
+ isPlaceholder: state.selectedItems.length === 0,
537
+ state
538
+ }
539
+ });
540
+ let DOMProps = filterDOMProps(props, { global: true });
541
+ return /*#__PURE__*/ $ahdqC$react.createElement($7230ffa83bc0c2cf$export$df3a06d6289f983e.span, {
542
+ ref,
543
+ ...DOMProps,
544
+ ...renderProps,
545
+ "data-placeholder": state.selectedItems.length === 0 || void 0
546
+ }, /*#__PURE__*/ $ahdqC$react.createElement($efe09c6d1c304b50$export$9afb8bc826b033ea.Provider, { value: void 0 }, renderProps.children));
547
+ });
476
548
  //#endregion
477
549
  //#region src/configurator/cva-definitions.ts
478
550
  const cvaDefinitions = {
@@ -609,7 +681,7 @@ const emptyConfiguration = () => ({
609
681
  });
610
682
  const ConfigurationContext = createContext(null);
611
683
  function UIConfigurationProvider(t0) {
612
- const $ = c(48);
684
+ const $ = c(50);
613
685
  const { defaults, initialValue, onApply, children } = t0;
614
686
  const inheritedOverrides = UIOverrides.useConfig();
615
687
  const [applied, setApplied] = useState(initialValue ?? emptyConfiguration);
@@ -623,95 +695,112 @@ function UIConfigurationProvider(t0) {
623
695
  let t1;
624
696
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
625
697
  t1 = () => {
626
- setComponentHosts(_temp$7);
698
+ setComponentHosts(_temp$8);
627
699
  return () => setComponentHosts(_temp2$5);
628
700
  };
629
701
  $[0] = t1;
630
702
  } else t1 = $[0];
631
703
  const hostComponents = t1;
632
- const active = previewConfiguration ?? (isOpen ? draft : applied);
633
704
  let t2;
634
- if ($[1] !== applied) {
635
- t2 = () => {
705
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
706
+ t2 = (value, t3, t4) => {
707
+ const closeEditor = t3 === void 0 ? false : t3;
708
+ const remount = t4 === void 0 ? true : t4;
709
+ if (closeEditor) setOpen(false);
710
+ setApplied(structuredClone(value));
711
+ setDraft(structuredClone(value));
712
+ setPreviewConfiguration(null);
713
+ if (remount) setRevision(_temp3$4);
714
+ };
715
+ $[1] = t2;
716
+ } else t2 = $[1];
717
+ const replaceConfiguration = t2;
718
+ const active = previewConfiguration ?? (isOpen ? draft : applied);
719
+ let t3;
720
+ if ($[2] !== applied) {
721
+ t3 = () => {
636
722
  setFloating(false);
637
723
  setDraft(structuredClone(applied));
638
- setRevision(_temp3$4);
724
+ setRevision(_temp4$4);
639
725
  setOpen(true);
640
726
  };
641
- $[1] = applied;
642
- $[2] = t2;
643
- } else t2 = $[2];
644
- const open = t2;
645
- let t3;
646
- if ($[3] !== isOpen || $[4] !== open) {
647
- t3 = () => {
648
- if (isOpen) setRevision(_temp4$4);
727
+ $[2] = applied;
728
+ $[3] = t3;
729
+ } else t3 = $[3];
730
+ const open = t3;
731
+ let t4;
732
+ if ($[4] !== isOpen || $[5] !== open) {
733
+ t4 = () => {
734
+ if (isOpen) setRevision(_temp5$2);
649
735
  else open();
650
736
  setFloating(true);
651
737
  };
652
- $[3] = isOpen;
653
- $[4] = open;
654
- $[5] = t3;
655
- } else t3 = $[5];
656
- const openFloating = t3;
657
- let t4;
658
- if ($[6] !== isOpen || $[7] !== openFloating) {
659
- t4 = (name) => {
660
- setTokenRequest((current) => ({
738
+ $[4] = isOpen;
739
+ $[5] = open;
740
+ $[6] = t4;
741
+ } else t4 = $[6];
742
+ const openFloating = t4;
743
+ let t5;
744
+ if ($[7] !== isOpen || $[8] !== openFloating) {
745
+ t5 = (name) => {
746
+ setTokenRequest((current_0) => ({
661
747
  name,
662
- id: (current?.id ?? 0) + 1
748
+ id: (current_0?.id ?? 0) + 1
663
749
  }));
664
750
  if (!isOpen) openFloating();
665
751
  };
666
- $[6] = isOpen;
667
- $[7] = openFloating;
668
- $[8] = t4;
669
- } else t4 = $[8];
670
- const revealToken = t4;
671
- let t5;
672
- if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
673
- t5 = () => setTokenRequest(null);
752
+ $[7] = isOpen;
753
+ $[8] = openFloating;
674
754
  $[9] = t5;
675
755
  } else t5 = $[9];
676
- const clearTokenRequest = t5;
756
+ const revealToken = t5;
677
757
  let t6;
678
- if ($[10] !== applied) {
679
- t6 = () => {
758
+ if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
759
+ t6 = () => setTokenRequest(null);
760
+ $[10] = t6;
761
+ } else t6 = $[10];
762
+ const clearTokenRequest = t6;
763
+ let t7;
764
+ if ($[11] !== applied) {
765
+ t7 = () => {
680
766
  setDraft(structuredClone(applied));
681
767
  setOpen(false);
682
768
  };
683
- $[10] = applied;
684
- $[11] = t6;
685
- } else t6 = $[11];
686
- const cancel = t6;
687
- let t7;
688
- if ($[12] !== draft || $[13] !== onApply) {
689
- t7 = () => {
769
+ $[11] = applied;
770
+ $[12] = t7;
771
+ } else t7 = $[12];
772
+ const cancel = t7;
773
+ let t8;
774
+ if ($[13] !== draft || $[14] !== onApply) {
775
+ t8 = () => {
690
776
  onApply?.(structuredClone(draft));
691
777
  setApplied(structuredClone(draft));
692
778
  setOpen(false);
693
779
  };
694
- $[12] = draft;
695
- $[13] = onApply;
696
- $[14] = t7;
697
- } else t7 = $[14];
698
- const apply = t7;
699
- let t8;
700
- if ($[15] !== active.overrides || $[16] !== inheritedOverrides) {
701
- t8 = applyCvaEdits(inheritedOverrides, active.overrides);
702
- $[15] = active.overrides;
703
- $[16] = inheritedOverrides;
704
- $[17] = t8;
705
- } else t8 = $[17];
706
- const overrides = t8;
707
- const t9 = componentHosts > 0;
708
- let t10;
709
- if ($[18] !== active || $[19] !== apply || $[20] !== cancel || $[21] !== defaults || $[22] !== draft || $[23] !== floating || $[24] !== inheritedOverrides || $[25] !== isOpen || $[26] !== open || $[27] !== openFloating || $[28] !== revealToken || $[29] !== revision || $[30] !== t9 || $[31] !== tokenRequest) {
710
- t10 = {
780
+ $[13] = draft;
781
+ $[14] = onApply;
782
+ $[15] = t8;
783
+ } else t8 = $[15];
784
+ const apply = t8;
785
+ let t9;
786
+ if ($[16] !== active.overrides || $[17] !== inheritedOverrides) {
787
+ t9 = applyCvaEdits(inheritedOverrides, active.overrides);
788
+ $[16] = active.overrides;
789
+ $[17] = inheritedOverrides;
790
+ $[18] = t9;
791
+ } else t9 = $[18];
792
+ const overrides = t9;
793
+ const t10 = isOpen ? draft : applied;
794
+ const t11 = componentHosts > 0;
795
+ let t12;
796
+ if ($[19] !== active || $[20] !== apply || $[21] !== cancel || $[22] !== defaults || $[23] !== draft || $[24] !== floating || $[25] !== inheritedOverrides || $[26] !== isOpen || $[27] !== open || $[28] !== openFloating || $[29] !== revealToken || $[30] !== revision || $[31] !== t10 || $[32] !== t11 || $[33] !== tokenRequest) {
797
+ t12 = {
711
798
  defaults,
712
799
  inheritedOverrides,
713
800
  draft,
714
801
  active,
802
+ currentConfiguration: t10,
803
+ replaceConfiguration,
715
804
  setPreviewConfiguration,
716
805
  setDraft,
717
806
  isOpen,
@@ -724,85 +813,89 @@ function UIConfigurationProvider(t0) {
724
813
  revealToken,
725
814
  tokenRequest,
726
815
  clearTokenRequest,
727
- componentsHosted: t9,
816
+ componentsHosted: t11,
728
817
  hostComponents
729
818
  };
730
- $[18] = active;
731
- $[19] = apply;
732
- $[20] = cancel;
733
- $[21] = defaults;
734
- $[22] = draft;
735
- $[23] = floating;
736
- $[24] = inheritedOverrides;
737
- $[25] = isOpen;
738
- $[26] = open;
739
- $[27] = openFloating;
740
- $[28] = revealToken;
741
- $[29] = revision;
742
- $[30] = t9;
743
- $[31] = tokenRequest;
744
- $[32] = t10;
745
- } else t10 = $[32];
746
- const contextValue = t10;
747
- let t11;
748
- if ($[33] !== active.theme || $[34] !== defaults) {
749
- t11 = runtimeCss(defaults, active.theme);
750
- $[33] = active.theme;
751
- $[34] = defaults;
752
- $[35] = t11;
753
- } else t11 = $[35];
754
- let t12;
755
- if ($[36] !== t11) {
756
- t12 = /* @__PURE__ */ jsx("style", {
819
+ $[19] = active;
820
+ $[20] = apply;
821
+ $[21] = cancel;
822
+ $[22] = defaults;
823
+ $[23] = draft;
824
+ $[24] = floating;
825
+ $[25] = inheritedOverrides;
826
+ $[26] = isOpen;
827
+ $[27] = open;
828
+ $[28] = openFloating;
829
+ $[29] = revealToken;
830
+ $[30] = revision;
831
+ $[31] = t10;
832
+ $[32] = t11;
833
+ $[33] = tokenRequest;
834
+ $[34] = t12;
835
+ } else t12 = $[34];
836
+ const contextValue = t12;
837
+ let t13;
838
+ if ($[35] !== active.theme || $[36] !== defaults) {
839
+ t13 = runtimeCss(defaults, active.theme);
840
+ $[35] = active.theme;
841
+ $[36] = defaults;
842
+ $[37] = t13;
843
+ } else t13 = $[37];
844
+ let t14;
845
+ if ($[38] !== t13) {
846
+ t14 = /* @__PURE__ */ jsx("style", {
757
847
  "data-povio-ui-configuration": true,
758
- children: t11
848
+ children: t13
759
849
  });
760
- $[36] = t11;
761
- $[37] = t12;
762
- } else t12 = $[37];
763
- let t13;
764
- if ($[38] !== active.config || $[39] !== children) {
765
- t13 = /* @__PURE__ */ jsx(UIConfig.Provider, {
850
+ $[38] = t13;
851
+ $[39] = t14;
852
+ } else t14 = $[39];
853
+ let t15;
854
+ if ($[40] !== active.config || $[41] !== children) {
855
+ t15 = /* @__PURE__ */ jsx(UIConfig.Provider, {
766
856
  config: active.config,
767
857
  children
768
858
  });
769
- $[38] = active.config;
770
- $[39] = children;
771
- $[40] = t13;
772
- } else t13 = $[40];
773
- let t14;
774
- if ($[41] !== overrides || $[42] !== t13) {
775
- t14 = /* @__PURE__ */ jsx(UIOverrides.Provider, {
859
+ $[40] = active.config;
860
+ $[41] = children;
861
+ $[42] = t15;
862
+ } else t15 = $[42];
863
+ let t16;
864
+ if ($[43] !== overrides || $[44] !== t15) {
865
+ t16 = /* @__PURE__ */ jsx(UIOverrides.Provider, {
776
866
  config: overrides,
777
- children: t13
867
+ children: t15
778
868
  });
779
- $[41] = overrides;
780
- $[42] = t13;
781
- $[43] = t14;
782
- } else t14 = $[43];
783
- let t15;
784
- if ($[44] !== contextValue || $[45] !== t12 || $[46] !== t14) {
785
- t15 = /* @__PURE__ */ jsxs(ConfigurationContext.Provider, {
869
+ $[43] = overrides;
870
+ $[44] = t15;
871
+ $[45] = t16;
872
+ } else t16 = $[45];
873
+ let t17;
874
+ if ($[46] !== contextValue || $[47] !== t14 || $[48] !== t16) {
875
+ t17 = /* @__PURE__ */ jsxs(ConfigurationContext.Provider, {
786
876
  value: contextValue,
787
- children: [t12, t14]
877
+ children: [t14, t16]
788
878
  });
789
- $[44] = contextValue;
790
- $[45] = t12;
791
- $[46] = t14;
792
- $[47] = t15;
793
- } else t15 = $[47];
794
- return t15;
879
+ $[46] = contextValue;
880
+ $[47] = t14;
881
+ $[48] = t16;
882
+ $[49] = t17;
883
+ } else t17 = $[49];
884
+ return t17;
885
+ }
886
+ function _temp5$2(value_1) {
887
+ return value_1 + 1;
795
888
  }
796
889
  function _temp4$4(value_0) {
797
890
  return value_0 + 1;
798
891
  }
799
- function _temp3$4(value) {
800
- return value + 1;
892
+ function _temp3$4(current) {
893
+ return current + 1;
801
894
  }
802
895
  function _temp2$5(count_0) {
803
896
  return count_0 - 1;
804
897
  }
805
- function _temp$7(count) {
898
+ function _temp$8(count) {
806
899
  return count + 1;
807
900
  }
808
901
  function useUIConfiguration() {
@@ -890,7 +983,7 @@ function InspectorDetails(t0) {
890
983
  $[13] = onSelect;
891
984
  $[14] = t6;
892
985
  } else t6 = $[14];
893
- t5 = snapshot.groups.map(_temp$6).filter(_temp2$4).map(t6);
986
+ t5 = snapshot.groups.map(_temp$7).filter(_temp2$4).map(t6);
894
987
  $[10] = onSelect;
895
988
  $[11] = snapshot.groups;
896
989
  $[12] = t5;
@@ -907,7 +1000,7 @@ function InspectorDetails(t0) {
907
1000
  function _temp2$4(group_0) {
908
1001
  return group_0.properties.length;
909
1002
  }
910
- function _temp$6(group) {
1003
+ function _temp$7(group) {
911
1004
  return {
912
1005
  name: group.name,
913
1006
  properties: group.properties.filter((property) => group.name !== "Layout" || ![
@@ -2158,120 +2251,6 @@ function PreviewInspector({ children, revision, isKnown, onSelect, onScroll }) {
2158
2251
  });
2159
2252
  }
2160
2253
  //#endregion
2161
- //#region src/configurator/ConfigurationLauncher.tsx
2162
- function ConfigurationLauncher({ position, onOpen }) {
2163
- const ref = useRef(null);
2164
- const gesture = useRef(null);
2165
- const dragged = useRef(false);
2166
- const pending = useRef(null);
2167
- const frame = useRef(null);
2168
- const place = useCallback((next) => {
2169
- const element = ref.current;
2170
- if (!element) return;
2171
- const left = Math.max(8, Math.min(next.left, window.innerWidth - element.offsetWidth - 8));
2172
- const top = Math.max(8, Math.min(next.top, window.innerHeight - element.offsetHeight - 8));
2173
- position.current = {
2174
- left,
2175
- top
2176
- };
2177
- element.style.left = `${left}px`;
2178
- element.style.top = `${top}px`;
2179
- }, [position]);
2180
- function finish() {
2181
- if (frame.current !== null) cancelAnimationFrame(frame.current);
2182
- frame.current = null;
2183
- if (pending.current) place(pending.current);
2184
- pending.current = null;
2185
- gesture.current = null;
2186
- }
2187
- useLayoutEffect(() => {
2188
- const element_0 = ref.current;
2189
- if (!element_0) return;
2190
- const resize = () => place(position.current ?? {
2191
- left: window.innerWidth - element_0.offsetWidth - 24,
2192
- top: window.innerHeight - element_0.offsetHeight - 24
2193
- });
2194
- resize();
2195
- window.addEventListener("resize", resize);
2196
- return () => {
2197
- window.removeEventListener("resize", resize);
2198
- if (frame.current !== null) cancelAnimationFrame(frame.current);
2199
- if (pending.current) position.current = pending.current;
2200
- };
2201
- }, [place, position]);
2202
- return /* @__PURE__ */ jsxs("button", {
2203
- ref,
2204
- type: "button",
2205
- className: "studio-floating-launcher",
2206
- "aria-label": "Open Povio UI configuration",
2207
- title: "Open Povio UI · Drag to move",
2208
- onClick: (event) => {
2209
- if (dragged.current && event.detail !== 0) {
2210
- dragged.current = false;
2211
- return;
2212
- }
2213
- onOpen();
2214
- },
2215
- onPointerDown: (event_0) => {
2216
- if (event_0.button !== 0) return;
2217
- const rect = event_0.currentTarget.getBoundingClientRect();
2218
- dragged.current = false;
2219
- gesture.current = {
2220
- x: event_0.clientX,
2221
- y: event_0.clientY,
2222
- left: rect.left,
2223
- top: rect.top,
2224
- pointerId: event_0.pointerId
2225
- };
2226
- event_0.currentTarget.setPointerCapture(event_0.pointerId);
2227
- },
2228
- onPointerMove: (event_1) => {
2229
- const start = gesture.current;
2230
- if (!start || start.pointerId !== event_1.pointerId) return;
2231
- const x = event_1.clientX - start.x;
2232
- const y = event_1.clientY - start.y;
2233
- if (!dragged.current && Math.hypot(x, y) < 5) return;
2234
- dragged.current = true;
2235
- pending.current = {
2236
- left: start.left + x,
2237
- top: start.top + y
2238
- };
2239
- if (frame.current !== null) return;
2240
- frame.current = requestAnimationFrame(() => {
2241
- frame.current = null;
2242
- if (pending.current) place(pending.current);
2243
- });
2244
- },
2245
- onPointerUp: (event_2) => {
2246
- if (gesture.current?.pointerId !== event_2.pointerId) return;
2247
- finish();
2248
- if (event_2.currentTarget.hasPointerCapture(event_2.pointerId)) event_2.currentTarget.releasePointerCapture(event_2.pointerId);
2249
- },
2250
- onPointerCancel: finish,
2251
- onLostPointerCapture: finish,
2252
- onKeyDown: (event_3) => {
2253
- const move = {
2254
- ArrowLeft: [-1, 0],
2255
- ArrowRight: [1, 0],
2256
- ArrowUp: [0, -1],
2257
- ArrowDown: [0, 1]
2258
- }[event_3.key];
2259
- if (!move || !position.current) return;
2260
- event_3.preventDefault();
2261
- const step = event_3.shiftKey ? 40 : 10;
2262
- place({
2263
- left: position.current.left + move[0] * step,
2264
- top: position.current.top + move[1] * step
2265
- });
2266
- },
2267
- children: [
2268
- /* @__PURE__ */ jsx(SlidersHorizontal, { size: 18 }),
2269
- /* @__PURE__ */ jsx("span", { children: "Povio UI" }),
2270
- /* @__PURE__ */ jsx(GripVertical, { size: 16 })
2271
- ]
2272
- });
2273
- }
2274
- //#endregion
2275
2254
  //#region src/configurator/useStudioPopout.ts
2276
2255
  const StudioPopoutContext = createContext(false);
2277
2256
  /** Keep the popup's styles current without copying scripts or starting a second app. */
@@ -2616,6 +2595,7 @@ function useStudioWindow(bounds, enabled = true) {
2616
2595
  onLostPointerCapture: move.onLostPointerCapture,
2617
2596
  onPointerCancel: move.onPointerCancel,
2618
2597
  onPointerDown(event_5) {
2598
+ if (!event_5.currentTarget.contains(event_5.target)) return;
2619
2599
  if (event_5.target.closest("button, input, select, textarea, a, label, [role='tab']")) return;
2620
2600
  move.onPointerDown(event_5);
2621
2601
  }
@@ -2643,7 +2623,7 @@ function CvaPreview(t0) {
2643
2623
  component = slot.split(".")[0];
2644
2624
  const props = {
2645
2625
  ...definition?.config.defaultVariants,
2646
- ...Object.fromEntries(Object.entries(variants).filter(_temp$5).map(_temp2$3))
2626
+ ...Object.fromEntries(Object.entries(variants).filter(_temp$6).map(_temp2$3))
2647
2627
  };
2648
2628
  const classes = (key, t4) => {
2649
2629
  const extra = t4 === void 0 ? {} : t4;
@@ -3412,7 +3392,7 @@ function _temp2$3(t0) {
3412
3392
  const [name, value_0] = t0;
3413
3393
  return [name, value_0 === "true" ? true : value_0 === "false" ? false : value_0];
3414
3394
  }
3415
- function _temp$5(t0) {
3395
+ function _temp$6(t0) {
3416
3396
  const [, value] = t0;
3417
3397
  return value !== "";
3418
3398
  }
@@ -3568,7 +3548,7 @@ function ClassField(t0) {
3568
3548
  onFocus,
3569
3549
  onChange: t4,
3570
3550
  onBlur: t5,
3571
- onKeyDown: _temp$4
3551
+ onKeyDown: _temp$5
3572
3552
  });
3573
3553
  $[10] = label;
3574
3554
  $[11] = onFocus;
@@ -3589,7 +3569,7 @@ function ClassField(t0) {
3589
3569
  } else t7 = $[17];
3590
3570
  return t7;
3591
3571
  }
3592
- function _temp$4(event_0) {
3572
+ function _temp$5(event_0) {
3593
3573
  if (event_0.key === "Enter" && !event_0.nativeEvent.isComposing) {
3594
3574
  event_0.preventDefault();
3595
3575
  event_0.currentTarget.parentElement?.focus();
@@ -3959,6 +3939,342 @@ async function saveThemeCss(connection, css) {
3959
3939
  }
3960
3940
  }
3961
3941
  //#endregion
3942
+ //#region src/configurator/theme-versions.ts
3943
+ const themeVersionsMetaName = "povio-ui-theme-versions";
3944
+ function createThemeVersion(name, id, configuration) {
3945
+ return {
3946
+ id,
3947
+ name: name.trim() || "Theme",
3948
+ ...configuration ? { configuration: structuredClone(configuration) } : {}
3949
+ };
3950
+ }
3951
+ function createThemeVersions() {
3952
+ return {
3953
+ version: 1,
3954
+ versions: [createThemeVersion("Default", "default")],
3955
+ activeVersionId: "default"
3956
+ };
3957
+ }
3958
+ function isRecord(value) {
3959
+ return value !== null && typeof value === "object" && !Array.isArray(value);
3960
+ }
3961
+ function safeJSON(value, ancestors = /* @__PURE__ */ new Set(), depth = 0) {
3962
+ if (value === null || typeof value === "string" || typeof value === "boolean") return true;
3963
+ if (typeof value === "number") return Number.isFinite(value);
3964
+ if (typeof value !== "object" || depth > 30 || ancestors.has(value)) return false;
3965
+ if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) return false;
3966
+ ancestors.add(value);
3967
+ const valid = Object.entries(value).every(([key, child]) => ![
3968
+ "__proto__",
3969
+ "prototype",
3970
+ "constructor"
3971
+ ].includes(key) && safeJSON(child, ancestors, depth + 1));
3972
+ ancestors.delete(value);
3973
+ return valid;
3974
+ }
3975
+ const stringMap = (value) => isRecord(value) && Object.values(value).every((item) => typeof item === "string");
3976
+ const variantValue = (value) => value === null || typeof value === "string" || typeof value === "boolean";
3977
+ function validCvaEdits(value) {
3978
+ return isRecord(value) && Object.entries(value).every(([slot, definition]) => {
3979
+ if (!/^[a-zA-Z][a-zA-Z0-9]*\.[a-zA-Z][a-zA-Z0-9]*$/.test(slot) || !isRecord(definition) || !Array.isArray(definition.base) || !definition.base.every((item) => typeof item === "string") || !isRecord(definition.config)) return false;
3980
+ const config = definition.config;
3981
+ return isRecord(config.variants) && Object.values(config.variants).every(stringMap) && isRecord(config.defaultVariants) && Object.values(config.defaultVariants).every(variantValue) && Array.isArray(config.compoundVariants) && config.compoundVariants.every((compound) => isRecord(compound) && Object.values(compound).every((item) => variantValue(item) || Array.isArray(item) && (item.every((part) => typeof part === "string") || item.every((part) => typeof part === "boolean"))));
3982
+ });
3983
+ }
3984
+ /** Returns an independent JSON configuration, or undefined for invalid/unset overrides. */
3985
+ function parseUIConfiguration(value) {
3986
+ if (!isRecord(value) || !safeJSON(value) || !isRecord(value.theme) || ![
3987
+ "light",
3988
+ "dark",
3989
+ "theme"
3990
+ ].every((key) => stringMap(value.theme && value.theme[key])) || !isRecord(value.config) || value.overrides !== void 0 && !validCvaEdits(value.overrides)) return void 0;
3991
+ return JSON.parse(JSON.stringify(value));
3992
+ }
3993
+ /** Returns an independent component configuration, or undefined when invalid. */
3994
+ function parseComponentConfiguration(value) {
3995
+ if (!isRecord(value) || !safeJSON(value) || !isRecord(value.config) || value.overrides !== void 0 && !validCvaEdits(value.overrides)) return void 0;
3996
+ const copy = JSON.parse(JSON.stringify(value));
3997
+ return {
3998
+ config: copy.config ?? {},
3999
+ overrides: copy.overrides ?? {}
4000
+ };
4001
+ }
4002
+ /** Sanitize stored JSON text or a repository value. */
4003
+ function parseThemeVersions(input) {
4004
+ const fallback = createThemeVersions();
4005
+ let value = input;
4006
+ if (typeof value === "string") try {
4007
+ value = JSON.parse(value);
4008
+ } catch {
4009
+ return fallback;
4010
+ }
4011
+ if (!isRecord(value) || value.version !== 1 || !Array.isArray(value.versions)) return fallback;
4012
+ const versions = [];
4013
+ const ids = /* @__PURE__ */ new Set();
4014
+ for (const entry of value.versions) {
4015
+ if (!isRecord(entry) || typeof entry.id !== "string" || !entry.id.trim() || ids.has(entry.id)) continue;
4016
+ ids.add(entry.id);
4017
+ const configuration = parseUIConfiguration(entry.configuration);
4018
+ versions.push({
4019
+ id: entry.id,
4020
+ name: typeof entry.name === "string" && entry.name.trim() ? entry.name.trim() : "Theme",
4021
+ ...configuration ? { configuration } : {}
4022
+ });
4023
+ }
4024
+ if (!versions.length) return fallback;
4025
+ return {
4026
+ version: 1,
4027
+ versions,
4028
+ activeVersionId: typeof value.activeVersionId === "string" && versions.some((version) => version.id === value.activeVersionId) ? value.activeVersionId : versions[0].id
4029
+ };
4030
+ }
4031
+ //#endregion
4032
+ //#region src/configurator/component-configuration.ts
4033
+ const emptyComponentConfiguration = () => ({
4034
+ config: {},
4035
+ overrides: {}
4036
+ });
4037
+ /**
4038
+ * The app's applied component settings: pass the JSON written by the configurator's Apply theme
4039
+ * and the app's code-level overrides, which stay underneath the applied variant overrides.
4040
+ */
4041
+ function resolveUIConfiguration(file, baseOverrides) {
4042
+ const { config, overrides } = parseComponentConfiguration(file) ?? emptyComponentConfiguration();
4043
+ return {
4044
+ config,
4045
+ overrides: applyCvaEdits(baseOverrides, overrides)
4046
+ };
4047
+ }
4048
+ /** Key-order independent JSON without empty objects, for comparing component configurations. */
4049
+ function canonicalJSON(value) {
4050
+ const normalize = (item) => {
4051
+ if (Array.isArray(item)) return item.map(normalize);
4052
+ if (!item || typeof item !== "object") return item;
4053
+ const entries = Object.keys(item).sort().flatMap((key) => {
4054
+ const child = normalize(item[key]);
4055
+ return child === void 0 || child && typeof child === "object" && !Array.isArray(child) && !Object.keys(child).length ? [] : [[key, child]];
4056
+ });
4057
+ return Object.fromEntries(entries);
4058
+ };
4059
+ return JSON.stringify(normalize(value));
4060
+ }
4061
+ //#endregion
4062
+ //#region src/configurator/repository-storage-protocol.ts
4063
+ const componentConfigurationMetaName = "povio-ui-component-configuration";
4064
+ const repositoryStorageTokenHeader = "x-povio-ui-storage-token";
4065
+ /** Dev-server event sent when a repository storage file changes, so other tabs reload it. */
4066
+ const repositoryStorageChangedEvent = "povio-ui:repository-storage-changed";
4067
+ //#endregion
4068
+ //#region src/configurator/useRepositoryStorage.ts
4069
+ const hot = import.meta.hot;
4070
+ function connectionFromDocument(metaName) {
4071
+ if (typeof document === "undefined") return null;
4072
+ try {
4073
+ const value = JSON.parse(document.querySelector(`meta[name="${metaName}"]`)?.content ?? "null");
4074
+ return value && typeof value.endpoint === "string" && value.endpoint.startsWith("/") && !value.endpoint.startsWith("//") && typeof value.token === "string" && typeof value.file === "string" ? value : null;
4075
+ } catch {
4076
+ return null;
4077
+ }
4078
+ }
4079
+ /** Repo is authoritative when connected; local storage remains an offline draft cache. */
4080
+ function useRepositoryStorage({ key, metaName, field, parse, noun, enabled = true }) {
4081
+ const Noun = `${noun[0].toUpperCase()}${noun.slice(1)}`;
4082
+ const [connection] = useState(() => enabled ? connectionFromDocument(metaName) : null);
4083
+ const [value, setValue] = useState(() => {
4084
+ try {
4085
+ return parse(localStorage.getItem(key));
4086
+ } catch {
4087
+ return parse(null);
4088
+ }
4089
+ });
4090
+ const [ready, setReady] = useState(!connection);
4091
+ const [status, setStatus] = useState(connection ? `Loading ${noun}…` : "Saved in this browser");
4092
+ const [error, setError] = useState("");
4093
+ const latest = useRef(value);
4094
+ latest.current = value;
4095
+ const revision = useRef(null);
4096
+ const saved = useRef("");
4097
+ const busy = useRef(false);
4098
+ const paused = useRef(false);
4099
+ const alive = useRef(true);
4100
+ const loadGeneration = useRef(0);
4101
+ useEffect(() => {
4102
+ alive.current = true;
4103
+ return () => {
4104
+ alive.current = false;
4105
+ };
4106
+ }, []);
4107
+ const read = useCallback(async (quiet) => {
4108
+ if (!connection) return;
4109
+ const generation = ++loadGeneration.current;
4110
+ if (!quiet) {
4111
+ setReady(false);
4112
+ setError("");
4113
+ setStatus(`Loading ${noun}…`);
4114
+ }
4115
+ paused.current = false;
4116
+ try {
4117
+ const response = await fetch(connection.endpoint, {
4118
+ headers: { [repositoryStorageTokenHeader]: connection.token },
4119
+ cache: "no-store"
4120
+ });
4121
+ const result = await response.json();
4122
+ if (!response.ok) throw new Error(result.error ?? `Could not read ${noun} settings.`);
4123
+ if (!alive.current || generation !== loadGeneration.current) return;
4124
+ revision.current = result.revision;
4125
+ if (result[field]) {
4126
+ const next = parse(result[field]);
4127
+ saved.current = JSON.stringify(next);
4128
+ latest.current = next;
4129
+ setValue(next);
4130
+ } else saved.current = "";
4131
+ setStatus(`Saved to ${connection.file}`);
4132
+ setReady(true);
4133
+ } catch (cause) {
4134
+ if (!alive.current || generation !== loadGeneration.current) return;
4135
+ paused.current = true;
4136
+ setError(cause instanceof Error ? cause.message : "Could not load repository settings.");
4137
+ setStatus("Repository unavailable");
4138
+ setReady(true);
4139
+ }
4140
+ }, [
4141
+ connection,
4142
+ field,
4143
+ noun,
4144
+ parse
4145
+ ]);
4146
+ const load = useCallback(() => read(false), [read]);
4147
+ useEffect(() => {
4148
+ load();
4149
+ }, [load]);
4150
+ useEffect(() => {
4151
+ if (!connection || !hot) return;
4152
+ const changed = (change) => {
4153
+ if (change.endpoint !== connection.endpoint || change.revision === revision.current) return;
4154
+ if (busy.current || JSON.stringify(latest.current) !== saved.current) return;
4155
+ read(true);
4156
+ };
4157
+ hot.on(repositoryStorageChangedEvent, changed);
4158
+ return () => hot.off?.(repositoryStorageChangedEvent, changed);
4159
+ }, [connection, read]);
4160
+ const save = useCallback(async () => {
4161
+ if (!connection || busy.current || paused.current || !ready) return;
4162
+ busy.current = true;
4163
+ try {
4164
+ while (alive.current && !paused.current) {
4165
+ const current = latest.current;
4166
+ const serialized = JSON.stringify(current);
4167
+ if (serialized === saved.current) break;
4168
+ setStatus("Saving to repository…");
4169
+ const response_0 = await fetch(connection.endpoint, {
4170
+ method: "POST",
4171
+ headers: {
4172
+ "Content-Type": "application/json",
4173
+ [repositoryStorageTokenHeader]: connection.token
4174
+ },
4175
+ body: JSON.stringify({
4176
+ [field]: current,
4177
+ revision: revision.current
4178
+ })
4179
+ });
4180
+ const result_0 = await response_0.json();
4181
+ if (!response_0.ok) throw new Error(response_0.status === 409 ? `${Noun} file changed elsewhere. Export your draft, then reload repository settings.` : result_0.error ?? `Could not save ${noun} settings.`);
4182
+ revision.current = result_0.revision;
4183
+ saved.current = serialized;
4184
+ }
4185
+ if (alive.current) {
4186
+ setError("");
4187
+ setStatus(`Saved to ${connection.file}`);
4188
+ }
4189
+ } catch (cause_0) {
4190
+ paused.current = true;
4191
+ if (alive.current) {
4192
+ setError(cause_0 instanceof Error ? cause_0.message : `Could not save ${noun} settings.`);
4193
+ setStatus(`${Noun} not saved to repository`);
4194
+ }
4195
+ } finally {
4196
+ busy.current = false;
4197
+ }
4198
+ }, [
4199
+ connection,
4200
+ field,
4201
+ noun,
4202
+ Noun,
4203
+ ready
4204
+ ]);
4205
+ useEffect(() => {
4206
+ if (!ready) return;
4207
+ try {
4208
+ localStorage.setItem(key, JSON.stringify(value));
4209
+ } catch {
4210
+ if (!connection) setStatus(`Browser storage unavailable — export your ${noun}`);
4211
+ }
4212
+ if (!connection || paused.current || JSON.stringify(value) === saved.current) return;
4213
+ setStatus("Saving to repository…");
4214
+ const timer = setTimeout(() => {
4215
+ save();
4216
+ }, 350);
4217
+ return () => clearTimeout(timer);
4218
+ }, [
4219
+ value,
4220
+ key,
4221
+ connection,
4222
+ noun,
4223
+ ready,
4224
+ save
4225
+ ]);
4226
+ return {
4227
+ value,
4228
+ setValue,
4229
+ ready,
4230
+ status,
4231
+ error,
4232
+ repositoryFile: connection?.file,
4233
+ reload: load
4234
+ };
4235
+ }
4236
+ //#endregion
4237
+ //#region src/configurator/component-configuration-client.ts
4238
+ const getComponentConfigurationWriter = () => connectionFromDocument(componentConfigurationMetaName);
4239
+ async function request(writer, init) {
4240
+ const response = await fetch(writer.endpoint, {
4241
+ ...init,
4242
+ cache: "no-store",
4243
+ headers: {
4244
+ ...init?.headers,
4245
+ [repositoryStorageTokenHeader]: writer.token
4246
+ }
4247
+ });
4248
+ return {
4249
+ response,
4250
+ result: await response.json()
4251
+ };
4252
+ }
4253
+ /** The component configuration in the repository, or null when the file does not exist yet. */
4254
+ async function readComponentConfiguration(writer) {
4255
+ const { response, result } = await request(writer);
4256
+ if (!response.ok) throw new Error(result.error ?? "Could not read UI configuration.");
4257
+ return {
4258
+ configuration: result.configuration ? parseComponentConfiguration(result.configuration) ?? null : null,
4259
+ revision: result.revision
4260
+ };
4261
+ }
4262
+ /** Applying is explicit, so a file changed elsewhere is re-read and overwritten once. */
4263
+ async function saveComponentConfiguration(writer, configuration, revision) {
4264
+ const post = (current) => request(writer, {
4265
+ method: "POST",
4266
+ headers: { "Content-Type": "application/json" },
4267
+ body: JSON.stringify({
4268
+ configuration,
4269
+ revision: current
4270
+ })
4271
+ });
4272
+ let { response, result } = await post(revision);
4273
+ if (response.status === 409) ({response, result} = await post((await readComponentConfiguration(writer)).revision));
4274
+ if (!response.ok) throw new Error(result.error ?? "Could not save UI configuration.");
4275
+ return result.revision;
4276
+ }
4277
+ //#endregion
3962
4278
  //#region src/configurator/ColorModeSwitch.tsx
3963
4279
  /** Controlled color-mode switch, shared by configurators and application settings. */
3964
4280
  function ColorModeSwitch(t0) {
@@ -4032,7 +4348,7 @@ function AlphaColorField(t0) {
4032
4348
  setPercentText(null);
4033
4349
  if (Number.isFinite(entered_0)) onChange(`#${color}${toAlpha(entered_0)}`);
4034
4350
  };
4035
- const blurOnEnter = _temp$3;
4351
+ const blurOnEnter = _temp$4;
4036
4352
  const t1 = `#${color}`;
4037
4353
  let t2;
4038
4354
  if ($[0] !== t1 || $[1] !== value) {
@@ -4134,7 +4450,7 @@ function AlphaColorField(t0) {
4134
4450
  ]
4135
4451
  });
4136
4452
  }
4137
- function _temp$3(event) {
4453
+ function _temp$4(event) {
4138
4454
  if (event.key === "Enter" && !event.nativeEvent.isComposing) event.currentTarget.blur();
4139
4455
  }
4140
4456
  //#endregion
@@ -4232,7 +4548,7 @@ function PaletteSelect(t0) {
4232
4548
  } else t6 = $[14];
4233
4549
  let t7;
4234
4550
  if ($[15] !== options) {
4235
- t7 = paletteFamilies(options).map(_temp$2);
4551
+ t7 = paletteFamilies(options).map(_temp$3);
4236
4552
  $[15] = options;
4237
4553
  $[16] = t7;
4238
4554
  } else t7 = $[16];
@@ -4393,7 +4709,7 @@ function _temp2$1(t0) {
4393
4709
  })]
4394
4710
  }, name_0);
4395
4711
  }
4396
- function _temp$2(t0) {
4712
+ function _temp$3(t0) {
4397
4713
  const { family: name, steps } = t0;
4398
4714
  return /* @__PURE__ */ jsx("optgroup", {
4399
4715
  label: `Base palette / ${name}`,
@@ -4566,7 +4882,7 @@ function useLoadedFonts() {
4566
4882
  const [revision, setRevision] = useState(0);
4567
4883
  let t1;
4568
4884
  if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
4569
- t1 = () => setRevision(_temp$1);
4885
+ t1 = () => setRevision(_temp$2);
4570
4886
  $[1] = t1;
4571
4887
  } else t1 = $[1];
4572
4888
  const refresh = t1;
@@ -4615,7 +4931,7 @@ function useLoadedFonts() {
4615
4931
  function _temp2(face) {
4616
4932
  return unquote(face.family);
4617
4933
  }
4618
- function _temp$1(value) {
4934
+ function _temp$2(value) {
4619
4935
  return value + 1;
4620
4936
  }
4621
4937
  const uploadedFamilies = /* @__PURE__ */ new Set();
@@ -5247,7 +5563,7 @@ function ShadesGenerator(t0) {
5247
5563
  if ($[2] !== initial || $[3] !== steps || $[4] !== text || $[5] !== title) {
5248
5564
  const hex = text.trim().replace(/^#/, "");
5249
5565
  base = /^[0-9a-f]{6}$/i.test(hex) ? toRgb(`#${hex}`) : /^[0-9a-f]{3}$/i.test(hex) ? toRgb(`#${hex.replace(/./g, "$&$&")}`) : null;
5250
- shades = base ? generateShades(base, steps.map(_temp)) : null;
5566
+ shades = base ? generateShades(base, steps.map(_temp$1)) : null;
5251
5567
  pending = !!shades && base !== initial;
5252
5568
  t8 = "studio-shades";
5253
5569
  t9 = "group";
@@ -5418,13 +5734,13 @@ function ShadesGenerator(t0) {
5418
5734
  } else t18 = $[51];
5419
5735
  return t18;
5420
5736
  }
5421
- function _temp(t0) {
5737
+ function _temp$1(t0) {
5422
5738
  const { step } = t0;
5423
5739
  return step;
5424
5740
  }
5425
5741
  //#endregion
5426
5742
  //#region src/configurator/ComponentPreview.tsx
5427
- const ComponentGallery = lazy(() => import("./ComponentGallery-DDSqnm9f.js"));
5743
+ const ComponentGallery = lazy(() => import("./ComponentGallery-COqEqqN6.js"));
5428
5744
  /** Every component, styled by a configuration; the configurator's preview and the App Canvas Components view. */
5429
5745
  function ComponentPreview(t0) {
5430
5746
  const $ = c(14);
@@ -5484,6 +5800,543 @@ function ComponentPreview(t0) {
5484
5800
  return t8;
5485
5801
  }
5486
5802
  //#endregion
5803
+ //#region src/configurator/ThemeVersionControls.tsx
5804
+ /** Switches, creates, renames and deletes theme versions from the configurator's title row. */
5805
+ function ThemeVersionControls(t0) {
5806
+ const $ = c(84);
5807
+ const { state } = t0;
5808
+ const { themes, setThemes, active, ready, error, status } = state;
5809
+ const createTrigger = useRef(null);
5810
+ const editTrigger = useRef(null);
5811
+ const [action, setAction] = useState(null);
5812
+ const [name, setName] = useState("");
5813
+ const disabled = !ready;
5814
+ let t1;
5815
+ if ($[0] !== active.name) {
5816
+ t1 = (next) => {
5817
+ setName(next === "create" ? `${active.name} copy` : active.name);
5818
+ setAction(next);
5819
+ };
5820
+ $[0] = active.name;
5821
+ $[1] = t1;
5822
+ } else t1 = $[1];
5823
+ const open = t1;
5824
+ const title = action === "create" ? "New theme version" : action === "delete" ? "Delete theme version?" : "Edit theme version";
5825
+ let t2;
5826
+ if ($[2] !== action || $[3] !== active.configuration || $[4] !== active.id || $[5] !== disabled || $[6] !== name || $[7] !== setThemes) {
5827
+ t2 = () => {
5828
+ if (disabled || !action) return;
5829
+ if (action !== "delete" && !name.trim()) return;
5830
+ if (action === "create") {
5831
+ const created = createThemeVersion(name, crypto.randomUUID(), active.configuration);
5832
+ setThemes((current) => ({
5833
+ ...current,
5834
+ versions: [...current.versions, created],
5835
+ activeVersionId: created.id
5836
+ }));
5837
+ } else if (action === "delete") setThemes((current_0) => {
5838
+ if (current_0.versions.length < 2) return current_0;
5839
+ const remaining = current_0.versions.filter((version) => version.id !== active.id);
5840
+ return {
5841
+ ...current_0,
5842
+ versions: remaining,
5843
+ activeVersionId: remaining[0].id
5844
+ };
5845
+ });
5846
+ else setThemes((current_1) => ({
5847
+ ...current_1,
5848
+ versions: current_1.versions.map((version_0) => version_0.id === active.id ? {
5849
+ ...version_0,
5850
+ name: name.trim()
5851
+ } : version_0)
5852
+ }));
5853
+ setAction(null);
5854
+ };
5855
+ $[2] = action;
5856
+ $[3] = active.configuration;
5857
+ $[4] = active.id;
5858
+ $[5] = disabled;
5859
+ $[6] = name;
5860
+ $[7] = setThemes;
5861
+ $[8] = t2;
5862
+ } else t2 = $[8];
5863
+ const save = t2;
5864
+ let t3;
5865
+ if ($[9] !== setThemes) {
5866
+ t3 = (id) => {
5867
+ if (id !== null) setThemes((current_2) => ({
5868
+ ...current_2,
5869
+ activeVersionId: String(id)
5870
+ }));
5871
+ };
5872
+ $[9] = setThemes;
5873
+ $[10] = t3;
5874
+ } else t3 = $[10];
5875
+ let t4;
5876
+ if ($[11] === Symbol.for("react.memo_cache_sentinel")) {
5877
+ t4 = /* @__PURE__ */ jsxs($7705c033048f6da7$export$353f5b6fc5456de1, {
5878
+ className: "studio-version-trigger",
5879
+ children: [/* @__PURE__ */ jsx($c8bb816105474884$export$e288731fd71264f0, {}), /* @__PURE__ */ jsx(ChevronDown, {
5880
+ size: 12,
5881
+ "aria-hidden": "true"
5882
+ })]
5883
+ });
5884
+ $[11] = t4;
5885
+ } else t4 = $[11];
5886
+ let t5;
5887
+ if ($[12] !== themes.versions) {
5888
+ t5 = /* @__PURE__ */ jsx($542a13ca2fa5b484$export$5b6b19405a83ff9d, {
5889
+ className: "studio-version-popover",
5890
+ placement: "bottom start",
5891
+ children: /* @__PURE__ */ jsx($928221da08ecbc62$export$41f133550aa26f48, {
5892
+ className: "studio-version-list",
5893
+ items: themes.versions,
5894
+ children: _temp
5895
+ })
5896
+ });
5897
+ $[12] = themes.versions;
5898
+ $[13] = t5;
5899
+ } else t5 = $[13];
5900
+ let t6;
5901
+ if ($[14] !== active.id || $[15] !== disabled || $[16] !== t3 || $[17] !== t5) {
5902
+ t6 = /* @__PURE__ */ jsxs($c8bb816105474884$export$ef9b1a59e592288f, {
5903
+ "aria-label": "Theme version",
5904
+ className: "studio-version-select",
5905
+ selectedKey: active.id,
5906
+ isDisabled: disabled,
5907
+ onSelectionChange: t3,
5908
+ children: [t4, t5]
5909
+ });
5910
+ $[14] = active.id;
5911
+ $[15] = disabled;
5912
+ $[16] = t3;
5913
+ $[17] = t5;
5914
+ $[18] = t6;
5915
+ } else t6 = $[18];
5916
+ let t7;
5917
+ if ($[19] !== open) {
5918
+ t7 = () => open("create");
5919
+ $[19] = open;
5920
+ $[20] = t7;
5921
+ } else t7 = $[20];
5922
+ let t8;
5923
+ if ($[21] === Symbol.for("react.memo_cache_sentinel")) {
5924
+ t8 = /* @__PURE__ */ jsx(Plus, { size: 14 });
5925
+ $[21] = t8;
5926
+ } else t8 = $[21];
5927
+ let t9;
5928
+ if ($[22] !== disabled || $[23] !== t7) {
5929
+ t9 = /* @__PURE__ */ jsx("button", {
5930
+ ref: createTrigger,
5931
+ type: "button",
5932
+ className: "studio-version-action",
5933
+ "aria-label": "Add theme version",
5934
+ title: "Add theme version",
5935
+ disabled,
5936
+ onClick: t7,
5937
+ children: t8
5938
+ });
5939
+ $[22] = disabled;
5940
+ $[23] = t7;
5941
+ $[24] = t9;
5942
+ } else t9 = $[24];
5943
+ let t10;
5944
+ if ($[25] !== open) {
5945
+ t10 = () => open("rename");
5946
+ $[25] = open;
5947
+ $[26] = t10;
5948
+ } else t10 = $[26];
5949
+ let t11;
5950
+ if ($[27] === Symbol.for("react.memo_cache_sentinel")) {
5951
+ t11 = /* @__PURE__ */ jsx(Pencil, { size: 14 });
5952
+ $[27] = t11;
5953
+ } else t11 = $[27];
5954
+ let t12;
5955
+ if ($[28] !== disabled || $[29] !== t10) {
5956
+ t12 = /* @__PURE__ */ jsx("button", {
5957
+ ref: editTrigger,
5958
+ type: "button",
5959
+ className: "studio-version-action",
5960
+ "aria-label": "Edit theme version",
5961
+ title: "Edit theme version",
5962
+ disabled,
5963
+ onClick: t10,
5964
+ children: t11
5965
+ });
5966
+ $[28] = disabled;
5967
+ $[29] = t10;
5968
+ $[30] = t12;
5969
+ } else t12 = $[30];
5970
+ let t13;
5971
+ if ($[31] !== error) {
5972
+ t13 = error && /* @__PURE__ */ jsx("p", {
5973
+ className: "studio-version-error",
5974
+ role: "alert",
5975
+ children: error
5976
+ });
5977
+ $[31] = error;
5978
+ $[32] = t13;
5979
+ } else t13 = $[32];
5980
+ const t14 = action === "create" ? createTrigger : editTrigger;
5981
+ const t15 = action !== null;
5982
+ let t16;
5983
+ if ($[33] === Symbol.for("react.memo_cache_sentinel")) {
5984
+ t16 = (isOpen) => {
5985
+ if (!isOpen) setAction(null);
5986
+ };
5987
+ $[33] = t16;
5988
+ } else t16 = $[33];
5989
+ const t17 = action === "delete" ? "alertdialog" : "dialog";
5990
+ let t18;
5991
+ if ($[34] !== save) {
5992
+ t18 = (event) => {
5993
+ event.preventDefault();
5994
+ save();
5995
+ };
5996
+ $[34] = save;
5997
+ $[35] = t18;
5998
+ } else t18 = $[35];
5999
+ let t19;
6000
+ if ($[36] !== title) {
6001
+ t19 = /* @__PURE__ */ jsx($2ec61d1d4f780267$export$a8a3e93435678ff9, {
6002
+ slot: "title",
6003
+ children: title
6004
+ });
6005
+ $[36] = title;
6006
+ $[37] = t19;
6007
+ } else t19 = $[37];
6008
+ let t20;
6009
+ if ($[38] === Symbol.for("react.memo_cache_sentinel")) {
6010
+ t20 = /* @__PURE__ */ jsx("button", {
6011
+ type: "button",
6012
+ "aria-label": "Close theme version dialog",
6013
+ onClick: () => setAction(null),
6014
+ children: /* @__PURE__ */ jsx(X, { size: 12 })
6015
+ });
6016
+ $[38] = t20;
6017
+ } else t20 = $[38];
6018
+ let t21;
6019
+ if ($[39] !== t19) {
6020
+ t21 = /* @__PURE__ */ jsxs("header", {
6021
+ className: "studio-version-dialog-heading",
6022
+ children: [t19, t20]
6023
+ });
6024
+ $[39] = t19;
6025
+ $[40] = t21;
6026
+ } else t21 = $[40];
6027
+ let t22;
6028
+ if ($[41] !== action || $[42] !== active.name || $[43] !== name) {
6029
+ t22 = action === "delete" ? /* @__PURE__ */ jsxs("p", { children: [
6030
+ "Delete “",
6031
+ active.name,
6032
+ "” and its saved theme?"
6033
+ ] }) : /* @__PURE__ */ jsxs("label", { children: ["Version name", /* @__PURE__ */ jsx("input", {
6034
+ autoFocus: true,
6035
+ value: name,
6036
+ maxLength: 80,
6037
+ placeholder: "Version name",
6038
+ onChange: (event_0) => setName(event_0.target.value),
6039
+ required: true
6040
+ })] });
6041
+ $[41] = action;
6042
+ $[42] = active.name;
6043
+ $[43] = name;
6044
+ $[44] = t22;
6045
+ } else t22 = $[44];
6046
+ let t23;
6047
+ if ($[45] !== action || $[46] !== active.name) {
6048
+ t23 = action === "create" && /* @__PURE__ */ jsxs("p", {
6049
+ className: "studio-version-hint",
6050
+ children: [
6051
+ "Starts as a copy of “",
6052
+ active.name,
6053
+ "”."
6054
+ ]
6055
+ });
6056
+ $[45] = action;
6057
+ $[46] = active.name;
6058
+ $[47] = t23;
6059
+ } else t23 = $[47];
6060
+ let t24;
6061
+ if ($[48] !== action || $[49] !== themes.versions) {
6062
+ t24 = action === "rename" ? /* @__PURE__ */ jsxs("button", {
6063
+ type: "button",
6064
+ className: "studio-version-delete",
6065
+ disabled: themes.versions.length < 2,
6066
+ onClick: () => setAction("delete"),
6067
+ children: [/* @__PURE__ */ jsx(Trash, { size: 12 }), " Delete version"]
6068
+ }) : /* @__PURE__ */ jsx("button", {
6069
+ type: "button",
6070
+ autoFocus: action === "delete",
6071
+ onClick: () => action === "delete" ? setAction("rename") : setAction(null),
6072
+ children: action === "delete" ? "Back" : "Cancel"
6073
+ });
6074
+ $[48] = action;
6075
+ $[49] = themes.versions;
6076
+ $[50] = t24;
6077
+ } else t24 = $[50];
6078
+ const t25 = action === "delete" ? "is-danger" : "is-primary";
6079
+ let t26;
6080
+ if ($[51] !== action || $[52] !== disabled || $[53] !== name) {
6081
+ t26 = disabled || action !== "delete" && !name.trim();
6082
+ $[51] = action;
6083
+ $[52] = disabled;
6084
+ $[53] = name;
6085
+ $[54] = t26;
6086
+ } else t26 = $[54];
6087
+ const t27 = action === "create" ? "Create version" : action === "delete" ? "Delete" : "Save";
6088
+ let t28;
6089
+ if ($[55] !== t25 || $[56] !== t26 || $[57] !== t27) {
6090
+ t28 = /* @__PURE__ */ jsx("button", {
6091
+ type: "submit",
6092
+ className: t25,
6093
+ disabled: t26,
6094
+ children: t27
6095
+ });
6096
+ $[55] = t25;
6097
+ $[56] = t26;
6098
+ $[57] = t27;
6099
+ $[58] = t28;
6100
+ } else t28 = $[58];
6101
+ let t29;
6102
+ if ($[59] !== t24 || $[60] !== t28) {
6103
+ t29 = /* @__PURE__ */ jsxs("div", {
6104
+ className: "studio-version-dialog-actions",
6105
+ children: [t24, t28]
6106
+ });
6107
+ $[59] = t24;
6108
+ $[60] = t28;
6109
+ $[61] = t29;
6110
+ } else t29 = $[61];
6111
+ let t30;
6112
+ if ($[62] !== t18 || $[63] !== t21 || $[64] !== t22 || $[65] !== t23 || $[66] !== t29) {
6113
+ t30 = /* @__PURE__ */ jsxs("form", {
6114
+ onSubmit: t18,
6115
+ children: [
6116
+ t21,
6117
+ t22,
6118
+ t23,
6119
+ t29
6120
+ ]
6121
+ });
6122
+ $[62] = t18;
6123
+ $[63] = t21;
6124
+ $[64] = t22;
6125
+ $[65] = t23;
6126
+ $[66] = t29;
6127
+ $[67] = t30;
6128
+ } else t30 = $[67];
6129
+ let t31;
6130
+ if ($[68] !== action || $[69] !== t17 || $[70] !== t30 || $[71] !== title) {
6131
+ t31 = /* @__PURE__ */ jsx($f2ff30fde7b014be$export$3ddf2d174ce01153, {
6132
+ "aria-label": title,
6133
+ role: t17,
6134
+ children: t30
6135
+ }, action);
6136
+ $[68] = action;
6137
+ $[69] = t17;
6138
+ $[70] = t30;
6139
+ $[71] = title;
6140
+ $[72] = t31;
6141
+ } else t31 = $[72];
6142
+ let t32;
6143
+ if ($[73] !== t14 || $[74] !== t15 || $[75] !== t31) {
6144
+ t32 = /* @__PURE__ */ jsx($542a13ca2fa5b484$export$5b6b19405a83ff9d, {
6145
+ triggerRef: t14,
6146
+ placement: "bottom start",
6147
+ offset: 6,
6148
+ className: "studio-version-popover studio-version-dialog",
6149
+ isOpen: t15,
6150
+ onOpenChange: t16,
6151
+ children: t31
6152
+ });
6153
+ $[73] = t14;
6154
+ $[74] = t15;
6155
+ $[75] = t31;
6156
+ $[76] = t32;
6157
+ } else t32 = $[76];
6158
+ let t33;
6159
+ if ($[77] !== status || $[78] !== t12 || $[79] !== t13 || $[80] !== t32 || $[81] !== t6 || $[82] !== t9) {
6160
+ t33 = /* @__PURE__ */ jsxs("div", {
6161
+ className: "studio-version-picker",
6162
+ title: status,
6163
+ children: [
6164
+ t6,
6165
+ t9,
6166
+ t12,
6167
+ t13,
6168
+ t32
6169
+ ]
6170
+ });
6171
+ $[77] = status;
6172
+ $[78] = t12;
6173
+ $[79] = t13;
6174
+ $[80] = t32;
6175
+ $[81] = t6;
6176
+ $[82] = t9;
6177
+ $[83] = t33;
6178
+ } else t33 = $[83];
6179
+ return t33;
6180
+ }
6181
+ function _temp(version_1) {
6182
+ return /* @__PURE__ */ jsx($928221da08ecbc62$export$a11e76429ed99b4, {
6183
+ id: version_1.id,
6184
+ textValue: version_1.name,
6185
+ className: "studio-version-item",
6186
+ children: version_1.name
6187
+ });
6188
+ }
6189
+ //#endregion
6190
+ //#region src/configurator/useThemeVersions.ts
6191
+ /** The editor only needs differences from the repository base theme. */
6192
+ function withoutDefaults(value, defaults) {
6193
+ const differing = (mode) => Object.fromEntries(Object.entries(value.theme[mode]).filter(([name, item]) => item !== defaults[mode][name]));
6194
+ return {
6195
+ ...value,
6196
+ theme: {
6197
+ light: differing("light"),
6198
+ dark: differing("dark"),
6199
+ theme: differing("theme")
6200
+ }
6201
+ };
6202
+ }
6203
+ /**
6204
+ * Named theme versions kept in `povio.themes.json` (or this browser when no writer is connected).
6205
+ * Loads the active version into the configuration and records every edit back into it.
6206
+ */
6207
+ function useThemeVersions(t0) {
6208
+ const $ = c(26);
6209
+ const enabled = t0 === void 0 ? true : t0;
6210
+ let t1;
6211
+ if ($[0] !== enabled) {
6212
+ t1 = {
6213
+ key: "povio-ui-theme-versions",
6214
+ metaName: themeVersionsMetaName,
6215
+ field: "themes",
6216
+ parse: parseThemeVersions,
6217
+ noun: "theme versions",
6218
+ enabled
6219
+ };
6220
+ $[0] = enabled;
6221
+ $[1] = t1;
6222
+ } else t1 = $[1];
6223
+ const storage = useRepositoryStorage(t1);
6224
+ const { value: themes, setValue: setThemes, ready } = storage;
6225
+ let t2;
6226
+ if ($[2] !== themes.activeVersionId || $[3] !== themes.versions) {
6227
+ t2 = themes.versions.find((version) => version.id === themes.activeVersionId) ?? themes.versions[0];
6228
+ $[2] = themes.activeVersionId;
6229
+ $[3] = themes.versions;
6230
+ $[4] = t2;
6231
+ } else t2 = $[4];
6232
+ const active = t2;
6233
+ const { currentConfiguration, replaceConfiguration, defaults } = useUIConfiguration();
6234
+ const loaded = useRef(null);
6235
+ const t3 = active.id;
6236
+ let t4;
6237
+ if ($[5] !== defaults) {
6238
+ t4 = JSON.stringify(defaults);
6239
+ $[5] = defaults;
6240
+ $[6] = t4;
6241
+ } else t4 = $[6];
6242
+ const key = `${t3}:${t4}`;
6243
+ let t5;
6244
+ if ($[7] !== active.configuration) {
6245
+ t5 = JSON.stringify(active.configuration);
6246
+ $[7] = active.configuration;
6247
+ $[8] = t5;
6248
+ } else t5 = $[8];
6249
+ const saved = t5;
6250
+ let t6;
6251
+ let t7;
6252
+ if ($[9] !== active.configuration || $[10] !== active.id || $[11] !== currentConfiguration || $[12] !== defaults || $[13] !== enabled || $[14] !== key || $[15] !== ready || $[16] !== replaceConfiguration || $[17] !== saved || $[18] !== setThemes) {
6253
+ t6 = () => {
6254
+ if (!enabled || !ready) return;
6255
+ if (!loaded.current || loaded.current.key !== key || loaded.current.saved !== saved) {
6256
+ const value = active.configuration ?? (loaded.current ? emptyConfiguration() : currentConfiguration);
6257
+ const sameValues = !!loaded.current && loaded.current.versionId === active.id && loaded.current.saved === saved;
6258
+ loaded.current = {
6259
+ key,
6260
+ versionId: active.id,
6261
+ saved
6262
+ };
6263
+ replaceConfiguration(withoutDefaults(value, defaults), false, !sameValues);
6264
+ return;
6265
+ }
6266
+ const snapshot = {
6267
+ ...currentConfiguration,
6268
+ theme: {
6269
+ light: {
6270
+ ...defaults.light,
6271
+ ...currentConfiguration.theme.light
6272
+ },
6273
+ dark: {
6274
+ ...defaults.dark,
6275
+ ...currentConfiguration.theme.dark
6276
+ },
6277
+ theme: {
6278
+ ...defaults.theme,
6279
+ ...currentConfiguration.theme.theme
6280
+ }
6281
+ }
6282
+ };
6283
+ const serialized = JSON.stringify(snapshot);
6284
+ if (serialized === saved) return;
6285
+ loaded.current.saved = serialized;
6286
+ setThemes((current) => ({
6287
+ ...current,
6288
+ versions: current.versions.map((version_0) => version_0.id === active.id ? {
6289
+ ...version_0,
6290
+ configuration: structuredClone(snapshot)
6291
+ } : version_0)
6292
+ }));
6293
+ };
6294
+ t7 = [
6295
+ enabled,
6296
+ ready,
6297
+ key,
6298
+ saved,
6299
+ active.id,
6300
+ active.configuration,
6301
+ defaults,
6302
+ currentConfiguration,
6303
+ replaceConfiguration,
6304
+ setThemes
6305
+ ];
6306
+ $[9] = active.configuration;
6307
+ $[10] = active.id;
6308
+ $[11] = currentConfiguration;
6309
+ $[12] = defaults;
6310
+ $[13] = enabled;
6311
+ $[14] = key;
6312
+ $[15] = ready;
6313
+ $[16] = replaceConfiguration;
6314
+ $[17] = saved;
6315
+ $[18] = setThemes;
6316
+ $[19] = t6;
6317
+ $[20] = t7;
6318
+ } else {
6319
+ t6 = $[19];
6320
+ t7 = $[20];
6321
+ }
6322
+ useLayoutEffect(t6, t7);
6323
+ let t8;
6324
+ if ($[21] !== active || $[22] !== setThemes || $[23] !== storage || $[24] !== themes) {
6325
+ t8 = {
6326
+ ...storage,
6327
+ themes,
6328
+ setThemes,
6329
+ active
6330
+ };
6331
+ $[21] = active;
6332
+ $[22] = setThemes;
6333
+ $[23] = storage;
6334
+ $[24] = themes;
6335
+ $[25] = t8;
6336
+ } else t8 = $[25];
6337
+ return t8;
6338
+ }
6339
+ //#endregion
5487
6340
  //#region src/configurator/UIConfigurator.tsx
5488
6341
  const colorNamespaces = {
5489
6342
  surface: "Surfaces",
@@ -5769,22 +6622,36 @@ function TokenField({ name, value, original, changed, onChange, onReset, onValid
5769
6622
  });
5770
6623
  }
5771
6624
  function PopoutOverlay(t0) {
5772
- const $ = c(3);
5773
- const { children, className } = t0;
6625
+ const $ = c(6);
6626
+ const { children, className, onOpenChange } = t0;
5774
6627
  const t1 = className ?? "studio-overlay";
5775
6628
  let t2;
5776
- if ($[0] !== children || $[1] !== t1) {
5777
- t2 = /* @__PURE__ */ jsx("div", {
6629
+ if ($[0] !== onOpenChange) {
6630
+ t2 = (event) => {
6631
+ if (event.key === "Escape" && !event.defaultPrevented) {
6632
+ event.preventDefault();
6633
+ event.stopPropagation();
6634
+ onOpenChange?.(false);
6635
+ }
6636
+ };
6637
+ $[0] = onOpenChange;
6638
+ $[1] = t2;
6639
+ } else t2 = $[1];
6640
+ let t3;
6641
+ if ($[2] !== children || $[3] !== t1 || $[4] !== t2) {
6642
+ t3 = /* @__PURE__ */ jsx("div", {
5778
6643
  className: t1,
6644
+ onKeyDown: t2,
5779
6645
  children
5780
6646
  });
5781
- $[0] = children;
5782
- $[1] = t1;
5783
- $[2] = t2;
5784
- } else t2 = $[2];
5785
- return t2;
6647
+ $[2] = children;
6648
+ $[3] = t1;
6649
+ $[4] = t2;
6650
+ $[5] = t3;
6651
+ } else t3 = $[5];
6652
+ return t3;
5786
6653
  }
5787
- function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating, onPopout, onDock, onMinimize, popupBlocked }) {
6654
+ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating, onPopout, onDock, popupBlocked, themeVersions }) {
5788
6655
  const Overlay = poppedOut || floating ? PopoutOverlay : $8b8d26808cb8cb53$export$8948f78d83984c69;
5789
6656
  const Surface = poppedOut || floating ? "div" : $8b8d26808cb8cb53$export$2b77a92f1a5ad772;
5790
6657
  const studioWindow = useStudioWindow(windowBounds, !poppedOut);
@@ -5799,7 +6666,7 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
5799
6666
  return () => observer.disconnect();
5800
6667
  }, [studioWindow.ref]);
5801
6668
  const inherited = UIConfig.useConfig();
5802
- const { defaults, draft, setDraft, isOpen, cancel, apply, revision, tokenRequest, clearTokenRequest, componentsHosted } = useUIConfiguration();
6669
+ const { defaults, draft, setDraft, isOpen, apply, revision, tokenRequest, clearTokenRequest, componentsHosted } = useUIConfiguration();
5803
6670
  const remembered = memory.current;
5804
6671
  const [mode, setMode] = useState(remembered.mode ?? "light");
5805
6672
  const [sizeUnit, setSizeUnit] = useState(remembered.sizeUnit ?? "px");
@@ -5831,6 +6698,23 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
5831
6698
  useEffect(() => {
5832
6699
  setThemeWriter(getThemeWriter());
5833
6700
  }, []);
6701
+ const [componentWriter, setComponentWriter] = useState(null);
6702
+ const [repositoryComponents, setRepositoryComponents] = useState(null);
6703
+ useEffect(() => {
6704
+ const writer = getComponentConfigurationWriter();
6705
+ setComponentWriter(writer);
6706
+ if (!writer) return;
6707
+ let alive = true;
6708
+ readComponentConfiguration(writer).then(({ configuration, revision: revision_0 }) => {
6709
+ if (alive) setRepositoryComponents({
6710
+ json: canonicalJSON(configuration ?? emptyComponentConfiguration()),
6711
+ revision: revision_0
6712
+ });
6713
+ }).catch(() => {});
6714
+ return () => {
6715
+ alive = false;
6716
+ };
6717
+ }, []);
5834
6718
  const [exportTab, setExportTab] = useState(remembered.exportTab ?? "css");
5835
6719
  const editorRef = useRef(null);
5836
6720
  const previewRef = useRef(null);
@@ -5868,6 +6752,18 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
5868
6752
  const exportRef = useRef(null);
5869
6753
  const changedCount = Object.keys(draft.overrides ?? {}).length + Object.values(draft.theme).reduce((count, tokens) => count + Object.keys(tokens).length, 0) + Object.values(draft.config).reduce((count_0, value) => count_0 + (typeof value === "object" && value !== null ? Object.keys(value).length : 1), 0);
5870
6754
  const config = inherited;
6755
+ const components = {
6756
+ config: draft.config,
6757
+ overrides: draft.overrides ?? {}
6758
+ };
6759
+ const componentsJson = canonicalJSON(components);
6760
+ const componentsDiffer = !!componentWriter && !!repositoryComponents && componentsJson !== repositoryComponents.json;
6761
+ const themeCss = exportCss(draft.theme, defaults);
6762
+ const themeDiffers = [
6763
+ "light",
6764
+ "dark",
6765
+ "theme"
6766
+ ].some((mode_0) => Object.keys(parseThemeCss(themeCss)[mode_0]).length > 0);
5871
6767
  const exportText = exportTab === "css" ? exportCss(draft.theme, defaults) : exportTab === "overrides" ? exportCvaEdits(draft.overrides) : `import { UIConfig } from "@povio/ui/ui-config";\n\nconst config = ${JSON.stringify(draft.config, null, 2)} satisfies Partial<UIConfig.Options>;\n\n// Wrap your application:\n// <UIConfig.Provider config={config}>{children}</UIConfig.Provider>\n`;
5872
6768
  const changeSection = (next) => {
5873
6769
  if (compactPreview && bodyRef.current?.parentElement) bodyRef.current.parentElement.scrollTop = 0;
@@ -5991,7 +6887,7 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
5991
6887
  }));
5992
6888
  setInvalidFields({});
5993
6889
  setResetRevision((value_5) => value_5 + 1);
5994
- setMessage(`${preset.label} preset applied. Apply settings to keep it.`);
6890
+ setMessage(`${preset.label} preset applied. Changes stay in this session.`);
5995
6891
  };
5996
6892
  const setComponent = (key_0, field, value_6) => {
5997
6893
  setDraft((current_9) => ({
@@ -6200,7 +7096,7 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
6200
7096
  })] }, key_12);
6201
7097
  const showTabs = sectionTabList.length > 1 && isTokenSection(section);
6202
7098
  const overrideCount = `${changedCount} ${changedCount === 1 ? "override" : "overrides"}`;
6203
- const footerStatus = Object.keys(invalidFields).length ? "Fix invalid values or reset before applying or exporting." : nothingToReset && !changedCount ? "No active changes to reset." : (popupBlocked ? "Allow pop-ups for this site, then try again." : message) || overrideCount;
7099
+ const footerStatus = Object.keys(invalidFields).length ? "Fix invalid values or reset before exporting." : nothingToReset && !changedCount ? "No active changes to reset." : (popupBlocked ? "Allow pop-ups for this site, then try again." : message) || overrideCount;
6204
7100
  const toggleAllButton = isTokenSection(section) && !flatTab && collapsibleKeys.length > 1 && /* @__PURE__ */ jsxs("button", {
6205
7101
  type: "button",
6206
7102
  className: "studio-toggle-all",
@@ -6224,7 +7120,7 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
6224
7120
  className: `studio-overlay${floating && !poppedOut ? " studio-overlay-floating" : ""}`,
6225
7121
  isOpen,
6226
7122
  onOpenChange: (next_2) => {
6227
- if (!next_2) cancel();
7123
+ if (!next_2) apply();
6228
7124
  },
6229
7125
  isDismissable: false,
6230
7126
  children: /* @__PURE__ */ jsx(Surface, {
@@ -6239,18 +7135,18 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
6239
7135
  /* @__PURE__ */ jsxs("header", {
6240
7136
  className: "studio-topbar",
6241
7137
  ...poppedOut ? {} : studioWindow.dragArea,
6242
- children: [
6243
- /* @__PURE__ */ jsx("div", {
6244
- className: "studio-title",
6245
- children: /* @__PURE__ */ jsx($2ec61d1d4f780267$export$a8a3e93435678ff9, {
6246
- slot: "title",
6247
- children: "Povio UI Configuration"
6248
- })
6249
- }),
6250
- /* @__PURE__ */ jsxs("nav", {
6251
- className: "studio-nav",
6252
- "aria-label": "Configuration sections",
6253
- children: [/* @__PURE__ */ jsxs("div", {
7138
+ children: [/* @__PURE__ */ jsxs("div", {
7139
+ className: "studio-title",
7140
+ children: [/* @__PURE__ */ jsx($2ec61d1d4f780267$export$a8a3e93435678ff9, {
7141
+ slot: "title",
7142
+ className: "studio-visually-hidden",
7143
+ children: "Povio UI Configuration"
7144
+ }), /* @__PURE__ */ jsx(ThemeVersionControls, { state: themeVersions })]
7145
+ }), /* @__PURE__ */ jsxs("nav", {
7146
+ className: "studio-nav",
7147
+ "aria-label": "Configuration sections",
7148
+ children: [
7149
+ /* @__PURE__ */ jsxs("div", {
6254
7150
  className: "studio-section-tabs",
6255
7151
  children: [
6256
7152
  navSections.map((group_5) => /* @__PURE__ */ jsx("button", {
@@ -6268,7 +7164,8 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
6268
7164
  children: "Advanced"
6269
7165
  })
6270
7166
  ]
6271
- }), !componentsHosted && /* @__PURE__ */ jsx("button", {
7167
+ }),
7168
+ !componentsHosted && /* @__PURE__ */ jsx("button", {
6272
7169
  type: "button",
6273
7170
  className: "studio-preview-tab",
6274
7171
  "aria-current": compactPreview ? "page" : void 0,
@@ -6278,11 +7175,8 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
6278
7175
  if (dialog) dialog.scrollTop = 0;
6279
7176
  },
6280
7177
  children: "Components"
6281
- })]
6282
- }),
6283
- /* @__PURE__ */ jsx("div", {
6284
- className: "studio-topbar-controls",
6285
- children: /* @__PURE__ */ jsxs("label", {
7178
+ }),
7179
+ /* @__PURE__ */ jsxs("label", {
6286
7180
  className: "studio-search",
6287
7181
  title: "Search tokens",
6288
7182
  children: [
@@ -6309,8 +7203,8 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
6309
7203
  })
6310
7204
  ]
6311
7205
  })
6312
- })
6313
- ]
7206
+ ]
7207
+ })]
6314
7208
  }),
6315
7209
  /* @__PURE__ */ jsxs("div", {
6316
7210
  ref: bodyRef,
@@ -6440,7 +7334,7 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
6440
7334
  className: "studio-presets",
6441
7335
  children: [/* @__PURE__ */ jsx("p", {
6442
7336
  className: "studio-presets-intro",
6443
- children: "A preset replaces your theme edits with its own. Component defaults and overrides stay as they are; Apply or Save theme keeps it, Cancel discards it."
7337
+ children: "A preset replaces your theme edits with its own. Component defaults and overrides stay as they are; Changes stay in this session. Save theme writes CSS settings to the repository."
6444
7338
  }), [appThemePreset, ...themePresets].map((preset_0) => {
6445
7339
  const active = isPresetActive(preset_0, defaults, draft.theme);
6446
7340
  const colors = presetEdits(preset_0, defaults).light;
@@ -6724,27 +7618,44 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
6724
7618
  children: footerStatus
6725
7619
  }),
6726
7620
  /* @__PURE__ */ jsx("button", {
6727
- onClick: () => cancel(),
6728
- children: "Cancel"
6729
- }),
6730
- /* @__PURE__ */ jsxs("button", {
6731
7621
  className: "studio-primary",
6732
- "aria-label": "Apply settings",
6733
- disabled: !!Object.keys(invalidFields).length,
6734
- onClick: () => {
6735
- apply();
7622
+ disabled: !(themeWriter && themeDiffers || componentsDiffer) || savingTheme || !!Object.keys(invalidFields).length,
7623
+ title: !themeWriter && !componentWriter ? "Applying needs the uiConfigurator Vite plugin" : themeWriter && themeDiffers || componentsDiffer ? `Write this version to ${[themeWriter && themeDiffers && themeWriter.file, componentsDiffer && componentWriter?.file].filter(Boolean).join(" and ")}` : "The repository already matches this version",
7624
+ onClick: async () => {
7625
+ setSavingTheme(true);
7626
+ setMessage("");
7627
+ const written = [];
7628
+ try {
7629
+ if (themeWriter && themeDiffers) {
7630
+ await saveThemeCss(themeWriter, themeCss);
7631
+ written.push(themeWriter.file);
7632
+ }
7633
+ if (componentsDiffer && componentWriter && repositoryComponents) {
7634
+ const revision_1 = await saveComponentConfiguration(componentWriter, components, repositoryComponents.revision);
7635
+ setRepositoryComponents({
7636
+ json: componentsJson,
7637
+ revision: revision_1
7638
+ });
7639
+ written.push(componentWriter.file);
7640
+ }
7641
+ setMessage(`Applied to ${written.join(" and ")}.`);
7642
+ } catch (error_0) {
7643
+ setMessage(error_0 instanceof Error ? error_0.message : "Could not apply theme.");
7644
+ } finally {
7645
+ setSavingTheme(false);
7646
+ }
6736
7647
  },
6737
- children: [/* @__PURE__ */ jsx(Check, { size: 14 }), " Apply"]
7648
+ children: savingTheme ? "Applying…" : "Apply theme"
6738
7649
  })
6739
7650
  ]
6740
7651
  }),
6741
7652
  /* @__PURE__ */ jsx("button", {
6742
7653
  type: "button",
6743
- className: "studio-window-minimize",
6744
- "aria-label": "Minimize UI configuration",
6745
- title: "Minimize to floating button",
6746
- onClick: onMinimize,
6747
- children: /* @__PURE__ */ jsx(Minus, { size: 17 })
7654
+ className: "studio-window-close",
7655
+ "aria-label": "Close UI configuration",
7656
+ title: "Close",
7657
+ onClick: apply,
7658
+ children: /* @__PURE__ */ jsx(X, { size: 17 })
6748
7659
  }),
6749
7660
  /* @__PURE__ */ jsx("button", {
6750
7661
  type: "button",
@@ -6759,8 +7670,7 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
6759
7670
  className: "studio-window-grip",
6760
7671
  "aria-label": "Move UI configuration",
6761
7672
  title: "Drag to move, or use arrow keys",
6762
- ...studioWindow.move,
6763
- children: /* @__PURE__ */ jsx(GripVertical, { size: 20 })
7673
+ ...studioWindow.move
6764
7674
  }), windowEdges.map((edge) => /* @__PURE__ */ jsx("button", {
6765
7675
  type: "button",
6766
7676
  className: `studio-window-resize studio-window-resize-${edge}`,
@@ -6821,12 +7731,8 @@ const floatingDefault = {
6821
7731
  };
6822
7732
  const hostedFloatingWidth = 360;
6823
7733
  function UIConfigurationModal() {
6824
- const { isOpen, revision, open, openFloating, floating, componentsHosted } = useUIConfiguration();
6825
- const [minimized, setMinimized] = useState(false);
6826
- const [hasLauncher, setHasLauncher] = useState(false);
6827
- const restorePopout = useRef(false);
6828
- const launcherPosition = useRef(null);
6829
- useEffect(() => setMinimized(false), [revision]);
7734
+ const { isOpen, revision, floating, componentsHosted } = useUIConfiguration();
7735
+ const themeVersions = useThemeVersions();
6830
7736
  const memory = useRef({});
6831
7737
  const windowBounds = useRef(null);
6832
7738
  const floatingBounds = useRef(floatingDefault);
@@ -6834,39 +7740,17 @@ function UIConfigurationModal() {
6834
7740
  ...floatingDefault,
6835
7741
  width: hostedFloatingWidth
6836
7742
  };
6837
- const popout = useStudioPopout(isOpen && !minimized);
6838
- if ((!isOpen || minimized) && hasLauncher) return createPortal(/* @__PURE__ */ jsx(ConfigurationLauncher, {
6839
- position: launcherPosition,
6840
- onOpen: () => {
6841
- setMinimized(false);
6842
- if (!isOpen) {
6843
- if (floating) openFloating();
6844
- else open();
6845
- }
6846
- if (restorePopout.current) popout.open();
6847
- }
6848
- }), document.body);
7743
+ const popout = useStudioPopout(isOpen);
6849
7744
  if (!isOpen) return null;
6850
7745
  const content = /* @__PURE__ */ jsx(ConfigurationModalContent, {
6851
7746
  memory,
6852
7747
  windowBounds: floating ? floatingBounds : windowBounds,
6853
7748
  floating,
6854
7749
  poppedOut: !!popout.popup,
6855
- onPopout: () => {
6856
- restorePopout.current = true;
6857
- popout.open();
6858
- },
6859
- onDock: () => {
6860
- restorePopout.current = false;
6861
- popout.dock();
6862
- },
6863
- onMinimize: () => {
6864
- restorePopout.current = !!popout.popup;
6865
- setHasLauncher(true);
6866
- setMinimized(true);
6867
- popout.dock();
6868
- },
6869
- popupBlocked: popout.blocked
7750
+ onPopout: popout.open,
7751
+ onDock: popout.dock,
7752
+ popupBlocked: popout.blocked,
7753
+ themeVersions
6870
7754
  }, revision);
6871
7755
  return popout.popup ? createPortal(/* @__PURE__ */ jsx(StudioPopoutContext, {
6872
7756
  value: true,
@@ -6877,4 +7761,4 @@ function UIConfigurationModal() {
6877
7761
  }), popout.popup.document.body) : floating ? createPortal(content, document.body) : content;
6878
7762
  }
6879
7763
  //#endregion
6880
- export { getBoxHighlights as a, UIConfigurationProvider as c, Pin as d, Moon as f, inspectTokens as i, useUIConfiguration as l, ColorModeSwitch as n, HighlightOverlay as o, inspectElement as r, InspectorDetails as s, UIConfigurationModal as t, Sun as u };
7764
+ export { Moon as _, inspectElement as a, HighlightOverlay as c, useUIConfiguration as d, Trash as f, Pencil as g, Pin as h, resolveUIConfiguration as i, InspectorDetails as l, Plus as m, ColorModeSwitch as n, inspectTokens as o, Sun as p, useRepositoryStorage as r, getBoxHighlights as s, UIConfigurationModal as t, UIConfigurationProvider as u };