@pure-ds/core 0.6.10 → 0.7.1
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/.github/copilot-instructions.md +6 -1
- package/custom-elements.json +803 -16
- package/dist/types/pds.d.ts +1 -0
- package/dist/types/public/assets/js/pds-ask.d.ts +2 -0
- package/dist/types/public/assets/js/pds-ask.d.ts.map +1 -0
- package/dist/types/public/assets/js/pds-auto-definer.d.ts +14 -0
- package/dist/types/public/assets/js/pds-auto-definer.d.ts.map +1 -0
- package/dist/types/public/assets/js/pds-autocomplete.d.ts +79 -0
- package/dist/types/public/assets/js/pds-autocomplete.d.ts.map +1 -0
- package/dist/types/public/assets/js/pds-enhancers.d.ts +7 -0
- package/dist/types/public/assets/js/pds-enhancers.d.ts.map +1 -0
- package/dist/types/public/assets/js/pds-manager.d.ts +98 -1
- package/dist/types/public/assets/js/pds-manager.d.ts.map +1 -1
- package/dist/types/public/assets/js/pds-toast.d.ts +8 -0
- package/dist/types/public/assets/js/pds-toast.d.ts.map +1 -0
- package/dist/types/public/assets/js/pds.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-drawer.d.ts +1 -143
- package/dist/types/public/assets/pds/components/pds-drawer.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-icon.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-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.map +1 -1
- package/dist/types/public/assets/pds/components/pds-richtext.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-scrollrow.d.ts +1 -63
- package/dist/types/public/assets/pds/components/pds-scrollrow.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-splitpanel.d.ts +1 -89
- package/dist/types/public/assets/pds/components/pds-splitpanel.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-theme.d.ts +1 -22
- package/dist/types/public/assets/pds/components/pds-theme.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/public/assets/pds/components/pds-upload.d.ts.map +1 -1
- package/dist/types/src/js/common/ask.d.ts.map +1 -1
- 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-ask.d.ts +2 -0
- package/dist/types/src/js/pds-ask.d.ts.map +1 -0
- package/dist/types/src/js/pds-auto-definer.d.ts +2 -0
- package/dist/types/src/js/pds-auto-definer.d.ts.map +1 -0
- package/dist/types/src/js/pds-autocomplete.d.ts +2 -0
- package/dist/types/src/js/pds-autocomplete.d.ts.map +1 -0
- 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-start-helpers.d.ts.map +1 -1
- package/dist/types/src/js/pds-enhancers.d.ts +2 -0
- package/dist/types/src/js/pds-enhancers.d.ts.map +1 -0
- 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-toast.d.ts +2 -0
- package/dist/types/src/js/pds-toast.d.ts.map +1 -0
- package/dist/types/src/js/pds.d.ts.map +1 -1
- package/package.json +11 -5
- package/packages/pds-cli/README.md +60 -0
- package/packages/pds-cli/bin/pds-import.js +176 -0
- package/packages/pds-cli/bin/pds-static.js +27 -1
- package/packages/pds-cli/bin/postinstall.mjs +17 -8
- package/packages/pds-cli/bin/templates/bootstrap/pds.config.js +1 -5
- package/packages/pds-cli/bin/templates/bootstrap/public/index.html +2 -1
- package/packages/pds-cli/bin/templates/starter-templates.js +1 -3
- package/public/assets/js/app.js +9 -163
- package/public/assets/js/pds-ask.js +25 -0
- package/public/assets/js/pds-auto-definer.js +1 -0
- package/public/assets/js/pds-autocomplete.js +7 -0
- package/public/assets/js/pds-enhancers.js +1 -0
- package/public/assets/js/pds-manager.js +370 -267
- package/public/assets/js/pds-toast.js +1 -0
- package/public/assets/js/pds.js +2 -32
- package/public/assets/pds/components/pds-calendar.js +2 -2
- package/public/assets/pds/components/pds-drawer.js +1 -1
- package/public/assets/pds/components/pds-form.js +7 -6
- package/public/assets/pds/components/pds-icon.js +12 -9
- package/public/assets/pds/components/pds-live-converter.js +47 -0
- package/public/assets/pds/components/pds-live-edit.js +758 -44
- package/public/assets/pds/components/pds-live-importer.js +773 -0
- package/public/assets/pds/components/pds-live-template-canvas.js +172 -0
- package/public/assets/pds/components/pds-omnibox.js +147 -3
- package/public/assets/pds/components/pds-richtext.js +2 -0
- package/public/assets/pds/components/pds-scrollrow.js +61 -2
- package/public/assets/pds/components/pds-splitpanel.js +3 -1
- package/public/assets/pds/components/pds-theme.js +2 -0
- package/public/assets/pds/components/pds-toaster.js +52 -5
- package/public/assets/pds/components/pds-treeview.js +974 -0
- package/public/assets/pds/components/pds-upload.js +2 -0
- package/public/assets/pds/core/pds-ask.js +25 -0
- package/public/assets/pds/core/pds-auto-definer.js +1 -0
- package/public/assets/pds/core/pds-autocomplete.js +7 -0
- package/public/assets/pds/core/pds-enhancers.js +1 -0
- package/public/assets/pds/core/pds-manager.js +3646 -0
- package/public/assets/pds/core/pds-toast.js +1 -0
- package/public/assets/pds/core.js +2 -0
- package/public/assets/pds/custom-elements.json +803 -16
- package/public/assets/pds/pds-css-complete.json +7 -2
- 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 +38 -1
- package/src/js/pds-core/pds-config.js +9 -9
- package/src/js/pds-core/pds-enhancers.js +146 -0
- package/src/js/pds-core/pds-generator.js +170 -29
- package/src/js/pds-core/pds-live.js +456 -13
- package/src/js/pds-core/pds-start-helpers.js +5 -1
- package/src/js/pds-live-manager/conversion-service.js +3135 -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 +1 -0
- package/src/js/pds.js +192 -12
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { PDS } from "#pds";
|
|
2
2
|
|
|
3
3
|
const EDITOR_TAG = "pds-live-edit";
|
|
4
4
|
const STYLE_ID = "pds-live-editor-styles";
|
|
@@ -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;
|
|
@@ -191,7 +267,6 @@ ${EDITOR_TAG} {
|
|
|
191
267
|
margin: 0;
|
|
192
268
|
padding: 0;
|
|
193
269
|
list-style: none;
|
|
194
|
-
overflow: visible;
|
|
195
270
|
}
|
|
196
271
|
.${DROPDOWN_CLASS} .pds-live-editor-menu {
|
|
197
272
|
display: block;
|
|
@@ -199,11 +274,9 @@ ${EDITOR_TAG} {
|
|
|
199
274
|
padding: var(--spacing-1);
|
|
200
275
|
max-width: 350px;
|
|
201
276
|
padding-bottom: 0;
|
|
202
|
-
overflow: visible;
|
|
203
277
|
}
|
|
204
278
|
.${DROPDOWN_CLASS} .pds-live-editor-form-container {
|
|
205
279
|
padding-bottom: var(--spacing-2);
|
|
206
|
-
overflow: visible;
|
|
207
280
|
}
|
|
208
281
|
.${DROPDOWN_CLASS} .pds-live-editor-title {
|
|
209
282
|
display: block;
|
|
@@ -238,9 +311,42 @@ ${EDITOR_TAG} {
|
|
|
238
311
|
background: var(--color-surface-base);
|
|
239
312
|
position: sticky;
|
|
240
313
|
justify-content: space-between;
|
|
314
|
+
align-items: center;
|
|
241
315
|
bottom: 0;
|
|
242
316
|
z-index: 1;
|
|
243
317
|
}
|
|
318
|
+
.pds-live-editor-drawer-footer {
|
|
319
|
+
position: sticky;
|
|
320
|
+
bottom: 0;
|
|
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;
|
|
349
|
+
}
|
|
244
350
|
`;
|
|
245
351
|
document.head.appendChild(style);
|
|
246
352
|
}
|
|
@@ -319,6 +425,14 @@ function deepMerge(target = {}, source = {}) {
|
|
|
319
425
|
return out;
|
|
320
426
|
}
|
|
321
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
|
+
|
|
322
436
|
function titleize(value) {
|
|
323
437
|
return String(value)
|
|
324
438
|
.replace(/([a-z])([A-Z])/g, "$1 $2")
|
|
@@ -1010,6 +1124,7 @@ const GENERIC_FONT_FAMILIES = new Set([
|
|
|
1010
1124
|
]);
|
|
1011
1125
|
|
|
1012
1126
|
let loadGoogleFontFnPromise = null;
|
|
1127
|
+
let managerModulePromise = null;
|
|
1013
1128
|
|
|
1014
1129
|
function normalizeFontName(fontFamily) {
|
|
1015
1130
|
return String(fontFamily || "")
|
|
@@ -1030,6 +1145,19 @@ async function getLoadGoogleFontFn() {
|
|
|
1030
1145
|
}
|
|
1031
1146
|
if (loadGoogleFontFnPromise) return loadGoogleFontFnPromise;
|
|
1032
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 () => {
|
|
1033
1161
|
const candidates = [
|
|
1034
1162
|
PDS?.currentConfig?.managerURL,
|
|
1035
1163
|
"../core/pds-manager.js",
|
|
@@ -1043,14 +1171,13 @@ async function getLoadGoogleFontFn() {
|
|
|
1043
1171
|
if (attempted.has(resolved)) continue;
|
|
1044
1172
|
attempted.add(resolved);
|
|
1045
1173
|
const mod = await import(resolved);
|
|
1046
|
-
if (typeof mod
|
|
1047
|
-
return mod.loadGoogleFont;
|
|
1048
|
-
}
|
|
1174
|
+
if (mod && typeof mod === "object") return mod;
|
|
1049
1175
|
} catch (e) {}
|
|
1050
1176
|
}
|
|
1051
1177
|
return null;
|
|
1052
1178
|
})();
|
|
1053
|
-
|
|
1179
|
+
|
|
1180
|
+
return managerModulePromise;
|
|
1054
1181
|
}
|
|
1055
1182
|
|
|
1056
1183
|
async function loadTypographyFontsForDesign(typography) {
|
|
@@ -1696,9 +1823,11 @@ async function exportFromLiveEdit(format) {
|
|
|
1696
1823
|
}
|
|
1697
1824
|
|
|
1698
1825
|
function setFormSchemas(form, schema, uiSchema, design) {
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
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;
|
|
1702
1831
|
}
|
|
1703
1832
|
|
|
1704
1833
|
async function waitForElementDefinition(tagName, timeoutMs = 4000) {
|
|
@@ -1970,6 +2099,106 @@ function deepClone(value) {
|
|
|
1970
2099
|
return JSON.parse(JSON.stringify(value));
|
|
1971
2100
|
}
|
|
1972
2101
|
|
|
2102
|
+
function withThemeContextValues(values) {
|
|
2103
|
+
const nextValues = shallowClone(values || {});
|
|
2104
|
+
nextValues[FORM_THEME_CONTEXT_FIELD] = getActiveTheme().value;
|
|
2105
|
+
return nextValues;
|
|
2106
|
+
}
|
|
2107
|
+
|
|
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
|
+
|
|
1973
2202
|
function shouldKeepPathForSelection(selectedPaths, path) {
|
|
1974
2203
|
if (!path) return true;
|
|
1975
2204
|
return selectedPaths.some((selectedPath) => {
|
|
@@ -2233,6 +2462,12 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2233
2462
|
this._undoStack = [];
|
|
2234
2463
|
this._dropdownMenuOpen = false;
|
|
2235
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;
|
|
2236
2471
|
}
|
|
2237
2472
|
|
|
2238
2473
|
connectedCallback() {
|
|
@@ -2242,13 +2477,15 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2242
2477
|
}
|
|
2243
2478
|
PdsLiveEdit._activeInstance = this;
|
|
2244
2479
|
this._connected = true;
|
|
2245
|
-
if (
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
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
|
+
}
|
|
2252
2489
|
}
|
|
2253
2490
|
|
|
2254
2491
|
disconnectedCallback() {
|
|
@@ -2256,21 +2493,141 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2256
2493
|
}
|
|
2257
2494
|
|
|
2258
2495
|
_teardown() {
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2496
|
+
this._disableInteractiveEditing({ clearUI: true });
|
|
2497
|
+
this._connected = false;
|
|
2498
|
+
if (PDS && typeof PDS.removeEventListener === "function") {
|
|
2499
|
+
PDS.removeEventListener("pds:theme:changed", this._boundThemeChanged);
|
|
2263
2500
|
}
|
|
2264
2501
|
this._removeRepositionListeners();
|
|
2265
2502
|
this._clearCloseTimer();
|
|
2266
2503
|
this._removeActiveUI();
|
|
2267
|
-
this.
|
|
2504
|
+
this._drawerConfigFormContainer = null;
|
|
2505
|
+
this._drawerConfigFooter = null;
|
|
2268
2506
|
if (PdsLiveEdit._activeInstance === this) {
|
|
2269
2507
|
PdsLiveEdit._activeInstance = null;
|
|
2270
2508
|
}
|
|
2271
2509
|
}
|
|
2272
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
|
+
|
|
2273
2629
|
_handleMouseOver(event) {
|
|
2630
|
+
if (!this._interactiveEditingEnabled) return;
|
|
2274
2631
|
if (!event?.target || !(event.target instanceof Element)) return;
|
|
2275
2632
|
|
|
2276
2633
|
// Check if we're hovering over the dropdown (including Shadow DOM elements)
|
|
@@ -2311,6 +2668,8 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2311
2668
|
return null;
|
|
2312
2669
|
}
|
|
2313
2670
|
if (!this._selectors?.selector) return null;
|
|
2671
|
+
if (isLiveEditHighlightBlacklisted(node)) return null;
|
|
2672
|
+
if (node.closest("[data-pds-live-edit-ignore]")) return null;
|
|
2314
2673
|
if (node.closest(EDITOR_TAG)) return null;
|
|
2315
2674
|
if (node.closest(`.${DROPDOWN_CLASS}`)) return null;
|
|
2316
2675
|
if (node.closest("pds-drawer")) return null;
|
|
@@ -2323,6 +2682,7 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2323
2682
|
}
|
|
2324
2683
|
|
|
2325
2684
|
_showForTarget(target) {
|
|
2685
|
+
if (!this._interactiveEditingEnabled) return;
|
|
2326
2686
|
const quickContext = collectQuickContext(target);
|
|
2327
2687
|
const quickPaths = quickContext.paths;
|
|
2328
2688
|
if (!quickPaths.length) return;
|
|
@@ -2367,8 +2727,13 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2367
2727
|
this._lastPointer = null;
|
|
2368
2728
|
this._dropdownMenuOpen = false;
|
|
2369
2729
|
|
|
2370
|
-
|
|
2371
|
-
|
|
2730
|
+
if (
|
|
2731
|
+
this._connected &&
|
|
2732
|
+
this._interactiveEditingEnabled &&
|
|
2733
|
+
this._interactionListenersAttached
|
|
2734
|
+
) {
|
|
2735
|
+
this._addMouseOverListener();
|
|
2736
|
+
}
|
|
2372
2737
|
}
|
|
2373
2738
|
|
|
2374
2739
|
_addDocumentListeners() {
|
|
@@ -2515,6 +2880,7 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2515
2880
|
|
|
2516
2881
|
_addMouseOverListener() {
|
|
2517
2882
|
if (typeof document === "undefined") return;
|
|
2883
|
+
if (!this._interactiveEditingEnabled) return;
|
|
2518
2884
|
document.addEventListener("mouseover", this._boundMouseOver, true);
|
|
2519
2885
|
}
|
|
2520
2886
|
|
|
@@ -2724,13 +3090,142 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2724
3090
|
this._openDrawer(target, quickPaths);
|
|
2725
3091
|
this._removeActiveUI();
|
|
2726
3092
|
});
|
|
3093
|
+
|
|
3094
|
+
const quickModeNav = await this._buildQuickModeDropdown();
|
|
2727
3095
|
|
|
2728
3096
|
// Add buttons to footer
|
|
2729
3097
|
footer.appendChild(applyBtn);
|
|
2730
3098
|
footer.appendChild(undoBtn);
|
|
3099
|
+
footer.appendChild(quickModeNav);
|
|
2731
3100
|
footer.appendChild(gearBtn);
|
|
2732
3101
|
}
|
|
2733
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
|
+
|
|
2734
3229
|
async _openDrawer(target, quickPaths) {
|
|
2735
3230
|
if (!this._drawer) {
|
|
2736
3231
|
this._drawer = document.createElement("pds-drawer");
|
|
@@ -2739,6 +3234,8 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2739
3234
|
this.appendChild(this._drawer);
|
|
2740
3235
|
}
|
|
2741
3236
|
|
|
3237
|
+
this._drawer.style.setProperty("--drawer-width", "min(96vw, 44rem)");
|
|
3238
|
+
|
|
2742
3239
|
if (!customElements.get("pds-drawer")) {
|
|
2743
3240
|
await customElements.whenDefined("pds-drawer");
|
|
2744
3241
|
}
|
|
@@ -2750,7 +3247,7 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2750
3247
|
|
|
2751
3248
|
const content = document.createElement("div");
|
|
2752
3249
|
content.setAttribute("slot", "drawer-content");
|
|
2753
|
-
content.className = "
|
|
3250
|
+
content.className = "pds-live-editor-drawer-content";
|
|
2754
3251
|
|
|
2755
3252
|
const presetCard = document.createElement("section");
|
|
2756
3253
|
presetCard.className = "card surface-elevated stack-sm";
|
|
@@ -2864,6 +3361,8 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2864
3361
|
const configFooter = document.createElement("div");
|
|
2865
3362
|
configFooter.className = "flex gap-sm";
|
|
2866
3363
|
configCard.appendChild(configFooter);
|
|
3364
|
+
this._drawerConfigFormContainer = configFormContainer;
|
|
3365
|
+
this._drawerConfigFooter = configFooter;
|
|
2867
3366
|
|
|
2868
3367
|
const fullDesign = shallowClone(PDS?.currentConfig?.design || {});
|
|
2869
3368
|
const fullConfigFormResult = await buildFullConfigForm(
|
|
@@ -2886,6 +3385,40 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2886
3385
|
configFormContainer.appendChild(unavailable);
|
|
2887
3386
|
}
|
|
2888
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
|
+
|
|
2889
3422
|
const exportCard = document.createElement("section");
|
|
2890
3423
|
exportCard.className = "card surface-elevated stack-sm";
|
|
2891
3424
|
|
|
@@ -2945,28 +3478,49 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2945
3478
|
exportNav.append(exportButton, exportMenu);
|
|
2946
3479
|
exportCard.appendChild(exportNav);
|
|
2947
3480
|
|
|
2948
|
-
const resetCard = document.createElement("section");
|
|
2949
|
-
resetCard.className = "card surface-elevated stack-sm";
|
|
2950
|
-
|
|
2951
|
-
const resetTitle = document.createElement("h4");
|
|
2952
|
-
resetTitle.textContent = "Reset";
|
|
2953
|
-
resetCard.appendChild(resetTitle);
|
|
2954
|
-
|
|
2955
3481
|
const resetButton = document.createElement("button");
|
|
2956
3482
|
resetButton.type = "button";
|
|
2957
|
-
resetButton.className = "btn-outline";
|
|
3483
|
+
resetButton.className = "btn-outline pds-live-editor-reset-btn";
|
|
2958
3484
|
resetButton.textContent = "Reset Config";
|
|
2959
|
-
resetButton.addEventListener("click", () => {
|
|
2960
|
-
|
|
2961
|
-
window.location.reload();
|
|
3485
|
+
resetButton.addEventListener("click", async () => {
|
|
3486
|
+
await this.resetConfig();
|
|
2962
3487
|
});
|
|
2963
|
-
resetCard.appendChild(resetButton);
|
|
2964
3488
|
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
3489
|
+
const drawerFooter = document.createElement("div");
|
|
3490
|
+
drawerFooter.className = "pds-live-editor-drawer-footer";
|
|
3491
|
+
drawerFooter.appendChild(resetButton);
|
|
3492
|
+
|
|
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;
|
|
3513
|
+
};
|
|
3514
|
+
|
|
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);
|
|
2970
3524
|
|
|
2971
3525
|
this._drawer.replaceChildren(header, content);
|
|
2972
3526
|
|
|
@@ -2981,6 +3535,158 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
2981
3535
|
await exportFromLiveEdit(format);
|
|
2982
3536
|
}
|
|
2983
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("hr");
|
|
3547
|
+
heading.setAttribute("data-content", "Injected HTML below");
|
|
3548
|
+
|
|
3549
|
+
const canvas = document.createElement("div");
|
|
3550
|
+
canvas.id = "pds-live-edit-canvas-content";
|
|
3551
|
+
canvas.className = "stack-md";
|
|
3552
|
+
|
|
3553
|
+
container.append(heading, canvas)
|
|
3554
|
+
document.body.appendChild(container);
|
|
3555
|
+
return container;
|
|
3556
|
+
}
|
|
3557
|
+
|
|
3558
|
+
_injectTemplateIntoCanvas(template) {
|
|
3559
|
+
if (!template || typeof template !== "object") return;
|
|
3560
|
+
const container = this._ensureLiveCanvasContainer();
|
|
3561
|
+
const canvas = container.querySelector("#pds-live-edit-canvas-content");
|
|
3562
|
+
if (!canvas) return;
|
|
3563
|
+
canvas.innerHTML = String(template.html || "");
|
|
3564
|
+
}
|
|
3565
|
+
|
|
3566
|
+
async openDesignSettings() {
|
|
3567
|
+
const target = this._activeTarget || document.body;
|
|
3568
|
+
const quickPaths = this._activeTarget ? collectQuickContext(this._activeTarget).paths : [];
|
|
3569
|
+
|
|
3570
|
+
await this._openDrawer(target, quickPaths);
|
|
3571
|
+
|
|
3572
|
+
const drawer = this._drawer;
|
|
3573
|
+
if (!drawer) return;
|
|
3574
|
+
|
|
3575
|
+
const presetGroup = drawer.querySelector('details[data-section="preset-theme"]');
|
|
3576
|
+
if (presetGroup) {
|
|
3577
|
+
presetGroup.setAttribute("open", "");
|
|
3578
|
+
}
|
|
3579
|
+
|
|
3580
|
+
const configGroup = drawer.querySelector('details[data-section="configuration"]');
|
|
3581
|
+
if (configGroup) {
|
|
3582
|
+
configGroup.setAttribute("open", "");
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
|
|
3586
|
+
async resetConfig() {
|
|
3587
|
+
let confirmed = true;
|
|
3588
|
+
if (typeof PDS?.ask === "function") {
|
|
3589
|
+
confirmed = await PDS.ask(
|
|
3590
|
+
"This clears your saved local configuration and reloads the page.",
|
|
3591
|
+
{
|
|
3592
|
+
title: "Reset Config?",
|
|
3593
|
+
type: "confirm",
|
|
3594
|
+
buttons: {
|
|
3595
|
+
ok: { name: "Reset", variant: "danger" },
|
|
3596
|
+
cancel: { name: "Cancel", cancel: true },
|
|
3597
|
+
},
|
|
3598
|
+
}
|
|
3599
|
+
);
|
|
3600
|
+
}
|
|
3601
|
+
|
|
3602
|
+
if (!confirmed) return false;
|
|
3603
|
+
|
|
3604
|
+
try {
|
|
3605
|
+
window.localStorage.removeItem("pure-ds-config");
|
|
3606
|
+
} catch (e) {}
|
|
3607
|
+
|
|
3608
|
+
window.location.reload();
|
|
3609
|
+
return true;
|
|
3610
|
+
}
|
|
3611
|
+
|
|
3612
|
+
async openImportDetailsFromToast(options = {}) {
|
|
3613
|
+
const requestedFileName = String(options?.fileName || "");
|
|
3614
|
+
const requestedSourceType = String(options?.sourceType || "");
|
|
3615
|
+
const requestedImportMode = String(options?.importMode || "");
|
|
3616
|
+
const target = this._activeTarget || document.body;
|
|
3617
|
+
const quickPaths = this._activeTarget ? collectQuickContext(this._activeTarget).paths : [];
|
|
3618
|
+
|
|
3619
|
+
await this._openDrawer(target, quickPaths);
|
|
3620
|
+
|
|
3621
|
+
const drawer = this._drawer;
|
|
3622
|
+
if (!drawer) return;
|
|
3623
|
+
|
|
3624
|
+
const importGroup = drawer.querySelector('details[data-section="import-convert-export"]');
|
|
3625
|
+
if (importGroup) {
|
|
3626
|
+
importGroup.setAttribute("open", "");
|
|
3627
|
+
}
|
|
3628
|
+
|
|
3629
|
+
const tryOpenImporterDetails = (attempt = 0) => {
|
|
3630
|
+
const importer = drawer.querySelector("pds-live-importer");
|
|
3631
|
+
if (!importer) {
|
|
3632
|
+
if (attempt < 12) setTimeout(() => tryOpenImporterDetails(attempt + 1), 100);
|
|
3633
|
+
return;
|
|
3634
|
+
}
|
|
3635
|
+
|
|
3636
|
+
if (typeof importer.openHistoryDetailsByMeta === "function") {
|
|
3637
|
+
importer.openHistoryDetailsByMeta({
|
|
3638
|
+
fileName: requestedFileName,
|
|
3639
|
+
sourceType: requestedSourceType,
|
|
3640
|
+
importMode: requestedImportMode,
|
|
3641
|
+
});
|
|
3642
|
+
}
|
|
3643
|
+
};
|
|
3644
|
+
|
|
3645
|
+
tryOpenImporterDetails();
|
|
3646
|
+
}
|
|
3647
|
+
|
|
3648
|
+
_endLiveEditSessionAfterImport() {
|
|
3649
|
+
this._removeActiveUI();
|
|
3650
|
+
|
|
3651
|
+
if (this._drawer) {
|
|
3652
|
+
if (typeof this._drawer.closeDrawer === "function") {
|
|
3653
|
+
this._drawer.closeDrawer();
|
|
3654
|
+
} else {
|
|
3655
|
+
this._drawer.removeAttribute("open");
|
|
3656
|
+
}
|
|
3657
|
+
}
|
|
3658
|
+
|
|
3659
|
+
this.dispatchEvent(
|
|
3660
|
+
new CustomEvent("pds:live-edit:disable", {
|
|
3661
|
+
bubbles: true,
|
|
3662
|
+
composed: true,
|
|
3663
|
+
detail: { reason: "import-complete" },
|
|
3664
|
+
})
|
|
3665
|
+
);
|
|
3666
|
+
}
|
|
3667
|
+
|
|
3668
|
+
async _applyImportResult(result, options = {}) {
|
|
3669
|
+
if (!result || typeof result !== "object") return;
|
|
3670
|
+
|
|
3671
|
+
const importMode = String(options?.importMode || result?.meta?.importMode || "convert-only");
|
|
3672
|
+
const injectTemplate = options.injectTemplate !== false;
|
|
3673
|
+
const validationBlocked = Boolean(result?.meta?.validationBlocked || result?.meta?.validation?.ok === false);
|
|
3674
|
+
const shouldApplyPatch =
|
|
3675
|
+
options.applyDesignPatch === true ||
|
|
3676
|
+
(options.applyDesignPatch !== false && importMode !== "convert-only" && !validationBlocked);
|
|
3677
|
+
const patch = result.designPatch;
|
|
3678
|
+
const patchKeys =
|
|
3679
|
+
patch && typeof patch === "object" ? Object.keys(patch).filter(Boolean) : [];
|
|
3680
|
+
|
|
3681
|
+
if (shouldApplyPatch && patchKeys.length > 0) {
|
|
3682
|
+
await applyDesignPatch(patch);
|
|
3683
|
+
}
|
|
3684
|
+
|
|
3685
|
+
if (injectTemplate && result.template?.html) {
|
|
3686
|
+
this._injectTemplateIntoCanvas(result.template);
|
|
3687
|
+
}
|
|
3688
|
+
}
|
|
3689
|
+
|
|
2984
3690
|
async _handleFormSubmit(event, form) {
|
|
2985
3691
|
if (!form || typeof form.getValuesFlat !== "function") return;
|
|
2986
3692
|
|
|
@@ -3007,8 +3713,16 @@ class PdsLiveEdit extends HTMLElement {
|
|
|
3007
3713
|
: typeof form._normalizeFlatValues === "function"
|
|
3008
3714
|
? form._normalizeFlatValues(form.getValuesFlat())
|
|
3009
3715
|
: form.getValuesFlat();
|
|
3010
|
-
const
|
|
3716
|
+
const sanitizedFlatValues = {};
|
|
3011
3717
|
Object.entries(flatValues || {}).forEach(([path, value]) => {
|
|
3718
|
+
if (path === FORM_THEME_CONTEXT_POINTER || path === FORM_THEME_CONTEXT_FIELD) {
|
|
3719
|
+
return;
|
|
3720
|
+
}
|
|
3721
|
+
sanitizedFlatValues[path] = value;
|
|
3722
|
+
});
|
|
3723
|
+
|
|
3724
|
+
const patch = {};
|
|
3725
|
+
Object.entries(sanitizedFlatValues).forEach(([path, value]) => {
|
|
3012
3726
|
setValueAtJsonPath(patch, path, value);
|
|
3013
3727
|
});
|
|
3014
3728
|
await applyDesignPatch(patch);
|