@pure-ds/core 0.6.9 → 0.6.11
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/custom-elements.json +865 -35
- package/dist/types/pds.d.ts +31 -0
- package/dist/types/public/assets/js/pds-manager.d.ts +100 -2
- package/dist/types/public/assets/js/pds-manager.d.ts.map +1 -1
- package/dist/types/public/assets/js/pds.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-form.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-live-converter.d.ts +8 -0
- package/dist/types/public/assets/pds/components/pds-live-converter.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-live-edit.d.ts +1 -195
- package/dist/types/public/assets/pds/components/pds-live-edit.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-live-importer.d.ts +2 -0
- package/dist/types/public/assets/pds/components/pds-live-importer.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-live-template-canvas.d.ts +2 -0
- package/dist/types/public/assets/pds/components/pds-live-template-canvas.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-omnibox.d.ts +0 -2
- package/dist/types/public/assets/pds/components/pds-omnibox.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-scrollrow.d.ts +20 -0
- package/dist/types/public/assets/pds/components/pds-scrollrow.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-toaster.d.ts +1 -1
- package/dist/types/public/assets/pds/components/pds-toaster.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-treeview.d.ts +37 -0
- package/dist/types/public/assets/pds/components/pds-treeview.d.ts.map +1 -0
- package/dist/types/src/js/common/toast.d.ts +8 -0
- package/dist/types/src/js/common/toast.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-config.d.ts +1306 -13
- package/dist/types/src/js/pds-core/pds-config.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-enhancers-meta.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-enhancers.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-generator.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-live.d.ts +2 -1
- package/dist/types/src/js/pds-core/pds-live.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-ontology.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-start-helpers.d.ts +1 -4
- package/dist/types/src/js/pds-core/pds-start-helpers.d.ts.map +1 -1
- package/dist/types/src/js/pds-live-manager/conversion-service.d.ts +66 -0
- package/dist/types/src/js/pds-live-manager/conversion-service.d.ts.map +1 -0
- package/dist/types/src/js/pds-live-manager/import-contract.d.ts +15 -0
- package/dist/types/src/js/pds-live-manager/import-contract.d.ts.map +1 -0
- package/dist/types/src/js/pds-live-manager/import-history-service.d.ts +32 -0
- package/dist/types/src/js/pds-live-manager/import-history-service.d.ts.map +1 -0
- package/dist/types/src/js/pds-live-manager/import-service.d.ts +21 -0
- package/dist/types/src/js/pds-live-manager/import-service.d.ts.map +1 -0
- package/dist/types/src/js/pds-live-manager/template-service.d.ts +17 -0
- package/dist/types/src/js/pds-live-manager/template-service.d.ts.map +1 -0
- package/dist/types/src/js/pds-manager.d.ts +4 -0
- package/dist/types/src/js/pds.d.ts.map +1 -1
- package/package.json +7 -3
- package/packages/pds-cli/README.md +51 -0
- package/packages/pds-cli/bin/pds-import.js +176 -0
- package/packages/pds-cli/bin/pds-static.js +31 -1
- package/packages/pds-cli/bin/postinstall.mjs +17 -8
- package/public/assets/js/app.js +23 -147
- package/public/assets/js/pds-manager.js +481 -248
- package/public/assets/js/pds.js +16 -16
- package/public/assets/pds/components/pds-form.js +124 -27
- package/public/assets/pds/components/pds-live-converter.js +47 -0
- package/public/assets/pds/components/pds-live-edit.js +1626 -211
- package/public/assets/pds/components/pds-live-importer.js +772 -0
- package/public/assets/pds/components/pds-live-template-canvas.js +171 -0
- package/public/assets/pds/components/pds-omnibox.js +146 -20
- package/public/assets/pds/components/pds-scrollrow.js +56 -1
- package/public/assets/pds/components/pds-toaster.js +50 -5
- package/public/assets/pds/components/pds-treeview.js +972 -0
- package/public/assets/pds/custom-elements.json +865 -35
- package/public/assets/pds/pds-css-complete.json +7 -7
- package/public/assets/pds/pds.css-data.json +5 -35
- package/public/assets/pds/templates/commerce-scroll-explorer.html +115 -0
- package/public/assets/pds/templates/content-brand-showcase.html +110 -0
- package/public/assets/pds/templates/feedback-ops-dashboard.html +91 -0
- package/public/assets/pds/templates/release-readiness-radar.html +69 -0
- package/public/assets/pds/templates/support-command-center.html +92 -0
- package/public/assets/pds/templates/templates.json +53 -0
- package/public/assets/pds/templates/workspace-settings-lab.html +131 -0
- package/public/assets/pds/vscode-custom-data.json +54 -4
- package/readme.md +34 -0
- package/src/js/pds-core/pds-config.js +831 -40
- package/src/js/pds-core/pds-enhancers-meta.js +11 -0
- package/src/js/pds-core/pds-enhancers.js +259 -5
- package/src/js/pds-core/pds-generator.js +353 -52
- package/src/js/pds-core/pds-live.js +630 -15
- package/src/js/pds-core/pds-ontology.js +6 -0
- package/src/js/pds-core/pds-start-helpers.js +14 -6
- package/src/js/pds-live-manager/conversion-service.js +3136 -0
- package/src/js/pds-live-manager/import-contract.js +57 -0
- package/src/js/pds-live-manager/import-history-service.js +145 -0
- package/src/js/pds-live-manager/import-service.js +255 -0
- package/src/js/pds-live-manager/tailwind-conversion-rules.json +383 -0
- package/src/js/pds-live-manager/template-service.js +170 -0
- package/src/js/pds.d.ts +31 -0
- package/src/js/pds.js +71 -60
|
@@ -96,9 +96,42 @@ const QUICK_STYLE_PROPERTIES = [
|
|
|
96
96
|
"width",
|
|
97
97
|
];
|
|
98
98
|
|
|
99
|
+
const LIVE_EDIT_HIGHLIGHT_BLACKLIST = [
|
|
100
|
+
{
|
|
101
|
+
id: "toaster",
|
|
102
|
+
selector: "pds-toaster",
|
|
103
|
+
includeDescendants: true,
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: "live-edit-toggle",
|
|
107
|
+
selector: "#pds-live-edit-toggle",
|
|
108
|
+
includeDescendants: true,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: "ask-dialog",
|
|
112
|
+
selector: "dialog",
|
|
113
|
+
includeDescendants: true,
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
function isLiveEditHighlightBlacklisted(node) {
|
|
118
|
+
if (!(node instanceof Element)) return false;
|
|
119
|
+
return LIVE_EDIT_HIGHLIGHT_BLACKLIST.some((entry) => {
|
|
120
|
+
if (!entry?.selector) return false;
|
|
121
|
+
if (entry.includeDescendants) {
|
|
122
|
+
return Boolean(node.closest(entry.selector));
|
|
123
|
+
}
|
|
124
|
+
return node.matches(entry.selector);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
99
128
|
const INLINE_VAR_REGEX = /var\(\s*(--[^)\s,]+)\s*/g;
|
|
100
129
|
const CUSTOM_PROP_REGEX = /--.+/;
|
|
101
130
|
const COLOR_VALUE_REGEX = /#(?:[0-9a-f]{3,8})\b|rgba?\([^)]*\)|hsla?\([^)]*\)/gi;
|
|
131
|
+
const SHIKI_BUNDLE_URL = "https://esm.sh/shiki@1.29.2?bundle";
|
|
132
|
+
const SETTINGS_ONLY_ATTR = "data-pds-live-settings-only";
|
|
133
|
+
|
|
134
|
+
let shikiModulePromise = null;
|
|
102
135
|
|
|
103
136
|
const ENUM_FIELD_OPTIONS = {
|
|
104
137
|
"shape.borderWidth": ["hairline", "thin", "medium", "thick"],
|
|
@@ -108,6 +141,47 @@ let cachedTokenIndex = null;
|
|
|
108
141
|
let cachedTokenIndexMeta = null;
|
|
109
142
|
let colorNormalizer = null;
|
|
110
143
|
|
|
144
|
+
function escapeHtml(value) {
|
|
145
|
+
return String(value || "")
|
|
146
|
+
.replaceAll("&", "&")
|
|
147
|
+
.replaceAll("<", "<")
|
|
148
|
+
.replaceAll(">", ">")
|
|
149
|
+
.replaceAll('"', """)
|
|
150
|
+
.replaceAll("'", "'");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function loadShikiModule() {
|
|
154
|
+
if (shikiModulePromise) return shikiModulePromise;
|
|
155
|
+
shikiModulePromise = import(SHIKI_BUNDLE_URL).catch(() => null);
|
|
156
|
+
return shikiModulePromise;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function resolveShikiTheme() {
|
|
160
|
+
const isDark =
|
|
161
|
+
PDS?.theme === "dark" ||
|
|
162
|
+
document.documentElement.getAttribute("data-theme") === "dark" ||
|
|
163
|
+
document.documentElement.classList.contains("theme-dark");
|
|
164
|
+
return isDark ? "github-dark-default" : "github-light-default";
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function renderHtmlWithShiki(code = "") {
|
|
168
|
+
const fallback = `<pre><code>${escapeHtml(code)}</code></pre>`;
|
|
169
|
+
const shiki = await loadShikiModule();
|
|
170
|
+
|
|
171
|
+
if (!shiki || typeof shiki.codeToHtml !== "function") {
|
|
172
|
+
return fallback;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
return shiki.codeToHtml(String(code || ""), {
|
|
177
|
+
lang: "html",
|
|
178
|
+
theme: resolveShikiTheme(),
|
|
179
|
+
});
|
|
180
|
+
} catch (error) {
|
|
181
|
+
return fallback;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
111
185
|
const GLOBAL_LAYOUT_PATHS = new Set([
|
|
112
186
|
"layout.maxWidth",
|
|
113
187
|
"layout.maxWidths",
|
|
@@ -138,6 +212,8 @@ const DARK_MODE_PATH_MARKER = ".darkMode.";
|
|
|
138
212
|
const QUICK_EDIT_LIMIT = 4;
|
|
139
213
|
const DROPDOWN_VIEWPORT_PADDING = 8;
|
|
140
214
|
const FONT_FAMILY_PATH_REGEX = /^typography\.fontFamily/i;
|
|
215
|
+
const FORM_THEME_CONTEXT_FIELD = "__pdsThemeContext";
|
|
216
|
+
const FORM_THEME_CONTEXT_POINTER = `/${FORM_THEME_CONTEXT_FIELD}`;
|
|
141
217
|
|
|
142
218
|
function isHoverCapable() {
|
|
143
219
|
if (typeof window === "undefined" || !window.matchMedia) return false;
|
|
@@ -188,8 +264,13 @@ ${EDITOR_TAG} {
|
|
|
188
264
|
.${DROPDOWN_CLASS} menu {
|
|
189
265
|
min-width: max-content;
|
|
190
266
|
max-width: 350px;
|
|
267
|
+
margin: 0;
|
|
268
|
+
padding: 0;
|
|
269
|
+
list-style: none;
|
|
191
270
|
}
|
|
192
271
|
.${DROPDOWN_CLASS} .pds-live-editor-menu {
|
|
272
|
+
display: block;
|
|
273
|
+
background-color: var(--color-surface-base);
|
|
193
274
|
padding: var(--spacing-1);
|
|
194
275
|
max-width: 350px;
|
|
195
276
|
padding-bottom: 0;
|
|
@@ -230,8 +311,41 @@ ${EDITOR_TAG} {
|
|
|
230
311
|
background: var(--color-surface-base);
|
|
231
312
|
position: sticky;
|
|
232
313
|
justify-content: space-between;
|
|
314
|
+
align-items: center;
|
|
315
|
+
bottom: 0;
|
|
316
|
+
z-index: 1;
|
|
317
|
+
}
|
|
318
|
+
.pds-live-editor-drawer-footer {
|
|
319
|
+
position: sticky;
|
|
233
320
|
bottom: 0;
|
|
234
321
|
z-index: 1;
|
|
322
|
+
padding-top: var(--spacing-3);
|
|
323
|
+
padding-bottom: env(safe-area-inset-bottom, 0);
|
|
324
|
+
border-top: var(--border-width-thin) solid var(--color-border);
|
|
325
|
+
background: var(--color-surface-base);
|
|
326
|
+
}
|
|
327
|
+
.pds-live-editor-drawer-footer > button {
|
|
328
|
+
width: 100%;
|
|
329
|
+
justify-content: center;
|
|
330
|
+
}
|
|
331
|
+
.pds-live-editor-drawer-footer .pds-live-editor-reset-btn {
|
|
332
|
+
color: var(--color-danger-700);
|
|
333
|
+
border-color: var(--color-danger-700);
|
|
334
|
+
}
|
|
335
|
+
.pds-live-editor-drawer-footer .pds-live-editor-reset-btn:hover,
|
|
336
|
+
.pds-live-editor-drawer-footer .pds-live-editor-reset-btn:focus-visible,
|
|
337
|
+
.pds-live-editor-drawer-footer .pds-live-editor-reset-btn:active {
|
|
338
|
+
color: var(--color-danger-700);
|
|
339
|
+
border-color: var(--color-danger-700);
|
|
340
|
+
}
|
|
341
|
+
.pds-live-editor-drawer-content {
|
|
342
|
+
min-height: 100%;
|
|
343
|
+
display: grid;
|
|
344
|
+
grid-template-rows: minmax(0, 1fr) auto;
|
|
345
|
+
gap: var(--spacing-4);
|
|
346
|
+
}
|
|
347
|
+
.pds-live-editor-drawer-content > .accordion {
|
|
348
|
+
min-height: 0;
|
|
235
349
|
}
|
|
236
350
|
`;
|
|
237
351
|
document.head.appendChild(style);
|
|
@@ -311,6 +425,14 @@ function deepMerge(target = {}, source = {}) {
|
|
|
311
425
|
return out;
|
|
312
426
|
}
|
|
313
427
|
|
|
428
|
+
function markNodeTreeAsLiveEditIgnored(node) {
|
|
429
|
+
if (!(node instanceof Element)) return;
|
|
430
|
+
node.setAttribute("data-pds-live-edit-ignore", "true");
|
|
431
|
+
node.querySelectorAll("*").forEach((element) => {
|
|
432
|
+
element.setAttribute("data-pds-live-edit-ignore", "true");
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
314
436
|
function titleize(value) {
|
|
315
437
|
return String(value)
|
|
316
438
|
.replace(/([a-z])([A-Z])/g, "$1 $2")
|
|
@@ -589,6 +711,62 @@ function toColorInputValue(value) {
|
|
|
589
711
|
return hexValue || value;
|
|
590
712
|
}
|
|
591
713
|
|
|
714
|
+
function isColorPath(path) {
|
|
715
|
+
return String(path || "").toLowerCase().startsWith("colors.");
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
function inferColorVariableCandidates(path) {
|
|
719
|
+
const normalizedPath = String(path || "").toLowerCase();
|
|
720
|
+
const key = normalizedPath.replace(/^colors\./, "").replace(/^darkmode\./, "");
|
|
721
|
+
const tail = key.split(".").pop();
|
|
722
|
+
|
|
723
|
+
const directMap = {
|
|
724
|
+
primary: ["--color-primary-500"],
|
|
725
|
+
secondary: ["--color-secondary-500", "--color-gray-500"],
|
|
726
|
+
accent: ["--color-accent-500"],
|
|
727
|
+
background: ["--color-surface-base"],
|
|
728
|
+
success: ["--color-success-500"],
|
|
729
|
+
warning: ["--color-warning-500"],
|
|
730
|
+
danger: ["--color-danger-500"],
|
|
731
|
+
info: ["--color-info-500"],
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
const candidates = new Set();
|
|
735
|
+
if (tail && directMap[tail]) {
|
|
736
|
+
directMap[tail].forEach((item) => candidates.add(item));
|
|
737
|
+
}
|
|
738
|
+
if (tail) {
|
|
739
|
+
candidates.add(`--color-${tail}-500`);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
return Array.from(candidates);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
function resolveColorValueForPath(path, value, hintValue) {
|
|
746
|
+
if (!isColorPath(path)) return null;
|
|
747
|
+
|
|
748
|
+
const fromValue = toColorInputValue(value);
|
|
749
|
+
if (normalizeHexColor(fromValue)) return fromValue;
|
|
750
|
+
|
|
751
|
+
const fromHint = toColorInputValue(hintValue);
|
|
752
|
+
if (normalizeHexColor(fromHint)) return fromHint;
|
|
753
|
+
|
|
754
|
+
if (typeof window === "undefined" || typeof document === "undefined") return null;
|
|
755
|
+
const root = document.documentElement;
|
|
756
|
+
if (!root) return null;
|
|
757
|
+
|
|
758
|
+
const style = window.getComputedStyle(root);
|
|
759
|
+
const candidates = inferColorVariableCandidates(path);
|
|
760
|
+
for (const varName of candidates) {
|
|
761
|
+
const raw = style.getPropertyValue(varName).trim();
|
|
762
|
+
if (!raw) continue;
|
|
763
|
+
const resolved = toColorInputValue(raw);
|
|
764
|
+
if (normalizeHexColor(resolved)) return resolved;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
return null;
|
|
768
|
+
}
|
|
769
|
+
|
|
592
770
|
function getCustomPropertyNames(style) {
|
|
593
771
|
const names = [];
|
|
594
772
|
if (!style) return names;
|
|
@@ -929,7 +1107,105 @@ function splitFontFamilyStack(value) {
|
|
|
929
1107
|
return parts;
|
|
930
1108
|
}
|
|
931
1109
|
|
|
932
|
-
|
|
1110
|
+
const GENERIC_FONT_FAMILIES = new Set([
|
|
1111
|
+
"serif",
|
|
1112
|
+
"sans-serif",
|
|
1113
|
+
"monospace",
|
|
1114
|
+
"cursive",
|
|
1115
|
+
"fantasy",
|
|
1116
|
+
"system-ui",
|
|
1117
|
+
"ui-serif",
|
|
1118
|
+
"ui-sans-serif",
|
|
1119
|
+
"ui-monospace",
|
|
1120
|
+
"ui-rounded",
|
|
1121
|
+
"emoji",
|
|
1122
|
+
"math",
|
|
1123
|
+
"fangsong",
|
|
1124
|
+
]);
|
|
1125
|
+
|
|
1126
|
+
let loadGoogleFontFnPromise = null;
|
|
1127
|
+
let managerModulePromise = null;
|
|
1128
|
+
|
|
1129
|
+
function normalizeFontName(fontFamily) {
|
|
1130
|
+
return String(fontFamily || "")
|
|
1131
|
+
.trim()
|
|
1132
|
+
.replace(/^['"]+|['"]+$/g, "")
|
|
1133
|
+
.trim();
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
function isLikelyLoadableFont(fontFamily) {
|
|
1137
|
+
const normalized = normalizeFontName(fontFamily).toLowerCase();
|
|
1138
|
+
if (!normalized) return false;
|
|
1139
|
+
return !GENERIC_FONT_FAMILIES.has(normalized);
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
async function getLoadGoogleFontFn() {
|
|
1143
|
+
if (typeof PDS?.loadGoogleFont === "function") {
|
|
1144
|
+
return PDS.loadGoogleFont;
|
|
1145
|
+
}
|
|
1146
|
+
if (loadGoogleFontFnPromise) return loadGoogleFontFnPromise;
|
|
1147
|
+
loadGoogleFontFnPromise = (async () => {
|
|
1148
|
+
const manager = await getPdsManagerModule();
|
|
1149
|
+
if (typeof manager?.loadGoogleFont === "function") {
|
|
1150
|
+
return manager.loadGoogleFont;
|
|
1151
|
+
}
|
|
1152
|
+
return null;
|
|
1153
|
+
})();
|
|
1154
|
+
return loadGoogleFontFnPromise;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
async function getPdsManagerModule() {
|
|
1158
|
+
if (managerModulePromise) return managerModulePromise;
|
|
1159
|
+
|
|
1160
|
+
managerModulePromise = (async () => {
|
|
1161
|
+
const candidates = [
|
|
1162
|
+
PDS?.currentConfig?.managerURL,
|
|
1163
|
+
"../core/pds-manager.js",
|
|
1164
|
+
"/assets/pds/core/pds-manager.js",
|
|
1165
|
+
].filter(Boolean);
|
|
1166
|
+
|
|
1167
|
+
const attempted = new Set();
|
|
1168
|
+
for (const candidate of candidates) {
|
|
1169
|
+
try {
|
|
1170
|
+
const resolved = new URL(candidate, import.meta.url).href;
|
|
1171
|
+
if (attempted.has(resolved)) continue;
|
|
1172
|
+
attempted.add(resolved);
|
|
1173
|
+
const mod = await import(resolved);
|
|
1174
|
+
if (mod && typeof mod === "object") return mod;
|
|
1175
|
+
} catch (e) {}
|
|
1176
|
+
}
|
|
1177
|
+
return null;
|
|
1178
|
+
})();
|
|
1179
|
+
|
|
1180
|
+
return managerModulePromise;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
async function loadTypographyFontsForDesign(typography) {
|
|
1184
|
+
if (!typography || typeof typography !== "object") return;
|
|
1185
|
+
|
|
1186
|
+
const loadGoogleFont = await getLoadGoogleFontFn();
|
|
1187
|
+
if (typeof loadGoogleFont !== "function") return;
|
|
1188
|
+
|
|
1189
|
+
const families = [
|
|
1190
|
+
typography.fontFamilyHeadings,
|
|
1191
|
+
typography.fontFamilyBody,
|
|
1192
|
+
typography.fontFamilyMono,
|
|
1193
|
+
];
|
|
1194
|
+
|
|
1195
|
+
const fontNames = new Set();
|
|
1196
|
+
families.forEach((stack) => {
|
|
1197
|
+
splitFontFamilyStack(stack).forEach((item) => {
|
|
1198
|
+
const fontName = normalizeFontName(item);
|
|
1199
|
+
if (isLikelyLoadableFont(fontName)) {
|
|
1200
|
+
fontNames.add(fontName);
|
|
1201
|
+
}
|
|
1202
|
+
});
|
|
1203
|
+
});
|
|
1204
|
+
|
|
1205
|
+
await Promise.allSettled(Array.from(fontNames).map((name) => loadGoogleFont(name)));
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
function getPresetFontFamilyVariations(previewFontSize = resolveFontFamilyPreviewFontSize()) {
|
|
933
1209
|
const presets = Object.values(PDS?.presets || {});
|
|
934
1210
|
const seen = new Set();
|
|
935
1211
|
const items = [];
|
|
@@ -938,9 +1214,11 @@ function getPresetFontFamilyVariations() {
|
|
|
938
1214
|
if (!normalized || seen.has(normalized)) return;
|
|
939
1215
|
seen.add(normalized);
|
|
940
1216
|
items.push({
|
|
1217
|
+
//index: items.length,
|
|
941
1218
|
id: normalized,
|
|
1219
|
+
value: normalized,
|
|
942
1220
|
text: normalized,
|
|
943
|
-
style: `font-family: ${normalized}
|
|
1221
|
+
style: `font-family: ${normalized}; font-size: ${previewFontSize};`,
|
|
944
1222
|
});
|
|
945
1223
|
};
|
|
946
1224
|
|
|
@@ -959,35 +1237,95 @@ function getPresetFontFamilyVariations() {
|
|
|
959
1237
|
});
|
|
960
1238
|
});
|
|
961
1239
|
|
|
962
|
-
return items
|
|
1240
|
+
return items.sort((a, b) =>
|
|
1241
|
+
String(b?.text || "").localeCompare(String(a?.text || ""), undefined, {
|
|
1242
|
+
sensitivity: "base",
|
|
1243
|
+
})
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
function resolveFontFamilyPreviewFontSize(control) {
|
|
1248
|
+
const controlInput = control?.querySelector?.(".ac-input");
|
|
1249
|
+
if (controlInput) {
|
|
1250
|
+
const fontSize = getComputedStyle(controlInput).fontSize;
|
|
1251
|
+
if (fontSize) return fontSize;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
const selectors = [
|
|
1255
|
+
"[name='/typography/fontFamilyBody']",
|
|
1256
|
+
"[name='/typography/fontFamilyHeadings']",
|
|
1257
|
+
"[name='/typography/fontFamilyMono']",
|
|
1258
|
+
];
|
|
1259
|
+
|
|
1260
|
+
for (const selector of selectors) {
|
|
1261
|
+
const omnibox = document.querySelector(selector);
|
|
1262
|
+
const input = omnibox?.shadowRoot?.querySelector?.(".ac-input");
|
|
1263
|
+
if (!input) continue;
|
|
1264
|
+
const fontSize = getComputedStyle(input).fontSize;
|
|
1265
|
+
if (fontSize) return fontSize;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
return "var(--font-size-md)";
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
async function loadGoogleFontsForFontFamilyItems(items) {
|
|
1272
|
+
if (!Array.isArray(items) || !items.length) return;
|
|
1273
|
+
|
|
1274
|
+
const loadGoogleFont = await getLoadGoogleFontFn();
|
|
1275
|
+
if (typeof loadGoogleFont !== "function") return;
|
|
1276
|
+
|
|
1277
|
+
const fontNames = new Set();
|
|
1278
|
+
items.forEach((item) => {
|
|
1279
|
+
const stack = item?.value || item?.text;
|
|
1280
|
+
splitFontFamilyStack(stack).forEach((entry) => {
|
|
1281
|
+
const fontName = normalizeFontName(entry);
|
|
1282
|
+
if (isLikelyLoadableFont(fontName)) {
|
|
1283
|
+
fontNames.add(fontName);
|
|
1284
|
+
}
|
|
1285
|
+
});
|
|
1286
|
+
});
|
|
1287
|
+
|
|
1288
|
+
if (!fontNames.size) return;
|
|
1289
|
+
await Promise.allSettled(Array.from(fontNames).map((name) => loadGoogleFont(name)));
|
|
963
1290
|
}
|
|
964
1291
|
|
|
965
1292
|
function buildFontFamilyOmniboxSettings() {
|
|
966
|
-
const
|
|
967
|
-
const filterItems = (search) => {
|
|
1293
|
+
const filterItems = (items, search) => {
|
|
968
1294
|
const query = String(search || "").trim().toLowerCase();
|
|
969
|
-
if (!query) return
|
|
970
|
-
return
|
|
1295
|
+
if (!query) return items;
|
|
1296
|
+
return items.filter((item) => {
|
|
1297
|
+
const text = String(
|
|
1298
|
+
item?.text || item?.id || item?.element?.textContent || ""
|
|
1299
|
+
).toLowerCase();
|
|
1300
|
+
return text.includes(query);
|
|
1301
|
+
});
|
|
971
1302
|
};
|
|
972
1303
|
|
|
973
|
-
|
|
1304
|
+
|
|
1305
|
+
return {
|
|
1306
|
+
//debug: true,
|
|
1307
|
+
itemGrid: "0 1fr 0",
|
|
974
1308
|
hideCategory: true,
|
|
975
|
-
iconHandler: (item) => {
|
|
976
|
-
|
|
1309
|
+
iconHandler: (item) => {
|
|
977
1310
|
return "";
|
|
978
1311
|
},
|
|
979
1312
|
categories: {
|
|
980
1313
|
FontFamilies: {
|
|
981
1314
|
trigger: () => true,
|
|
982
|
-
getItems: (options) =>
|
|
983
|
-
|
|
984
|
-
const
|
|
1315
|
+
getItems: async (options) => {
|
|
1316
|
+
const previewFontSize = resolveFontFamilyPreviewFontSize(options?.control);
|
|
1317
|
+
const allItems = getPresetFontFamilyVariations(previewFontSize);
|
|
1318
|
+
const items = filterItems(allItems, options?.search);
|
|
985
1319
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1320
|
+
await loadGoogleFontsForFontFamilyItems(items);
|
|
1321
|
+
|
|
1322
|
+
return items;
|
|
1323
|
+
},
|
|
1324
|
+
action: (options) => {
|
|
1325
|
+
const input = document.querySelector("pds-omnibox");
|
|
1326
|
+
if (input) {
|
|
1327
|
+
input.value = options.text;
|
|
989
1328
|
}
|
|
990
|
-
return options?.text || options?.id;
|
|
991
1329
|
},
|
|
992
1330
|
},
|
|
993
1331
|
},
|
|
@@ -1034,7 +1372,7 @@ function buildSchemaFromPaths(paths, design, hints = {}) {
|
|
|
1034
1372
|
};
|
|
1035
1373
|
|
|
1036
1374
|
const isColorValue = (value, path) => {
|
|
1037
|
-
if (
|
|
1375
|
+
if (isColorPath(path)) return true;
|
|
1038
1376
|
if (typeof value !== "string") return false;
|
|
1039
1377
|
return /^#([0-9a-f]{3,8})$/i.test(value) || /^rgba?\(/i.test(value) || /^hsla?\(/i.test(value);
|
|
1040
1378
|
};
|
|
@@ -1064,8 +1402,12 @@ function buildSchemaFromPaths(paths, design, hints = {}) {
|
|
|
1064
1402
|
const value = getValueAtPath(design, [category, ...rest]);
|
|
1065
1403
|
const hintValue = hints[path];
|
|
1066
1404
|
const enumOptions = getEnumOptions(path);
|
|
1067
|
-
const
|
|
1068
|
-
const
|
|
1405
|
+
const resolvedColorValue = resolveColorValueForPath(path, value, hintValue);
|
|
1406
|
+
const normalizedValue = normalizeEnumValue(path, resolvedColorValue ?? value);
|
|
1407
|
+
const normalizedHint = normalizeEnumValue(
|
|
1408
|
+
path,
|
|
1409
|
+
resolvedColorValue ?? hintValue,
|
|
1410
|
+
);
|
|
1069
1411
|
const inferredType = Array.isArray(value)
|
|
1070
1412
|
? "array"
|
|
1071
1413
|
: value === null
|
|
@@ -1232,6 +1574,10 @@ async function applyDesignPatch(patch) {
|
|
|
1232
1574
|
const nextOptions = { ...currentOptions, design: nextDesign };
|
|
1233
1575
|
if (resolvedPresetId) nextOptions.preset = resolvedPresetId;
|
|
1234
1576
|
|
|
1577
|
+
try {
|
|
1578
|
+
await loadTypographyFontsForDesign(nextDesign?.typography);
|
|
1579
|
+
} catch (e) {}
|
|
1580
|
+
|
|
1235
1581
|
const nextGenerator = new Generator(nextOptions);
|
|
1236
1582
|
if (PDS?.applyStyles) {
|
|
1237
1583
|
await PDS.applyStyles(nextGenerator);
|
|
@@ -1307,6 +1653,17 @@ function getActivePresetId() {
|
|
|
1307
1653
|
return stored?.preset || PDS?.currentConfig?.preset || PDS?.currentPreset || null;
|
|
1308
1654
|
}
|
|
1309
1655
|
|
|
1656
|
+
function getPresetNameById(presetId) {
|
|
1657
|
+
if (!presetId) return "";
|
|
1658
|
+
const presets = PDS?.presets || {};
|
|
1659
|
+
const preset =
|
|
1660
|
+
presets?.[presetId] ||
|
|
1661
|
+
Object.values(presets || {}).find(
|
|
1662
|
+
(candidate) => String(candidate?.id || candidate?.name) === String(presetId)
|
|
1663
|
+
);
|
|
1664
|
+
return preset?.name || String(presetId);
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1310
1667
|
async function applyPresetSelection(presetId) {
|
|
1311
1668
|
if (!presetId) return;
|
|
1312
1669
|
setStoredConfig({
|
|
@@ -1466,18 +1823,58 @@ async function exportFromLiveEdit(format) {
|
|
|
1466
1823
|
}
|
|
1467
1824
|
|
|
1468
1825
|
function setFormSchemas(form, schema, uiSchema, design) {
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
form.
|
|
1826
|
+
const themedSchema = withThemeConditionalSchema(schema, uiSchema);
|
|
1827
|
+
const formValues = withThemeContextValues(design);
|
|
1828
|
+
form.jsonSchema = themedSchema.schema;
|
|
1829
|
+
form.uiSchema = themedSchema.uiSchema;
|
|
1830
|
+
form.values = formValues;
|
|
1472
1831
|
}
|
|
1473
1832
|
|
|
1474
|
-
async function
|
|
1475
|
-
|
|
1833
|
+
async function waitForElementDefinition(tagName, timeoutMs = 4000) {
|
|
1834
|
+
if (customElements.get(tagName)) return true;
|
|
1835
|
+
|
|
1836
|
+
let probe = null;
|
|
1837
|
+
try {
|
|
1838
|
+
if (typeof document !== "undefined" && document.body) {
|
|
1839
|
+
probe = document.createElement(tagName);
|
|
1840
|
+
probe.setAttribute("hidden", "");
|
|
1841
|
+
probe.setAttribute("aria-hidden", "true");
|
|
1842
|
+
probe.style.display = "none";
|
|
1843
|
+
document.body.appendChild(probe);
|
|
1844
|
+
}
|
|
1845
|
+
} catch (e) {}
|
|
1846
|
+
|
|
1847
|
+
await Promise.race([
|
|
1848
|
+
customElements.whenDefined(tagName),
|
|
1849
|
+
new Promise((_, reject) => {
|
|
1850
|
+
setTimeout(() => reject(new Error(`Timed out waiting for <${tagName}> definition`)), timeoutMs);
|
|
1851
|
+
}),
|
|
1852
|
+
]);
|
|
1853
|
+
|
|
1854
|
+
try {
|
|
1855
|
+
if (probe && probe.parentNode) {
|
|
1856
|
+
probe.parentNode.removeChild(probe);
|
|
1857
|
+
}
|
|
1858
|
+
} catch (e) {}
|
|
1476
1859
|
|
|
1477
|
-
if (!customElements.get(
|
|
1478
|
-
|
|
1860
|
+
if (!customElements.get(tagName)) {
|
|
1861
|
+
throw new Error(`<${tagName}> is not defined`);
|
|
1479
1862
|
}
|
|
1480
1863
|
|
|
1864
|
+
return true;
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
async function createConfiguredForm({
|
|
1868
|
+
schema,
|
|
1869
|
+
uiSchema,
|
|
1870
|
+
values,
|
|
1871
|
+
onSubmit,
|
|
1872
|
+
onUndo,
|
|
1873
|
+
normalizeFlatValues,
|
|
1874
|
+
formOptions,
|
|
1875
|
+
}) {
|
|
1876
|
+
await waitForElementDefinition("pds-form");
|
|
1877
|
+
|
|
1481
1878
|
const form = document.createElement("pds-form");
|
|
1482
1879
|
const fontFamilyOmniboxSettings = buildFontFamilyOmniboxSettings();
|
|
1483
1880
|
form.setAttribute("hide-actions", "");
|
|
@@ -1488,16 +1885,38 @@ async function buildForm(paths, design, onSubmit, onUndo, hints = {}) {
|
|
|
1488
1885
|
enhancements: {
|
|
1489
1886
|
rangeOutput: true,
|
|
1490
1887
|
},
|
|
1888
|
+
...(formOptions && typeof formOptions === "object" ? formOptions : {}),
|
|
1491
1889
|
};
|
|
1890
|
+
|
|
1492
1891
|
form.defineRenderer(
|
|
1493
1892
|
"font-family-omnibox",
|
|
1494
1893
|
({ id, path, value, attrs, set }) => {
|
|
1495
|
-
const resolveSelectedValue = (options, actionResult) => {
|
|
1894
|
+
const resolveSelectedValue = (options, actionResult, selectionEvent) => {
|
|
1496
1895
|
if (typeof actionResult === "string" && actionResult.trim()) {
|
|
1497
1896
|
return actionResult;
|
|
1498
1897
|
}
|
|
1898
|
+
|
|
1899
|
+
const eventDetail = selectionEvent?.detail;
|
|
1900
|
+
const fromEventValue = String(eventDetail?.value || "").trim();
|
|
1901
|
+
if (fromEventValue) return fromEventValue;
|
|
1902
|
+
|
|
1903
|
+
const fromEventText = String(eventDetail?.text || "").trim();
|
|
1904
|
+
if (fromEventText) return fromEventText;
|
|
1905
|
+
|
|
1906
|
+
const fromEventElementText = String(
|
|
1907
|
+
eventDetail?.element?.textContent || ""
|
|
1908
|
+
).trim();
|
|
1909
|
+
if (fromEventElementText) return fromEventElementText;
|
|
1910
|
+
|
|
1499
1911
|
const fromText = String(options?.text || "").trim();
|
|
1500
1912
|
if (fromText) return fromText;
|
|
1913
|
+
|
|
1914
|
+
const fromValue = String(options?.value || "").trim();
|
|
1915
|
+
if (fromValue) return fromValue;
|
|
1916
|
+
|
|
1917
|
+
const fromElementText = String(options?.element?.textContent || "").trim();
|
|
1918
|
+
if (fromElementText) return fromElementText;
|
|
1919
|
+
|
|
1501
1920
|
return String(options?.id || "").trim();
|
|
1502
1921
|
};
|
|
1503
1922
|
|
|
@@ -1509,15 +1928,36 @@ async function buildForm(paths, design, onSubmit, onUndo, hints = {}) {
|
|
|
1509
1928
|
categoryName,
|
|
1510
1929
|
{
|
|
1511
1930
|
...categoryConfig,
|
|
1512
|
-
action: (
|
|
1931
|
+
action: (...args) => {
|
|
1932
|
+
const [options, selectionEvent] = args;
|
|
1513
1933
|
const actionResult =
|
|
1514
1934
|
typeof originalAction === "function"
|
|
1515
|
-
? originalAction(
|
|
1935
|
+
? originalAction(...args)
|
|
1516
1936
|
: undefined;
|
|
1517
|
-
|
|
1937
|
+
|
|
1938
|
+
if (actionResult && typeof actionResult.then === "function") {
|
|
1939
|
+
return actionResult.then((resolved) => {
|
|
1940
|
+
const selected = resolveSelectedValue(
|
|
1941
|
+
options,
|
|
1942
|
+
resolved,
|
|
1943
|
+
selectionEvent
|
|
1944
|
+
);
|
|
1945
|
+
if (selected) {
|
|
1946
|
+
set(selected);
|
|
1947
|
+
}
|
|
1948
|
+
return resolved;
|
|
1949
|
+
});
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
const selected = resolveSelectedValue(
|
|
1953
|
+
options,
|
|
1954
|
+
actionResult,
|
|
1955
|
+
selectionEvent
|
|
1956
|
+
);
|
|
1518
1957
|
if (selected) {
|
|
1519
1958
|
set(selected);
|
|
1520
1959
|
}
|
|
1960
|
+
|
|
1521
1961
|
return actionResult;
|
|
1522
1962
|
},
|
|
1523
1963
|
},
|
|
@@ -1529,8 +1969,11 @@ async function buildForm(paths, design, onSubmit, onUndo, hints = {}) {
|
|
|
1529
1969
|
const omnibox = document.createElement("pds-omnibox");
|
|
1530
1970
|
omnibox.id = id;
|
|
1531
1971
|
omnibox.setAttribute("name", path);
|
|
1532
|
-
omnibox.setAttribute("item-grid", "0 1fr");
|
|
1533
|
-
omnibox.setAttribute(
|
|
1972
|
+
omnibox.setAttribute("item-grid", "0 1fr 0");
|
|
1973
|
+
omnibox.setAttribute(
|
|
1974
|
+
"placeholder",
|
|
1975
|
+
attrs?.placeholder || "Select a font family"
|
|
1976
|
+
);
|
|
1534
1977
|
omnibox.value = value ?? "";
|
|
1535
1978
|
omnibox.settings = {
|
|
1536
1979
|
...fontFamilyOmniboxSettings,
|
|
@@ -1542,161 +1985,691 @@ async function buildForm(paths, design, onSubmit, onUndo, hints = {}) {
|
|
|
1542
1985
|
omnibox.addEventListener("change", (event) => {
|
|
1543
1986
|
set(event?.target?.value ?? omnibox.value ?? "");
|
|
1544
1987
|
});
|
|
1988
|
+
omnibox.addEventListener("result-selected", (event) => {
|
|
1989
|
+
const selected = resolveSelectedValue(event?.detail, undefined, event);
|
|
1990
|
+
if (!selected) return;
|
|
1991
|
+
omnibox.value = selected;
|
|
1992
|
+
set(selected);
|
|
1993
|
+
});
|
|
1545
1994
|
return omnibox;
|
|
1546
1995
|
}
|
|
1547
1996
|
);
|
|
1997
|
+
|
|
1548
1998
|
form.addEventListener("pw:submit", onSubmit);
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
setValueAtPath(values, path.split("."), normalized);
|
|
1554
|
-
}
|
|
1555
|
-
});
|
|
1556
|
-
Object.entries(hints || {}).forEach(([path, hintValue]) => {
|
|
1557
|
-
const segments = path.split(".");
|
|
1558
|
-
const currentValue = getValueAtPath(values, segments);
|
|
1559
|
-
if (currentValue === undefined || currentValue === null) {
|
|
1560
|
-
setValueAtPath(values, segments, hintValue);
|
|
1561
|
-
}
|
|
1562
|
-
});
|
|
1563
|
-
setFormSchemas(form, schema, uiSchema, values);
|
|
1999
|
+
if (typeof normalizeFlatValues === "function") {
|
|
2000
|
+
form._normalizeFlatValues = normalizeFlatValues;
|
|
2001
|
+
}
|
|
2002
|
+
setFormSchemas(form, schema, uiSchema, values || {});
|
|
1564
2003
|
|
|
1565
|
-
// Apply button (will trigger form submit programmatically)
|
|
1566
2004
|
const applyBtn = document.createElement("button");
|
|
1567
2005
|
applyBtn.className = "btn-primary btn-sm";
|
|
1568
2006
|
applyBtn.type = "button";
|
|
1569
2007
|
applyBtn.textContent = "Apply";
|
|
1570
2008
|
applyBtn.addEventListener("click", async () => {
|
|
1571
|
-
// Manually trigger pw:submit event for pds-form
|
|
1572
2009
|
if (typeof form.getValuesFlat === "function") {
|
|
1573
|
-
// Wait for form to be ready if it's still loading
|
|
1574
2010
|
if (!customElements.get("pds-form")) {
|
|
1575
2011
|
await customElements.whenDefined("pds-form");
|
|
1576
2012
|
}
|
|
1577
|
-
|
|
1578
|
-
const flatValues =
|
|
2013
|
+
|
|
2014
|
+
const flatValues =
|
|
2015
|
+
typeof form._normalizeFlatValues === "function"
|
|
2016
|
+
? form._normalizeFlatValues(form.getValuesFlat())
|
|
2017
|
+
: form.getValuesFlat();
|
|
1579
2018
|
const event = new CustomEvent("pw:submit", {
|
|
1580
2019
|
detail: {
|
|
1581
2020
|
json: flatValues,
|
|
1582
2021
|
formData: new FormData(),
|
|
1583
2022
|
valid: true,
|
|
1584
|
-
issues: []
|
|
2023
|
+
issues: [],
|
|
1585
2024
|
},
|
|
1586
2025
|
bubbles: true,
|
|
1587
|
-
cancelable: true
|
|
2026
|
+
cancelable: true,
|
|
1588
2027
|
});
|
|
1589
2028
|
form.dispatchEvent(event);
|
|
1590
2029
|
}
|
|
1591
2030
|
});
|
|
1592
2031
|
|
|
1593
|
-
// Undo button
|
|
1594
2032
|
const undoBtn = document.createElement("button");
|
|
1595
|
-
undoBtn.className = "btn-secondary btn-sm";
|
|
2033
|
+
undoBtn.className = "btn-secondary btn-sm icon-only";
|
|
1596
2034
|
undoBtn.type = "button";
|
|
1597
|
-
undoBtn.
|
|
2035
|
+
undoBtn.setAttribute("aria-label", "Undo");
|
|
2036
|
+
undoBtn.setAttribute("title", "Undo");
|
|
2037
|
+
const undoIcon = document.createElement("pds-icon");
|
|
2038
|
+
undoIcon.setAttribute("icon", "arrow-counter-clockwise");
|
|
2039
|
+
undoIcon.setAttribute("size", "sm");
|
|
2040
|
+
undoBtn.appendChild(undoIcon);
|
|
1598
2041
|
undoBtn.addEventListener("click", onUndo);
|
|
1599
2042
|
|
|
1600
2043
|
return { form, applyBtn, undoBtn };
|
|
1601
2044
|
}
|
|
1602
2045
|
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
this._activeDropdown = null;
|
|
1612
|
-
this._holdOpen = false;
|
|
1613
|
-
this._closeTimer = null;
|
|
1614
|
-
this._drawer = null;
|
|
1615
|
-
this._selectors = null;
|
|
1616
|
-
this._lastPointer = null;
|
|
1617
|
-
this._boundDocKeydown = this._handleDocumentKeydown.bind(this);
|
|
1618
|
-
this._connected = false;
|
|
1619
|
-
this._undoStack = [];
|
|
1620
|
-
this._dropdownMenuOpen = false;
|
|
1621
|
-
this._dropdownObserver = null;
|
|
2046
|
+
async function buildForm(paths, design, onSubmit, onUndo, hints = {}) {
|
|
2047
|
+
const quickPayload = buildQuickConfigPayload(paths, design, hints);
|
|
2048
|
+
const schema = quickPayload?.schema;
|
|
2049
|
+
const uiSchema = quickPayload?.uiSchema;
|
|
2050
|
+
const values = quickPayload?.values;
|
|
2051
|
+
|
|
2052
|
+
if (!schema || !uiSchema) {
|
|
2053
|
+
throw new Error("Central config form metadata is unavailable for quick edit");
|
|
1622
2054
|
}
|
|
1623
2055
|
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
2056
|
+
return createConfiguredForm({
|
|
2057
|
+
schema,
|
|
2058
|
+
uiSchema,
|
|
2059
|
+
values: values || {},
|
|
2060
|
+
onSubmit,
|
|
2061
|
+
onUndo,
|
|
2062
|
+
formOptions: {
|
|
2063
|
+
layouts: {
|
|
2064
|
+
arrays: "compact",
|
|
2065
|
+
},
|
|
2066
|
+
enhancements: {
|
|
2067
|
+
rangeOutput: true,
|
|
2068
|
+
},
|
|
2069
|
+
},
|
|
2070
|
+
});
|
|
2071
|
+
}
|
|
1632
2072
|
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
document.addEventListener("mouseout", this._boundMouseOut, true);
|
|
1637
|
-
document.addEventListener("mousemove", this._boundMouseMove, true);
|
|
2073
|
+
function getConfigFormPayloadFromMetadata(design) {
|
|
2074
|
+
if (typeof PDS?.buildConfigFormSchema === "function") {
|
|
2075
|
+
return PDS.buildConfigFormSchema(design);
|
|
1638
2076
|
}
|
|
1639
2077
|
|
|
1640
|
-
|
|
1641
|
-
|
|
2078
|
+
const payload = PDS?.configFormSchema;
|
|
2079
|
+
if (payload && payload.schema && payload.uiSchema) {
|
|
2080
|
+
return {
|
|
2081
|
+
schema: payload.schema,
|
|
2082
|
+
uiSchema: payload.uiSchema,
|
|
2083
|
+
values: shallowClone(design || payload.values || {}),
|
|
2084
|
+
metadata: payload.metadata || {},
|
|
2085
|
+
};
|
|
1642
2086
|
}
|
|
1643
2087
|
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
document.removeEventListener("mouseover", this._boundMouseOver, true);
|
|
1647
|
-
document.removeEventListener("mouseout", this._boundMouseOut, true);
|
|
1648
|
-
document.removeEventListener("mousemove", this._boundMouseMove, true);
|
|
1649
|
-
}
|
|
1650
|
-
this._removeRepositionListeners();
|
|
1651
|
-
this._clearCloseTimer();
|
|
1652
|
-
this._removeActiveUI();
|
|
1653
|
-
this._connected = false;
|
|
1654
|
-
if (PdsLiveEdit._activeInstance === this) {
|
|
1655
|
-
PdsLiveEdit._activeInstance = null;
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
2088
|
+
return null;
|
|
2089
|
+
}
|
|
1658
2090
|
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
const isOverDropdown = path.some(node => node === this._activeDropdown);
|
|
1666
|
-
if (isOverDropdown) {
|
|
1667
|
-
this._clearCloseTimer();
|
|
1668
|
-
return;
|
|
1669
|
-
}
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1672
|
-
const target = this._findEditableTarget(event.target);
|
|
1673
|
-
|
|
1674
|
-
// If hovering over the same active target, just clear timer
|
|
1675
|
-
if (target && target === this._activeTarget) {
|
|
1676
|
-
this._clearCloseTimer();
|
|
1677
|
-
return;
|
|
1678
|
-
}
|
|
1679
|
-
|
|
1680
|
-
// If hovering over a new target, show its editor
|
|
1681
|
-
if (target && target !== this._activeTarget) {
|
|
1682
|
-
this._removeActiveUI();
|
|
1683
|
-
this._showForTarget(target);
|
|
2091
|
+
function deepClone(value) {
|
|
2092
|
+
if (typeof structuredClone === "function") {
|
|
2093
|
+
try {
|
|
2094
|
+
return structuredClone(value);
|
|
2095
|
+
} catch (e) {
|
|
2096
|
+
// Fall through to JSON clone
|
|
1684
2097
|
}
|
|
1685
2098
|
}
|
|
2099
|
+
return JSON.parse(JSON.stringify(value));
|
|
2100
|
+
}
|
|
1686
2101
|
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
}
|
|
2102
|
+
function withThemeContextValues(values) {
|
|
2103
|
+
const nextValues = shallowClone(values || {});
|
|
2104
|
+
nextValues[FORM_THEME_CONTEXT_FIELD] = getActiveTheme().value;
|
|
2105
|
+
return nextValues;
|
|
2106
|
+
}
|
|
1693
2107
|
|
|
1694
|
-
|
|
2108
|
+
function mergeVisibleWhenCondition(existingCondition, conditionToAdd) {
|
|
2109
|
+
if (!existingCondition) return deepClone(conditionToAdd);
|
|
2110
|
+
if (
|
|
2111
|
+
existingCondition &&
|
|
2112
|
+
typeof existingCondition === "object" &&
|
|
2113
|
+
Array.isArray(existingCondition.$and)
|
|
2114
|
+
) {
|
|
2115
|
+
return {
|
|
2116
|
+
...deepClone(existingCondition),
|
|
2117
|
+
$and: [...existingCondition.$and.map((entry) => deepClone(entry)), deepClone(conditionToAdd)],
|
|
2118
|
+
};
|
|
2119
|
+
}
|
|
2120
|
+
return {
|
|
2121
|
+
$and: [deepClone(existingCondition), deepClone(conditionToAdd)],
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
function collectSchemaNodeMap(schemaNode, pointer = "", out = new Map()) {
|
|
2126
|
+
if (!schemaNode || typeof schemaNode !== "object") return out;
|
|
2127
|
+
if (pointer) {
|
|
2128
|
+
out.set(pointer, schemaNode);
|
|
2129
|
+
}
|
|
2130
|
+
if (schemaNode.type === "object" && schemaNode.properties && typeof schemaNode.properties === "object") {
|
|
2131
|
+
Object.entries(schemaNode.properties).forEach(([key, childNode]) => {
|
|
2132
|
+
collectSchemaNodeMap(childNode, `${pointer}/${key}`, out);
|
|
2133
|
+
});
|
|
2134
|
+
}
|
|
2135
|
+
return out;
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
function applyThemeVisibilityConditions(schema, uiSchema) {
|
|
2139
|
+
if (!schema || typeof schema !== "object") {
|
|
2140
|
+
return uiSchema && typeof uiSchema === "object" ? deepClone(uiSchema) : {};
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
const conditionedUi = uiSchema && typeof uiSchema === "object" ? deepClone(uiSchema) : {};
|
|
2144
|
+
const schemaNodeMap = collectSchemaNodeMap(schema);
|
|
2145
|
+
|
|
2146
|
+
const darkCondition = { [FORM_THEME_CONTEXT_POINTER]: "dark" };
|
|
2147
|
+
const lightCondition = { [FORM_THEME_CONTEXT_POINTER]: { $ne: "dark" } };
|
|
2148
|
+
|
|
2149
|
+
const ensureCondition = (pointer, condition) => {
|
|
2150
|
+
if (!pointer || pointer === FORM_THEME_CONTEXT_POINTER) return;
|
|
2151
|
+
const current = conditionedUi[pointer] && typeof conditionedUi[pointer] === "object"
|
|
2152
|
+
? conditionedUi[pointer]
|
|
2153
|
+
: {};
|
|
2154
|
+
conditionedUi[pointer] = {
|
|
2155
|
+
...current,
|
|
2156
|
+
"ui:visibleWhen": mergeVisibleWhenCondition(current["ui:visibleWhen"], condition),
|
|
2157
|
+
};
|
|
2158
|
+
};
|
|
2159
|
+
|
|
2160
|
+
schemaNodeMap.forEach((node, pointer) => {
|
|
2161
|
+
if (!pointer.includes("/darkMode") || pointer === FORM_THEME_CONTEXT_POINTER) return;
|
|
2162
|
+
|
|
2163
|
+
ensureCondition(pointer, darkCondition);
|
|
2164
|
+
|
|
2165
|
+
const isDarkLeaf = !(node?.type === "object" && node?.properties);
|
|
2166
|
+
if (!isDarkLeaf) return;
|
|
2167
|
+
|
|
2168
|
+
const lightPointer = pointer.replace("/darkMode/", "/");
|
|
2169
|
+
const lightNode = schemaNodeMap.get(lightPointer);
|
|
2170
|
+
const isLightLeaf = !!lightNode && !(lightNode?.type === "object" && lightNode?.properties);
|
|
2171
|
+
if (isLightLeaf) {
|
|
2172
|
+
ensureCondition(lightPointer, lightCondition);
|
|
2173
|
+
}
|
|
2174
|
+
});
|
|
2175
|
+
|
|
2176
|
+
conditionedUi[FORM_THEME_CONTEXT_POINTER] = {
|
|
2177
|
+
...(conditionedUi[FORM_THEME_CONTEXT_POINTER] || {}),
|
|
2178
|
+
"ui:hidden": true,
|
|
2179
|
+
};
|
|
2180
|
+
|
|
2181
|
+
return conditionedUi;
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
function withThemeConditionalSchema(schema, uiSchema) {
|
|
2185
|
+
const baseSchema = deepClone(schema || { type: "object", properties: {} });
|
|
2186
|
+
if (!baseSchema.properties || typeof baseSchema.properties !== "object") {
|
|
2187
|
+
baseSchema.properties = {};
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
baseSchema.properties[FORM_THEME_CONTEXT_FIELD] = {
|
|
2191
|
+
type: "string",
|
|
2192
|
+
oneOf: [
|
|
2193
|
+
{ const: "light", title: "Light" },
|
|
2194
|
+
{ const: "dark", title: "Dark" },
|
|
2195
|
+
],
|
|
2196
|
+
};
|
|
2197
|
+
|
|
2198
|
+
const conditionedUi = applyThemeVisibilityConditions(baseSchema, uiSchema);
|
|
2199
|
+
return { schema: baseSchema, uiSchema: conditionedUi };
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
function shouldKeepPathForSelection(selectedPaths, path) {
|
|
2203
|
+
if (!path) return true;
|
|
2204
|
+
return selectedPaths.some((selectedPath) => {
|
|
2205
|
+
if (selectedPath === path) return true;
|
|
2206
|
+
return selectedPath.startsWith(`${path}.`);
|
|
2207
|
+
});
|
|
2208
|
+
}
|
|
2209
|
+
|
|
2210
|
+
function pruneSchemaForPaths(node, selectedPaths, path = "") {
|
|
2211
|
+
if (!node || typeof node !== "object") return node;
|
|
2212
|
+
if (!isObjectSchemaNode(node)) return deepClone(node);
|
|
2213
|
+
|
|
2214
|
+
if (path && !shouldKeepPathForSelection(selectedPaths, path)) {
|
|
2215
|
+
return null;
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
const properties = {};
|
|
2219
|
+
Object.entries(node.properties || {}).forEach(([key, childNode]) => {
|
|
2220
|
+
const childPath = path ? `${path}.${key}` : key;
|
|
2221
|
+
if (!shouldKeepPathForSelection(selectedPaths, childPath)) return;
|
|
2222
|
+
const prunedChild = pruneSchemaForPaths(childNode, selectedPaths, childPath);
|
|
2223
|
+
if (prunedChild) {
|
|
2224
|
+
properties[key] = prunedChild;
|
|
2225
|
+
}
|
|
2226
|
+
});
|
|
2227
|
+
|
|
2228
|
+
if (!Object.keys(properties).length) return null;
|
|
2229
|
+
|
|
2230
|
+
const clonedNode = deepClone(node);
|
|
2231
|
+
clonedNode.properties = properties;
|
|
2232
|
+
if (Array.isArray(clonedNode.required)) {
|
|
2233
|
+
clonedNode.required = clonedNode.required.filter((key) =>
|
|
2234
|
+
Object.prototype.hasOwnProperty.call(properties, key)
|
|
2235
|
+
);
|
|
2236
|
+
}
|
|
2237
|
+
return clonedNode;
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
function uiPointerToPath(pointer) {
|
|
2241
|
+
if (!pointer || pointer === "/") return "";
|
|
2242
|
+
return pointer
|
|
2243
|
+
.replace(/^\//, "")
|
|
2244
|
+
.split("/")
|
|
2245
|
+
.filter(Boolean)
|
|
2246
|
+
.join(".");
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
function filterUiSchemaForPaths(uiSchema, selectedPaths) {
|
|
2250
|
+
if (!uiSchema || typeof uiSchema !== "object") return {};
|
|
2251
|
+
const filtered = {};
|
|
2252
|
+
Object.entries(uiSchema).forEach(([pointer, value]) => {
|
|
2253
|
+
const path = uiPointerToPath(pointer);
|
|
2254
|
+
if (!path || shouldKeepPathForSelection(selectedPaths, path)) {
|
|
2255
|
+
filtered[pointer] = deepClone(value);
|
|
2256
|
+
}
|
|
2257
|
+
});
|
|
2258
|
+
return filtered;
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
function buildValuesForPaths(valuesSource, selectedPaths, hints = {}) {
|
|
2262
|
+
const values = {};
|
|
2263
|
+
selectedPaths.forEach((path) => {
|
|
2264
|
+
const segments = path.split(".");
|
|
2265
|
+
let value = getValueAtPath(valuesSource, segments);
|
|
2266
|
+
if ((value === undefined || value === null) && hints[path] !== undefined) {
|
|
2267
|
+
value = hints[path];
|
|
2268
|
+
}
|
|
2269
|
+
if (isColorPath(path)) {
|
|
2270
|
+
const resolvedColorValue = resolveColorValueForPath(path, value, hints[path]);
|
|
2271
|
+
if (resolvedColorValue) {
|
|
2272
|
+
value = resolvedColorValue;
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
if (value !== undefined) {
|
|
2276
|
+
setValueAtPath(values, segments, deepClone(value));
|
|
2277
|
+
}
|
|
2278
|
+
});
|
|
2279
|
+
return values;
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
function buildQuickConfigPayload(paths, design, hints = {}) {
|
|
2283
|
+
const payload = getConfigFormPayloadFromMetadata(design);
|
|
2284
|
+
if (!payload?.schema || !payload?.uiSchema) return null;
|
|
2285
|
+
|
|
2286
|
+
const selectedPaths = normalizePaths(paths);
|
|
2287
|
+
if (!selectedPaths.length) return null;
|
|
2288
|
+
|
|
2289
|
+
const schema = pruneSchemaForPaths(payload.schema, selectedPaths, "");
|
|
2290
|
+
if (!schema) return null;
|
|
2291
|
+
|
|
2292
|
+
const uiSchema = filterUiSchemaForPaths(payload.uiSchema, selectedPaths);
|
|
2293
|
+
const valuesSource =
|
|
2294
|
+
payload?.values && typeof payload.values === "object"
|
|
2295
|
+
? payload.values
|
|
2296
|
+
: shallowClone(design || {});
|
|
2297
|
+
const values = buildValuesForPaths(valuesSource || {}, selectedPaths, hints);
|
|
2298
|
+
|
|
2299
|
+
return { schema, uiSchema, values };
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
const FULL_CONFIG_GROUPS_KEY = "__groups";
|
|
2303
|
+
|
|
2304
|
+
function isObjectSchemaNode(node) {
|
|
2305
|
+
return !!(node && typeof node === "object" && node.type === "object" && node.properties);
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
function buildGroupedFullConfigPayload(payload, design) {
|
|
2309
|
+
const values =
|
|
2310
|
+
payload?.values && typeof payload.values === "object"
|
|
2311
|
+
? payload.values
|
|
2312
|
+
: shallowClone(design || {});
|
|
2313
|
+
|
|
2314
|
+
if (!payload?.schema || !payload?.uiSchema || !isObjectSchemaNode(payload.schema)) {
|
|
2315
|
+
return {
|
|
2316
|
+
schema: payload?.schema,
|
|
2317
|
+
uiSchema: payload?.uiSchema,
|
|
2318
|
+
values,
|
|
2319
|
+
normalizeFlatValues: null,
|
|
2320
|
+
};
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2323
|
+
const rootProperties = payload.schema.properties || {};
|
|
2324
|
+
const groupedKeys = [];
|
|
2325
|
+
const scalarKeys = [];
|
|
2326
|
+
|
|
2327
|
+
Object.entries(rootProperties).forEach(([key, schemaNode]) => {
|
|
2328
|
+
if (isObjectSchemaNode(schemaNode)) {
|
|
2329
|
+
groupedKeys.push(key);
|
|
2330
|
+
return;
|
|
2331
|
+
}
|
|
2332
|
+
scalarKeys.push(key);
|
|
2333
|
+
});
|
|
2334
|
+
|
|
2335
|
+
if (!groupedKeys.length || !scalarKeys.length) {
|
|
2336
|
+
return {
|
|
2337
|
+
schema: payload.schema,
|
|
2338
|
+
uiSchema: payload.uiSchema,
|
|
2339
|
+
values,
|
|
2340
|
+
normalizeFlatValues: null,
|
|
2341
|
+
};
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
const transformedSchema = {
|
|
2345
|
+
...payload.schema,
|
|
2346
|
+
properties: {
|
|
2347
|
+
...Object.fromEntries(scalarKeys.map((key) => [key, rootProperties[key]])),
|
|
2348
|
+
[FULL_CONFIG_GROUPS_KEY]: {
|
|
2349
|
+
type: "object",
|
|
2350
|
+
title: "Design Groups",
|
|
2351
|
+
properties: Object.fromEntries(
|
|
2352
|
+
groupedKeys.map((key) => [key, rootProperties[key]])
|
|
2353
|
+
),
|
|
2354
|
+
},
|
|
2355
|
+
},
|
|
2356
|
+
};
|
|
2357
|
+
|
|
2358
|
+
const transformedValues = {
|
|
2359
|
+
...Object.fromEntries(scalarKeys.map((key) => [key, values?.[key]])),
|
|
2360
|
+
[FULL_CONFIG_GROUPS_KEY]: Object.fromEntries(
|
|
2361
|
+
groupedKeys.map((key) => [key, values?.[key]])
|
|
2362
|
+
),
|
|
2363
|
+
};
|
|
2364
|
+
|
|
2365
|
+
const transformedUiSchema = { ...(payload.uiSchema || {}) };
|
|
2366
|
+
const addGroupPrefix = (path = "") => `/${FULL_CONFIG_GROUPS_KEY}${path}`;
|
|
2367
|
+
|
|
2368
|
+
groupedKeys.forEach((key) => {
|
|
2369
|
+
const originalPath = `/${key}`;
|
|
2370
|
+
|
|
2371
|
+
if (Object.prototype.hasOwnProperty.call(transformedUiSchema, originalPath)) {
|
|
2372
|
+
transformedUiSchema[addGroupPrefix(originalPath)] = transformedUiSchema[originalPath];
|
|
2373
|
+
delete transformedUiSchema[originalPath];
|
|
2374
|
+
}
|
|
2375
|
+
|
|
2376
|
+
Object.keys(transformedUiSchema).forEach((path) => {
|
|
2377
|
+
if (!path.startsWith(`${originalPath}/`)) return;
|
|
2378
|
+
transformedUiSchema[addGroupPrefix(path)] = transformedUiSchema[path];
|
|
2379
|
+
delete transformedUiSchema[path];
|
|
2380
|
+
});
|
|
2381
|
+
});
|
|
2382
|
+
|
|
2383
|
+
transformedUiSchema[`/${FULL_CONFIG_GROUPS_KEY}`] = {
|
|
2384
|
+
"ui:layout": "accordion",
|
|
2385
|
+
"ui:layoutOptions": { openFirst: false },
|
|
2386
|
+
};
|
|
2387
|
+
|
|
2388
|
+
const normalizeFlatValues = (flatValues = {}) => {
|
|
2389
|
+
const normalized = {};
|
|
2390
|
+
const groupPointerPrefix = `/${FULL_CONFIG_GROUPS_KEY}/`;
|
|
2391
|
+
const groupDotPrefix = `${FULL_CONFIG_GROUPS_KEY}.`;
|
|
2392
|
+
Object.entries(flatValues || {}).forEach(([path, value]) => {
|
|
2393
|
+
const inputPath = String(path || "");
|
|
2394
|
+
if (!inputPath) return;
|
|
2395
|
+
if (inputPath === FULL_CONFIG_GROUPS_KEY || inputPath === `/${FULL_CONFIG_GROUPS_KEY}`) {
|
|
2396
|
+
return;
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2399
|
+
if (inputPath.startsWith(groupPointerPrefix)) {
|
|
2400
|
+
normalized[`/${inputPath.slice(groupPointerPrefix.length)}`] = value;
|
|
2401
|
+
return;
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
if (inputPath.startsWith(groupDotPrefix)) {
|
|
2405
|
+
normalized[inputPath.slice(groupDotPrefix.length)] = value;
|
|
2406
|
+
return;
|
|
2407
|
+
}
|
|
2408
|
+
|
|
2409
|
+
normalized[inputPath] = value;
|
|
2410
|
+
});
|
|
2411
|
+
return normalized;
|
|
2412
|
+
};
|
|
2413
|
+
|
|
2414
|
+
return {
|
|
2415
|
+
schema: transformedSchema,
|
|
2416
|
+
uiSchema: transformedUiSchema,
|
|
2417
|
+
values: transformedValues,
|
|
2418
|
+
normalizeFlatValues,
|
|
2419
|
+
};
|
|
2420
|
+
}
|
|
2421
|
+
|
|
2422
|
+
async function buildFullConfigForm(design, onSubmit, onUndo) {
|
|
2423
|
+
const payload = getConfigFormPayloadFromMetadata(design);
|
|
2424
|
+
if (!payload?.schema || !payload?.uiSchema) return null;
|
|
2425
|
+
|
|
2426
|
+
const groupedPayload = buildGroupedFullConfigPayload(payload, design);
|
|
2427
|
+
|
|
2428
|
+
return createConfiguredForm({
|
|
2429
|
+
schema: groupedPayload.schema,
|
|
2430
|
+
uiSchema: groupedPayload.uiSchema,
|
|
2431
|
+
values: groupedPayload.values,
|
|
2432
|
+
onSubmit,
|
|
2433
|
+
onUndo,
|
|
2434
|
+
normalizeFlatValues: groupedPayload.normalizeFlatValues,
|
|
2435
|
+
formOptions: {
|
|
2436
|
+
layouts: {
|
|
2437
|
+
arrays: "compact",
|
|
2438
|
+
},
|
|
2439
|
+
enhancements: {
|
|
2440
|
+
rangeOutput: true,
|
|
2441
|
+
},
|
|
2442
|
+
},
|
|
2443
|
+
});
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2446
|
+
class PdsLiveEdit extends HTMLElement {
|
|
2447
|
+
constructor() {
|
|
2448
|
+
super();
|
|
2449
|
+
this._boundMouseOver = this._handleMouseOver.bind(this);
|
|
2450
|
+
this._boundMouseOut = this._handleMouseOut.bind(this);
|
|
2451
|
+
this._boundMouseMove = this._handleMouseMove.bind(this);
|
|
2452
|
+
this._boundReposition = this._repositionDropdown.bind(this);
|
|
2453
|
+
this._activeTarget = null;
|
|
2454
|
+
this._activeDropdown = null;
|
|
2455
|
+
this._holdOpen = false;
|
|
2456
|
+
this._closeTimer = null;
|
|
2457
|
+
this._drawer = null;
|
|
2458
|
+
this._selectors = null;
|
|
2459
|
+
this._lastPointer = null;
|
|
2460
|
+
this._boundDocKeydown = this._handleDocumentKeydown.bind(this);
|
|
2461
|
+
this._connected = false;
|
|
2462
|
+
this._undoStack = [];
|
|
2463
|
+
this._dropdownMenuOpen = false;
|
|
2464
|
+
this._dropdownObserver = null;
|
|
2465
|
+
this._boundThemeChanged = this._handleThemeChanged.bind(this);
|
|
2466
|
+
this._themeRefreshInFlight = null;
|
|
2467
|
+
this._drawerConfigFormContainer = null;
|
|
2468
|
+
this._drawerConfigFooter = null;
|
|
2469
|
+
this._interactiveEditingEnabled = true;
|
|
2470
|
+
this._interactionListenersAttached = false;
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
connectedCallback() {
|
|
2474
|
+
if (this._connected) return;
|
|
2475
|
+
if (PdsLiveEdit._activeInstance && PdsLiveEdit._activeInstance !== this) {
|
|
2476
|
+
PdsLiveEdit._activeInstance._teardown();
|
|
2477
|
+
}
|
|
2478
|
+
PdsLiveEdit._activeInstance = this;
|
|
2479
|
+
this._connected = true;
|
|
2480
|
+
if (this.hasAttribute(SETTINGS_ONLY_ATTR)) {
|
|
2481
|
+
this._interactiveEditingEnabled = false;
|
|
2482
|
+
}
|
|
2483
|
+
if (PDS && typeof PDS.addEventListener === "function") {
|
|
2484
|
+
PDS.addEventListener("pds:theme:changed", this._boundThemeChanged);
|
|
2485
|
+
}
|
|
2486
|
+
if (this._interactiveEditingEnabled) {
|
|
2487
|
+
this._enableInteractiveEditing();
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
disconnectedCallback() {
|
|
2492
|
+
this._teardown();
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2495
|
+
_teardown() {
|
|
2496
|
+
this._disableInteractiveEditing({ clearUI: true });
|
|
2497
|
+
this._connected = false;
|
|
2498
|
+
if (PDS && typeof PDS.removeEventListener === "function") {
|
|
2499
|
+
PDS.removeEventListener("pds:theme:changed", this._boundThemeChanged);
|
|
2500
|
+
}
|
|
2501
|
+
this._removeRepositionListeners();
|
|
2502
|
+
this._clearCloseTimer();
|
|
2503
|
+
this._removeActiveUI();
|
|
2504
|
+
this._drawerConfigFormContainer = null;
|
|
2505
|
+
this._drawerConfigFooter = null;
|
|
2506
|
+
if (PdsLiveEdit._activeInstance === this) {
|
|
2507
|
+
PdsLiveEdit._activeInstance = null;
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
_enableInteractiveEditing() {
|
|
2512
|
+
if (!isHoverCapable()) return;
|
|
2513
|
+
ensureStyles();
|
|
2514
|
+
this._selectors = collectSelectors();
|
|
2515
|
+
if (this._interactionListenersAttached) return;
|
|
2516
|
+
document.addEventListener("mouseover", this._boundMouseOver, true);
|
|
2517
|
+
document.addEventListener("mouseout", this._boundMouseOut, true);
|
|
2518
|
+
document.addEventListener("mousemove", this._boundMouseMove, true);
|
|
2519
|
+
this._interactionListenersAttached = true;
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
_disableInteractiveEditing(options = {}) {
|
|
2523
|
+
if (this._interactionListenersAttached) {
|
|
2524
|
+
document.removeEventListener("mouseover", this._boundMouseOver, true);
|
|
2525
|
+
document.removeEventListener("mouseout", this._boundMouseOut, true);
|
|
2526
|
+
document.removeEventListener("mousemove", this._boundMouseMove, true);
|
|
2527
|
+
this._interactionListenersAttached = false;
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2530
|
+
if (options?.clearUI !== false) {
|
|
2531
|
+
this._removeActiveUI();
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2534
|
+
|
|
2535
|
+
setInteractiveEditingEnabled(enabled = true) {
|
|
2536
|
+
const next = Boolean(enabled);
|
|
2537
|
+
this._interactiveEditingEnabled = next;
|
|
2538
|
+
|
|
2539
|
+
if (next) {
|
|
2540
|
+
this.removeAttribute(SETTINGS_ONLY_ATTR);
|
|
2541
|
+
} else {
|
|
2542
|
+
this.setAttribute(SETTINGS_ONLY_ATTR, "true");
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
if (!this._connected) {
|
|
2546
|
+
return next;
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
if (next) {
|
|
2550
|
+
this._enableInteractiveEditing();
|
|
2551
|
+
} else {
|
|
2552
|
+
this._disableInteractiveEditing({ clearUI: true });
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
return next;
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
isInteractiveEditingEnabled() {
|
|
2559
|
+
return Boolean(this._interactiveEditingEnabled);
|
|
2560
|
+
}
|
|
2561
|
+
|
|
2562
|
+
async _handleThemeChanged() {
|
|
2563
|
+
if (this._themeRefreshInFlight) return this._themeRefreshInFlight;
|
|
2564
|
+
this._themeRefreshInFlight = (async () => {
|
|
2565
|
+
try {
|
|
2566
|
+
await this._refreshQuickFormForTheme();
|
|
2567
|
+
await this._refreshDrawerConfigFormForTheme();
|
|
2568
|
+
} finally {
|
|
2569
|
+
this._themeRefreshInFlight = null;
|
|
2570
|
+
}
|
|
2571
|
+
})();
|
|
2572
|
+
return this._themeRefreshInFlight;
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2575
|
+
async _refreshQuickFormForTheme() {
|
|
2576
|
+
if (!this._activeDropdown || !this._activeTarget) return;
|
|
2577
|
+
if (!document.contains(this._activeTarget)) return;
|
|
2578
|
+
|
|
2579
|
+
const formContainer = this._activeDropdown.querySelector('.pds-live-editor-form-container');
|
|
2580
|
+
const footer = this._activeDropdown.querySelector('.pds-live-editor-footer');
|
|
2581
|
+
if (!formContainer || !footer) return;
|
|
2582
|
+
|
|
2583
|
+
const currentDesign = shallowClone(PDS?.currentConfig?.design || {});
|
|
2584
|
+
const quickContext = collectQuickContext(this._activeTarget);
|
|
2585
|
+
const limitedPaths = quickContext.paths.slice(0, QUICK_EDIT_LIMIT);
|
|
2586
|
+
const quickPaths = quickContext.paths;
|
|
2587
|
+
|
|
2588
|
+
await this._renderQuickForm(
|
|
2589
|
+
formContainer,
|
|
2590
|
+
footer,
|
|
2591
|
+
limitedPaths,
|
|
2592
|
+
currentDesign,
|
|
2593
|
+
quickContext.hints,
|
|
2594
|
+
this._activeTarget,
|
|
2595
|
+
quickPaths
|
|
2596
|
+
);
|
|
2597
|
+
}
|
|
2598
|
+
|
|
2599
|
+
async _refreshDrawerConfigFormForTheme() {
|
|
2600
|
+
if (!this._drawer) return;
|
|
2601
|
+
if (!this._drawer.hasAttribute("open")) return;
|
|
2602
|
+
if (!this._drawerConfigFormContainer || !this._drawerConfigFooter) return;
|
|
2603
|
+
|
|
2604
|
+
const fullDesign = shallowClone(PDS?.currentConfig?.design || {});
|
|
2605
|
+
const fullConfigFormResult = await buildFullConfigForm(
|
|
2606
|
+
fullDesign,
|
|
2607
|
+
(event) => this._handleFormSubmit(event, fullConfigFormResult?.form),
|
|
2608
|
+
() => this._handleUndo()
|
|
2609
|
+
);
|
|
2610
|
+
|
|
2611
|
+
this._drawerConfigFormContainer.replaceChildren();
|
|
2612
|
+
this._drawerConfigFooter.replaceChildren();
|
|
2613
|
+
|
|
2614
|
+
if (fullConfigFormResult?.form) {
|
|
2615
|
+
fullConfigFormResult.form._undoBtn = fullConfigFormResult.undoBtn;
|
|
2616
|
+
fullConfigFormResult.undoBtn.disabled = this._undoStack.length === 0;
|
|
2617
|
+
this._drawerConfigFormContainer.appendChild(fullConfigFormResult.form);
|
|
2618
|
+
this._drawerConfigFooter.appendChild(fullConfigFormResult.applyBtn);
|
|
2619
|
+
this._drawerConfigFooter.appendChild(fullConfigFormResult.undoBtn);
|
|
2620
|
+
} else {
|
|
2621
|
+
const unavailable = document.createElement("p");
|
|
2622
|
+
unavailable.className = "text-muted";
|
|
2623
|
+
unavailable.textContent =
|
|
2624
|
+
"Full config metadata is unavailable in this runtime.";
|
|
2625
|
+
this._drawerConfigFormContainer.appendChild(unavailable);
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
|
|
2629
|
+
_handleMouseOver(event) {
|
|
2630
|
+
if (!this._interactiveEditingEnabled) return;
|
|
2631
|
+
if (!event?.target || !(event.target instanceof Element)) return;
|
|
2632
|
+
|
|
2633
|
+
// Check if we're hovering over the dropdown (including Shadow DOM elements)
|
|
2634
|
+
if (this._activeDropdown) {
|
|
2635
|
+
const path = event.composedPath ? event.composedPath() : [event.target];
|
|
2636
|
+
const isOverDropdown = path.some(node => node === this._activeDropdown);
|
|
2637
|
+
if (isOverDropdown) {
|
|
2638
|
+
this._clearCloseTimer();
|
|
2639
|
+
return;
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
const target = this._findEditableTarget(event.target);
|
|
2644
|
+
|
|
2645
|
+
// If hovering over the same active target, just clear timer
|
|
2646
|
+
if (target && target === this._activeTarget) {
|
|
2647
|
+
this._clearCloseTimer();
|
|
2648
|
+
return;
|
|
2649
|
+
}
|
|
2650
|
+
|
|
2651
|
+
// If hovering over a new target, show its editor
|
|
2652
|
+
if (target && target !== this._activeTarget) {
|
|
2653
|
+
this._removeActiveUI();
|
|
2654
|
+
this._showForTarget(target);
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2658
|
+
_handleMouseOut(event) {
|
|
2659
|
+
if (!this._activeTarget) return;
|
|
2660
|
+
|
|
2661
|
+
// Schedule a delayed close - the safe zone logic will determine if we actually close
|
|
2662
|
+
this._scheduleClose();
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
_findEditableTarget(node) {
|
|
1695
2666
|
const tag = node.tagName?.toLowerCase?.();
|
|
1696
2667
|
if (tag && ["html", "head", "meta", "link", "style", "script", "title"].includes(tag)) {
|
|
1697
2668
|
return null;
|
|
1698
2669
|
}
|
|
1699
2670
|
if (!this._selectors?.selector) return null;
|
|
2671
|
+
if (isLiveEditHighlightBlacklisted(node)) return null;
|
|
2672
|
+
if (node.closest("[data-pds-live-edit-ignore]")) return null;
|
|
1700
2673
|
if (node.closest(EDITOR_TAG)) return null;
|
|
1701
2674
|
if (node.closest(`.${DROPDOWN_CLASS}`)) return null;
|
|
1702
2675
|
if (node.closest("pds-drawer")) return null;
|
|
@@ -1709,6 +2682,7 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
1709
2682
|
}
|
|
1710
2683
|
|
|
1711
2684
|
_showForTarget(target) {
|
|
2685
|
+
if (!this._interactiveEditingEnabled) return;
|
|
1712
2686
|
const quickContext = collectQuickContext(target);
|
|
1713
2687
|
const quickPaths = quickContext.paths;
|
|
1714
2688
|
if (!quickPaths.length) return;
|
|
@@ -1753,8 +2727,13 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
1753
2727
|
this._lastPointer = null;
|
|
1754
2728
|
this._dropdownMenuOpen = false;
|
|
1755
2729
|
|
|
1756
|
-
|
|
1757
|
-
|
|
2730
|
+
if (
|
|
2731
|
+
this._connected &&
|
|
2732
|
+
this._interactiveEditingEnabled &&
|
|
2733
|
+
this._interactionListenersAttached
|
|
2734
|
+
) {
|
|
2735
|
+
this._addMouseOverListener();
|
|
2736
|
+
}
|
|
1758
2737
|
}
|
|
1759
2738
|
|
|
1760
2739
|
_addDocumentListeners() {
|
|
@@ -1901,6 +2880,7 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
1901
2880
|
|
|
1902
2881
|
_addMouseOverListener() {
|
|
1903
2882
|
if (typeof document === "undefined") return;
|
|
2883
|
+
if (!this._interactiveEditingEnabled) return;
|
|
1904
2884
|
document.addEventListener("mouseover", this._boundMouseOver, true);
|
|
1905
2885
|
}
|
|
1906
2886
|
|
|
@@ -2017,7 +2997,7 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2017
2997
|
button.appendChild(icon);
|
|
2018
2998
|
|
|
2019
2999
|
const menu = document.createElement("menu");
|
|
2020
|
-
|
|
3000
|
+
const quickItem = document.createElement("div");
|
|
2021
3001
|
quickItem.className = "pds-live-editor-menu";
|
|
2022
3002
|
|
|
2023
3003
|
const header = document.createElement("div");
|
|
@@ -2063,13 +3043,28 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2063
3043
|
container.replaceChildren();
|
|
2064
3044
|
footer.replaceChildren();
|
|
2065
3045
|
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
3046
|
+
let form;
|
|
3047
|
+
let applyBtn;
|
|
3048
|
+
let undoBtn;
|
|
3049
|
+
try {
|
|
3050
|
+
const result = await buildForm(
|
|
3051
|
+
paths,
|
|
3052
|
+
design,
|
|
3053
|
+
(event) => this._handleFormSubmit(event, form),
|
|
3054
|
+
() => this._handleUndo(),
|
|
3055
|
+
hints
|
|
3056
|
+
);
|
|
3057
|
+
form = result.form;
|
|
3058
|
+
applyBtn = result.applyBtn;
|
|
3059
|
+
undoBtn = result.undoBtn;
|
|
3060
|
+
} catch (error) {
|
|
3061
|
+
const fallback = document.createElement("p");
|
|
3062
|
+
fallback.className = "text-muted";
|
|
3063
|
+
fallback.textContent = "Editor form unavailable. Lazy component definition did not complete in time.";
|
|
3064
|
+
container.appendChild(fallback);
|
|
3065
|
+
console.warn("[PDS Live Edit] Failed to render quick form:", error);
|
|
3066
|
+
return;
|
|
3067
|
+
}
|
|
2073
3068
|
|
|
2074
3069
|
// Store reference to undo button for enabling/disabling
|
|
2075
3070
|
form._undoBtn = undoBtn;
|
|
@@ -2095,13 +3090,142 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2095
3090
|
this._openDrawer(target, quickPaths);
|
|
2096
3091
|
this._removeActiveUI();
|
|
2097
3092
|
});
|
|
3093
|
+
|
|
3094
|
+
const quickModeNav = await this._buildQuickModeDropdown();
|
|
2098
3095
|
|
|
2099
3096
|
// Add buttons to footer
|
|
2100
3097
|
footer.appendChild(applyBtn);
|
|
2101
3098
|
footer.appendChild(undoBtn);
|
|
3099
|
+
footer.appendChild(quickModeNav);
|
|
2102
3100
|
footer.appendChild(gearBtn);
|
|
2103
3101
|
}
|
|
2104
3102
|
|
|
3103
|
+
async _buildQuickModeDropdown() {
|
|
3104
|
+
const nav = document.createElement("nav");
|
|
3105
|
+
nav.setAttribute("data-dropdown", "");
|
|
3106
|
+
nav.setAttribute("data-mode", "auto");
|
|
3107
|
+
nav.setAttribute("data-direction", "auto");
|
|
3108
|
+
|
|
3109
|
+
const button = document.createElement("button");
|
|
3110
|
+
button.type = "button";
|
|
3111
|
+
button.className = "btn-outline btn-sm icon-only";
|
|
3112
|
+
button.setAttribute("aria-label", "Quick theme and preset");
|
|
3113
|
+
|
|
3114
|
+
const icon = document.createElement("pds-icon");
|
|
3115
|
+
icon.setAttribute("icon", "palette");
|
|
3116
|
+
icon.setAttribute("size", "sm");
|
|
3117
|
+
button.appendChild(icon);
|
|
3118
|
+
|
|
3119
|
+
const menu = document.createElement("menu");
|
|
3120
|
+
const content = await this._buildQuickModeContent();
|
|
3121
|
+
menu.appendChild(content);
|
|
3122
|
+
nav.append(button, menu);
|
|
3123
|
+
return nav;
|
|
3124
|
+
}
|
|
3125
|
+
|
|
3126
|
+
async _buildQuickModeContent() {
|
|
3127
|
+
const content = document.createElement("div");
|
|
3128
|
+
content.className = "pds-live-editor-menu stack-sm";
|
|
3129
|
+
|
|
3130
|
+
const themeLabel = document.createElement("label");
|
|
3131
|
+
themeLabel.className = "stack-xs";
|
|
3132
|
+
const themeText = document.createElement("span");
|
|
3133
|
+
themeText.textContent = "Theme";
|
|
3134
|
+
const themeToggle = document.createElement("pds-theme");
|
|
3135
|
+
themeLabel.append(themeText, themeToggle);
|
|
3136
|
+
content.appendChild(themeLabel);
|
|
3137
|
+
|
|
3138
|
+
const presetLabel = document.createElement("label");
|
|
3139
|
+
presetLabel.className = "stack-xs";
|
|
3140
|
+
const presetText = document.createElement("span");
|
|
3141
|
+
presetText.textContent = "Preset";
|
|
3142
|
+
presetLabel.appendChild(presetText);
|
|
3143
|
+
|
|
3144
|
+
let presetControlRendered = false;
|
|
3145
|
+
try {
|
|
3146
|
+
await waitForElementDefinition("pds-omnibox");
|
|
3147
|
+
|
|
3148
|
+
const presetOmnibox = document.createElement("pds-omnibox");
|
|
3149
|
+
presetOmnibox.setAttribute("item-grid", "0 1fr 0");
|
|
3150
|
+
presetOmnibox.setAttribute("placeholder", "Search presets...");
|
|
3151
|
+
|
|
3152
|
+
const activePresetId = getActivePresetId();
|
|
3153
|
+
const activePresetName = getPresetNameById(activePresetId);
|
|
3154
|
+
if (activePresetName) {
|
|
3155
|
+
presetOmnibox.value = activePresetName;
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
const omniboxSettingsBuilder =
|
|
3159
|
+
typeof PDS?.buildPresetOmniboxSettings === "function"
|
|
3160
|
+
? PDS.buildPresetOmniboxSettings.bind(PDS)
|
|
3161
|
+
: null;
|
|
3162
|
+
|
|
3163
|
+
if (omniboxSettingsBuilder) {
|
|
3164
|
+
presetOmnibox.settings = omniboxSettingsBuilder({
|
|
3165
|
+
onSelect: async ({ preset, selection }) => {
|
|
3166
|
+
if (selection?.disabled) return selection?.id;
|
|
3167
|
+
const presetId = preset?.id || selection?.id;
|
|
3168
|
+
await applyPresetSelection(presetId);
|
|
3169
|
+
return presetId;
|
|
3170
|
+
},
|
|
3171
|
+
});
|
|
3172
|
+
}
|
|
3173
|
+
|
|
3174
|
+
presetOmnibox.addEventListener("result-selected", (event) => {
|
|
3175
|
+
const selectedText = event?.detail?.text;
|
|
3176
|
+
if (typeof selectedText === "string" && selectedText.trim()) {
|
|
3177
|
+
presetOmnibox.value = selectedText;
|
|
3178
|
+
}
|
|
3179
|
+
});
|
|
3180
|
+
|
|
3181
|
+
presetLabel.appendChild(presetOmnibox);
|
|
3182
|
+
presetControlRendered = true;
|
|
3183
|
+
} catch (error) {
|
|
3184
|
+
console.warn("[PDS Live Edit] Quick preset omnibox unavailable, falling back to select.", error);
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
if (!presetControlRendered) {
|
|
3188
|
+
const presetSelect = document.createElement("select");
|
|
3189
|
+
const presetOptions = getPresetOptions();
|
|
3190
|
+
const activePreset = getActivePresetId();
|
|
3191
|
+
|
|
3192
|
+
presetOptions.forEach((preset) => {
|
|
3193
|
+
const option = document.createElement("option");
|
|
3194
|
+
option.value = preset.id;
|
|
3195
|
+
option.textContent = preset.name;
|
|
3196
|
+
if (String(preset.id) === String(activePreset)) {
|
|
3197
|
+
option.selected = true;
|
|
3198
|
+
}
|
|
3199
|
+
presetSelect.appendChild(option);
|
|
3200
|
+
});
|
|
3201
|
+
|
|
3202
|
+
presetSelect.addEventListener("change", async (event) => {
|
|
3203
|
+
const nextPreset = event.target?.value;
|
|
3204
|
+
await applyPresetSelection(nextPreset);
|
|
3205
|
+
});
|
|
3206
|
+
|
|
3207
|
+
presetLabel.appendChild(presetSelect);
|
|
3208
|
+
}
|
|
3209
|
+
|
|
3210
|
+
content.appendChild(presetLabel);
|
|
3211
|
+
return content;
|
|
3212
|
+
}
|
|
3213
|
+
|
|
3214
|
+
async createSharedQuickModeMenuItem() {
|
|
3215
|
+
const item = document.createElement("li");
|
|
3216
|
+
item.className = "pds-live-shared-quick-mode-item";
|
|
3217
|
+
item.setAttribute("data-pds-live-edit-ignore", "true");
|
|
3218
|
+
|
|
3219
|
+
const quickModeContent = await this._buildQuickModeContent();
|
|
3220
|
+
if (!quickModeContent) {
|
|
3221
|
+
return item;
|
|
3222
|
+
}
|
|
3223
|
+
|
|
3224
|
+
markNodeTreeAsLiveEditIgnored(quickModeContent);
|
|
3225
|
+
item.appendChild(quickModeContent);
|
|
3226
|
+
return item;
|
|
3227
|
+
}
|
|
3228
|
+
|
|
2105
3229
|
async _openDrawer(target, quickPaths) {
|
|
2106
3230
|
if (!this._drawer) {
|
|
2107
3231
|
this._drawer = document.createElement("pds-drawer");
|
|
@@ -2110,6 +3234,8 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2110
3234
|
this.appendChild(this._drawer);
|
|
2111
3235
|
}
|
|
2112
3236
|
|
|
3237
|
+
this._drawer.style.setProperty("--drawer-width", "min(96vw, 44rem)");
|
|
3238
|
+
|
|
2113
3239
|
if (!customElements.get("pds-drawer")) {
|
|
2114
3240
|
await customElements.whenDefined("pds-drawer");
|
|
2115
3241
|
}
|
|
@@ -2121,7 +3247,7 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2121
3247
|
|
|
2122
3248
|
const content = document.createElement("div");
|
|
2123
3249
|
content.setAttribute("slot", "drawer-content");
|
|
2124
|
-
content.className = "
|
|
3250
|
+
content.className = "pds-live-editor-drawer-content";
|
|
2125
3251
|
|
|
2126
3252
|
const presetCard = document.createElement("section");
|
|
2127
3253
|
presetCard.className = "card surface-elevated stack-sm";
|
|
@@ -2137,26 +3263,72 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2137
3263
|
presetText.textContent = "Choose a base style";
|
|
2138
3264
|
presetLabel.appendChild(presetText);
|
|
2139
3265
|
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
3266
|
+
let presetControlRendered = false;
|
|
3267
|
+
try {
|
|
3268
|
+
await waitForElementDefinition("pds-omnibox");
|
|
3269
|
+
|
|
3270
|
+
const presetOmnibox = document.createElement("pds-omnibox");
|
|
3271
|
+
presetOmnibox.setAttribute("item-grid", "0 1fr 0");
|
|
3272
|
+
presetOmnibox.setAttribute("placeholder", "Search presets...");
|
|
2143
3273
|
|
|
2144
|
-
|
|
2145
|
-
const
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
if (String(preset.id) === String(activePreset)) {
|
|
2149
|
-
option.selected = true;
|
|
3274
|
+
const activePresetId = getActivePresetId();
|
|
3275
|
+
const activePresetName = getPresetNameById(activePresetId);
|
|
3276
|
+
if (activePresetName) {
|
|
3277
|
+
presetOmnibox.value = activePresetName;
|
|
2150
3278
|
}
|
|
2151
|
-
presetSelect.appendChild(option);
|
|
2152
|
-
});
|
|
2153
3279
|
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
3280
|
+
const omniboxSettingsBuilder =
|
|
3281
|
+
typeof PDS?.buildPresetOmniboxSettings === "function"
|
|
3282
|
+
? PDS.buildPresetOmniboxSettings.bind(PDS)
|
|
3283
|
+
: null;
|
|
3284
|
+
|
|
3285
|
+
if (omniboxSettingsBuilder) {
|
|
3286
|
+
presetOmnibox.settings = omniboxSettingsBuilder({
|
|
3287
|
+
onSelect: async ({ preset, selection }) => {
|
|
3288
|
+
if (selection?.disabled) return selection?.id;
|
|
3289
|
+
const presetId = preset?.id || selection?.id;
|
|
3290
|
+
await applyPresetSelection(presetId);
|
|
3291
|
+
return presetId;
|
|
3292
|
+
},
|
|
3293
|
+
});
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3296
|
+
presetOmnibox.addEventListener("result-selected", (event) => {
|
|
3297
|
+
const selectedText = event?.detail?.text;
|
|
3298
|
+
if (typeof selectedText === "string" && selectedText.trim()) {
|
|
3299
|
+
presetOmnibox.value = selectedText;
|
|
3300
|
+
}
|
|
3301
|
+
});
|
|
3302
|
+
|
|
3303
|
+
presetLabel.appendChild(presetOmnibox);
|
|
3304
|
+
presetControlRendered = true;
|
|
3305
|
+
} catch (error) {
|
|
3306
|
+
console.warn("[PDS Live Edit] Preset omnibox unavailable, falling back to select.", error);
|
|
3307
|
+
}
|
|
3308
|
+
|
|
3309
|
+
if (!presetControlRendered) {
|
|
3310
|
+
const presetSelect = document.createElement("select");
|
|
3311
|
+
const presetOptions = getPresetOptions();
|
|
3312
|
+
const activePreset = getActivePresetId();
|
|
3313
|
+
|
|
3314
|
+
presetOptions.forEach((preset) => {
|
|
3315
|
+
const option = document.createElement("option");
|
|
3316
|
+
option.value = preset.id;
|
|
3317
|
+
option.textContent = preset.name;
|
|
3318
|
+
if (String(preset.id) === String(activePreset)) {
|
|
3319
|
+
option.selected = true;
|
|
3320
|
+
}
|
|
3321
|
+
presetSelect.appendChild(option);
|
|
3322
|
+
});
|
|
3323
|
+
|
|
3324
|
+
presetSelect.addEventListener("change", async (event) => {
|
|
3325
|
+
const nextPreset = event.target?.value;
|
|
3326
|
+
await applyPresetSelection(nextPreset);
|
|
3327
|
+
});
|
|
3328
|
+
|
|
3329
|
+
presetLabel.appendChild(presetSelect);
|
|
3330
|
+
}
|
|
2158
3331
|
|
|
2159
|
-
presetLabel.appendChild(presetSelect);
|
|
2160
3332
|
presetCard.appendChild(presetLabel);
|
|
2161
3333
|
|
|
2162
3334
|
const themeCard = document.createElement("section");
|
|
@@ -2169,6 +3341,84 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2169
3341
|
const themeToggle = document.createElement("pds-theme");
|
|
2170
3342
|
themeCard.appendChild(themeToggle);
|
|
2171
3343
|
|
|
3344
|
+
const configCard = document.createElement("section");
|
|
3345
|
+
configCard.className = "card surface-elevated stack-sm";
|
|
3346
|
+
|
|
3347
|
+
const configTitle = document.createElement("h4");
|
|
3348
|
+
configTitle.textContent = "Configuration";
|
|
3349
|
+
configCard.appendChild(configTitle);
|
|
3350
|
+
|
|
3351
|
+
const configDescription = document.createElement("p");
|
|
3352
|
+
configDescription.className = "text-muted";
|
|
3353
|
+
configDescription.textContent =
|
|
3354
|
+
"Edit the full design config generated from PDS metadata.";
|
|
3355
|
+
configCard.appendChild(configDescription);
|
|
3356
|
+
|
|
3357
|
+
const configFormContainer = document.createElement("div");
|
|
3358
|
+
configFormContainer.className = "stack-sm";
|
|
3359
|
+
configCard.appendChild(configFormContainer);
|
|
3360
|
+
|
|
3361
|
+
const configFooter = document.createElement("div");
|
|
3362
|
+
configFooter.className = "flex gap-sm";
|
|
3363
|
+
configCard.appendChild(configFooter);
|
|
3364
|
+
this._drawerConfigFormContainer = configFormContainer;
|
|
3365
|
+
this._drawerConfigFooter = configFooter;
|
|
3366
|
+
|
|
3367
|
+
const fullDesign = shallowClone(PDS?.currentConfig?.design || {});
|
|
3368
|
+
const fullConfigFormResult = await buildFullConfigForm(
|
|
3369
|
+
fullDesign,
|
|
3370
|
+
(event) => this._handleFormSubmit(event, fullConfigFormResult?.form),
|
|
3371
|
+
() => this._handleUndo()
|
|
3372
|
+
);
|
|
3373
|
+
|
|
3374
|
+
if (fullConfigFormResult?.form) {
|
|
3375
|
+
fullConfigFormResult.form._undoBtn = fullConfigFormResult.undoBtn;
|
|
3376
|
+
fullConfigFormResult.undoBtn.disabled = this._undoStack.length === 0;
|
|
3377
|
+
configFormContainer.appendChild(fullConfigFormResult.form);
|
|
3378
|
+
configFooter.appendChild(fullConfigFormResult.applyBtn);
|
|
3379
|
+
configFooter.appendChild(fullConfigFormResult.undoBtn);
|
|
3380
|
+
} else {
|
|
3381
|
+
const unavailable = document.createElement("p");
|
|
3382
|
+
unavailable.className = "text-muted";
|
|
3383
|
+
unavailable.textContent =
|
|
3384
|
+
"Full config metadata is unavailable in this runtime.";
|
|
3385
|
+
configFormContainer.appendChild(unavailable);
|
|
3386
|
+
}
|
|
3387
|
+
|
|
3388
|
+
const templateCard = document.createElement("section");
|
|
3389
|
+
templateCard.className = "card surface-elevated stack-sm";
|
|
3390
|
+
|
|
3391
|
+
const templateTitle = document.createElement("h4");
|
|
3392
|
+
templateTitle.textContent = "Canvas Templates";
|
|
3393
|
+
templateCard.appendChild(templateTitle);
|
|
3394
|
+
|
|
3395
|
+
const templateCanvas = document.createElement("pds-live-template-canvas");
|
|
3396
|
+
templateCanvas.addEventListener("pds:live-template:inject", async (event) => {
|
|
3397
|
+
await this._applyImportResult(event?.detail?.result, { injectTemplate: true });
|
|
3398
|
+
});
|
|
3399
|
+
templateCard.appendChild(templateCanvas);
|
|
3400
|
+
|
|
3401
|
+
const importCard = document.createElement("section");
|
|
3402
|
+
importCard.className = "card surface-elevated stack-sm";
|
|
3403
|
+
|
|
3404
|
+
const importTitle = document.createElement("h4");
|
|
3405
|
+
importTitle.textContent = "Import & Convert";
|
|
3406
|
+
importCard.appendChild(importTitle);
|
|
3407
|
+
|
|
3408
|
+
const importer = document.createElement("pds-live-importer");
|
|
3409
|
+
|
|
3410
|
+
importer.addEventListener("pds:live-import:result", async (event) => {
|
|
3411
|
+
const result = event?.detail?.result;
|
|
3412
|
+
if (!result) return;
|
|
3413
|
+
await this._applyImportResult(result, {
|
|
3414
|
+
injectTemplate: true,
|
|
3415
|
+
importMode: event?.detail?.importMode,
|
|
3416
|
+
});
|
|
3417
|
+
this._endLiveEditSessionAfterImport();
|
|
3418
|
+
});
|
|
3419
|
+
|
|
3420
|
+
importCard.append(importer);
|
|
3421
|
+
|
|
2172
3422
|
const exportCard = document.createElement("section");
|
|
2173
3423
|
exportCard.className = "card surface-elevated stack-sm";
|
|
2174
3424
|
|
|
@@ -2228,54 +3478,49 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2228
3478
|
exportNav.append(exportButton, exportMenu);
|
|
2229
3479
|
exportCard.appendChild(exportNav);
|
|
2230
3480
|
|
|
2231
|
-
const
|
|
2232
|
-
|
|
3481
|
+
const resetButton = document.createElement("button");
|
|
3482
|
+
resetButton.type = "button";
|
|
3483
|
+
resetButton.className = "btn-outline pds-live-editor-reset-btn";
|
|
3484
|
+
resetButton.textContent = "Reset Config";
|
|
3485
|
+
resetButton.addEventListener("click", async () => {
|
|
3486
|
+
await this.resetConfig();
|
|
3487
|
+
});
|
|
2233
3488
|
|
|
2234
|
-
const
|
|
2235
|
-
|
|
2236
|
-
|
|
3489
|
+
const drawerFooter = document.createElement("div");
|
|
3490
|
+
drawerFooter.className = "pds-live-editor-drawer-footer";
|
|
3491
|
+
drawerFooter.appendChild(resetButton);
|
|
2237
3492
|
|
|
2238
|
-
const
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
}));
|
|
2259
|
-
} catch (error) {
|
|
2260
|
-
console.warn("Omnibox query failed:", error);
|
|
2261
|
-
return [];
|
|
2262
|
-
}
|
|
2263
|
-
},
|
|
2264
|
-
action: async (options) => {
|
|
2265
|
-
if (options?.code && navigator.clipboard) {
|
|
2266
|
-
await navigator.clipboard.writeText(options.code);
|
|
2267
|
-
await PDS.toast("Copied token to clipboard", { type: "success" });
|
|
2268
|
-
}
|
|
2269
|
-
},
|
|
2270
|
-
},
|
|
2271
|
-
},
|
|
3493
|
+
const accordion = document.createElement("section");
|
|
3494
|
+
accordion.className = "accordion";
|
|
3495
|
+
accordion.setAttribute("aria-label", "Design settings groups");
|
|
3496
|
+
|
|
3497
|
+
const buildAccordionGroup = (title, nodes = [], open = false, sectionId = "") => {
|
|
3498
|
+
const details = document.createElement("details");
|
|
3499
|
+
if (open) details.open = true;
|
|
3500
|
+
if (sectionId) details.dataset.section = sectionId;
|
|
3501
|
+
|
|
3502
|
+
const summary = document.createElement("summary");
|
|
3503
|
+
summary.textContent = title;
|
|
3504
|
+
|
|
3505
|
+
const body = document.createElement("div");
|
|
3506
|
+
body.className = "stack-md";
|
|
3507
|
+
nodes.forEach((node) => {
|
|
3508
|
+
if (node) body.appendChild(node);
|
|
3509
|
+
});
|
|
3510
|
+
|
|
3511
|
+
details.append(summary, body);
|
|
3512
|
+
return details;
|
|
2272
3513
|
};
|
|
2273
|
-
searchCard.appendChild(omnibox);
|
|
2274
3514
|
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
3515
|
+
accordion.appendChild(buildAccordionGroup("Preset & Theme", [presetCard, themeCard], true, "preset-theme"));
|
|
3516
|
+
accordion.appendChild(buildAccordionGroup("Configuration", [configCard], false, "configuration"));
|
|
3517
|
+
accordion.appendChild(buildAccordionGroup("Canvas", [templateCard], false, "canvas"));
|
|
3518
|
+
accordion.appendChild(
|
|
3519
|
+
buildAccordionGroup("Import & Export", [importCard, exportCard], false, "import-convert-export")
|
|
3520
|
+
);
|
|
3521
|
+
|
|
3522
|
+
content.appendChild(accordion);
|
|
3523
|
+
content.appendChild(drawerFooter);
|
|
2279
3524
|
|
|
2280
3525
|
this._drawer.replaceChildren(header, content);
|
|
2281
3526
|
|
|
@@ -2290,6 +3535,161 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2290
3535
|
await exportFromLiveEdit(format);
|
|
2291
3536
|
}
|
|
2292
3537
|
|
|
3538
|
+
_ensureLiveCanvasContainer() {
|
|
3539
|
+
let container = document.getElementById("pds-live-edit-canvas");
|
|
3540
|
+
if (container) return container;
|
|
3541
|
+
|
|
3542
|
+
container = document.createElement("section");
|
|
3543
|
+
container.id = "pds-live-edit-canvas";
|
|
3544
|
+
container.className = "card stack-md";
|
|
3545
|
+
|
|
3546
|
+
const heading = document.createElement("h3");
|
|
3547
|
+
heading.textContent = "PDS Live Canvas";
|
|
3548
|
+
const description = document.createElement("p");
|
|
3549
|
+
description.className = "text-muted";
|
|
3550
|
+
description.textContent = "Injected templates render here to preview config changes.";
|
|
3551
|
+
|
|
3552
|
+
const canvas = document.createElement("div");
|
|
3553
|
+
canvas.id = "pds-live-edit-canvas-content";
|
|
3554
|
+
canvas.className = "stack-md";
|
|
3555
|
+
|
|
3556
|
+
container.append(heading, description, canvas);
|
|
3557
|
+
document.body.appendChild(container);
|
|
3558
|
+
return container;
|
|
3559
|
+
}
|
|
3560
|
+
|
|
3561
|
+
_injectTemplateIntoCanvas(template) {
|
|
3562
|
+
if (!template || typeof template !== "object") return;
|
|
3563
|
+
const container = this._ensureLiveCanvasContainer();
|
|
3564
|
+
const canvas = container.querySelector("#pds-live-edit-canvas-content");
|
|
3565
|
+
if (!canvas) return;
|
|
3566
|
+
canvas.innerHTML = String(template.html || "");
|
|
3567
|
+
}
|
|
3568
|
+
|
|
3569
|
+
async openDesignSettings() {
|
|
3570
|
+
const target = this._activeTarget || document.body;
|
|
3571
|
+
const quickPaths = this._activeTarget ? collectQuickContext(this._activeTarget).paths : [];
|
|
3572
|
+
|
|
3573
|
+
await this._openDrawer(target, quickPaths);
|
|
3574
|
+
|
|
3575
|
+
const drawer = this._drawer;
|
|
3576
|
+
if (!drawer) return;
|
|
3577
|
+
|
|
3578
|
+
const presetGroup = drawer.querySelector('details[data-section="preset-theme"]');
|
|
3579
|
+
if (presetGroup) {
|
|
3580
|
+
presetGroup.setAttribute("open", "");
|
|
3581
|
+
}
|
|
3582
|
+
|
|
3583
|
+
const configGroup = drawer.querySelector('details[data-section="configuration"]');
|
|
3584
|
+
if (configGroup) {
|
|
3585
|
+
configGroup.setAttribute("open", "");
|
|
3586
|
+
}
|
|
3587
|
+
}
|
|
3588
|
+
|
|
3589
|
+
async resetConfig() {
|
|
3590
|
+
let confirmed = true;
|
|
3591
|
+
if (typeof PDS?.ask === "function") {
|
|
3592
|
+
confirmed = await PDS.ask(
|
|
3593
|
+
"This clears your saved local configuration and reloads the page.",
|
|
3594
|
+
{
|
|
3595
|
+
title: "Reset Config?",
|
|
3596
|
+
type: "confirm",
|
|
3597
|
+
buttons: {
|
|
3598
|
+
ok: { name: "Reset", variant: "danger" },
|
|
3599
|
+
cancel: { name: "Cancel", cancel: true },
|
|
3600
|
+
},
|
|
3601
|
+
}
|
|
3602
|
+
);
|
|
3603
|
+
}
|
|
3604
|
+
|
|
3605
|
+
if (!confirmed) return false;
|
|
3606
|
+
|
|
3607
|
+
try {
|
|
3608
|
+
window.localStorage.removeItem("pure-ds-config");
|
|
3609
|
+
} catch (e) {}
|
|
3610
|
+
|
|
3611
|
+
window.location.reload();
|
|
3612
|
+
return true;
|
|
3613
|
+
}
|
|
3614
|
+
|
|
3615
|
+
async openImportDetailsFromToast(options = {}) {
|
|
3616
|
+
const requestedFileName = String(options?.fileName || "");
|
|
3617
|
+
const requestedSourceType = String(options?.sourceType || "");
|
|
3618
|
+
const requestedImportMode = String(options?.importMode || "");
|
|
3619
|
+
const target = this._activeTarget || document.body;
|
|
3620
|
+
const quickPaths = this._activeTarget ? collectQuickContext(this._activeTarget).paths : [];
|
|
3621
|
+
|
|
3622
|
+
await this._openDrawer(target, quickPaths);
|
|
3623
|
+
|
|
3624
|
+
const drawer = this._drawer;
|
|
3625
|
+
if (!drawer) return;
|
|
3626
|
+
|
|
3627
|
+
const importGroup = drawer.querySelector('details[data-section="import-convert-export"]');
|
|
3628
|
+
if (importGroup) {
|
|
3629
|
+
importGroup.setAttribute("open", "");
|
|
3630
|
+
}
|
|
3631
|
+
|
|
3632
|
+
const tryOpenImporterDetails = (attempt = 0) => {
|
|
3633
|
+
const importer = drawer.querySelector("pds-live-importer");
|
|
3634
|
+
if (!importer) {
|
|
3635
|
+
if (attempt < 12) setTimeout(() => tryOpenImporterDetails(attempt + 1), 100);
|
|
3636
|
+
return;
|
|
3637
|
+
}
|
|
3638
|
+
|
|
3639
|
+
if (typeof importer.openHistoryDetailsByMeta === "function") {
|
|
3640
|
+
importer.openHistoryDetailsByMeta({
|
|
3641
|
+
fileName: requestedFileName,
|
|
3642
|
+
sourceType: requestedSourceType,
|
|
3643
|
+
importMode: requestedImportMode,
|
|
3644
|
+
});
|
|
3645
|
+
}
|
|
3646
|
+
};
|
|
3647
|
+
|
|
3648
|
+
tryOpenImporterDetails();
|
|
3649
|
+
}
|
|
3650
|
+
|
|
3651
|
+
_endLiveEditSessionAfterImport() {
|
|
3652
|
+
this._removeActiveUI();
|
|
3653
|
+
|
|
3654
|
+
if (this._drawer) {
|
|
3655
|
+
if (typeof this._drawer.closeDrawer === "function") {
|
|
3656
|
+
this._drawer.closeDrawer();
|
|
3657
|
+
} else {
|
|
3658
|
+
this._drawer.removeAttribute("open");
|
|
3659
|
+
}
|
|
3660
|
+
}
|
|
3661
|
+
|
|
3662
|
+
this.dispatchEvent(
|
|
3663
|
+
new CustomEvent("pds:live-edit:disable", {
|
|
3664
|
+
bubbles: true,
|
|
3665
|
+
composed: true,
|
|
3666
|
+
detail: { reason: "import-complete" },
|
|
3667
|
+
})
|
|
3668
|
+
);
|
|
3669
|
+
}
|
|
3670
|
+
|
|
3671
|
+
async _applyImportResult(result, options = {}) {
|
|
3672
|
+
if (!result || typeof result !== "object") return;
|
|
3673
|
+
|
|
3674
|
+
const importMode = String(options?.importMode || result?.meta?.importMode || "convert-only");
|
|
3675
|
+
const injectTemplate = options.injectTemplate !== false;
|
|
3676
|
+
const validationBlocked = Boolean(result?.meta?.validationBlocked || result?.meta?.validation?.ok === false);
|
|
3677
|
+
const shouldApplyPatch =
|
|
3678
|
+
options.applyDesignPatch === true ||
|
|
3679
|
+
(options.applyDesignPatch !== false && importMode !== "convert-only" && !validationBlocked);
|
|
3680
|
+
const patch = result.designPatch;
|
|
3681
|
+
const patchKeys =
|
|
3682
|
+
patch && typeof patch === "object" ? Object.keys(patch).filter(Boolean) : [];
|
|
3683
|
+
|
|
3684
|
+
if (shouldApplyPatch && patchKeys.length > 0) {
|
|
3685
|
+
await applyDesignPatch(patch);
|
|
3686
|
+
}
|
|
3687
|
+
|
|
3688
|
+
if (injectTemplate && result.template?.html) {
|
|
3689
|
+
this._injectTemplateIntoCanvas(result.template);
|
|
3690
|
+
}
|
|
3691
|
+
}
|
|
3692
|
+
|
|
2293
3693
|
async _handleFormSubmit(event, form) {
|
|
2294
3694
|
if (!form || typeof form.getValuesFlat !== "function") return;
|
|
2295
3695
|
|
|
@@ -2308,9 +3708,24 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2308
3708
|
}
|
|
2309
3709
|
|
|
2310
3710
|
// Apply the changes
|
|
2311
|
-
const
|
|
2312
|
-
const
|
|
3711
|
+
const eventJson = event?.detail?.json;
|
|
3712
|
+
const hasEventPayload =
|
|
3713
|
+
eventJson && typeof eventJson === "object" && Object.keys(eventJson).length > 0;
|
|
3714
|
+
const flatValues = hasEventPayload
|
|
3715
|
+
? eventJson
|
|
3716
|
+
: typeof form._normalizeFlatValues === "function"
|
|
3717
|
+
? form._normalizeFlatValues(form.getValuesFlat())
|
|
3718
|
+
: form.getValuesFlat();
|
|
3719
|
+
const sanitizedFlatValues = {};
|
|
2313
3720
|
Object.entries(flatValues || {}).forEach(([path, value]) => {
|
|
3721
|
+
if (path === FORM_THEME_CONTEXT_POINTER || path === FORM_THEME_CONTEXT_FIELD) {
|
|
3722
|
+
return;
|
|
3723
|
+
}
|
|
3724
|
+
sanitizedFlatValues[path] = value;
|
|
3725
|
+
});
|
|
3726
|
+
|
|
3727
|
+
const patch = {};
|
|
3728
|
+
Object.entries(sanitizedFlatValues).forEach(([path, value]) => {
|
|
2314
3729
|
setValueAtJsonPath(patch, path, value);
|
|
2315
3730
|
});
|
|
2316
3731
|
await applyDesignPatch(patch);
|