@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.
Files changed (90) hide show
  1. package/custom-elements.json +865 -35
  2. package/dist/types/pds.d.ts +31 -0
  3. package/dist/types/public/assets/js/pds-manager.d.ts +100 -2
  4. package/dist/types/public/assets/js/pds-manager.d.ts.map +1 -1
  5. package/dist/types/public/assets/js/pds.d.ts.map +1 -1
  6. package/dist/types/public/assets/pds/components/pds-form.d.ts.map +1 -1
  7. package/dist/types/public/assets/pds/components/pds-live-converter.d.ts +8 -0
  8. package/dist/types/public/assets/pds/components/pds-live-converter.d.ts.map +1 -0
  9. package/dist/types/public/assets/pds/components/pds-live-edit.d.ts +1 -195
  10. package/dist/types/public/assets/pds/components/pds-live-edit.d.ts.map +1 -1
  11. package/dist/types/public/assets/pds/components/pds-live-importer.d.ts +2 -0
  12. package/dist/types/public/assets/pds/components/pds-live-importer.d.ts.map +1 -0
  13. package/dist/types/public/assets/pds/components/pds-live-template-canvas.d.ts +2 -0
  14. package/dist/types/public/assets/pds/components/pds-live-template-canvas.d.ts.map +1 -0
  15. package/dist/types/public/assets/pds/components/pds-omnibox.d.ts +0 -2
  16. package/dist/types/public/assets/pds/components/pds-omnibox.d.ts.map +1 -1
  17. package/dist/types/public/assets/pds/components/pds-scrollrow.d.ts +20 -0
  18. package/dist/types/public/assets/pds/components/pds-scrollrow.d.ts.map +1 -1
  19. package/dist/types/public/assets/pds/components/pds-toaster.d.ts +1 -1
  20. package/dist/types/public/assets/pds/components/pds-toaster.d.ts.map +1 -1
  21. package/dist/types/public/assets/pds/components/pds-treeview.d.ts +37 -0
  22. package/dist/types/public/assets/pds/components/pds-treeview.d.ts.map +1 -0
  23. package/dist/types/src/js/common/toast.d.ts +8 -0
  24. package/dist/types/src/js/common/toast.d.ts.map +1 -1
  25. package/dist/types/src/js/pds-core/pds-config.d.ts +1306 -13
  26. package/dist/types/src/js/pds-core/pds-config.d.ts.map +1 -1
  27. package/dist/types/src/js/pds-core/pds-enhancers-meta.d.ts.map +1 -1
  28. package/dist/types/src/js/pds-core/pds-enhancers.d.ts.map +1 -1
  29. package/dist/types/src/js/pds-core/pds-generator.d.ts.map +1 -1
  30. package/dist/types/src/js/pds-core/pds-live.d.ts +2 -1
  31. package/dist/types/src/js/pds-core/pds-live.d.ts.map +1 -1
  32. package/dist/types/src/js/pds-core/pds-ontology.d.ts.map +1 -1
  33. package/dist/types/src/js/pds-core/pds-start-helpers.d.ts +1 -4
  34. package/dist/types/src/js/pds-core/pds-start-helpers.d.ts.map +1 -1
  35. package/dist/types/src/js/pds-live-manager/conversion-service.d.ts +66 -0
  36. package/dist/types/src/js/pds-live-manager/conversion-service.d.ts.map +1 -0
  37. package/dist/types/src/js/pds-live-manager/import-contract.d.ts +15 -0
  38. package/dist/types/src/js/pds-live-manager/import-contract.d.ts.map +1 -0
  39. package/dist/types/src/js/pds-live-manager/import-history-service.d.ts +32 -0
  40. package/dist/types/src/js/pds-live-manager/import-history-service.d.ts.map +1 -0
  41. package/dist/types/src/js/pds-live-manager/import-service.d.ts +21 -0
  42. package/dist/types/src/js/pds-live-manager/import-service.d.ts.map +1 -0
  43. package/dist/types/src/js/pds-live-manager/template-service.d.ts +17 -0
  44. package/dist/types/src/js/pds-live-manager/template-service.d.ts.map +1 -0
  45. package/dist/types/src/js/pds-manager.d.ts +4 -0
  46. package/dist/types/src/js/pds.d.ts.map +1 -1
  47. package/package.json +7 -3
  48. package/packages/pds-cli/README.md +51 -0
  49. package/packages/pds-cli/bin/pds-import.js +176 -0
  50. package/packages/pds-cli/bin/pds-static.js +31 -1
  51. package/packages/pds-cli/bin/postinstall.mjs +17 -8
  52. package/public/assets/js/app.js +23 -147
  53. package/public/assets/js/pds-manager.js +481 -248
  54. package/public/assets/js/pds.js +16 -16
  55. package/public/assets/pds/components/pds-form.js +124 -27
  56. package/public/assets/pds/components/pds-live-converter.js +47 -0
  57. package/public/assets/pds/components/pds-live-edit.js +1626 -211
  58. package/public/assets/pds/components/pds-live-importer.js +772 -0
  59. package/public/assets/pds/components/pds-live-template-canvas.js +171 -0
  60. package/public/assets/pds/components/pds-omnibox.js +146 -20
  61. package/public/assets/pds/components/pds-scrollrow.js +56 -1
  62. package/public/assets/pds/components/pds-toaster.js +50 -5
  63. package/public/assets/pds/components/pds-treeview.js +972 -0
  64. package/public/assets/pds/custom-elements.json +865 -35
  65. package/public/assets/pds/pds-css-complete.json +7 -7
  66. package/public/assets/pds/pds.css-data.json +5 -35
  67. package/public/assets/pds/templates/commerce-scroll-explorer.html +115 -0
  68. package/public/assets/pds/templates/content-brand-showcase.html +110 -0
  69. package/public/assets/pds/templates/feedback-ops-dashboard.html +91 -0
  70. package/public/assets/pds/templates/release-readiness-radar.html +69 -0
  71. package/public/assets/pds/templates/support-command-center.html +92 -0
  72. package/public/assets/pds/templates/templates.json +53 -0
  73. package/public/assets/pds/templates/workspace-settings-lab.html +131 -0
  74. package/public/assets/pds/vscode-custom-data.json +54 -4
  75. package/readme.md +34 -0
  76. package/src/js/pds-core/pds-config.js +831 -40
  77. package/src/js/pds-core/pds-enhancers-meta.js +11 -0
  78. package/src/js/pds-core/pds-enhancers.js +259 -5
  79. package/src/js/pds-core/pds-generator.js +353 -52
  80. package/src/js/pds-core/pds-live.js +630 -15
  81. package/src/js/pds-core/pds-ontology.js +6 -0
  82. package/src/js/pds-core/pds-start-helpers.js +14 -6
  83. package/src/js/pds-live-manager/conversion-service.js +3136 -0
  84. package/src/js/pds-live-manager/import-contract.js +57 -0
  85. package/src/js/pds-live-manager/import-history-service.js +145 -0
  86. package/src/js/pds-live-manager/import-service.js +255 -0
  87. package/src/js/pds-live-manager/tailwind-conversion-rules.json +383 -0
  88. package/src/js/pds-live-manager/template-service.js +170 -0
  89. package/src/js/pds.d.ts +31 -0
  90. package/src/js/pds.js +71 -60
