@pure-ds/core 0.5.61 → 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 +2 -2
  6. package/dist/types/pds.config.d.ts.map +1 -1
  7. package/dist/types/pds.d.ts +3 -0
  8. package/dist/types/public/assets/js/pds-manager.d.ts +144 -429
  9. package/dist/types/public/assets/js/pds-manager.d.ts.map +1 -1
  10. package/dist/types/public/assets/js/pds.d.ts +3 -4
  11. package/dist/types/public/assets/js/pds.d.ts.map +1 -1
  12. package/dist/types/public/assets/pds/components/pds-live-edit.d.ts +150 -0
  13. package/dist/types/public/assets/pds/components/pds-live-edit.d.ts.map +1 -0
  14. package/dist/types/public/assets/pds/components/pds-omnibox.d.ts +2 -0
  15. package/dist/types/public/assets/pds/components/pds-omnibox.d.ts.map +1 -1
  16. package/dist/types/public/assets/pds/components/pds-richtext.d.ts.map +1 -1
  17. package/dist/types/public/assets/pds/components/pds-theme.d.ts +5 -0
  18. package/dist/types/public/assets/pds/components/pds-theme.d.ts.map +1 -1
  19. package/dist/types/src/js/pds-core/pds-config.d.ts +3 -0
  20. package/dist/types/src/js/pds-core/pds-config.d.ts.map +1 -1
  21. package/dist/types/src/js/pds-core/pds-enhancers.d.ts.map +1 -1
  22. package/dist/types/src/js/pds-core/pds-live.d.ts.map +1 -1
  23. package/dist/types/src/js/pds-core/pds-ontology.d.ts.map +1 -1
  24. package/dist/types/src/js/pds-core/pds-theme-utils.d.ts +6 -0
  25. package/dist/types/src/js/pds-core/pds-theme-utils.d.ts.map +1 -0
  26. package/dist/types/src/js/pds.d.ts.map +1 -1
  27. package/package.json +1 -4
  28. package/packages/pds-cli/bin/templates/bootstrap/pds.config.js +1 -1
  29. package/public/assets/js/app.js +106 -5636
  30. package/public/assets/js/pds-manager.js +137 -137
  31. package/public/assets/js/pds.js +7 -7
  32. package/public/assets/pds/components/pds-live-edit.js +1555 -0
  33. package/public/assets/pds/components/pds-omnibox.js +558 -369
  34. package/public/assets/pds/components/pds-richtext.js +57 -7
  35. package/public/assets/pds/components/pds-theme.js +58 -0
  36. package/readme.md +2 -2
  37. package/src/js/pds-core/pds-config.js +21 -3
  38. package/src/js/pds-core/pds-enhancers.js +61 -4
  39. package/src/js/pds-core/pds-live.js +180 -1
  40. package/src/js/pds-core/pds-ontology.js +8 -0
  41. package/src/js/pds-core/pds-theme-utils.js +33 -0
  42. package/src/js/pds.d.ts +3 -0
  43. package/src/js/pds.js +22 -0
@@ -10,6 +10,7 @@
10
10
  * @attr {boolean} disabled - Disable the input
11
11
  * @attr {boolean} required - Mark the input as required
12
12
  * @attr {string} autocomplete - Native autocomplete attribute (default: off)
13
+ * @attr {string} item-grid - Grid template columns for suggestion items
13
14
  *
14
15
  * @property {Object} settings - AutoComplete settings object (required by consumer)
15
16
  */
@@ -18,192 +19,225 @@ const DEFAULT_PLACEHOLDER = "Search...";
18
19
  const DEFAULT_ICON = "magnifying-glass";
19
20
 
