@povio/ui 5.0.0-rc.14 → 5.0.0-rc.15

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 (79) hide show
  1. package/dist/{AppCanvasPage-vta1j5YQ.js → AppCanvasPage-BnyCHO3I.js} +139 -456
  2. package/dist/{AppCanvasPage-BZ2mrKY4.d.ts → AppCanvasPage-U9SxNwjS.d.ts} +1 -1
  3. package/dist/{BottomSheet-BXLE3161.js → BottomSheet-AqYVSMK9.js} +1 -75
  4. package/dist/BottomSheetHeader-Be6Elvs2.js +79 -0
  5. package/dist/{Calendar-DRHruqr_.js → Calendar-1p3VjSED.js} +3 -3
  6. package/dist/{CanvasComponentsFrame-D6Mh_G3q.js → CanvasComponentsFrame-Dp0oDDoH.js} +6 -6
  7. package/dist/{UIConfigurator-CjAW1SJY.js → CanvasInspector-DdP3mHUY.js} +1314 -474
  8. package/dist/{ComponentGallery-CzKU899_.js → ComponentGallery-C_rXFvUY.js} +250 -1797
  9. package/dist/{DatePicker-xDEqzNJv.js → DatePicker-CAzuZRmd.js} +6 -6
  10. package/dist/{DatePickerInput-B0fEeCOf.js → DatePickerInput-BeQOVCk0.js} +4 -3
  11. package/dist/{DateRangePicker-DxuVhRaf.js → DateRangePicker-X3mBhfmL.js} +5 -5
  12. package/dist/{DateTimePicker-4N1Pka07.js → DateTimePicker-EtmGtoRe.js} +6 -6
  13. package/dist/{InputItem-Cv19Hwnx.js → InputItem-yC5oMyN-.js} +7 -7
  14. package/dist/{Inputs-D1aE_J9f.js → Inputs-Bd2nRNqk.js} +1 -1
  15. package/dist/{NumberRangeInput-Bzfe-RlV.js → NumberRangeInput-TkPXiWV3.js} +2 -2
  16. package/dist/{RichTextEditor-Bd7F5D8f.js → RichTextEditor-DiaPcBUM.js} +110 -32
  17. package/dist/{Select-CgIhoWgk.js → Select-tNlFSbAC.js} +5 -5
  18. package/dist/{Table-piX1SWvN.js → Table-CgG02oHQ.js} +1 -1
  19. package/dist/{TextArea-uPffb457.js → TextArea-DuvFUjts.js} +1 -1
  20. package/dist/{TimePicker-DN-i98z5.js → TimePicker-CBkiE-Yq.js} +5 -4
  21. package/dist/{TooltipWrapper-CDHFaUKZ.js → TooltipWrapper-CSXs5-E3.js} +2 -2
  22. package/dist/components/autocomplete.js +3 -3
  23. package/dist/components/bottom-sheet.js +1 -1
  24. package/dist/components/date-picker.js +1 -1
  25. package/dist/components/date-range-picker.js +1 -1
  26. package/dist/components/date-time-picker.js +1 -1
  27. package/dist/components/input.js +3 -3
  28. package/dist/components/number-field.js +3 -3
  29. package/dist/components/number-range-input.js +1 -1
  30. package/dist/components/query-autocomplete.js +1 -1
  31. package/dist/components/query-select.js +2 -2
  32. package/dist/components/select.js +1 -1
  33. package/dist/components/text-area.js +1 -1
  34. package/dist/components/time-picker.js +1 -1
  35. package/dist/config/app-canvas-tanstack.d.ts +1 -1
  36. package/dist/config/app-canvas-tanstack.js +1 -1
  37. package/dist/config/app-canvas.d.ts +1 -1
  38. package/dist/config/app-canvas.js +1 -1
  39. package/dist/config/ui-configurator.d.ts +21 -2
  40. package/dist/config/ui-configurator.js +121 -3
  41. package/dist/{datePickerValue.utils-QWR2q5Vv.js → datePickerValue.utils-BDB6KM8q.js} +1 -1
  42. package/dist/demos-DIwj5vc0.js +2011 -0
  43. package/dist/index.js +7 -7
  44. package/dist/{logger-CqZjM-sn.js → logger-CW24po62.js} +10 -1
  45. package/dist/rhf/date-picker.js +1 -1
  46. package/dist/rhf/date-range-picker.js +1 -1
  47. package/dist/rhf/date-time-picker.js +1 -1
  48. package/dist/rhf/number-range-input.js +1 -1
  49. package/dist/rhf/rich-text-editor.js +1 -1
  50. package/dist/rhf/select.js +1 -1
  51. package/dist/rhf/text-area.js +1 -1
  52. package/dist/rhf/time-picker.js +1 -1
  53. package/dist/rhf.js +7 -7
  54. package/dist/rich-text-editor.js +1 -1
  55. package/dist/{staticDateTimeSegments-BWea3HAt.js → staticDateTimeSegments-Bs1_N5MR.js} +1 -1
  56. package/dist/{staticSelect.utils-BfTCi26B.js → staticSelect.utils-BgdYv2vP.js} +5 -4
  57. package/dist/styles/app-canvas.css +30 -24
  58. package/dist/styles/configurator.css +342 -34
  59. package/dist/tanstack/date-picker.js +1 -1
  60. package/dist/tanstack/date-range-picker.js +1 -1
  61. package/dist/tanstack/date-time-picker.js +1 -1
  62. package/dist/tanstack/form.js +1 -1
  63. package/dist/tanstack/inputs.js +1 -1
  64. package/dist/tanstack/number-range-input.js +1 -1
  65. package/dist/tanstack/rich-text-editor.js +1 -1
  66. package/dist/tanstack/select.js +1 -1
  67. package/dist/tanstack/table.js +2 -2
  68. package/dist/tanstack/text-area.js +1 -1
  69. package/dist/tanstack/time-picker.js +1 -1
  70. package/dist/tanstack.js +15 -15
  71. package/dist/token-classes-BqLWiy6O.js +245 -0
  72. package/dist/{useFieldAccessibility-B-bjtrNw.js → useFieldAccessibility-DnCdz938.js} +2 -1
  73. package/dist/{useFormAutosave-pmh35PXp.js → useFormAutosave-CxqZAJAB.js} +1 -1
  74. package/dist/{useStaticInputHandoff-B7DEm75m.js → useStaticInputHandoff-DKsxpVck.js} +2 -1
  75. package/dist/{useTableColumnConfig-CNJ_ZvIN.js → useTableColumnConfig-BnbKElno.js} +1 -1
  76. package/dist/utils/logger.js +1 -1
  77. package/package.json +1 -1
  78. package/dist/groups-oQmSeqXn.js +0 -18
  79. package/dist/underline-66hmELxa.js +0 -81
