@wpmoo/ui 1.0.0-rc.2 → 1.0.0-rc.4

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 (84) hide show
  1. package/ASSET_LICENSE.md +3 -1
  2. package/README.md +50 -107
  3. package/certification.json +20 -3
  4. package/dist/assets/css/moo-ui.css +8254 -7629
  5. package/dist/assets/css/moo-ui.min.css +3 -3
  6. package/dist/assets/css/moo.css +595 -71
  7. package/dist/assets/css/moo.min.css +3 -3
  8. package/dist/js/chart.js +15258 -0
  9. package/dist/js/chart.min.js +27 -0
  10. package/dist/js/combobox.js +98 -40
  11. package/dist/js/context-menu.js +5 -0
  12. package/dist/js/datatable.js +5 -0
  13. package/dist/js/datepicker.js +1154 -0
  14. package/dist/js/datepicker.min.js +6 -0
  15. package/dist/js/moo-ui.js +18950 -0
  16. package/dist/js/moo-ui.min.js +27 -0
  17. package/dist/js/sidebar.js +67 -25
  18. package/dist/js/slider.js +324 -0
  19. package/package.json +24 -4
  20. package/scss/_components.scss +73 -0
  21. package/scss/_config.scss +24 -0
  22. package/scss/_settings.scss +8 -0
  23. package/scss/components/_accordion.scss +59 -0
  24. package/scss/components/_alert.scss +94 -0
  25. package/scss/components/_avatar.scss +154 -0
  26. package/scss/components/_badge.scss +33 -0
  27. package/scss/components/_breadcrumb.scss +130 -0
  28. package/scss/components/_button.scss +228 -0
  29. package/scss/components/_button_group.scss +51 -0
  30. package/scss/components/_card.scss +142 -0
  31. package/scss/components/_checkbox.scss +115 -0
  32. package/scss/components/_close_button.scss +59 -0
  33. package/scss/components/_collapsible.scss +43 -0
  34. package/scss/components/_combobox.scss +258 -0
  35. package/scss/components/_context-menu.scss +28 -0
  36. package/scss/components/_datatable.scss +1082 -0
  37. package/scss/components/_datepicker.scss +236 -0
  38. package/scss/components/_dialog.scss +66 -0
  39. package/scss/components/_dropdown.scss +202 -0
  40. package/scss/components/_field.scss +125 -0
  41. package/scss/components/_input.scss +35 -0
  42. package/scss/components/_input_group.scss +201 -0
  43. package/scss/components/_kbd.scss +10 -0
  44. package/scss/components/_menubar.scss +16 -0
  45. package/scss/components/_navigation.scss +41 -0
  46. package/scss/components/_pagination.scss +70 -0
  47. package/scss/components/_popover.scss +47 -0
  48. package/scss/components/_progress.scss +7 -0
  49. package/scss/components/_radio_group.scss +9 -0
  50. package/scss/components/_select.scss +7 -0
  51. package/scss/components/_separator.scss +15 -0
  52. package/scss/components/_sheet.scss +32 -0
  53. package/scss/components/_sidebar.scss +7 -0
  54. package/scss/components/_skeleton.scss +17 -0
  55. package/scss/components/_slider.scss +214 -0
  56. package/scss/components/_spinner.scss +17 -0
  57. package/scss/components/_switch.scss +25 -0
  58. package/scss/components/_table.scss +7 -0
  59. package/scss/components/_tabs.scss +139 -0
  60. package/scss/components/_textarea.scss +7 -0
  61. package/scss/components/_toast.scss +119 -0
  62. package/scss/components/_toggle_group.scss +19 -0
  63. package/scss/components/_tooltip.scss +83 -0
  64. package/scss/components/sidebar/_collapsed.scss +187 -0
  65. package/scss/components/sidebar/_identity.scss +72 -0
  66. package/scss/components/sidebar/_inset.scss +59 -0
  67. package/scss/components/sidebar/_layout.scss +176 -0
  68. package/scss/components/sidebar/_menus.scss +236 -0
  69. package/scss/foundations/_core_global_primitives.scss +5 -0
  70. package/scss/foundations/_core_state_layer.scss +25 -0
  71. package/scss/foundations/_focus.scss +139 -0
  72. package/scss/foundations/_overlay_backdrop.scss +19 -0
  73. package/scss/moo-core.scss +47 -0
  74. package/scss/moo-ui.scss +50 -0
  75. package/scss/settings/_bootstrap_overrides.scss +11 -0
  76. package/scss/settings/_component_variables.scss +479 -0
  77. package/scss/settings/_forms.scss +65 -0
  78. package/scss/settings/_palette.scss +132 -0
  79. package/scss/themes/_scoped_core.scss +239 -0
  80. package/scss/themes/_standalone_root.scss +117 -0
  81. package/scss/utilities/_scroll_fade.scss +193 -0
  82. package/scss/utilities/_scroll_fade_primitives.scss +43 -0
  83. package/scss/_facade-settings.scss +0 -51
  84. package/scss/settings/_facade_public.scss +0 -23
