@povio/ui 5.0.0-rc.4 → 5.0.0-rc.6

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.
@@ -3,6 +3,7 @@ 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";
6
7
  import { t as Info } from "../info-iUmX3uDk.js";
7
8
  import { a as checkboxDefinition, i as checkboxContentWrapperDefinition, o as checkboxGroupLabelDefinition, r as checkboxContentRowDefinition, s as checkboxIconDefinition, u as Minus } from "../CheckboxCheckmark-CpC3wlMs.js";
8
9
  import { i as Search, n as selectListBoxItemDefinition, r as selectInputTagsContentWrapperDefinition, t as selectPopoverDefinition } from "../selectDesktop.cva-CHAMxhfO.js";
@@ -44,7 +45,6 @@ import { a as stepperSeparatorDefinition, i as stepperNumberDefinition, n as ste
44
45
  import { i as dialogOverlayDefinition, n as dialogMainDefinition, t as dialogContentDefinition } from "../dialog.cva-COhDZaVl.js";
45
46
  import { i as alertDefinition, n as statusIconDefinition, r as statusSeparatorDefinition, t as Alert } from "../Alert-CnvEb1D_.js";
46
47
  import { a as toastDefinition, i as toastContainerDefinition } from "../toast.cva-C_L_RffH.js";
47
- 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";
48
48
  import { t as linkDefinition } from "../link.cva-DMTHZiJG.js";
49
49
  import { t as tooltipWrapperTriggerDefinition } from "../tooltipWrapper.cva-BBQ4ic3D.js";
50
50
  import { C as validToken, S as toRgb, _ as parseThemeCss, a as generateShades, b as spacingLevels, c as isFontSizeToken, d as layoutKindFor, f as layoutKinds, g as listedLayoutToken, h as linkedLayoutTokens, i as exportCss, l as isRgb, m as layoutScales, n as controlHeightCounterpart, o as groupFor, p as layoutLevelFor, r as emptyTheme, s as groups, t as baseColorNames, u as labelFor, v as previewTokens, x as toHex, y as runtimeCss } from "../theme-model-DtYPxNvH.js";
@@ -56,10 +56,12 @@ import { CollectionBuilder } from "react-aria/CollectionBuilder";
56
56
  import { filterDOMProps } from "react-aria/filterDOMProps";
57
57
  import { useFocusRing } from "react-aria/useFocusRing";
58
58
  import { createHideableComponent } from "react-aria/private/collections/Hidden";
59
+ import { createPortal } from "react-dom";
59
60
  import "react-aria/useLocalizedStringFormatter";
60
61
  import "react-aria/useListFormatter";
61
62
  import { HiddenSelect, useSelect } from "react-aria/useSelect";
62
63
  import { useSelectState } from "react-stately/useSelectState";
64
+ import { UNSAFE_PortalProvider } from "react-aria";
63
65
  //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/arrow-down-to-line.mjs
64
66
  /**
65
67
  * @license lucide-react v1.43.0 - ISC
@@ -67,7 +69,7 @@ import { useSelectState } from "react-stately/useSelectState";
67
69
  * This source code is licensed under the ISC license.
68
70
  * See the LICENSE file in the root directory of this source tree.
69
71
  */
70
- const __iconData$5 = {
72
+ const __iconData$8 = {
71
73
  name: "arrow-down-to-line",
72
74
  size: 24,
73
75
  node: [
@@ -85,8 +87,8 @@ const __iconData$5 = {
85
87
  }]
86
88
  ]
87
89
  };
88
- __iconData$5.node;
89
- const ArrowDownToLine = createLucideIcon(__iconData$5);
90
+ __iconData$8.node;
91
+ const ArrowDownToLine = createLucideIcon(__iconData$8);
90
92
  //#endregion
91
93
  //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/chevrons-up-down.mjs
92
94
  /**
@@ -95,7 +97,7 @@ const ArrowDownToLine = createLucideIcon(__iconData$5);
95
97
  * This source code is licensed under the ISC license.
96
98
  * See the LICENSE file in the root directory of this source tree.
97
99
  */
98
- const __iconData$4 = {
100
+ const __iconData$7 = {
99
101
  name: "chevrons-up-down",
100
102
  size: 24,
101
103
  node: [["path", {
@@ -106,8 +108,36 @@ const __iconData$4 = {
106
108
  key: "sgt6xg"
107
109
  }]]
108
110
  };
109
- __iconData$4.node;
110
- const ChevronsUpDown = createLucideIcon(__iconData$4);
111
+ __iconData$7.node;
112
+ const ChevronsUpDown = createLucideIcon(__iconData$7);
113
+ //#endregion
114
+ //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/external-link.mjs
115
+ /**
116
+ * @license lucide-react v1.43.0 - ISC
117
+ *
118
+ * This source code is licensed under the ISC license.
119
+ * See the LICENSE file in the root directory of this source tree.
120
+ */
121
+ const __iconData$6 = {
122
+ name: "external-link",
123
+ size: 24,
124
+ node: [
125
+ ["path", {
126
+ d: "M15 3h6v6",
127
+ key: "1q9fwt"
128
+ }],
129
+ ["path", {
130
+ d: "M10 14 21 3",
131
+ key: "gplh6r"
132
+ }],
133
+ ["path", {
134
+ d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",
135
+ key: "a6xqqp"
136
+ }]
137
+ ]
138
+ };
139
+ __iconData$6.node;
140
+ const ExternalLink = createLucideIcon(__iconData$6);
111
141
  //#endregion
112
142
  //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/moon.mjs
113
143
  /**
@@ -116,7 +146,7 @@ const ChevronsUpDown = createLucideIcon(__iconData$4);
116
146
  * This source code is licensed under the ISC license.
117
147
  * See the LICENSE file in the root directory of this source tree.
118
148
  */
119
- const __iconData$3 = {
149
+ const __iconData$5 = {
120
150
  name: "moon",
121
151
  size: 24,
122
152
  node: [["path", {
@@ -124,8 +154,33 @@ const __iconData$3 = {
124
154
  key: "kfwtm"
125
155
  }]]
126
156
  };
127
- __iconData$3.node;
128
- const Moon = createLucideIcon(__iconData$3);
157
+ __iconData$5.node;
158
+ const Moon = createLucideIcon(__iconData$5);
159
+ //#endregion
160
+ //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/panel-top.mjs
161
+ /**
162
+ * @license lucide-react v1.43.0 - ISC
163
+ *
164
+ * This source code is licensed under the ISC license.
165
+ * See the LICENSE file in the root directory of this source tree.
166
+ */
167
+ const __iconData$4 = {
168
+ name: "panel-top",
169
+ size: 24,
170
+ node: [["rect", {
171
+ width: "18",
172
+ height: "18",
173
+ x: "3",
174
+ y: "3",
175
+ rx: "2",
176
+ key: "afitv7"
177
+ }], ["path", {
178
+ d: "M3 9h18",
179
+ key: "1pudct"
180
+ }]]
181
+ };
182
+ __iconData$4.node;
183
+ const PanelTop = createLucideIcon(__iconData$4);
129
184
  //#endregion
130
185
  //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/plus.mjs
131
186
  /**
@@ -134,7 +189,7 @@ const Moon = createLucideIcon(__iconData$3);
134
189
  * This source code is licensed under the ISC license.
135
190
  * See the LICENSE file in the root directory of this source tree.
136
191
  */
137
- const __iconData$2 = {
192
+ const __iconData$3 = {
138
193
  name: "plus",
139
194
  size: 24,
140
195
  node: [["path", {
@@ -145,8 +200,8 @@ const __iconData$2 = {
145
200
  key: "s699le"
146
201
  }]]
147
202
  };
148
- __iconData$2.node;
149
- const Plus = createLucideIcon(__iconData$2);
203
+ __iconData$3.node;
204
+ const Plus = createLucideIcon(__iconData$3);
150
205
  //#endregion
151
206
  //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/rotate-ccw.mjs
152
207
  /**
@@ -155,7 +210,7 @@ const Plus = createLucideIcon(__iconData$2);
155
210
  * This source code is licensed under the ISC license.
156
211
  * See the LICENSE file in the root directory of this source tree.
157
212
  */
158
- const __iconData$1 = {
213
+ const __iconData$2 = {
159
214
  name: "rotate-ccw",
160
215
  size: 24,
161
216
  node: [["path", {
@@ -166,8 +221,60 @@ const __iconData$1 = {
166
221
  key: "1xhq8a"
167
222
  }]]
168
223
  };
224
+ __iconData$2.node;
225
+ const RotateCcw = createLucideIcon(__iconData$2);
226
+ //#endregion
227
+ //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/sliders-horizontal.mjs
228
+ /**
229
+ * @license lucide-react v1.43.0 - ISC
230
+ *
231
+ * This source code is licensed under the ISC license.
232
+ * See the LICENSE file in the root directory of this source tree.
233
+ */
234
+ const __iconData$1 = {
235
+ name: "sliders-horizontal",
236
+ size: 24,
237
+ node: [
238
+ ["path", {
239
+ d: "M10 5H3",
240
+ key: "1qgfaw"
241
+ }],
242
+ ["path", {
243
+ d: "M12 19H3",
244
+ key: "yhmn1j"
245
+ }],
246
+ ["path", {
247
+ d: "M14 3v4",
248
+ key: "1sua03"
249
+ }],
250
+ ["path", {
251
+ d: "M16 17v4",
252
+ key: "1q0r14"
253
+ }],
254
+ ["path", {
255
+ d: "M21 12h-9",
256
+ key: "1o4lsq"
257
+ }],
258
+ ["path", {
259
+ d: "M21 19h-5",
260
+ key: "1rlt1p"
261
+ }],
262
+ ["path", {
263
+ d: "M21 5h-7",
264
+ key: "1oszz2"
265
+ }],
266
+ ["path", {
267
+ d: "M8 10v4",
268
+ key: "tgpxqk"
269
+ }],
270
+ ["path", {
271
+ d: "M8 12H3",
272
+ key: "a7s4jb"
273
+ }]
274
+ ]
275
+ };
169
276
  __iconData$1.node;
170
- const RotateCcw = createLucideIcon(__iconData$1);
277
+ const SlidersHorizontal = createLucideIcon(__iconData$1);
171
278
  //#endregion
172
279
  //#region ../../node_modules/.bun/lucide-react@1.43.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/icons/sun.mjs
173
280
  /**
@@ -611,6 +718,461 @@ function useUIConfiguration() {
611
718
  return context;
612
719
  }
613
720
  //#endregion
721
+ //#region src/configurator/ConfigurationLauncher.tsx
722
+ function ConfigurationLauncher({ position, onOpen }) {
723
+ const ref = useRef(null);
724
+ const gesture = useRef(null);
725
+ const dragged = useRef(false);
726
+ const pending = useRef(null);
727
+ const frame = useRef(null);
728
+ const place = useCallback((next) => {
729
+ const element = ref.current;
730
+ if (!element) return;
731
+ const left = Math.max(8, Math.min(next.left, window.innerWidth - element.offsetWidth - 8));
732
+ const top = Math.max(8, Math.min(next.top, window.innerHeight - element.offsetHeight - 8));
733
+ position.current = {
734
+ left,
735
+ top
736
+ };
737
+ element.style.left = `${left}px`;
738
+ element.style.top = `${top}px`;
739
+ }, [position]);
740
+ function finish() {
741
+ if (frame.current !== null) cancelAnimationFrame(frame.current);
742
+ frame.current = null;
743
+ if (pending.current) place(pending.current);
744
+ pending.current = null;
745
+ gesture.current = null;
746
+ }
747
+ useLayoutEffect(() => {
748
+ const element_0 = ref.current;
749
+ if (!element_0) return;
750
+ const resize = () => place(position.current ?? {
751
+ left: window.innerWidth - element_0.offsetWidth - 24,
752
+ top: window.innerHeight - element_0.offsetHeight - 24
753
+ });
754
+ resize();
755
+ window.addEventListener("resize", resize);
756
+ return () => {
757
+ window.removeEventListener("resize", resize);
758
+ if (frame.current !== null) cancelAnimationFrame(frame.current);
759
+ if (pending.current) position.current = pending.current;
760
+ };
761
+ }, [place, position]);
762
+ return /* @__PURE__ */ jsxs("button", {
763
+ ref,
764
+ type: "button",
765
+ className: "studio-floating-launcher",
766
+ "aria-label": "Open Povio UI configuration",
767
+ title: "Open Povio UI · Drag to move",
768
+ onClick: (event) => {
769
+ if (dragged.current && event.detail !== 0) {
770
+ dragged.current = false;
771
+ return;
772
+ }
773
+ onOpen();
774
+ },
775
+ onPointerDown: (event_0) => {
776
+ if (event_0.button !== 0) return;
777
+ const rect = event_0.currentTarget.getBoundingClientRect();
778
+ dragged.current = false;
779
+ gesture.current = {
780
+ x: event_0.clientX,
781
+ y: event_0.clientY,
782
+ left: rect.left,
783
+ top: rect.top,
784
+ pointerId: event_0.pointerId
785
+ };
786
+ event_0.currentTarget.setPointerCapture(event_0.pointerId);
787
+ },
788
+ onPointerMove: (event_1) => {
789
+ const start = gesture.current;
790
+ if (!start || start.pointerId !== event_1.pointerId) return;
791
+ const x = event_1.clientX - start.x;
792
+ const y = event_1.clientY - start.y;
793
+ if (!dragged.current && Math.hypot(x, y) < 5) return;
794
+ dragged.current = true;
795
+ pending.current = {
796
+ left: start.left + x,
797
+ top: start.top + y
798
+ };
799
+ if (frame.current !== null) return;
800
+ frame.current = requestAnimationFrame(() => {
801
+ frame.current = null;
802
+ if (pending.current) place(pending.current);
803
+ });
804
+ },
805
+ onPointerUp: (event_2) => {
806
+ if (gesture.current?.pointerId !== event_2.pointerId) return;
807
+ finish();
808
+ if (event_2.currentTarget.hasPointerCapture(event_2.pointerId)) event_2.currentTarget.releasePointerCapture(event_2.pointerId);
809
+ },
810
+ onPointerCancel: finish,
811
+ onLostPointerCapture: finish,
812
+ onKeyDown: (event_3) => {
813
+ const move = {
814
+ ArrowLeft: [-1, 0],
815
+ ArrowRight: [1, 0],
816
+ ArrowUp: [0, -1],
817
+ ArrowDown: [0, 1]
818
+ }[event_3.key];
819
+ if (!move || !position.current) return;
820
+ event_3.preventDefault();
821
+ const step = event_3.shiftKey ? 40 : 10;
822
+ place({
823
+ left: position.current.left + move[0] * step,
824
+ top: position.current.top + move[1] * step
825
+ });
826
+ },
827
+ children: [
828
+ /* @__PURE__ */ jsx(SlidersHorizontal, { size: 18 }),
829
+ /* @__PURE__ */ jsx("span", { children: "Povio UI" }),
830
+ /* @__PURE__ */ jsx(GripVertical, { size: 16 })
831
+ ]
832
+ });
833
+ }
834
+ //#endregion
835
+ //#region src/configurator/useStudioPopout.ts
836
+ const StudioPopoutContext = createContext(false);
837
+ /** Keep the popup's styles current without copying scripts or starting a second app. */
838
+ function mirrorStyles(source, target) {
839
+ const base = target.createElement("base");
840
+ base.href = source.baseURI;
841
+ target.head.append(base);
842
+ const copies = /* @__PURE__ */ new Map();
843
+ const sync = () => {
844
+ target.documentElement.className = source.documentElement.className;
845
+ target.documentElement.style.cssText = source.documentElement.style.cssText;
846
+ const originals = new Set(source.querySelectorAll("style, link[rel=\"stylesheet\"]"));
847
+ for (const [original, copy] of copies) if (!originals.has(original)) {
848
+ copy.remove();
849
+ copies.delete(original);
850
+ }
851
+ for (const original of originals) {
852
+ let copy = copies.get(original);
853
+ if (!copy) {
854
+ copy = original.cloneNode(true);
855
+ copies.set(original, copy);
856
+ target.head.append(copy);
857
+ } else if (!copy.isEqualNode(original)) {
858
+ const replacement = original.cloneNode(true);
859
+ copy.replaceWith(replacement);
860
+ copies.set(original, replacement);
861
+ }
862
+ }
863
+ source.fonts.forEach((font) => target.fonts.add(font));
864
+ };
865
+ sync();
866
+ const observer = new MutationObserver((records) => {
867
+ if (records.some((record) => {
868
+ const element = record.target.nodeType === 1 ? record.target : record.target.parentElement;
869
+ return element === source.documentElement || element?.closest("style, link[rel=\"stylesheet\"]") || [...record.addedNodes, ...record.removedNodes].some((node) => node.nodeType === 1 && (node.matches("style, link[rel=\"stylesheet\"]") || node.querySelector("style, link[rel=\"stylesheet\"]")));
870
+ })) sync();
871
+ });
872
+ observer.observe(source.documentElement, {
873
+ childList: true,
874
+ subtree: true,
875
+ characterData: true,
876
+ attributes: true,
877
+ attributeFilter: [
878
+ "class",
879
+ "style",
880
+ "href",
881
+ "media",
882
+ "disabled"
883
+ ]
884
+ });
885
+ source.fonts.addEventListener("loadingdone", sync);
886
+ return () => {
887
+ observer.disconnect();
888
+ source.fonts.removeEventListener("loadingdone", sync);
889
+ };
890
+ }
891
+ function useStudioPopout(isOpen) {
892
+ const $ = c(11);
893
+ const geometry = useRef(null);
894
+ const [popup, setPopup] = useState(null);
895
+ const [blocked, setBlocked] = useState(false);
896
+ let t0;
897
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
898
+ t0 = () => {
899
+ const saved = geometry.current;
900
+ const dimensions = saved ? `width=${saved.width},height=${saved.height},left=${saved.left},top=${saved.top}` : "width=1200,height=850";
901
+ const child = window.open("", "_blank", `popup=yes,${dimensions},resizable=yes,scrollbars=yes`);
902
+ if (!child) {
903
+ setBlocked(true);
904
+ return;
905
+ }
906
+ child.document.title = "Povio UI Configuration";
907
+ child.document.documentElement.dataset.povioUiPopout = "";
908
+ child.document.body.style.margin = "0";
909
+ setBlocked(false);
910
+ setPopup(child);
911
+ child.focus();
912
+ };
913
+ $[0] = t0;
914
+ } else t0 = $[0];
915
+ const open = t0;
916
+ let t1;
917
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
918
+ t1 = () => setPopup(null);
919
+ $[1] = t1;
920
+ } else t1 = $[1];
921
+ const dock = t1;
922
+ let t2;
923
+ let t3;
924
+ if ($[2] !== popup) {
925
+ t2 = () => {
926
+ if (!popup) return;
927
+ const stopMirroring = mirrorStyles(document, popup.document);
928
+ const remember = () => {
929
+ if (!popup.closed && popup.innerWidth > 0 && popup.innerHeight > 0) geometry.current = {
930
+ width: popup.innerWidth,
931
+ height: popup.innerHeight,
932
+ left: popup.screenX,
933
+ top: popup.screenY
934
+ };
935
+ };
936
+ const close = () => {
937
+ remember();
938
+ setPopup(null);
939
+ };
940
+ const closeWithHost = () => popup.close();
941
+ popup.addEventListener("pagehide", close);
942
+ popup.addEventListener("resize", remember);
943
+ popup.addEventListener("blur", remember);
944
+ window.addEventListener("pagehide", closeWithHost);
945
+ return () => {
946
+ remember();
947
+ stopMirroring();
948
+ popup.removeEventListener("pagehide", close);
949
+ popup.removeEventListener("resize", remember);
950
+ popup.removeEventListener("blur", remember);
951
+ window.removeEventListener("pagehide", closeWithHost);
952
+ if (!popup.closed) popup.close();
953
+ };
954
+ };
955
+ t3 = [popup];
956
+ $[2] = popup;
957
+ $[3] = t2;
958
+ $[4] = t3;
959
+ } else {
960
+ t2 = $[3];
961
+ t3 = $[4];
962
+ }
963
+ useEffect(t2, t3);
964
+ let t4;
965
+ let t5;
966
+ if ($[5] !== isOpen) {
967
+ t4 = () => {
968
+ if (!isOpen) setPopup(null);
969
+ };
970
+ t5 = [isOpen];
971
+ $[5] = isOpen;
972
+ $[6] = t4;
973
+ $[7] = t5;
974
+ } else {
975
+ t4 = $[6];
976
+ t5 = $[7];
977
+ }
978
+ useEffect(t4, t5);
979
+ let t6;
980
+ if ($[8] !== blocked || $[9] !== popup) {
981
+ t6 = {
982
+ popup,
983
+ blocked,
984
+ open,
985
+ dock
986
+ };
987
+ $[8] = blocked;
988
+ $[9] = popup;
989
+ $[10] = t6;
990
+ } else t6 = $[10];
991
+ return t6;
992
+ }
993
+ //#endregion
994
+ //#region src/configurator/useStudioWindow.ts
995
+ const windowEdges = [
996
+ "n",
997
+ "e",
998
+ "s",
999
+ "w",
1000
+ "ne",
1001
+ "se",
1002
+ "sw",
1003
+ "nw"
1004
+ ];
1005
+ function constrain(bounds) {
1006
+ const margin = 8;
1007
+ const width = Math.min(Math.max(360, bounds.width), window.innerWidth - 16);
1008
+ const height = Math.min(Math.max(360, bounds.height), window.innerHeight - 16);
1009
+ return {
1010
+ width,
1011
+ height,
1012
+ left: Math.max(margin, Math.min(bounds.left, window.innerWidth - width - margin)),
1013
+ top: Math.max(margin, Math.min(bounds.top, window.innerHeight - height - margin))
1014
+ };
1015
+ }
1016
+ function writeBounds(element, bounds) {
1017
+ Object.assign(element.style, {
1018
+ position: "fixed",
1019
+ left: `${bounds.left}px`,
1020
+ top: `${bounds.top}px`,
1021
+ width: `${bounds.width}px`,
1022
+ height: `${bounds.height}px`,
1023
+ transform: "",
1024
+ willChange: ""
1025
+ });
1026
+ }
1027
+ function adjust(start, action, x, y) {
1028
+ if (action === "move") return constrain({
1029
+ ...start,
1030
+ left: start.left + x,
1031
+ top: start.top + y
1032
+ });
1033
+ const margin = 8;
1034
+ const minWidth = Math.min(360, window.innerWidth - 16);
1035
+ const minHeight = Math.min(360, window.innerHeight - 16);
1036
+ const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
1037
+ let { left, top } = start;
1038
+ let right = left + start.width;
1039
+ let bottom = top + start.height;
1040
+ if (action.includes("w")) left = clamp(left + x, margin, right - minWidth);
1041
+ if (action.includes("e")) right = clamp(right + x, left + minWidth, window.innerWidth - margin);
1042
+ if (action.includes("n")) top = clamp(top + y, margin, bottom - minHeight);
1043
+ if (action.includes("s")) bottom = clamp(bottom + y, top + minHeight, window.innerHeight - margin);
1044
+ return {
1045
+ left,
1046
+ top,
1047
+ width: right - left,
1048
+ height: bottom - top
1049
+ };
1050
+ }
1051
+ function useStudioWindow(bounds, enabled = true) {
1052
+ const ref = useRef(null);
1053
+ const gesture = useRef(null);
1054
+ const frame = useRef(null);
1055
+ useLayoutEffect(() => {
1056
+ const element = ref.current;
1057
+ if (!enabled || !element) return;
1058
+ if (bounds.current) {
1059
+ bounds.current = constrain(bounds.current);
1060
+ writeBounds(element, bounds.current);
1061
+ }
1062
+ return () => {
1063
+ const rect = element.getBoundingClientRect();
1064
+ bounds.current = gesture.current?.latest ?? {
1065
+ left: rect.left,
1066
+ top: rect.top,
1067
+ width: rect.width,
1068
+ height: rect.height
1069
+ };
1070
+ };
1071
+ }, [bounds, enabled]);
1072
+ useEffect(() => {
1073
+ if (!enabled) return;
1074
+ const resize = () => {
1075
+ if (frame.current !== null) cancelAnimationFrame(frame.current);
1076
+ frame.current = null;
1077
+ const current = gesture.current?.latest ?? bounds.current;
1078
+ gesture.current = null;
1079
+ if (current && ref.current) {
1080
+ bounds.current = constrain(current);
1081
+ writeBounds(ref.current, bounds.current);
1082
+ }
1083
+ };
1084
+ window.addEventListener("resize", resize);
1085
+ return () => {
1086
+ window.removeEventListener("resize", resize);
1087
+ if (frame.current !== null) cancelAnimationFrame(frame.current);
1088
+ };
1089
+ }, [bounds, enabled]);
1090
+ function currentBounds() {
1091
+ const rect_0 = ref.current?.getBoundingClientRect();
1092
+ return rect_0 ? {
1093
+ left: rect_0.left,
1094
+ top: rect_0.top,
1095
+ width: rect_0.width,
1096
+ height: rect_0.height
1097
+ } : null;
1098
+ }
1099
+ function finish() {
1100
+ if (frame.current !== null) cancelAnimationFrame(frame.current);
1101
+ frame.current = null;
1102
+ const current_0 = gesture.current;
1103
+ gesture.current = null;
1104
+ if (!current_0 || !ref.current) return;
1105
+ bounds.current = current_0.latest;
1106
+ writeBounds(ref.current, current_0.latest);
1107
+ }
1108
+ function controls(action) {
1109
+ return {
1110
+ onPointerDown(event) {
1111
+ if (event.button !== 0 || gesture.current) return;
1112
+ const start = currentBounds();
1113
+ if (!start || !ref.current) return;
1114
+ event.preventDefault();
1115
+ event.currentTarget.focus({ preventScroll: true });
1116
+ event.currentTarget.setPointerCapture(event.pointerId);
1117
+ writeBounds(ref.current, start);
1118
+ if (action === "move") ref.current.style.willChange = "transform";
1119
+ gesture.current = {
1120
+ action,
1121
+ x: event.clientX,
1122
+ y: event.clientY,
1123
+ bounds: start,
1124
+ latest: start,
1125
+ pointerId: event.pointerId
1126
+ };
1127
+ },
1128
+ onPointerMove(event_0) {
1129
+ const start_0 = gesture.current;
1130
+ if (!start_0 || start_0.pointerId !== event_0.pointerId) return;
1131
+ start_0.latest = adjust(start_0.bounds, start_0.action, event_0.clientX - start_0.x, event_0.clientY - start_0.y);
1132
+ if (frame.current !== null) return;
1133
+ frame.current = requestAnimationFrame(() => {
1134
+ frame.current = null;
1135
+ const current_1 = gesture.current;
1136
+ if (!current_1 || !ref.current) return;
1137
+ if (current_1.action === "move") {
1138
+ const x = current_1.latest.left - current_1.bounds.left;
1139
+ const y = current_1.latest.top - current_1.bounds.top;
1140
+ ref.current.style.transform = `translate3d(${x}px, ${y}px, 0)`;
1141
+ } else writeBounds(ref.current, current_1.latest);
1142
+ });
1143
+ },
1144
+ onPointerUp(event_1) {
1145
+ if (gesture.current?.pointerId !== event_1.pointerId) return;
1146
+ finish();
1147
+ if (event_1.currentTarget.hasPointerCapture(event_1.pointerId)) event_1.currentTarget.releasePointerCapture(event_1.pointerId);
1148
+ },
1149
+ onLostPointerCapture: finish,
1150
+ onPointerCancel: finish,
1151
+ onKeyDown(event_2) {
1152
+ const direction = {
1153
+ ArrowLeft: [-1, 0],
1154
+ ArrowRight: [1, 0],
1155
+ ArrowUp: [0, -1],
1156
+ ArrowDown: [0, 1]
1157
+ }[event_2.key];
1158
+ if (!direction || gesture.current) return;
1159
+ event_2.preventDefault();
1160
+ const start_1 = currentBounds();
1161
+ const step = event_2.shiftKey ? 40 : 10;
1162
+ if (start_1 && ref.current) {
1163
+ bounds.current = adjust(start_1, action, direction[0] * step, direction[1] * step);
1164
+ writeBounds(ref.current, bounds.current);
1165
+ }
1166
+ }
1167
+ };
1168
+ }
1169
+ return {
1170
+ ref,
1171
+ move: controls("move"),
1172
+ resize: (edge) => controls(edge)
1173
+ };
1174
+ }
1175
+ //#endregion
614
1176
  //#region src/configurator/ContextualPreview.tsx
615
1177
  function CvaPreview(t0) {
616
1178
  const $ = c(84);
@@ -630,7 +1192,7 @@ function CvaPreview(t0) {
630
1192
  component = slot.split(".")[0];
631
1193
  const props = {
632
1194
  ...definition?.config.defaultVariants,
633
- ...Object.fromEntries(Object.entries(variants).filter(_temp$5).map(_temp2$2))
1195
+ ...Object.fromEntries(Object.entries(variants).filter(_temp$5).map(_temp2$3))
634
1196
  };
635
1197
  const classes = (key, t4) => {
636
1198
  const extra = t4 === void 0 ? {} : t4;
@@ -1395,7 +1957,7 @@ function _temp4$2(value_2) {
1395
1957
  function _temp3$2(event_1) {
1396
1958
  return event_1.preventDefault();
1397
1959
  }
1398
- function _temp2$2(t0) {
1960
+ function _temp2$3(t0) {
1399
1961
  const [name, value_0] = t0;
1400
1962
  return [name, value_0 === "true" ? true : value_0 === "false" ? false : value_0];
1401
1963
  }
@@ -1607,7 +2169,7 @@ function CvaEditor(t0) {
1607
2169
  let update;
1608
2170
  if ($[2] !== component || $[3] !== draft.overrides || $[4] !== inheritedOverrides || $[5] !== setDraft || $[6] !== setSlot || $[7] !== slot) {
1609
2171
  slots = Object.keys(cvaDefinitions);
1610
- const components = [...new Set(slots.map(_temp2$1))];
2172
+ const components = [...new Set(slots.map(_temp2$2))];
1611
2173
  let t10;
1612
2174
  if ($[20] !== inheritedOverrides || $[21] !== slot) {
1613
2175
  t10 = resolveCvaDefinition(slot, inheritedOverrides);
@@ -1911,7 +2473,7 @@ function _temp3$1(name) {
1911
2473
  children: title(name)
1912
2474
  }, name);
1913
2475
  }
1914
- function _temp2$1(key) {
2476
+ function _temp2$2(key) {
1915
2477
  return key.split(".")[0];
1916
2478
  }
1917
2479
  //#endregion
@@ -2153,8 +2715,9 @@ function scrollSelectedIntoView(list) {
2153
2715
  }
2154
2716
  /** Picks a base palette color for a semantic token, showing each option's swatch, step and hex value. */
2155
2717
  function PaletteSelect(t0) {
2156
- const $ = c(28);
2718
+ const $ = c(50);
2157
2719
  const { id, label, options, selected, onSelect } = t0;
2720
+ const poppedOut = use(StudioPopoutContext);
2158
2721
  let current;
2159
2722
  let t1;
2160
2723
  if ($[0] !== options || $[1] !== selected) {
@@ -2175,15 +2738,99 @@ function PaletteSelect(t0) {
2175
2738
  t1 = $[3];
2176
2739
  }
2177
2740
  const [, family, step] = t1;
2741
+ if (poppedOut) {
2742
+ const t2 = `studio-palette-picker studio-palette-native ${current ? "" : "is-custom"}`;
2743
+ let t3;
2744
+ if ($[6] !== current || $[7] !== family || $[8] !== step) {
2745
+ t3 = current && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
2746
+ className: "studio-palette-swatch",
2747
+ style: { backgroundColor: `rgb(${current.value})` }
2748
+ }), /* @__PURE__ */ jsxs("span", {
2749
+ className: "studio-palette-trigger-label",
2750
+ children: [
2751
+ family,
2752
+ " ",
2753
+ step
2754
+ ]
2755
+ })] });
2756
+ $[6] = current;
2757
+ $[7] = family;
2758
+ $[8] = step;
2759
+ $[9] = t3;
2760
+ } else t3 = $[9];
2761
+ let t4;
2762
+ if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
2763
+ t4 = /* @__PURE__ */ jsx(ChevronDown, { size: 13 });
2764
+ $[10] = t4;
2765
+ } else t4 = $[10];
2766
+ let t5;
2767
+ if ($[11] !== t3) {
2768
+ t5 = /* @__PURE__ */ jsxs("div", {
2769
+ className: "studio-palette-trigger",
2770
+ "aria-hidden": "true",
2771
+ children: [t3, t4]
2772
+ });
2773
+ $[11] = t3;
2774
+ $[12] = t5;
2775
+ } else t5 = $[12];
2776
+ let t6;
2777
+ if ($[13] !== onSelect) {
2778
+ t6 = (event) => onSelect(event.target.value);
2779
+ $[13] = onSelect;
2780
+ $[14] = t6;
2781
+ } else t6 = $[14];
2782
+ let t7;
2783
+ if ($[15] !== options) {
2784
+ t7 = paletteFamilies(options).map(_temp$2);
2785
+ $[15] = options;
2786
+ $[16] = t7;
2787
+ } else t7 = $[16];
2788
+ let t8;
2789
+ if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
2790
+ t8 = /* @__PURE__ */ jsx("option", {
2791
+ value: customPaletteKey,
2792
+ children: "Custom value…"
2793
+ });
2794
+ $[17] = t8;
2795
+ } else t8 = $[17];
2796
+ let t9;
2797
+ if ($[18] !== id || $[19] !== label || $[20] !== selected || $[21] !== t6 || $[22] !== t7) {
2798
+ t9 = /* @__PURE__ */ jsxs("select", {
2799
+ id,
2800
+ "aria-label": label,
2801
+ value: selected,
2802
+ onChange: t6,
2803
+ children: [t7, t8]
2804
+ });
2805
+ $[18] = id;
2806
+ $[19] = label;
2807
+ $[20] = selected;
2808
+ $[21] = t6;
2809
+ $[22] = t7;
2810
+ $[23] = t9;
2811
+ } else t9 = $[23];
2812
+ let t10;
2813
+ if ($[24] !== t2 || $[25] !== t5 || $[26] !== t9) {
2814
+ t10 = /* @__PURE__ */ jsxs("div", {
2815
+ className: t2,
2816
+ children: [t5, t9]
2817
+ });
2818
+ $[24] = t2;
2819
+ $[25] = t5;
2820
+ $[26] = t9;
2821
+ $[27] = t10;
2822
+ } else t10 = $[27];
2823
+ return t10;
2824
+ }
2178
2825
  const t2 = `studio-palette-picker ${current ? "" : "is-custom"}`;
2179
2826
  let t3;
2180
- if ($[6] !== onSelect) {
2827
+ if ($[28] !== onSelect) {
2181
2828
  t3 = (key) => key !== null && onSelect(String(key));
2182
- $[6] = onSelect;
2183
- $[7] = t3;
2184
- } else t3 = $[7];
2829
+ $[28] = onSelect;
2830
+ $[29] = t3;
2831
+ } else t3 = $[29];
2185
2832
  let t4;
2186
- if ($[8] !== current || $[9] !== family || $[10] !== step) {
2833
+ if ($[30] !== current || $[31] !== family || $[32] !== step) {
2187
2834
  t4 = current && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
2188
2835
  className: "studio-palette-swatch",
2189
2836
  style: { backgroundColor: `rgb(${current.value})` },
@@ -2196,36 +2843,36 @@ function PaletteSelect(t0) {
2196
2843
  step
2197
2844
  ]
2198
2845
  })] });
2199
- $[8] = current;
2200
- $[9] = family;
2201
- $[10] = step;
2202
- $[11] = t4;
2203
- } else t4 = $[11];
2846
+ $[30] = current;
2847
+ $[31] = family;
2848
+ $[32] = step;
2849
+ $[33] = t4;
2850
+ } else t4 = $[33];
2204
2851
  let t5;
2205
- if ($[12] === Symbol.for("react.memo_cache_sentinel")) {
2852
+ if ($[34] === Symbol.for("react.memo_cache_sentinel")) {
2206
2853
  t5 = /* @__PURE__ */ jsx(ChevronDown, {
2207
2854
  size: 13,
2208
2855
  "aria-hidden": "true"
2209
2856
  });
2210
- $[12] = t5;
2211
- } else t5 = $[12];
2857
+ $[34] = t5;
2858
+ } else t5 = $[34];
2212
2859
  let t6;
2213
- if ($[13] !== t4) {
2860
+ if ($[35] !== t4) {
2214
2861
  t6 = /* @__PURE__ */ jsxs($7705c033048f6da7$export$353f5b6fc5456de1, {
2215
2862
  className: "studio-palette-trigger",
2216
2863
  children: [t4, t5]
2217
2864
  });
2218
- $[13] = t4;
2219
- $[14] = t6;
2220
- } else t6 = $[14];
2865
+ $[35] = t4;
2866
+ $[36] = t6;
2867
+ } else t6 = $[36];
2221
2868
  let t7;
2222
- if ($[15] !== options) {
2223
- t7 = paletteFamilies(options).map(_temp$2);
2224
- $[15] = options;
2225
- $[16] = t7;
2226
- } else t7 = $[16];
2869
+ if ($[37] !== options) {
2870
+ t7 = paletteFamilies(options).map(_temp2$1);
2871
+ $[37] = options;
2872
+ $[38] = t7;
2873
+ } else t7 = $[38];
2227
2874
  let t8;
2228
- if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
2875
+ if ($[39] === Symbol.for("react.memo_cache_sentinel")) {
2229
2876
  t8 = /* @__PURE__ */ jsx($928221da08ecbc62$export$dca12b0bb56e4fc, {
2230
2877
  id: "other",
2231
2878
  children: /* @__PURE__ */ jsx($928221da08ecbc62$export$a11e76429ed99b4, {
@@ -2234,10 +2881,10 @@ function PaletteSelect(t0) {
2234
2881
  children: "Custom value…"
2235
2882
  })
2236
2883
  });
2237
- $[17] = t8;
2238
- } else t8 = $[17];
2884
+ $[39] = t8;
2885
+ } else t8 = $[39];
2239
2886
  let t9;
2240
- if ($[18] !== t7) {
2887
+ if ($[40] !== t7) {
2241
2888
  t9 = /* @__PURE__ */ jsx($542a13ca2fa5b484$export$5b6b19405a83ff9d, {
2242
2889
  className: "studio-palette-popover",
2243
2890
  placement: "bottom end",
@@ -2247,11 +2894,11 @@ function PaletteSelect(t0) {
2247
2894
  children: [t7, t8]
2248
2895
  })
2249
2896
  });
2250
- $[18] = t7;
2251
- $[19] = t9;
2252
- } else t9 = $[19];
2897
+ $[40] = t7;
2898
+ $[41] = t9;
2899
+ } else t9 = $[41];
2253
2900
  let t10;
2254
- if ($[20] !== id || $[21] !== label || $[22] !== selected || $[23] !== t2 || $[24] !== t3 || $[25] !== t6 || $[26] !== t9) {
2901
+ if ($[42] !== id || $[43] !== label || $[44] !== selected || $[45] !== t2 || $[46] !== t3 || $[47] !== t6 || $[48] !== t9) {
2255
2902
  t10 = /* @__PURE__ */ jsxs($c8bb816105474884$export$ef9b1a59e592288f, {
2256
2903
  id,
2257
2904
  "aria-label": label,
@@ -2260,39 +2907,56 @@ function PaletteSelect(t0) {
2260
2907
  onSelectionChange: t3,
2261
2908
  children: [t6, t9]
2262
2909
  });
2263
- $[20] = id;
2264
- $[21] = label;
2265
- $[22] = selected;
2266
- $[23] = t2;
2267
- $[24] = t3;
2268
- $[25] = t6;
2269
- $[26] = t9;
2270
- $[27] = t10;
2271
- } else t10 = $[27];
2910
+ $[42] = id;
2911
+ $[43] = label;
2912
+ $[44] = selected;
2913
+ $[45] = t2;
2914
+ $[46] = t3;
2915
+ $[47] = t6;
2916
+ $[48] = t9;
2917
+ $[49] = t10;
2918
+ } else t10 = $[49];
2272
2919
  return t10;
2273
2920
  }
2274
- function _temp$2(t0) {
2275
- const { family: name, steps } = t0;
2921
+ function _temp2$1(t0) {
2922
+ const { family: name_0, steps: steps_0 } = t0;
2276
2923
  return /* @__PURE__ */ jsxs($928221da08ecbc62$export$dca12b0bb56e4fc, {
2277
- id: name,
2278
- children: [/* @__PURE__ */ jsxs($53e61d82d8b8611d$export$8b251419efc915eb, { children: ["Base palette / ", name] }), steps.map((t1) => {
2279
- const { step: value, option: option_0 } = t1;
2924
+ id: name_0,
2925
+ children: [/* @__PURE__ */ jsxs($53e61d82d8b8611d$export$8b251419efc915eb, { children: ["Base palette / ", name_0] }), steps_0.map((t1) => {
2926
+ const { step: value_0, option: option_1 } = t1;
2280
2927
  return /* @__PURE__ */ jsxs($928221da08ecbc62$export$a11e76429ed99b4, {
2281
- id: option_0.name,
2282
- textValue: `${name} ${value}`,
2283
- "aria-label": `${name} ${value}`,
2928
+ id: option_1.name,
2929
+ textValue: `${name_0} ${value_0}`,
2930
+ "aria-label": `${name_0} ${value_0}`,
2284
2931
  className: "studio-palette-item",
2285
2932
  children: [
2286
2933
  /* @__PURE__ */ jsx("span", {
2287
2934
  className: "studio-palette-swatch",
2288
- style: { backgroundColor: `rgb(${option_0.value})` },
2935
+ style: { backgroundColor: `rgb(${option_1.value})` },
2289
2936
  "aria-hidden": "true"
2290
2937
  }),
2291
- /* @__PURE__ */ jsx("span", { children: value }),
2292
- /* @__PURE__ */ jsx("code", { children: toHex(option_0.value).toUpperCase() })
2938
+ /* @__PURE__ */ jsx("span", { children: value_0 }),
2939
+ /* @__PURE__ */ jsx("code", { children: toHex(option_1.value).toUpperCase() })
2293
2940
  ]
2294
- }, option_0.name);
2941
+ }, option_1.name);
2295
2942
  })]
2943
+ }, name_0);
2944
+ }
2945
+ function _temp$2(t0) {
2946
+ const { family: name, steps } = t0;
2947
+ return /* @__PURE__ */ jsx("optgroup", {
2948
+ label: `Base palette / ${name}`,
2949
+ children: steps.map((t1) => {
2950
+ const { step: value, option: option_0 } = t1;
2951
+ return /* @__PURE__ */ jsxs("option", {
2952
+ value: option_0.name,
2953
+ children: [
2954
+ name,
2955
+ " ",
2956
+ value
2957
+ ]
2958
+ }, option_0.name);
2959
+ })
2296
2960
  }, name);
2297
2961
  }
2298
2962
  //#endregion
@@ -3402,7 +4066,7 @@ function groupKeyFor(section, name, defaults) {
3402
4066
  const textStyle = section === "Typography" ? name.match(/^--text-(.+?)(?:--.+)?$/)?.[1] : void 0;
3403
4067
  return textStyle ? `--text-${textStyle}` : section === "Typography" ? name.startsWith("--font-weight-") ? "Font weights" : name.startsWith("--font-") ? "Font families" : "Letter spacing" : section === "Colors" ? baseColorNames(defaults).has(name) ? `Base system · ${name.slice(2).split("-")[0]}` : colorNamespaces[name.slice(2).split("-")[0]] ?? "Other" : section === "Spacing" || section === "Radius" || section === "Sizing" ? componentToken(name).title : section === "Effects" ? effectToken(name).title : "tokens";
3404
4068
  }
3405
- const ComponentGallery = lazy(() => import("../ComponentGallery-BWiPGUL8.js"));
4069
+ const ComponentGallery = lazy(() => import("../ComponentGallery-C2tjrHWn.js"));
3406
4070
  function ComponentPreview(t0) {
3407
4071
  const $ = c(14);
3408
4072
  const { value, mode, inspector } = t0;
@@ -3646,7 +4310,34 @@ function TokenField({ name, value, original, changed, onChange, onReset, onValid
3646
4310
  ]
3647
4311
  });
3648
4312
  }
3649
- function ConfigurationModalContent({ memory }) {
4313
+ function PopoutOverlay(t0) {
4314
+ const $ = c(2);
4315
+ const { children } = t0;
4316
+ let t1;
4317
+ if ($[0] !== children) {
4318
+ t1 = /* @__PURE__ */ jsx("div", {
4319
+ className: "studio-overlay",
4320
+ children
4321
+ });
4322
+ $[0] = children;
4323
+ $[1] = t1;
4324
+ } else t1 = $[1];
4325
+ return t1;
4326
+ }
4327
+ function ConfigurationModalContent({ memory, windowBounds, poppedOut, onPopout, onDock, onMinimize, popupBlocked }) {
4328
+ const Overlay = poppedOut ? PopoutOverlay : $8b8d26808cb8cb53$export$8948f78d83984c69;
4329
+ const Surface = poppedOut ? "div" : $8b8d26808cb8cb53$export$2b77a92f1a5ad772;
4330
+ const studioWindow = useStudioWindow(windowBounds, !poppedOut);
4331
+ const [compactPreview, setCompactPreview] = useState(false);
4332
+ useEffect(() => {
4333
+ const modal = studioWindow.ref.current;
4334
+ if (!modal) return;
4335
+ const observer = new ResizeObserver(([entry]) => {
4336
+ if (entry && entry.contentRect.width > 800) setCompactPreview(false);
4337
+ });
4338
+ observer.observe(modal);
4339
+ return () => observer.disconnect();
4340
+ }, [studioWindow.ref]);
3650
4341
  const inherited = UIConfig.useConfig();
3651
4342
  const { defaults, draft, setDraft, isOpen, cancel, apply, revision } = useUIConfiguration();
3652
4343
  const remembered = memory.current;
@@ -3665,7 +4356,15 @@ function ConfigurationModalContent({ memory }) {
3665
4356
  const [expandedGroups, setExpandedGroups] = useState(remembered.expandedGroups ?? {});
3666
4357
  const [sectionTabs, setSectionTabs] = useState(remembered.sectionTabs ?? {});
3667
4358
  const [resetRevision, setResetRevision] = useState(0);
3668
- const [invalidFields, setInvalidFields] = useState({});
4359
+ const [invalidFields, setInvalidFields] = useState(remembered.invalidRevision === revision ? remembered.invalidFields ?? {} : {});
4360
+ useLayoutEffect(() => {
4361
+ memory.current.invalidRevision = revision;
4362
+ memory.current.invalidFields = invalidFields;
4363
+ }, [
4364
+ memory,
4365
+ revision,
4366
+ invalidFields
4367
+ ]);
3669
4368
  const [message, setMessage] = useState("");
3670
4369
  const [themeWriter, setThemeWriter] = useState(null);
3671
4370
  const [savingTheme, setSavingTheme] = useState(false);
@@ -3711,6 +4410,8 @@ function ConfigurationModalContent({ memory }) {
3711
4410
  const config = inherited;
3712
4411
  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`;
3713
4412
  const changeSection = (next) => {
4413
+ if (compactPreview && bodyRef.current?.parentElement) bodyRef.current.parentElement.scrollTop = 0;
4414
+ setCompactPreview(false);
3714
4415
  if (isLayoutKind(next)) setSectionTabs((current) => ({
3715
4416
  ...current,
3716
4417
  Layout: next
@@ -3738,6 +4439,7 @@ function ConfigurationModalContent({ memory }) {
3738
4439
  ]);
3739
4440
  /** Opens the editor on a token picked in the inspector: its section, its group, scrolled into view and highlighted. */
3740
4441
  const focusToken = useCallback((picked) => {
4442
+ setCompactPreview(false);
3741
4443
  const name_1 = listedLayoutToken(picked, defaults);
3742
4444
  const next_0 = sectionFor(name_1);
3743
4445
  if (isLayoutKind(next_0)) setSectionTabs((current_1) => ({
@@ -3765,7 +4467,7 @@ function ConfigurationModalContent({ memory }) {
3765
4467
  useEffect(() => {
3766
4468
  if (!highlightedToken) return;
3767
4469
  const frame_0 = requestAnimationFrame(() => {
3768
- (document.getElementById(`token-${highlightedToken}`)?.closest(".studio-token"))?.scrollIntoView({
4470
+ (editorRef.current?.ownerDocument.getElementById(`token-${highlightedToken}`)?.closest(".studio-token"))?.scrollIntoView({
3769
4471
  block: "center",
3770
4472
  behavior: "smooth"
3771
4473
  });
@@ -3858,8 +4560,8 @@ function ConfigurationModalContent({ memory }) {
3858
4560
  ...defaults.theme
3859
4561
  }).filter(([name_9]) => (section === "Font size" ? isFontSizeToken(name_9) : section === "Spacing" || section === "Sizing" ? layoutKindFor(name_9) === section && listedLayoutToken(name_9, defaults) === name_9 : groupFor(name_9) === section) && !name_9.startsWith("--color-"));
3860
4562
  const groupedEntries = /* @__PURE__ */ new Map();
3861
- for (const entry of sectionEntries) {
3862
- const [name_10] = entry;
4563
+ for (const entry_0 of sectionEntries) {
4564
+ const [name_10] = entry_0;
3863
4565
  const textStyle = section === "Typography" ? name_10.match(/^--text-(.+?)(?:--.+)?$/)?.[1] : void 0;
3864
4566
  const key_1 = groupKeyFor(section, name_10, defaults);
3865
4567
  if (!groupedEntries.has(key_1)) groupedEntries.set(key_1, {
@@ -3867,7 +4569,7 @@ function ConfigurationModalContent({ memory }) {
3867
4569
  compact: !!textStyle,
3868
4570
  entries: []
3869
4571
  });
3870
- groupedEntries.get(key_1).entries.push(entry);
4572
+ groupedEntries.get(key_1).entries.push(entry_0);
3871
4573
  }
3872
4574
  const paletteStep = (name_11) => Number(name_11.match(/-(\d+)-base$/)?.[1]);
3873
4575
  const isPaletteGroup = (entries) => entries.every(([name_12]) => palette.has(name_12));
@@ -3959,7 +4661,7 @@ function ConfigurationModalContent({ memory }) {
3959
4661
  const renderFontFamilies = (entries_2) => {
3960
4662
  const isFamily = ([name_22, value_10]) => value_10.includes(`var(${name_22}-base)`);
3961
4663
  const families = entries_2.filter(isFamily);
3962
- const roles = entries_2.filter((entry_0) => !isFamily(entry_0));
4664
+ const roles = entries_2.filter((entry_1) => !isFamily(entry_1));
3963
4665
  const themeFonts = families.map(([name_23]) => ({
3964
4666
  name: name_23,
3965
4667
  label: familyName(name_23.replace(/^--font-/, "")),
@@ -3990,7 +4692,7 @@ function ConfigurationModalContent({ memory }) {
3990
4692
  }, `${revision}-${resetRevision}-${name_24}`))
3991
4693
  }),
3992
4694
  /* @__PURE__ */ jsx(FontUpload, { onUpload: refreshLoadedFonts }),
3993
- !!families.length && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("hr", { className: "studio-font-divider" }), families.map((entry_1) => renderToken(entry_1))] })
4695
+ !!families.length && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("hr", { className: "studio-font-divider" }), families.map((entry_2) => renderToken(entry_2))] })
3994
4696
  ]
3995
4697
  }, "font-families");
3996
4698
  };
@@ -4014,17 +4716,19 @@ function ConfigurationModalContent({ memory }) {
4014
4716
  children: options_0.map((option) => /* @__PURE__ */ jsx("option", { children: option }, option))
4015
4717
  })]
4016
4718
  }, `${key_11}-${field_1}`);
4017
- return /* @__PURE__ */ jsx($8b8d26808cb8cb53$export$8948f78d83984c69, {
4719
+ return /* @__PURE__ */ jsx(Overlay, {
4018
4720
  className: "studio-overlay",
4019
4721
  isOpen,
4020
4722
  onOpenChange: (next_2) => {
4021
4723
  if (!next_2) cancel();
4022
4724
  },
4023
4725
  isDismissable: false,
4024
- children: /* @__PURE__ */ jsx($8b8d26808cb8cb53$export$2b77a92f1a5ad772, {
4025
- className: "studio-modal",
4726
+ children: /* @__PURE__ */ jsx(Surface, {
4727
+ className: `studio-modal${poppedOut ? " studio-modal-popout" : ""}`,
4728
+ ref: studioWindow.ref,
4026
4729
  children: /* @__PURE__ */ jsxs($f2ff30fde7b014be$export$3ddf2d174ce01153, {
4027
4730
  className: "studio-dialog",
4731
+ "data-compact-preview": compactPreview || void 0,
4028
4732
  style: { "--studio-editor-track": editorWidth ? `minmax(260px, ${editorWidth}px)` : void 0 },
4029
4733
  children: [
4030
4734
  /* @__PURE__ */ jsxs("header", {
@@ -4040,22 +4744,35 @@ function ConfigurationModalContent({ memory }) {
4040
4744
  /* @__PURE__ */ jsxs("nav", {
4041
4745
  className: "studio-nav",
4042
4746
  "aria-label": "Configuration sections",
4043
- children: [
4044
- navSections.map((group_3) => /* @__PURE__ */ jsx("button", {
4045
- "aria-current": (group_3 === "Layout" ? isLayoutKind(section) : section === group_3) ? "page" : void 0,
4046
- onClick: () => changeSection(group_3 === "Layout" ? lastLayoutSection : group_3),
4047
- children: group_3
4048
- }, group_3)),
4049
- /* @__PURE__ */ jsx("span", {
4050
- className: "studio-nav-divider",
4051
- "aria-hidden": "true"
4052
- }),
4053
- /* @__PURE__ */ jsx("button", {
4054
- "aria-current": advancedSection ? "page" : void 0,
4055
- onClick: () => changeSection(isAdvancedSection(sectionTabs.Advanced ?? "") ? sectionTabs.Advanced : advancedSections[0][0]),
4056
- children: "Advanced"
4057
- })
4058
- ]
4747
+ children: [/* @__PURE__ */ jsxs("div", {
4748
+ className: "studio-section-tabs",
4749
+ children: [
4750
+ navSections.map((group_3) => /* @__PURE__ */ jsx("button", {
4751
+ "aria-current": !compactPreview && (group_3 === "Layout" ? isLayoutKind(section) : section === group_3) ? "page" : void 0,
4752
+ onClick: () => changeSection(group_3 === "Layout" ? lastLayoutSection : group_3),
4753
+ children: group_3
4754
+ }, group_3)),
4755
+ /* @__PURE__ */ jsx("span", {
4756
+ className: "studio-nav-divider",
4757
+ "aria-hidden": "true"
4758
+ }),
4759
+ /* @__PURE__ */ jsx("button", {
4760
+ "aria-current": !compactPreview && advancedSection ? "page" : void 0,
4761
+ onClick: () => changeSection(isAdvancedSection(sectionTabs.Advanced ?? "") ? sectionTabs.Advanced : advancedSections[0][0]),
4762
+ children: "Advanced"
4763
+ })
4764
+ ]
4765
+ }), /* @__PURE__ */ jsx("button", {
4766
+ type: "button",
4767
+ className: "studio-preview-tab",
4768
+ "aria-current": compactPreview ? "page" : void 0,
4769
+ onClick: () => {
4770
+ setCompactPreview(true);
4771
+ const dialog = bodyRef.current?.parentElement;
4772
+ if (dialog) dialog.scrollTop = 0;
4773
+ },
4774
+ children: "Live preview"
4775
+ })]
4059
4776
  }),
4060
4777
  /* @__PURE__ */ jsx("div", {
4061
4778
  className: "studio-topbar-controls",
@@ -4185,9 +4902,9 @@ function ConfigurationModalContent({ memory }) {
4185
4902
  id: `group-${section}-${key_14.replaceAll(" ", "-")}`,
4186
4903
  hidden: !isExpanded(key_14),
4187
4904
  className: group_5.compact ? "studio-type-fields" : void 0,
4188
- children: [section === "Colors" && isPaletteGroup(group_5.entries) && renderPaletteShades(group_5.title, group_5.entries), group_5.entries.map((entry_2) => renderToken(entry_2, group_5.compact))]
4905
+ children: [section === "Colors" && isPaletteGroup(group_5.entries) && renderPaletteShades(group_5.title, group_5.entries), group_5.entries.map((entry_3) => renderToken(entry_3, group_5.compact))]
4189
4906
  })]
4190
- }, key_14) : section === "Typography" && key_14 === "Font families" ? renderFontFamilies(group_5.entries) : group_5.entries.map((entry_3) => renderToken(entry_3))), !orderedGroups.length && /* @__PURE__ */ jsx("p", { children: "No matching tokens. Try a component name such as “button”." })]
4907
+ }, key_14) : section === "Typography" && key_14 === "Font families" ? renderFontFamilies(group_5.entries) : group_5.entries.map((entry_4) => renderToken(entry_4))), !orderedGroups.length && /* @__PURE__ */ jsx("p", { children: "No matching tokens. Try a component name such as “button”." })]
4191
4908
  })] }),
4192
4909
  section === "Variants & overrides" && /* @__PURE__ */ jsx(CvaEditor, {
4193
4910
  slot: cvaSlot,
@@ -4473,7 +5190,7 @@ function ConfigurationModalContent({ memory }) {
4473
5190
  }),
4474
5191
  /* @__PURE__ */ jsx("span", {
4475
5192
  role: "status",
4476
- children: Object.keys(invalidFields).length ? "Fix invalid values or reset before applying or exporting." : nothingToReset && !changedCount ? "No active changes to reset." : message || `${changedCount} overrides · Changes stay in this session`
5193
+ children: 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) || `${changedCount} overrides · Changes stay in this session`
4477
5194
  }),
4478
5195
  /* @__PURE__ */ jsx("button", {
4479
5196
  onClick: () => cancel(),
@@ -4489,6 +5206,36 @@ function ConfigurationModalContent({ memory }) {
4489
5206
  })
4490
5207
  ]
4491
5208
  }),
5209
+ /* @__PURE__ */ jsx("button", {
5210
+ type: "button",
5211
+ className: "studio-window-minimize",
5212
+ "aria-label": "Minimize UI configuration",
5213
+ title: "Minimize to floating button",
5214
+ onClick: onMinimize,
5215
+ children: /* @__PURE__ */ jsx(Minus, { size: 17 })
5216
+ }),
5217
+ /* @__PURE__ */ jsx("button", {
5218
+ type: "button",
5219
+ className: "studio-window-popout",
5220
+ "aria-label": poppedOut ? "Dock configuration back in page" : "Pop out UI configuration",
5221
+ title: poppedOut ? "Dock back in page" : "Open in a separate window",
5222
+ onClick: poppedOut ? onDock : onPopout,
5223
+ children: poppedOut ? /* @__PURE__ */ jsx(PanelTop, { size: 17 }) : /* @__PURE__ */ jsx(ExternalLink, { size: 17 })
5224
+ }),
5225
+ !poppedOut && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
5226
+ type: "button",
5227
+ className: "studio-window-grip",
5228
+ "aria-label": "Move UI configuration",
5229
+ title: "Drag to move, or use arrow keys",
5230
+ ...studioWindow.move,
5231
+ children: /* @__PURE__ */ jsx(GripVertical, { size: 20 })
5232
+ }), windowEdges.map((edge) => /* @__PURE__ */ jsx("button", {
5233
+ type: "button",
5234
+ className: `studio-window-resize studio-window-resize-${edge}`,
5235
+ "aria-label": `Resize UI configuration ${edge}`,
5236
+ title: "Drag to resize, or use arrow keys",
5237
+ ...studioWindow.resize(edge)
5238
+ }, edge))] }),
4492
5239
  /* @__PURE__ */ jsx($8b8d26808cb8cb53$export$8948f78d83984c69, {
4493
5240
  className: "studio-overlay studio-confirm-overlay",
4494
5241
  isOpen: confirmingReset,
@@ -4534,22 +5281,113 @@ function ConfigurationModalContent({ memory }) {
4534
5281
  });
4535
5282
  }
4536
5283
  function UIConfigurationModal() {
4537
- const $ = c(4);
4538
- const { isOpen, revision } = useUIConfiguration();
5284
+ const $ = c(22);
5285
+ const { isOpen, revision, open } = useUIConfiguration();
5286
+ const [minimized, setMinimized] = useState(false);
5287
+ const [hasLauncher, setHasLauncher] = useState(false);
5288
+ const restorePopout = useRef(false);
5289
+ const launcherPosition = useRef(null);
4539
5290
  let t0;
4540
5291
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
4541
- t0 = {};
5292
+ t0 = () => setMinimized(false);
4542
5293
  $[0] = t0;
4543
5294
  } else t0 = $[0];
4544
- const memory = useRef(t0);
4545
5295
  let t1;
4546
- if ($[1] !== isOpen || $[2] !== revision) {
4547
- t1 = isOpen ? /* @__PURE__ */ jsx(ConfigurationModalContent, { memory }, revision) : null;
4548
- $[1] = isOpen;
4549
- $[2] = revision;
4550
- $[3] = t1;
4551
- } else t1 = $[3];
4552
- return t1;
5296
+ if ($[1] !== revision) {
5297
+ t1 = [revision];
5298
+ $[1] = revision;
5299
+ $[2] = t1;
5300
+ } else t1 = $[2];
5301
+ useEffect(t0, t1);
5302
+ let t2;
5303
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
5304
+ t2 = {};
5305
+ $[3] = t2;
5306
+ } else t2 = $[3];
5307
+ const memory = useRef(t2);
5308
+ const windowBounds = useRef(null);
5309
+ const popout = useStudioPopout(isOpen && !minimized);
5310
+ if ((!isOpen || minimized) && hasLauncher) {
5311
+ let t3;
5312
+ if ($[4] !== isOpen || $[5] !== open || $[6] !== popout) {
5313
+ t3 = createPortal(/* @__PURE__ */ jsx(ConfigurationLauncher, {
5314
+ position: launcherPosition,
5315
+ onOpen: () => {
5316
+ setMinimized(false);
5317
+ if (!isOpen) open();
5318
+ if (restorePopout.current) popout.open();
5319
+ }
5320
+ }), document.body);
5321
+ $[4] = isOpen;
5322
+ $[5] = open;
5323
+ $[6] = popout;
5324
+ $[7] = t3;
5325
+ } else t3 = $[7];
5326
+ return t3;
5327
+ }
5328
+ if (!isOpen) return null;
5329
+ const t3 = !!popout.popup;
5330
+ let t4;
5331
+ let t5;
5332
+ let t6;
5333
+ if ($[8] !== popout) {
5334
+ t4 = () => {
5335
+ restorePopout.current = true;
5336
+ popout.open();
5337
+ };
5338
+ t5 = () => {
5339
+ restorePopout.current = false;
5340
+ popout.dock();
5341
+ };
5342
+ t6 = () => {
5343
+ restorePopout.current = !!popout.popup;
5344
+ setHasLauncher(true);
5345
+ setMinimized(true);
5346
+ popout.dock();
5347
+ };
5348
+ $[8] = popout;
5349
+ $[9] = t4;
5350
+ $[10] = t5;
5351
+ $[11] = t6;
5352
+ } else {
5353
+ t4 = $[9];
5354
+ t5 = $[10];
5355
+ t6 = $[11];
5356
+ }
5357
+ let t7;
5358
+ if ($[12] !== popout.blocked || $[13] !== revision || $[14] !== t3 || $[15] !== t4 || $[16] !== t5 || $[17] !== t6) {
5359
+ t7 = /* @__PURE__ */ jsx(ConfigurationModalContent, {
5360
+ memory,
5361
+ windowBounds,
5362
+ poppedOut: t3,
5363
+ onPopout: t4,
5364
+ onDock: t5,
5365
+ onMinimize: t6,
5366
+ popupBlocked: popout.blocked
5367
+ }, revision);
5368
+ $[12] = popout.blocked;
5369
+ $[13] = revision;
5370
+ $[14] = t3;
5371
+ $[15] = t4;
5372
+ $[16] = t5;
5373
+ $[17] = t6;
5374
+ $[18] = t7;
5375
+ } else t7 = $[18];
5376
+ const content = t7;
5377
+ let t8;
5378
+ if ($[19] !== content || $[20] !== popout.popup) {
5379
+ t8 = popout.popup ? createPortal(/* @__PURE__ */ jsx(StudioPopoutContext, {
5380
+ value: true,
5381
+ children: /* @__PURE__ */ jsx(UNSAFE_PortalProvider, {
5382
+ getContainer: () => popout.popup.document.body,
5383
+ children: content
5384
+ })
5385
+ }), popout.popup.document.body) : content;
5386
+ $[19] = content;
5387
+ $[20] = popout.popup;
5388
+ $[21] = t8;
5389
+ } else t8 = $[21];
5390
+ return t8;
4553
5391
  }
4554
5392
  //#endregion
4555
5393
  export { ColorModeSwitch, UIConfigurationModal, UIConfigurationProvider, exportCss, parseThemeCss, useUIConfiguration };