20
21
  export class PdsOmnibox extends HTMLElement {
21
- static formAssociated = true;
22
-
23
- static get observedAttributes() {
24
- return ["name", "placeholder", "value", "disabled", "required", "autocomplete", "icon"];
25
- }
26
-
27
- #root;
28
- #internals;
29
- #input;
30
- #icon;
31
- #settings;
32
- #defaultValue = "";
33
- #autoCompleteResizeHandler;
34
- #autoCompleteScrollHandler;
35
- #autoCompleteViewportHandler;
36
- #lengthProbe;
37
- #suggestionsUpdatedHandler;
38
- #suggestionsObserver;
39
-
40
- constructor() {
41
- super();
42
- this.#root = this.attachShadow({ mode: "open" });
43
- this.#internals = this.attachInternals();
44
- this.#renderStructure();
45
- void this.#adoptStyles();
46
- }
47
-
48
- connectedCallback() {
49
- this.#defaultValue = this.getAttribute("value") || "";
50
- this.#syncAttributes();
51
- this.#updateFormValue(this.#input.value || "");
52
- if (!this.#suggestionsUpdatedHandler) {
53
- this.#suggestionsUpdatedHandler = (event) => {
54
- this.#handleSuggestionsUpdated(event);
55
- };
56
- this.addEventListener("suggestions-updated", this.#suggestionsUpdatedHandler);
57
- }
58
- }
59
-
60
- disconnectedCallback() {
61
- this.#teardownAutoCompleteSizing();
62
- this.#teardownSuggestionsObserver();
63
- if (this.#suggestionsUpdatedHandler) {
64
- this.removeEventListener("suggestions-updated", this.#suggestionsUpdatedHandler);
65
- this.#suggestionsUpdatedHandler = null;
66
- }
67
- }
68
-
69
- attributeChangedCallback(name, oldValue, newValue) {
70
- if (oldValue === newValue) return;
71
- this.#syncAttributes();
72
- }
73
-
74
- get settings() {
75
- return this.#settings;
76
- }
77
-
78
- set settings(value) {
79
- this.#settings = value;
80
- }
81
-
82
- get name() {
83
- return this.getAttribute("name") || "";
84
- }
85
-
86
- set name(value) {
87
- if (value == null || value === "") this.removeAttribute("name");
88
- else this.setAttribute("name", value);
89
- }
90
-
91
- get placeholder() {
92
- return this.getAttribute("placeholder") || DEFAULT_PLACEHOLDER;
93
- }
94
-
95
- set placeholder(value) {
96
- if (value == null || value === "") this.removeAttribute("placeholder");
97
- else this.setAttribute("placeholder", value);
98
- }
99
-
100
- get value() {
101
- return this.#input?.value || "";
102
- }
103
-
104
- set value(value) {
105
- const next = value == null ? "" : String(value);
106
- if (this.#input) this.#input.value = next;
107
- this.#updateFormValue(next);
108
- }
109
-
110
- get disabled() {
111
- return this.hasAttribute("disabled");
112
- }
113
-
114
- set disabled(value) {
115
- if (value) this.setAttribute("disabled", "");
116
- else this.removeAttribute("disabled");
117
- }
118
-
119
- get required() {
120
- return this.hasAttribute("required");
121
- }
122
-
123
- set required(value) {
124
- if (value) this.setAttribute("required", "");
125
- else this.removeAttribute("required");
126
- }
127
-
128
- get autocomplete() {
129
- return this.getAttribute("autocomplete") || "off";
130
- }
131
-
132
- set autocomplete(value) {
133
- if (value == null || value === "") this.removeAttribute("autocomplete");
134
- else this.setAttribute("autocomplete", value);
135
- }
136
-
137
- get icon() {
138
- return this.getAttribute("icon") || DEFAULT_ICON;
139
- }
140
-
141
- set icon(value) {
142
- if (value == null || value === "") this.removeAttribute("icon");
143
- else this.setAttribute("icon", value);
144
- }
145
-
146
- formAssociatedCallback() {}
147
-
148
- formDisabledCallback(disabled) {
149
- if (!this.#input) return;
150
- this.#input.disabled = disabled;
151
- }
152
-
153
- formResetCallback() {
154
- this.value = this.#defaultValue;
155
- }
156
-
157
- formStateRestoreCallback(state) {
158
- this.value = state ?? "";
159
- }
160
-
161
- checkValidity() {
162
- return this.#input?.checkValidity?.() ?? true;
163
- }
164
-
165
- reportValidity() {
166
- return this.#input?.reportValidity?.() ?? true;
167
- }
168
-
169
- #renderStructure() {
170
- this.#root.innerHTML = `
22
+ static formAssociated = true;
23
+
24
+ static get observedAttributes() {
25
+ return [
26
+ "name",
27
+ "placeholder",
28
+ "value",
29
+ "disabled",
30
+ "required",
31
+ "autocomplete",
32
+ "icon",
33
+ "item-grid",
34
+ ];
35
+ }
36
+
37
+ #root;
38
+ #internals;
39
+ #input;
40
+ #icon;
41
+ #settings;
42
+ #defaultValue = "";
43
+ #autoCompleteResizeHandler;
44
+ #autoCompleteScrollHandler;
45
+ #autoCompleteViewportHandler;
46
+ #lengthProbe;
47
+ #suggestionsUpdatedHandler;
48
+ #suggestionsObserver;
49
+
50
+ constructor() {
51
+ super();
52
+ this.#root = this.attachShadow({ mode: "open" });
53
+ this.#internals = this.attachInternals();
54
+ this.#renderStructure();
55
+ void this.#adoptStyles();
56
+ }
57
+
58
+ connectedCallback() {
59
+ this.#defaultValue = this.getAttribute("value") || "";
60
+ this.#syncAttributes();
61
+ this.#updateFormValue(this.#input.value || "");
62
+ if (!this.#suggestionsUpdatedHandler) {
63
+ this.#suggestionsUpdatedHandler = (event) => {
64
+ this.#handleSuggestionsUpdated(event);
65
+ };
66
+ this.addEventListener(
67
+ "suggestions-updated",
68
+ this.#suggestionsUpdatedHandler,
69
+ );
70
+ }
71
+ }
72
+
73
+ disconnectedCallback() {
74
+ this.#teardownAutoCompleteSizing();
75
+ this.#teardownSuggestionsObserver();
76
+ const autoComplete = this.#input?._autoComplete;
77
+ if (autoComplete) {
78
+ autoComplete.controller?.().clear?.("disconnected");
79
+ autoComplete.resultsDiv?.remove?.();
80
+ this.#input._autoComplete = null;
81
+ }
82
+ if (this.#suggestionsUpdatedHandler) {
83
+ this.removeEventListener(
84
+ "suggestions-updated",
85
+ this.#suggestionsUpdatedHandler,
86
+ );
87
+ this.#suggestionsUpdatedHandler = null;
88
+ }
89
+ }
90
+
91
+ attributeChangedCallback(name, oldValue, newValue) {
92
+ if (oldValue === newValue) return;
93
+ this.#syncAttributes();
94
+ }
95
+
96
+ get settings() {
97
+ return this.#settings;
98
+ }
99
+
100
+ set settings(value) {
101
+ this.#settings = value;
102
+ }
103
+
104
+ get name() {
105
+ return this.getAttribute("name") || "";
106
+ }
107
+
108
+ set name(value) {
109
+ if (value == null || value === "") this.removeAttribute("name");
110
+ else this.setAttribute("name", value);
111
+ }
112
+
113
+ get placeholder() {
114
+ return this.getAttribute("placeholder") || DEFAULT_PLACEHOLDER;
115
+ }
116
+
117
+ set placeholder(value) {
118
+ if (value == null || value === "") this.removeAttribute("placeholder");
119
+ else this.setAttribute("placeholder", value);
120
+ }
121
+
122
+ get value() {
123
+ return this.#input?.value || "";
124
+ }
125
+
126
+ set value(value) {
127
+ const next = value == null ? "" : String(value);
128
+ if (this.#input) this.#input.value = next;
129
+ this.#updateFormValue(next);
130
+ }
131
+
132
+ get disabled() {
133
+ return this.hasAttribute("disabled");
134
+ }
135
+
136
+ set disabled(value) {
137
+ if (value) this.setAttribute("disabled", "");
138
+ else this.removeAttribute("disabled");
139
+ }
140
+
141
+ get required() {
142
+ return this.hasAttribute("required");
143
+ }
144
+
145
+ set required(value) {
146
+ if (value) this.setAttribute("required", "");
147
+ else this.removeAttribute("required");
148
+ }
149
+
150
+ get autocomplete() {
151
+ return this.getAttribute("autocomplete") || "off";
152
+ }
153
+
154
+ set autocomplete(value) {
155
+ if (value == null || value === "") this.removeAttribute("autocomplete");
156
+ else this.setAttribute("autocomplete", value);
157
+ }
158
+
159
+ get icon() {
160
+ return this.getAttribute("icon") || DEFAULT_ICON;
161
+ }
162
+
163
+ set icon(value) {
164
+ if (value == null || value === "") this.removeAttribute("icon");
165
+ else this.setAttribute("icon", value);
166
+ }
167
+
168
+ get itemGrid() {
169
+ return this.getAttribute("item-grid") || "";
170
+ }
171
+
172
+ set itemGrid(value) {
173
+ if (value == null || value === "") this.removeAttribute("item-grid");
174
+ else this.setAttribute("item-grid", value);
175
+ }
176
+
177
+ formAssociatedCallback() {}
178
+
179
+ formDisabledCallback(disabled) {
180
+ if (!this.#input) return;
181
+ this.#input.disabled = disabled;
182
+ }
183
+
184
+ formResetCallback() {
185
+ this.value = this.#defaultValue;
186
+ }
187
+
188
+ formStateRestoreCallback(state) {
189
+ this.value = state ?? "";
190
+ }
191
+
192
+ checkValidity() {
193
+ return this.#input?.checkValidity?.() ?? true;
194
+ }
195
+
196
+ reportValidity() {
197
+ return this.#input?.reportValidity?.() ?? true;
198
+ }
199
+
200
+ #renderStructure() {
201
+ this.#root.innerHTML = `
171
202
  <div class="ac-container input-icon">
172
203
  <pds-icon morph icon="${DEFAULT_ICON}"></pds-icon>
173
204
  <input class="ac-input" type="search" placeholder="${DEFAULT_PLACEHOLDER}" autocomplete="off" />
174
205
  </div>
175
206
  `;
176
207
 
177
- this.#lengthProbe = document.createElement("div");
178
- this.#lengthProbe.style.cssText = "position:absolute; visibility:hidden; width:0; height:0; pointer-events:none;";
179
- this.#root.appendChild(this.#lengthProbe);
180
-
181
- this.#input = this.#root.querySelector("input");
182
- this.#icon = this.#root.querySelector("pds-icon");
183
- this.#input.addEventListener("input", () => {
184
- this.#updateFormValue(this.#input.value);
185
- this.#updateSuggestionMaxHeight();
186
- this.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
187
- });
188
- this.#input.addEventListener("change", () => {
189
- this.dispatchEvent(new Event("change", { bubbles: true, composed: true }));
190
- });
191
- this.#input.addEventListener("focus", (e) => {
192
- this.#handleAutoComplete(e);
193
- });
194
- this.#input.addEventListener("show-results", (event) => {
195
- this.dispatchEvent(
196
- new CustomEvent("suggestions-updated", {
197
- detail: { results: event?.detail?.results ?? [] },
198
- bubbles: true,
199
- composed: true,
200
- })
201
- );
202
- });
203
- }
204
-
205
- async #adoptStyles() {
206
- const componentStyles = PDS.createStylesheet(/*css*/`
208
+ this.#lengthProbe = document.createElement("div");
209
+ this.#lengthProbe.style.cssText =
210
+ "position:absolute; visibility:hidden; width:0; height:0; pointer-events:none;";
211
+ this.#root.appendChild(this.#lengthProbe);
212
+
213
+ this.#input = this.#root.querySelector("input");
214
+ this.#icon = this.#root.querySelector("pds-icon");
215
+ this.#input.addEventListener("input", () => {
216
+ this.#updateFormValue(this.#input.value);
217
+ this.#updateSuggestionMaxHeight();
218
+ this.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
219
+ });
220
+ this.#input.addEventListener("change", () => {
221
+ this.dispatchEvent(
222
+ new Event("change", { bubbles: true, composed: true }),
223
+ );
224
+ });
225
+ this.#input.addEventListener("focus", (e) => {
226
+ this.#handleAutoComplete(e);
227
+ });
228
+ this.#input.addEventListener("show-results", (event) => {
229
+ this.dispatchEvent(
230
+ new CustomEvent("suggestions-updated", {
231
+ detail: { results: event?.detail?.results ?? [] },
232
+ bubbles: true,
233
+ composed: true,
234
+ }),
235
+ );
236
+ });
237
+ }
238
+
239
+ async #adoptStyles() {
240
+ const componentStyles = PDS.createStylesheet(/*css*/ `
207
241
  @layer omnibox {
208
242
  :host {
209
243
  display: block;
@@ -275,6 +309,12 @@ export class PdsOmnibox extends HTMLElement {
275
309
  justify-self: center;
276
310
  }
277
311
 
312
+ &.disabled{
313
+ mouse-events: none;
314
+ opacity: 0.5;
315
+ cursor: not-allowed;
316
+ }
317
+
278
318
  > .text {
279
319
  grid-column: 2;
280
320
  min-width: var(--spacing-0);
@@ -315,13 +355,12 @@ export class PdsOmnibox extends HTMLElement {
315
355
 
316
356
  &:hover,
317
357
  &.selected {
318
- background-color: var(--accent-color, var(--ac-accent-color-default));
319
- color: var(--ac-bg, var(--ac-bg-default));
358
+ background-color: var(--color-surface-elevated);
359
+ border: 2px dotted var(--color-primary-500);
320
360
 
321
361
  svg-icon,
322
362
  pds-icon {
323
- --icon-fill-color: var(--color-surface-base);
324
- color: var(--color-surface-base);
363
+ filter: brightness(120%)
325
364
  }
326
365
 
327
366
  small,
@@ -356,6 +395,20 @@ export class PdsOmnibox extends HTMLElement {
356
395
  }
357
396
  }
358
397
 
398
+ .ac-suggestion.ac-active[data-direction="down"] {
399
+ border-radius: 0 0 var(--ac-rad) var(--ac-rad);
400
+
401
+ .ac-itm:first-child {
402
+ border-top-left-radius: 0;
403
+ border-top-right-radius: 0;
404
+ }
405
+
406
+ .ac-itm:last-child {
407
+ border-bottom-left-radius: var(--ac-rad);
408
+ border-bottom-right-radius: var(--ac-rad);
409
+ }
410
+ }
411
+
359
412
  &.ac-active[data-direction="up"] {
360
413
  .ac-input {
361
414
  border-top-left-radius: 0;
@@ -365,6 +418,7 @@ export class PdsOmnibox extends HTMLElement {
365
418
  .ac-suggestion {
366
419
  top: auto;
367
420
  bottom: calc(100% + var(--ac-suggest-offset));
421
+ border-radius: var(--ac-rad) var(--ac-rad) 0 0;
368
422
  }
369
423
 
370
424
  .ac-itm:last-child {
@@ -375,8 +429,26 @@ export class PdsOmnibox extends HTMLElement {
375
429
  .ac-itm:first-child {
376
430
  border-top-left-radius: var(--ac-rad);
377
431
  border-top-right-radius: var(--ac-rad);
432
+ border-bottom-left-radius: 0;
433
+ border-bottom-right-radius: 0;
378
434
  }
379
435
  }
436
+
437
+ .ac-suggestion.ac-active[data-direction="up"] {
438
+ border-radius: var(--ac-rad) var(--ac-rad) 0 0;
439
+
440
+ .ac-itm:last-child {
441
+ border-bottom-left-radius: 0;
442
+ border-bottom-right-radius: 0;
443
+ }
444
+
445
+ .ac-itm:first-child {
446
+ border-top-left-radius: var(--ac-rad);
447
+ border-top-right-radius: var(--ac-rad);
448
+ border-bottom-left-radius: 0;
449
+ border-bottom-right-radius: 0;
450
+ }
451
+ }
380
452
  }
381
453
 
382
454
  @media (max-width: var(--breakpoint-sm)) {
@@ -399,218 +471,335 @@ export class PdsOmnibox extends HTMLElement {
399
471
 
400
472
  .ac-itm:hover,
401
473
  .ac-itm.selected {
402
- background-color: var(--color-accent-300);
403
- color: var(--color-surface-base);
474
+ background-color: var(--color-primary-500);
475
+ color: var(--color-primary-contrast, #ffffff);
476
+ }
477
+
478
+ &.is-disabled {
479
+ cursor: not-allowed;
480
+ color: var(--color-text-muted);
481
+
482
+ small,
483
+ .category {
484
+ color: var(--color-text-muted);
485
+ }
486
+
487
+ svg-icon,
488
+ pds-icon {
489
+ --icon-fill-color: var(--color-text-muted);
490
+ color: var(--color-text-muted);
491
+ filter: none;
492
+ }
493
+ }
494
+
495
+ &.is-disabled:hover,
496
+ &.is-disabled.selected {
497
+ background-color: var(--ac-bg, var(--ac-bg-default));
498
+ box-shadow: none;
404
499
  }
405
500
  }
501
+
502
+ .preset-colors {
503
+ display: flex;
504
+ gap: var(--spacing-1);
505
+ flex-shrink: 0;
506
+ }
507
+
508
+ .preset-colors span {
509
+ width: var(--spacing-2);
510
+ height: var(--spacing-5);
511
+ }
406
512
  }
407
513
  }
408
514
  }
409
515
  `);
