@pure-ds/core 0.5.60 → 0.6.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.
Files changed (43) hide show
  1. package/dist/types/packages/pds-configurator/src/pds-home-content.d.ts +375 -0
  2. package/dist/types/packages/pds-configurator/src/pds-home-content.d.ts.map +1 -0
  3. package/dist/types/packages/pds-configurator/src/pds-home.d.ts +2 -0
  4. package/dist/types/packages/pds-configurator/src/pds-home.d.ts.map +1 -0
  5. package/dist/types/pds.config.d.ts +4 -8
  6. package/dist/types/pds.config.d.ts.map +1 -1
  7. package/dist/types/pds.d.ts +3 -1
  8. package/dist/types/public/assets/js/pds-manager.d.ts.map +1 -1
  9. package/dist/types/public/assets/js/pds.d.ts.map +1 -1
  10. package/dist/types/public/assets/pds/components/pds-live-edit.d.ts +150 -0
  11. package/dist/types/public/assets/pds/components/pds-live-edit.d.ts.map +1 -0
  12. package/dist/types/public/assets/pds/components/pds-omnibox.d.ts +2 -0
  13. package/dist/types/public/assets/pds/components/pds-omnibox.d.ts.map +1 -1
  14. package/dist/types/public/assets/pds/components/pds-richtext.d.ts.map +1 -1
  15. package/dist/types/public/assets/pds/components/pds-theme.d.ts +5 -0
  16. package/dist/types/public/assets/pds/components/pds-theme.d.ts.map +1 -1
  17. package/dist/types/src/js/pds-core/pds-config.d.ts +457 -0
  18. package/dist/types/src/js/pds-core/pds-config.d.ts.map +1 -1
  19. package/dist/types/src/js/pds-core/pds-enhancers.d.ts.map +1 -1
  20. package/dist/types/src/js/pds-core/pds-live.d.ts.map +1 -1
  21. package/dist/types/src/js/pds-core/pds-ontology.d.ts.map +1 -1
  22. package/dist/types/src/js/pds-core/pds-start-helpers.d.ts.map +1 -1
  23. package/dist/types/src/js/pds-core/pds-theme-utils.d.ts +6 -0
  24. package/dist/types/src/js/pds-core/pds-theme-utils.d.ts.map +1 -0
  25. package/dist/types/src/js/pds.d.ts.map +1 -1
  26. package/package.json +1 -4
  27. package/packages/pds-cli/bin/templates/bootstrap/pds.config.js +9 -2
  28. package/public/assets/js/app.js +106 -5636
  29. package/public/assets/js/pds-manager.js +156 -156
  30. package/public/assets/js/pds.js +7 -7
  31. package/public/assets/pds/components/pds-live-edit.js +1555 -0
  32. package/public/assets/pds/components/pds-omnibox.js +558 -369
  33. package/public/assets/pds/components/pds-richtext.js +57 -7
  34. package/public/assets/pds/components/pds-theme.js +58 -0
  35. package/readme.md +2 -2
  36. package/src/js/pds-core/pds-config.js +705 -1
  37. package/src/js/pds-core/pds-enhancers.js +61 -4
  38. package/src/js/pds-core/pds-live.js +545 -437
  39. package/src/js/pds-core/pds-ontology.js +8 -0
  40. package/src/js/pds-core/pds-start-helpers.js +15 -0
  41. package/src/js/pds-core/pds-theme-utils.js +33 -0
  42. package/src/js/pds.d.ts +3 -1
  43. package/src/js/pds.js +22 -0
