@povio/ui 5.0.0-rc.13 → 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.
- package/README.md +8 -0
- package/dist/{AppCanvasPage-DtWEvs_Y.js → AppCanvasPage-BnyCHO3I.js} +152 -462
- package/dist/{AppCanvasPage-BZ2mrKY4.d.ts → AppCanvasPage-U9SxNwjS.d.ts} +1 -1
- package/dist/{BottomSheet-BXLE3161.js → BottomSheet-AqYVSMK9.js} +1 -75
- package/dist/BottomSheetHeader-Be6Elvs2.js +79 -0
- package/dist/{Calendar-DRHruqr_.js → Calendar-1p3VjSED.js} +3 -3
- package/dist/{CanvasComponentsFrame-CbgJJv-3.js → CanvasComponentsFrame-Dp0oDDoH.js} +6 -6
- package/dist/{UIConfigurator-DekPXjv9.js → CanvasInspector-DdP3mHUY.js} +1707 -522
- package/dist/{ComponentGallery-COqEqqN6.js → ComponentGallery-C_rXFvUY.js} +250 -1797
- package/dist/{DatePicker-xDEqzNJv.js → DatePicker-CAzuZRmd.js} +6 -6
- package/dist/{DatePickerInput-B0fEeCOf.js → DatePickerInput-BeQOVCk0.js} +4 -3
- package/dist/{DateRangePicker-DxuVhRaf.js → DateRangePicker-X3mBhfmL.js} +5 -5
- package/dist/{DateTimePicker-4N1Pka07.js → DateTimePicker-EtmGtoRe.js} +6 -6
- package/dist/{InputItem-Cv19Hwnx.js → InputItem-yC5oMyN-.js} +7 -7
- package/dist/{Inputs-D1aE_J9f.js → Inputs-Bd2nRNqk.js} +1 -1
- package/dist/{NumberRangeInput-Bzfe-RlV.js → NumberRangeInput-TkPXiWV3.js} +2 -2
- package/dist/{RichTextEditor-Bd7F5D8f.js → RichTextEditor-DiaPcBUM.js} +110 -32
- package/dist/{Select-CgIhoWgk.js → Select-tNlFSbAC.js} +5 -5
- package/dist/{Table-piX1SWvN.js → Table-CgG02oHQ.js} +1 -1
- package/dist/{TextArea-uPffb457.js → TextArea-DuvFUjts.js} +1 -1
- package/dist/{TimePicker-DN-i98z5.js → TimePicker-CBkiE-Yq.js} +5 -4
- package/dist/{TooltipWrapper-CDHFaUKZ.js → TooltipWrapper-CSXs5-E3.js} +2 -2
- package/dist/components/autocomplete.js +3 -3
- package/dist/components/bottom-sheet.js +1 -1
- package/dist/components/date-picker.js +1 -1
- package/dist/components/date-range-picker.js +1 -1
- package/dist/components/date-time-picker.js +1 -1
- package/dist/components/input.js +3 -3
- package/dist/components/number-field.js +3 -3
- package/dist/components/number-range-input.js +1 -1
- package/dist/components/query-autocomplete.js +1 -1
- package/dist/components/query-select.js +2 -2
- package/dist/components/select.js +1 -1
- package/dist/components/text-area.js +1 -1
- package/dist/components/time-picker.js +1 -1
- package/dist/config/app-canvas-tanstack.d.ts +1 -1
- package/dist/config/app-canvas-tanstack.js +1 -1
- package/dist/config/app-canvas.d.ts +1 -1
- package/dist/config/app-canvas.js +1 -1
- package/dist/config/ui-configurator-vite.d.ts +2 -0
- package/dist/config/ui-configurator-vite.js +234 -8
- package/dist/config/ui-configurator.d.ts +21 -2
- package/dist/config/ui-configurator.js +121 -3
- package/dist/{datePickerValue.utils-QWR2q5Vv.js → datePickerValue.utils-BDB6KM8q.js} +1 -1
- package/dist/demos-DIwj5vc0.js +2011 -0
- package/dist/index.js +7 -7
- package/dist/{logger-CqZjM-sn.js → logger-CW24po62.js} +10 -1
- package/dist/rhf/date-picker.js +1 -1
- package/dist/rhf/date-range-picker.js +1 -1
- package/dist/rhf/date-time-picker.js +1 -1
- package/dist/rhf/number-range-input.js +1 -1
- package/dist/rhf/rich-text-editor.js +1 -1
- package/dist/rhf/select.js +1 -1
- package/dist/rhf/text-area.js +1 -1
- package/dist/rhf/time-picker.js +1 -1
- package/dist/rhf.js +7 -7
- package/dist/rich-text-editor.js +1 -1
- package/dist/{staticDateTimeSegments-BWea3HAt.js → staticDateTimeSegments-Bs1_N5MR.js} +1 -1
- package/dist/{staticSelect.utils-BfTCi26B.js → staticSelect.utils-BgdYv2vP.js} +5 -4
- package/dist/styles/app-canvas.css +30 -24
- package/dist/styles/configurator.css +544 -34
- package/dist/tanstack/date-picker.js +1 -1
- package/dist/tanstack/date-range-picker.js +1 -1
- package/dist/tanstack/date-time-picker.js +1 -1
- package/dist/tanstack/form.js +1 -1
- package/dist/tanstack/inputs.js +1 -1
- package/dist/tanstack/number-range-input.js +1 -1
- package/dist/tanstack/rich-text-editor.js +1 -1
- package/dist/tanstack/select.js +1 -1
- package/dist/tanstack/table.js +2 -2
- package/dist/tanstack/text-area.js +1 -1
- package/dist/tanstack/time-picker.js +1 -1
- package/dist/tanstack.js +15 -15
- package/dist/token-classes-BqLWiy6O.js +245 -0
- package/dist/{useFieldAccessibility-B-bjtrNw.js → useFieldAccessibility-DnCdz938.js} +2 -1
- package/dist/{useFormAutosave-pmh35PXp.js → useFormAutosave-CxqZAJAB.js} +1 -1
- package/dist/{useStaticInputHandoff-B7DEm75m.js → useStaticInputHandoff-DKsxpVck.js} +2 -1
- package/dist/{useTableColumnConfig-CNJ_ZvIN.js → useTableColumnConfig-BnbKElno.js} +1 -1
- package/dist/utils/logger.js +1 -1
- package/package.json +1 -1
- package/dist/groups-oQmSeqXn.js +0 -18
- 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-
|
|
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$
|
|
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$
|
|
714
|
+
if (remount) setRevision(_temp3$5);
|
|
714
715
|
};
|
|
715
716
|
$[1] = t2;
|
|
716
717
|
} else t2 = $[1];
|
|
@@ -731,7 +732,7 @@ function UIConfigurationProvider(t0) {
|
|
|
731
732
|
let t4;
|
|
732
733
|
if ($[4] !== isOpen || $[5] !== open) {
|
|
733
734
|
t4 = () => {
|
|
734
|
-
if (isOpen) setRevision(_temp5$
|
|
735
|
+
if (isOpen) setRevision(_temp5$3);
|
|
735
736
|
else open();
|
|
736
737
|
setFloating(true);
|
|
737
738
|
};
|
|
@@ -883,16 +884,16 @@ function UIConfigurationProvider(t0) {
|
|
|
883
884
|
} else t17 = $[49];
|
|
884
885
|
return t17;
|
|
885
886
|
}
|
|
886
|
-
function _temp5$
|
|
887
|
+
function _temp5$3(value_1) {
|
|
887
888
|
return value_1 + 1;
|
|
888
889
|
}
|
|
889
890
|
function _temp4$4(value_0) {
|
|
890
891
|
return value_0 + 1;
|
|
891
892
|
}
|
|
892
|
-
function _temp3$
|
|
893
|
+
function _temp3$5(current) {
|
|
893
894
|
return current + 1;
|
|
894
895
|
}
|
|
895
|
-
function _temp2$
|
|
896
|
+
function _temp2$6(count_0) {
|
|
896
897
|
return count_0 - 1;
|
|
897
898
|
}
|
|
898
899
|
function _temp$8(count) {
|
|
@@ -904,6 +905,360 @@ function useUIConfiguration() {
|
|
|
904
905
|
return context;
|
|
905
906
|
}
|
|
906
907
|
//#endregion
|
|
908
|
+
//#region src/configurator/theme-writer-protocol.ts
|
|
909
|
+
/** Shared by the browser configurator and the isolated Node Vite entry. */
|
|
910
|
+
const themeWriterMetaName = "povio-ui-theme-writer";
|
|
911
|
+
const themeWriterTokenHeader = "x-povio-ui-theme-token";
|
|
912
|
+
//#endregion
|
|
913
|
+
//#region src/configurator/theme-writer-client.ts
|
|
914
|
+
function getThemeWriter() {
|
|
915
|
+
if (typeof document === "undefined") return null;
|
|
916
|
+
const content = document.querySelector(`meta[name="${themeWriterMetaName}"]`)?.content;
|
|
917
|
+
if (!content) return null;
|
|
918
|
+
try {
|
|
919
|
+
const connection = JSON.parse(content);
|
|
920
|
+
if (typeof connection.endpoint === "string" && connection.endpoint.startsWith("/") && !connection.endpoint.startsWith("//") && typeof connection.token === "string" && typeof connection.file === "string") return connection;
|
|
921
|
+
} catch {}
|
|
922
|
+
return null;
|
|
923
|
+
}
|
|
924
|
+
async function saveThemeCss(connection, css) {
|
|
925
|
+
const response = await fetch(connection.endpoint, {
|
|
926
|
+
method: "POST",
|
|
927
|
+
headers: {
|
|
928
|
+
"Content-Type": "application/json",
|
|
929
|
+
[themeWriterTokenHeader]: connection.token
|
|
930
|
+
},
|
|
931
|
+
body: JSON.stringify({ css })
|
|
932
|
+
});
|
|
933
|
+
if (!response.ok) {
|
|
934
|
+
const result = await response.json().catch(() => null);
|
|
935
|
+
throw new Error(result?.error ?? `Theme save failed (${response.status}).`);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
//#endregion
|
|
939
|
+
//#region src/configurator/fontsource-client.ts
|
|
940
|
+
const validId = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
941
|
+
let catalog;
|
|
942
|
+
/** One metadata request per page, not one font download per search result. */
|
|
943
|
+
function loadFontsourceCatalog() {
|
|
944
|
+
catalog ??= fetch("https://api.fontsource.org/v1/fonts", { signal: AbortSignal.timeout(15e3) }).then(async (response) => {
|
|
945
|
+
if (!response.ok) throw new Error("Fontsource is unavailable. Try again.");
|
|
946
|
+
const data = await response.json();
|
|
947
|
+
if (!Array.isArray(data)) throw new Error("Fontsource returned an invalid catalog.");
|
|
948
|
+
return data.filter((font) => font && typeof font.id === "string" && font.id.length <= 100 && validId.test(font.id) && typeof font.family === "string" && typeof font.category === "string" && typeof font.variable === "boolean" && Array.isArray(font.subsets) && font.subsets.every((s) => typeof s === "string" && validId.test(s)) && typeof font.defSubset === "string" && font.subsets.includes(font.defSubset) && Array.isArray(font.weights) && font.weights.length > 0 && font.weights.every((w) => typeof w === "number" && w > 0 && w <= 1e3) && Array.isArray(font.styles) && (font.styles.includes("normal") || font.styles.includes("italic")) && font.type !== "icons").sort((a, b) => a.family.localeCompare(b.family));
|
|
949
|
+
}).catch((error) => {
|
|
950
|
+
catalog = void 0;
|
|
951
|
+
throw error;
|
|
952
|
+
});
|
|
953
|
+
return catalog;
|
|
954
|
+
}
|
|
955
|
+
function fontsourceWriter() {
|
|
956
|
+
const writer = getThemeWriter();
|
|
957
|
+
const fonts = writer?.fontsource;
|
|
958
|
+
return fonts && typeof fonts.endpoint === "string" && fonts.endpoint.startsWith("/") && !fonts.endpoint.startsWith("//") && typeof fonts.cssFile === "string" ? {
|
|
959
|
+
...fonts,
|
|
960
|
+
token: writer.token
|
|
961
|
+
} : null;
|
|
962
|
+
}
|
|
963
|
+
async function addFontsourceFamily(id) {
|
|
964
|
+
const writer = fontsourceWriter();
|
|
965
|
+
if (!writer) throw new Error("Adding fonts requires the Povio UI Vite plugin in a development server.");
|
|
966
|
+
const response = await fetch(writer.endpoint, {
|
|
967
|
+
method: "POST",
|
|
968
|
+
headers: {
|
|
969
|
+
"Content-Type": "application/json",
|
|
970
|
+
[themeWriterTokenHeader]: writer.token
|
|
971
|
+
},
|
|
972
|
+
body: JSON.stringify({ id })
|
|
973
|
+
});
|
|
974
|
+
const result = await response.json();
|
|
975
|
+
if (!response.ok) throw new Error(result.error ?? "Could not add this font to the app.");
|
|
976
|
+
if (typeof result.family !== "string" || typeof result.packageName !== "string" || !Array.isArray(result.imports)) throw new Error("The font installer returned an invalid response.");
|
|
977
|
+
return result;
|
|
978
|
+
}
|
|
979
|
+
/** The static preview is temporary; installed variable families use their full range. */
|
|
980
|
+
function fontsourcePreview(font) {
|
|
981
|
+
const subset = font.subsets.includes("latin") ? "latin" : font.defSubset;
|
|
982
|
+
const weight = font.weights.includes(400) ? 400 : font.weights[0];
|
|
983
|
+
const style = font.styles.includes("normal") ? "normal" : "italic";
|
|
984
|
+
return {
|
|
985
|
+
alias: `Povio Fontsource preview ${font.id}`,
|
|
986
|
+
weight,
|
|
987
|
+
style,
|
|
988
|
+
url: `https://cdn.jsdelivr.net/fontsource/fonts/${font.id}@latest/${subset}-${weight}-${style}.woff2`
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
//#endregion
|
|
992
|
+
//#region src/configurator/FontsourcePicker.tsx
|
|
993
|
+
function FontsourcePicker({ roles, onAdded }) {
|
|
994
|
+
const trigger = useRef(null);
|
|
995
|
+
const mounted = useRef(true);
|
|
996
|
+
useEffect(() => {
|
|
997
|
+
mounted.current = true;
|
|
998
|
+
return () => {
|
|
999
|
+
mounted.current = false;
|
|
1000
|
+
};
|
|
1001
|
+
}, []);
|
|
1002
|
+
const [open, setOpen] = useState(false);
|
|
1003
|
+
const [fonts, setFonts] = useState([]);
|
|
1004
|
+
const [loading, setLoading] = useState(false);
|
|
1005
|
+
const [query, setQuery] = useState("");
|
|
1006
|
+
const [limit, setLimit] = useState(30);
|
|
1007
|
+
const [category, setCategory] = useState("");
|
|
1008
|
+
const [variableOnly, setVariableOnly] = useState(false);
|
|
1009
|
+
useEffect(() => setLimit(30), [
|
|
1010
|
+
query,
|
|
1011
|
+
category,
|
|
1012
|
+
variableOnly
|
|
1013
|
+
]);
|
|
1014
|
+
const [selected, setSelected] = useState(null);
|
|
1015
|
+
const [sample, setSample] = useState("The quick brown fox jumps over the lazy dog.");
|
|
1016
|
+
const [previewState, setPreviewState] = useState("loading");
|
|
1017
|
+
const [role, setRole] = useState(roles[0]?.token ?? "");
|
|
1018
|
+
const [adding, setAdding] = useState(false);
|
|
1019
|
+
const [error, setError] = useState("");
|
|
1020
|
+
const [notice, setNotice] = useState("");
|
|
1021
|
+
const [retry, setRetry] = useState(0);
|
|
1022
|
+
const writer = fontsourceWriter();
|
|
1023
|
+
useEffect(() => {
|
|
1024
|
+
if (!open) return;
|
|
1025
|
+
let active = true;
|
|
1026
|
+
setLoading(true);
|
|
1027
|
+
setError("");
|
|
1028
|
+
loadFontsourceCatalog().then((value) => {
|
|
1029
|
+
if (active) setFonts(value);
|
|
1030
|
+
}).catch((cause) => {
|
|
1031
|
+
if (active) setError(cause instanceof Error ? cause.message : "Could not load Fontsource.");
|
|
1032
|
+
}).finally(() => {
|
|
1033
|
+
if (active) setLoading(false);
|
|
1034
|
+
});
|
|
1035
|
+
return () => {
|
|
1036
|
+
active = false;
|
|
1037
|
+
};
|
|
1038
|
+
}, [open, retry]);
|
|
1039
|
+
useEffect(() => {
|
|
1040
|
+
if (!open || !selected) return;
|
|
1041
|
+
let active_0 = true;
|
|
1042
|
+
const doc = trigger.current?.ownerDocument ?? document;
|
|
1043
|
+
const preview = fontsourcePreview(selected);
|
|
1044
|
+
const face = new FontFace(preview.alias, `url("${preview.url}")`, {
|
|
1045
|
+
weight: String(preview.weight),
|
|
1046
|
+
style: preview.style
|
|
1047
|
+
});
|
|
1048
|
+
setPreviewState("loading");
|
|
1049
|
+
face.load().then((loaded) => {
|
|
1050
|
+
if (active_0) {
|
|
1051
|
+
doc.fonts.add(loaded);
|
|
1052
|
+
setPreviewState("ready");
|
|
1053
|
+
}
|
|
1054
|
+
}).catch(() => {
|
|
1055
|
+
if (active_0) setPreviewState("error");
|
|
1056
|
+
});
|
|
1057
|
+
return () => {
|
|
1058
|
+
active_0 = false;
|
|
1059
|
+
doc.fonts.delete(face);
|
|
1060
|
+
};
|
|
1061
|
+
}, [open, selected]);
|
|
1062
|
+
const filtered = useMemo(() => fonts.filter((font) => font.family.toLowerCase().includes(query.trim().toLowerCase()) && (!category || category === font.category) && (!variableOnly || font.variable)), [
|
|
1063
|
+
fonts,
|
|
1064
|
+
query,
|
|
1065
|
+
category,
|
|
1066
|
+
variableOnly
|
|
1067
|
+
]);
|
|
1068
|
+
const preview_0 = selected ? fontsourcePreview(selected) : null;
|
|
1069
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1070
|
+
className: "studio-fontsource",
|
|
1071
|
+
children: [
|
|
1072
|
+
/* @__PURE__ */ jsx("button", {
|
|
1073
|
+
ref: trigger,
|
|
1074
|
+
type: "button",
|
|
1075
|
+
className: "studio-gallery-back",
|
|
1076
|
+
onClick: () => {
|
|
1077
|
+
setOpen(true);
|
|
1078
|
+
setError("");
|
|
1079
|
+
},
|
|
1080
|
+
children: "Browse Fontsource"
|
|
1081
|
+
}),
|
|
1082
|
+
notice && /* @__PURE__ */ jsx("span", {
|
|
1083
|
+
className: "studio-fontsource-notice",
|
|
1084
|
+
role: "status",
|
|
1085
|
+
children: notice
|
|
1086
|
+
}),
|
|
1087
|
+
/* @__PURE__ */ jsx($542a13ca2fa5b484$export$5b6b19405a83ff9d, {
|
|
1088
|
+
triggerRef: trigger,
|
|
1089
|
+
placement: "bottom start",
|
|
1090
|
+
offset: 6,
|
|
1091
|
+
isOpen: open,
|
|
1092
|
+
onOpenChange: (value_0) => {
|
|
1093
|
+
if (!adding) setOpen(value_0);
|
|
1094
|
+
},
|
|
1095
|
+
isKeyboardDismissDisabled: adding,
|
|
1096
|
+
className: "studio-fontsource-popover",
|
|
1097
|
+
children: /* @__PURE__ */ jsxs($f2ff30fde7b014be$export$3ddf2d174ce01153, {
|
|
1098
|
+
"aria-label": "Fontsource font picker",
|
|
1099
|
+
children: [
|
|
1100
|
+
/* @__PURE__ */ jsxs("header", { children: [/* @__PURE__ */ jsx($2ec61d1d4f780267$export$a8a3e93435678ff9, {
|
|
1101
|
+
slot: "title",
|
|
1102
|
+
children: "Fontsource fonts"
|
|
1103
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
1104
|
+
type: "button",
|
|
1105
|
+
"aria-label": "Close font picker",
|
|
1106
|
+
disabled: adding,
|
|
1107
|
+
onClick: () => setOpen(false),
|
|
1108
|
+
children: /* @__PURE__ */ jsx(X, { size: 13 })
|
|
1109
|
+
})] }),
|
|
1110
|
+
/* @__PURE__ */ jsxs("label", {
|
|
1111
|
+
className: "studio-fontsource-search",
|
|
1112
|
+
children: [/* @__PURE__ */ jsx(Search, { size: 13 }), /* @__PURE__ */ jsx("input", {
|
|
1113
|
+
autoFocus: true,
|
|
1114
|
+
"aria-label": "Search Fontsource fonts",
|
|
1115
|
+
placeholder: "Find a font family…",
|
|
1116
|
+
value: query,
|
|
1117
|
+
onChange: (event) => setQuery(event.target.value)
|
|
1118
|
+
})]
|
|
1119
|
+
}),
|
|
1120
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1121
|
+
className: "studio-fontsource-filters",
|
|
1122
|
+
children: [/* @__PURE__ */ jsxs("select", {
|
|
1123
|
+
"aria-label": "Font category",
|
|
1124
|
+
value: category,
|
|
1125
|
+
onChange: (event_0) => setCategory(event_0.target.value),
|
|
1126
|
+
children: [/* @__PURE__ */ jsx("option", {
|
|
1127
|
+
value: "",
|
|
1128
|
+
children: "All categories"
|
|
1129
|
+
}), [...new Set(fonts.map((font_0) => font_0.category))].sort().map((name) => /* @__PURE__ */ jsx("option", {
|
|
1130
|
+
value: name,
|
|
1131
|
+
children: name
|
|
1132
|
+
}, name))]
|
|
1133
|
+
}), /* @__PURE__ */ jsxs("label", { children: [
|
|
1134
|
+
/* @__PURE__ */ jsx("input", {
|
|
1135
|
+
type: "checkbox",
|
|
1136
|
+
checked: variableOnly,
|
|
1137
|
+
onChange: (event_1) => setVariableOnly(event_1.target.checked)
|
|
1138
|
+
}),
|
|
1139
|
+
" ",
|
|
1140
|
+
"Variable only"
|
|
1141
|
+
] })]
|
|
1142
|
+
}),
|
|
1143
|
+
loading ? /* @__PURE__ */ jsx("p", {
|
|
1144
|
+
role: "status",
|
|
1145
|
+
children: "Loading font families…"
|
|
1146
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1147
|
+
/* @__PURE__ */ jsxs("span", {
|
|
1148
|
+
className: "studio-fontsource-count",
|
|
1149
|
+
children: [
|
|
1150
|
+
filtered.length,
|
|
1151
|
+
" families",
|
|
1152
|
+
filtered.length > limit ? ` · showing ${limit}` : ""
|
|
1153
|
+
]
|
|
1154
|
+
}),
|
|
1155
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1156
|
+
className: "studio-fontsource-list",
|
|
1157
|
+
role: "group",
|
|
1158
|
+
"aria-label": "Fontsource families",
|
|
1159
|
+
children: [filtered.slice(0, limit).map((font_1) => /* @__PURE__ */ jsxs("button", {
|
|
1160
|
+
type: "button",
|
|
1161
|
+
disabled: adding,
|
|
1162
|
+
"aria-pressed": selected?.id === font_1.id,
|
|
1163
|
+
onClick: () => {
|
|
1164
|
+
setSelected(font_1);
|
|
1165
|
+
setError("");
|
|
1166
|
+
},
|
|
1167
|
+
children: [
|
|
1168
|
+
/* @__PURE__ */ jsx("span", { children: font_1.family }),
|
|
1169
|
+
/* @__PURE__ */ jsxs("small", { children: [font_1.category, font_1.variable ? " · variable" : ""] }),
|
|
1170
|
+
selected?.id === font_1.id && /* @__PURE__ */ jsx(Check, { size: 12 })
|
|
1171
|
+
]
|
|
1172
|
+
}, font_1.id)), !filtered.length && !error && /* @__PURE__ */ jsx("p", { children: "No matching font families." })]
|
|
1173
|
+
}),
|
|
1174
|
+
filtered.length > limit && /* @__PURE__ */ jsx("button", {
|
|
1175
|
+
type: "button",
|
|
1176
|
+
className: "studio-fontsource-more",
|
|
1177
|
+
onClick: () => setLimit((value_1) => value_1 + 30),
|
|
1178
|
+
children: "Show more fonts"
|
|
1179
|
+
})
|
|
1180
|
+
] }),
|
|
1181
|
+
selected && /* @__PURE__ */ jsxs("section", {
|
|
1182
|
+
className: "studio-fontsource-preview",
|
|
1183
|
+
"aria-label": `Preview ${selected.family}`,
|
|
1184
|
+
children: [
|
|
1185
|
+
/* @__PURE__ */ jsx("strong", { children: selected.family }),
|
|
1186
|
+
/* @__PURE__ */ jsx("input", {
|
|
1187
|
+
"aria-label": "Font preview text",
|
|
1188
|
+
value: sample,
|
|
1189
|
+
onChange: (event_2) => setSample(event_2.target.value)
|
|
1190
|
+
}),
|
|
1191
|
+
/* @__PURE__ */ jsx("p", {
|
|
1192
|
+
className: "studio-fontsource-sample",
|
|
1193
|
+
style: {
|
|
1194
|
+
fontFamily: previewState === "ready" ? `"${preview_0.alias}", sans-serif` : "inherit",
|
|
1195
|
+
fontWeight: preview_0?.weight,
|
|
1196
|
+
fontStyle: preview_0?.style
|
|
1197
|
+
},
|
|
1198
|
+
children: sample || "Aa Bb Cc 0123456789"
|
|
1199
|
+
}),
|
|
1200
|
+
/* @__PURE__ */ jsx("span", {
|
|
1201
|
+
role: "status",
|
|
1202
|
+
children: previewState === "loading" ? "Loading preview…" : previewState === "error" ? "Preview could not load. You can still add this family." : ""
|
|
1203
|
+
}),
|
|
1204
|
+
/* @__PURE__ */ jsxs("label", {
|
|
1205
|
+
className: "studio-fontsource-role",
|
|
1206
|
+
children: ["Use for", /* @__PURE__ */ jsxs("select", {
|
|
1207
|
+
"aria-label": "Use font for",
|
|
1208
|
+
value: role,
|
|
1209
|
+
disabled: adding,
|
|
1210
|
+
onChange: (event_3) => setRole(event_3.target.value),
|
|
1211
|
+
children: [/* @__PURE__ */ jsx("option", {
|
|
1212
|
+
value: "",
|
|
1213
|
+
children: "Add to available fonts"
|
|
1214
|
+
}), roles.map((item) => /* @__PURE__ */ jsx("option", {
|
|
1215
|
+
value: item.token,
|
|
1216
|
+
children: item.label
|
|
1217
|
+
}, item.token))]
|
|
1218
|
+
})]
|
|
1219
|
+
}),
|
|
1220
|
+
/* @__PURE__ */ jsx("button", {
|
|
1221
|
+
type: "button",
|
|
1222
|
+
className: "studio-primary",
|
|
1223
|
+
disabled: adding || !writer,
|
|
1224
|
+
onClick: async () => {
|
|
1225
|
+
setAdding(true);
|
|
1226
|
+
setError("");
|
|
1227
|
+
try {
|
|
1228
|
+
const font_2 = await addFontsourceFamily(selected.id);
|
|
1229
|
+
if (!mounted.current) return;
|
|
1230
|
+
onAdded(font_2, role || void 0);
|
|
1231
|
+
setNotice(`${font_2.family} added to the app.`);
|
|
1232
|
+
setOpen(false);
|
|
1233
|
+
} catch (cause_0) {
|
|
1234
|
+
setError(cause_0 instanceof Error ? cause_0.message : "Could not add font.");
|
|
1235
|
+
} finally {
|
|
1236
|
+
setAdding(false);
|
|
1237
|
+
}
|
|
1238
|
+
},
|
|
1239
|
+
children: adding ? "Adding font…" : "Add font to app"
|
|
1240
|
+
})
|
|
1241
|
+
]
|
|
1242
|
+
}),
|
|
1243
|
+
error && /* @__PURE__ */ jsxs("p", {
|
|
1244
|
+
role: "alert",
|
|
1245
|
+
children: [error, !fonts.length && /* @__PURE__ */ jsx("button", {
|
|
1246
|
+
type: "button",
|
|
1247
|
+
onClick: () => setRetry((value_2) => value_2 + 1),
|
|
1248
|
+
children: "Retry"
|
|
1249
|
+
})]
|
|
1250
|
+
}),
|
|
1251
|
+
/* @__PURE__ */ jsx("p", {
|
|
1252
|
+
className: "studio-fontsource-help",
|
|
1253
|
+
children: writer ? `Adding installs the font package and updates ${writer.cssFile}. Your theme version keeps the Heading/Body choice; Apply theme writes it to the repo.` : "Preview fonts here. Adding them to your app requires the Povio UI Vite plugin in development."
|
|
1254
|
+
})
|
|
1255
|
+
]
|
|
1256
|
+
})
|
|
1257
|
+
})
|
|
1258
|
+
]
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
1261
|
+
//#endregion
|
|
907
1262
|
//#region src/configurator/inspector/InspectorDetails.tsx
|
|
908
1263
|
/** A token as a design tool names a variable: `--text-large--line-height` → `text-large/line-height`. */
|
|
909
1264
|
const variableName = (token) => token.replace(/^--/, "").replace(/-base$/, "").replaceAll("--", "/");
|
|
@@ -983,7 +1338,7 @@ function InspectorDetails(t0) {
|
|
|
983
1338
|
$[13] = onSelect;
|
|
984
1339
|
$[14] = t6;
|
|
985
1340
|
} else t6 = $[14];
|
|
986
|
-
t5 = snapshot.groups.map(_temp$7).filter(_temp2$
|
|
1341
|
+
t5 = snapshot.groups.map(_temp$7).filter(_temp2$5).map(t6);
|
|
987
1342
|
$[10] = onSelect;
|
|
988
1343
|
$[11] = snapshot.groups;
|
|
989
1344
|
$[12] = t5;
|
|
@@ -997,7 +1352,7 @@ function InspectorDetails(t0) {
|
|
|
997
1352
|
} else t6 = $[17];
|
|
998
1353
|
return t6;
|
|
999
1354
|
}
|
|
1000
|
-
function _temp2$
|
|
1355
|
+
function _temp2$5(group_0) {
|
|
1001
1356
|
return group_0.properties.length;
|
|
1002
1357
|
}
|
|
1003
1358
|
function _temp$7(group) {
|
|
@@ -1025,7 +1380,7 @@ function BoxModel(t0) {
|
|
|
1025
1380
|
let t3;
|
|
1026
1381
|
let t4;
|
|
1027
1382
|
if ($[0] !== box.border || $[1] !== box.content.height || $[2] !== box.content.width || $[3] !== box.gap.column || $[4] !== box.gap.row || $[5] !== box.margin || $[6] !== box.padding || $[7] !== box.position || $[8] !== box.radius || $[9] !== onHighlight || $[10] !== onSelect || $[11] !== snapshot.groups) {
|
|
1028
|
-
const properties = snapshot.groups.flatMap(_temp5$
|
|
1383
|
+
const properties = snapshot.groups.flatMap(_temp5$2);
|
|
1029
1384
|
const tokenFor = (label) => properties.find((property) => property.label === label)?.token;
|
|
1030
1385
|
const nonzero = _temp7$1;
|
|
1031
1386
|
let t5;
|
|
@@ -1204,13 +1559,13 @@ function _temp7$1(value_0) {
|
|
|
1204
1559
|
function _temp6$1(part) {
|
|
1205
1560
|
return parseFloat(part) !== 0 && Number.isFinite(parseFloat(part));
|
|
1206
1561
|
}
|
|
1207
|
-
function _temp5$
|
|
1562
|
+
function _temp5$2(group) {
|
|
1208
1563
|
return group.properties;
|
|
1209
1564
|
}
|
|
1210
1565
|
function _temp4$3(value) {
|
|
1211
|
-
return value.replace(/(-?\d*\.?\d+)px/g, _temp3$
|
|
1566
|
+
return value.replace(/(-?\d*\.?\d+)px/g, _temp3$4);
|
|
1212
1567
|
}
|
|
1213
|
-
function _temp3$
|
|
1568
|
+
function _temp3$4(_, amount) {
|
|
1214
1569
|
return String(Math.round(Number(amount) * 10) / 10);
|
|
1215
1570
|
}
|
|
1216
1571
|
//#endregion
|
|
@@ -1480,236 +1835,6 @@ function getBoxHighlights(element, key) {
|
|
|
1480
1835
|
};
|
|
1481
1836
|
}
|
|
1482
1837
|
//#endregion
|
|
1483
|
-
//#region src/configurator/inspector/token-classes.ts
|
|
1484
|
-
/** Tailwind breakpoints from the Atlas base theme, in rem. */
|
|
1485
|
-
const breakpoints = {
|
|
1486
|
-
sm: 23.75,
|
|
1487
|
-
md: 37.5,
|
|
1488
|
-
lg: 80,
|
|
1489
|
-
xl: 105
|
|
1490
|
-
};
|
|
1491
|
-
/** Utility prefix → the slots it sets, its specificity, and the theme namespace its value lives in. */
|
|
1492
|
-
const utilities = [
|
|
1493
|
-
[
|
|
1494
|
-
"p",
|
|
1495
|
-
[
|
|
1496
|
-
"padding.top",
|
|
1497
|
-
"padding.right",
|
|
1498
|
-
"padding.bottom",
|
|
1499
|
-
"padding.left"
|
|
1500
|
-
],
|
|
1501
|
-
0,
|
|
1502
|
-
"spacing"
|
|
1503
|
-
],
|
|
1504
|
-
[
|
|
1505
|
-
"px",
|
|
1506
|
-
["padding.left", "padding.right"],
|
|
1507
|
-
1,
|
|
1508
|
-
"spacing"
|
|
1509
|
-
],
|
|
1510
|
-
[
|
|
1511
|
-
"py",
|
|
1512
|
-
["padding.top", "padding.bottom"],
|
|
1513
|
-
1,
|
|
1514
|
-
"spacing"
|
|
1515
|
-
],
|
|
1516
|
-
[
|
|
1517
|
-
"pt",
|
|
1518
|
-
["padding.top"],
|
|
1519
|
-
2,
|
|
1520
|
-
"spacing"
|
|
1521
|
-
],
|
|
1522
|
-
[
|
|
1523
|
-
"pr",
|
|
1524
|
-
["padding.right"],
|
|
1525
|
-
2,
|
|
1526
|
-
"spacing"
|
|
1527
|
-
],
|
|
1528
|
-
[
|
|
1529
|
-
"pe",
|
|
1530
|
-
["padding.right"],
|
|
1531
|
-
2,
|
|
1532
|
-
"spacing"
|
|
1533
|
-
],
|
|
1534
|
-
[
|
|
1535
|
-
"pb",
|
|
1536
|
-
["padding.bottom"],
|
|
1537
|
-
2,
|
|
1538
|
-
"spacing"
|
|
1539
|
-
],
|
|
1540
|
-
[
|
|
1541
|
-
"pl",
|
|
1542
|
-
["padding.left"],
|
|
1543
|
-
2,
|
|
1544
|
-
"spacing"
|
|
1545
|
-
],
|
|
1546
|
-
[
|
|
1547
|
-
"ps",
|
|
1548
|
-
["padding.left"],
|
|
1549
|
-
2,
|
|
1550
|
-
"spacing"
|
|
1551
|
-
],
|
|
1552
|
-
[
|
|
1553
|
-
"gap",
|
|
1554
|
-
["gap.row", "gap.column"],
|
|
1555
|
-
0,
|
|
1556
|
-
"spacing"
|
|
1557
|
-
],
|
|
1558
|
-
[
|
|
1559
|
-
"gap-x",
|
|
1560
|
-
["gap.column"],
|
|
1561
|
-
1,
|
|
1562
|
-
"spacing"
|
|
1563
|
-
],
|
|
1564
|
-
[
|
|
1565
|
-
"gap-y",
|
|
1566
|
-
["gap.row"],
|
|
1567
|
-
1,
|
|
1568
|
-
"spacing"
|
|
1569
|
-
],
|
|
1570
|
-
[
|
|
1571
|
-
"rounded",
|
|
1572
|
-
["radius"],
|
|
1573
|
-
0,
|
|
1574
|
-
"radius"
|
|
1575
|
-
]
|
|
1576
|
-
];
|
|
1577
|
-
/** Splits `md:hover:px-4` into its variants and utility, ignoring colons inside `[...]` / `(...)`. */
|
|
1578
|
-
function splitVariants(className) {
|
|
1579
|
-
const parts = [];
|
|
1580
|
-
let depth = 0;
|
|
1581
|
-
let current = "";
|
|
1582
|
-
for (const char of className) {
|
|
1583
|
-
if (char === "[" || char === "(") depth++;
|
|
1584
|
-
if (char === "]" || char === ")") depth--;
|
|
1585
|
-
if (char === ":" && depth === 0) {
|
|
1586
|
-
parts.push(current);
|
|
1587
|
-
current = "";
|
|
1588
|
-
} else current += char;
|
|
1589
|
-
}
|
|
1590
|
-
return {
|
|
1591
|
-
variants: parts,
|
|
1592
|
-
utility: current
|
|
1593
|
-
};
|
|
1594
|
-
}
|
|
1595
|
-
/** Variants that style a pseudo-element or other elements, never the element's own value. */
|
|
1596
|
-
const otherTargets = /* @__PURE__ */ new Set([
|
|
1597
|
-
"placeholder",
|
|
1598
|
-
"before",
|
|
1599
|
-
"after",
|
|
1600
|
-
"selection",
|
|
1601
|
-
"marker",
|
|
1602
|
-
"file",
|
|
1603
|
-
"first-letter",
|
|
1604
|
-
"first-line",
|
|
1605
|
-
"backdrop",
|
|
1606
|
-
"*",
|
|
1607
|
-
"**"
|
|
1608
|
-
]);
|
|
1609
|
-
const stateSelectors = {
|
|
1610
|
-
hover: ":hover",
|
|
1611
|
-
focus: ":focus",
|
|
1612
|
-
"focus-within": ":focus-within",
|
|
1613
|
-
"focus-visible": ":focus-visible",
|
|
1614
|
-
active: ":active",
|
|
1615
|
-
disabled: ":disabled",
|
|
1616
|
-
enabled: ":enabled",
|
|
1617
|
-
checked: ":checked",
|
|
1618
|
-
indeterminate: ":indeterminate",
|
|
1619
|
-
invalid: ":invalid",
|
|
1620
|
-
valid: ":valid",
|
|
1621
|
-
required: ":required",
|
|
1622
|
-
optional: ":optional",
|
|
1623
|
-
"read-only": ":read-only",
|
|
1624
|
-
"placeholder-shown": ":placeholder-shown",
|
|
1625
|
-
empty: ":empty",
|
|
1626
|
-
open: ":is([open], :popover-open, :open)",
|
|
1627
|
-
first: ":first-child",
|
|
1628
|
-
last: ":last-child",
|
|
1629
|
-
only: ":only-child",
|
|
1630
|
-
odd: ":nth-child(odd)",
|
|
1631
|
-
even: ":nth-child(even)"
|
|
1632
|
-
};
|
|
1633
|
-
/** A CSS selector for one state variant, or `undefined` when its condition cannot be read from the element. */
|
|
1634
|
-
function variantSelector(variant) {
|
|
1635
|
-
if (variant.startsWith("not-")) {
|
|
1636
|
-
const inner = variantSelector(variant.slice(4));
|
|
1637
|
-
return inner && `:not(${inner})`;
|
|
1638
|
-
}
|
|
1639
|
-
if (variant.startsWith("has-")) {
|
|
1640
|
-
const inner = variantSelector(variant.slice(4));
|
|
1641
|
-
return inner && `:has(${inner})`;
|
|
1642
|
-
}
|
|
1643
|
-
if (stateSelectors[variant]) return stateSelectors[variant];
|
|
1644
|
-
if (variant.startsWith("aria-") && !variant.includes("[")) return `[aria-${variant.slice(5)}="true"]`;
|
|
1645
|
-
const arbitrary = variant.match(/^\[(&?)(:[^\s&>+~,]+)\]$/);
|
|
1646
|
-
return arbitrary ? arbitrary[2].replaceAll("_", " ") : void 0;
|
|
1647
|
-
}
|
|
1648
|
-
/**
|
|
1649
|
-
* How a variant class relates to an element's current value: `other` styles a pseudo-element or descendants,
|
|
1650
|
-
* `inactive` / `active` are state conditions read from the element, and `unknown` covers breakpoints, container
|
|
1651
|
-
* queries, group/peer state and anything else that cannot be checked from the element alone.
|
|
1652
|
-
*/
|
|
1653
|
-
function variantState(variants, element) {
|
|
1654
|
-
if (variants.some((variant) => otherTargets.has(variant))) return "other";
|
|
1655
|
-
const selectors = variants.map(variantSelector);
|
|
1656
|
-
if (selectors.some((selector) => selector === void 0) || typeof element.matches !== "function") return "unknown";
|
|
1657
|
-
try {
|
|
1658
|
-
return element.matches(`*${selectors.join("")}`) ? "active" : "inactive";
|
|
1659
|
-
} catch {
|
|
1660
|
-
return "unknown";
|
|
1661
|
-
}
|
|
1662
|
-
}
|
|
1663
|
-
/** Breakpoint weight when every variant is an active breakpoint; `undefined` for state variants or inactive breakpoints. */
|
|
1664
|
-
function variantWeight(variants, viewportWidth, rootFontSize) {
|
|
1665
|
-
let weight = 0;
|
|
1666
|
-
for (const variant of variants) {
|
|
1667
|
-
const max = variant.startsWith("max-");
|
|
1668
|
-
const size = breakpoints[max ? variant.slice(4) : variant];
|
|
1669
|
-
if (size === void 0) return void 0;
|
|
1670
|
-
if (!(max ? viewportWidth < size * rootFontSize : viewportWidth >= size * rootFontSize)) return void 0;
|
|
1671
|
-
weight = Math.max(weight, size);
|
|
1672
|
-
}
|
|
1673
|
-
return weight;
|
|
1674
|
-
}
|
|
1675
|
-
function tokenFor(value, namespace, isKnown) {
|
|
1676
|
-
const referenced = value.match(/^\[.*?var\((--[\w-]+)/)?.[1] ?? value.match(/^\((--[\w-]+)\)$/)?.[1];
|
|
1677
|
-
if (referenced) return isKnown(referenced) ? referenced : void 0;
|
|
1678
|
-
const name = `--${namespace}-${value}`;
|
|
1679
|
-
return isKnown(name) ? name : void 0;
|
|
1680
|
-
}
|
|
1681
|
-
/**
|
|
1682
|
-
* Resolves which theme tokens drive an element's padding, gap and radius from its rendered Tailwind classes.
|
|
1683
|
-
* Only tokens accepted by `isKnown` are returned, so every result can be opened in the editor.
|
|
1684
|
-
*/
|
|
1685
|
-
function inspectTokens(className, isKnown, viewportWidth = Infinity, rootFontSize = 16) {
|
|
1686
|
-
const winners = /* @__PURE__ */ new Map();
|
|
1687
|
-
for (const raw of className.split(/\s+/).filter(Boolean)) {
|
|
1688
|
-
const { variants, utility } = splitVariants(raw);
|
|
1689
|
-
const weight = variantWeight(variants, viewportWidth, rootFontSize);
|
|
1690
|
-
if (weight === void 0) continue;
|
|
1691
|
-
const clean = utility.replace(/^!|!$/g, "");
|
|
1692
|
-
for (const [prefix, slots, specificity, namespace] of utilities) {
|
|
1693
|
-
if (!clean.startsWith(`${prefix}-`)) continue;
|
|
1694
|
-
const token = tokenFor(clean.slice(prefix.length + 1), namespace, isKnown);
|
|
1695
|
-
if (!token) continue;
|
|
1696
|
-
const rank = weight * 10 + specificity;
|
|
1697
|
-
for (const slot of slots) if ((winners.get(slot)?.rank ?? -1) <= rank) winners.set(slot, {
|
|
1698
|
-
token,
|
|
1699
|
-
rank
|
|
1700
|
-
});
|
|
1701
|
-
}
|
|
1702
|
-
}
|
|
1703
|
-
const result = {
|
|
1704
|
-
padding: {},
|
|
1705
|
-
gap: {}
|
|
1706
|
-
};
|
|
1707
|
-
for (const [slot, { token }] of winners) if (slot === "radius") result.radius = token;
|
|
1708
|
-
else if (slot.startsWith("gap.")) result.gap[slot.slice(4)] = token;
|
|
1709
|
-
else result.padding[slot.slice(8)] = token;
|
|
1710
|
-
return result;
|
|
1711
|
-
}
|
|
1712
|
-
//#endregion
|
|
1713
1838
|
//#region src/configurator/inspector/inspection-model.ts
|
|
1714
1839
|
function readableColor(value) {
|
|
1715
1840
|
const rgb = value.trim().match(/^rgb\(\s*(\d+)\s*[, ]\s*(\d+)\s*[, ]\s*(\d+)\s*\)$/);
|
|
@@ -1896,8 +2021,9 @@ function inspectElement(element, isKnown) {
|
|
|
1896
2021
|
if (row.label === "Display" && ["inline", "block"].includes(value)) return false;
|
|
1897
2022
|
if (row.label === "Shadow" && value === "none") return false;
|
|
1898
2023
|
if (row.label === "Opacity" && Number(value) === 1) return false;
|
|
1899
|
-
|
|
1900
|
-
if (row.label === "
|
|
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;
|
|
1901
2027
|
if (row.label === "Line height" && value === "normal") return false;
|
|
1902
2028
|
if (row.label === "Letter spacing" && (value === "normal" || isZero(value))) return false;
|
|
1903
2029
|
if (row.label === "Alignment" && [
|
|
@@ -2623,7 +2749,7 @@ function CvaPreview(t0) {
|
|
|
2623
2749
|
component = slot.split(".")[0];
|
|
2624
2750
|
const props = {
|
|
2625
2751
|
...definition?.config.defaultVariants,
|
|
2626
|
-
...Object.fromEntries(Object.entries(variants).filter(_temp$6).map(_temp2$
|
|
2752
|
+
...Object.fromEntries(Object.entries(variants).filter(_temp$6).map(_temp2$4))
|
|
2627
2753
|
};
|
|
2628
2754
|
const classes = (key, t4) => {
|
|
2629
2755
|
const extra = t4 === void 0 ? {} : t4;
|
|
@@ -2754,7 +2880,7 @@ function CvaPreview(t0) {
|
|
|
2754
2880
|
sample = /* @__PURE__ */ jsx("a", {
|
|
2755
2881
|
className: exact,
|
|
2756
2882
|
href: "#preview",
|
|
2757
|
-
onClick: _temp3$
|
|
2883
|
+
onClick: _temp3$3,
|
|
2758
2884
|
children: "Example link"
|
|
2759
2885
|
});
|
|
2760
2886
|
break bb0;
|
|
@@ -3385,10 +3511,10 @@ function CvaPreview(t0) {
|
|
|
3385
3511
|
function _temp4$2(value_2) {
|
|
3386
3512
|
return /* @__PURE__ */ jsx("option", { children: value_2 }, value_2);
|
|
3387
3513
|
}
|
|
3388
|
-
function _temp3$
|
|
3514
|
+
function _temp3$3(event_1) {
|
|
3389
3515
|
return event_1.preventDefault();
|
|
3390
3516
|
}
|
|
3391
|
-
function _temp2$
|
|
3517
|
+
function _temp2$4(t0) {
|
|
3392
3518
|
const [name, value_0] = t0;
|
|
3393
3519
|
return [name, value_0 === "true" ? true : value_0 === "false" ? false : value_0];
|
|
3394
3520
|
}
|
|
@@ -3600,7 +3726,7 @@ function CvaEditor(t0) {
|
|
|
3600
3726
|
let update;
|
|
3601
3727
|
if ($[2] !== component || $[3] !== draft.overrides || $[4] !== inheritedOverrides || $[5] !== setDraft || $[6] !== setSlot || $[7] !== slot) {
|
|
3602
3728
|
slots = Object.keys(cvaDefinitions);
|
|
3603
|
-
const components = [...new Set(slots.map(_temp2$
|
|
3729
|
+
const components = [...new Set(slots.map(_temp2$3))];
|
|
3604
3730
|
let t10;
|
|
3605
3731
|
if ($[20] !== inheritedOverrides || $[21] !== slot) {
|
|
3606
3732
|
t10 = resolveCvaDefinition(slot, inheritedOverrides);
|
|
@@ -3643,7 +3769,7 @@ function CvaEditor(t0) {
|
|
|
3643
3769
|
const next_0 = event.target.value;
|
|
3644
3770
|
setSlot(slots.find((key_0) => key_0.startsWith(`${next_0}.`)));
|
|
3645
3771
|
};
|
|
3646
|
-
t5 = components.map(_temp3$
|
|
3772
|
+
t5 = components.map(_temp3$2);
|
|
3647
3773
|
$[2] = component;
|
|
3648
3774
|
$[3] = draft.overrides;
|
|
3649
3775
|
$[4] = inheritedOverrides;
|
|
@@ -3784,7 +3910,7 @@ function CvaEditor(t0) {
|
|
|
3784
3910
|
children: [/* @__PURE__ */ jsx("option", {
|
|
3785
3911
|
value: "",
|
|
3786
3912
|
children: "None"
|
|
3787
|
-
}), Object.keys(options).map(_temp5)]
|
|
3913
|
+
}), Object.keys(options).map(_temp5$1)]
|
|
3788
3914
|
})]
|
|
3789
3915
|
}),
|
|
3790
3916
|
Object.entries(options).map((t20) => {
|
|
@@ -3886,7 +4012,7 @@ function _temp6(t0) {
|
|
|
3886
4012
|
const [key_3] = t0;
|
|
3887
4013
|
return key_3 !== "className";
|
|
3888
4014
|
}
|
|
3889
|
-
function _temp5(value_1) {
|
|
4015
|
+
function _temp5$1(value_1) {
|
|
3890
4016
|
return /* @__PURE__ */ jsx("option", {
|
|
3891
4017
|
value: value_1,
|
|
3892
4018
|
children: value_1
|
|
@@ -3898,47 +4024,16 @@ function _temp4$1(key_2) {
|
|
|
3898
4024
|
children: title(key_2.split(".")[1])
|
|
3899
4025
|
}, key_2);
|
|
3900
4026
|
}
|
|
3901
|
-
function _temp3$
|
|
4027
|
+
function _temp3$2(name) {
|
|
3902
4028
|
return /* @__PURE__ */ jsx("option", {
|
|
3903
4029
|
value: name,
|
|
3904
4030
|
children: title(name)
|
|
3905
4031
|
}, name);
|
|
3906
4032
|
}
|
|
3907
|
-
function _temp2$
|
|
4033
|
+
function _temp2$3(key) {
|
|
3908
4034
|
return key.split(".")[0];
|
|
3909
4035
|
}
|
|
3910
4036
|
//#endregion
|
|
3911
|
-
//#region src/configurator/theme-writer-protocol.ts
|
|
3912
|
-
/** Shared by the browser configurator and the isolated Node Vite entry. */
|
|
3913
|
-
const themeWriterMetaName = "povio-ui-theme-writer";
|
|
3914
|
-
const themeWriterTokenHeader = "x-povio-ui-theme-token";
|
|
3915
|
-
//#endregion
|
|
3916
|
-
//#region src/configurator/theme-writer-client.ts
|
|
3917
|
-
function getThemeWriter() {
|
|
3918
|
-
if (typeof document === "undefined") return null;
|
|
3919
|
-
const content = document.querySelector(`meta[name="${themeWriterMetaName}"]`)?.content;
|
|
3920
|
-
if (!content) return null;
|
|
3921
|
-
try {
|
|
3922
|
-
const connection = JSON.parse(content);
|
|
3923
|
-
if (typeof connection.endpoint === "string" && connection.endpoint.startsWith("/") && !connection.endpoint.startsWith("//") && typeof connection.token === "string" && typeof connection.file === "string") return connection;
|
|
3924
|
-
} catch {}
|
|
3925
|
-
return null;
|
|
3926
|
-
}
|
|
3927
|
-
async function saveThemeCss(connection, css) {
|
|
3928
|
-
const response = await fetch(connection.endpoint, {
|
|
3929
|
-
method: "POST",
|
|
3930
|
-
headers: {
|
|
3931
|
-
"Content-Type": "application/json",
|
|
3932
|
-
[themeWriterTokenHeader]: connection.token
|
|
3933
|
-
},
|
|
3934
|
-
body: JSON.stringify({ css })
|
|
3935
|
-
});
|
|
3936
|
-
if (!response.ok) {
|
|
3937
|
-
const result = await response.json().catch(() => null);
|
|
3938
|
-
throw new Error(result?.error ?? `Theme save failed (${response.status}).`);
|
|
3939
|
-
}
|
|
3940
|
-
}
|
|
3941
|
-
//#endregion
|
|
3942
4037
|
//#region src/configurator/theme-versions.ts
|
|
3943
4038
|
const themeVersionsMetaName = "povio-ui-theme-versions";
|
|
3944
4039
|
function createThemeVersion(name, id, configuration) {
|
|
@@ -4634,7 +4729,7 @@ function PaletteSelect(t0) {
|
|
|
4634
4729
|
} else t6 = $[36];
|
|
4635
4730
|
let t7;
|
|
4636
4731
|
if ($[37] !== options) {
|
|
4637
|
-
t7 = paletteFamilies(options).map(_temp2$
|
|
4732
|
+
t7 = paletteFamilies(options).map(_temp2$2);
|
|
4638
4733
|
$[37] = options;
|
|
4639
4734
|
$[38] = t7;
|
|
4640
4735
|
} else t7 = $[38];
|
|
@@ -4654,6 +4749,7 @@ function PaletteSelect(t0) {
|
|
|
4654
4749
|
if ($[40] !== t7) {
|
|
4655
4750
|
t9 = /* @__PURE__ */ jsx($542a13ca2fa5b484$export$5b6b19405a83ff9d, {
|
|
4656
4751
|
className: "studio-palette-popover",
|
|
4752
|
+
"data-povio-inspector-ignore": "",
|
|
4657
4753
|
placement: "bottom end",
|
|
4658
4754
|
children: /* @__PURE__ */ jsxs($928221da08ecbc62$export$41f133550aa26f48, {
|
|
4659
4755
|
className: "studio-palette-list",
|
|
@@ -4685,7 +4781,7 @@ function PaletteSelect(t0) {
|
|
|
4685
4781
|
} else t10 = $[49];
|
|
4686
4782
|
return t10;
|
|
4687
4783
|
}
|
|
4688
|
-
function _temp2$
|
|
4784
|
+
function _temp2$2(t0) {
|
|
4689
4785
|
const { family: name_0, steps: steps_0 } = t0;
|
|
4690
4786
|
return /* @__PURE__ */ jsxs($928221da08ecbc62$export$dca12b0bb56e4fc, {
|
|
4691
4787
|
id: name_0,
|
|
@@ -4893,13 +4989,13 @@ function useLoadedFonts() {
|
|
|
4893
4989
|
document.fonts.ready.then(() => {
|
|
4894
4990
|
if (!active) return;
|
|
4895
4991
|
const root = getComputedStyle(document.documentElement);
|
|
4896
|
-
const families = [...new Set([...document.fonts].map(_temp2))];
|
|
4897
|
-
setFonts(families.map((
|
|
4898
|
-
const base = `--font-${
|
|
4899
|
-
const value_0 = unquote(root.getPropertyValue(base)) ===
|
|
4900
|
-
const group = uploadedFamilies.has(
|
|
4992
|
+
const families = [...new Set([...document.fonts].map(_temp2$1))].filter(_temp3$1);
|
|
4993
|
+
setFonts(families.map((family_0) => {
|
|
4994
|
+
const base = `--font-${family_0.split(/\s+/)[0].toLowerCase()}-base`;
|
|
4995
|
+
const value_0 = unquote(root.getPropertyValue(base)) === family_0 ? `var(${base}), sans-serif` : `"${family_0}", sans-serif`;
|
|
4996
|
+
const group = uploadedFamilies.has(family_0) ? "Uploaded fonts" : "Loaded fonts";
|
|
4901
4997
|
return {
|
|
4902
|
-
name: `loaded:${
|
|
4998
|
+
name: `loaded:${family_0}`,
|
|
4903
4999
|
label: familyName(value_0),
|
|
4904
5000
|
value: value_0,
|
|
4905
5001
|
group
|
|
@@ -4928,7 +5024,10 @@ function useLoadedFonts() {
|
|
|
4928
5024
|
return t4;
|
|
4929
5025
|
}
|
|
4930
5026
|
/** Families added through the upload button in this page session. */
|
|
4931
|
-
function
|
|
5027
|
+
function _temp3$1(family) {
|
|
5028
|
+
return !family.startsWith("Povio Fontsource preview ");
|
|
5029
|
+
}
|
|
5030
|
+
function _temp2$1(face) {
|
|
4932
5031
|
return unquote(face.family);
|
|
4933
5032
|
}
|
|
4934
5033
|
function _temp$2(value) {
|
|
@@ -5106,7 +5205,7 @@ function FontRoleCard(t0) {
|
|
|
5106
5205
|
} else t11 = $[21];
|
|
5107
5206
|
let t12;
|
|
5108
5207
|
if ($[22] !== options) {
|
|
5109
|
-
t12 = new Set(options.map(
|
|
5208
|
+
t12 = new Set(options.map(_temp4));
|
|
5110
5209
|
$[22] = options;
|
|
5111
5210
|
$[23] = t12;
|
|
5112
5211
|
} else t12 = $[23];
|
|
@@ -5120,7 +5219,7 @@ function FontRoleCard(t0) {
|
|
|
5120
5219
|
if ($[26] !== options || $[27] !== t13) {
|
|
5121
5220
|
t14 = t13.map((group_0) => /* @__PURE__ */ jsx("optgroup", {
|
|
5122
5221
|
label: group_0,
|
|
5123
|
-
children: options.filter((option_1) => option_1.group === group_0).map(
|
|
5222
|
+
children: options.filter((option_1) => option_1.group === group_0).map(_temp5)
|
|
5124
5223
|
}, group_0));
|
|
5125
5224
|
$[26] = options;
|
|
5126
5225
|
$[27] = t13;
|
|
@@ -5182,13 +5281,13 @@ function FontRoleCard(t0) {
|
|
|
5182
5281
|
} else t17 = $[45];
|
|
5183
5282
|
return t17;
|
|
5184
5283
|
}
|
|
5185
|
-
function
|
|
5284
|
+
function _temp5(option_2) {
|
|
5186
5285
|
return /* @__PURE__ */ jsx("option", {
|
|
5187
5286
|
value: option_2.name,
|
|
5188
5287
|
children: option_2.label
|
|
5189
5288
|
}, option_2.name);
|
|
5190
5289
|
}
|
|
5191
|
-
function
|
|
5290
|
+
function _temp4(t0) {
|
|
5192
5291
|
const { group } = t0;
|
|
5193
5292
|
return group;
|
|
5194
5293
|
}
|
|
@@ -5533,214 +5632,819 @@ function isPresetActive(preset, defaults, current) {
|
|
|
5533
5632
|
return Object.keys(a).length === Object.keys(b).length && Object.entries(a).every(([name, value]) => b[name] === value);
|
|
5534
5633
|
});
|
|
5535
5634
|
}
|
|
5536
|
-
|
|
5537
|
-
|
|
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;
|
|
5538
5713
|
/**
|
|
5539
|
-
*
|
|
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.
|
|
5540
5716
|
*/
|
|
5541
|
-
function
|
|
5542
|
-
const
|
|
5543
|
-
const
|
|
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;
|
|
5544
5834
|
let t1;
|
|
5545
|
-
if ($[0] !==
|
|
5546
|
-
t1 =
|
|
5547
|
-
$[0] =
|
|
5548
|
-
$[1] =
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
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}%`;
|
|
5557
5846
|
let t4;
|
|
5558
|
-
|
|
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;
|
|
5559
5857
|
let t6;
|
|
5858
|
+
if ($[6] !== label) {
|
|
5859
|
+
t6 = /* @__PURE__ */ jsx("span", { children: label });
|
|
5860
|
+
$[6] = label;
|
|
5861
|
+
$[7] = t6;
|
|
5862
|
+
} else t6 = $[7];
|
|
5560
5863
|
let t7;
|
|
5864
|
+
if ($[8] !== display) {
|
|
5865
|
+
t7 = /* @__PURE__ */ jsx("output", { children: display });
|
|
5866
|
+
$[8] = display;
|
|
5867
|
+
$[9] = t7;
|
|
5868
|
+
} else t7 = $[9];
|
|
5561
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];
|
|
5562
5875
|
let t9;
|
|
5563
|
-
if ($[
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
if ($[18] !== t11) {
|
|
5574
|
-
t6 = /* @__PURE__ */ jsx("label", {
|
|
5575
|
-
htmlFor: t11,
|
|
5576
|
-
children: "Base color (500)"
|
|
5577
|
-
});
|
|
5578
|
-
$[18] = t11;
|
|
5579
|
-
$[19] = t6;
|
|
5580
|
-
} else t6 = $[19];
|
|
5581
|
-
let t12;
|
|
5582
|
-
if ($[20] === Symbol.for("react.memo_cache_sentinel")) {
|
|
5583
|
-
t12 = /* @__PURE__ */ jsx("span", {
|
|
5584
|
-
"aria-hidden": "true",
|
|
5585
|
-
children: "#"
|
|
5586
|
-
});
|
|
5587
|
-
$[20] = t12;
|
|
5588
|
-
} else t12 = $[20];
|
|
5589
|
-
const t13 = `shades-${title}`;
|
|
5590
|
-
const t14 = !base;
|
|
5591
|
-
let t15;
|
|
5592
|
-
if ($[21] === Symbol.for("react.memo_cache_sentinel")) {
|
|
5593
|
-
t15 = (event) => setText(event.target.value.replace(/^#/, ""));
|
|
5594
|
-
$[21] = t15;
|
|
5595
|
-
} else t15 = $[21];
|
|
5596
|
-
if ($[22] !== t13 || $[23] !== t14 || $[24] !== text) {
|
|
5597
|
-
t7 = /* @__PURE__ */ jsxs("span", {
|
|
5598
|
-
className: "studio-token-input",
|
|
5599
|
-
children: [t12, /* @__PURE__ */ jsx("input", {
|
|
5600
|
-
id: t13,
|
|
5601
|
-
value: text,
|
|
5602
|
-
"aria-invalid": t14,
|
|
5603
|
-
spellCheck: false,
|
|
5604
|
-
onChange: t15
|
|
5605
|
-
})]
|
|
5606
|
-
});
|
|
5607
|
-
$[22] = t13;
|
|
5608
|
-
$[23] = t14;
|
|
5609
|
-
$[24] = text;
|
|
5610
|
-
$[25] = t7;
|
|
5611
|
-
} else t7 = $[25];
|
|
5612
|
-
t2 = "color";
|
|
5613
|
-
t3 = "Pick base color";
|
|
5614
|
-
t4 = base ? toHex(base) : "#000000";
|
|
5615
|
-
$[2] = initial;
|
|
5616
|
-
$[3] = steps;
|
|
5617
|
-
$[4] = text;
|
|
5618
|
-
$[5] = title;
|
|
5619
|
-
$[6] = base;
|
|
5620
|
-
$[7] = pending;
|
|
5621
|
-
$[8] = shades;
|
|
5622
|
-
$[9] = t10;
|
|
5623
|
-
$[10] = t2;
|
|
5624
|
-
$[11] = t3;
|
|
5625
|
-
$[12] = t4;
|
|
5626
|
-
$[13] = t5;
|
|
5627
|
-
$[14] = t6;
|
|
5628
|
-
$[15] = t7;
|
|
5629
|
-
$[16] = t8;
|
|
5630
|
-
$[17] = t9;
|
|
5631
|
-
} else {
|
|
5632
|
-
base = $[6];
|
|
5633
|
-
pending = $[7];
|
|
5634
|
-
shades = $[8];
|
|
5635
|
-
t10 = $[9];
|
|
5636
|
-
t2 = $[10];
|
|
5637
|
-
t3 = $[11];
|
|
5638
|
-
t4 = $[12];
|
|
5639
|
-
t5 = $[13];
|
|
5640
|
-
t6 = $[14];
|
|
5641
|
-
t7 = $[15];
|
|
5642
|
-
t8 = $[16];
|
|
5643
|
-
t9 = $[17];
|
|
5644
|
-
}
|
|
5645
|
-
let t11;
|
|
5646
|
-
if ($[26] === Symbol.for("react.memo_cache_sentinel")) {
|
|
5647
|
-
t11 = (event_0) => setText(event_0.target.value.slice(1).toUpperCase());
|
|
5648
|
-
$[26] = t11;
|
|
5649
|
-
} else t11 = $[26];
|
|
5650
|
-
let t12;
|
|
5651
|
-
if ($[27] !== t2 || $[28] !== t3 || $[29] !== t4) {
|
|
5652
|
-
t12 = /* @__PURE__ */ jsx("input", {
|
|
5653
|
-
type: t2,
|
|
5654
|
-
"aria-label": t3,
|
|
5655
|
-
value: t4,
|
|
5656
|
-
onChange: t11
|
|
5657
|
-
});
|
|
5658
|
-
$[27] = t2;
|
|
5659
|
-
$[28] = t3;
|
|
5660
|
-
$[29] = t4;
|
|
5661
|
-
$[30] = t12;
|
|
5662
|
-
} else t12 = $[30];
|
|
5663
|
-
const t13 = !pending;
|
|
5664
|
-
let t14;
|
|
5665
|
-
if ($[31] !== onApply || $[32] !== shades || $[33] !== steps) {
|
|
5666
|
-
t14 = () => {
|
|
5667
|
-
if (shades) onApply(Object.fromEntries(steps.map((t15) => {
|
|
5668
|
-
const { name, step: step_0 } = t15;
|
|
5669
|
-
return [name, shades[step_0]];
|
|
5670
|
-
})));
|
|
5671
|
-
};
|
|
5672
|
-
$[31] = onApply;
|
|
5673
|
-
$[32] = shades;
|
|
5674
|
-
$[33] = steps;
|
|
5675
|
-
$[34] = t14;
|
|
5676
|
-
} else t14 = $[34];
|
|
5677
|
-
let t15;
|
|
5678
|
-
if ($[35] !== t13 || $[36] !== t14) {
|
|
5679
|
-
t15 = /* @__PURE__ */ jsx("div", {
|
|
5680
|
-
className: "studio-shades-actions",
|
|
5681
|
-
children: /* @__PURE__ */ jsx("button", {
|
|
5682
|
-
type: "button",
|
|
5683
|
-
className: "studio-primary",
|
|
5684
|
-
disabled: t13,
|
|
5685
|
-
onClick: t14,
|
|
5686
|
-
children: "Change shades"
|
|
5687
|
-
})
|
|
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
|
|
5688
5886
|
});
|
|
5689
|
-
$[
|
|
5690
|
-
$[
|
|
5691
|
-
$[
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
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,
|
|
5697
5901
|
children: [
|
|
5698
5902
|
t6,
|
|
5699
5903
|
t7,
|
|
5700
|
-
|
|
5701
|
-
t15
|
|
5904
|
+
t9
|
|
5702
5905
|
]
|
|
5703
5906
|
});
|
|
5704
|
-
$[
|
|
5705
|
-
$[
|
|
5706
|
-
$[
|
|
5707
|
-
$[
|
|
5708
|
-
$[
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
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
|
+
};
|
|
5716
5971
|
});
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
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
|
|
5727
5988
|
});
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
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
|
+
});
|
|
5736
6237
|
}
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
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)}`;
|
|
6254
|
+
}
|
|
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
|
+
});
|
|
5740
6444
|
}
|
|
5741
6445
|
//#endregion
|
|
5742
6446
|
//#region src/configurator/ComponentPreview.tsx
|
|
5743
|
-
const ComponentGallery = lazy(() => import("./ComponentGallery-
|
|
6447
|
+
const ComponentGallery = lazy(() => import("./ComponentGallery-C_rXFvUY.js").then((n) => n.n));
|
|
5744
6448
|
/** Every component, styled by a configuration; the configurator's preview and the App Canvas Components view. */
|
|
5745
6449
|
function ComponentPreview(t0) {
|
|
5746
6450
|
const $ = c(14);
|
|
@@ -5887,6 +6591,7 @@ function ThemeVersionControls(t0) {
|
|
|
5887
6591
|
if ($[12] !== themes.versions) {
|
|
5888
6592
|
t5 = /* @__PURE__ */ jsx($542a13ca2fa5b484$export$5b6b19405a83ff9d, {
|
|
5889
6593
|
className: "studio-version-popover",
|
|
6594
|
+
"data-povio-inspector-ignore": "",
|
|
5890
6595
|
placement: "bottom start",
|
|
5891
6596
|
children: /* @__PURE__ */ jsx($928221da08ecbc62$export$41f133550aa26f48, {
|
|
5892
6597
|
className: "studio-version-list",
|
|
@@ -6143,6 +6848,7 @@ function ThemeVersionControls(t0) {
|
|
|
6143
6848
|
if ($[73] !== t14 || $[74] !== t15 || $[75] !== t31) {
|
|
6144
6849
|
t32 = /* @__PURE__ */ jsx($542a13ca2fa5b484$export$5b6b19405a83ff9d, {
|
|
6145
6850
|
triggerRef: t14,
|
|
6851
|
+
"data-povio-inspector-ignore": "",
|
|
6146
6852
|
placement: "bottom start",
|
|
6147
6853
|
offset: 6,
|
|
6148
6854
|
className: "studio-version-popover studio-version-dialog",
|
|
@@ -6651,7 +7357,7 @@ function PopoutOverlay(t0) {
|
|
|
6651
7357
|
} else t3 = $[5];
|
|
6652
7358
|
return t3;
|
|
6653
7359
|
}
|
|
6654
|
-
function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating, onPopout, onDock, popupBlocked, themeVersions }) {
|
|
7360
|
+
function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating, onPopout, onDock, popupBlocked, themeVersions, editorOnly }) {
|
|
6655
7361
|
const Overlay = poppedOut || floating ? PopoutOverlay : $8b8d26808cb8cb53$export$8948f78d83984c69;
|
|
6656
7362
|
const Surface = poppedOut || floating ? "div" : $8b8d26808cb8cb53$export$2b77a92f1a5ad772;
|
|
6657
7363
|
const studioWindow = useStudioWindow(windowBounds, !poppedOut);
|
|
@@ -6666,11 +7372,12 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
|
|
|
6666
7372
|
return () => observer.disconnect();
|
|
6667
7373
|
}, [studioWindow.ref]);
|
|
6668
7374
|
const inherited = UIConfig.useConfig();
|
|
6669
|
-
const { defaults, draft, setDraft, isOpen, apply, revision, tokenRequest, clearTokenRequest
|
|
7375
|
+
const { defaults, draft, setDraft, isOpen, apply, revision, tokenRequest, clearTokenRequest } = useUIConfiguration();
|
|
6670
7376
|
const remembered = memory.current;
|
|
6671
7377
|
const [mode, setMode] = useState(remembered.mode ?? "light");
|
|
6672
7378
|
const [sizeUnit, setSizeUnit] = useState(remembered.sizeUnit ?? "px");
|
|
6673
7379
|
const [loadedFonts, refreshLoadedFonts] = useLoadedFonts();
|
|
7380
|
+
const [fontsourceFamilies, setFontsourceFamilies] = useState([]);
|
|
6674
7381
|
const [editorWidth, setEditorWidth] = useState(remembered.editorWidth);
|
|
6675
7382
|
const [confirmingReset, setConfirmingReset] = useState(false);
|
|
6676
7383
|
const [nothingToReset, setNothingToReset] = useState(false);
|
|
@@ -6953,7 +7660,7 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
|
|
|
6953
7660
|
onApply: (values) => {
|
|
6954
7661
|
for (const [name_16, value_7] of Object.entries(values)) setToken(name_16, value_7);
|
|
6955
7662
|
}
|
|
6956
|
-
},
|
|
7663
|
+
}, title);
|
|
6957
7664
|
};
|
|
6958
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()));
|
|
6959
7666
|
const visibleGroups = section === "Typography" ? tokenGroups : tokenGroups.map(([key_3, group_1]) => [key_3, {
|
|
@@ -7037,6 +7744,7 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
|
|
|
7037
7744
|
const options = [
|
|
7038
7745
|
...themeFonts,
|
|
7039
7746
|
...loadedFonts.filter((font) => !themeFonts.some(({ value: value_11 }) => value_11 === font.value)),
|
|
7747
|
+
...fontsourceFamilies.filter((font_0) => !loadedFonts.some((loaded) => loaded.label === font_0.label)),
|
|
7040
7748
|
...systemFonts
|
|
7041
7749
|
];
|
|
7042
7750
|
const roleLabels = {
|
|
@@ -7059,6 +7767,23 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
|
|
|
7059
7767
|
highlighted: highlightedToken === name_24
|
|
7060
7768
|
}, `${revision}-${resetRevision}-${name_24}`))
|
|
7061
7769
|
}),
|
|
7770
|
+
/* @__PURE__ */ jsx(FontsourcePicker, {
|
|
7771
|
+
roles: roles.map(([token_0]) => ({
|
|
7772
|
+
token: token_0,
|
|
7773
|
+
label: roleLabels[token_0] ?? labelFor(token_0).replace(/^font /, "")
|
|
7774
|
+
})),
|
|
7775
|
+
onAdded: (font_1, role) => {
|
|
7776
|
+
const value_13 = `${JSON.stringify(font_1.family)}, sans-serif`;
|
|
7777
|
+
setFontsourceFamilies((current_12) => [...current_12.filter((item) => item.name !== `fontsource:${font_1.packageName}`), {
|
|
7778
|
+
name: `fontsource:${font_1.packageName}`,
|
|
7779
|
+
label: font_1.family,
|
|
7780
|
+
value: value_13,
|
|
7781
|
+
group: "Fontsource fonts"
|
|
7782
|
+
}]);
|
|
7783
|
+
refreshLoadedFonts();
|
|
7784
|
+
if (role) setToken(role, value_13);
|
|
7785
|
+
}
|
|
7786
|
+
}),
|
|
7062
7787
|
/* @__PURE__ */ jsx(FontUpload, { onUpload: refreshLoadedFonts }),
|
|
7063
7788
|
!!families.length && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("hr", { className: "studio-font-divider" }), families.map((entry_2) => renderToken(entry_2))] })
|
|
7064
7789
|
]
|
|
@@ -7126,10 +7851,10 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
|
|
|
7126
7851
|
children: /* @__PURE__ */ jsx(Surface, {
|
|
7127
7852
|
className: `studio-modal${poppedOut ? " studio-modal-popout" : ""}`,
|
|
7128
7853
|
ref: studioWindow.ref,
|
|
7129
|
-
"data-
|
|
7854
|
+
"data-editor-only": editorOnly || void 0,
|
|
7130
7855
|
children: /* @__PURE__ */ jsxs($f2ff30fde7b014be$export$3ddf2d174ce01153, {
|
|
7131
7856
|
className: "studio-dialog",
|
|
7132
|
-
"data-compact-preview": compactPreview && !
|
|
7857
|
+
"data-compact-preview": compactPreview && !editorOnly || void 0,
|
|
7133
7858
|
style: { "--studio-editor-track": editorWidth ? `minmax(260px, ${editorWidth}px)` : void 0 },
|
|
7134
7859
|
children: [
|
|
7135
7860
|
/* @__PURE__ */ jsxs("header", {
|
|
@@ -7165,7 +7890,7 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
|
|
|
7165
7890
|
})
|
|
7166
7891
|
]
|
|
7167
7892
|
}),
|
|
7168
|
-
!
|
|
7893
|
+
!editorOnly && /* @__PURE__ */ jsx("button", {
|
|
7169
7894
|
type: "button",
|
|
7170
7895
|
className: "studio-preview-tab",
|
|
7171
7896
|
"aria-current": compactPreview ? "page" : void 0,
|
|
@@ -7233,25 +7958,37 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
|
|
|
7233
7958
|
}), toggleAllButton]
|
|
7234
7959
|
}) : showTabs ? /* @__PURE__ */ jsxs("div", {
|
|
7235
7960
|
className: "studio-subtabs-bar",
|
|
7236
|
-
children: [
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
|
|
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", {
|
|
7241
7982
|
type: "button",
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
|
|
7251
|
-
"aria-label": "has changes"
|
|
7252
|
-
})]
|
|
7253
|
-
}, tab_0))
|
|
7254
|
-
}), 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
|
+
]
|
|
7255
7992
|
}) : advancedSection ? /* @__PURE__ */ jsx("div", {
|
|
7256
7993
|
className: "studio-subtabs-bar",
|
|
7257
7994
|
children: /* @__PURE__ */ jsx("div", {
|
|
@@ -7431,10 +8168,10 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
|
|
|
7431
8168
|
children: [/* @__PURE__ */ jsxs("span", { children: ["Use static inputs until interaction", /* @__PURE__ */ jsx("small", { children: "Reduce work when rendering large forms." })] }), /* @__PURE__ */ jsx("input", {
|
|
7432
8169
|
type: "checkbox",
|
|
7433
8170
|
checked: config.renderStaticInput,
|
|
7434
|
-
onChange: (event_5) => setDraft((
|
|
7435
|
-
...
|
|
8171
|
+
onChange: (event_5) => setDraft((current_14) => ({
|
|
8172
|
+
...current_14,
|
|
7436
8173
|
config: {
|
|
7437
|
-
...
|
|
8174
|
+
...current_14.config,
|
|
7438
8175
|
renderStaticInput: event_5.target.checked
|
|
7439
8176
|
}
|
|
7440
8177
|
}))
|
|
@@ -7528,7 +8265,7 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
|
|
|
7528
8265
|
]
|
|
7529
8266
|
})
|
|
7530
8267
|
]
|
|
7531
|
-
}), !
|
|
8268
|
+
}), !editorOnly && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("aside", {
|
|
7532
8269
|
ref: previewRef,
|
|
7533
8270
|
className: "studio-preview",
|
|
7534
8271
|
onScroll: (event_6) => memory.current.previewScroll = event_6.currentTarget.scrollTop,
|
|
@@ -7722,23 +8459,24 @@ function ConfigurationModalContent({ memory, windowBounds, poppedOut, floating,
|
|
|
7722
8459
|
})
|
|
7723
8460
|
});
|
|
7724
8461
|
}
|
|
7725
|
-
/** Where a floating configurator first opens; an editor-only window
|
|
8462
|
+
/** Where a floating configurator first opens; an editor-only window is narrower. */
|
|
7726
8463
|
const floatingDefault = {
|
|
7727
8464
|
left: 32,
|
|
7728
8465
|
top: 80,
|
|
7729
8466
|
width: 640,
|
|
7730
8467
|
height: 720
|
|
7731
8468
|
};
|
|
7732
|
-
const
|
|
7733
|
-
function UIConfigurationModal() {
|
|
8469
|
+
const editorOnlyFloatingWidth = 360;
|
|
8470
|
+
function UIConfigurationModal({ editorOnly: editorOnlyProp = false } = {}) {
|
|
7734
8471
|
const { isOpen, revision, floating, componentsHosted } = useUIConfiguration();
|
|
8472
|
+
const editorOnly = editorOnlyProp || componentsHosted;
|
|
7735
8473
|
const themeVersions = useThemeVersions();
|
|
7736
8474
|
const memory = useRef({});
|
|
7737
8475
|
const windowBounds = useRef(null);
|
|
7738
8476
|
const floatingBounds = useRef(floatingDefault);
|
|
7739
|
-
if (
|
|
8477
|
+
if (editorOnly && floatingBounds.current === floatingDefault) floatingBounds.current = {
|
|
7740
8478
|
...floatingDefault,
|
|
7741
|
-
width:
|
|
8479
|
+
width: editorOnlyFloatingWidth
|
|
7742
8480
|
};
|
|
7743
8481
|
const popout = useStudioPopout(isOpen);
|
|
7744
8482
|
if (!isOpen) return null;
|
|
@@ -7750,7 +8488,8 @@ function UIConfigurationModal() {
|
|
|
7750
8488
|
onPopout: popout.open,
|
|
7751
8489
|
onDock: popout.dock,
|
|
7752
8490
|
popupBlocked: popout.blocked,
|
|
7753
|
-
themeVersions
|
|
8491
|
+
themeVersions,
|
|
8492
|
+
editorOnly
|
|
7754
8493
|
}, revision);
|
|
7755
8494
|
return popout.popup ? createPortal(/* @__PURE__ */ jsx(StudioPopoutContext, {
|
|
7756
8495
|
value: true,
|
|
@@ -7761,4 +8500,450 @@ function UIConfigurationModal() {
|
|
|
7761
8500
|
}), popout.popup.document.body) : floating ? createPortal(content, document.body) : content;
|
|
7762
8501
|
}
|
|
7763
8502
|
//#endregion
|
|
7764
|
-
|
|
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 };
|