@@ -55,6 +55,17 @@ export const defaultPDSEnhancerMetadata = [
55
55
  </label>
56
56
  `.trim(),
57
57
  },
58
+ {
59
+ selector: "label[data-color]",
60
+ description:
61
+ "Wraps color inputs with a styled control shell and synced hex output while keeping the native picker.",
62
+ demoHtml: `
63
+ <label data-color>
64
+ <span>Brand color</span>
65
+ <input type="color" value="#7c3aed">
66
+ </label>
67
+ `.trim(),
68
+ },
58
69
  {
59
70
  selector: 'input[type="range"]',
60
71
  description: "Enhances range inputs with an attached <output>.",
@@ -15,6 +15,7 @@ const enhancerDefinitions = [
15
15
  { selector: ".accordion" },
16
16
  { selector: "nav[data-dropdown]" },
17
17
  { selector: "label[data-toggle]" },
18
+ { selector: "label[data-color]" },
18
19
  { selector: 'input[type="range"]' },
19
20
  { selector: "form[data-required]" },
20
21
  { selector: "fieldset[role=group][data-open]" },
@@ -67,6 +68,7 @@ function enhanceDropdown(elem) {
67
68
  }
68
69
 
69
70
  const isMenu = menu.tagName?.toLowerCase() === "menu";
71
+ const VIEWPORT_PADDING = 8;
70
72
  if (isMenu && !menu.hasAttribute("role")) {
71
73
  menu.setAttribute("role", "menu");
72
74
  }
@@ -151,6 +153,145 @@ function enhanceDropdown(elem) {
151
153
  return spaceForRightAligned > spaceForLeftAligned ? "right" : "left";
152
154
  };
153
155
 
156
+ const readLengthToken = (tokenName, fallback = 8) => {
157
+ const raw = getComputedStyle(elem).getPropertyValue(tokenName).trim();
158
+ if (!raw) return fallback;
159
+ const probe = document.createElement("span");
160
+ probe.style.position = "fixed";
161
+ probe.style.visibility = "hidden";
162
+ probe.style.pointerEvents = "none";
163
+ probe.style.height = raw;
164
+ document.body.appendChild(probe);
165
+ const parsed = Number.parseFloat(getComputedStyle(probe).height);
166
+ probe.remove();
167
+ return Number.isFinite(parsed) ? parsed : fallback;
168
+ };
169
+
170
+ const clearFloatingMenuPosition = () => {
171
+ menu.style.removeProperty("position");
172
+ menu.style.removeProperty("left");
173
+ menu.style.removeProperty("top");
174
+ menu.style.removeProperty("right");
175
+ menu.style.removeProperty("bottom");
176
+ menu.style.removeProperty("margin-top");
177
+ menu.style.removeProperty("margin-bottom");
178
+ menu.style.removeProperty("max-width");
179
+ menu.style.removeProperty("max-inline-size");
180
+ menu.style.removeProperty("max-height");
181
+ menu.style.removeProperty("overflow");
182
+ };
183
+
184
+ const reattachFloatingMenu = () => {
185
+ if (menu.getAttribute("aria-hidden") !== "false") return;
186
+ clearFloatingMenuPosition();
187
+ requestAnimationFrame(() => {
188
+ requestAnimationFrame(() => {
189
+ positionFloatingMenu();
190
+ });
191
+ });
192
+ };
193
+
194
+ const positionFloatingMenu = () => {
195
+ if (menu.getAttribute("aria-hidden") !== "false") return;
196
+ const anchorRect = (trigger || elem).getBoundingClientRect();
197
+ const viewport = window.visualViewport;
198
+ const viewportWidth =
199
+ viewport?.width || document.documentElement?.clientWidth || window.innerWidth;
200
+ const viewportHeight =
201
+ viewport?.height || document.documentElement?.clientHeight || window.innerHeight;
202
+ const viewportOffsetLeft = viewport?.offsetLeft || 0;
203
+ const viewportOffsetTop = viewport?.offsetTop || 0;
204
+ const maxMenuWidth = Math.max(1, viewportWidth - VIEWPORT_PADDING * 2);
205
+ const maxMenuHeight = Math.max(1, viewportHeight - VIEWPORT_PADDING * 2);
206
+
207
+ menu.style.maxWidth = `${Math.round(maxMenuWidth)}px`;
208
+ menu.style.maxInlineSize = `${Math.round(maxMenuWidth)}px`;
209
+ menu.style.maxHeight = `${Math.round(maxMenuHeight)}px`;
210
+ menu.style.overflow = "auto";
211
+
212
+ const { width: menuWidth, height: menuHeight } = measureMenuSize();
213
+ const spacing = readLengthToken("--spacing-2", 8);
214
+ const direction = resolveDirection();
215
+ const align = resolveAlign();
216
+
217
+ elem.dataset.dropdownDirection = direction;
218
+ elem.dataset.dropdownAlign = align;
219
+
220
+ let left = align === "right" ? anchorRect.right - menuWidth : anchorRect.left;
221
+ if (menuWidth >= maxMenuWidth - 1) {
222
+ left = viewportOffsetLeft + VIEWPORT_PADDING;
223
+ } else {
224
+ left = Math.max(
225
+ viewportOffsetLeft + VIEWPORT_PADDING,
226
+ Math.min(
227
+ left,
228
+ viewportOffsetLeft + viewportWidth - menuWidth - VIEWPORT_PADDING,
229
+ ),
230
+ );
231
+ }
232
+
233
+ let top =
234
+ direction === "up"
235
+ ? anchorRect.top - spacing - menuHeight
236
+ : anchorRect.bottom + spacing;
237
+ top = Math.max(
238
+ viewportOffsetTop + VIEWPORT_PADDING,
239
+ Math.min(
240
+ top,
241
+ viewportOffsetTop + viewportHeight - menuHeight - VIEWPORT_PADDING,
242
+ ),
243
+ );
244
+
245
+ menu.style.position = "fixed";
246
+ menu.style.left = `${Math.round(left)}px`;
247
+ menu.style.top = `${Math.round(top)}px`;
248
+ menu.style.right = "auto";
249
+ menu.style.bottom = "auto";
250
+ menu.style.marginTop = "0";
251
+ menu.style.marginBottom = "0";
252
+ };
253
+
254
+ let repositionHandler = null;
255
+ const bindReposition = () => {
256
+ if (repositionHandler) return;
257
+ repositionHandler = () => positionFloatingMenu();
258
+ window.addEventListener("resize", repositionHandler);
259
+ window.addEventListener("scroll", repositionHandler, true);
260
+ };
261
+
262
+ const unbindReposition = () => {
263
+ if (!repositionHandler) return;
264
+ window.removeEventListener("resize", repositionHandler);
265
+ window.removeEventListener("scroll", repositionHandler, true);
266
+ repositionHandler = null;
267
+ };
268
+
269
+ let configChangedHandler = null;
270
+ const bindConfigChanged = () => {
271
+ if (configChangedHandler || typeof document === "undefined") return;
272
+ configChangedHandler = () => {
273
+ if (menu.getAttribute("aria-hidden") !== "false") return;
274
+ elem.dataset.dropdownDirection = resolveDirection();
275
+ elem.dataset.dropdownAlign = resolveAlign();
276
+ reattachFloatingMenu();
277
+ setTimeout(() => {
278
+ if (menu.getAttribute("aria-hidden") !== "false") return;
279
+ reattachFloatingMenu();
280
+ }, 50);
281
+ setTimeout(() => {
282
+ if (menu.getAttribute("aria-hidden") !== "false") return;
283
+ reattachFloatingMenu();
284
+ }, 150);
285
+ };
286
+ document.addEventListener("pds:config-changed", configChangedHandler);
287
+ };
288
+
289
+ const unbindConfigChanged = () => {
290
+ if (!configChangedHandler || typeof document === "undefined") return;
291
+ document.removeEventListener("pds:config-changed", configChangedHandler);
292
+ configChangedHandler = null;
293
+ };
294
+
154
295
  // Store click handler reference for cleanup
155
296
  let clickHandler = null;
156
297
 
@@ -159,6 +300,9 @@ function enhanceDropdown(elem) {
159
300
  elem.dataset.dropdownAlign = resolveAlign();
160
301
  menu.setAttribute("aria-hidden", "false");
161
302
  trigger?.setAttribute("aria-expanded", "true");
303
+ bindReposition();
304
+ bindConfigChanged();
305
+ reattachFloatingMenu();
162
306
 
163
307
  // Add click-outside handler when opening
164
308
  if (!clickHandler) {
@@ -181,6 +325,9 @@ function enhanceDropdown(elem) {
181
325
  const closeMenu = () => {
182
326
  menu.setAttribute("aria-hidden", "true");
183
327
  trigger?.setAttribute("aria-expanded", "false");
328
+ unbindReposition();
329
+ unbindConfigChanged();
330
+ clearFloatingMenuPosition();
184
331
 
185
332
  // Remove click-outside handler when closing
186
333
  if (clickHandler) {
@@ -272,9 +419,109 @@ function enhanceToggle(elem) {
272
419
  checkbox.addEventListener("change", updateAria);
273
420
  }
274
421
 
422
+ function enhanceColorInput(elem) {
423
+ if (elem.dataset.enhancedColorInput) return;
424
+
425
+ const input = elem.querySelector('input[type="color"]');
426
+ if (!input) return;
427
+
428
+ elem.dataset.enhancedColorInput = "true";
429
+
430
+ let control = elem.querySelector(':scope > .color-control');
431
+ let swatch = elem.querySelector(':scope > .color-control > .color-swatch');
432
+ let output = elem.querySelector(':scope > .color-control > output');
433
+
434
+ if (!control) {
435
+ control = document.createElement("span");
436
+ control.className = "color-control";
437
+ input.before(control);
438
+ }
439
+
440
+ if (!swatch) {
441
+ swatch = document.createElement("span");
442
+ swatch.className = "color-swatch";
443
+ control.appendChild(swatch);
444
+ }
445
+
446
+ if (input.parentElement !== swatch) {
447
+ swatch.appendChild(input);
448
+ }
449
+
450
+ if (!output) {
451
+ output = document.createElement("output");
452
+ control.appendChild(output);
453
+ }
454
+
455
+ const sync = () => {
456
+ const isUnset = input.dataset.colorUnset === "1";
457
+
458
+ if (isUnset) {
459
+ output.value = "";
460
+ output.textContent = "not set";
461
+ control.dataset.value = "";
462
+ control.dataset.unset = "1";
463
+ swatch.dataset.unset = "1";
464
+ return;
465
+ }
466
+
467
+ output.value = input.value;
468
+ output.textContent = input.value;
469
+ control.dataset.value = input.value;
470
+ delete control.dataset.unset;
471
+ delete swatch.dataset.unset;
472
+ };
473
+
474
+ sync();
475
+
476
+ const setResolved = () => {
477
+ if (input.dataset.colorUnset === "1") {
478
+ input.dataset.colorUnset = "0";
479
+ }
480
+ sync();
481
+ };
482
+
483
+ input.addEventListener("input", setResolved, { passive: true });
484
+ input.addEventListener("change", setResolved, { passive: true });
485
+ }
486
+
275
487
  function enhanceRange(elem) {
276
488
  if (elem.dataset.enhancedRange) return;
277
489
 
490
+ const wireProgrammaticUpdates = (updateFn) => {
491
+ if (elem.dataset.enhancedRangeProgrammatic) return;
492
+ elem.dataset.enhancedRangeProgrammatic = "1";
493
+
494
+ const descriptor =
495
+ Object.getOwnPropertyDescriptor(Object.getPrototypeOf(elem), "value") ||
496
+ Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
497
+
498
+ if (descriptor?.get && descriptor?.set) {
499
+ Object.defineProperty(elem, "value", {
500
+ configurable: true,
501
+ enumerable: descriptor.enumerable,
502
+ get() {
503
+ return descriptor.get.call(this);
504
+ },
505
+ set(nextValue) {
506
+ descriptor.set.call(this, nextValue);
507
+ updateFn();
508
+ },
509
+ });
510
+ }
511
+
512
+ const attrObserver = new MutationObserver((mutations) => {
513
+ const shouldUpdate = mutations.some((mutation) => {
514
+ const attr = mutation.attributeName;
515
+ return attr === "value" || attr === "min" || attr === "max";
516
+ });
517
+ if (shouldUpdate) updateFn();
518
+ });
519
+ attrObserver.observe(elem, {
520
+ attributes: true,
521
+ attributeFilter: ["value", "min", "max"],
522
+ });
523
+ };
524
+
278
525
  const label = elem.closest("label");
279
526
  const hasRangeOutputClass = label?.classList.contains("range-output");
280
527
 
@@ -312,6 +559,9 @@ function enhanceRange(elem) {
312
559
  output.textContent = elem.value;
313
560
  };
314
561
  elem.addEventListener("input", updateOutput);
562
+ elem.addEventListener("change", updateOutput);
563
+ wireProgrammaticUpdates(updateOutput);
564
+ updateOutput();
315
565
  }
316
566
  } else {
317
567
  let container = elem.closest(".range-container");
@@ -346,6 +596,8 @@ function enhanceRange(elem) {
346
596
  elem.addEventListener("pointerleave", hide);
347
597
  elem.addEventListener("focus", show);
348
598
  elem.addEventListener("blur", hide);
599
+ elem.addEventListener("change", updateBubble);
600
+ wireProgrammaticUpdates(updateBubble);
349
601
  updateBubble();
350
602
  }
351
603
 
@@ -413,9 +665,9 @@ function enhanceOpenGroup(elem) {
413
665
  addInput.placeholder = "Add item...";
414
666
  addInput.classList.add("input-text", "input-sm");
415
667
  addInput.style.width = "auto";
416
- const firstInput = elem.querySelector(
417
- 'input[type="radio"], input[type="checkbox"]',
418
- );
668
+
669
+ const getFirstInput = () =>
670
+ elem.querySelector('input[type="radio"], input[type="checkbox"]');
419
671
 
420
672
  elem.appendChild(addInput);
421
673
  addInput.addEventListener("keydown", (event) => {
@@ -424,7 +676,8 @@ function enhanceOpenGroup(elem) {
424
676
  if (value) {
425
677
  event.preventDefault();
426
678
 
427
- const type = firstInput.type === "radio" ? "radio" : "checkbox";
679
+ const firstInput = getFirstInput();
680
+ const type = firstInput?.type === "radio" ? "radio" : "checkbox";
428
681
  const id = `open-group-${Math.random().toString(36).substring(2, 11)}`;
429
682
  const label = document.createElement("label");
430
683
 
@@ -435,7 +688,7 @@ function enhanceOpenGroup(elem) {
435
688
  const input = document.createElement("input");
436
689
  input.type = type;
437
690
  input.name =
438
- firstInput.name || elem.getAttribute("data-name") || "open-group";
691
+ firstInput?.name || elem.getAttribute("data-name") || "open-group";
439
692
  input.value = value;
440
693
  input.id = id;
441
694
 
@@ -550,6 +803,7 @@ const enhancerRunners = new Map([
550
803
  [".accordion", enhanceAccordion],
551
804
  ["nav[data-dropdown]", enhanceDropdown],
552
805
  ["label[data-toggle]", enhanceToggle],
806
+ ["label[data-color]", enhanceColorInput],
553
807
  ['input[type="range"]', enhanceRange],
554
808
  ["form[data-required]", enhanceRequired],
555
809
  ["fieldset[role=group][data-open]", enhanceOpenGroup],