@toriistudio/v0-playground 0.6.0 → 0.7.0
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/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +319 -4
- package/dist/index.mjs +327 -12
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -119,6 +119,7 @@ type ControlsConfig = {
|
|
|
119
119
|
mainLabel?: string;
|
|
120
120
|
showGrid?: boolean;
|
|
121
121
|
showPresentationButton?: boolean;
|
|
122
|
+
showCodeSnippet?: boolean;
|
|
122
123
|
addAdvancedPaletteControl?: ResolvedAdvancedPaletteConfig;
|
|
123
124
|
};
|
|
124
125
|
type UseControlsConfig = Omit<ControlsConfig, "addAdvancedPaletteControl"> & {
|
package/dist/index.d.ts
CHANGED
|
@@ -119,6 +119,7 @@ type ControlsConfig = {
|
|
|
119
119
|
mainLabel?: string;
|
|
120
120
|
showGrid?: boolean;
|
|
121
121
|
showPresentationButton?: boolean;
|
|
122
|
+
showCodeSnippet?: boolean;
|
|
122
123
|
addAdvancedPaletteControl?: ResolvedAdvancedPaletteConfig;
|
|
123
124
|
};
|
|
124
125
|
type UseControlsConfig = Omit<ControlsConfig, "addAdvancedPaletteControl"> & {
|
package/dist/index.js
CHANGED
|
@@ -448,7 +448,8 @@ var ControlsProvider = ({ children }) => {
|
|
|
448
448
|
const [schema, setSchema] = (0, import_react2.useState)({});
|
|
449
449
|
const [values, setValues] = (0, import_react2.useState)({});
|
|
450
450
|
const [config, setConfig] = (0, import_react2.useState)({
|
|
451
|
-
showCopyButton: true
|
|
451
|
+
showCopyButton: true,
|
|
452
|
+
showCodeSnippet: false
|
|
452
453
|
});
|
|
453
454
|
const [componentName, setComponentName] = (0, import_react2.useState)();
|
|
454
455
|
const [channelName, setChannelName] = (0, import_react2.useState)(null);
|
|
@@ -1092,11 +1093,227 @@ var AdvancedPaletteControl_default = AdvancedPaletteControl;
|
|
|
1092
1093
|
|
|
1093
1094
|
// src/components/ControlPanel/ControlPanel.tsx
|
|
1094
1095
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1096
|
+
var splitPropsString = (input) => {
|
|
1097
|
+
const props = [];
|
|
1098
|
+
let current = "";
|
|
1099
|
+
let curlyDepth = 0;
|
|
1100
|
+
let squareDepth = 0;
|
|
1101
|
+
let parenDepth = 0;
|
|
1102
|
+
let inSingleQuote = false;
|
|
1103
|
+
let inDoubleQuote = false;
|
|
1104
|
+
let inBacktick = false;
|
|
1105
|
+
let escapeNext = false;
|
|
1106
|
+
for (const char of input) {
|
|
1107
|
+
if (escapeNext) {
|
|
1108
|
+
current += char;
|
|
1109
|
+
escapeNext = false;
|
|
1110
|
+
continue;
|
|
1111
|
+
}
|
|
1112
|
+
if (char === "\\") {
|
|
1113
|
+
current += char;
|
|
1114
|
+
escapeNext = true;
|
|
1115
|
+
continue;
|
|
1116
|
+
}
|
|
1117
|
+
if (char === "'" && !inDoubleQuote && !inBacktick) {
|
|
1118
|
+
inSingleQuote = !inSingleQuote;
|
|
1119
|
+
current += char;
|
|
1120
|
+
continue;
|
|
1121
|
+
}
|
|
1122
|
+
if (char === '"' && !inSingleQuote && !inBacktick) {
|
|
1123
|
+
inDoubleQuote = !inDoubleQuote;
|
|
1124
|
+
current += char;
|
|
1125
|
+
continue;
|
|
1126
|
+
}
|
|
1127
|
+
if (char === "`" && !inSingleQuote && !inDoubleQuote) {
|
|
1128
|
+
inBacktick = !inBacktick;
|
|
1129
|
+
current += char;
|
|
1130
|
+
continue;
|
|
1131
|
+
}
|
|
1132
|
+
if (!inSingleQuote && !inDoubleQuote && !inBacktick) {
|
|
1133
|
+
if (char === "{") {
|
|
1134
|
+
curlyDepth += 1;
|
|
1135
|
+
} else if (char === "}") {
|
|
1136
|
+
curlyDepth = Math.max(0, curlyDepth - 1);
|
|
1137
|
+
} else if (char === "[") {
|
|
1138
|
+
squareDepth += 1;
|
|
1139
|
+
} else if (char === "]") {
|
|
1140
|
+
squareDepth = Math.max(0, squareDepth - 1);
|
|
1141
|
+
} else if (char === "(") {
|
|
1142
|
+
parenDepth += 1;
|
|
1143
|
+
} else if (char === ")") {
|
|
1144
|
+
parenDepth = Math.max(0, parenDepth - 1);
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
const atTopLevel = !inSingleQuote && !inDoubleQuote && !inBacktick && curlyDepth === 0 && squareDepth === 0 && parenDepth === 0;
|
|
1148
|
+
if (atTopLevel && /\s/.test(char)) {
|
|
1149
|
+
if (current.trim()) {
|
|
1150
|
+
props.push(current.trim());
|
|
1151
|
+
}
|
|
1152
|
+
current = "";
|
|
1153
|
+
continue;
|
|
1154
|
+
}
|
|
1155
|
+
current += char;
|
|
1156
|
+
}
|
|
1157
|
+
if (current.trim()) {
|
|
1158
|
+
props.push(current.trim());
|
|
1159
|
+
}
|
|
1160
|
+
return props;
|
|
1161
|
+
};
|
|
1162
|
+
var formatJsxCodeSnippet = (input) => {
|
|
1163
|
+
const trimmed = input.trim();
|
|
1164
|
+
if (!trimmed) return "";
|
|
1165
|
+
if (trimmed.includes("\n")) {
|
|
1166
|
+
return trimmed;
|
|
1167
|
+
}
|
|
1168
|
+
if (!trimmed.startsWith("<") || !trimmed.endsWith(">")) {
|
|
1169
|
+
return trimmed;
|
|
1170
|
+
}
|
|
1171
|
+
if (!trimmed.endsWith("/>")) {
|
|
1172
|
+
return trimmed;
|
|
1173
|
+
}
|
|
1174
|
+
const inner = trimmed.slice(1, -2).trim();
|
|
1175
|
+
const firstSpaceIndex = inner.indexOf(" ");
|
|
1176
|
+
if (firstSpaceIndex === -1) {
|
|
1177
|
+
return `<${inner} />`;
|
|
1178
|
+
}
|
|
1179
|
+
const componentName = inner.slice(0, firstSpaceIndex);
|
|
1180
|
+
const propsString = inner.slice(firstSpaceIndex + 1).trim();
|
|
1181
|
+
if (!propsString) {
|
|
1182
|
+
return `<${componentName} />`;
|
|
1183
|
+
}
|
|
1184
|
+
const propsList = splitPropsString(propsString);
|
|
1185
|
+
if (propsList.length === 0) {
|
|
1186
|
+
return `<${componentName} ${propsString} />`;
|
|
1187
|
+
}
|
|
1188
|
+
const formattedProps = propsList.map((prop) => ` ${prop}`).join("\n");
|
|
1189
|
+
return `<${componentName}
|
|
1190
|
+
${formattedProps}
|
|
1191
|
+
/>`;
|
|
1192
|
+
};
|
|
1193
|
+
var isWhitespace = (char) => /\s/.test(char);
|
|
1194
|
+
var isAttrNameChar = (char) => /[A-Za-z0-9_$\-.:]/.test(char);
|
|
1195
|
+
var isAlphaStart = (char) => /[A-Za-z_$]/.test(char);
|
|
1196
|
+
var tokenizeJsx = (input) => {
|
|
1197
|
+
const tokens = [];
|
|
1198
|
+
let i = 0;
|
|
1199
|
+
while (i < input.length) {
|
|
1200
|
+
const char = input[i];
|
|
1201
|
+
if (char === "<") {
|
|
1202
|
+
tokens.push({ type: "punctuation", value: "<" });
|
|
1203
|
+
i += 1;
|
|
1204
|
+
if (input[i] === "/") {
|
|
1205
|
+
tokens.push({ type: "punctuation", value: "/" });
|
|
1206
|
+
i += 1;
|
|
1207
|
+
}
|
|
1208
|
+
const start = i;
|
|
1209
|
+
while (i < input.length && isAttrNameChar(input[i])) {
|
|
1210
|
+
i += 1;
|
|
1211
|
+
}
|
|
1212
|
+
if (i > start) {
|
|
1213
|
+
tokens.push({ type: "tag", value: input.slice(start, i) });
|
|
1214
|
+
}
|
|
1215
|
+
continue;
|
|
1216
|
+
}
|
|
1217
|
+
if (char === "/" && input[i + 1] === ">") {
|
|
1218
|
+
tokens.push({ type: "punctuation", value: "/>" });
|
|
1219
|
+
i += 2;
|
|
1220
|
+
continue;
|
|
1221
|
+
}
|
|
1222
|
+
if (char === ">") {
|
|
1223
|
+
tokens.push({ type: "punctuation", value: ">" });
|
|
1224
|
+
i += 1;
|
|
1225
|
+
continue;
|
|
1226
|
+
}
|
|
1227
|
+
if (char === "=") {
|
|
1228
|
+
tokens.push({ type: "punctuation", value: "=" });
|
|
1229
|
+
i += 1;
|
|
1230
|
+
continue;
|
|
1231
|
+
}
|
|
1232
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
1233
|
+
const quote = char;
|
|
1234
|
+
let j = i + 1;
|
|
1235
|
+
let value = quote;
|
|
1236
|
+
while (j < input.length) {
|
|
1237
|
+
const current = input[j];
|
|
1238
|
+
value += current;
|
|
1239
|
+
if (current === quote && input[j - 1] !== "\\") {
|
|
1240
|
+
break;
|
|
1241
|
+
}
|
|
1242
|
+
j += 1;
|
|
1243
|
+
}
|
|
1244
|
+
tokens.push({ type: "string", value });
|
|
1245
|
+
i = j + 1;
|
|
1246
|
+
continue;
|
|
1247
|
+
}
|
|
1248
|
+
if (char === "{") {
|
|
1249
|
+
let depth = 1;
|
|
1250
|
+
let j = i + 1;
|
|
1251
|
+
while (j < input.length && depth > 0) {
|
|
1252
|
+
if (input[j] === "{") {
|
|
1253
|
+
depth += 1;
|
|
1254
|
+
} else if (input[j] === "}") {
|
|
1255
|
+
depth -= 1;
|
|
1256
|
+
}
|
|
1257
|
+
j += 1;
|
|
1258
|
+
}
|
|
1259
|
+
const expression = input.slice(i, j);
|
|
1260
|
+
tokens.push({ type: "expression", value: expression });
|
|
1261
|
+
i = j;
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
if (isAlphaStart(char)) {
|
|
1265
|
+
const start = i;
|
|
1266
|
+
i += 1;
|
|
1267
|
+
while (i < input.length && isAttrNameChar(input[i])) {
|
|
1268
|
+
i += 1;
|
|
1269
|
+
}
|
|
1270
|
+
const word = input.slice(start, i);
|
|
1271
|
+
let k = i;
|
|
1272
|
+
while (k < input.length && isWhitespace(input[k])) {
|
|
1273
|
+
k += 1;
|
|
1274
|
+
}
|
|
1275
|
+
if (input[k] === "=") {
|
|
1276
|
+
tokens.push({ type: "attrName", value: word });
|
|
1277
|
+
} else {
|
|
1278
|
+
tokens.push({ type: "plain", value: word });
|
|
1279
|
+
}
|
|
1280
|
+
continue;
|
|
1281
|
+
}
|
|
1282
|
+
tokens.push({ type: "plain", value: char });
|
|
1283
|
+
i += 1;
|
|
1284
|
+
}
|
|
1285
|
+
return tokens;
|
|
1286
|
+
};
|
|
1287
|
+
var TOKEN_CLASS_MAP = {
|
|
1288
|
+
tag: "text-sky-300",
|
|
1289
|
+
attrName: "text-amber-200",
|
|
1290
|
+
string: "text-emerald-300",
|
|
1291
|
+
expression: "text-purple-300",
|
|
1292
|
+
punctuation: "text-stone-400"
|
|
1293
|
+
};
|
|
1294
|
+
var highlightJsx = (input) => {
|
|
1295
|
+
const tokens = tokenizeJsx(input);
|
|
1296
|
+
const nodes = [];
|
|
1297
|
+
tokens.forEach((token, index) => {
|
|
1298
|
+
if (token.type === "plain") {
|
|
1299
|
+
nodes.push(token.value);
|
|
1300
|
+
} else {
|
|
1301
|
+
nodes.push(
|
|
1302
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: TOKEN_CLASS_MAP[token.type], children: token.value }, `token-${index}`)
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
});
|
|
1306
|
+
return nodes;
|
|
1307
|
+
};
|
|
1095
1308
|
var ControlPanel = () => {
|
|
1096
1309
|
const [copied, setCopied] = (0, import_react5.useState)(false);
|
|
1310
|
+
const [codeCopied, setCodeCopied] = (0, import_react5.useState)(false);
|
|
1311
|
+
const [isCodeVisible, setIsCodeVisible] = (0, import_react5.useState)(false);
|
|
1097
1312
|
const [folderStates, setFolderStates] = (0, import_react5.useState)({});
|
|
1313
|
+
const codeCopyTimeoutRef = (0, import_react5.useRef)(null);
|
|
1098
1314
|
const { leftPanelWidth, isDesktop, isHydrated } = useResizableLayout();
|
|
1099
1315
|
const { schema, setValue, values, componentName, config } = useControlsContext();
|
|
1316
|
+
const isControlsOnlyView = typeof window !== "undefined" && new URLSearchParams(window.location.search).get(CONTROLS_ONLY_PARAM) === "true";
|
|
1100
1317
|
const previewUrl = usePreviewUrl(values);
|
|
1101
1318
|
const buildUrl = (0, import_react5.useCallback)(
|
|
1102
1319
|
(modifier) => {
|
|
@@ -1270,6 +1487,65 @@ var ControlPanel = () => {
|
|
|
1270
1487
|
jsonToComponentString
|
|
1271
1488
|
}) ?? jsx14;
|
|
1272
1489
|
const shouldShowCopyButton = config?.showCopyButton !== false && Boolean(copyText);
|
|
1490
|
+
const baseSnippet = copyText || jsx14;
|
|
1491
|
+
const formattedCode = (0, import_react5.useMemo)(
|
|
1492
|
+
() => formatJsxCodeSnippet(baseSnippet),
|
|
1493
|
+
[baseSnippet]
|
|
1494
|
+
);
|
|
1495
|
+
const hasCodeSnippet = Boolean(config?.showCodeSnippet && formattedCode);
|
|
1496
|
+
const highlightedCode = (0, import_react5.useMemo)(
|
|
1497
|
+
() => formattedCode ? highlightJsx(formattedCode) : null,
|
|
1498
|
+
[formattedCode]
|
|
1499
|
+
);
|
|
1500
|
+
(0, import_react5.useEffect)(() => {
|
|
1501
|
+
if (!hasCodeSnippet) {
|
|
1502
|
+
setIsCodeVisible(false);
|
|
1503
|
+
}
|
|
1504
|
+
}, [hasCodeSnippet]);
|
|
1505
|
+
(0, import_react5.useEffect)(() => {
|
|
1506
|
+
setCodeCopied(false);
|
|
1507
|
+
if (codeCopyTimeoutRef.current) {
|
|
1508
|
+
clearTimeout(codeCopyTimeoutRef.current);
|
|
1509
|
+
codeCopyTimeoutRef.current = null;
|
|
1510
|
+
}
|
|
1511
|
+
}, [formattedCode]);
|
|
1512
|
+
(0, import_react5.useEffect)(() => {
|
|
1513
|
+
return () => {
|
|
1514
|
+
if (codeCopyTimeoutRef.current) {
|
|
1515
|
+
clearTimeout(codeCopyTimeoutRef.current);
|
|
1516
|
+
}
|
|
1517
|
+
};
|
|
1518
|
+
}, []);
|
|
1519
|
+
const handleToggleCodeVisibility = (0, import_react5.useCallback)(() => {
|
|
1520
|
+
setIsCodeVisible((prev) => {
|
|
1521
|
+
const next = !prev;
|
|
1522
|
+
if (!next) {
|
|
1523
|
+
setCodeCopied(false);
|
|
1524
|
+
if (codeCopyTimeoutRef.current) {
|
|
1525
|
+
clearTimeout(codeCopyTimeoutRef.current);
|
|
1526
|
+
codeCopyTimeoutRef.current = null;
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
return next;
|
|
1530
|
+
});
|
|
1531
|
+
}, []);
|
|
1532
|
+
const handleCodeCopy = (0, import_react5.useCallback)(() => {
|
|
1533
|
+
if (!formattedCode) return;
|
|
1534
|
+
if (typeof navigator === "undefined" || !navigator.clipboard || typeof navigator.clipboard.writeText !== "function") {
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
navigator.clipboard.writeText(formattedCode).then(() => {
|
|
1538
|
+
setCodeCopied(true);
|
|
1539
|
+
if (codeCopyTimeoutRef.current) {
|
|
1540
|
+
clearTimeout(codeCopyTimeoutRef.current);
|
|
1541
|
+
}
|
|
1542
|
+
codeCopyTimeoutRef.current = setTimeout(() => {
|
|
1543
|
+
setCodeCopied(false);
|
|
1544
|
+
codeCopyTimeoutRef.current = null;
|
|
1545
|
+
}, 3e3);
|
|
1546
|
+
}).catch(() => {
|
|
1547
|
+
});
|
|
1548
|
+
}, [formattedCode]);
|
|
1273
1549
|
const labelize = (key) => key.replace(/([A-Z])/g, " $1").replace(/[\-_]/g, " ").replace(/\s+/g, " ").trim().replace(/(^|\s)\S/g, (s) => s.toUpperCase());
|
|
1274
1550
|
const renderButtonControl = (key, control, variant) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1275
1551
|
"div",
|
|
@@ -1436,7 +1712,7 @@ var ControlPanel = () => {
|
|
|
1436
1712
|
height: "auto",
|
|
1437
1713
|
flex: "0 0 auto"
|
|
1438
1714
|
};
|
|
1439
|
-
if (isHydrated) {
|
|
1715
|
+
if (isHydrated && !isControlsOnlyView) {
|
|
1440
1716
|
if (isDesktop) {
|
|
1441
1717
|
Object.assign(panelStyle, {
|
|
1442
1718
|
position: "absolute",
|
|
@@ -1472,12 +1748,51 @@ var ControlPanel = () => {
|
|
|
1472
1748
|
([key, control]) => renderControl(key, control, "root")
|
|
1473
1749
|
),
|
|
1474
1750
|
bottomFolderSections,
|
|
1751
|
+
hasCodeSnippet && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "border border-stone-700/60 rounded-lg bg-stone-900/70", children: [
|
|
1752
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1753
|
+
"button",
|
|
1754
|
+
{
|
|
1755
|
+
type: "button",
|
|
1756
|
+
onClick: handleToggleCodeVisibility,
|
|
1757
|
+
className: "w-full flex items-center justify-between px-4 py-3 text-left font-semibold text-stone-200 tracking-wide",
|
|
1758
|
+
"aria-expanded": isCodeVisible,
|
|
1759
|
+
children: [
|
|
1760
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: isCodeVisible ? "Hide Code" : "Show Code" }),
|
|
1761
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1762
|
+
import_lucide_react3.ChevronDown,
|
|
1763
|
+
{
|
|
1764
|
+
className: `w-4 h-4 transition-transform duration-200 ${isCodeVisible ? "rotate-180" : ""}`
|
|
1765
|
+
}
|
|
1766
|
+
)
|
|
1767
|
+
]
|
|
1768
|
+
}
|
|
1769
|
+
),
|
|
1770
|
+
isCodeVisible && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "relative border-t border-stone-700/60 bg-stone-950/60 px-4 py-4 rounded-b-lg", children: [
|
|
1771
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1772
|
+
"button",
|
|
1773
|
+
{
|
|
1774
|
+
type: "button",
|
|
1775
|
+
onClick: handleCodeCopy,
|
|
1776
|
+
className: "absolute top-3 right-3 flex items-center gap-1 rounded-md border border-stone-700 bg-stone-800 px-2 py-1 text-xs font-medium text-white shadow hover:bg-stone-700",
|
|
1777
|
+
children: codeCopied ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
1778
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.Check, { className: "h-3.5 w-3.5" }),
|
|
1779
|
+
"Copied"
|
|
1780
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
1781
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.Copy, { className: "h-3.5 w-3.5" }),
|
|
1782
|
+
"Copy"
|
|
1783
|
+
] })
|
|
1784
|
+
}
|
|
1785
|
+
),
|
|
1786
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("pre", { className: "whitespace-pre overflow-x-auto text-xs md:text-sm text-stone-200 pr-14", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("code", { className: "block text-stone-200", children: highlightedCode ?? formattedCode }) })
|
|
1787
|
+
] })
|
|
1788
|
+
] }),
|
|
1475
1789
|
shouldShowCopyButton && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex-1 pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1476
1790
|
"button",
|
|
1477
1791
|
{
|
|
1478
1792
|
onClick: () => {
|
|
1479
|
-
|
|
1480
|
-
|
|
1793
|
+
const copyPayload = formattedCode || baseSnippet;
|
|
1794
|
+
if (!copyPayload) return;
|
|
1795
|
+
navigator.clipboard.writeText(copyPayload);
|
|
1481
1796
|
setCopied(true);
|
|
1482
1797
|
setTimeout(() => setCopied(false), 5e3);
|
|
1483
1798
|
},
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/components/Playground/Playground.tsx
|
|
2
|
-
import { useEffect as
|
|
2
|
+
import { useEffect as useEffect6, useMemo as useMemo4, useState as useState5 } from "react";
|
|
3
3
|
import { Check as Check3, Copy as Copy2 } from "lucide-react";
|
|
4
4
|
|
|
5
5
|
// src/context/ResizableLayout.tsx
|
|
@@ -411,7 +411,8 @@ var ControlsProvider = ({ children }) => {
|
|
|
411
411
|
const [schema, setSchema] = useState2({});
|
|
412
412
|
const [values, setValues] = useState2({});
|
|
413
413
|
const [config, setConfig] = useState2({
|
|
414
|
-
showCopyButton: true
|
|
414
|
+
showCopyButton: true,
|
|
415
|
+
showCodeSnippet: false
|
|
415
416
|
});
|
|
416
417
|
const [componentName, setComponentName] = useState2();
|
|
417
418
|
const [channelName, setChannelName] = useState2(null);
|
|
@@ -629,7 +630,7 @@ var useControls = (schema, options) => {
|
|
|
629
630
|
var useUrlSyncedControls = useControls;
|
|
630
631
|
|
|
631
632
|
// src/components/ControlPanel/ControlPanel.tsx
|
|
632
|
-
import { useState as useState4, useMemo as useMemo3, useCallback as useCallback3 } from "react";
|
|
633
|
+
import { useState as useState4, useMemo as useMemo3, useCallback as useCallback3, useEffect as useEffect5, useRef as useRef4 } from "react";
|
|
633
634
|
import {
|
|
634
635
|
Check as Check2,
|
|
635
636
|
Copy,
|
|
@@ -1066,11 +1067,227 @@ var AdvancedPaletteControl_default = AdvancedPaletteControl;
|
|
|
1066
1067
|
|
|
1067
1068
|
// src/components/ControlPanel/ControlPanel.tsx
|
|
1068
1069
|
import { Fragment, jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1070
|
+
var splitPropsString = (input) => {
|
|
1071
|
+
const props = [];
|
|
1072
|
+
let current = "";
|
|
1073
|
+
let curlyDepth = 0;
|
|
1074
|
+
let squareDepth = 0;
|
|
1075
|
+
let parenDepth = 0;
|
|
1076
|
+
let inSingleQuote = false;
|
|
1077
|
+
let inDoubleQuote = false;
|
|
1078
|
+
let inBacktick = false;
|
|
1079
|
+
let escapeNext = false;
|
|
1080
|
+
for (const char of input) {
|
|
1081
|
+
if (escapeNext) {
|
|
1082
|
+
current += char;
|
|
1083
|
+
escapeNext = false;
|
|
1084
|
+
continue;
|
|
1085
|
+
}
|
|
1086
|
+
if (char === "\\") {
|
|
1087
|
+
current += char;
|
|
1088
|
+
escapeNext = true;
|
|
1089
|
+
continue;
|
|
1090
|
+
}
|
|
1091
|
+
if (char === "'" && !inDoubleQuote && !inBacktick) {
|
|
1092
|
+
inSingleQuote = !inSingleQuote;
|
|
1093
|
+
current += char;
|
|
1094
|
+
continue;
|
|
1095
|
+
}
|
|
1096
|
+
if (char === '"' && !inSingleQuote && !inBacktick) {
|
|
1097
|
+
inDoubleQuote = !inDoubleQuote;
|
|
1098
|
+
current += char;
|
|
1099
|
+
continue;
|
|
1100
|
+
}
|
|
1101
|
+
if (char === "`" && !inSingleQuote && !inDoubleQuote) {
|
|
1102
|
+
inBacktick = !inBacktick;
|
|
1103
|
+
current += char;
|
|
1104
|
+
continue;
|
|
1105
|
+
}
|
|
1106
|
+
if (!inSingleQuote && !inDoubleQuote && !inBacktick) {
|
|
1107
|
+
if (char === "{") {
|
|
1108
|
+
curlyDepth += 1;
|
|
1109
|
+
} else if (char === "}") {
|
|
1110
|
+
curlyDepth = Math.max(0, curlyDepth - 1);
|
|
1111
|
+
} else if (char === "[") {
|
|
1112
|
+
squareDepth += 1;
|
|
1113
|
+
} else if (char === "]") {
|
|
1114
|
+
squareDepth = Math.max(0, squareDepth - 1);
|
|
1115
|
+
} else if (char === "(") {
|
|
1116
|
+
parenDepth += 1;
|
|
1117
|
+
} else if (char === ")") {
|
|
1118
|
+
parenDepth = Math.max(0, parenDepth - 1);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
const atTopLevel = !inSingleQuote && !inDoubleQuote && !inBacktick && curlyDepth === 0 && squareDepth === 0 && parenDepth === 0;
|
|
1122
|
+
if (atTopLevel && /\s/.test(char)) {
|
|
1123
|
+
if (current.trim()) {
|
|
1124
|
+
props.push(current.trim());
|
|
1125
|
+
}
|
|
1126
|
+
current = "";
|
|
1127
|
+
continue;
|
|
1128
|
+
}
|
|
1129
|
+
current += char;
|
|
1130
|
+
}
|
|
1131
|
+
if (current.trim()) {
|
|
1132
|
+
props.push(current.trim());
|
|
1133
|
+
}
|
|
1134
|
+
return props;
|
|
1135
|
+
};
|
|
1136
|
+
var formatJsxCodeSnippet = (input) => {
|
|
1137
|
+
const trimmed = input.trim();
|
|
1138
|
+
if (!trimmed) return "";
|
|
1139
|
+
if (trimmed.includes("\n")) {
|
|
1140
|
+
return trimmed;
|
|
1141
|
+
}
|
|
1142
|
+
if (!trimmed.startsWith("<") || !trimmed.endsWith(">")) {
|
|
1143
|
+
return trimmed;
|
|
1144
|
+
}
|
|
1145
|
+
if (!trimmed.endsWith("/>")) {
|
|
1146
|
+
return trimmed;
|
|
1147
|
+
}
|
|
1148
|
+
const inner = trimmed.slice(1, -2).trim();
|
|
1149
|
+
const firstSpaceIndex = inner.indexOf(" ");
|
|
1150
|
+
if (firstSpaceIndex === -1) {
|
|
1151
|
+
return `<${inner} />`;
|
|
1152
|
+
}
|
|
1153
|
+
const componentName = inner.slice(0, firstSpaceIndex);
|
|
1154
|
+
const propsString = inner.slice(firstSpaceIndex + 1).trim();
|
|
1155
|
+
if (!propsString) {
|
|
1156
|
+
return `<${componentName} />`;
|
|
1157
|
+
}
|
|
1158
|
+
const propsList = splitPropsString(propsString);
|
|
1159
|
+
if (propsList.length === 0) {
|
|
1160
|
+
return `<${componentName} ${propsString} />`;
|
|
1161
|
+
}
|
|
1162
|
+
const formattedProps = propsList.map((prop) => ` ${prop}`).join("\n");
|
|
1163
|
+
return `<${componentName}
|
|
1164
|
+
${formattedProps}
|
|
1165
|
+
/>`;
|
|
1166
|
+
};
|
|
1167
|
+
var isWhitespace = (char) => /\s/.test(char);
|
|
1168
|
+
var isAttrNameChar = (char) => /[A-Za-z0-9_$\-.:]/.test(char);
|
|
1169
|
+
var isAlphaStart = (char) => /[A-Za-z_$]/.test(char);
|
|
1170
|
+
var tokenizeJsx = (input) => {
|
|
1171
|
+
const tokens = [];
|
|
1172
|
+
let i = 0;
|
|
1173
|
+
while (i < input.length) {
|
|
1174
|
+
const char = input[i];
|
|
1175
|
+
if (char === "<") {
|
|
1176
|
+
tokens.push({ type: "punctuation", value: "<" });
|
|
1177
|
+
i += 1;
|
|
1178
|
+
if (input[i] === "/") {
|
|
1179
|
+
tokens.push({ type: "punctuation", value: "/" });
|
|
1180
|
+
i += 1;
|
|
1181
|
+
}
|
|
1182
|
+
const start = i;
|
|
1183
|
+
while (i < input.length && isAttrNameChar(input[i])) {
|
|
1184
|
+
i += 1;
|
|
1185
|
+
}
|
|
1186
|
+
if (i > start) {
|
|
1187
|
+
tokens.push({ type: "tag", value: input.slice(start, i) });
|
|
1188
|
+
}
|
|
1189
|
+
continue;
|
|
1190
|
+
}
|
|
1191
|
+
if (char === "/" && input[i + 1] === ">") {
|
|
1192
|
+
tokens.push({ type: "punctuation", value: "/>" });
|
|
1193
|
+
i += 2;
|
|
1194
|
+
continue;
|
|
1195
|
+
}
|
|
1196
|
+
if (char === ">") {
|
|
1197
|
+
tokens.push({ type: "punctuation", value: ">" });
|
|
1198
|
+
i += 1;
|
|
1199
|
+
continue;
|
|
1200
|
+
}
|
|
1201
|
+
if (char === "=") {
|
|
1202
|
+
tokens.push({ type: "punctuation", value: "=" });
|
|
1203
|
+
i += 1;
|
|
1204
|
+
continue;
|
|
1205
|
+
}
|
|
1206
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
1207
|
+
const quote = char;
|
|
1208
|
+
let j = i + 1;
|
|
1209
|
+
let value = quote;
|
|
1210
|
+
while (j < input.length) {
|
|
1211
|
+
const current = input[j];
|
|
1212
|
+
value += current;
|
|
1213
|
+
if (current === quote && input[j - 1] !== "\\") {
|
|
1214
|
+
break;
|
|
1215
|
+
}
|
|
1216
|
+
j += 1;
|
|
1217
|
+
}
|
|
1218
|
+
tokens.push({ type: "string", value });
|
|
1219
|
+
i = j + 1;
|
|
1220
|
+
continue;
|
|
1221
|
+
}
|
|
1222
|
+
if (char === "{") {
|
|
1223
|
+
let depth = 1;
|
|
1224
|
+
let j = i + 1;
|
|
1225
|
+
while (j < input.length && depth > 0) {
|
|
1226
|
+
if (input[j] === "{") {
|
|
1227
|
+
depth += 1;
|
|
1228
|
+
} else if (input[j] === "}") {
|
|
1229
|
+
depth -= 1;
|
|
1230
|
+
}
|
|
1231
|
+
j += 1;
|
|
1232
|
+
}
|
|
1233
|
+
const expression = input.slice(i, j);
|
|
1234
|
+
tokens.push({ type: "expression", value: expression });
|
|
1235
|
+
i = j;
|
|
1236
|
+
continue;
|
|
1237
|
+
}
|
|
1238
|
+
if (isAlphaStart(char)) {
|
|
1239
|
+
const start = i;
|
|
1240
|
+
i += 1;
|
|
1241
|
+
while (i < input.length && isAttrNameChar(input[i])) {
|
|
1242
|
+
i += 1;
|
|
1243
|
+
}
|
|
1244
|
+
const word = input.slice(start, i);
|
|
1245
|
+
let k = i;
|
|
1246
|
+
while (k < input.length && isWhitespace(input[k])) {
|
|
1247
|
+
k += 1;
|
|
1248
|
+
}
|
|
1249
|
+
if (input[k] === "=") {
|
|
1250
|
+
tokens.push({ type: "attrName", value: word });
|
|
1251
|
+
} else {
|
|
1252
|
+
tokens.push({ type: "plain", value: word });
|
|
1253
|
+
}
|
|
1254
|
+
continue;
|
|
1255
|
+
}
|
|
1256
|
+
tokens.push({ type: "plain", value: char });
|
|
1257
|
+
i += 1;
|
|
1258
|
+
}
|
|
1259
|
+
return tokens;
|
|
1260
|
+
};
|
|
1261
|
+
var TOKEN_CLASS_MAP = {
|
|
1262
|
+
tag: "text-sky-300",
|
|
1263
|
+
attrName: "text-amber-200",
|
|
1264
|
+
string: "text-emerald-300",
|
|
1265
|
+
expression: "text-purple-300",
|
|
1266
|
+
punctuation: "text-stone-400"
|
|
1267
|
+
};
|
|
1268
|
+
var highlightJsx = (input) => {
|
|
1269
|
+
const tokens = tokenizeJsx(input);
|
|
1270
|
+
const nodes = [];
|
|
1271
|
+
tokens.forEach((token, index) => {
|
|
1272
|
+
if (token.type === "plain") {
|
|
1273
|
+
nodes.push(token.value);
|
|
1274
|
+
} else {
|
|
1275
|
+
nodes.push(
|
|
1276
|
+
/* @__PURE__ */ jsx10("span", { className: TOKEN_CLASS_MAP[token.type], children: token.value }, `token-${index}`)
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
});
|
|
1280
|
+
return nodes;
|
|
1281
|
+
};
|
|
1069
1282
|
var ControlPanel = () => {
|
|
1070
1283
|
const [copied, setCopied] = useState4(false);
|
|
1284
|
+
const [codeCopied, setCodeCopied] = useState4(false);
|
|
1285
|
+
const [isCodeVisible, setIsCodeVisible] = useState4(false);
|
|
1071
1286
|
const [folderStates, setFolderStates] = useState4({});
|
|
1287
|
+
const codeCopyTimeoutRef = useRef4(null);
|
|
1072
1288
|
const { leftPanelWidth, isDesktop, isHydrated } = useResizableLayout();
|
|
1073
1289
|
const { schema, setValue, values, componentName, config } = useControlsContext();
|
|
1290
|
+
const isControlsOnlyView = typeof window !== "undefined" && new URLSearchParams(window.location.search).get(CONTROLS_ONLY_PARAM) === "true";
|
|
1074
1291
|
const previewUrl = usePreviewUrl(values);
|
|
1075
1292
|
const buildUrl = useCallback3(
|
|
1076
1293
|
(modifier) => {
|
|
@@ -1244,6 +1461,65 @@ var ControlPanel = () => {
|
|
|
1244
1461
|
jsonToComponentString
|
|
1245
1462
|
}) ?? jsx14;
|
|
1246
1463
|
const shouldShowCopyButton = config?.showCopyButton !== false && Boolean(copyText);
|
|
1464
|
+
const baseSnippet = copyText || jsx14;
|
|
1465
|
+
const formattedCode = useMemo3(
|
|
1466
|
+
() => formatJsxCodeSnippet(baseSnippet),
|
|
1467
|
+
[baseSnippet]
|
|
1468
|
+
);
|
|
1469
|
+
const hasCodeSnippet = Boolean(config?.showCodeSnippet && formattedCode);
|
|
1470
|
+
const highlightedCode = useMemo3(
|
|
1471
|
+
() => formattedCode ? highlightJsx(formattedCode) : null,
|
|
1472
|
+
[formattedCode]
|
|
1473
|
+
);
|
|
1474
|
+
useEffect5(() => {
|
|
1475
|
+
if (!hasCodeSnippet) {
|
|
1476
|
+
setIsCodeVisible(false);
|
|
1477
|
+
}
|
|
1478
|
+
}, [hasCodeSnippet]);
|
|
1479
|
+
useEffect5(() => {
|
|
1480
|
+
setCodeCopied(false);
|
|
1481
|
+
if (codeCopyTimeoutRef.current) {
|
|
1482
|
+
clearTimeout(codeCopyTimeoutRef.current);
|
|
1483
|
+
codeCopyTimeoutRef.current = null;
|
|
1484
|
+
}
|
|
1485
|
+
}, [formattedCode]);
|
|
1486
|
+
useEffect5(() => {
|
|
1487
|
+
return () => {
|
|
1488
|
+
if (codeCopyTimeoutRef.current) {
|
|
1489
|
+
clearTimeout(codeCopyTimeoutRef.current);
|
|
1490
|
+
}
|
|
1491
|
+
};
|
|
1492
|
+
}, []);
|
|
1493
|
+
const handleToggleCodeVisibility = useCallback3(() => {
|
|
1494
|
+
setIsCodeVisible((prev) => {
|
|
1495
|
+
const next = !prev;
|
|
1496
|
+
if (!next) {
|
|
1497
|
+
setCodeCopied(false);
|
|
1498
|
+
if (codeCopyTimeoutRef.current) {
|
|
1499
|
+
clearTimeout(codeCopyTimeoutRef.current);
|
|
1500
|
+
codeCopyTimeoutRef.current = null;
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
return next;
|
|
1504
|
+
});
|
|
1505
|
+
}, []);
|
|
1506
|
+
const handleCodeCopy = useCallback3(() => {
|
|
1507
|
+
if (!formattedCode) return;
|
|
1508
|
+
if (typeof navigator === "undefined" || !navigator.clipboard || typeof navigator.clipboard.writeText !== "function") {
|
|
1509
|
+
return;
|
|
1510
|
+
}
|
|
1511
|
+
navigator.clipboard.writeText(formattedCode).then(() => {
|
|
1512
|
+
setCodeCopied(true);
|
|
1513
|
+
if (codeCopyTimeoutRef.current) {
|
|
1514
|
+
clearTimeout(codeCopyTimeoutRef.current);
|
|
1515
|
+
}
|
|
1516
|
+
codeCopyTimeoutRef.current = setTimeout(() => {
|
|
1517
|
+
setCodeCopied(false);
|
|
1518
|
+
codeCopyTimeoutRef.current = null;
|
|
1519
|
+
}, 3e3);
|
|
1520
|
+
}).catch(() => {
|
|
1521
|
+
});
|
|
1522
|
+
}, [formattedCode]);
|
|
1247
1523
|
const labelize = (key) => key.replace(/([A-Z])/g, " $1").replace(/[\-_]/g, " ").replace(/\s+/g, " ").trim().replace(/(^|\s)\S/g, (s) => s.toUpperCase());
|
|
1248
1524
|
const renderButtonControl = (key, control, variant) => /* @__PURE__ */ jsx10(
|
|
1249
1525
|
"div",
|
|
@@ -1410,7 +1686,7 @@ var ControlPanel = () => {
|
|
|
1410
1686
|
height: "auto",
|
|
1411
1687
|
flex: "0 0 auto"
|
|
1412
1688
|
};
|
|
1413
|
-
if (isHydrated) {
|
|
1689
|
+
if (isHydrated && !isControlsOnlyView) {
|
|
1414
1690
|
if (isDesktop) {
|
|
1415
1691
|
Object.assign(panelStyle, {
|
|
1416
1692
|
position: "absolute",
|
|
@@ -1446,12 +1722,51 @@ var ControlPanel = () => {
|
|
|
1446
1722
|
([key, control]) => renderControl(key, control, "root")
|
|
1447
1723
|
),
|
|
1448
1724
|
bottomFolderSections,
|
|
1725
|
+
hasCodeSnippet && /* @__PURE__ */ jsxs5("div", { className: "border border-stone-700/60 rounded-lg bg-stone-900/70", children: [
|
|
1726
|
+
/* @__PURE__ */ jsxs5(
|
|
1727
|
+
"button",
|
|
1728
|
+
{
|
|
1729
|
+
type: "button",
|
|
1730
|
+
onClick: handleToggleCodeVisibility,
|
|
1731
|
+
className: "w-full flex items-center justify-between px-4 py-3 text-left font-semibold text-stone-200 tracking-wide",
|
|
1732
|
+
"aria-expanded": isCodeVisible,
|
|
1733
|
+
children: [
|
|
1734
|
+
/* @__PURE__ */ jsx10("span", { children: isCodeVisible ? "Hide Code" : "Show Code" }),
|
|
1735
|
+
/* @__PURE__ */ jsx10(
|
|
1736
|
+
ChevronDown2,
|
|
1737
|
+
{
|
|
1738
|
+
className: `w-4 h-4 transition-transform duration-200 ${isCodeVisible ? "rotate-180" : ""}`
|
|
1739
|
+
}
|
|
1740
|
+
)
|
|
1741
|
+
]
|
|
1742
|
+
}
|
|
1743
|
+
),
|
|
1744
|
+
isCodeVisible && /* @__PURE__ */ jsxs5("div", { className: "relative border-t border-stone-700/60 bg-stone-950/60 px-4 py-4 rounded-b-lg", children: [
|
|
1745
|
+
/* @__PURE__ */ jsx10(
|
|
1746
|
+
"button",
|
|
1747
|
+
{
|
|
1748
|
+
type: "button",
|
|
1749
|
+
onClick: handleCodeCopy,
|
|
1750
|
+
className: "absolute top-3 right-3 flex items-center gap-1 rounded-md border border-stone-700 bg-stone-800 px-2 py-1 text-xs font-medium text-white shadow hover:bg-stone-700",
|
|
1751
|
+
children: codeCopied ? /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1752
|
+
/* @__PURE__ */ jsx10(Check2, { className: "h-3.5 w-3.5" }),
|
|
1753
|
+
"Copied"
|
|
1754
|
+
] }) : /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1755
|
+
/* @__PURE__ */ jsx10(Copy, { className: "h-3.5 w-3.5" }),
|
|
1756
|
+
"Copy"
|
|
1757
|
+
] })
|
|
1758
|
+
}
|
|
1759
|
+
),
|
|
1760
|
+
/* @__PURE__ */ jsx10("pre", { className: "whitespace-pre overflow-x-auto text-xs md:text-sm text-stone-200 pr-14", children: /* @__PURE__ */ jsx10("code", { className: "block text-stone-200", children: highlightedCode ?? formattedCode }) })
|
|
1761
|
+
] })
|
|
1762
|
+
] }),
|
|
1449
1763
|
shouldShowCopyButton && /* @__PURE__ */ jsx10("div", { className: "flex-1 pt-4", children: /* @__PURE__ */ jsx10(
|
|
1450
1764
|
"button",
|
|
1451
1765
|
{
|
|
1452
1766
|
onClick: () => {
|
|
1453
|
-
|
|
1454
|
-
|
|
1767
|
+
const copyPayload = formattedCode || baseSnippet;
|
|
1768
|
+
if (!copyPayload) return;
|
|
1769
|
+
navigator.clipboard.writeText(copyPayload);
|
|
1455
1770
|
setCopied(true);
|
|
1456
1771
|
setTimeout(() => setCopied(false), 5e3);
|
|
1457
1772
|
},
|
|
@@ -1501,7 +1816,7 @@ var ControlPanel = () => {
|
|
|
1501
1816
|
var ControlPanel_default = ControlPanel;
|
|
1502
1817
|
|
|
1503
1818
|
// src/components/PreviewContainer/PreviewContainer.tsx
|
|
1504
|
-
import { useRef as
|
|
1819
|
+
import { useRef as useRef5 } from "react";
|
|
1505
1820
|
|
|
1506
1821
|
// src/components/Grid/Grid.tsx
|
|
1507
1822
|
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
@@ -1528,7 +1843,7 @@ import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
|
1528
1843
|
var PreviewContainer = ({ children, hideControls }) => {
|
|
1529
1844
|
const { config } = useControlsContext();
|
|
1530
1845
|
const { leftPanelWidth, isDesktop, isHydrated, containerRef } = useResizableLayout();
|
|
1531
|
-
const previewRef =
|
|
1846
|
+
const previewRef = useRef5(null);
|
|
1532
1847
|
return /* @__PURE__ */ jsx12(
|
|
1533
1848
|
"div",
|
|
1534
1849
|
{
|
|
@@ -1553,7 +1868,7 @@ var HiddenPreview = ({ children }) => /* @__PURE__ */ jsx13("div", { "aria-hidde
|
|
|
1553
1868
|
function Playground({ children }) {
|
|
1554
1869
|
const [isHydrated, setIsHydrated] = useState5(false);
|
|
1555
1870
|
const [copied, setCopied] = useState5(false);
|
|
1556
|
-
|
|
1871
|
+
useEffect6(() => {
|
|
1557
1872
|
setIsHydrated(true);
|
|
1558
1873
|
}, []);
|
|
1559
1874
|
const { showControls, isPresentationMode, isControlsOnly } = useMemo4(() => {
|
|
@@ -1601,7 +1916,7 @@ function Playground({ children }) {
|
|
|
1601
1916
|
}
|
|
1602
1917
|
|
|
1603
1918
|
// src/hooks/useAdvancedPaletteControls.ts
|
|
1604
|
-
import { useCallback as useCallback4, useEffect as
|
|
1919
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useMemo as useMemo5, useRef as useRef6, useState as useState6 } from "react";
|
|
1605
1920
|
var cloneForCallbacks = (palette) => clonePalette(palette);
|
|
1606
1921
|
var useAdvancedPaletteControls = (options = {}) => {
|
|
1607
1922
|
const resolvedDefaultPalette = useMemo5(
|
|
@@ -1615,10 +1930,10 @@ var useAdvancedPaletteControls = (options = {}) => {
|
|
|
1615
1930
|
const [palette, setPaletteState] = useState6(
|
|
1616
1931
|
() => clonePalette(resolvedDefaultPalette)
|
|
1617
1932
|
);
|
|
1618
|
-
const defaultSignatureRef =
|
|
1933
|
+
const defaultSignatureRef = useRef6(
|
|
1619
1934
|
createPaletteSignature(resolvedDefaultPalette)
|
|
1620
1935
|
);
|
|
1621
|
-
|
|
1936
|
+
useEffect7(() => {
|
|
1622
1937
|
const nextSignature = createPaletteSignature(resolvedDefaultPalette);
|
|
1623
1938
|
if (defaultSignatureRef.current === nextSignature) return;
|
|
1624
1939
|
defaultSignatureRef.current = nextSignature;
|