@@ -1,3 +1,8 @@
1
+ /*!
2
+ * Moo UI combobox.js v1.0.0-rc.4 (https://ui.wpmoo.org/)
3
+ * Copyright 2026 WPMoo (https://wpmoo.org)
4
+ * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
+ */
1
6
  const instances = new WeakMap();
2
7
  const normalize = (value) => value.trim().toLowerCase();
3
8
 
@@ -30,36 +35,36 @@ export default class Combobox {
30
35
  throw new TypeError("Combobox requires an input, menu, and at least one option.");
31
36
  }
32
37
 
33
- this._isMultiple = element.dataset.mooComboboxMultiple === "true";
38
+ this._isMultiple = element.dataset.comboboxMultiple === "true";
34
39
  this._hidden = this._isMultiple ? null : element.querySelector('input[type="hidden"]');
35
40
  this._chipValue = element.querySelector(".combobox-value");
36
- this._valueStore = element.querySelector("[data-moo-combobox-value-store]");
37
- this._chipIconTemplate = element.querySelector("[data-moo-combobox-chip-icon]");
38
- this._clearTrigger = element.querySelector("[data-moo-combobox-clear]");
41
+ this._valueStore = element.querySelector("[data-combobox-value-store]");
42
+ this._chipIconTemplate = element.querySelector("[data-combobox-chip-icon]");
43
+ this._clearTrigger = element.querySelector("[data-combobox-clear]");
39
44
  this._indicator = element.querySelector(".combobox-indicator");
40
- this._groups = Array.from(element.querySelectorAll("[data-moo-combobox-group]"));
41
- this._separators = Array.from(element.querySelectorAll("[data-moo-combobox-separator]"));
45
+ this._groups = Array.from(element.querySelectorAll("[data-combobox-group]"));
46
+ this._separators = Array.from(element.querySelectorAll("[data-combobox-separator]"));
42
47
  this._listeners = [];
43
48
  this._generated = [];
44
49
  this._startsOpen = this._menu.classList.contains("show");
45
50
 
46
- this._empty = this._menu.querySelector("[data-moo-combobox-empty]");
51
+ this._empty = this._menu.querySelector("[data-combobox-empty]");
47
52
  if (!this._empty) {
48
53
  this._empty = this._document.createElement("li");
49
54
  this._empty.className = "combobox-empty";
50
55
  this._empty.hidden = true;
51
- this._empty.dataset.mooComboboxEmpty = "true";
56
+ this._empty.dataset.comboboxEmpty = "true";
52
57
  this._empty.textContent = this._config.noResultsText;
53
58
  this._menu.appendChild(this._empty);
54
59
  this._generated.push(this._empty);
55
60
  }
56
61
 
57
- this._liveRegion = element.querySelector("[data-moo-combobox-live]");
62
+ this._liveRegion = element.querySelector("[data-combobox-live]");
58
63
  if (!this._liveRegion) {
59
64
  this._liveRegion = this._document.createElement("span");
60
65
  this._liveRegion.className = "visually-hidden";
61
66
  this._liveRegion.setAttribute("aria-live", "polite");
62
- this._liveRegion.dataset.mooComboboxLive = "true";
67
+ this._liveRegion.dataset.comboboxLive = "true";
63
68
  element.appendChild(this._liveRegion);
64
69
  this._generated.push(this._liveRegion);
65
70
  }