@@ -1,437 +1,545 @@
1
- /**
2
- * Live-mode initialization and API surface for PDS.
3
- * Separated to keep the base runtime bundle lean for production/static usage.
4
- */
5
- import { Generator } from "./pds-generator.js";
6
- import { applyStyles, adoptLayers, adoptPrimitives } from "./pds-runtime.js";
7
- import { presets, defaultLog } from "./pds-config.js";
8
- import { defaultPDSEnhancers } from "./pds-enhancers.js";
9
- import { defaultPDSEnhancerMetadata } from "./pds-enhancers-meta.js";
10
- import { resolvePublicAssetURL } from "./pds-paths.js";
11
- import { loadTypographyFonts } from "../common/font-loader.js";
12
- import {
13
- ensureAbsoluteAssetURL,
14
- ensureTrailingSlash,
15
- attachFoucListener,
16
- normalizeInitConfig,
17
- resolveRuntimeAssetRoot,
18
- resolveThemeAndApply,
19
- setupAutoDefinerAndEnhancers,
20
- stripFunctions,
21
- } from "./pds-start-helpers.js";
22
-
23
- let __liveApiReady = false;
24
- let __queryClass = null;
25
- const BROADCAST_CHANNEL_NAME = "pds-configurator";
26
- let __broadcastChannel = null;
27
- let __broadcastId = null;
28
- let __broadcastListenerAttached = false;
29
-
30
- function __getBroadcastChannel() {
31
- if (typeof BroadcastChannel === "undefined") return null;
32
- if (!__broadcastChannel) {
33
- __broadcastChannel = new BroadcastChannel(BROADCAST_CHANNEL_NAME);
34
- }
35
- if (!__broadcastId) {
36
- __broadcastId = `pds-${Math.random().toString(36).slice(2)}`;
37
- }
38
- return __broadcastChannel;
39
- }
40
-
41
- async function __attachLiveAPIs(PDS, { applyResolvedTheme, setupSystemListenerIfNeeded }) {
42
- if (__liveApiReady) return;
43
-
44
- const [ontologyModule, enumsModule, queryModule, commonModule] =
45
- await Promise.all([
46
- import("./pds-ontology.js"),
47
- import("./pds-enums.js"),
48
- import("./pds-query.js"),
49
- import("../common/common.js"),
50
- ]);
51
-
52
- const ontology = ontologyModule?.default || ontologyModule?.ontology;
53
- const findComponentForElement = ontologyModule?.findComponentForElement;
54
- const enums = enumsModule?.enums;
55
- __queryClass = queryModule?.PDSQuery || queryModule?.default || null;
56
-
57
- // Expose live-only APIs
58
- PDS.ontology = ontology;
59
- PDS.findComponentForElement = findComponentForElement;
60
- PDS.enums = enums;
61
- PDS.common = commonModule || {};
62
- PDS.presets = presets;
63
- PDS.enhancerMetadata = defaultPDSEnhancerMetadata;
64
- PDS.applyStyles = function(generator) {
65
- return applyStyles(generator || Generator.instance);
66
- };
67
- PDS.adoptLayers = function(shadowRoot, layers, additionalSheets) {
68
- return adoptLayers(
69
- shadowRoot,
70
- layers,
71
- additionalSheets,
72
- Generator.instance
73
- );
74
- };
75
- PDS.adoptPrimitives = function(shadowRoot, additionalSheets) {
76
- return adoptPrimitives(shadowRoot, additionalSheets, Generator.instance);
77
- };
78
- PDS.getGenerator = async function() {
79
- return Generator;
80
- };
81
- PDS.query = async function(question) {
82
- if (!__queryClass) {
83
- const mod = await import("./pds-query.js");
84
- __queryClass = mod?.PDSQuery || mod?.default || null;
85
- }
86
- if (!__queryClass) return [];
87
- const queryEngine = new __queryClass(PDS);
88
- return await queryEngine.search(question);
89
- };
90
-
91
- // Live-only compiled getter
92
- if (!Object.getOwnPropertyDescriptor(PDS, "compiled")) {
93
- Object.defineProperty(PDS, "compiled", {
94
- get() {
95
- if (PDS.registry?.isLive && Generator.instance) {
96
- return Generator.instance.compiled;
97
- }
98
- return null;
99
- },
100
- enumerable: true,
101
- configurable: false,
102
- });
103
- }
104
-
105
- // Live-only preload helper
106
- PDS.preloadCritical = function(config, options = {}) {
107
- if (typeof window === "undefined" || !document.head || !config) {
108
- return;
109
- }
110
-
111
- const { theme, layers = ["tokens"] } = options;
112
-
113
- try {
114
- let resolvedTheme = theme || "light";
115
- if (theme === "system" || !theme) {
116
- const prefersDark =
117
- window.matchMedia &&
118
- window.matchMedia("(prefers-color-scheme: dark)").matches;
119
- resolvedTheme = prefersDark ? "dark" : "light";
120
- }
121
-
122
- document.documentElement.setAttribute("data-theme", resolvedTheme);
123
-
124
- const tempConfig = config.design
125
- ? { ...config, theme: resolvedTheme }
126
- : { design: config, theme: resolvedTheme };
127
- const tempGenerator = new Generator(tempConfig);
128
-
129
- const criticalCSS = layers
130
- .map((layer) => {
131
- try {
132
- return tempGenerator.css?.[layer] || "";
133
- } catch (e) {
134
- return "";
135
- }
136
- })
137
- .filter((css) => css.trim())
138
- .join("\n");
139
-
140
- if (criticalCSS) {
141
- const existing = document.head.querySelector("style[data-pds-preload]");
142
- if (existing) existing.remove();
143
-
144
- const styleEl = document.createElement("style");
145
- styleEl.setAttribute("data-pds-preload", "");
146
- styleEl.textContent = criticalCSS;
147
- document.head.insertBefore(styleEl, document.head.firstChild);
148
- }
149
- } catch (error) {
150
- console.warn("PDS preload failed:", error);
151
- }
152
- };
153
-
154
- __liveApiReady = true;
155
- }
156
-
157
-
158
- export async function startLive(PDS, config, { emitReady, applyResolvedTheme, setupSystemListenerIfNeeded }) {
159
- if (!config || typeof config !== "object") {
160
- throw new Error(
161
- "PDS.start({ mode: 'live', ... }) requires a valid configuration object"
162
- );
163
- }
164
-
165
- // Attach live-only API surface (ontology, presets, query, etc.)
166
- await __attachLiveAPIs(PDS, { applyResolvedTheme, setupSystemListenerIfNeeded });
167
- attachFoucListener(PDS);
168
-
169
- // FOUC Prevention: Use constructable stylesheet for synchronous, immediate effect
170
- if (typeof document !== "undefined" && document.adoptedStyleSheets) {
171
- const css = /*css*/`
172
- html { opacity: 0; }
173
- html.pds-ready { opacity: 1; transition: opacity 0.3s ease-in; }
174
- `;
175
- try {
176
- const hasFoucSheet = document.adoptedStyleSheets.some((sheet) => sheet._pdsFouc);
177
- if (!hasFoucSheet) {
178
- const foucSheet = new CSSStyleSheet();
179
- foucSheet.replaceSync(css);
180
- foucSheet._pdsFouc = true;
181
- document.adoptedStyleSheets = [foucSheet, ...document.adoptedStyleSheets];
182
- }
183
- } catch (e) {
184
- console.warn("Constructable stylesheets not supported, using <style> tag fallback:", e);
185
- const existingFoucStyle = document.head.querySelector("style[data-pds-fouc]");
186
- if (!existingFoucStyle) {
187
- const foucStyle = document.createElement("style");
188
- foucStyle.setAttribute("data-pds-fouc", "");
189
- foucStyle.textContent = css;
190
- document.head.insertBefore(foucStyle, document.head.firstChild);
191
- }
192
- }
193
- }
194
-
195
- // Extract runtime flags directly from unified config
196
- let applyGlobalStyles = config.applyGlobalStyles ?? true;
197
- let manageTheme = config.manageTheme ?? true;
198
- let themeStorageKey = config.themeStorageKey ?? "pure-ds-theme";
199
- let preloadStyles = config.preloadStyles ?? false;
200
- let criticalLayers = config.criticalLayers ?? ["tokens", "primitives"];
201
-
202
- let applyConfiguratorStyles = config.applyConfiguratorStyles ?? false;
203
-
204
- if(applyConfiguratorStyles)
205
- console.warn("📢 This app is listening to PDS Configurator change broadcasting and will immediately apply configurator styles");
206
-
207
- const cfgAuto = (config && config.autoDefine) || null;
208
-
209
- try {
210
- // 1) Handle theme preference
211
- const { resolvedTheme } = resolveThemeAndApply({
212
- manageTheme,
213
- themeStorageKey,
214
- applyResolvedTheme,
215
- setupSystemListenerIfNeeded,
216
- });
217
-
218
- // 2) Normalize first-arg API: support { preset, design, enhancers }
219
- const normalized = normalizeInitConfig(config, {}, { presets, defaultLog });
220
- const userEnhancers = normalized.enhancers;
221
- const { log: logFn, ...configToClone } = normalized.generatorConfig;
222
- const generatorConfig = structuredClone(configToClone);
223
- generatorConfig.log = logFn;
224
- if (manageTheme) {
225
- generatorConfig.theme = resolvedTheme;
226
- }
227
-
228
- const generator = new Generator(generatorConfig);
229
-
230
- // 3) Load fonts from Google Fonts if needed (before applying styles)
231
- if (generatorConfig.design?.typography) {
232
- try {
233
- await loadTypographyFonts(generatorConfig.design.typography);
234
- } catch (ex) {
235
- generatorConfig?.log?.("warn", "Failed to load some fonts from Google Fonts:", ex);
236
- }
237
- }
238
-
239
- // 4) Preload critical styles synchronously to prevent flash
240
- if (preloadStyles && typeof window !== "undefined" && document.head) {
241
- try {
242
- const criticalCSS = criticalLayers
243
- .map((layer) => {
244
- try {
245
- return generator.css?.[layer] || "";
246
- } catch (e) {
247
- generatorConfig?.log?.(
248
- "warn",
249
- `Failed to generate critical CSS for layer "${layer}":`,
250
- e
251
- );
252
- return "";
253
- }
254
- })
255
- .filter((css) => css.trim())
256
- .join("\n");
257
-
258
- if (criticalCSS) {
259
- const existingCritical = document.head.querySelector(
260
- "style[data-pds-critical]"
261
- );
262
- if (existingCritical) {
263
- existingCritical.remove();
264
- }
265
-
266
- const styleEl = document.createElement("style");
267
- styleEl.setAttribute("data-pds-critical", "");
268
- styleEl.textContent = criticalCSS;
269
-
270
- const insertAfter = document.head.querySelector(
271
- 'meta[charset], meta[name="viewport"]'
272
- );
273
- if (insertAfter) {
274
- insertAfter.parentNode.insertBefore(
275
- styleEl,
276
- insertAfter.nextSibling
277
- );
278
- } else {
279
- document.head.insertBefore(styleEl, document.head.firstChild);
280
- }
281
- }
282
- } catch (error) {
283
- generatorConfig?.log?.("warn", "Failed to preload critical styles:", error);
284
- }
285
- }
286
-
287
- // Set the registry to live mode
288
- PDS.registry.setLiveMode();
289
-
290
- // Log preset info if available
291
- if (normalized.presetInfo?.name) {
292
- generatorConfig?.log?.("log", `PDS live with preset "${normalized.presetInfo.name}"`);
293
- } else {
294
- generatorConfig?.log?.("log", "PDS live with custom config");
295
- }
296
-
297
- // Apply styles globally if requested (default behavior)
298
- if (applyGlobalStyles) {
299
- await applyStyles(Generator.instance);
300
-
301
- if (typeof window !== "undefined") {
302
- setTimeout(() => {
303
- const criticalStyle = document.head.querySelector(
304
- "style[data-pds-critical]"
305
- );
306
- if (criticalStyle) criticalStyle.remove();
307
-
308
- const preloadStyle = document.head.querySelector(
309
- "style[data-pds-preload]"
310
- );
311
- if (preloadStyle) preloadStyle.remove();
312
-
313
- const legacyRuntime = document.getElementById(
314
- "pds-runtime-stylesheet"
315
- );
316
- if (legacyRuntime) legacyRuntime.remove();
317
- }, 100);
318
- }
319
- }
320
-
321
- const assetRootURL = resolveRuntimeAssetRoot(config, { resolvePublicAssetURL });
322
-
323
- let derivedAutoDefineBaseURL;
324
- if (cfgAuto && cfgAuto.baseURL) {
325
- derivedAutoDefineBaseURL = ensureTrailingSlash(
326
- ensureAbsoluteAssetURL(cfgAuto.baseURL, { preferModule: false })
327
- );
328
- } else {
329
- derivedAutoDefineBaseURL = `${assetRootURL}components/`;
330
- }
331
-
332
- // 5) Set up AutoDefiner + run enhancers (defaults merged with user)
333
- let autoDefiner = null;
334
- let mergedEnhancers = [];
335
-
336
- try {
337
- const res = await setupAutoDefinerAndEnhancers({
338
- autoDefineBaseURL: derivedAutoDefineBaseURL,
339
- autoDefinePreload:
340
- (cfgAuto && Array.isArray(cfgAuto.predefine) && cfgAuto.predefine) ||
341
- [],
342
- autoDefineMapper:
343
- (cfgAuto && typeof cfgAuto.mapper === "function" && cfgAuto.mapper) ||
344
- null,
345
- enhancers: userEnhancers,
346
- autoDefineOverrides: cfgAuto || null,
347
- autoDefinePreferModule: !(cfgAuto && cfgAuto.baseURL),
348
- }, { baseEnhancers: defaultPDSEnhancers });
349
- autoDefiner = res.autoDefiner;
350
- mergedEnhancers = res.mergedEnhancers || [];
351
-
352
- } catch (error) {
353
- generatorConfig?.log?.("error", "❌ Failed to initialize AutoDefiner/Enhancers:", error);
354
- }
355
-
356
- const resolvedConfig = generator?.options || generatorConfig;
357
-
358
- const cloneableConfig = stripFunctions(config);
359
- PDS.currentConfig = Object.freeze({
360
- mode: "live",
361
- ...structuredClone(cloneableConfig),
362
- design: structuredClone(normalized.generatorConfig.design),
363
- preset: normalized.generatorConfig.preset,
364
- theme: resolvedTheme,
365
- enhancers: mergedEnhancers,
366
- });
367
-
368
- if (applyConfiguratorStyles) {
369
- const channel = __getBroadcastChannel();
370
- if (!channel) {
371
- console.warn("[PDS Live] BroadcastChannel unavailable; configurator updates will not be received.");
372
- }
373
- if (channel && !__broadcastListenerAttached) {
374
- __broadcastListenerAttached = true;
375
- console.log("[PDS Live] Listening for configurator broadcasts.");
376
- channel.addEventListener("message", async (event) => {
377
- try {
378
- const data = event?.data;
379
- if (!data || data.type !== "pds:configurator:design") return;
380
- if (data.sourceId && data.sourceId === __broadcastId) return;
381
-
382
- console.log("[PDS Live] Received configurator broadcast.");
383
-
384
- const incomingConfig = data.payload?.config;
385
- if (!incomingConfig || typeof incomingConfig !== "object") return;
386
-
387
- const incomingTheme = data.payload?.theme || null;
388
- if (incomingTheme) {
389
- try {
390
- PDS.theme = incomingTheme;
391
- } catch (ex) {
392
- /* ignore theme errors */
393
- }
394
- }
395
-
396
- if (incomingConfig.typography) {
397
- try {
398
- await loadTypographyFonts(incomingConfig.typography);
399
- } catch (ex) {
400
- /* ignore font loading errors */
401
- }
402
- }
403
-
404
- const generatorOptions = {
405
- design: structuredClone(incomingConfig),
406
- };
407
- if (incomingTheme) generatorOptions.theme = incomingTheme;
408
-
409
- const incomingGenerator = new Generator(generatorOptions);
410
- applyStyles(incomingGenerator);
411
- console.log("[PDS Live] Applied configurator styles from broadcast.");
412
- } catch (ex) {
413
- console.warn("Failed to apply broadcasted configurator styles:", ex);
414
- }
415
- });
416
- }
417
- }
418
-
419
- emitReady({
420
- mode: "live",
421
- generator,
422
- config: resolvedConfig,
423
- theme: resolvedTheme,
424
- autoDefiner,
425
- });
426
-
427
- return {
428
- generator,
429
- config: resolvedConfig,
430
- theme: resolvedTheme,
431
- autoDefiner,
432
- };
433
- } catch (error) {
434
- PDS.dispatchEvent(new CustomEvent("pds:error", { detail: { error } }));
435
- throw error;
436
- }
437
- }
1
+ /**
2
+ * Live-mode initialization and API surface for PDS.
3
+ * Separated to keep the base runtime bundle lean for production/static usage.
4
+ */
5
+ import { Generator } from "./pds-generator.js";
6
+ import { applyStyles, adoptLayers, adoptPrimitives } from "./pds-runtime.js";
7
+ import { presets, defaultLog, PDS_CONFIG_RELATIONS } from "./pds-config.js";
8
+ import { defaultPDSEnhancers } from "./pds-enhancers.js";
9
+ import { defaultPDSEnhancerMetadata } from "./pds-enhancers-meta.js";
10
+ import { resolvePublicAssetURL } from "./pds-paths.js";
11
+ import { loadTypographyFonts } from "../common/font-loader.js";
12
+ import {
13
+ ensureAbsoluteAssetURL,
14
+ ensureTrailingSlash,
15
+ attachFoucListener,
16
+ normalizeInitConfig,
17
+ resolveRuntimeAssetRoot,
18
+ resolveThemeAndApply,
19
+ setupAutoDefinerAndEnhancers,
20
+ stripFunctions,
21
+ } from "./pds-start-helpers.js";
22
+ import {
23
+ isPresetThemeCompatible,
24
+ resolveThemePreference,
25
+ } from "./pds-theme-utils.js";
26
+
27
+ let __liveApiReady = false;
28
+ let __queryClass = null;
29
+
30
+ function getStoredLiveConfig() {
31
+ if (typeof window === "undefined" || !window.localStorage) return null;
32
+ try {
33
+ const raw = window.localStorage.getItem("pure-ds-config");
34
+ if (!raw) return null;
35
+ const parsed = JSON.parse(raw);
36
+ if (parsed && ("preset" in parsed || "design" in parsed)) return parsed;
37
+ } catch (e) {
38
+ return null;
39
+ }
40
+ return null;
41
+ }
42
+
43
+ function deepMergeConfig(target = {}, source = {}) {
44
+ if (!source || typeof source !== "object") return target;
45
+ const out = Array.isArray(target) ? [...target] : { ...target };
46
+ for (const [key, value] of Object.entries(source)) {
47
+ if (value && typeof value === "object" && !Array.isArray(value)) {
48
+ out[key] = deepMergeConfig(
49
+ out[key] && typeof out[key] === "object" ? out[key] : {},
50
+ value
51
+ );
52
+ } else {
53
+ out[key] = value;
54
+ }
55
+ }
56
+ return out;
57
+ }
58
+
59
+ function applyStoredConfigOverrides(baseConfig) {
60
+ const stored = getStoredLiveConfig();
61
+ if (!stored || !baseConfig || typeof baseConfig !== "object") return baseConfig;
62
+
63
+ const storedPreset = stored.preset;
64
+ const storedDesign =
65
+ stored.design && typeof stored.design === "object" ? stored.design : null;
66
+
67
+ if (!storedPreset && !storedDesign) return baseConfig;
68
+
69
+ const hasNewShape =
70
+ "preset" in baseConfig || "design" in baseConfig || "enhancers" in baseConfig;
71
+
72
+ let nextConfig = { ...baseConfig };
73
+
74
+ if (storedPreset) {
75
+ nextConfig.preset = storedPreset;
76
+ }
77
+
78
+ if (storedDesign) {
79
+ if (hasNewShape) {
80
+ const baseDesign =
81
+ baseConfig.design && typeof baseConfig.design === "object"
82
+ ? baseConfig.design
83
+ : {};
84
+ nextConfig.design = deepMergeConfig(baseDesign, storedDesign);
85
+ } else {
86
+ nextConfig = deepMergeConfig(baseConfig, storedDesign);
87
+ }
88
+ }
89
+
90
+ return nextConfig;
91
+ }
92
+
93
+ async function __attachLiveAPIs(PDS, { applyResolvedTheme, setupSystemListenerIfNeeded }) {
94
+ if (__liveApiReady) return;
95
+
96
+ const [ontologyModule, enumsModule, queryModule, commonModule] =
97
+ await Promise.all([
98
+ import("./pds-ontology.js"),
99
+ import("./pds-enums.js"),
100
+ import("./pds-query.js"),
101
+ import("../common/common.js"),
102
+ ]);
103
+
104
+ const ontology = ontologyModule?.default || ontologyModule?.ontology;
105
+ const findComponentForElement = ontologyModule?.findComponentForElement;
106
+ const enums = enumsModule?.enums;
107
+ __queryClass = queryModule?.PDSQuery || queryModule?.default || null;
108
+
109
+ // Expose live-only APIs
110
+ PDS.ontology = ontology;
111
+ PDS.findComponentForElement = findComponentForElement;
112
+ PDS.enums = enums;
113
+ PDS.common = commonModule || {};
114
+ PDS.presets = presets;
115
+ PDS.configRelations = PDS_CONFIG_RELATIONS;
116
+ PDS.enhancerMetadata = defaultPDSEnhancerMetadata;
117
+ PDS.applyStyles = function(generator) {
118
+ return applyStyles(generator || Generator.instance);
119
+ };
120
+ PDS.adoptLayers = function(shadowRoot, layers, additionalSheets) {
121
+ return adoptLayers(
122
+ shadowRoot,
123
+ layers,
124
+ additionalSheets,
125
+ Generator.instance
126
+ );
127
+ };
128
+ PDS.adoptPrimitives = function(shadowRoot, additionalSheets) {
129
+ return adoptPrimitives(shadowRoot, additionalSheets, Generator.instance);
130
+ };
131
+ PDS.getGenerator = async function() {
132
+ return Generator;
133
+ };
134
+ PDS.query = async function(question) {
135
+ if (!__queryClass) {
136
+ const mod = await import("./pds-query.js");
137
+ __queryClass = mod?.PDSQuery || mod?.default || null;
138
+ }
139
+ if (!__queryClass) return [];
140
+ const queryEngine = new __queryClass(PDS);
141
+ return await queryEngine.search(question);
142
+ };
143
+
144
+ PDS.applyLivePreset = async function(presetId, options = {}) {
145
+ if (!presetId) return false;
146
+ if (!PDS.registry?.isLive) {
147
+ console.warn("PDS.applyLivePreset is only available in live mode.");
148
+ return false;
149
+ }
150
+
151
+ const baseConfig = PDS.currentConfig || {};
152
+ const { design: _design, preset: _preset, ...rest } = baseConfig;
153
+ const inputConfig = {
154
+ ...structuredClone(stripFunctions(rest)),
155
+ preset: presetId,
156
+ };
157
+
158
+ const normalized = normalizeInitConfig(inputConfig, {}, {
159
+ presets,
160
+ defaultLog,
161
+ });
162
+
163
+ const resolvedTheme = resolveThemePreference(PDS.theme);
164
+ if (!isPresetThemeCompatible(normalized.generatorConfig.design, resolvedTheme)) {
165
+ const presetName =
166
+ normalized.presetInfo?.name ||
167
+ normalized.generatorConfig?.design?.name ||
168
+ presetId;
169
+ console.warn(
170
+ `PDS theme "${resolvedTheme}" not supported by preset "${presetName}".`
171
+ );
172
+ }
173
+
174
+ if (baseConfig.theme && !normalized.generatorConfig.theme) {
175
+ normalized.generatorConfig.theme = baseConfig.theme;
176
+ }
177
+
178
+ const generator = new Generator(normalized.generatorConfig);
179
+
180
+ if (normalized.generatorConfig.design?.typography) {
181
+ try {
182
+ await loadTypographyFonts(normalized.generatorConfig.design.typography);
183
+ } catch (error) {
184
+ normalized.generatorConfig?.log?.(
185
+ "warn",
186
+ "Failed to load some fonts from Google Fonts:",
187
+ error,
188
+ );
189
+ }
190
+ }
191
+
192
+ await applyStyles(generator);
193
+
194
+ const presetInfo = normalized.presetInfo || { id: presetId, name: presetId };
195
+ PDS.currentPreset = presetInfo;
196
+ PDS.currentConfig = Object.freeze({
197
+ ...baseConfig,
198
+ preset: normalized.generatorConfig.preset,
199
+ design: structuredClone(normalized.generatorConfig.design),
200
+ theme: normalized.generatorConfig.theme || baseConfig.theme,
201
+ });
202
+
203
+ const persist = options?.persist !== false;
204
+ if (persist && typeof window !== "undefined") {
205
+ const storageKey = "pure-ds-config";
206
+ try {
207
+ const storedRaw = localStorage.getItem(storageKey);
208
+ const storedParsed = storedRaw ? JSON.parse(storedRaw) : null;
209
+ const nextStored = {
210
+ ...(storedParsed && typeof storedParsed === "object"
211
+ ? storedParsed
212
+ : {}),
213
+ preset: presetInfo.id || presetId,
214
+ design: structuredClone(normalized.generatorConfig.design || {}),
215
+ };
216
+ localStorage.setItem(storageKey, JSON.stringify(nextStored));
217
+ } catch (error) {
218
+ normalized.generatorConfig?.log?.(
219
+ "warn",
220
+ "Failed to store preset:",
221
+ error,
222
+ );
223
+ }
224
+ }
225
+
226
+ return true;
227
+ };
228
+
229
+ // Live-only compiled getter
230
+ if (!Object.getOwnPropertyDescriptor(PDS, "compiled")) {
231
+ Object.defineProperty(PDS, "compiled", {
232
+ get() {
233
+ if (PDS.registry?.isLive && Generator.instance) {
234
+ return Generator.instance.compiled;
235
+ }
236
+ return null;
237
+ },
238
+ enumerable: true,
239
+ configurable: false,
240
+ });
241
+ }
242
+
243
+ // Live-only preload helper
244
+ PDS.preloadCritical = function(config, options = {}) {
245
+ if (typeof window === "undefined" || !document.head || !config) {
246
+ return;
247
+ }
248
+
249
+ const { theme, layers = ["tokens"] } = options;
250
+
251
+ try {
252
+ let resolvedTheme = theme || "light";
253
+ if (theme === "system" || !theme) {
254
+ const prefersDark =
255
+ window.matchMedia &&
256
+ window.matchMedia("(prefers-color-scheme: dark)").matches;
257
+ resolvedTheme = prefersDark ? "dark" : "light";
258
+ }
259
+
260
+ document.documentElement.setAttribute("data-theme", resolvedTheme);
261
+
262
+ const tempConfig = config.design
263
+ ? { ...config, theme: resolvedTheme }
264
+ : { design: config, theme: resolvedTheme };
265
+ const tempGenerator = new Generator(tempConfig);
266
+
267
+ const criticalCSS = layers
268
+ .map((layer) => {
269
+ try {
270
+ return tempGenerator.css?.[layer] || "";
271
+ } catch (e) {
272
+ return "";
273
+ }
274
+ })
275
+ .filter((css) => css.trim())
276
+ .join("\n");
277
+
278
+ if (criticalCSS) {
279
+ const existing = document.head.querySelector("style[data-pds-preload]");
280
+ if (existing) existing.remove();
281
+
282
+ const styleEl = document.createElement("style");
283
+ styleEl.setAttribute("data-pds-preload", "");
284
+ styleEl.textContent = criticalCSS;
285
+ document.head.insertBefore(styleEl, document.head.firstChild);
286
+ }
287
+ } catch (error) {
288
+ console.warn("PDS preload failed:", error);
289
+ }
290
+ };
291
+
292
+ __liveApiReady = true;
293
+ }
294
+
295
+
296
+ export async function startLive(PDS, config, { emitReady, applyResolvedTheme, setupSystemListenerIfNeeded }) {
297
+ if (!config || typeof config !== "object") {
298
+ throw new Error(
299
+ "PDS.start({ mode: 'live', ... }) requires a valid configuration object"
300
+ );
301
+ }
302
+
303
+ config = applyStoredConfigOverrides(config);
304
+
305
+ // Attach live-only API surface (ontology, presets, query, etc.)
306
+ await __attachLiveAPIs(PDS, { applyResolvedTheme, setupSystemListenerIfNeeded });
307
+ attachFoucListener(PDS);
308
+
309
+ // FOUC Prevention: Use constructable stylesheet for synchronous, immediate effect
310
+ if (typeof document !== "undefined" && document.adoptedStyleSheets) {
311
+ const css = /*css*/`
312
+ html { opacity: 0; }
313
+ html.pds-ready { opacity: 1; transition: opacity 0.3s ease-in; }
314
+ `;
315
+ try {
316
+ const hasFoucSheet = document.adoptedStyleSheets.some((sheet) => sheet._pdsFouc);
317
+ if (!hasFoucSheet) {
318
+ const foucSheet = new CSSStyleSheet();
319
+ foucSheet.replaceSync(css);
320
+ foucSheet._pdsFouc = true;
321
+ document.adoptedStyleSheets = [foucSheet, ...document.adoptedStyleSheets];
322
+ }
323
+ } catch (e) {
324
+ console.warn("Constructable stylesheets not supported, using <style> tag fallback:", e);
325
+ const existingFoucStyle = document.head.querySelector("style[data-pds-fouc]");
326
+ if (!existingFoucStyle) {
327
+ const foucStyle = document.createElement("style");
328
+ foucStyle.setAttribute("data-pds-fouc", "");
329
+ foucStyle.textContent = css;
330
+ document.head.insertBefore(foucStyle, document.head.firstChild);
331
+ }
332
+ }
333
+ }
334
+
335
+ // Extract runtime flags directly from unified config
336
+ let applyGlobalStyles = config.applyGlobalStyles ?? true;
337
+ let manageTheme = config.manageTheme ?? true;
338
+ let themeStorageKey = config.themeStorageKey ?? "pure-ds-theme";
339
+ let preloadStyles = config.preloadStyles ?? false;
340
+ let criticalLayers = config.criticalLayers ?? ["tokens", "primitives"];
341
+
342
+ const cfgAuto = (config && config.autoDefine) || null;
343
+
344
+ try {
345
+ // 1) Handle theme preference
346
+ const { resolvedTheme } = resolveThemeAndApply({
347
+ manageTheme,
348
+ themeStorageKey,
349
+ applyResolvedTheme,
350
+ setupSystemListenerIfNeeded,
351
+ });
352
+
353
+ // 2) Normalize first-arg API: support { preset, design, enhancers }
354
+ const normalized = normalizeInitConfig(config, {}, { presets, defaultLog });
355
+ if (manageTheme && !isPresetThemeCompatible(normalized.generatorConfig.design, resolvedTheme)) {
356
+ const presetName =
357
+ normalized.presetInfo?.name ||
358
+ normalized.generatorConfig?.design?.name ||
359
+ normalized.generatorConfig?.preset ||
360
+ "current preset";
361
+ console.warn(
362
+ `PDS theme "${resolvedTheme}" not supported by preset "${presetName}".`
363
+ );
364
+ }
365
+ const userEnhancers = normalized.enhancers;
366
+ const { log: logFn, ...configToClone } = normalized.generatorConfig;
367
+ const generatorConfig = structuredClone(configToClone);
368
+ generatorConfig.log = logFn;
369
+ if (manageTheme) {
370
+ generatorConfig.theme = resolvedTheme;
371
+ }
372
+
373
+ const generator = new Generator(generatorConfig);
374
+
375
+ // 3) Load fonts from Google Fonts if needed (before applying styles)
376
+ if (generatorConfig.design?.typography) {
377
+ try {
378
+ await loadTypographyFonts(generatorConfig.design.typography);
379
+ } catch (ex) {
380
+ generatorConfig?.log?.("warn", "Failed to load some fonts from Google Fonts:", ex);
381
+ }
382
+ }
383
+
384
+ // 4) Preload critical styles synchronously to prevent flash
385
+ if (preloadStyles && typeof window !== "undefined" && document.head) {
386
+ try {
387
+ const criticalCSS = criticalLayers
388
+ .map((layer) => {
389
+ try {
390
+ return generator.css?.[layer] || "";
391
+ } catch (e) {
392
+ generatorConfig?.log?.(
393
+ "warn",
394
+ `Failed to generate critical CSS for layer "${layer}":`,
395
+ e
396
+ );
397
+ return "";
398
+ }
399
+ })
400
+ .filter((css) => css.trim())
401
+ .join("\n");
402
+
403
+ if (criticalCSS) {
404
+ const existingCritical = document.head.querySelector(
405
+ "style[data-pds-critical]"
406
+ );
407
+ if (existingCritical) {
408
+ existingCritical.remove();
409
+ }
410
+
411
+ const styleEl = document.createElement("style");
412
+ styleEl.setAttribute("data-pds-critical", "");
413
+ styleEl.textContent = criticalCSS;
414
+
415
+ const insertAfter = document.head.querySelector(
416
+ 'meta[charset], meta[name="viewport"]'
417
+ );
418
+ if (insertAfter) {
419
+ insertAfter.parentNode.insertBefore(
420
+ styleEl,
421
+ insertAfter.nextSibling
422
+ );
423
+ } else {
424
+ document.head.insertBefore(styleEl, document.head.firstChild);
425
+ }
426
+ }
427
+ } catch (error) {
428
+ generatorConfig?.log?.("warn", "Failed to preload critical styles:", error);
429
+ }
430
+ }
431
+
432
+ // Set the registry to live mode
433
+ PDS.registry.setLiveMode();
434
+
435
+ // Log preset info if available
436
+ if (normalized.presetInfo?.name) {
437
+ generatorConfig?.log?.("log", `PDS live with preset "${normalized.presetInfo.name}"`);
438
+ } else {
439
+ generatorConfig?.log?.("log", "PDS live with custom config");
440
+ }
441
+
442
+ // Apply styles globally if requested (default behavior)
443
+ if (applyGlobalStyles) {
444
+ await applyStyles(Generator.instance);
445
+
446
+ if (typeof window !== "undefined") {
447
+ setTimeout(() => {
448
+ const criticalStyle = document.head.querySelector(
449
+ "style[data-pds-critical]"
450
+ );
451
+ if (criticalStyle) criticalStyle.remove();
452
+
453
+ const preloadStyle = document.head.querySelector(
454
+ "style[data-pds-preload]"
455
+ );
456
+ if (preloadStyle) preloadStyle.remove();
457
+
458
+ const legacyRuntime = document.getElementById(
459
+ "pds-runtime-stylesheet"
460
+ );
461
+ if (legacyRuntime) legacyRuntime.remove();
462
+ }, 100);
463
+ }
464
+ }
465
+
466
+ const assetRootURL = resolveRuntimeAssetRoot(config, { resolvePublicAssetURL });
467
+
468
+ let derivedAutoDefineBaseURL;
469
+ if (cfgAuto && cfgAuto.baseURL) {
470
+ derivedAutoDefineBaseURL = ensureTrailingSlash(
471
+ ensureAbsoluteAssetURL(cfgAuto.baseURL, { preferModule: false })
472
+ );
473
+ } else {
474
+ derivedAutoDefineBaseURL = `${assetRootURL}components/`;
475
+ }
476
+
477
+ // 5) Set up AutoDefiner + run enhancers (defaults merged with user)
478
+ let autoDefiner = null;
479
+ let mergedEnhancers = [];
480
+
481
+ try {
482
+ const res = await setupAutoDefinerAndEnhancers({
483
+ autoDefineBaseURL: derivedAutoDefineBaseURL,
484
+ autoDefinePreload:
485
+ (cfgAuto && Array.isArray(cfgAuto.predefine) && cfgAuto.predefine) ||
486
+ [],
487
+ autoDefineMapper:
488
+ (cfgAuto && typeof cfgAuto.mapper === "function" && cfgAuto.mapper) ||
489
+ null,
490
+ enhancers: userEnhancers,
491
+ autoDefineOverrides: cfgAuto || null,
492
+ autoDefinePreferModule: !(cfgAuto && cfgAuto.baseURL),
493
+ }, { baseEnhancers: defaultPDSEnhancers });
494
+ autoDefiner = res.autoDefiner;
495
+ mergedEnhancers = res.mergedEnhancers || [];
496
+
497
+ } catch (error) {
498
+ generatorConfig?.log?.("error", "❌ Failed to initialize AutoDefiner/Enhancers:", error);
499
+ }
500
+
501
+ const resolvedConfig = generator?.options || generatorConfig;
502
+
503
+ const cloneableConfig = stripFunctions(config);
504
+ PDS.currentConfig = Object.freeze({
505
+ mode: "live",
506
+ ...structuredClone(cloneableConfig),
507
+ design: structuredClone(normalized.generatorConfig.design),
508
+ preset: normalized.generatorConfig.preset,
509
+ theme: resolvedTheme,
510
+ enhancers: mergedEnhancers,
511
+ });
512
+
513
+
514
+ if (config?.liveEdit && typeof document !== "undefined") {
515
+ try {
516
+ if (!document.querySelector("pds-live-edit")) {
517
+ setTimeout(() => {
518
+ const liveEditor = document.createElement("pds-live-edit");
519
+ document.body.appendChild(liveEditor);
520
+ }, 1000);
521
+ }
522
+ } catch (error) {
523
+ generatorConfig?.log?.("warn", "Live editor failed to start:", error);
524
+ }
525
+ }
526
+
527
+ emitReady({
528
+ mode: "live",
529
+ generator,
530
+ config: resolvedConfig,
531
+ theme: resolvedTheme,
532
+ autoDefiner,
533
+ });
534
+
535
+ return {
536
+ generator,
537
+ config: resolvedConfig,
538
+ theme: resolvedTheme,
539
+ autoDefiner,
540
+ };
541
+ } catch (error) {
542
+ PDS.dispatchEvent(new CustomEvent("pds:error", { detail: { error } }));
543
+ throw error;
544
+ }
545
+ }