@pure-ds/core 0.7.5 → 0.7.7

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.
@@ -1,689 +1 @@
1
- // src/js/pds-core/pds-enhancers.js
2
- var enhancerDefinitions = [
3
- { selector: ".accordion" },
4
- { selector: "nav[data-dropdown]" },
5
- { selector: "label[data-toggle]" },
6
- { selector: "label[data-color]" },
7
- { selector: 'input[type="range"]' },
8
- { selector: "form[data-required]" },
9
- { selector: "fieldset[role=group][data-open]" },
10
- { selector: "[data-clip]" },
11
- { selector: "button, a[class*='btn-']" }
12
- ];
13
- function enhanceAccordion(elem) {
14
- if (elem.dataset.enhancedAccordion)
15
- return;
16
- elem.dataset.enhancedAccordion = "true";
17
- elem.addEventListener(
18
- "toggle",
19
- (event) => {
20
- if (event.target.open && event.target.parentElement === elem) {
21
- elem.querySelectorAll(":scope > details[open]").forEach((details) => {
22
- if (details !== event.target) {
23
- details.open = false;
24
- }
25
- });
26
- }
27
- },
28
- true
29
- );
30
- }
31
- function enhanceDropdown(elem) {
32
- if (elem.dataset.enhancedDropdown)
33
- return;
34
- elem.dataset.enhancedDropdown = "true";
35
- const menu = elem.lastElementChild;
36
- if (!menu)
37
- return;
38
- const trigger = elem.querySelector("[data-dropdown-toggle]") || elem.querySelector("button");
39
- if (trigger && !trigger.hasAttribute("type")) {
40
- trigger.setAttribute("type", "button");
41
- }
42
- if (!menu.id) {
43
- menu.id = `dropdown-${Math.random().toString(36).slice(2, 9)}`;
44
- }
45
- const isMenu = menu.tagName?.toLowerCase() === "menu";
46
- const VIEWPORT_PADDING = 8;
47
- if (isMenu && !menu.hasAttribute("role")) {
48
- menu.setAttribute("role", "menu");
49
- }
50
- if (!menu.hasAttribute("aria-hidden")) {
51
- menu.setAttribute("aria-hidden", "true");
52
- }
53
- if (trigger) {
54
- trigger.setAttribute("aria-haspopup", "true");
55
- trigger.setAttribute("aria-controls", menu.id);
56
- trigger.setAttribute("aria-expanded", "false");
57
- }
58
- const measureMenuSize = () => {
59
- const previousStyle = menu.getAttribute("style");
60
- menu.style.visibility = "hidden";
61
- menu.style.display = "inline-block";
62
- menu.style.pointerEvents = "none";
63
- const rect = menu.getBoundingClientRect();
64
- const width = Math.max(menu.offsetWidth || 0, menu.scrollWidth || 0, rect.width || 0, 1);
65
- const height = Math.max(
66
- menu.offsetHeight || 0,
67
- menu.scrollHeight || 0,
68
- rect.height || 0,
69
- 1
70
- );
71
- if (previousStyle === null) {
72
- menu.removeAttribute("style");
73
- } else {
74
- menu.setAttribute("style", previousStyle);
75
- }
76
- return { width, height };
77
- };
78
- const resolveDirection = () => {
79
- const mode = (elem.getAttribute("data-direction") || elem.getAttribute("data-dropdown-direction") || elem.getAttribute("data-mode") || "auto").toLowerCase();
80
- if (mode === "up" || mode === "down")
81
- return mode;
82
- const anchorRect = (trigger || elem).getBoundingClientRect();
83
- const { height: menuHeight } = measureMenuSize();
84
- const spaceBelow = Math.max(0, window.innerHeight - anchorRect.bottom);
85
- const spaceAbove = Math.max(0, anchorRect.top);
86
- const fitsDown = spaceBelow >= menuHeight;
87
- const fitsUp = spaceAbove >= menuHeight;
88
- if (fitsDown && !fitsUp)
89
- return "down";
90
- if (fitsUp && !fitsDown)
91
- return "up";
92
- if (fitsDown && fitsUp)
93
- return "down";
94
- return spaceAbove > spaceBelow ? "up" : "down";
95
- };
96
- const resolveAlign = () => {
97
- const align = (elem.getAttribute("data-align") || elem.getAttribute("data-dropdown-align") || "auto").toLowerCase();
98
- if (align === "left" || align === "right" || align === "start" || align === "end") {
99
- return align === "start" ? "left" : align === "end" ? "right" : align;
100
- }
101
- const anchorRect = (trigger || elem).getBoundingClientRect();
102
- const { width: menuWidth } = measureMenuSize();
103
- const spaceForLeftAligned = Math.max(0, window.innerWidth - anchorRect.left);
104
- const spaceForRightAligned = Math.max(0, anchorRect.right);
105
- const fitsLeft = spaceForLeftAligned >= menuWidth;
106
- const fitsRight = spaceForRightAligned >= menuWidth;
107
- if (fitsLeft && !fitsRight)
108
- return "left";
109
- if (fitsRight && !fitsLeft)
110
- return "right";
111
- if (fitsLeft && fitsRight)
112
- return "left";
113
- return spaceForRightAligned > spaceForLeftAligned ? "right" : "left";
114
- };
115
- const readLengthToken = (tokenName, fallback = 8) => {
116
- const raw = getComputedStyle(elem).getPropertyValue(tokenName).trim();
117
- if (!raw)
118
- return fallback;
119
- const probe = document.createElement("span");
120
- probe.style.position = "fixed";
121
- probe.style.visibility = "hidden";
122
- probe.style.pointerEvents = "none";
123
- probe.style.height = raw;
124
- document.body.appendChild(probe);
125
- const parsed = Number.parseFloat(getComputedStyle(probe).height);
126
- probe.remove();
127
- return Number.isFinite(parsed) ? parsed : fallback;
128
- };
129
- const clearFloatingMenuPosition = () => {
130
- menu.style.removeProperty("position");
131
- menu.style.removeProperty("left");
132
- menu.style.removeProperty("top");
133
- menu.style.removeProperty("right");
134
- menu.style.removeProperty("bottom");
135
- menu.style.removeProperty("margin-top");
136
- menu.style.removeProperty("margin-bottom");
137
- menu.style.removeProperty("max-width");
138
- menu.style.removeProperty("max-inline-size");
139
- menu.style.removeProperty("max-height");
140
- menu.style.removeProperty("overflow");
141
- };
142
- const reattachFloatingMenu = () => {
143
- if (menu.getAttribute("aria-hidden") !== "false")
144
- return;
145
- clearFloatingMenuPosition();
146
- requestAnimationFrame(() => {
147
- requestAnimationFrame(() => {
148
- positionFloatingMenu();
149
- });
150
- });
151
- };
152
- const positionFloatingMenu = () => {
153
- if (menu.getAttribute("aria-hidden") !== "false")
154
- return;
155
- const anchorRect = (trigger || elem).getBoundingClientRect();
156
- const viewport = window.visualViewport;
157
- const viewportWidth = viewport?.width || document.documentElement?.clientWidth || window.innerWidth;
158
- const viewportHeight = viewport?.height || document.documentElement?.clientHeight || window.innerHeight;
159
- const viewportOffsetLeft = viewport?.offsetLeft || 0;
160
- const viewportOffsetTop = viewport?.offsetTop || 0;
161
- const maxMenuWidth = Math.max(1, viewportWidth - VIEWPORT_PADDING * 2);
162
- const maxMenuHeight = Math.max(1, viewportHeight - VIEWPORT_PADDING * 2);
163
- menu.style.maxWidth = `${Math.round(maxMenuWidth)}px`;
164
- menu.style.maxInlineSize = `${Math.round(maxMenuWidth)}px`;
165
- menu.style.maxHeight = `${Math.round(maxMenuHeight)}px`;
166
- menu.style.overflow = "auto";
167
- const { width: menuWidth, height: menuHeight } = measureMenuSize();
168
- const spacing = readLengthToken("--spacing-2", 8);
169
- const direction = resolveDirection();
170
- const align = resolveAlign();
171
- elem.dataset.dropdownDirection = direction;
172
- elem.dataset.dropdownAlign = align;
173
- let left = align === "right" ? anchorRect.right - menuWidth : anchorRect.left;
174
- if (menuWidth >= maxMenuWidth - 1) {
175
- left = viewportOffsetLeft + VIEWPORT_PADDING;
176
- } else {
177
- left = Math.max(
178
- viewportOffsetLeft + VIEWPORT_PADDING,
179
- Math.min(
180
- left,
181
- viewportOffsetLeft + viewportWidth - menuWidth - VIEWPORT_PADDING
182
- )
183
- );
184
- }
185
- let top = direction === "up" ? anchorRect.top - spacing - menuHeight : anchorRect.bottom + spacing;
186
- top = Math.max(
187
- viewportOffsetTop + VIEWPORT_PADDING,
188
- Math.min(
189
- top,
190
- viewportOffsetTop + viewportHeight - menuHeight - VIEWPORT_PADDING
191
- )
192
- );
193
- menu.style.position = "fixed";
194
- menu.style.left = `${Math.round(left)}px`;
195
- menu.style.top = `${Math.round(top)}px`;
196
- menu.style.right = "auto";
197
- menu.style.bottom = "auto";
198
- menu.style.marginTop = "0";
199
- menu.style.marginBottom = "0";
200
- };
201
- let repositionHandler = null;
202
- const bindReposition = () => {
203
- if (repositionHandler)
204
- return;
205
- repositionHandler = () => positionFloatingMenu();
206
- window.addEventListener("resize", repositionHandler);
207
- window.addEventListener("scroll", repositionHandler, true);
208
- };
209
- const unbindReposition = () => {
210
- if (!repositionHandler)
211
- return;
212
- window.removeEventListener("resize", repositionHandler);
213
- window.removeEventListener("scroll", repositionHandler, true);
214
- repositionHandler = null;
215
- };
216
- let configChangedHandler = null;
217
- const bindConfigChanged = () => {
218
- if (configChangedHandler || typeof document === "undefined")
219
- return;
220
- configChangedHandler = () => {
221
- if (menu.getAttribute("aria-hidden") !== "false")
222
- return;
223
- elem.dataset.dropdownDirection = resolveDirection();
224
- elem.dataset.dropdownAlign = resolveAlign();
225
- reattachFloatingMenu();
226
- setTimeout(() => {
227
- if (menu.getAttribute("aria-hidden") !== "false")
228
- return;
229
- reattachFloatingMenu();
230
- }, 50);
231
- setTimeout(() => {
232
- if (menu.getAttribute("aria-hidden") !== "false")
233
- return;
234
- reattachFloatingMenu();
235
- }, 150);
236
- };
237
- document.addEventListener("pds:config-changed", configChangedHandler);
238
- };
239
- const unbindConfigChanged = () => {
240
- if (!configChangedHandler || typeof document === "undefined")
241
- return;
242
- document.removeEventListener("pds:config-changed", configChangedHandler);
243
- configChangedHandler = null;
244
- };
245
- let clickHandler = null;
246
- const openMenu = () => {
247
- elem.dataset.dropdownDirection = resolveDirection();
248
- elem.dataset.dropdownAlign = resolveAlign();
249
- menu.setAttribute("aria-hidden", "false");
250
- trigger?.setAttribute("aria-expanded", "true");
251
- bindReposition();
252
- bindConfigChanged();
253
- reattachFloatingMenu();
254
- if (!clickHandler) {
255
- clickHandler = (event) => {
256
- const path = event.composedPath ? event.composedPath() : [event.target];
257
- const clickedInside = path.some((node) => node === elem);
258
- if (!clickedInside) {
259
- closeMenu();
260
- }
261
- };
262
- setTimeout(() => {
263
- document.addEventListener("click", clickHandler);
264
- }, 0);
265
- }
266
- };
267
- const closeMenu = () => {
268
- menu.setAttribute("aria-hidden", "true");
269
- trigger?.setAttribute("aria-expanded", "false");
270
- unbindReposition();
271
- unbindConfigChanged();
272
- clearFloatingMenuPosition();
273
- if (clickHandler) {
274
- document.removeEventListener("click", clickHandler);
275
- clickHandler = null;
276
- }
277
- };
278
- const toggleMenu = () => {
279
- if (menu.getAttribute("aria-hidden") === "false") {
280
- closeMenu();
281
- } else {
282
- openMenu();
283
- }
284
- };
285
- trigger?.addEventListener("click", (event) => {
286
- event.preventDefault();
287
- event.stopPropagation();
288
- toggleMenu();
289
- });
290
- elem.addEventListener("keydown", (event) => {
291
- if (event.key === "Escape") {
292
- closeMenu();
293
- trigger?.focus();
294
- }
295
- });
296
- elem.addEventListener("focusout", (event) => {
297
- if (event.relatedTarget) {
298
- const path = event.composedPath ? event.composedPath() : [event.relatedTarget];
299
- const focusedInside = path.some((node) => node === elem);
300
- if (!focusedInside) {
301
- closeMenu();
302
- }
303
- }
304
- });
305
- }
306
- function enhanceToggle(elem) {
307
- if (elem.dataset.enhancedToggle)
308
- return;
309
- elem.dataset.enhancedToggle = "true";
310
- const checkbox = elem.querySelector('input[type="checkbox"]');
311
- if (!checkbox)
312
- return;
313
- if (!elem.hasAttribute("tabindex")) {
314
- elem.setAttribute("tabindex", "0");
315
- }
316
- elem.setAttribute("role", "switch");
317
- elem.setAttribute("aria-checked", checkbox.checked ? "true" : "false");
318
- const toggleSwitch = document.createElement("span");
319
- toggleSwitch.className = "toggle-switch";
320
- toggleSwitch.setAttribute("role", "presentation");
321
- toggleSwitch.setAttribute("aria-hidden", "true");
322
- const knob = document.createElement("span");
323
- knob.className = "toggle-knob";
324
- toggleSwitch.appendChild(knob);
325
- elem.insertBefore(toggleSwitch, checkbox.nextSibling);
326
- const updateAria = () => {
327
- elem.setAttribute("aria-checked", checkbox.checked ? "true" : "false");
328
- };
329
- const toggle = () => {
330
- if (checkbox.disabled)
331
- return;
332
- checkbox.checked = !checkbox.checked;
333
- updateAria();
334
- checkbox.dispatchEvent(new Event("change", { bubbles: true }));
335
- };
336
- elem.addEventListener("click", (event) => {
337
- event.preventDefault();
338
- toggle();
339
- });
340
- elem.addEventListener("keydown", (event) => {
341
- if (event.key === " " || event.key === "Enter") {
342
- event.preventDefault();
343
- toggle();
344
- }
345
- });
346
- checkbox.addEventListener("change", updateAria);
347
- }
348
- function enhanceColorInput(elem) {
349
- if (elem.dataset.enhancedColorInput)
350
- return;
351
- const input = elem.querySelector('input[type="color"]');
352
- if (!input)
353
- return;
354
- elem.dataset.enhancedColorInput = "true";
355
- let control = elem.querySelector(":scope > .color-control");
356
- let swatch = elem.querySelector(":scope > .color-control > .color-swatch");
357
- let output = elem.querySelector(":scope > .color-control > output");
358
- if (!control) {
359
- control = document.createElement("span");
360
- control.className = "color-control";
361
- input.before(control);
362
- }
363
- if (!swatch) {
364
- swatch = document.createElement("span");
365
- swatch.className = "color-swatch";
366
- control.appendChild(swatch);
367
- }
368
- if (input.parentElement !== swatch) {
369
- swatch.appendChild(input);
370
- }
371
- if (!output) {
372
- output = document.createElement("output");
373
- control.appendChild(output);
374
- }
375
- const sync = () => {
376
- const isUnset = input.dataset.colorUnset === "1";
377
- if (isUnset) {
378
- output.value = "";
379
- output.textContent = "not set";
380
- control.dataset.value = "";
381
- control.dataset.unset = "1";
382
- swatch.dataset.unset = "1";
383
- return;
384
- }
385
- output.value = input.value;
386
- output.textContent = input.value;
387
- control.dataset.value = input.value;
388
- delete control.dataset.unset;
389
- delete swatch.dataset.unset;
390
- };
391
- sync();
392
- const setResolved = () => {
393
- if (input.dataset.colorUnset === "1") {
394
- input.dataset.colorUnset = "0";
395
- }
396
- sync();
397
- };
398
- input.addEventListener("input", setResolved, { passive: true });
399
- input.addEventListener("change", setResolved, { passive: true });
400
- }
401
- function enhanceRange(elem) {
402
- if (elem.dataset.enhancedRange)
403
- return;
404
- const wireProgrammaticUpdates = (updateFn) => {
405
- if (elem.dataset.enhancedRangeProgrammatic)
406
- return;
407
- elem.dataset.enhancedRangeProgrammatic = "1";
408
- const descriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(elem), "value") || Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
409
- if (descriptor?.get && descriptor?.set) {
410
- Object.defineProperty(elem, "value", {
411
- configurable: true,
412
- enumerable: descriptor.enumerable,
413
- get() {
414
- return descriptor.get.call(this);
415
- },
416
- set(nextValue) {
417
- descriptor.set.call(this, nextValue);
418
- updateFn();
419
- }
420
- });
421
- }
422
- const attrObserver = new MutationObserver((mutations) => {
423
- const shouldUpdate = mutations.some((mutation) => {
424
- const attr = mutation.attributeName;
425
- return attr === "value" || attr === "min" || attr === "max";
426
- });
427
- if (shouldUpdate)
428
- updateFn();
429
- });
430
- attrObserver.observe(elem, {
431
- attributes: true,
432
- attributeFilter: ["value", "min", "max"]
433
- });
434
- };
435
- const label = elem.closest("label");
436
- const hasRangeOutputClass = label?.classList.contains("range-output");
437
- const inputId = elem.id || `range-${Math.random().toString(36).substring(2, 11)}`;
438
- const outputId = `${inputId}-output`;
439
- elem.id = inputId;
440
- if (hasRangeOutputClass) {
441
- const labelSpan = label.querySelector("span");
442
- if (labelSpan && !labelSpan.classList.contains("range-output-wrapper")) {
443
- const wrapper = document.createElement("span");
444
- wrapper.className = "range-output-wrapper";
445
- wrapper.style.display = "flex";
446
- wrapper.style.justifyContent = "space-between";
447
- wrapper.style.alignItems = "center";
448
- const textSpan = document.createElement("span");
449
- textSpan.textContent = labelSpan.textContent;
450
- wrapper.appendChild(textSpan);
451
- const output = document.createElement("output");
452
- output.id = outputId;
453
- output.setAttribute("for", inputId);
454
- output.style.color = "var(--surface-text-secondary, var(--color-text-secondary))";
455
- output.style.fontSize = "0.875rem";
456
- output.textContent = elem.value;
457
- wrapper.appendChild(output);
458
- labelSpan.textContent = "";
459
- labelSpan.appendChild(wrapper);
460
- const updateOutput = () => {
461
- output.textContent = elem.value;
462
- };
463
- elem.addEventListener("input", updateOutput);
464
- elem.addEventListener("change", updateOutput);
465
- wireProgrammaticUpdates(updateOutput);
466
- updateOutput();
467
- }
468
- } else {
469
- let container = elem.closest(".range-container");
470
- if (!container) {
471
- container = document.createElement("div");
472
- container.className = "range-container";
473
- elem.parentNode?.insertBefore(container, elem);
474
- container.appendChild(elem);
475
- }
476
- container.style.position = "relative";
477
- const bubble = document.createElement("output");
478
- bubble.id = outputId;
479
- bubble.setAttribute("for", inputId);
480
- bubble.className = "range-bubble";
481
- bubble.setAttribute("aria-live", "polite");
482
- container.appendChild(bubble);
483
- const updateBubble = () => {
484
- const min = parseFloat(elem.min) || 0;
485
- const max = parseFloat(elem.max) || 100;
486
- const value = parseFloat(elem.value);
487
- const pct = (value - min) / (max - min);
488
- bubble.style.left = `calc(${pct * 100}% )`;
489
- bubble.textContent = String(value);
490
- };
491
- const show = () => bubble.classList.add("visible");
492
- const hide = () => bubble.classList.remove("visible");
493
- elem.addEventListener("input", updateBubble);
494
- elem.addEventListener("pointerdown", show);
495
- elem.addEventListener("pointerup", hide);
496
- elem.addEventListener("pointerleave", hide);
497
- elem.addEventListener("focus", show);
498
- elem.addEventListener("blur", hide);
499
- elem.addEventListener("change", updateBubble);
500
- wireProgrammaticUpdates(updateBubble);
501
- updateBubble();
502
- }
503
- elem.dataset.enhancedRange = "1";
504
- }
505
- function enhanceRequired(elem) {
506
- if (elem.dataset.enhancedRequired)
507
- return;
508
- elem.dataset.enhancedRequired = "true";
509
- const enhanceRequiredField = (input) => {
510
- let label;
511
- if (input.closest("[role$=group]")) {
512
- label = input.closest("[role$=group]").querySelector("legend");
513
- } else {
514
- label = input.closest("label");
515
- }
516
- if (!label)
517
- return;
518
- if (label.querySelector(".required-asterisk"))
519
- return;
520
- const asterisk = document.createElement("span");
521
- asterisk.classList.add("required-asterisk");
522
- asterisk.textContent = "*";
523
- asterisk.style.marginLeft = "4px";
524
- const labelText = label.querySelector("span, [data-label]");
525
- if (labelText) {
526
- labelText.appendChild(asterisk);
527
- } else {
528
- const field = label.querySelector("input, select, textarea");
529
- if (field) {
530
- label.insertBefore(asterisk, field);
531
- } else {
532
- label.appendChild(asterisk);
533
- }
534
- }
535
- const form = input.closest("form");
536
- if (form && !form.querySelector(".required-legend")) {
537
- const legend = document.createElement("small");
538
- legend.classList.add("required-legend");
539
- legend.textContent = "* Required fields";
540
- form.insertBefore(
541
- legend,
542
- form.querySelector(".form-actions") || form.lastElementChild
543
- );
544
- }
545
- };
546
- elem.querySelectorAll("[required]").forEach((input) => {
547
- enhanceRequiredField(input);
548
- });
549
- }
550
- function enhanceOpenGroup(elem) {
551
- if (elem.dataset.enhancedOpenGroup)
552
- return;
553
- elem.dataset.enhancedOpenGroup = "true";
554
- elem.classList.add("flex", "flex-wrap", "buttons");
555
- const addInput = document.createElement("input");
556
- addInput.type = "text";
557
- addInput.placeholder = "Add item...";
558
- addInput.classList.add("input-text", "input-sm");
559
- addInput.style.width = "auto";
560
- const getFirstInput = () => elem.querySelector('input[type="radio"], input[type="checkbox"]');
561
- elem.appendChild(addInput);
562
- addInput.addEventListener("keydown", (event) => {
563
- if (event.key === "Enter" || event.key === "Tab") {
564
- const value = addInput.value.trim();
565
- if (value) {
566
- event.preventDefault();
567
- const firstInput = getFirstInput();
568
- const type = firstInput?.type === "radio" ? "radio" : "checkbox";
569
- const id = `open-group-${Math.random().toString(36).substring(2, 11)}`;
570
- const label = document.createElement("label");
571
- const span = document.createElement("span");
572
- span.setAttribute("data-label", "");
573
- span.textContent = value;
574
- const input = document.createElement("input");
575
- input.type = type;
576
- input.name = firstInput?.name || elem.getAttribute("data-name") || "open-group";
577
- input.value = value;
578
- input.id = id;
579
- label.appendChild(span);
580
- label.appendChild(input);
581
- elem.insertBefore(label, addInput);
582
- addInput.value = "";
583
- }
584
- } else if (event.key === "Backspace" && addInput.value === "") {
585
- event.preventDefault();
586
- const labels = elem.querySelectorAll("label");
587
- if (labels.length > 0) {
588
- const lastLabel = labels[labels.length - 1];
589
- lastLabel.remove();
590
- }
591
- }
592
- });
593
- }
594
- function enhanceClip(elem) {
595
- if (elem.dataset.enhancedClip)
596
- return;
597
- elem.dataset.enhancedClip = "true";
598
- if (!elem.hasAttribute("tabindex")) {
599
- elem.setAttribute("tabindex", "0");
600
- }
601
- if (!elem.hasAttribute("role")) {
602
- elem.setAttribute("role", "button");
603
- }
604
- const syncAria = () => {
605
- const isOpen = elem.getAttribute("data-clip-open") === "true";
606
- elem.setAttribute("aria-expanded", isOpen ? "true" : "false");
607
- };
608
- const toggleOpen = () => {
609
- const isOpen = elem.getAttribute("data-clip-open") === "true";
610
- elem.setAttribute("data-clip-open", isOpen ? "false" : "true");
611
- syncAria();
612
- };
613
- elem.addEventListener("click", (event) => {
614
- if (event.defaultPrevented)
615
- return;
616
- toggleOpen();
617
- });
618
- elem.addEventListener("keydown", (event) => {
619
- if (event.key === " " || event.key === "Enter") {
620
- event.preventDefault();
621
- toggleOpen();
622
- }
623
- });
624
- syncAria();
625
- }
626
- function enhanceButtonWorking(elem) {
627
- if (elem.dataset.enhancedBtnWorking)
628
- return;
629
- elem.dataset.enhancedBtnWorking = "true";
630
- let originalIcon = null;
631
- let addedIcon = false;
632
- const observer = new MutationObserver((mutations) => {
633
- mutations.forEach((mutation) => {
634
- if (mutation.attributeName === "class") {
635
- const hasWorking = elem.classList.contains("btn-working");
636
- const icon = elem.querySelector("pds-icon");
637
- if (hasWorking) {
638
- if (icon) {
639
- if (!originalIcon) {
640
- originalIcon = icon.getAttribute("icon");
641
- }
642
- icon.setAttribute("icon", "circle-notch");
643
- } else {
644
- const newIcon = document.createElement("pds-icon");
645
- newIcon.setAttribute("icon", "circle-notch");
646
- newIcon.setAttribute("size", "sm");
647
- elem.insertBefore(newIcon, elem.firstChild);
648
- addedIcon = true;
649
- }
650
- } else if (mutation.oldValue?.includes("btn-working")) {
651
- if (icon) {
652
- if (addedIcon) {
653
- icon.remove();
654
- addedIcon = false;
655
- } else if (originalIcon) {
656
- icon.setAttribute("icon", originalIcon);
657
- originalIcon = null;
658
- }
659
- }
660
- }
661
- }
662
- });
663
- });
664
- observer.observe(elem, {
665
- attributes: true,
666
- attributeFilter: ["class"],
667
- attributeOldValue: true
668
- });
669
- }
670
- var enhancerRunners = /* @__PURE__ */ new Map([
671
- [".accordion", enhanceAccordion],
672
- ["nav[data-dropdown]", enhanceDropdown],
673
- ["label[data-toggle]", enhanceToggle],
674
- ["label[data-color]", enhanceColorInput],
675
- ['input[type="range"]', enhanceRange],
676
- ["form[data-required]", enhanceRequired],
677
- ["fieldset[role=group][data-open]", enhanceOpenGroup],
678
- ["[data-clip]", enhanceClip],
679
- ["button, a[class*='btn-']", enhanceButtonWorking]
680
- ]);
681
- var defaultPDSEnhancers = enhancerDefinitions.map((meta) => ({
682
- ...meta,
683
- run: enhancerRunners.get(meta.selector) || (() => {
684
- })
685
- }));
686
- export {
687
- defaultPDSEnhancers
688
- };
689
- //# sourceMappingURL=pds-enhancers.js.map
1
+ var F=[{selector:".accordion"},{selector:"nav[data-dropdown]"},{selector:"label[data-toggle]"},{selector:"label[data-color]"},{selector:'input[type="range"]'},{selector:"form[data-required]"},{selector:"fieldset[role=group][data-open]"},{selector:"[data-clip]"},{selector:"button, a[class*='btn-']"}];function W(t){t.dataset.enhancedAccordion||(t.dataset.enhancedAccordion="true",t.addEventListener("toggle",e=>{e.target.open&&e.target.parentElement===t&&t.querySelectorAll(":scope > details[open]").forEach(n=>{n!==e.target&&(n.open=!1)})},!0))}function H(t){if(t.dataset.enhancedDropdown)return;t.dataset.enhancedDropdown="true";let e=t.lastElementChild;if(!e)return;let n=t.querySelector("[data-dropdown-toggle]")||t.querySelector("button");n&&!n.hasAttribute("type")&&n.setAttribute("type","button"),e.id||(e.id=`dropdown-${Math.random().toString(36).slice(2,9)}`);let o=e.tagName?.toLowerCase()==="menu",a=8;o&&!e.hasAttribute("role")&&e.setAttribute("role","menu"),e.hasAttribute("aria-hidden")||e.setAttribute("aria-hidden","true"),n&&(n.setAttribute("aria-haspopup","true"),n.setAttribute("aria-controls",e.id),n.setAttribute("aria-expanded","false"));let c=()=>{let s=e.getAttribute("style");e.style.visibility="hidden",e.style.display="inline-block",e.style.pointerEvents="none";let h=e.getBoundingClientRect(),f=Math.max(e.offsetWidth||0,e.scrollWidth||0,h.width||0,1),d=Math.max(e.offsetHeight||0,e.scrollHeight||0,h.height||0,1);return s===null?e.removeAttribute("style"):e.setAttribute("style",s),{width:f,height:d}},i=()=>{let s=(t.getAttribute("data-direction")||t.getAttribute("data-dropdown-direction")||t.getAttribute("data-mode")||"auto").toLowerCase();if(s==="up"||s==="down")return s;let h=(n||t).getBoundingClientRect(),{height:f}=c(),d=Math.max(0,window.innerHeight-h.bottom),b=Math.max(0,h.top),v=d>=f,y=b>=f;return v&&!y?"down":y&&!v?"up":v&&y?"down":b>d?"up":"down"},r=()=>{let s=(t.getAttribute("data-align")||t.getAttribute("data-dropdown-align")||"auto").toLowerCase();if(s==="left"||s==="right"||s==="start"||s==="end")return s==="start"?"left":s==="end"?"right":s;let h=(n||t).getBoundingClientRect(),{width:f}=c(),d=Math.max(0,window.innerWidth-h.left),b=Math.max(0,h.right),v=d>=f,y=b>=f;return v&&!y?"left":y&&!v?"right":v&&y?"left":b>d?"right":"left"},p=(s,h=8)=>{let f=getComputedStyle(t).getPropertyValue(s).trim();if(!f)return h;let d=document.createElement("span");d.style.position="fixed",d.style.visibility="hidden",d.style.pointerEvents="none",d.style.height=f,document.body.appendChild(d);let b=Number.parseFloat(getComputedStyle(d).height);return d.remove(),Number.isFinite(b)?b:h},u=()=>{e.style.removeProperty("position"),e.style.removeProperty("left"),e.style.removeProperty("top"),e.style.removeProperty("right"),e.style.removeProperty("bottom"),e.style.removeProperty("margin-top"),e.style.removeProperty("margin-bottom"),e.style.removeProperty("max-width"),e.style.removeProperty("max-inline-size"),e.style.removeProperty("max-height"),e.style.removeProperty("overflow")},l=()=>{e.getAttribute("aria-hidden")==="false"&&(u(),requestAnimationFrame(()=>{requestAnimationFrame(()=>{w()})}))},w=()=>{if(e.getAttribute("aria-hidden")!=="false")return;let s=(n||t).getBoundingClientRect(),h=window.visualViewport,f=h?.width||document.documentElement?.clientWidth||window.innerWidth,d=h?.height||document.documentElement?.clientHeight||window.innerHeight,b=h?.offsetLeft||0,v=h?.offsetTop||0,y=Math.max(1,f-a*2),T=Math.max(1,d-a*2);e.style.maxWidth=`${Math.round(y)}px`,e.style.maxInlineSize=`${Math.round(y)}px`,e.style.maxHeight=`${Math.round(T)}px`,e.style.overflow="auto";let{width:k,height:M}=c(),q=p("--spacing-2",8),P=i(),R=r();t.dataset.dropdownDirection=P,t.dataset.dropdownAlign=R;let C=R==="right"?s.right-k:s.left;k>=y-1?C=b+a:C=Math.max(b+a,Math.min(C,b+f-k-a));let S=P==="up"?s.top-q-M:s.bottom+q;S=Math.max(v+a,Math.min(S,v+d-M-a)),e.style.position="fixed",e.style.left=`${Math.round(C)}px`,e.style.top=`${Math.round(S)}px`,e.style.right="auto",e.style.bottom="auto",e.style.marginTop="0",e.style.marginBottom="0"},g=null,E=()=>{g||(g=()=>w(),window.addEventListener("resize",g),window.addEventListener("scroll",g,!0))},L=()=>{g&&(window.removeEventListener("resize",g),window.removeEventListener("scroll",g,!0),g=null)},m=null,O=()=>{m||typeof document>"u"||(m=()=>{e.getAttribute("aria-hidden")==="false"&&(t.dataset.dropdownDirection=i(),t.dataset.dropdownAlign=r(),l(),setTimeout(()=>{e.getAttribute("aria-hidden")==="false"&&l()},50),setTimeout(()=>{e.getAttribute("aria-hidden")==="false"&&l()},150))},document.addEventListener("pds:config-changed",m))},D=()=>{!m||typeof document>"u"||(document.removeEventListener("pds:config-changed",m),m=null)},A=null,I=()=>{t.dataset.dropdownDirection=i(),t.dataset.dropdownAlign=r(),e.setAttribute("aria-hidden","false"),n?.setAttribute("aria-expanded","true"),E(),O(),l(),A||(A=s=>{(s.composedPath?s.composedPath():[s.target]).some(d=>d===t)||x()},setTimeout(()=>{document.addEventListener("click",A)},0))},x=()=>{e.setAttribute("aria-hidden","true"),n?.setAttribute("aria-expanded","false"),L(),D(),u(),A&&(document.removeEventListener("click",A),A=null)},B=()=>{e.getAttribute("aria-hidden")==="false"?x():I()};n?.addEventListener("click",s=>{s.preventDefault(),s.stopPropagation(),B()}),t.addEventListener("keydown",s=>{s.key==="Escape"&&(x(),n?.focus())}),t.addEventListener("focusout",s=>{s.relatedTarget&&((s.composedPath?s.composedPath():[s.relatedTarget]).some(d=>d===t)||x())})}function N(t){if(t.dataset.enhancedToggle)return;t.dataset.enhancedToggle="true";let e=t.querySelector('input[type="checkbox"]');if(!e)return;t.hasAttribute("tabindex")||t.setAttribute("tabindex","0"),t.setAttribute("role","switch"),t.setAttribute("aria-checked",e.checked?"true":"false");let n=document.createElement("span");n.className="toggle-switch",n.setAttribute("role","presentation"),n.setAttribute("aria-hidden","true");let o=document.createElement("span");o.className="toggle-knob",n.appendChild(o),t.insertBefore(n,e.nextSibling);let a=()=>{t.setAttribute("aria-checked",e.checked?"true":"false")},c=()=>{e.disabled||(e.checked=!e.checked,a(),e.dispatchEvent(new Event("change",{bubbles:!0})))};t.addEventListener("click",i=>{i.preventDefault(),c()}),t.addEventListener("keydown",i=>{(i.key===" "||i.key==="Enter")&&(i.preventDefault(),c())}),e.addEventListener("change",a)}function $(t){if(t.dataset.enhancedColorInput)return;let e=t.querySelector('input[type="color"]');if(!e)return;t.dataset.enhancedColorInput="true";let n=t.querySelector(":scope > .color-control"),o=t.querySelector(":scope > .color-control > .color-swatch"),a=t.querySelector(":scope > .color-control > output");n||(n=document.createElement("span"),n.className="color-control",e.before(n)),o||(o=document.createElement("span"),o.className="color-swatch",n.appendChild(o)),e.parentElement!==o&&o.appendChild(e),a||(a=document.createElement("output"),n.appendChild(a));let c=()=>{if(e.dataset.colorUnset==="1"){a.value="",a.textContent="not set",n.dataset.value="",n.dataset.unset="1",o.dataset.unset="1";return}a.value=e.value,a.textContent=e.value,n.dataset.value=e.value,delete n.dataset.unset,delete o.dataset.unset};c();let i=()=>{e.dataset.colorUnset==="1"&&(e.dataset.colorUnset="0"),c()};e.addEventListener("input",i,{passive:!0}),e.addEventListener("change",i,{passive:!0})}function U(t){if(t.dataset.enhancedRange)return;let e=i=>{if(t.dataset.enhancedRangeProgrammatic)return;t.dataset.enhancedRangeProgrammatic="1";let r=Object.getOwnPropertyDescriptor(Object.getPrototypeOf(t),"value")||Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,"value");r?.get&&r?.set&&Object.defineProperty(t,"value",{configurable:!0,enumerable:r.enumerable,get(){return r.get.call(this)},set(u){r.set.call(this,u),i()}}),new MutationObserver(u=>{u.some(w=>{let g=w.attributeName;return g==="value"||g==="min"||g==="max"})&&i()}).observe(t,{attributes:!0,attributeFilter:["value","min","max"]})},n=t.closest("label"),o=n?.classList.contains("range-output"),a=t.id||`range-${Math.random().toString(36).substring(2,11)}`,c=`${a}-output`;if(t.id=a,o){let i=n.querySelector("span");if(i&&!i.classList.contains("range-output-wrapper")){let r=document.createElement("span");r.className="range-output-wrapper",r.style.display="flex",r.style.justifyContent="space-between",r.style.alignItems="center";let p=document.createElement("span");p.textContent=i.textContent,r.appendChild(p);let u=document.createElement("output");u.id=c,u.setAttribute("for",a),u.style.color="var(--surface-text-secondary, var(--color-text-secondary))",u.style.fontSize="0.875rem",u.textContent=t.value,r.appendChild(u),i.textContent="",i.appendChild(r);let l=()=>{u.textContent=t.value};t.addEventListener("input",l),t.addEventListener("change",l),e(l),l()}}else{let i=t.closest(".range-container");i||(i=document.createElement("div"),i.className="range-container",t.parentNode?.insertBefore(i,t),i.appendChild(t)),i.style.position="relative";let r=document.createElement("output");r.id=c,r.setAttribute("for",a),r.className="range-bubble",r.setAttribute("aria-live","polite"),i.appendChild(r);let p=()=>{let w=parseFloat(t.min)||0,g=parseFloat(t.max)||100,E=parseFloat(t.value),L=(E-w)/(g-w);r.style.left=`calc(${L*100}% )`,r.textContent=String(E)},u=()=>r.classList.add("visible"),l=()=>r.classList.remove("visible");t.addEventListener("input",p),t.addEventListener("pointerdown",u),t.addEventListener("pointerup",l),t.addEventListener("pointerleave",l),t.addEventListener("focus",u),t.addEventListener("blur",l),t.addEventListener("change",p),e(p),p()}t.dataset.enhancedRange="1"}function z(t){if(t.dataset.enhancedRequired)return;t.dataset.enhancedRequired="true";let e=n=>{let o;if(n.closest("[role$=group]")?o=n.closest("[role$=group]").querySelector("legend"):o=n.closest("label"),!o||o.querySelector(".required-asterisk"))return;let a=document.createElement("span");a.classList.add("required-asterisk"),a.textContent="*",a.style.marginLeft="4px";let c=o.querySelector("span, [data-label]");if(c)c.appendChild(a);else{let r=o.querySelector("input, select, textarea");r?o.insertBefore(a,r):o.appendChild(a)}let i=n.closest("form");if(i&&!i.querySelector(".required-legend")){let r=document.createElement("small");r.classList.add("required-legend"),r.textContent="* Required fields",i.insertBefore(r,i.querySelector(".form-actions")||i.lastElementChild)}};t.querySelectorAll("[required]").forEach(n=>{e(n)})}function j(t){if(t.dataset.enhancedOpenGroup)return;t.dataset.enhancedOpenGroup="true",t.classList.add("flex","flex-wrap","buttons");let e=document.createElement("input");e.type="text",e.placeholder="Add item...",e.classList.add("input-text","input-sm"),e.style.width="auto";let n=()=>t.querySelector('input[type="radio"], input[type="checkbox"]');t.appendChild(e),e.addEventListener("keydown",o=>{if(o.key==="Enter"||o.key==="Tab"){let a=e.value.trim();if(a){o.preventDefault();let c=n(),i=c?.type==="radio"?"radio":"checkbox",r=`open-group-${Math.random().toString(36).substring(2,11)}`,p=document.createElement("label"),u=document.createElement("span");u.setAttribute("data-label",""),u.textContent=a;let l=document.createElement("input");l.type=i,l.name=c?.name||t.getAttribute("data-name")||"open-group",l.value=a,l.id=r,p.appendChild(u),p.appendChild(l),t.insertBefore(p,e),e.value=""}}else if(o.key==="Backspace"&&e.value===""){o.preventDefault();let a=t.querySelectorAll("label");a.length>0&&a[a.length-1].remove()}})}function V(t){if(t.dataset.enhancedClip)return;t.dataset.enhancedClip="true",t.hasAttribute("tabindex")||t.setAttribute("tabindex","0"),t.hasAttribute("role")||t.setAttribute("role","button");let e=()=>{let o=t.getAttribute("data-clip-open")==="true";t.setAttribute("aria-expanded",o?"true":"false")},n=()=>{let o=t.getAttribute("data-clip-open")==="true";t.setAttribute("data-clip-open",o?"false":"true"),e()};t.addEventListener("click",o=>{o.defaultPrevented||n()}),t.addEventListener("keydown",o=>{(o.key===" "||o.key==="Enter")&&(o.preventDefault(),n())}),e()}function G(t){if(t.dataset.enhancedBtnWorking)return;t.dataset.enhancedBtnWorking="true";let e=null,n=!1;new MutationObserver(a=>{a.forEach(c=>{if(c.attributeName==="class"){let i=t.classList.contains("btn-working"),r=t.querySelector("pds-icon");if(i)if(r)e||(e=r.getAttribute("icon")),r.setAttribute("icon","circle-notch");else{let p=document.createElement("pds-icon");p.setAttribute("icon","circle-notch"),p.setAttribute("size","sm"),t.insertBefore(p,t.firstChild),n=!0}else c.oldValue?.includes("btn-working")&&r&&(n?(r.remove(),n=!1):e&&(r.setAttribute("icon",e),e=null))}})}).observe(t,{attributes:!0,attributeFilter:["class"],attributeOldValue:!0})}var _=new Map([[".accordion",W],["nav[data-dropdown]",H],["label[data-toggle]",N],["label[data-color]",$],['input[type="range"]',U],["form[data-required]",z],["fieldset[role=group][data-open]",j],["[data-clip]",V],["button, a[class*='btn-']",G]]),J=F.map(t=>({...t,run:_.get(t.selector)||(()=>{})}));export{J as defaultPDSEnhancers};