@@ -67,8 +72,8 @@ export default class Combobox {
67
72
  instances.set(element, this);
68
73
  this._bindEvents();
69
74
  this._toggleClear(
70
- this._input.dataset.mooComboboxSelected === "true" ||
71
- element.dataset.mooComboboxSelected === "true"
75
+ this._input.dataset.comboboxSelected === "true" ||
76
+ element.dataset.comboboxSelected === "true"
72
77
  );
73
78
  this._syncMultipleValue();
74
79
  this._filterOptions({ open: this._startsOpen, activate: this._startsOpen });
@@ -85,8 +90,8 @@ export default class Combobox {
85
90
  this._closeMenu(false);
86
91
  this._generated.forEach((element) => element.remove());
87
92
  this._generated = [];
88
- this._chipValue?.querySelectorAll("[data-moo-combobox-generated]").forEach((item) => item.remove());
89
- this._valueStore?.querySelectorAll("[data-moo-combobox-generated]").forEach((item) => item.remove());
93
+ this._chipValue?.querySelectorAll("[data-combobox-generated]").forEach((item) => item.remove());
94
+ this._valueStore?.querySelectorAll("[data-combobox-generated]").forEach((item) => item.remove());
90
95
  instances.delete(this._element);
91
96
  }
92
97
 
@@ -108,7 +113,7 @@ export default class Combobox {
108
113
  }
109
114
 
110
115
  _optionGroupIsHidden(option) {
111
- return option.closest("[data-moo-combobox-group]")?.hidden || false;
116
+ return option.closest("[data-combobox-group]")?.hidden || false;
112
117
  }
113
118
 
114
119
  _visibleOptions() {
@@ -157,7 +162,10 @@ export default class Combobox {
157
162
  this._menu.classList.remove("show");
158
163
  this._input.setAttribute("aria-expanded", "false");
159
164
  this._input.removeAttribute("aria-activedescendant");
160
- this._options.forEach((option) => option.removeAttribute("aria-current"));
165
+ this._options.forEach((option) => {
166
+ option.removeAttribute("aria-current");
167
+ option.classList.remove("active");
168
+ });
161
169
  if (wasOpen && emit) {
162
170
  this._trigger("hidden");
163
171
  }
@@ -173,8 +181,8 @@ export default class Combobox {
173
181
 
174
182
  _toggleClear(selected) {
175
183
  const value = selected ? "true" : "false";
176
- this._element.dataset.mooComboboxSelected = value;
177
- this._input.dataset.mooComboboxSelected = value;
184
+ this._element.dataset.comboboxSelected = value;
185
+ this._input.dataset.comboboxSelected = value;
178
186
  if (this._clearTrigger) {
179
187
  this._clearTrigger.hidden = !selected;
180
188
  if (this._indicator) {
@@ -189,7 +197,7 @@ export default class Combobox {
189
197
  const chip = this._document.createElement("span");
190
198
  chip.className = "badge text-bg-secondary combobox-chip";
191
199
  chip.dataset.value = value;
192
- chip.dataset.mooComboboxGenerated = "true";
200
+ chip.dataset.comboboxGenerated = "true";
193
201
  const labelElement = this._document.createElement("span");
194
202
  labelElement.className = "combobox-chip__label";
195
203
  labelElement.textContent = label;
@@ -198,7 +206,7 @@ export default class Combobox {
198
206
  remove.className = "combobox-chip__remove";
199
207
  remove.type = "button";
200
208
  remove.dataset.value = value;
201
- remove.dataset.mooComboboxChipRemove = "true";
209
+ remove.dataset.comboboxChipRemove = "true";
202
210
  remove.setAttribute("aria-label", `Remove ${label}`);
203
211
  remove.append(this._chipIconTemplate?.content.cloneNode(true) || "x");
204
212
  chip.appendChild(remove);
@@ -215,13 +223,13 @@ export default class Combobox {
215
223
  }
216
224
  if (this._valueStore) {
217
225
  this._valueStore.replaceChildren();
218
- const name = this._valueStore.dataset.mooComboboxName || "";
226
+ const name = this._valueStore.dataset.comboboxName || "";
219
227
  selected.forEach((option) => {
220
228
  const field = this._document.createElement("input");
221
229
  field.type = "hidden";
222
230
  field.name = name;
223
231
  field.value = option.dataset.value || "";
224
- field.dataset.mooComboboxGenerated = "true";
232
+ field.dataset.comboboxGenerated = "true";
225
233
  this._valueStore.appendChild(field);
226
234
  });
227
235
  }
@@ -287,16 +295,35 @@ export default class Combobox {
287
295
  return this._visibleOptions().find((option) => option.id === activeId) || null;
288
296
  }
289
297
 
290
- _activateFirstOptionIfNeeded() {
298
+ _selectedOption() {
299
+ if (this._isMultiple) {
300
+ return null;
301
+ }
302
+ return (
303
+ this._visibleOptions().find(
304
+ (option) => option.getAttribute("aria-selected") === "true"
305
+ ) || null
306
+ );
307
+ }
308
+
309
+ _preferredActiveOption() {
310
+ return this._selectedOption() || this._visibleOptions()[0] || null;
311
+ }
312
+
313
+ _activatePreferredOptionIfNeeded() {
291
314
  if (!this._activeOption()) {
292
- this._setActiveOption(this._visibleOptions()[0] || null);
315
+ this._setActiveOption(this._preferredActiveOption());
293
316
  }
294
317
  }
295
318
 
296
- _setActiveOption(option) {
319
+ _setActiveOption(option, { scroll = true } = {}) {
297
320
  this._options.forEach((candidate) => {
298
321
  const active = candidate === option;
299
- candidate.toggleAttribute("aria-current", active);
322
+ if (active) {
323
+ candidate.setAttribute("aria-current", "true");
324
+ } else {
325
+ candidate.removeAttribute("aria-current");
326
+ }
300
327
  candidate.classList.toggle("active", active);
301
328
  });
302
329
  if (!option) {
@@ -304,12 +331,36 @@ export default class Combobox {
304
331
  return;
305
332
  }
306
333
  this._input.setAttribute("aria-activedescendant", option.id);
307
- const optionRect = option.getBoundingClientRect();
308
- const menuRect = this._menu.getBoundingClientRect();
309
- if (optionRect.top < menuRect.top) {
310
- this._menu.scrollTop -= menuRect.top - optionRect.top;
311
- } else if (optionRect.bottom > menuRect.bottom) {
312
- this._menu.scrollTop += optionRect.bottom - menuRect.bottom;
334
+ if (scroll) {
335
+ const optionRect = option.getBoundingClientRect();
336
+ const menuRect = this._menu.getBoundingClientRect();
337
+ if (optionRect.top < menuRect.top) {
338
+ this._menu.scrollTop -= menuRect.top - optionRect.top;
339
+ } else if (optionRect.bottom > menuRect.bottom) {
340
+ this._menu.scrollTop += optionRect.bottom - menuRect.bottom;
341
+ }
342
+ }
343
+ }
344
+
345
+ _activateOptionFromPointer(option, event) {
346
+ if (
347
+ event.pointerType === "touch" ||
348
+ option.disabled ||
349
+ option.getAttribute("aria-disabled") === "true" ||
350
+ option === this._activeOption()
351
+ ) {
352
+ return;
353
+ }
354
+ this._setActiveOption(option, { scroll: false });
355
+ }
356
+
357
+ _restoreSelectedActiveOption() {
358
+ if (!this._menu.classList.contains("show")) {
359
+ return;
360
+ }
361
+ const selected = this._selectedOption();
362
+ if (selected) {
363
+ this._setActiveOption(selected, { scroll: false });
313
364
  }
314
365
  }
315
366
 
@@ -341,7 +392,7 @@ export default class Combobox {
341
392
  this._emitChange();
342
393
  }
343
394
 
344
- _filterOptions({ open = true, activate = true } = {}) {
395
+ _filterOptions({ open = true, activate = true, resetActive = false } = {}) {
345
396
  if (open) {
346
397
  this._openMenu();
347
398
  }
@@ -355,24 +406,27 @@ export default class Combobox {
355
406
  this._syncGroupVisibility();
356
407
  this._empty.hidden = count !== 0;
357
408
  this._liveRegion.textContent = count === 0 ? "No results" : `${count} result${count === 1 ? "" : "s"}`;
409
+ if (resetActive) {
410
+ this._setActiveOption(null, { scroll: false });
411
+ }
358
412
  if (activate) {
359
- this._activateFirstOptionIfNeeded();
413
+ this._activatePreferredOptionIfNeeded();
360
414
  }
361
415
  }
362
416
 
363
417
  _bindEvents() {
364
418
  this._listen(this._input, "focus", () => {
365
419
  this._openMenu();
366
- if (!this._isMultiple && this._input.dataset.mooComboboxSelected === "true") {
420
+ if (!this._isMultiple && this._input.dataset.comboboxSelected === "true") {
367
421
  this._input.select();
368
422
  }
369
- this._activateFirstOptionIfNeeded();
423
+ this._activatePreferredOptionIfNeeded();
370
424
  });
371
425
  this._listen(this._input, "input", () => {
372
426
  if (!this._isMultiple) {
373
427
  this._clearSelection();
374
428
  }
375
- this._filterOptions();
429
+ this._filterOptions({ resetActive: true });
376
430
  });
377
431
  this._listen(this._input, "blur", (event) => {
378
432
  const nextTarget = event.relatedTarget;
@@ -383,11 +437,14 @@ export default class Combobox {
383
437
  });
384
438
  this._listen(this._input, "click", () => {
385
439
  this._openMenu();
386
- this._setActiveOption(this._visibleOptions()[0] || null);
440
+ this._setActiveOption(this._preferredActiveOption());
387
441
  });
388
442
  this._listen(this._input, "keydown", (event) => this._handleKeydown(event));
389
443
  this._options.forEach((option) => {
390
444
  this._listen(option, "keydown", (event) => this._handleKeydown(event));
445
+ this._listen(option, "pointerenter", (event) => {
446
+ this._activateOptionFromPointer(option, event);
447
+ });
391
448
  this._listen(option, "click", () => {
392
449
  this._chooseOption(option);
393
450
  if (this._isMultiple) {
@@ -402,8 +459,9 @@ export default class Combobox {
402
459
  this._clearSelection();
403
460
  this._input.value = "";
404
461
  this._input.focus();
405
- this._filterOptions();
462
+ this._filterOptions({ resetActive: true });
406
463
  });
464
+ this._listen(this._menu, "pointerleave", () => this._restoreSelectedActiveOption());
407
465
  this._listen(this._element, "click", (event) => this._handleRootClick(event));
408
466
  this._listen(this._document, "click", (event) => {
409
467
  if (event.target instanceof this._window.Node && !this._element.contains(event.target)) {
@@ -415,7 +473,7 @@ export default class Combobox {
415
473
  _handleRootClick(event) {
416
474
  const target = event.target;
417
475
  const trigger = target instanceof this._window.Element
418
- ? target.closest("[data-moo-combobox-chip-remove]")
476
+ ? target.closest("[data-combobox-chip-remove]")
419
477
  : null;
420
478
  if (trigger) {
421
479
  event.preventDefault();
@@ -1,3 +1,8 @@
1
+ /*!
2
+ * Moo UI context-menu.js v1.0.0-rc.4 (https://ui.wpmoo.org/)
3
+ * Copyright 2026 WPMoo (https://wpmoo.org)
4
+ * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
+ */
1
6
  const instances = new WeakMap();
2
7
 
3
8
  function pointerRect(event) {
@@ -1,3 +1,8 @@
1
+ /*!
2
+ * Moo UI datatable.js v1.0.0-rc.4 (https://ui.wpmoo.org/)
3
+ * Copyright 2026 WPMoo (https://wpmoo.org)
4
+ * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
+ */
1
6
  const instances = new WeakMap();
2
7
 
3
8
  function normalize(value) {