@@ -23,7 +23,7 @@ import { a as $928221da08ecbc62$export$dca12b0bb56e4fc, i as $928221da08ecbc62$e
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";
25
25
  import { n as switchDefinition, t as Switch } from "./Switch-CqnGEdeD.js";
26
- import { n as textAreaWrapperDefinition, t as TextArea } from "./TextArea-uPffb457.js";
26
+ import { n as textAreaWrapperDefinition, t as TextArea } from "./TextArea-DuvFUjts.js";
27
27
  import { a as breadcrumbsDefinition, i as breadcrumbSegmentDefinition, n as breadcrumbIconDefinition, r as breadcrumbItemDefinition, t as breadcrumbChevronDefinition } from "./breadcrumbs.cva-7zzdDhVR.js";
28
28
  import { i as menuPopoverWrapperDefinition, n as menuItemDefinition, r as menuPopoverDefinition, t as dropdownMenuDefinition } from "./dropdownMenu.cva-DvEmX0bs.js";
29
29
  import { i as tooltipTextDefinition, n as tooltipPointerHorizontalDefinition, r as tooltipPointerVerticalDefinition, t as tooltipDefinition } from "./tooltip.cva-BIzlOXHH.js";
@@ -50,6 +50,7 @@ import { a as tableHeaderTextDefinition, i as tableHeadRowDefinition, n as table
50
50
  import { t as linkDefinition } from "./link.cva-DMTHZiJG.js";
51
51
  import { t as tooltipWrapperTriggerDefinition } from "./tooltipWrapper.cva-BBQ4ic3D.js";
52
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 { n as splitVariants, r as variantState, t as inspectTokens } from "./token-classes-BqLWiy6O.js";
53
54
  import $ahdqC$react, { Fragment, Suspense, createContext, lazy, use, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
54
55
  import { c } from "react/compiler-runtime";
55
56
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -696,7 +697,7 @@ function UIConfigurationProvider(t0) {
696
697
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
697
698
  t1 = () => {
698
699
  setComponentHosts(_temp$8);
699
- return () => setComponentHosts(_temp2$5);
700
+ return () => setComponentHosts(_temp2$6);
700
701
  };
701
702
  $[0] = t1;
702
703
  } else t1 = $[0];
@@ -710,7 +711,7 @@ function UIConfigurationProvider(t0) {
710
711
  setApplied(structuredClone(value));
711
712
  setDraft(structuredClone(value));
712
713
  setPreviewConfiguration(null);
713
- if (remount) setRevision(_temp3$4);
714
+ if (remount) setRevision(_temp3$5);
714
715
  };
715
716
  $[1] = t2;
716
717
  } else t2 = $[1];
@@ -889,10 +890,10 @@ function _temp5$3(value_1) {
889
890
  function _temp4$4(value_0) {
890
891
  return value_0 + 1;
891
892
  }
892
- function _temp3$4(current) {
893
+ function _temp3$5(current) {
893
894
  return current + 1;
894
895
  }
895
- function _temp2$5(count_0) {
896
+ function _temp2$6(count_0) {
896
897
  return count_0 - 1;
897
898
  }
898
899
  function _temp$8(count) {
@@ -1337,7 +1338,7 @@ function InspectorDetails(t0) {
1337
1338
  $[13] = onSelect;
1338
1339
  $[14] = t6;
1339
1340
  } else t6 = $[14];
1340
- t5 = snapshot.groups.map(_temp$7).filter(_temp2$4).map(t6);
1341
+ t5 = snapshot.groups.map(_temp$7).filter(_temp2$5).map(t6);
1341
1342
  $[10] = onSelect;
1342
1343
  $[11] = snapshot.groups;
1343
1344
  $[12] = t5;
@@ -1351,7 +1352,7 @@ function InspectorDetails(t0) {
1351
1352
  } else t6 = $[17];
1352
1353
  return t6;
1353
1354
  }
1354
- function _temp2$4(group_0) {
1355
+ function _temp2$5(group_0) {
1355
1356
  return group_0.properties.length;
1356
1357
  }
1357
1358
  function _temp$7(group) {
@@ -1562,9 +1563,9 @@ function _temp5$2(group) {
1562
1563
  return group.properties;
1563
1564
  }
1564
1565
  function _temp4$3(value) {
1565
- return value.replace(/(-?\d*\.?\d+)px/g, _temp3$3);
1566
+ return value.replace(/(-?\d*\.?\d+)px/g, _temp3$4);
1566
1567
  }
1567
- function _temp3$3(_, amount) {
1568
+ function _temp3$4(_, amount) {
1568
1569
  return String(Math.round(Number(amount) * 10) / 10);
1569
1570
  }
1570
1571
  //#endregion
@@ -1834,236 +1835,6 @@ function getBoxHighlights(element, key) {
1834
1835
  };
1835
1836
  }
1836
1837
  //#endregion
1837
- //#region src/configurator/inspector/token-classes.ts
1838
- /** Tailwind breakpoints from the Atlas base theme, in rem. */
1839
- const breakpoints = {
1840
- sm: 23.75,
1841
- md: 37.5,
1842
- lg: 80,
1843
- xl: 105
1844
- };
1845
- /** Utility prefix → the slots it sets, its specificity, and the theme namespace its value lives in. */
1846
- const utilities = [
1847
- [
1848
- "p",
1849
- [
1850
- "padding.top",
1851
- "padding.right",
1852
- "padding.bottom",
1853
- "padding.left"
1854
- ],
1855
- 0,
1856
- "spacing"
1857
- ],
1858
- [
1859
- "px",
1860
- ["padding.left", "padding.right"],
1861
- 1,
1862
- "spacing"
1863
- ],
1864
- [
1865
- "py",
1866
- ["padding.top", "padding.bottom"],
1867
- 1,
1868
- "spacing"
1869
- ],
1870
- [
1871
- "pt",
1872
- ["padding.top"],
1873
- 2,
1874
- "spacing"
1875
- ],
1876
- [
1877
- "pr",
1878
- ["padding.right"],
1879
- 2,
1880
- "spacing"
1881
- ],
1882
- [
1883
- "pe",
1884
- ["padding.right"],
1885
- 2,
1886
- "spacing"
1887
- ],
1888
- [
1889
- "pb",
1890
- ["padding.bottom"],
1891
- 2,
1892
- "spacing"
1893
- ],
1894
- [
1895
- "pl",
1896
- ["padding.left"],
1897
- 2,
1898
- "spacing"
1899
- ],
1900
- [
1901
- "ps",
1902
- ["padding.left"],
1903
- 2,
1904
- "spacing"
1905
- ],
1906
- [
1907
- "gap",
1908
- ["gap.row", "gap.column"],
1909
- 0,
1910
- "spacing"
1911
- ],
1912
- [
1913
- "gap-x",
1914
- ["gap.column"],
1915
- 1,
1916
- "spacing"
1917
- ],
1918
- [
1919
- "gap-y",
1920
- ["gap.row"],
1921
- 1,
1922
- "spacing"
1923
- ],
1924
- [
1925
- "rounded",
1926
- ["radius"],
1927
- 0,
1928
- "radius"
1929
- ]
1930
- ];
1931
- /** Splits `md:hover:px-4` into its variants and utility, ignoring colons inside `[...]` / `(...)`. */
1932
- function splitVariants(className) {
1933
- const parts = [];
1934
- let depth = 0;
1935
- let current = "";
1936
- for (const char of className) {
1937
- if (char === "[" || char === "(") depth++;
1938
- if (char === "]" || char === ")") depth--;
1939
- if (char === ":" && depth === 0) {
1940
- parts.push(current);
1941
- current = "";
1942
- } else current += char;
1943
- }
1944
- return {
1945
- variants: parts,
1946
- utility: current
1947
- };
1948
- }
1949
- /** Variants that style a pseudo-element or other elements, never the element's own value. */
1950
- const otherTargets = /* @__PURE__ */ new Set([
1951
- "placeholder",
1952
- "before",
1953
- "after",
1954
- "selection",
1955
- "marker",
1956
- "file",
1957
- "first-letter",
1958
- "first-line",
1959
- "backdrop",
1960
- "*",
1961
- "**"
1962
- ]);
1963
- const stateSelectors = {
1964
- hover: ":hover",
1965
- focus: ":focus",
1966
- "focus-within": ":focus-within",
1967
- "focus-visible": ":focus-visible",
1968
- active: ":active",
1969
- disabled: ":disabled",
1970
- enabled: ":enabled",
1971
- checked: ":checked",
1972
- indeterminate: ":indeterminate",
1973
- invalid: ":invalid",
1974
- valid: ":valid",
1975
- required: ":required",
1976
- optional: ":optional",
1977
- "read-only": ":read-only",
1978
- "placeholder-shown": ":placeholder-shown",
1979
- empty: ":empty",
1980
- open: ":is([open], :popover-open, :open)",
1981
- first: ":first-child",
1982
- last: ":last-child",
1983
- only: ":only-child",
1984
- odd: ":nth-child(odd)",
1985
- even: ":nth-child(even)"
1986
- };
1987
- /** A CSS selector for one state variant, or `undefined` when its condition cannot be read from the element. */
1988
- function variantSelector(variant) {
1989
- if (variant.startsWith("not-")) {
1990
- const inner = variantSelector(variant.slice(4));
1991
- return inner && `:not(${inner})`;
1992
- }
1993
- if (variant.startsWith("has-")) {
1994
- const inner = variantSelector(variant.slice(4));
1995
- return inner && `:has(${inner})`;
1996
- }
1997
- if (stateSelectors[variant]) return stateSelectors[variant];
1998
- if (variant.startsWith("aria-") && !variant.includes("[")) return `[aria-${variant.slice(5)}="true"]`;
1999
- const arbitrary = variant.match(/^\[(&?)(:[^\s&>+~,]+)\]$/);
2000
- return arbitrary ? arbitrary[2].replaceAll("_", " ") : void 0;
2001
- }
2002
- /**
2003
- * How a variant class relates to an element's current value: `other` styles a pseudo-element or descendants,
2004
- * `inactive` / `active` are state conditions read from the element, and `unknown` covers breakpoints, container
2005
- * queries, group/peer state and anything else that cannot be checked from the element alone.
2006
- */
2007
- function variantState(variants, element) {
2008
- if (variants.some((variant) => otherTargets.has(variant))) return "other";
2009
- const selectors = variants.map(variantSelector);
2010
- if (selectors.some((selector) => selector === void 0) || typeof element.matches !== "function") return "unknown";
2011
- try {
2012
- return element.matches(`*${selectors.join("")}`) ? "active" : "inactive";
2013
- } catch {
2014
- return "unknown";
2015
- }
2016
- }
2017
- /** Breakpoint weight when every variant is an active breakpoint; `undefined` for state variants or inactive breakpoints. */
2018
- function variantWeight(variants, viewportWidth, rootFontSize) {
2019
- let weight = 0;
2020
- for (const variant of variants) {
2021
- const max = variant.startsWith("max-");
2022
- const size = breakpoints[max ? variant.slice(4) : variant];
2023
- if (size === void 0) return void 0;
2024
- if (!(max ? viewportWidth < size * rootFontSize : viewportWidth >= size * rootFontSize)) return void 0;
2025
- weight = Math.max(weight, size);
2026
- }
2027
- return weight;
2028
- }
2029
- function tokenFor(value, namespace, isKnown) {
2030
- const referenced = value.match(/^\[.*?var\((--[\w-]+)/)?.[1] ?? value.match(/^\((--[\w-]+)\)$/)?.[1];
2031
- if (referenced) return isKnown(referenced) ? referenced : void 0;
2032
- const name = `--${namespace}-${value}`;
2033
- return isKnown(name) ? name : void 0;
2034
- }
2035
- /**
2036
- * Resolves which theme tokens drive an element's padding, gap and radius from its rendered Tailwind classes.
2037
- * Only tokens accepted by `isKnown` are returned, so every result can be opened in the editor.
2038
- */
2039
- function inspectTokens(className, isKnown, viewportWidth = Infinity, rootFontSize = 16) {
2040
- const winners = /* @__PURE__ */ new Map();
2041
- for (const raw of className.split(/\s+/).filter(Boolean)) {
2042
- const { variants, utility } = splitVariants(raw);
2043
- const weight = variantWeight(variants, viewportWidth, rootFontSize);
2044
- if (weight === void 0) continue;
2045
- const clean = utility.replace(/^!|!$/g, "");
2046
- for (const [prefix, slots, specificity, namespace] of utilities) {
2047
- if (!clean.startsWith(`${prefix}-`)) continue;
2048
- const token = tokenFor(clean.slice(prefix.length + 1), namespace, isKnown);
2049
- if (!token) continue;
2050
- const rank = weight * 10 + specificity;
2051
- for (const slot of slots) if ((winners.get(slot)?.rank ?? -1) <= rank) winners.set(slot, {
2052
- token,
2053
- rank
2054
- });
2055
- }
2056
- }
2057
- const result = {
2058
- padding: {},
2059
- gap: {}
2060
- };
2061
- for (const [slot, { token }] of winners) if (slot === "radius") result.radius = token;
2062
- else if (slot.startsWith("gap.")) result.gap[slot.slice(4)] = token;
2063
- else result.padding[slot.slice(8)] = token;
2064
- return result;
2065
- }
2066
- //#endregion
2067
1838
  //#region src/configurator/inspector/inspection-model.ts
2068
1839
  function readableColor(value) {
2069
1840
  const rgb = value.trim().match(/^rgb\(\s*(\d+)\s*[, ]\s*(\d+)\s*[, ]\s*(\d+)\s*\)$/);
@@ -2250,8 +2021,9 @@ function inspectElement(element, isKnown) {
2250
2021
  if (row.label === "Display" && ["inline", "block"].includes(value)) return false;
2251
2022
  if (row.label === "Shadow" && value === "none") return false;
2252
2023
  if (row.label === "Opacity" && Number(value) === 1) return false;
2253
- if (row.label === "Fill" && (value === "transparent" || /^rgba?\([^)]*[,/]\s*0(?:\.0+)?%?\s*\)$/.test(value))) return false;
2254
- if (row.label === "Border" && !(Number.parseFloat(border.top) > 0)) return false;
2024
+ const transparent = value === "transparent" || /^rgba?\([^)]*[,/]\s*0(?:\.0+)?%?\s*\)$/.test(value);
2025
+ if (row.label === "Fill" && transparent) return false;
2026
+ if (row.label === "Border" && (transparent || !(Number.parseFloat(border.top) > 0))) return false;
2255
2027
  if (row.label === "Line height" && value === "normal") return false;
2256
2028
  if (row.label === "Letter spacing" && (value === "normal" || isZero(value))) return false;
2257
2029
  if (row.label === "Alignment" && [
@@ -2977,7 +2749,7 @@ function CvaPreview(t0) {
2977
2749
  component = slot.split(".")[0];
2978
2750
  const props = {
2979
2751
  ...definition?.config.defaultVariants,
2980
- ...Object.fromEntries(Object.entries(variants).filter(_temp$6).map(_temp2$3))
2752
+ ...Object.fromEntries(Object.entries(variants).filter(_temp$6).map(_temp2$4))
2981
2753
  };
2982
2754
  const classes = (key, t4) => {
2983
2755
  const extra = t4 === void 0 ? {} : t4;
@@ -3108,7 +2880,7 @@ function CvaPreview(t0) {
3108
2880
  sample = /* @__PURE__ */ jsx("a", {
3109
2881
  className: exact,
3110
2882
  href: "#preview",
3111
- onClick: _temp3$2,
2883
+ onClick: _temp3$3,
3112
2884
  children: "Example link"
3113
2885
  });
3114
2886
  break bb0;
@@ -3739,10 +3511,10 @@ function CvaPreview(t0) {
3739
3511
  function _temp4$2(value_2) {
3740
3512
  return /* @__PURE__ */ jsx("option", { children: value_2 }, value_2);
3741
3513
  }
3742
- function _temp3$2(event_1) {
3514
+ function _temp3$3(event_1) {
3743
3515
  return event_1.preventDefault();
3744
3516
  }
3745
- function _temp2$3(t0) {
3517
+ function _temp2$4(t0) {
3746
3518
  const [name, value_0] = t0;
3747
3519
  return [name, value_0 === "true" ? true : value_0 === "false" ? false : value_0];
3748
3520
  }
@@ -3954,7 +3726,7 @@ function CvaEditor(t0) {
3954
3726
  let update;
3955
3727
  if ($[2] !== component || $[3] !== draft.overrides || $[4] !== inheritedOverrides || $[5] !== setDraft || $[6] !== setSlot || $[7] !== slot) {
3956
3728
  slots = Object.keys(cvaDefinitions);
3957
- const components = [...new Set(slots.map(_temp2$2))];
3729
+ const components = [...new Set(slots.map(_temp2$3))];
3958
3730
  let t10;
3959
3731
  if ($[20] !== inheritedOverrides || $[21] !== slot) {
3960
3732
  t10 = resolveCvaDefinition(slot, inheritedOverrides);
@@ -3997,7 +3769,7 @@ function CvaEditor(t0) {
3997
3769
  const next_0 = event.target.value;
3998
3770
  setSlot(slots.find((key_0) => key_0.startsWith(`${next_0}.`)));
3999
3771
  };
4000
- t5 = components.map(_temp3$1);
3772
+ t5 = components.map(_temp3$2);
4001
3773
  $[2] = component;
4002
3774
  $[3] = draft.overrides;
4003
3775
  $[4] = inheritedOverrides;
@@ -4252,13 +4024,13 @@ function _temp4$1(key_2) {
4252
4024
  children: title(key_2.split(".")[1])
4253
4025
  }, key_2);
4254
4026
  }
4255
- function _temp3$1(name) {
4027
+ function _temp3$2(name) {
4256
4028
  return /* @__PURE__ */ jsx("option", {
4257
4029
  value: name,
4258
4030
  children: title(name)
4259
4031
  }, name);
4260
4032
  }
4261
- function _temp2$2(key) {
4033
+ function _temp2$3(key) {
4262
4034
  return key.split(".")[0];
4263
4035
  }
4264
4036
  //#endregion
@@ -4957,7 +4729,7 @@ function PaletteSelect(t0) {
4957
4729
  } else t6 = $[36];
4958
4730
  let t7;
4959
4731
  if ($[37] !== options) {
4960
- t7 = paletteFamilies(options).map(_temp2$1);
4732
+ t7 = paletteFamilies(options).map(_temp2$2);
4961
4733
  $[37] = options;
4962
4734
  $[38] = t7;
4963
4735
  } else t7 = $[38];
@@ -4977,6 +4749,7 @@ function PaletteSelect(t0) {
4977
4749
  if ($[40] !== t7) {
4978
4750
  t9 = /* @__PURE__ */ jsx($542a13ca2fa5b484$export$5b6b19405a83ff9d, {
4979
4751
  className: "studio-palette-popover",
4752
+ "data-povio-inspector-ignore": "",
4980
4753
  placement: "bottom end",
4981
4754
  children: /* @__PURE__ */ jsxs($928221da08ecbc62$export$41f133550aa26f48, {
4982
4755
  className: "studio-palette-list",
@@ -5008,7 +4781,7 @@ function PaletteSelect(t0) {
5008
4781
  } else t10 = $[49];
5009
4782
  return t10;
5010
4783
  }
5011
- function _temp2$1(t0) {
4784
+ function _temp2$2(t0) {
5012
4785
  const { family: name_0, steps: steps_0 } = t0;
5013
4786
  return /* @__PURE__ */ jsxs($928221da08ecbc62$export$dca12b0bb56e4fc, {
5014
4787
  id: name_0,
@@ -5216,7 +4989,7 @@ function useLoadedFonts() {
5216
4989
  document.fonts.ready.then(() => {
5217
4990
  if (!active) return;
5218
4991
  const root = getComputedStyle(document.documentElement);
5219
- const families = [...new Set([...document.fonts].map(_temp2))].filter(_temp3);
4992
+ const families = [...new Set([...document.fonts].map(_temp2$1))].filter(_temp3$1);
5220
4993
  setFonts(families.map((family_0) => {
5221
4994
  const base = `--font-${family_0.split(/\s+/)[0].toLowerCase()}-base`;
5222
4995
  const value_0 = unquote(root.getPropertyValue(base)) === family_0 ? `var(${base}), sans-serif` : `"${family_0}", sans-serif`;
@@ -5251,10 +5024,10 @@ function useLoadedFonts() {
5251
5024
  return t4;
5252
5025
  }
5253
5026
  /** Families added through the upload button in this page session. */
5254
- function _temp3(family) {
5027
+ function _temp3$1(family) {
5255
5028
  return !family.startsWith("Povio Fontsource preview ");
5256
5029
  }
5257
- function _temp2(face) {
5030
+ function _temp2$1(face) {
5258
5031
  return unquote(face.family);
5259
5032
  }
5260
5033
  function _temp$2(value) {
@@ -5859,214 +5632,819 @@ function isPresetActive(preset, defaults, current) {
5859
5632
  return Object.keys(a).length === Object.keys(b).length && Object.entries(a).every(([name, value]) => b[name] === value);
5860
5633
  });
5861
5634
  }
5862
- //#endregion
5863
- //#region src/configurator/ShadesGenerator.tsx
5635
+ const defaultShadeCurve = {
5636
+ hue: 0,
5637
+ saturation: 100,
5638
+ start: .985,
5639
+ end: .16,
5640
+ startHandle: {
5641
+ x: 1 / 3,
5642
+ y: .985
5643
+ },
5644
+ endHandle: {
5645
+ x: 2 / 3,
5646
+ y: .16
5647
+ },
5648
+ pins: {},
5649
+ basePinned: false
5650
+ };
5651
+ const toLinear = (channel) => {
5652
+ const c = channel / 255;
5653
+ return c <= .04045 ? c / 12.92 : ((c + .055) / 1.055) ** 2.4;
5654
+ };
5655
+ const toGamma = (channel) => {
5656
+ return (channel <= .0031308 ? 12.92 * channel : 1.055 * channel ** (1 / 2.4) - .055) * 255;
5657
+ };
5658
+ /** sRGB channels (0–255) to OKLCH: lightness 0–1, chroma, hue in degrees. */
5659
+ function rgbToOklch([red, green, blue]) {
5660
+ const [r, g, b] = [
5661
+ red,
5662
+ green,
5663
+ blue
5664
+ ].map((value) => toLinear(value ?? 0));
5665
+ const l = Math.cbrt(.4122214708 * r + .5363325363 * g + .0514459929 * b);
5666
+ const m = Math.cbrt(.2119034982 * r + .6806995451 * g + .1073969566 * b);
5667
+ const s = Math.cbrt(.0883024619 * r + .2817188376 * g + .6299787005 * b);
5668
+ const lightness = .2104542553 * l + .793617785 * m - .0040720468 * s;
5669
+ const a = 1.9779984951 * l - 2.428592205 * m + .4505937099 * s;
5670
+ const bAxis = .0259040371 * l + .7827717662 * m - .808675766 * s;
5671
+ return [
5672
+ lightness,
5673
+ Math.hypot(a, bAxis),
5674
+ (Math.atan2(bAxis, a) * 180 / Math.PI + 360) % 360
5675
+ ];
5676
+ }
5677
+ function oklchToRgb(lightness, chroma, hue) {
5678
+ const angle = hue * Math.PI / 180;
5679
+ const a = chroma * Math.cos(angle);
5680
+ const b = chroma * Math.sin(angle);
5681
+ const l = (lightness + .3963377774 * a + .2158037573 * b) ** 3;
5682
+ const m = (lightness - .1055613458 * a - .0638541728 * b) ** 3;
5683
+ const s = (lightness - .0894841775 * a - 1.291485548 * b) ** 3;
5684
+ return [
5685
+ 4.0767416621 * l - 3.3077115913 * m + .2309699292 * s,
5686
+ -1.2684380046 * l + 2.6097574011 * m - .3413193965 * s,
5687
+ -.0041960863 * l - .7034186147 * m + 1.707614701 * s
5688
+ ].map(toGamma);
5689
+ }
5690
+ const inGamut = (channels) => channels.every((value) => value >= -.5 && value <= 255.5);
5691
+ /** The color at this lightness and hue, keeping as much of the chroma as sRGB can show. */
5692
+ function fitToGamut(lightness, chroma, hue) {
5693
+ const exact = oklchToRgb(lightness, chroma, hue);
5694
+ if (inGamut(exact)) return exact;
5695
+ let low = 0;
5696
+ let high = chroma;
5697
+ for (let i = 0; i < 20; i++) {
5698
+ const middle = (low + high) / 2;
5699
+ if (inGamut(oklchToRgb(lightness, middle, hue))) low = middle;
5700
+ else high = middle;
5701
+ }
5702
+ return oklchToRgb(lightness, low, hue);
5703
+ }
5704
+ const toChannels = (channels) => channels.map((value) => Math.max(0, Math.min(255, Math.round(value)))).join(" ");
5705
+ const clamp$1 = (value, low, high) => Math.max(low, Math.min(high, value));
5706
+ /** The base color with the curve's Hue and Saturation applied: the hue and chroma every shade takes. */
5707
+ function adjustBase(baseRgb, curve) {
5708
+ const [lightness, chroma, hue] = rgbToOklch(baseRgb.split(/\s+/).map(Number));
5709
+ return toChannels(fitToGamut(lightness, chroma * curve.saturation / 100, (hue + curve.hue + 360) % 360));
5710
+ }
5711
+ /** Where each step sits on the curve's x axis, lightest first. */
5712
+ const stepPosition = (index, count) => count > 1 ? index / (count - 1) : 0;
5864
5713
  /**
5865
- * Generates a whole base palette scale from one color, which becomes its 500 step.
5714
+ * The curve as cubic bezier segments between its fixed points: the two ends and every pin. The end handles shape the
5715
+ * first and last segment; pins get smooth, monotone tangents so the curve never overshoots between them.
5866
5716
  */
5867
- function ShadesGenerator(t0) {
5868
- const $ = c(52);
5869
- const { title, steps, initial, onApply } = t0;
5717
+ function curveSegments(curve, steps, baseLightness) {
5718
+ const ordered = [...steps].sort((a, b) => a - b);
5719
+ const count = ordered.length;
5720
+ const fixed = [{
5721
+ x: 0,
5722
+ y: curve.start
5723
+ }, {
5724
+ x: 1,
5725
+ y: curve.end
5726
+ }];
5727
+ ordered.forEach((step, index) => {
5728
+ if (index === 0 || index === count - 1) return;
5729
+ const x = stepPosition(index, count);
5730
+ if (step === 500 && curve.basePinned) fixed.push({
5731
+ x,
5732
+ y: baseLightness
5733
+ });
5734
+ else if (curve.pins[step] !== void 0) fixed.push({
5735
+ x,
5736
+ y: curve.pins[step]
5737
+ });
5738
+ });
5739
+ fixed.sort((a, b) => a.x - b.x);
5740
+ const slopes = fixed.slice(1).map((point, k) => (point.y - fixed[k].y) / (point.x - fixed[k].x));
5741
+ const tangent = (k) => {
5742
+ const before = slopes[k - 1];
5743
+ const after = slopes[k];
5744
+ if (Math.sign(before) !== Math.sign(after) || before === 0 || after === 0) return 0;
5745
+ const average = (before + after) / 2;
5746
+ const limit = 3 * Math.min(Math.abs(before), Math.abs(after));
5747
+ return Math.sign(average) * Math.min(Math.abs(average), limit);
5748
+ };
5749
+ const fromHandle = (anchor, handle, width, sign) => {
5750
+ const reach = Math.abs(handle.x - anchor.x);
5751
+ const scale = Math.min(1, width * .9 / Math.max(reach, 1e-6));
5752
+ return {
5753
+ x: anchor.x + sign * reach * scale,
5754
+ y: anchor.y + (handle.y - anchor.y) * scale
5755
+ };
5756
+ };
5757
+ const last = fixed.length - 2;
5758
+ return fixed.slice(0, -1).map((from, k) => {
5759
+ const to = fixed[k + 1];
5760
+ const width = to.x - from.x;
5761
+ return [
5762
+ from,
5763
+ k === 0 ? fromHandle(from, curve.startHandle, width, 1) : {
5764
+ x: from.x + width / 3,
5765
+ y: from.y + tangent(k) * width / 3
5766
+ },
5767
+ k === last ? fromHandle(to, curve.endHandle, width, -1) : {
5768
+ x: to.x - width / 3,
5769
+ y: to.y - tangent(k + 1) * width / 3
5770
+ },
5771
+ to
5772
+ ];
5773
+ });
5774
+ }
5775
+ const bezier = ([p0, p1, p2, p3], t) => {
5776
+ const u = 1 - t;
5777
+ return {
5778
+ x: u * u * u * p0.x + 3 * u * u * t * p1.x + 3 * u * t * t * p2.x + t * t * t * p3.x,
5779
+ y: u * u * u * p0.y + 3 * u * u * t * p1.y + 3 * u * t * t * p2.y + t * t * t * p3.y
5780
+ };
5781
+ };
5782
+ /** The curve's lightness at `x`, clamped to 0–1 so no shade passes white or black. */
5783
+ function curveLightness(segments, x) {
5784
+ const segment = segments.find((item) => x <= item[3].x + 1e-9) ?? segments.at(-1);
5785
+ let low = 0;
5786
+ let high = 1;
5787
+ for (let i = 0; i < 40; i++) {
5788
+ const middle = (low + high) / 2;
5789
+ if (bezier(segment, middle).x < x) low = middle;
5790
+ else high = middle;
5791
+ }
5792
+ return clamp$1(bezier(segment, (low + high) / 2).y, 0, 1);
5793
+ }
5794
+ /** The lightness of every step on the curve, pins included, keyed by step. */
5795
+ function curveStepLightness(curve, steps, baseLightness) {
5796
+ const ordered = [...steps].sort((a, b) => a - b);
5797
+ const segments = curveSegments(curve, ordered, baseLightness);
5798
+ return Object.fromEntries(ordered.map((step, index) => [step, step === 500 && curve.basePinned ? baseLightness : curve.pins[step] ?? curveLightness(segments, stepPosition(index, ordered.length))]));
5799
+ }
5800
+ /** Generates a palette's RGB channel values from its base color and lightness curve, keyed by step. */
5801
+ function generateCurveShades(baseRgb, steps, curve) {
5802
+ const [baseLightness, baseChroma, baseHue] = rgbToOklch(baseRgb.split(/\s+/).map(Number));
5803
+ const ordered = [...steps].sort((a, b) => a - b);
5804
+ const lightness = curveStepLightness(curve, ordered, baseLightness);
5805
+ const hue = (baseHue + curve.hue + 360) % 360;
5806
+ const chroma = baseChroma * curve.saturation / 100;
5807
+ return Object.fromEntries(ordered.map((step, index) => {
5808
+ const taper = 1 - .55 * (Math.abs(stepPosition(index, ordered.length) - .5) * 2) ** 1.6;
5809
+ return [step, toChannels(fitToGamut(lightness[step], chroma * taper, hue))];
5810
+ }));
5811
+ }
5812
+ //#endregion
5813
+ //#region src/configurator/ShadesGenerator.tsx
5814
+ const colorRows = [{
5815
+ field: "hue",
5816
+ label: "Hue",
5817
+ min: -180,
5818
+ max: 180,
5819
+ step: 1,
5820
+ unit: "°"
5821
+ }, {
5822
+ field: "saturation",
5823
+ label: "Saturation",
5824
+ min: 0,
5825
+ max: 300,
5826
+ step: 1,
5827
+ unit: "%"
5828
+ }];
5829
+ /** A Figma-style slider field: label and value in a 24px field filled to the value; drag or use arrow keys. */
5830
+ function SliderField(t0) {
5831
+ const $ = c(25);
5832
+ const { label, value, min, max, step, display, disabled, onChange } = t0;
5833
+ const origin = min < 0 ? 0 : min;
5870
5834
  let t1;
5871
- if ($[0] !== initial) {
5872
- t1 = isRgb(initial) ? toHex(initial).slice(1).toUpperCase() : "";
5873
- $[0] = initial;
5874
- $[1] = t1;
5875
- } else t1 = $[1];
5876
- const [text, setText] = useState(t1);
5877
- let base;
5878
- let pending;
5879
- let shades;
5880
- let t10;
5881
- let t2;
5882
- let t3;
5835
+ if ($[0] !== max || $[1] !== min) {
5836
+ t1 = (amount) => (amount - min) / (max - min) * 100;
5837
+ $[0] = max;
5838
+ $[1] = min;
5839
+ $[2] = t1;
5840
+ } else t1 = $[2];
5841
+ const percent = t1;
5842
+ const from = Math.min(percent(origin), percent(value));
5843
+ const to = Math.max(percent(origin), percent(value));
5844
+ const t2 = `${from}%`;
5845
+ const t3 = `${to}%`;
5883
5846
  let t4;
5884
- let t5;
5847
+ if ($[3] !== t2 || $[4] !== t3) {
5848
+ t4 = {
5849
+ "--from": t2,
5850
+ "--to": t3
5851
+ };
5852
+ $[3] = t2;
5853
+ $[4] = t3;
5854
+ $[5] = t4;
5855
+ } else t4 = $[5];
5856
+ const t5 = t4;
5885
5857
  let t6;
5858
+ if ($[6] !== label) {
5859
+ t6 = /* @__PURE__ */ jsx("span", { children: label });
5860
+ $[6] = label;
5861
+ $[7] = t6;
5862
+ } else t6 = $[7];
5886
5863
  let t7;
5864
+ if ($[8] !== display) {
5865
+ t7 = /* @__PURE__ */ jsx("output", { children: display });
5866
+ $[8] = display;
5867
+ $[9] = t7;
5868
+ } else t7 = $[9];
5887
5869
  let t8;
5870
+ if ($[10] !== onChange) {
5871
+ t8 = (event) => onChange(Number(event.target.value));
5872
+ $[10] = onChange;
5873
+ $[11] = t8;
5874
+ } else t8 = $[11];
5888
5875
  let t9;
5889
- if ($[2] !== initial || $[3] !== steps || $[4] !== text || $[5] !== title) {
5890
- const hex = text.trim().replace(/^#/, "");
5891
- base = /^[0-9a-f]{6}$/i.test(hex) ? toRgb(`#${hex}`) : /^[0-9a-f]{3}$/i.test(hex) ? toRgb(`#${hex.replace(/./g, "$&$&")}`) : null;
5892
- shades = base ? generateShades(base, steps.map(_temp$1)) : null;
5893
- pending = !!shades && base !== initial;
5894
- t8 = "studio-shades";
5895
- t9 = "group";
5896
- t10 = `Generate ${title} shades`;
5897
- t5 = "studio-shades-input";
5898
- const t11 = `shades-${title}`;
5899
- if ($[18] !== t11) {
5900
- t6 = /* @__PURE__ */ jsx("label", {
5901
- htmlFor: t11,
5902
- children: "Base color (500)"
5903
- });
5904
- $[18] = t11;
5905
- $[19] = t6;
5906
- } else t6 = $[19];
5907
- let t12;
5908
- if ($[20] === Symbol.for("react.memo_cache_sentinel")) {
5909
- t12 = /* @__PURE__ */ jsx("span", {
5910
- "aria-hidden": "true",
5911
- children: "#"
5912
- });
5913
- $[20] = t12;
5914
- } else t12 = $[20];
5915
- const t13 = `shades-${title}`;
5916
- const t14 = !base;
5917
- let t15;
5918
- if ($[21] === Symbol.for("react.memo_cache_sentinel")) {
5919
- t15 = (event) => setText(event.target.value.replace(/^#/, ""));
5920
- $[21] = t15;
5921
- } else t15 = $[21];
5922
- if ($[22] !== t13 || $[23] !== t14 || $[24] !== text) {
5923
- t7 = /* @__PURE__ */ jsxs("span", {
5924
- className: "studio-token-input",
5925
- children: [t12, /* @__PURE__ */ jsx("input", {
5926
- id: t13,
5927
- value: text,
5928
- "aria-invalid": t14,
5929
- spellCheck: false,
5930
- onChange: t15
5931
- })]
5932
- });
5933
- $[22] = t13;
5934
- $[23] = t14;
5935
- $[24] = text;
5936
- $[25] = t7;
5937
- } else t7 = $[25];
5938
- t2 = "color";
5939
- t3 = "Pick base color";
5940
- t4 = base ? toHex(base) : "#000000";
5941
- $[2] = initial;
5942
- $[3] = steps;
5943
- $[4] = text;
5944
- $[5] = title;
5945
- $[6] = base;
5946
- $[7] = pending;
5947
- $[8] = shades;
5948
- $[9] = t10;
5949
- $[10] = t2;
5950
- $[11] = t3;
5951
- $[12] = t4;
5952
- $[13] = t5;
5953
- $[14] = t6;
5954
- $[15] = t7;
5955
- $[16] = t8;
5956
- $[17] = t9;
5957
- } else {
5958
- base = $[6];
5959
- pending = $[7];
5960
- shades = $[8];
5961
- t10 = $[9];
5962
- t2 = $[10];
5963
- t3 = $[11];
5964
- t4 = $[12];
5965
- t5 = $[13];
5966
- t6 = $[14];
5967
- t7 = $[15];
5968
- t8 = $[16];
5969
- t9 = $[17];
5970
- }
5971
- let t11;
5972
- if ($[26] === Symbol.for("react.memo_cache_sentinel")) {
5973
- t11 = (event_0) => setText(event_0.target.value.slice(1).toUpperCase());
5974
- $[26] = t11;
5975
- } else t11 = $[26];
5976
- let t12;
5977
- if ($[27] !== t2 || $[28] !== t3 || $[29] !== t4) {
5978
- t12 = /* @__PURE__ */ jsx("input", {
5979
- type: t2,
5980
- "aria-label": t3,
5981
- value: t4,
5982
- onChange: t11
5983
- });
5984
- $[27] = t2;
5985
- $[28] = t3;
5986
- $[29] = t4;
5987
- $[30] = t12;
5988
- } else t12 = $[30];
5989
- const t13 = !pending;
5990
- let t14;
5991
- if ($[31] !== onApply || $[32] !== shades || $[33] !== steps) {
5992
- t14 = () => {
5993
- if (shades) onApply(Object.fromEntries(steps.map((t15) => {
5994
- const { name, step: step_0 } = t15;
5995
- return [name, shades[step_0]];
5996
- })));
5997
- };
5998
- $[31] = onApply;
5999
- $[32] = shades;
6000
- $[33] = steps;
6001
- $[34] = t14;
6002
- } else t14 = $[34];
6003
- let t15;
6004
- if ($[35] !== t13 || $[36] !== t14) {
6005
- t15 = /* @__PURE__ */ jsx("div", {
6006
- className: "studio-shades-actions",
6007
- children: /* @__PURE__ */ jsx("button", {
6008
- type: "button",
6009
- className: "studio-primary",
6010
- disabled: t13,
6011
- onClick: t14,
6012
- children: "Change shades"
6013
- })
5876
+ if ($[12] !== disabled || $[13] !== display || $[14] !== max || $[15] !== min || $[16] !== step || $[17] !== t8 || $[18] !== value) {
5877
+ t9 = /* @__PURE__ */ jsx("input", {
5878
+ type: "range",
5879
+ min,
5880
+ max,
5881
+ step,
5882
+ value,
5883
+ disabled,
5884
+ "aria-valuetext": display,
5885
+ onChange: t8
6014
5886
  });
6015
- $[35] = t13;
6016
- $[36] = t14;
6017
- $[37] = t15;
6018
- } else t15 = $[37];
6019
- let t16;
6020
- if ($[38] !== t12 || $[39] !== t15 || $[40] !== t5 || $[41] !== t6 || $[42] !== t7) {
6021
- t16 = /* @__PURE__ */ jsxs("div", {
6022
- className: t5,
5887
+ $[12] = disabled;
5888
+ $[13] = display;
5889
+ $[14] = max;
5890
+ $[15] = min;
5891
+ $[16] = step;
5892
+ $[17] = t8;
5893
+ $[18] = value;
5894
+ $[19] = t9;
5895
+ } else t9 = $[19];
5896
+ let t10;
5897
+ if ($[20] !== t5 || $[21] !== t6 || $[22] !== t7 || $[23] !== t9) {
5898
+ t10 = /* @__PURE__ */ jsxs("label", {
5899
+ className: "studio-slider-field",
5900
+ style: t5,
6023
5901
  children: [
6024
5902
  t6,
6025
5903
  t7,
6026
- t12,
6027
- t15
5904
+ t9
6028
5905
  ]
6029
5906
  });
6030
- $[38] = t12;
6031
- $[39] = t15;
6032
- $[40] = t5;
6033
- $[41] = t6;
6034
- $[42] = t7;
6035
- $[43] = t16;
6036
- } else t16 = $[43];
6037
- let t17;
6038
- if ($[44] !== base) {
6039
- t17 = !base && /* @__PURE__ */ jsx("p", {
6040
- className: "studio-error",
6041
- children: "Enter a hex color such as #75ACFF."
5907
+ $[20] = t5;
5908
+ $[21] = t6;
5909
+ $[22] = t7;
5910
+ $[23] = t9;
5911
+ $[24] = t10;
5912
+ } else t10 = $[24];
5913
+ return t10;
5914
+ }
5915
+ /** Dragging the base this close to the base color's own lightness snaps it there. */
5916
+ const baseSnap = .012;
5917
+ /** Keeps a moved shade at least this far (per step) from the fixed points beside it, so shades stay in order. */
5918
+ const orderMargin = .006;
5919
+ const width = 320;
5920
+ const height = 260;
5921
+ const insetX = 14;
5922
+ const insetY = 40;
5923
+ const toX = (x) => insetX + x * 292;
5924
+ const toY = (y) => insetY + (1 - y) * 180;
5925
+ const clamp = (value, low, high) => Math.max(low, Math.min(high, value));
5926
+ /**
5927
+ * The palette's lightness curve, edited like a vector path: drag the ends (the backgrounds) and their handles, and drag
5928
+ * any shade up or down to make the curve pass through it. A moved shade stays between the fixed points beside it, so
5929
+ * the curve keeps its order; double-click it (or press Delete) to release it. The base snaps to its own lightness.
5930
+ */
5931
+ function CurveEditor(t0) {
5932
+ const $ = c(13);
5933
+ const { curve, steps, shades, baseLightness, disabled, onChange } = t0;
5934
+ const svgRef = useRef(null);
5935
+ const [grip, setGrip] = useState(null);
5936
+ const press = useRef(null);
5937
+ const ordered = [...steps].sort(_temp$1);
5938
+ const segments = curveSegments(curve, ordered, baseLightness);
5939
+ const lightness = curveStepLightness(curve, ordered, baseLightness);
5940
+ const path = segments.map(_temp2).join(" ");
5941
+ const baseIndex = ordered.indexOf(500);
5942
+ let t1;
5943
+ if ($[0] !== curve.basePinned || $[1] !== curve.pins) {
5944
+ t1 = (step) => step === 500 && curve.basePinned || curve.pins[step] !== void 0;
5945
+ $[0] = curve.basePinned;
5946
+ $[1] = curve.pins;
5947
+ $[2] = t1;
5948
+ } else t1 = $[2];
5949
+ const isMoved = t1;
5950
+ const moveShade = (step_0, y) => {
5951
+ const index_0 = ordered.indexOf(step_0);
5952
+ let lighter = {
5953
+ index: 0,
5954
+ y: curve.start
5955
+ };
5956
+ let darker = {
5957
+ index: ordered.length - 1,
5958
+ y: curve.end
5959
+ };
5960
+ ordered.forEach((other, otherIndex) => {
5961
+ if (other === step_0 || otherIndex === 0 || otherIndex === ordered.length - 1 || !isMoved(other)) return;
5962
+ const value = lightness[other];
5963
+ if (otherIndex < index_0 && otherIndex > lighter.index) lighter = {
5964
+ index: otherIndex,
5965
+ y: value
5966
+ };
5967
+ if (otherIndex > index_0 && otherIndex < darker.index) darker = {
5968
+ index: otherIndex,
5969
+ y: value
5970
+ };
6042
5971
  });
6043
- $[44] = base;
6044
- $[45] = t17;
6045
- } else t17 = $[45];
6046
- let t18;
6047
- if ($[46] !== t10 || $[47] !== t16 || $[48] !== t17 || $[49] !== t8 || $[50] !== t9) {
6048
- t18 = /* @__PURE__ */ jsxs("div", {
6049
- className: t8,
6050
- role: t9,
6051
- "aria-label": t10,
6052
- children: [t16, t17]
5972
+ const bounded = clamp(y, darker.y + orderMargin * (darker.index - index_0), lighter.y - orderMargin * (index_0 - lighter.index));
5973
+ const pins = { ...curve.pins };
5974
+ if (step_0 === 500 && Math.abs(bounded - baseLightness) < baseSnap) {
5975
+ delete pins[500];
5976
+ onChange({
5977
+ ...curve,
5978
+ pins,
5979
+ basePinned: true
5980
+ });
5981
+ return;
5982
+ }
5983
+ pins[step_0] = bounded;
5984
+ onChange({
5985
+ ...curve,
5986
+ pins,
5987
+ basePinned: step_0 === 500 ? false : curve.basePinned
6053
5988
  });
6054
- $[46] = t10;
6055
- $[47] = t16;
6056
- $[48] = t17;
6057
- $[49] = t8;
6058
- $[50] = t9;
6059
- $[51] = t18;
6060
- } else t18 = $[51];
6061
- return t18;
5989
+ };
5990
+ let t2;
5991
+ if ($[3] !== curve || $[4] !== disabled || $[5] !== isMoved || $[6] !== onChange) {
5992
+ t2 = (step_1) => {
5993
+ if (disabled || !isMoved(step_1)) return;
5994
+ const pins_0 = { ...curve.pins };
5995
+ delete pins_0[step_1];
5996
+ onChange({
5997
+ ...curve,
5998
+ pins: pins_0,
5999
+ basePinned: step_1 === 500 ? false : curve.basePinned
6000
+ });
6001
+ };
6002
+ $[3] = curve;
6003
+ $[4] = disabled;
6004
+ $[5] = isMoved;
6005
+ $[6] = onChange;
6006
+ $[7] = t2;
6007
+ } else t2 = $[7];
6008
+ const release = t2;
6009
+ const move = (target, point) => {
6010
+ if (typeof target === "number") moveShade(target, point.y);
6011
+ else if (target === "start" || target === "end") {
6012
+ const y_0 = clamp(point.y, 0, 1);
6013
+ const handle = target === "start" ? "startHandle" : "endHandle";
6014
+ const delta = y_0 - curve[target];
6015
+ onChange({
6016
+ ...curve,
6017
+ [target]: y_0,
6018
+ [handle]: {
6019
+ ...curve[handle],
6020
+ y: clamp(curve[handle].y + delta, -.18, 1.18)
6021
+ }
6022
+ });
6023
+ } else onChange({
6024
+ ...curve,
6025
+ [target]: {
6026
+ x: clamp(point.x, 0, 1),
6027
+ y: clamp(point.y, -.18, 1.18)
6028
+ }
6029
+ });
6030
+ };
6031
+ const pointAt = (event) => {
6032
+ const box = svgRef.current.getBoundingClientRect();
6033
+ const px = (event.clientX - box.left) * width / box.width;
6034
+ const py = (event.clientY - box.top) * height / box.height;
6035
+ return {
6036
+ x: (px - insetX) / 292,
6037
+ y: 1 - (py - insetY) / 180
6038
+ };
6039
+ };
6040
+ const startDrag = (target_0) => (event_0) => {
6041
+ if (disabled || event_0.button !== 0) return;
6042
+ event_0.preventDefault();
6043
+ svgRef.current?.setPointerCapture(event_0.pointerId);
6044
+ press.current = {
6045
+ grip: target_0,
6046
+ x: event_0.clientX,
6047
+ y: event_0.clientY,
6048
+ moved: false
6049
+ };
6050
+ setGrip(target_0);
6051
+ };
6052
+ const nudge = (target_1) => (event_1) => {
6053
+ const amount = event_1.shiftKey ? .05 : .01;
6054
+ const vertical = target_1 === "start" || target_1 === "end";
6055
+ const offset = {
6056
+ ArrowUp: [0, amount],
6057
+ ArrowDown: [0, -amount],
6058
+ ArrowLeft: [vertical ? 0 : -amount, 0],
6059
+ ArrowRight: [vertical ? 0 : amount, 0]
6060
+ }[event_1.key];
6061
+ if (!offset || disabled) return;
6062
+ event_1.preventDefault();
6063
+ const current = vertical ? {
6064
+ x: target_1 === "start" ? 0 : 1,
6065
+ y: curve[target_1]
6066
+ } : curve[target_1];
6067
+ move(target_1, {
6068
+ x: current.x + offset[0],
6069
+ y: current.y + offset[1]
6070
+ });
6071
+ };
6072
+ const shadeKeys = (step_2) => (event_2) => {
6073
+ if (disabled) return;
6074
+ if (event_2.key === "Delete" || event_2.key === "Backspace") {
6075
+ event_2.preventDefault();
6076
+ release(step_2);
6077
+ return;
6078
+ }
6079
+ const amount_0 = event_2.shiftKey ? .05 : .01;
6080
+ const offset_0 = event_2.key === "ArrowUp" ? amount_0 : event_2.key === "ArrowDown" ? -amount_0 : 0;
6081
+ if (!offset_0) return;
6082
+ event_2.preventDefault();
6083
+ moveShade(step_2, lightness[step_2] + offset_0);
6084
+ };
6085
+ const ends = [{
6086
+ grip: "start",
6087
+ handle: "startHandle",
6088
+ x: 0,
6089
+ y: curve.start,
6090
+ label: `Lightest end, ${ordered[0]}`
6091
+ }, {
6092
+ grip: "end",
6093
+ handle: "endHandle",
6094
+ x: 1,
6095
+ y: curve.end,
6096
+ label: `Darkest end, ${ordered.at(-1)}`
6097
+ }];
6098
+ let t3;
6099
+ let t4;
6100
+ if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
6101
+ t3 = () => setGrip(null);
6102
+ t4 = () => setGrip(null);
6103
+ $[8] = t3;
6104
+ $[9] = t4;
6105
+ } else {
6106
+ t3 = $[8];
6107
+ t4 = $[9];
6108
+ }
6109
+ let t5;
6110
+ if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
6111
+ t5 = toY(1);
6112
+ $[10] = t5;
6113
+ } else t5 = $[10];
6114
+ let t6;
6115
+ let t7;
6116
+ if ($[11] === Symbol.for("react.memo_cache_sentinel")) {
6117
+ t6 = /* @__PURE__ */ jsx("rect", {
6118
+ className: "studio-curve-range",
6119
+ x: insetX,
6120
+ y: t5,
6121
+ width: 292,
6122
+ height: toY(0) - toY(1)
6123
+ });
6124
+ t7 = [
6125
+ .25,
6126
+ .5,
6127
+ .75
6128
+ ].map(_temp3);
6129
+ $[11] = t6;
6130
+ $[12] = t7;
6131
+ } else {
6132
+ t6 = $[11];
6133
+ t7 = $[12];
6134
+ }
6135
+ return /* @__PURE__ */ jsxs("svg", {
6136
+ ref: svgRef,
6137
+ className: `studio-curve-editor ${grip ? "is-dragging" : ""}`,
6138
+ viewBox: `0 0 ${width} ${height}`,
6139
+ "aria-label": "Lightness curve",
6140
+ onPointerMove: (event_3) => {
6141
+ const current_0 = press.current;
6142
+ if (!grip || !current_0) return;
6143
+ if (!current_0.moved && Math.hypot(event_3.clientX - current_0.x, event_3.clientY - current_0.y) < 3) return;
6144
+ current_0.moved = true;
6145
+ move(grip, pointAt(event_3));
6146
+ },
6147
+ onDoubleClick: () => {
6148
+ const target_2 = press.current?.grip;
6149
+ if (typeof target_2 === "number") release(target_2);
6150
+ },
6151
+ onPointerUp: t3,
6152
+ onPointerCancel: t4,
6153
+ children: [
6154
+ t6,
6155
+ t7,
6156
+ ordered.map((step_3, index_1) => /* @__PURE__ */ jsx("line", {
6157
+ className: "studio-curve-step",
6158
+ x1: toX(stepPosition(index_1, ordered.length)),
6159
+ x2: toX(stepPosition(index_1, ordered.length)),
6160
+ y1: toY(0),
6161
+ y2: toY(1)
6162
+ }, step_3)),
6163
+ baseIndex >= 0 && !curve.basePinned && /* @__PURE__ */ jsx("line", {
6164
+ className: "studio-curve-base-mark",
6165
+ x1: toX(stepPosition(baseIndex, ordered.length)) - 12,
6166
+ x2: toX(stepPosition(baseIndex, ordered.length)) + 12,
6167
+ y1: toY(baseLightness),
6168
+ y2: toY(baseLightness),
6169
+ children: /* @__PURE__ */ jsx("title", { children: "The base color's own lightness" })
6170
+ }),
6171
+ /* @__PURE__ */ jsx("path", {
6172
+ className: "studio-curve-path",
6173
+ d: path
6174
+ }),
6175
+ ends.map((end) => /* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("line", {
6176
+ className: "studio-curve-handle-line",
6177
+ x1: toX(end.x),
6178
+ y1: toY(end.y),
6179
+ x2: toX(curve[end.handle].x),
6180
+ y2: toY(curve[end.handle].y)
6181
+ }), /* @__PURE__ */ jsx("circle", {
6182
+ className: "studio-curve-handle",
6183
+ cx: toX(curve[end.handle].x),
6184
+ cy: toY(curve[end.handle].y),
6185
+ r: "5",
6186
+ tabIndex: disabled ? -1 : 0,
6187
+ role: "button",
6188
+ "aria-label": `${end.label} handle. Drag or use arrow keys.`,
6189
+ onPointerDown: startDrag(end.handle),
6190
+ onKeyDown: nudge(end.handle)
6191
+ })] }, end.handle)),
6192
+ ordered.map((step_4, index_2) => {
6193
+ if (index_2 === 0 || index_2 === ordered.length - 1 || !shades[step_4]) return null;
6194
+ const pinned = isMoved(step_4);
6195
+ const cx = toX(stepPosition(index_2, ordered.length));
6196
+ const cy = toY(lightness[step_4]);
6197
+ return /* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("circle", {
6198
+ className: `studio-curve-shade ${pinned ? "is-pinned" : ""} ${step_4 === 500 ? "is-base" : ""}`,
6199
+ cx,
6200
+ cy,
6201
+ r: pinned ? 5 : step_4 === 500 ? 4.5 : 3.5,
6202
+ fill: `rgb(${shades[step_4]})`,
6203
+ tabIndex: disabled ? -1 : 0,
6204
+ role: "button",
6205
+ "aria-label": `${step_4 === 500 ? "Base, 500" : step_4}, lightness ${(lightness[step_4] * 100).toFixed(1)}${pinned ? ", moved" : ""}. Drag or use arrow keys; Delete releases it.`,
6206
+ onPointerDown: startDrag(step_4),
6207
+ onKeyDown: shadeKeys(step_4),
6208
+ children: /* @__PURE__ */ jsx("title", { children: pinned ? `${step_4}: drag to adjust · double-click to release` : `${step_4}: drag to adjust` })
6209
+ }), step_4 === 500 && /* @__PURE__ */ jsx("text", {
6210
+ className: "studio-curve-label",
6211
+ x: cx + 8,
6212
+ y: cy - 8,
6213
+ children: curve.basePinned ? "Base · on base color" : "Base"
6214
+ })] }, step_4);
6215
+ }),
6216
+ ends.map((end_0) => /* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("rect", {
6217
+ className: "studio-curve-end",
6218
+ x: toX(end_0.x) - 5,
6219
+ y: toY(end_0.y) - 5,
6220
+ width: "10",
6221
+ height: "10",
6222
+ rx: "2",
6223
+ tabIndex: disabled ? -1 : 0,
6224
+ role: "button",
6225
+ "aria-label": `${end_0.label}, lightness ${(end_0.y * 100).toFixed(1)}. Drag or use arrow keys.`,
6226
+ onPointerDown: startDrag(end_0.grip),
6227
+ onKeyDown: nudge(end_0.grip)
6228
+ }), /* @__PURE__ */ jsx("text", {
6229
+ className: "studio-curve-label",
6230
+ x: end_0.x ? toX(1) - 8 : toX(0) + 8,
6231
+ y: end_0.x ? toY(end_0.y) - 10 : toY(end_0.y) + 18,
6232
+ textAnchor: end_0.x ? "end" : "start",
6233
+ children: `${end_0.x ? ordered.at(-1) : ordered[0]} · ${(end_0.y * 100).toFixed(1)}`
6234
+ })] }, end_0.grip))
6235
+ ]
6236
+ });
6237
+ }
6238
+ /**
6239
+ * Generates a whole base palette scale from one color. Advanced palette controls draw the scale from an editable
6240
+ * lightness curve instead and apply it live; until they are used, the classic weights apply with the base at 500.
6241
+ */
6242
+ function _temp3(y_1) {
6243
+ return /* @__PURE__ */ jsx("line", {
6244
+ className: "studio-curve-grid",
6245
+ x1: insetX,
6246
+ x2: 306,
6247
+ y1: toY(y_1),
6248
+ y2: toY(y_1)
6249
+ }, y_1);
6250
+ }
6251
+ function _temp2(t0, index) {
6252
+ const [from, first, second, to] = t0;
6253
+ return `${index ? "" : `M${toX(from.x)},${toY(from.y)} `}C${toX(first.x)},${toY(first.y)} ${toX(second.x)},${toY(second.y)} ${toX(to.x)},${toY(to.y)}`;
6062
6254
  }
6063
- function _temp$1(t0) {
6064
- const { step } = t0;
6065
- return step;
6255
+ function _temp$1(a, b) {
6256
+ return a - b;
6257
+ }
6258
+ function ShadesGenerator({ title, steps, initial, onApply }) {
6259
+ const hexOf = (rgb) => isRgb(rgb) ? toHex(rgb).slice(1).toUpperCase() : "";
6260
+ const parseHex = (value) => {
6261
+ const hex = value.trim().replace(/^#/, "");
6262
+ return /^[0-9a-f]{6}$/i.test(hex) ? toRgb(`#${hex}`) : /^[0-9a-f]{3}$/i.test(hex) ? toRgb(`#${hex.replace(/./g, "$&$&")}`) : null;
6263
+ };
6264
+ /** The color the palette is generated from; Hue and Saturation adjust it on top. */
6265
+ const [source, setSource] = useState(isRgb(initial) ? initial : null);
6266
+ /** What is being typed into the base field, while it has focus. */
6267
+ const [draftText, setDraftText] = useState(null);
6268
+ const [advanced, setAdvanced] = useState(false);
6269
+ /** `null` until an advanced control is used: the classic generator. */
6270
+ const [curve, setCurve] = useState(null);
6271
+ /** The base the curve last applied from, so the button only offers changes to a new base. */
6272
+ const [curveBase, setCurveBase] = useState(null);
6273
+ const ownApply = useRef(null);
6274
+ const [synced, setSynced] = useState(initial);
6275
+ if (initial !== synced) {
6276
+ setSynced(initial);
6277
+ if (initial !== ownApply.current) {
6278
+ setSource(isRgb(initial) ? initial : null);
6279
+ setDraftText(null);
6280
+ setCurve(null);
6281
+ setCurveBase(null);
6282
+ }
6283
+ }
6284
+ const base = source;
6285
+ const shownBase = base && curve ? adjustBase(base, curve) : base;
6286
+ const fieldText = draftText ?? (shownBase ? hexOf(shownBase) : "");
6287
+ const invalid = draftText !== null ? !parseHex(draftText) : !base;
6288
+ /** A base entered by hand replaces the adjusted one, so Hue and Saturation start again from it. */
6289
+ const enterBase = (value_0) => {
6290
+ setDraftText(value_0);
6291
+ const parsed = parseHex(value_0);
6292
+ if (!parsed) return;
6293
+ setSource(parsed);
6294
+ if (curve && (curve.hue !== 0 || curve.saturation !== 100)) setCurve({
6295
+ ...curve,
6296
+ hue: 0,
6297
+ saturation: 100
6298
+ });
6299
+ };
6300
+ const numbers = steps.map(({ step }) => step);
6301
+ const shadesFor = (from, using) => using ? generateCurveShades(from, numbers, using) : generateShades(from, numbers);
6302
+ const shades = base ? shadesFor(base, curve) : null;
6303
+ const pending = !!shades && (curve ? base !== curveBase : base !== initial);
6304
+ const apply = (values, from_0) => {
6305
+ ownApply.current = values[500] ?? null;
6306
+ setCurveBase(from_0);
6307
+ onApply(Object.fromEntries(steps.map(({ name, step: step_0 }) => [name, values[step_0]])));
6308
+ };
6309
+ const updateCurve = (next) => {
6310
+ setCurve(next);
6311
+ if (base) apply(generateCurveShades(base, numbers, next), base);
6312
+ };
6313
+ const resetCurve = () => {
6314
+ setCurve(null);
6315
+ setCurveBase(null);
6316
+ if (base) apply(generateShades(base, numbers), base);
6317
+ };
6318
+ const active = curve ?? defaultShadeCurve;
6319
+ const curveShades = base ? generateCurveShades(base, numbers, active) : null;
6320
+ const baseLightness = shownBase ? rgbToOklch(shownBase.split(" ").map(Number))[0] : .5;
6321
+ const panelId = `shades-advanced-${title.replaceAll(" ", "-")}`;
6322
+ return /* @__PURE__ */ jsxs("div", {
6323
+ className: "studio-shades",
6324
+ role: "group",
6325
+ "aria-label": `Generate ${title} shades`,
6326
+ children: [
6327
+ /* @__PURE__ */ jsxs("div", {
6328
+ className: "studio-shades-row",
6329
+ children: [
6330
+ /* @__PURE__ */ jsx("label", {
6331
+ className: "studio-shades-label",
6332
+ htmlFor: `shades-${title}`,
6333
+ children: "Base"
6334
+ }),
6335
+ /* @__PURE__ */ jsxs("span", {
6336
+ className: "studio-shades-field",
6337
+ children: [
6338
+ /* @__PURE__ */ jsx("input", {
6339
+ type: "color",
6340
+ "aria-label": "Pick base color",
6341
+ value: shownBase ? toHex(shownBase) : "#000000",
6342
+ onChange: (event) => {
6343
+ enterBase(event.target.value.slice(1).toUpperCase());
6344
+ setDraftText(null);
6345
+ }
6346
+ }),
6347
+ /* @__PURE__ */ jsx("span", {
6348
+ "aria-hidden": "true",
6349
+ children: "#"
6350
+ }),
6351
+ /* @__PURE__ */ jsx("input", {
6352
+ id: `shades-${title}`,
6353
+ value: fieldText,
6354
+ "aria-invalid": invalid,
6355
+ spellCheck: false,
6356
+ onFocus: () => setDraftText(fieldText),
6357
+ onBlur: () => setDraftText(null),
6358
+ onChange: (event_0) => enterBase(event_0.target.value.replace(/^#/, ""))
6359
+ })
6360
+ ]
6361
+ }),
6362
+ /* @__PURE__ */ jsx("button", {
6363
+ type: "button",
6364
+ className: "studio-primary studio-shades-apply",
6365
+ disabled: !pending,
6366
+ onClick: () => {
6367
+ if (shades && base) apply(shades, base);
6368
+ },
6369
+ children: "Change shades"
6370
+ })
6371
+ ]
6372
+ }),
6373
+ invalid && /* @__PURE__ */ jsx("p", {
6374
+ className: "studio-error",
6375
+ children: "Enter a hex color such as #75ACFF."
6376
+ }),
6377
+ /* @__PURE__ */ jsxs("div", {
6378
+ className: "studio-shades-bar",
6379
+ children: [/* @__PURE__ */ jsxs("button", {
6380
+ type: "button",
6381
+ className: "studio-shades-advanced-toggle",
6382
+ "aria-expanded": advanced,
6383
+ "aria-controls": panelId,
6384
+ onClick: () => setAdvanced((value_1) => !value_1),
6385
+ children: [
6386
+ /* @__PURE__ */ jsx(ChevronRight, {
6387
+ size: 12,
6388
+ "aria-hidden": "true"
6389
+ }),
6390
+ "Advanced palette controls",
6391
+ curve && /* @__PURE__ */ jsx("span", {
6392
+ className: "studio-group-changed",
6393
+ "aria-label": "in use"
6394
+ })
6395
+ ]
6396
+ }), curve && /* @__PURE__ */ jsxs("button", {
6397
+ type: "button",
6398
+ className: "studio-shades-reset",
6399
+ "aria-label": "Back to standard shades",
6400
+ title: "Back to standard shades",
6401
+ onClick: resetCurve,
6402
+ children: [/* @__PURE__ */ jsx(RotateCcw, {
6403
+ size: 12,
6404
+ "aria-hidden": "true"
6405
+ }), "Reset"]
6406
+ })]
6407
+ }),
6408
+ advanced && /* @__PURE__ */ jsxs("div", {
6409
+ id: panelId,
6410
+ className: "studio-shades-advanced",
6411
+ children: [
6412
+ curveShades && /* @__PURE__ */ jsx(CurveEditor, {
6413
+ curve: active,
6414
+ steps: numbers,
6415
+ shades: curveShades,
6416
+ baseLightness,
6417
+ disabled: !base,
6418
+ onChange: updateCurve
6419
+ }),
6420
+ /* @__PURE__ */ jsx("p", {
6421
+ className: "studio-shades-hint",
6422
+ children: curve ? "Drag the ends, their handles or any shade · double-click a moved shade to release it" : "Standard shades in use · drag the curve or a shade to switch to it"
6423
+ }),
6424
+ /* @__PURE__ */ jsx("div", {
6425
+ className: "studio-slider-fields",
6426
+ children: colorRows.map(({ field, label, min, max, step: step_1, unit }) => /* @__PURE__ */ jsx(SliderField, {
6427
+ label,
6428
+ value: active[field],
6429
+ min,
6430
+ max,
6431
+ step: step_1,
6432
+ display: `${active[field]}${unit}`,
6433
+ disabled: !base,
6434
+ onChange: (value_2) => updateCurve({
6435
+ ...active,
6436
+ [field]: value_2
6437
+ })
6438
+ }, field))
6439
+ })
6440
+ ]
6441
+ })
6442
+ ]
6443
+ });
6066
6444
  }
6067
6445
  //#endregion
6068
6446
  //#region src/configurator/ComponentPreview.tsx
6069
- const ComponentGallery = lazy(() => import("./ComponentGallery-CzKU899_.js"));
6447
+ const ComponentGallery = lazy(() => import("./ComponentGallery-C_rXFvUY.js").then((n) => n.n));
6070
6448
  /** Every component, styled by a configuration; the configurator's preview and the App Canvas Components view. */
6071
6449
  function ComponentPreview(t0) {
6072
6450
  const $ = c(14);
@@ -6213,6 +6591,7 @@ function ThemeVersionControls(t0) {
6213
6591
  if ($[12] !== themes.versions) {
6214
6592
  t5 = /* @__PURE__ */ jsx($542a13ca2fa5b484$export$5b6b19405a83ff9d, {
6215
6593
  className: "studio-version-popover",
6594
+ "data-povio-inspector-ignore": "",
6216
6595
  placement: "bottom start",
6217
6596
  children: /* @__PURE__ */ jsx($928221da08ecbc62$export$41f133550aa26f48, {
6218
6597
  className: "studio-version-list",
@@ -6469,6 +6848,7 @@ function ThemeVersionControls(t0) {
6469
6848
  if ($[73] !== t14 || $[74] !== t15 || $[75] !== t31) {
6470
6849
  t32 = /* @__PURE__ */ jsx($542a13ca2fa5b484$export$5b6b19405a83ff9d, {
6471
6850
  triggerRef: t14,
6851
+ "data-povio-inspector-ignore": "",
6472
6852
  placement: "bottom start",
6473
6853
  offset: 6,
6474
6854
  className: "studio-version-popover studio-version-dialog",
@@ -6977,7 +7357,7 @@ function PopoutOverlay(t0) {
6977
7357
  } else t3 = $[5];
6978
7358
  return t3;
6979
7359
  }
6980
- function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating, onPopout, onDock, popupBlocked, themeVersions }) {
7360
+ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating, onPopout, onDock, popupBlocked, themeVersions, editorOnly }) {
6981
7361
  const Overlay = poppedOut || floating ? PopoutOverlay : $8b8d26808cb8cb53$export$8948f78d83984c69;
6982
7362
  const Surface = poppedOut || floating ? "div" : $8b8d26808cb8cb53$export$2b77a92f1a5ad772;
6983
7363
  const studioWindow = useStudioWindow(windowBounds, !poppedOut);
@@ -6992,7 +7372,7 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
6992
7372
  return () => observer.disconnect();
6993
7373
  }, [studioWindow.ref]);
6994
7374
  const inherited = UIConfig.useConfig();
6995
- const { defaults, draft, setDraft, isOpen, apply, revision, tokenRequest, clearTokenRequest, componentsHosted } = useUIConfiguration();
7375
+ const { defaults, draft, setDraft, isOpen, apply, revision, tokenRequest, clearTokenRequest } = useUIConfiguration();
6996
7376
  const remembered = memory.current;
6997
7377
  const [mode, setMode] = useState(remembered.mode ?? "light");
6998
7378
  const [sizeUnit, setSizeUnit] = useState(remembered.sizeUnit ?? "px");
@@ -7280,7 +7660,7 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
7280
7660
  onApply: (values) => {
7281
7661
  for (const [name_16, value_7] of Object.entries(values)) setToken(name_16, value_7);
7282
7662
  }
7283
- }, base);
7663
+ }, title);
7284
7664
  };
7285
7665
  const tokenGroups = [...groupedEntries.entries()].filter(([key_2, group_0]) => `${key_2} ${group_0.title} ${group_0.entries.map(([name_17]) => `${name_17} ${labelFor(name_17)}`).join(" ")}`.toLowerCase().includes(search.toLowerCase().trim()));
7286
7666
  const visibleGroups = section === "Typography" ? tokenGroups : tokenGroups.map(([key_3, group_1]) => [key_3, {
@@ -7471,10 +7851,10 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
7471
7851
  children: /* @__PURE__ */ jsx(Surface, {
7472
7852
  className: `studio-modal${poppedOut ? " studio-modal-popout" : ""}`,
7473
7853
  ref: studioWindow.ref,
7474
- "data-components-hosted": componentsHosted || void 0,
7854
+ "data-editor-only": editorOnly || void 0,
7475
7855
  children: /* @__PURE__ */ jsxs($f2ff30fde7b014be$export$3ddf2d174ce01153, {
7476
7856
  className: "studio-dialog",
7477
- "data-compact-preview": compactPreview && !componentsHosted || void 0,
7857
+ "data-compact-preview": compactPreview && !editorOnly || void 0,
7478
7858
  style: { "--studio-editor-track": editorWidth ? `minmax(260px, ${editorWidth}px)` : void 0 },
7479
7859
  children: [
7480
7860
  /* @__PURE__ */ jsxs("header", {
@@ -7510,7 +7890,7 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
7510
7890
  })
7511
7891
  ]
7512
7892
  }),
7513
- !componentsHosted && /* @__PURE__ */ jsx("button", {
7893
+ !editorOnly && /* @__PURE__ */ jsx("button", {
7514
7894
  type: "button",
7515
7895
  className: "studio-preview-tab",
7516
7896
  "aria-current": compactPreview ? "page" : void 0,
@@ -7578,25 +7958,37 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
7578
7958
  }), toggleAllButton]
7579
7959
  }) : showTabs ? /* @__PURE__ */ jsxs("div", {
7580
7960
  className: "studio-subtabs-bar",
7581
- children: [/* @__PURE__ */ jsx("div", {
7582
- className: "studio-subtabs",
7583
- role: "tablist",
7584
- "aria-label": `${section} tokens`,
7585
- children: sectionTabList.map((tab_0) => /* @__PURE__ */ jsxs("button", {
7961
+ children: [
7962
+ /* @__PURE__ */ jsx("div", {
7963
+ className: "studio-subtabs",
7964
+ role: "tablist",
7965
+ "aria-label": `${section} tokens`,
7966
+ children: sectionTabList.map((tab_0) => /* @__PURE__ */ jsxs("button", {
7967
+ type: "button",
7968
+ role: "tab",
7969
+ "aria-selected": !searching && tab_0 === activeSectionTab,
7970
+ disabled: searching,
7971
+ onClick: () => setSectionTabs((current_13) => ({
7972
+ ...current_13,
7973
+ [section]: tab_0
7974
+ })),
7975
+ children: [tab_0, groupChanged([...groupedEntries].filter(([key_14]) => tabFor(key_14) === tab_0).flatMap(([, group_6]) => group_6.entries)) && /* @__PURE__ */ jsx("span", {
7976
+ className: "studio-group-changed",
7977
+ "aria-label": "has changes"
7978
+ })]
7979
+ }, tab_0))
7980
+ }),
7981
+ section === "Colors" && !searching && activeSectionTab === semanticPaletteTab && /* @__PURE__ */ jsx("button", {
7586
7982
  type: "button",
7587
- role: "tab",
7588
- "aria-selected": !searching && tab_0 === activeSectionTab,
7589
- disabled: searching,
7590
- onClick: () => setSectionTabs((current_13) => ({
7591
- ...current_13,
7592
- [section]: tab_0
7593
- })),
7594
- children: [tab_0, groupChanged([...groupedEntries].filter(([key_14]) => tabFor(key_14) === tab_0).flatMap(([, group_6]) => group_6.entries)) && /* @__PURE__ */ jsx("span", {
7595
- className: "studio-group-changed",
7596
- "aria-label": "has changes"
7597
- })]
7598
- }, tab_0))
7599
- }), toggleAllButton]
7983
+ className: "studio-theme-toggle",
7984
+ onClick: () => setMode(mode === "dark" ? "light" : "dark"),
7985
+ "aria-pressed": mode === "dark",
7986
+ "aria-label": mode === "dark" ? "Dark" : "Light",
7987
+ title: "Toggle semantic palette mode",
7988
+ children: mode === "dark" ? /* @__PURE__ */ jsx(Moon, { size: 14 }) : /* @__PURE__ */ jsx(Sun, { size: 14 })
7989
+ }),
7990
+ toggleAllButton
7991
+ ]
7600
7992
  }) : advancedSection ? /* @__PURE__ */ jsx("div", {
7601
7993
  className: "studio-subtabs-bar",
7602
7994
  children: /* @__PURE__ */ jsx("div", {
@@ -7873,7 +8265,7 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
7873
8265
  ]
7874
8266
  })
7875
8267
  ]
7876
- }), !componentsHosted && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("aside", {
8268
+ }), !editorOnly && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("aside", {
7877
8269
  ref: previewRef,
7878
8270
  className: "studio-preview",
7879
8271
  onScroll: (event_6) => memory.current.previewScroll = event_6.currentTarget.scrollTop,
@@ -8067,23 +8459,24 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
8067
8459
  })
8068
8460
  });
8069
8461
  }
8070
- /** Where a floating configurator first opens; an editor-only window (components shown by the host) is narrower. */
8462
+ /** Where a floating configurator first opens; an editor-only window is narrower. */
8071
8463
  const floatingDefault = {
8072
8464
  left: 32,
8073
8465
  top: 80,
8074
8466
  width: 640,
8075
8467
  height: 720
8076
8468
  };
8077
- const hostedFloatingWidth = 360;
8078
- function UIConfigurationModal() {
8469
+ const editorOnlyFloatingWidth = 360;
8470
+ function UIConfigurationModal({ editorOnly: editorOnlyProp = false } = {}) {
8079
8471
  const { isOpen, revision, floating, componentsHosted } = useUIConfiguration();
8472
+ const editorOnly = editorOnlyProp || componentsHosted;
8080
8473
  const themeVersions = useThemeVersions();
8081
8474
  const memory = useRef({});
8082
8475
  const windowBounds = useRef(null);
8083
8476
  const floatingBounds = useRef(floatingDefault);
8084
- if (componentsHosted && floatingBounds.current === floatingDefault) floatingBounds.current = {
8477
+ if (editorOnly && floatingBounds.current === floatingDefault) floatingBounds.current = {
8085
8478
  ...floatingDefault,
8086
- width: hostedFloatingWidth
8479
+ width: editorOnlyFloatingWidth
8087
8480
  };
8088
8481
  const popout = useStudioPopout(isOpen);
8089
8482
  if (!isOpen) return null;
@@ -8095,7 +8488,8 @@ function UIConfigurationModal() {
8095
8488
  onPopout: popout.open,
8096
8489
  onDock: popout.dock,
8097
8490
  popupBlocked: popout.blocked,
8098
- themeVersions
8491
+ themeVersions,
8492
+ editorOnly
8099
8493
  }, revision);
8100
8494
  return popout.popup ? createPortal(/* @__PURE__ */ jsx(StudioPopoutContext, {
8101
8495
  value: true,
@@ -8106,4 +8500,450 @@ function UIConfigurationModal() {
8106
8500
  }), popout.popup.document.body) : floating ? createPortal(content, document.body) : content;
8107
8501
  }
8108
8502
  //#endregion
8109
- 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 };
8503
+ //#region src/app-canvas/CanvasInspector.tsx
8504
+ /** Inspect the live iframe DOM using its own, unscaled viewport coordinates. */
8505
+ function useCanvasInspector(enabled, generation, isKnown) {
8506
+ const [selection, setSelection] = useState(null);
8507
+ const [measurement, setMeasurement] = useState(null);
8508
+ const [pinned, setPinned] = useState(false);
8509
+ const [highlightKey, setHighlightKey] = useState(null);
8510
+ const hoverFrame = useRef(null);
8511
+ const pending = useRef(null);
8512
+ const clear = useCallback(() => {
8513
+ if (hoverFrame.current !== null) cancelAnimationFrame(hoverFrame.current);
8514
+ hoverFrame.current = null;
8515
+ pending.current = null;
8516
+ setSelection(null);
8517
+ setMeasurement(null);
8518
+ setPinned(false);
8519
+ setHighlightKey(null);
8520
+ }, []);
8521
+ useEffect(() => {
8522
+ if (!enabled) clear();
8523
+ }, [enabled, clear]);
8524
+ useEffect(() => {
8525
+ clear();
8526
+ }, [generation, clear]);
8527
+ useEffect(() => () => {
8528
+ if (hoverFrame.current !== null) cancelAnimationFrame(hoverFrame.current);
8529
+ }, []);
8530
+ /** Picks the element at a point in `doc`'s own viewport: an iframe's document, or the page itself. */
8531
+ const pickInDocument = useCallback((pageId, doc, x, y, pin) => {
8532
+ if (!enabled || pinned && !pin) return;
8533
+ try {
8534
+ const hit = doc.elementFromPoint(x, y);
8535
+ const element = hit?.closest("button,input,textarea,select,a,label,[role],h1,h2,h3,h4,h5,h6,p") ?? hit;
8536
+ if (!element || element === doc.documentElement || element === doc.body || element.namespaceURI !== "http://www.w3.org/1999/xhtml") return;
8537
+ const target = element;
8538
+ setSelection((current) => current?.element === target ? current : {
8539
+ pageId,
8540
+ element: target
8541
+ });
8542
+ setHighlightKey(null);
8543
+ if (pin) setPinned((current_0) => !(current_0 && selection?.element === target));
8544
+ } catch {
8545
+ clear();
8546
+ }
8547
+ }, [
8548
+ enabled,
8549
+ pinned,
8550
+ selection,
8551
+ clear
8552
+ ]);
8553
+ const pick = useCallback((pageId_0, frame, clientX, clientY, pin_0) => {
8554
+ const bounds = frame.getBoundingClientRect();
8555
+ if (!bounds.width || !bounds.height) return;
8556
+ try {
8557
+ const doc_0 = frame.contentDocument;
8558
+ if (!doc_0) return;
8559
+ const x_0 = (clientX - bounds.left) * frame.clientWidth / bounds.width;
8560
+ const y_0 = (clientY - bounds.top) * frame.clientHeight / bounds.height;
8561
+ pickInDocument(pageId_0, doc_0, x_0, y_0, pin_0);
8562
+ } catch {
8563
+ clear();
8564
+ }
8565
+ }, [pickInDocument, clear]);
8566
+ const hover = useCallback((pageId_1, frame_0, x_1, y_1) => {
8567
+ if (!enabled || pinned) return;
8568
+ pending.current = () => pick(pageId_1, frame_0, x_1, y_1, false);
8569
+ if (hoverFrame.current !== null) return;
8570
+ hoverFrame.current = requestAnimationFrame(() => {
8571
+ hoverFrame.current = null;
8572
+ pending.current?.();
8573
+ pending.current = null;
8574
+ });
8575
+ }, [
8576
+ enabled,
8577
+ pinned,
8578
+ pick
8579
+ ]);
8580
+ const select = useCallback((pageId_2, frame_1, x_2, y_2) => {
8581
+ if (hoverFrame.current !== null) cancelAnimationFrame(hoverFrame.current);
8582
+ hoverFrame.current = null;
8583
+ pending.current = null;
8584
+ pick(pageId_2, frame_1, x_2, y_2, true);
8585
+ }, [pick]);
8586
+ useEffect(() => {
8587
+ if (!enabled || !selection) return;
8588
+ const { element: element_0 } = selection;
8589
+ const doc_1 = element_0.ownerDocument;
8590
+ const owner = doc_1.defaultView;
8591
+ if (!owner) return;
8592
+ let scheduled = null;
8593
+ const measure = () => {
8594
+ scheduled = null;
8595
+ if (!element_0.isConnected) {
8596
+ clear();
8597
+ return;
8598
+ }
8599
+ const rect = element_0.getBoundingClientRect();
8600
+ const snapshot = inspectElement(element_0, isKnown);
8601
+ const details = highlightKey ? getBoxHighlights(element_0, highlightKey) : null;
8602
+ const spacing = highlightKey ? [] : [
8603
+ "padding.top",
8604
+ "padding.right",
8605
+ "padding.bottom",
8606
+ "padding.left",
8607
+ "margin.top",
8608
+ "margin.right",
8609
+ "margin.bottom",
8610
+ "margin.left",
8611
+ "gap.row",
8612
+ "gap.column"
8613
+ ].flatMap((key) => {
8614
+ const [kind, side] = key.split(".");
8615
+ const raw = kind === "padding" ? snapshot.box.padding[side] : kind === "margin" ? snapshot.box.margin[side] : snapshot.box.gap[side];
8616
+ if (!(Math.abs(Number.parseFloat(raw)) > 0)) return [];
8617
+ const details_0 = getBoxHighlights(element_0, key);
8618
+ const regions = details_0.regions.filter((region) => region.width > 0 && region.height > 0);
8619
+ return regions.length ? [{
8620
+ key,
8621
+ label: details_0.label,
8622
+ regions
8623
+ }] : [];
8624
+ });
8625
+ if (!highlightKey) {
8626
+ const seen = new Set(spacing.flatMap((item) => item.regions.map((region_0) => `${item.key}:${region_0.left}:${region_0.top}:${region_0.width}:${region_0.height}`)));
8627
+ for (const child of Array.from(element_0.children).slice(0, 80)) {
8628
+ if (child.namespaceURI !== "http://www.w3.org/1999/xhtml" || !child.getClientRects().length) continue;
8629
+ const style = owner.getComputedStyle(child);
8630
+ if (style.display === "none" || style.visibility === "hidden" || /^(absolute|fixed)$/.test(style.position)) continue;
8631
+ for (const side_0 of [
8632
+ "top",
8633
+ "right",
8634
+ "bottom",
8635
+ "left"
8636
+ ]) {
8637
+ if (!(Math.abs(Number.parseFloat(style.getPropertyValue(`margin-${side_0}`))) > 0)) continue;
8638
+ const key_0 = `margin.${side_0}`;
8639
+ const details_1 = getBoxHighlights(child, key_0);
8640
+ const regions_0 = details_1.regions.filter((region_1) => {
8641
+ const id = `${key_0}:${region_1.left}:${region_1.top}:${region_1.width}:${region_1.height}`;
8642
+ if (seen.has(id)) return false;
8643
+ seen.add(id);
8644
+ return region_1.width > 0 && region_1.height > 0;
8645
+ });
8646
+ if (regions_0.length) spacing.push({
8647
+ key: key_0,
8648
+ label: details_1.label,
8649
+ regions: regions_0
8650
+ });
8651
+ }
8652
+ }
8653
+ }
8654
+ const next = {
8655
+ snapshot,
8656
+ spacing,
8657
+ outline: {
8658
+ left: rect.left,
8659
+ top: rect.top,
8660
+ width: rect.width,
8661
+ height: rect.height
8662
+ },
8663
+ highlight: details && highlightKey ? {
8664
+ key: highlightKey,
8665
+ ...details
8666
+ } : null
8667
+ };
8668
+ setMeasurement((current_1) => JSON.stringify(current_1) === JSON.stringify(next) ? current_1 : next);
8669
+ };
8670
+ const schedule = () => {
8671
+ if (scheduled === null) scheduled = requestAnimationFrame(measure);
8672
+ };
8673
+ const mutations = new MutationObserver(schedule);
8674
+ mutations.observe(doc_1.documentElement, {
8675
+ subtree: true,
8676
+ childList: true,
8677
+ attributes: true,
8678
+ characterData: true
8679
+ });
8680
+ const resize = new ResizeObserver(schedule);
8681
+ resize.observe(element_0);
8682
+ owner.addEventListener("scroll", schedule, true);
8683
+ measure();
8684
+ return () => {
8685
+ mutations.disconnect();
8686
+ resize.disconnect();
8687
+ owner.removeEventListener("scroll", schedule, true);
8688
+ if (scheduled !== null) cancelAnimationFrame(scheduled);
8689
+ };
8690
+ }, [
8691
+ enabled,
8692
+ selection,
8693
+ highlightKey,
8694
+ clear,
8695
+ isKnown
8696
+ ]);
8697
+ return {
8698
+ selection,
8699
+ hoverPoint: useCallback((doc_2, x_3, y_3) => {
8700
+ if (!enabled || pinned) return;
8701
+ pending.current = () => pickInDocument("page", doc_2, x_3, y_3, false);
8702
+ if (hoverFrame.current !== null) return;
8703
+ hoverFrame.current = requestAnimationFrame(() => {
8704
+ hoverFrame.current = null;
8705
+ pending.current?.();
8706
+ pending.current = null;
8707
+ });
8708
+ }, [
8709
+ enabled,
8710
+ pinned,
8711
+ pickInDocument
8712
+ ]),
8713
+ selectPoint: useCallback((doc_3, x_4, y_4) => {
8714
+ if (hoverFrame.current !== null) cancelAnimationFrame(hoverFrame.current);
8715
+ hoverFrame.current = null;
8716
+ pending.current = null;
8717
+ pickInDocument("page", doc_3, x_4, y_4, true);
8718
+ }, [pickInDocument]),
8719
+ selectElement: (pageId_3, element_1) => {
8720
+ setSelection({
8721
+ pageId: pageId_3,
8722
+ element: element_1
8723
+ });
8724
+ setPinned(true);
8725
+ setHighlightKey(null);
8726
+ },
8727
+ measurement,
8728
+ pinned,
8729
+ hover,
8730
+ select,
8731
+ clear,
8732
+ highlight: setHighlightKey,
8733
+ togglePin: () => setPinned((value) => !value)
8734
+ };
8735
+ }
8736
+ function CanvasInspectorPanel(t0) {
8737
+ const $ = c(24);
8738
+ const { inspector, onClose, onSelectToken, className: t1, emptyHint: t2 } = t0;
8739
+ const className = t1 === void 0 ? "povio-canvas-inspector" : t1;
8740
+ const emptyHint = t2 === void 0 ? "Inspect a live page to see its padding, margins, borders, radii and gaps." : t2;
8741
+ const t3 = `studio-inspector-panel ${className}`;
8742
+ let t4;
8743
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
8744
+ t4 = /* @__PURE__ */ jsx("strong", { children: "Inspector view" });
8745
+ $[0] = t4;
8746
+ } else t4 = $[0];
8747
+ const t5 = !inspector.selection;
8748
+ let t6;
8749
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
8750
+ t6 = /* @__PURE__ */ jsx(Pin, { size: 14 });
8751
+ $[1] = t6;
8752
+ } else t6 = $[1];
8753
+ let t7;
8754
+ if ($[2] !== inspector.pinned || $[3] !== inspector.togglePin || $[4] !== t5) {
8755
+ t7 = /* @__PURE__ */ jsx("button", {
8756
+ "aria-label": "Pin inspected element",
8757
+ "aria-pressed": inspector.pinned,
8758
+ disabled: t5,
8759
+ onClick: inspector.togglePin,
8760
+ children: t6
8761
+ });
8762
+ $[2] = inspector.pinned;
8763
+ $[3] = inspector.togglePin;
8764
+ $[4] = t5;
8765
+ $[5] = t7;
8766
+ } else t7 = $[5];
8767
+ let t8;
8768
+ if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
8769
+ t8 = /* @__PURE__ */ jsx(X, { size: 15 });
8770
+ $[6] = t8;
8771
+ } else t8 = $[6];
8772
+ let t9;
8773
+ if ($[7] !== onClose) {
8774
+ t9 = /* @__PURE__ */ jsx("button", {
8775
+ "aria-label": "Close inspector view",
8776
+ onClick: onClose,
8777
+ children: t8
8778
+ });
8779
+ $[7] = onClose;
8780
+ $[8] = t9;
8781
+ } else t9 = $[8];
8782
+ let t10;
8783
+ if ($[9] !== t7 || $[10] !== t9) {
8784
+ t10 = /* @__PURE__ */ jsxs("header", { children: [
8785
+ t4,
8786
+ t7,
8787
+ t9
8788
+ ] });
8789
+ $[9] = t7;
8790
+ $[10] = t9;
8791
+ $[11] = t10;
8792
+ } else t10 = $[11];
8793
+ const t11 = inspector.pinned ? "Selection pinned · click it again to unpin" : "Hover a component · click to pin";
8794
+ let t12;
8795
+ if ($[12] !== t11) {
8796
+ t12 = /* @__PURE__ */ jsx("p", {
8797
+ className: "povio-canvas-inspect-hint",
8798
+ children: t11
8799
+ });
8800
+ $[12] = t11;
8801
+ $[13] = t12;
8802
+ } else t12 = $[13];
8803
+ let t13;
8804
+ if ($[14] !== emptyHint || $[15] !== inspector.highlight || $[16] !== inspector.measurement || $[17] !== onSelectToken) {
8805
+ t13 = inspector.measurement ? /* @__PURE__ */ jsx(InspectorDetails, {
8806
+ snapshot: inspector.measurement.snapshot,
8807
+ onSelect: onSelectToken,
8808
+ onHighlight: inspector.highlight
8809
+ }) : /* @__PURE__ */ jsx("p", {
8810
+ className: "povio-canvas-inspect-hint",
8811
+ children: emptyHint
8812
+ });
8813
+ $[14] = emptyHint;
8814
+ $[15] = inspector.highlight;
8815
+ $[16] = inspector.measurement;
8816
+ $[17] = onSelectToken;
8817
+ $[18] = t13;
8818
+ } else t13 = $[18];
8819
+ let t14;
8820
+ if ($[19] !== t10 || $[20] !== t12 || $[21] !== t13 || $[22] !== t3) {
8821
+ t14 = /* @__PURE__ */ jsxs("aside", {
8822
+ className: t3,
8823
+ "data-povio-inspector-ignore": "",
8824
+ "aria-label": "Inspector view",
8825
+ children: [
8826
+ t10,
8827
+ t12,
8828
+ t13
8829
+ ]
8830
+ });
8831
+ $[19] = t10;
8832
+ $[20] = t12;
8833
+ $[21] = t13;
8834
+ $[22] = t3;
8835
+ $[23] = t14;
8836
+ } else t14 = $[23];
8837
+ return t14;
8838
+ }
8839
+ function CanvasInspectionOverlay(t0) {
8840
+ const $ = c(10);
8841
+ const { measurement, width, className: t1 } = t0;
8842
+ const className = t1 === void 0 ? "povio-canvas-inspection-overlay" : t1;
8843
+ let t2;
8844
+ if ($[0] !== measurement.outline) {
8845
+ t2 = /* @__PURE__ */ jsx("div", {
8846
+ className: "studio-hover-outline",
8847
+ style: measurement.outline
8848
+ });
8849
+ $[0] = measurement.outline;
8850
+ $[1] = t2;
8851
+ } else t2 = $[1];
8852
+ let t3;
8853
+ if ($[2] !== measurement.highlight || $[3] !== measurement.spacing || $[4] !== width) {
8854
+ t3 = measurement.highlight ? /* @__PURE__ */ jsx(HighlightOverlay, {
8855
+ highlight: measurement.highlight,
8856
+ width
8857
+ }) : measurement.spacing.map((highlight) => /* @__PURE__ */ jsxs("div", {
8858
+ className: "povio-canvas-auto-spacing",
8859
+ children: [/* @__PURE__ */ jsx(HighlightOverlay, {
8860
+ highlight,
8861
+ width
8862
+ }), highlight.regions.map((region) => /* @__PURE__ */ jsx("span", {
8863
+ className: "povio-canvas-spacing-value",
8864
+ style: {
8865
+ left: region.left + region.width / 2,
8866
+ top: region.top + region.height / 2
8867
+ },
8868
+ children: highlight.label.split(": ")[1]
8869
+ }, `${region.left}:${region.top}:${region.width}:${region.height}`))]
8870
+ }, `${highlight.key}:${highlight.label}:${highlight.regions[0]?.left}:${highlight.regions[0]?.top}`));
8871
+ $[2] = measurement.highlight;
8872
+ $[3] = measurement.spacing;
8873
+ $[4] = width;
8874
+ $[5] = t3;
8875
+ } else t3 = $[5];
8876
+ let t4;
8877
+ if ($[6] !== className || $[7] !== t2 || $[8] !== t3) {
8878
+ t4 = /* @__PURE__ */ jsxs("div", {
8879
+ className,
8880
+ "aria-hidden": "true",
8881
+ children: [t2, t3]
8882
+ });
8883
+ $[6] = className;
8884
+ $[7] = t2;
8885
+ $[8] = t3;
8886
+ $[9] = t4;
8887
+ } else t4 = $[9];
8888
+ return t4;
8889
+ }
8890
+ /** Temporary layer hover never replaces the pinned inspector selection. */
8891
+ function CanvasLayerHighlight(t0) {
8892
+ const $ = c(5);
8893
+ const { element } = t0;
8894
+ const [bounds, setBounds] = useState(null);
8895
+ let t1;
8896
+ let t2;
8897
+ if ($[0] !== element) {
8898
+ t1 = () => {
8899
+ const owner = element.ownerDocument.defaultView;
8900
+ const measure = () => {
8901
+ if (!element.isConnected) {
8902
+ setBounds(null);
8903
+ return;
8904
+ }
8905
+ const rect = element.getBoundingClientRect();
8906
+ setBounds({
8907
+ left: rect.left,
8908
+ top: rect.top,
8909
+ width: rect.width,
8910
+ height: rect.height
8911
+ });
8912
+ };
8913
+ measure();
8914
+ const observer = new ResizeObserver(measure);
8915
+ observer.observe(element);
8916
+ owner?.addEventListener("scroll", measure, true);
8917
+ owner?.addEventListener("resize", measure);
8918
+ return () => {
8919
+ observer.disconnect();
8920
+ owner?.removeEventListener("scroll", measure, true);
8921
+ owner?.removeEventListener("resize", measure);
8922
+ };
8923
+ };
8924
+ t2 = [element];
8925
+ $[0] = element;
8926
+ $[1] = t1;
8927
+ $[2] = t2;
8928
+ } else {
8929
+ t1 = $[1];
8930
+ t2 = $[2];
8931
+ }
8932
+ useLayoutEffect(t1, t2);
8933
+ let t3;
8934
+ if ($[3] !== bounds) {
8935
+ t3 = bounds ? /* @__PURE__ */ jsx("div", {
8936
+ className: "povio-canvas-inspection-overlay povio-canvas-layer-highlight",
8937
+ "aria-hidden": "true",
8938
+ children: /* @__PURE__ */ jsx("div", {
8939
+ className: "studio-hover-outline",
8940
+ style: bounds
8941
+ })
8942
+ }) : null;
8943
+ $[3] = bounds;
8944
+ $[4] = t3;
8945
+ } else t3 = $[4];
8946
+ return t3;
8947
+ }
8948
+ //#endregion
8949
+ export { UIConfigurationModal as a, resolveUIConfiguration as c, Trash as d, Sun as f, Moon as h, useCanvasInspector as i, UIConfigurationProvider as l, Pencil as m, CanvasInspectorPanel as n, ColorModeSwitch as o, Plus as p, CanvasLayerHighlight as r, useRepositoryStorage as s, CanvasInspectionOverlay as t, useUIConfiguration as u };