410
516
 
411
- await PDS.adoptLayers(this.#root, LAYERS, [componentStyles]);
412
- }
517
+ await PDS.adoptLayers(this.#root, LAYERS, [componentStyles]);
518
+ }
413
519
 
414
- #syncAttributes() {
415
- if (!this.#input) return;
520
+ #syncAttributes() {
521
+ if (!this.#input) return;
416
522
 
417
- this.#input.placeholder = this.placeholder;
418
- this.#input.autocomplete = this.autocomplete;
419
- if (this.#icon) this.#icon.setAttribute("icon", this.icon);
523
+ this.#input.placeholder = this.placeholder;
524
+ this.#input.autocomplete = this.autocomplete;
525
+ if (this.#icon) this.#icon.setAttribute("icon", this.icon);
420
526
 
421
- if (this.hasAttribute("value")) {
422
- const v = this.getAttribute("value") || "";
423
- if (this.#input.value !== v) this.#input.value = v;
424
- }
527
+ if (this.hasAttribute("value")) {
528
+ const v = this.getAttribute("value") || "";
529
+ if (this.#input.value !== v) this.#input.value = v;
530
+ }
425
531
 
426
- if (this.disabled) this.#input.setAttribute("disabled", "");
427
- else this.#input.removeAttribute("disabled");
532
+ if (this.disabled) this.#input.setAttribute("disabled", "");
533
+ else this.#input.removeAttribute("disabled");
428
534
 
429
- if (this.required) this.#input.setAttribute("required", "");
430
- else this.#input.removeAttribute("required");
535
+ if (this.required) this.#input.setAttribute("required", "");
536
+ else this.#input.removeAttribute("required");
431
537
 
432
- this.#updateFormValue(this.#input.value);
433
- }
538
+ if (this.itemGrid) this.style.setProperty("--ac-grid", this.itemGrid);
539
+ else this.style.removeProperty("--ac-grid");
434
540
 
435
- #updateFormValue(value) {
436
- this.#internals.setFormValue(value);
437
- this.#syncValidity();
438
- }
541
+ this.#updateFormValue(this.#input.value);
542
+ }
439
543
 
440
- #syncValidity() {
441
- if (!this.#input) return;
442
- if (this.#input.checkValidity()) {
443
- this.#internals.setValidity({}, "", this.#input);
444
- return;
445
- }
446
- this.#internals.setValidity(
447
- { customError: true },
448
- this.#input.validationMessage || "Invalid value",
449
- this.#input
450
- );
451
- }
544
+ #updateFormValue(value) {
545
+ this.#internals.setFormValue(value);
546
+ this.#syncValidity();
547
+ }
452
548
 
453
- async #handleAutoComplete(e) {
549
+ #syncValidity() {
550
+ if (!this.#input) return;
551
+ if (this.#input.checkValidity()) {
552
+ this.#internals.setValidity({}, "", this.#input);
553
+ return;
554
+ }
555
+ this.#internals.setValidity(
556
+ { customError: true },
557
+ this.#input.validationMessage || "Invalid value",
558
+ this.#input,
559
+ );
560
+ }
454
561
 
455
- if (!this.settings) return;
562
+ async #handleAutoComplete(e) {
563
+ if (!this.settings) return;
456
564
 
457
- const AutoComplete = PDS.AutoComplete
565
+ const AutoComplete = PDS.AutoComplete;
458
566
 
459
- if (AutoComplete && typeof AutoComplete.connect === "function") {
567
+ if (AutoComplete && typeof AutoComplete.connect === "function") {
460
568
  const settings = {
461
569
  //debug: true,
462
570
  iconHandler: (item) => {
463
571
  return item.icon ? `<pds-icon icon="${item.icon}"></pds-icon>` : null;
464
572
  },
465
- ...this.settings
573
+ ...this.settings,
466
574
  };
467
-
468
-
469
- this.#input._autoComplete = new AutoComplete(this.#input.parentNode, this.#input, settings);
470
- this.#wrapAutoCompleteResultsHandler(this.#input._autoComplete);
471
- setTimeout(() => {
472
- this.#input._autoComplete.focusHandler(e);
473
- this.#setupAutoCompleteSizing();
474
- this.#updateSuggestionMaxHeight();
475
- this.#setupSuggestionsObserver();
476
- }, 100);
477
-
478
- }
479
- }
480
-
481
- #wrapAutoCompleteResultsHandler(autoComplete) {
482
- if (!autoComplete || autoComplete.__pdsSuggestionsWrapped) return;
483
- autoComplete.__pdsSuggestionsWrapped = true;
484
- const originalResultsHandler = autoComplete.resultsHandler?.bind(autoComplete);
485
- if (!originalResultsHandler) return;
486
-
487
- autoComplete.resultsHandler = (results, options) => {
488
- this.dispatchEvent(
489
- new CustomEvent("suggestions-updated", {
490
- detail: { results },
491
- bubbles: true,
492
- composed: true,
493
- })
494
- );
495
- return originalResultsHandler(results, options);
496
- };
497
- }
498
-
499
- #setupAutoCompleteSizing() {
500
- if (this.#autoCompleteResizeHandler) return;
501
- this.#autoCompleteResizeHandler = () => this.#updateSuggestionMaxHeight();
502
- this.#autoCompleteScrollHandler = () => this.#updateSuggestionMaxHeight();
503
- this.#autoCompleteViewportHandler = () => this.#updateSuggestionMaxHeight();
504
-
505
- window.addEventListener("resize", this.#autoCompleteResizeHandler);
506
- window.addEventListener("scroll", this.#autoCompleteScrollHandler, true);
507
- if (window.visualViewport) {
508
- window.visualViewport.addEventListener("resize", this.#autoCompleteViewportHandler);
509
- window.visualViewport.addEventListener("scroll", this.#autoCompleteViewportHandler);
510
- }
511
- }
512
-
513
- #setupSuggestionsObserver() {
514
- if (this.#suggestionsObserver) return;
515
- const container = this.#input?.parentElement;
516
- const root = container?.shadowRoot ?? container;
517
- const suggestion = root?.querySelector?.(".ac-suggestion");
518
- if (!suggestion) return;
519
- this.#suggestionsObserver = new MutationObserver(() => {
520
- if (!suggestion.classList.contains("ac-active")) {
521
- this.#resetIconToDefault();
522
- }
523
- });
524
- this.#suggestionsObserver.observe(suggestion, {
525
- attributes: true,
526
- attributeFilter: ["class"],
527
- });
528
- }
529
-
530
- #teardownSuggestionsObserver() {
531
- if (!this.#suggestionsObserver) return;
532
- this.#suggestionsObserver.disconnect();
533
- this.#suggestionsObserver = null;
534
- }
535
-
536
- #teardownAutoCompleteSizing() {
537
- if (!this.#autoCompleteResizeHandler) return;
538
- window.removeEventListener("resize", this.#autoCompleteResizeHandler);
539
- window.removeEventListener("scroll", this.#autoCompleteScrollHandler, true);
540
- if (window.visualViewport) {
541
- window.visualViewport.removeEventListener("resize", this.#autoCompleteViewportHandler);
542
- window.visualViewport.removeEventListener("scroll", this.#autoCompleteViewportHandler);
543
- }
544
- this.#autoCompleteResizeHandler = null;
545
- this.#autoCompleteScrollHandler = null;
546
- this.#autoCompleteViewportHandler = null;
547
- }
548
-
549
- #updateSuggestionMaxHeight() {
550
- if (!this.#input) return;
551
- const container = this.#input.parentElement;
552
- if (!container) return;
553
-
554
- const rect = container.getBoundingClientRect();
555
- const viewportHeight = window.visualViewport?.height || window.innerHeight;
556
- const gap = this.#readSpacingToken(container, "--ac-viewport-gap") || 0;
557
- const direction = container.getAttribute("data-direction") || "down";
558
-
559
- const available = direction === "up"
560
- ? rect.top - gap
561
- : viewportHeight - rect.bottom - gap;
562
-
563
- const maxHeight = Math.max(0, Math.floor(available));
564
- container.style.setProperty("--ac-max-height", `${maxHeight}px`);
565
- }
566
-
567
- #readSpacingToken(element, tokenName) {
568
- const value = getComputedStyle(element).getPropertyValue(tokenName).trim();
569
- if (!value) return 0;
570
- if (!this.#lengthProbe) return 0;
571
- this.#lengthProbe.style.height = value;
572
- const resolved = getComputedStyle(this.#lengthProbe).height;
573
- const parsed = Number.parseFloat(resolved);
574
- return Number.isFinite(parsed) ? parsed : 0;
575
- }
576
-
577
- #handleSuggestionsUpdated(event) {
578
-
579
- const results = event?.detail?.results;
580
- if (!Array.isArray(results) || !this.settings?.categories) return;
581
- if (!results.length) {
582
- this.#icon?.setAttribute("icon", this.icon);
583
- return;
584
- }
585
-
586
- const categories = this.settings.categories;
587
- const firstResult = results[0];
588
- const categoryConfig = categories[firstResult?.category] || {};
589
- const useIconForInput = categoryConfig?.useIconForInput ?? this.settings?.useIconForInput;
590
-
591
- if (typeof useIconForInput === "string") {
592
- this.#icon?.setAttribute("icon", useIconForInput);
593
- return;
594
- }
595
-
596
- if (useIconForInput === true) {
597
- const icon =
598
- firstResult?.icon ||
599
- firstResult?.element?.querySelector?.("pds-icon, svg-icon")?.getAttribute?.("icon");
600
- if (icon) {
601
- this.#icon?.setAttribute("icon", icon);
602
- return;
603
- }
604
- }
605
-
606
- this.#resetIconToDefault();
607
- }
608
575
 
609
- #resetIconToDefault() {
610
- this.#icon?.setAttribute("icon", this.icon);
611
- }
576
+ const container = this.#input?.parentElement;
577
+ if (container?.style) {
578
+ container.style.removeProperty("--ac-bg-default");
579
+ container.style.removeProperty("--ac-color-default");
580
+ container.style.removeProperty("--ac-accent-color");
581
+
582
+ const gridOverride = this.itemGrid;
583
+ if (gridOverride) {
584
+ container.style.setProperty("--ac-grid", gridOverride);
585
+ } else if (settings.hideCategory === true) {
586
+ container.style.setProperty("--ac-grid", "45px 1fr");
587
+ } else {
588
+ container.style.removeProperty("--ac-grid");
589
+ }
590
+ }
591
+
592
+ if (!this.#input._autoComplete) {
593
+ this.#input._autoComplete = new AutoComplete(
594
+ this.#input.parentNode,
595
+ this.#input,
596
+ settings,
597
+ );
598
+ }
599
+
600
+ this.#wrapAutoCompleteResultsHandler(this.#input._autoComplete);
601
+ setTimeout(() => {
602
+ this.#input._autoComplete.focusHandler(e);
603
+ this.#setupAutoCompleteSizing();
604
+ this.#updateSuggestionMaxHeight();
605
+ this.#setupSuggestionsObserver();
606
+ }, 100);
607
+ }
608
+ }
609
+
610
+ #wrapAutoCompleteResultsHandler(autoComplete) {
611
+ if (!autoComplete || autoComplete.__pdsSuggestionsWrapped) return;
612
+ autoComplete.__pdsSuggestionsWrapped = true;
613
+ const originalResultsHandler =
614
+ autoComplete.resultsHandler?.bind(autoComplete);
615
+ if (!originalResultsHandler) return;
616
+
617
+ autoComplete.resultsHandler = (results, options) => {
618
+ const container = this.#input?.parentElement;
619
+ if (container && autoComplete.settings) {
620
+ autoComplete.settings.direction =
621
+ this.#resolveSuggestionDirection(container);
622
+ }
623
+ this.dispatchEvent(
624
+ new CustomEvent("suggestions-updated", {
625
+ detail: { results },
626
+ bubbles: true,
627
+ composed: true,
628
+ }),
629
+ );
630
+ const res = originalResultsHandler(results, options);
631
+ this.#updateSuggestionMaxHeight();
632
+ return res;
633
+ };
634
+ }
635
+
636
+ #setupAutoCompleteSizing() {
637
+ if (this.#autoCompleteResizeHandler) return;
638
+ this.#autoCompleteResizeHandler = () => this.#updateSuggestionMaxHeight();
639
+ this.#autoCompleteScrollHandler = () => this.#updateSuggestionMaxHeight();
640
+ this.#autoCompleteViewportHandler = () => this.#updateSuggestionMaxHeight();
641
+
642
+ window.addEventListener("resize", this.#autoCompleteResizeHandler);
643
+ window.addEventListener("scroll", this.#autoCompleteScrollHandler, true);
644
+ if (window.visualViewport) {
645
+ window.visualViewport.addEventListener(
646
+ "resize",
647
+ this.#autoCompleteViewportHandler,
648
+ );
649
+ window.visualViewport.addEventListener(
650
+ "scroll",
651
+ this.#autoCompleteViewportHandler,
652
+ );
653
+ }
654
+ }
655
+
656
+ #setupSuggestionsObserver() {
657
+ if (this.#suggestionsObserver) return;
658
+ const container = this.#input?.parentElement;
659
+ const root = container?.shadowRoot ?? container;
660
+ const suggestion = root?.querySelector?.(".ac-suggestion");
661
+ if (!suggestion) return;
662
+ this.#suggestionsObserver = new MutationObserver(() => {
663
+ if (!suggestion.classList.contains("ac-active")) {
664
+ this.#resetIconToDefault();
665
+ }
666
+ });
667
+ this.#suggestionsObserver.observe(suggestion, {
668
+ attributes: true,
669
+ attributeFilter: ["class"],
670
+ });
671
+ }
672
+
673
+ #teardownSuggestionsObserver() {
674
+ if (!this.#suggestionsObserver) return;
675
+ this.#suggestionsObserver.disconnect();
676
+ this.#suggestionsObserver = null;
677
+ }
678
+
679
+ #teardownAutoCompleteSizing() {
680
+ if (!this.#autoCompleteResizeHandler) return;
681
+ window.removeEventListener("resize", this.#autoCompleteResizeHandler);
682
+ window.removeEventListener("scroll", this.#autoCompleteScrollHandler, true);
683
+ if (window.visualViewport) {
684
+ window.visualViewport.removeEventListener(
685
+ "resize",
686
+ this.#autoCompleteViewportHandler,
687
+ );
688
+ window.visualViewport.removeEventListener(
689
+ "scroll",
690
+ this.#autoCompleteViewportHandler,
691
+ );
692
+ }
693
+ this.#autoCompleteResizeHandler = null;
694
+ this.#autoCompleteScrollHandler = null;
695
+ this.#autoCompleteViewportHandler = null;
696
+ }
697
+
698
+ #updateSuggestionMaxHeight() {
699
+ if (!this.#input) return;
700
+ const container = this.#input.parentElement;
701
+ if (!container) return;
702
+
703
+ const rect = container.getBoundingClientRect();
704
+ const viewportHeight = window.visualViewport?.height || window.innerHeight;
705
+ const gap = this.#readSpacingToken(container, "--ac-viewport-gap") || 0;
706
+ const root = container.shadowRoot ?? container;
707
+ const suggestion = root?.querySelector?.(".ac-suggestion");
708
+ const currentDirection =
709
+ suggestion?.getAttribute("data-direction") ||
710
+ container.getAttribute("data-direction") ||
711
+ "down";
712
+
713
+ const availableDown = viewportHeight - rect.bottom - gap;
714
+ const availableUp = rect.top - gap;
715
+ const direction = this.#resolveSuggestionDirection(container);
716
+
717
+ if (direction !== currentDirection) {
718
+ container.setAttribute("data-direction", direction);
719
+ if (suggestion) suggestion.setAttribute("data-direction", direction);
720
+ if (suggestion) {
721
+ const offset =
722
+ this.#readSpacingToken(container, "--ac-suggest-offset") || 0;
723
+ if (direction === "up") {
724
+ suggestion.style.top = "auto";
725
+ suggestion.style.bottom = `${rect.height + offset}px`;
726
+ } else {
727
+ suggestion.style.bottom = "auto";
728
+ suggestion.style.top = `${rect.height + offset}px`;
729
+ }
730
+ }
731
+ }
732
+
733
+ const available = direction === "up" ? availableUp : availableDown;
734
+
735
+ const maxHeight = Math.max(0, Math.floor(available));
736
+ container.style.setProperty("--ac-max-height", `${maxHeight}px`);
737
+ }
738
+
739
+ #resolveSuggestionDirection(container) {
740
+ const rect = container.getBoundingClientRect();
741
+ const viewportHeight = window.visualViewport?.height || window.innerHeight;
742
+ const gap = this.#readSpacingToken(container, "--ac-viewport-gap") || 0;
743
+ const availableDown = viewportHeight - rect.bottom - gap;
744
+ const availableUp = rect.top - gap;
745
+ const maxDefault =
746
+ this.#readSpacingToken(container, "--ac-max-height-default") || 300;
747
+ const minDown = Math.min(maxDefault, 180);
748
+
749
+ return availableDown >= minDown || availableDown >= availableUp
750
+ ? "down"
751
+ : "up";
752
+ }
753
+
754
+ #readSpacingToken(element, tokenName) {
755
+ const value = getComputedStyle(element).getPropertyValue(tokenName).trim();
756
+ if (!value) return 0;
757
+ if (!this.#lengthProbe) return 0;
758
+ this.#lengthProbe.style.height = value;
759
+ const resolved = getComputedStyle(this.#lengthProbe).height;
760
+ const parsed = Number.parseFloat(resolved);
761
+ return Number.isFinite(parsed) ? parsed : 0;
762
+ }
763
+
764
+ #handleSuggestionsUpdated(event) {
765
+ const results = event?.detail?.results;
766
+ if (!Array.isArray(results) || !this.settings?.categories) return;
767
+ if (!results.length) {
768
+ this.#icon?.setAttribute("icon", this.icon);
769
+ return;
770
+ }
771
+
772
+ const categories = this.settings.categories;
773
+ const firstResult = results[0];
774
+ const categoryConfig = categories[firstResult?.category] || {};
775
+ const useIconForInput =
776
+ categoryConfig?.useIconForInput ?? this.settings?.useIconForInput;
777
+
778
+ if (typeof useIconForInput === "string") {
779
+ this.#icon?.setAttribute("icon", useIconForInput);
780
+ return;
781
+ }
782
+
783
+ if (useIconForInput === true) {
784
+ const icon =
785
+ firstResult?.icon ||
786
+ firstResult?.element
787
+ ?.querySelector?.("pds-icon, svg-icon")
788
+ ?.getAttribute?.("icon");
789
+ if (icon) {
790
+ this.#icon?.setAttribute("icon", icon);
791
+ return;
792
+ }
793
+ }
794
+
795
+ this.#resetIconToDefault();
796
+ }
797
+
798
+ #resetIconToDefault() {
799
+ this.#icon?.setAttribute("icon", this.icon);
800
+ }
612
801
  }
613
802
 
614
803
  if (!customElements.get("pds-omnibox")) {
615
- customElements.define("pds-omnibox", PdsOmnibox);
804
+ customElements.define("pds-omnibox", PdsOmnibox);
616
805
  }