@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 sidebar.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
  export default class Sidebar {
@@ -39,7 +44,8 @@ export default class Sidebar {
39
44
  instances.set(element, this);
40
45
  this._bindEvents();
41
46
  this._restoreState();
42
- this._element.setAttribute("data-moo-sidebar-ready", "");
47
+ this._scrollActiveItemIntoView();
48
+ this._element.setAttribute("data-sidebar-ready", "");
43
49
  this._observeDirection();
44
50
  }
45
51
 
@@ -51,15 +57,15 @@ export default class Sidebar {
51
57
  this._directionObserver?.disconnect();
52
58
  this._closeFlyouts();
53
59
  this._element
54
- .querySelectorAll("[data-moo-sidebar-dropdown-positioned]")
60
+ .querySelectorAll("[data-sidebar-dropdown-positioned]")
55
61
  .forEach((item) => this._clearDropdownPosition(item));
56
62
  this._element
57
- .querySelectorAll("[data-moo-sidebar-tooltip]")
63
+ .querySelectorAll("[data-sidebar-tooltip]")
58
64
  .forEach((control) => this._disposeTooltip(control));
59
65
  this._offcanvas?.dispose();
60
66
  this._offcanvas = null;
61
67
  this._offcanvasTrigger = null;
62
- this._element.removeAttribute("data-moo-sidebar-ready");
68
+ this._element.removeAttribute("data-sidebar-ready");
63
69
  instances.delete(this._element);
64
70
  }
65
71
 
@@ -79,7 +85,7 @@ export default class Sidebar {
79
85
  }
80
86
 
81
87
  _isCollapsed() {
82
- return this._isDesktop() && this._element.dataset.mooSidebarState === "collapsed";
88
+ return this._isDesktop() && this._element.dataset.sidebarState === "collapsed";
83
89
  }
84
90
 
85
91
  _trigger(name, detail = {}) {
@@ -108,7 +114,7 @@ export default class Sidebar {
108
114
  }
109
115
 
110
116
  _restoreState() {
111
- const key = this._element.dataset.mooSidebarKey;
117
+ const key = this._element.dataset.sidebarKey;
112
118
  let stored = null;
113
119
  if (key) {
114
120
  try {
@@ -120,19 +126,55 @@ export default class Sidebar {
120
126
  const initial =
121
127
  stored === "collapsed" || stored === "expanded"
122
128
  ? stored
123
- : this._element.dataset.mooSidebarState === "collapsed"
129
+ : this._element.dataset.sidebarState === "collapsed"
124
130
  ? "collapsed"
125
131
  : "expanded";
126
132
  this._setState(initial, false, false);
127
133
  }
128
134
 
135
+ _scrollActiveItemIntoView() {
136
+ const activeRoute = this._element.querySelector(
137
+ '[data-slot="sidebar-content"] a[data-slot="sidebar-menu-button"][aria-current="page"], ' +
138
+ '[data-slot="sidebar-content"] a.sidebar-menu-button[aria-current="page"], ' +
139
+ '[data-slot="sidebar-content"] a.sidebar-menu-button.active'
140
+ );
141
+ const active = activeRoute || this._element.querySelector(
142
+ '[data-slot="sidebar-content"] [data-slot="sidebar-menu-button"][aria-current="page"], ' +
143
+ '[data-slot="sidebar-content"] .sidebar-menu-button[aria-current="page"], ' +
144
+ '[data-slot="sidebar-content"] .sidebar-menu-button.active'
145
+ );
146
+ const content = active?.closest?.('[data-slot="sidebar-content"]');
147
+ if (!active || !content || content.clientHeight <= 0) {
148
+ return;
149
+ }
150
+ const maxScrollTop = content.scrollHeight - content.clientHeight;
151
+ if (maxScrollTop <= 0) {
152
+ return;
153
+ }
154
+
155
+ const contentRect = content.getBoundingClientRect();
156
+ const activeRect = active.getBoundingClientRect();
157
+ if (contentRect.height <= 0 || activeRect.height <= 0) {
158
+ return;
159
+ }
160
+
161
+ const targetScrollTop =
162
+ content.scrollTop +
163
+ activeRect.top -
164
+ contentRect.top -
165
+ (content.clientHeight - activeRect.height) / 2;
166
+ content.scrollTop = Math.round(
167
+ Math.min(Math.max(targetScrollTop, 0), maxScrollTop)
168
+ );
169
+ }
170
+
129
171
  _setState(state, persist = true, emit = true) {
130
172
  const next = state === "collapsed" ? "collapsed" : "expanded";
131
- const previous = this._element.dataset.mooSidebarState;
132
- this._element.dataset.mooSidebarState = next;
133
- const key = this._element.dataset.mooSidebarKey;
173
+ const previous = this._element.dataset.sidebarState;
174
+ this._element.dataset.sidebarState = next;
175
+ const key = this._element.dataset.sidebarKey;
134
176
  if (key === "catalog-shell") {
135
- this._root.dataset.mooSidebarCatalogState = next;
177
+ this._root.dataset.sidebarCatalogState = next;
136
178
  }
137
179
  if (persist && key) {
138
180
  try {
@@ -155,16 +197,16 @@ export default class Sidebar {
155
197
 
156
198
  _toggle() {
157
199
  this._setState(
158
- this._element.dataset.mooSidebarState === "collapsed" ? "expanded" : "collapsed"
200
+ this._element.dataset.sidebarState === "collapsed" ? "expanded" : "collapsed"
159
201
  );
160
202
  }
161
203
 
162
204
  _syncControls() {
163
205
  const expanded = this._isDesktop()
164
- ? this._element.dataset.mooSidebarState === "expanded"
206
+ ? this._element.dataset.sidebarState === "expanded"
165
207
  : this._sidebar?.classList.contains("show") || false;
166
208
  this._element
167
- .querySelectorAll("[data-moo-sidebar-trigger], [data-moo-sidebar-rail]")
209
+ .querySelectorAll("[data-sidebar-trigger], [data-sidebar-rail]")
168
210
  .forEach((control) => control.setAttribute("aria-expanded", String(expanded)));
169
211
  }
170
212
 
@@ -186,7 +228,7 @@ export default class Sidebar {
186
228
  if (!item) {
187
229
  return;
188
230
  }
189
- delete item.dataset.mooSidebarDropdownPositioned;
231
+ delete item.dataset.sidebarDropdownPositioned;
190
232
  item.style.removeProperty("--moo-sidebar-dropdown-block-start");
191
233
  item.style.removeProperty("--moo-sidebar-dropdown-inline-start");
192
234
  }
@@ -237,7 +279,7 @@ export default class Sidebar {
237
279
  "--moo-sidebar-dropdown-inline-start",
238
280
  `${Math.round(inlineStart)}px`
239
281
  );
240
- item.dataset.mooSidebarDropdownPositioned = "";
282
+ item.dataset.sidebarDropdownPositioned = "";
241
283
  }
242
284
 
243
285
  _removeFlyoutPortal() {
@@ -281,7 +323,7 @@ export default class Sidebar {
281
323
  flyout.removeAttribute("id");
282
324
  flyout.classList.remove("collapse", "show", "collapsing");
283
325
  flyout.classList.add("sidebar-menu-flyout");
284
- flyout.dataset.mooSidebarFlyout = "";
326
+ flyout.dataset.sidebarFlyout = "";
285
327
  flyout.removeAttribute("style");
286
328
  flyout.style.setProperty("--moo-sidebar-flyout-block-start", `${Math.round(rect.top)}px`);
287
329
  flyout.style.setProperty(
@@ -328,7 +370,7 @@ export default class Sidebar {
328
370
  }
329
371
  const collapsed = this._isCollapsed();
330
372
  const placement = this._root.dir === "rtl" ? "left" : "right";
331
- this._element.querySelectorAll("[data-moo-sidebar-tooltip]").forEach((control) => {
373
+ this._element.querySelectorAll("[data-sidebar-tooltip]").forEach((control) => {
332
374
  this._disposeTooltip(control);
333
375
  if (
334
376
  !collapsed ||
@@ -343,7 +385,7 @@ export default class Sidebar {
343
385
  // state-driven Sidebar tooltip instead.
344
386
  const anchor = this._tooltipAnchor(control);
345
387
  new Tooltip(anchor, {
346
- title: control.getAttribute("data-moo-sidebar-tooltip"),
388
+ title: control.getAttribute("data-sidebar-tooltip"),
347
389
  placement,
348
390
  container: "body",
349
391
  trigger: "hover focus",
@@ -386,7 +428,7 @@ export default class Sidebar {
386
428
  this._listen(this._window, "resize", () => {
387
429
  this._closeFlyouts();
388
430
  this._element
389
- .querySelectorAll("[data-moo-sidebar-dropdown-positioned]")
431
+ .querySelectorAll("[data-sidebar-dropdown-positioned]")
390
432
  .forEach((item) => this._clearDropdownPosition(item));
391
433
  this._syncControls();
392
434
  this._syncTooltips();
@@ -397,18 +439,18 @@ export default class Sidebar {
397
439
  if (!(target instanceof this._window.Element) || !this._element.contains(target)) {
398
440
  return null;
399
441
  }
400
- if (target.matches('[data-bs-toggle="dropdown"][data-moo-sidebar-tooltip]')) {
442
+ if (target.matches('[data-bs-toggle="dropdown"][data-sidebar-tooltip]')) {
401
443
  return target;
402
444
  }
403
445
  return target.querySelector?.(
404
- '[data-bs-toggle="dropdown"][data-moo-sidebar-tooltip]'
446
+ '[data-bs-toggle="dropdown"][data-sidebar-tooltip]'
405
447
  ) || null;
406
448
  }
407
449
 
408
450
  _handleControlClick(event) {
409
451
  const target = event.target;
410
452
  const control = target instanceof this._window.Element
411
- ? target.closest("[data-moo-sidebar-trigger], [data-moo-sidebar-rail]")
453
+ ? target.closest("[data-sidebar-trigger], [data-sidebar-rail]")
412
454
  : null;
413
455
  if (!control || !this._element.contains(control)) {
414
456
  return;
@@ -419,7 +461,7 @@ export default class Sidebar {
419
461
  this._toggle();
420
462
  return;
421
463
  }
422
- if (!control.matches("[data-moo-sidebar-trigger]")) {
464
+ if (!control.matches("[data-sidebar-trigger]")) {
423
465
  return;
424
466
  }
425
467
  const sidebar = this._document.getElementById(control.getAttribute("aria-controls"));
@@ -478,7 +520,7 @@ export default class Sidebar {
478
520
  }
479
521
  const preferred =
480
522
  this._document.querySelector(
481
- '[data-slot="sidebar-wrapper"][data-moo-sidebar-key]'
523
+ '[data-slot="sidebar-wrapper"][data-sidebar-key]'
482
524
  ) || this._document.querySelector('[data-slot="sidebar-wrapper"]');
483
525
  if (preferred !== this._element) {
484
526
  return;
@@ -0,0 +1,324 @@
1
+ /*!
2
+ * Moo UI slider.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
+ */
6
+ const instances = new WeakMap();
7
+
8
+ function asNumber(value, fallback) {
9
+ const number = Number(value);
10
+ return Number.isFinite(number) ? number : fallback;
11
+ }
12
+
13
+ function inputMinimum(input) {
14
+ return asNumber(input.min, 0);
15
+ }
16
+
17
+ function inputMaximum(input) {
18
+ return asNumber(input.max, 100);
19
+ }
20
+
21
+ function inputStep(input) {
22
+ if (!input.step || input.step === "any") {
23
+ return 1;
24
+ }
25
+ const step = Number(input.step);
26
+ return Number.isFinite(step) && step > 0 ? step : 1;
27
+ }
28
+
29
+ function clamp(value, min, max) {
30
+ return Math.min(Math.max(value, min), max);
31
+ }
32
+
33
+ function decimalPlaces(value) {
34
+ const text = String(value);
35
+ if (!text.includes(".")) {
36
+ return 0;
37
+ }
38
+ return text.split(".").at(-1).length;
39
+ }
40
+
41
+ function snapToStep(value, input) {
42
+ const min = inputMinimum(input);
43
+ const max = inputMaximum(input);
44
+ if (input.step === "any") {
45
+ return Number(clamp(value, min, max).toFixed(4));
46
+ }
47
+ const step = inputStep(input);
48
+ const snapped = min + Math.round((value - min) / step) * step;
49
+ const precision = Math.max(decimalPlaces(step), decimalPlaces(min));
50
+ return clamp(Number(snapped.toFixed(precision)), min, max);
51
+ }
52
+
53
+ function valuePercent(input) {
54
+ const min = inputMinimum(input);
55
+ const max = inputMaximum(input);
56
+ if (max <= min) {
57
+ return 0;
58
+ }
59
+ return ((asNumber(input.value, min) - min) / (max - min)) * 100;
60
+ }
61
+
62
+ function displayValue(input) {
63
+ return input.value || String(inputMinimum(input));
64
+ }
65
+
66
+ export default class MooSlider {
67
+ static getInstance(element) {
68
+ return element?.nodeType === 1 ? instances.get(element) || null : null;
69
+ }
70
+
71
+ static getOrCreateInstance(element, config = {}) {
72
+ return MooSlider.getInstance(element) || new MooSlider(element, config);
73
+ }
74
+
75
+ constructor(element, config = {}) {
76
+ if (element?.nodeType !== 1 || !element.matches("[data-slider]")) {
77
+ throw new TypeError("MooSlider requires a [data-slider] root element.");
78
+ }
79
+ const existing = instances.get(element);
80
+ if (existing) {
81
+ return existing;
82
+ }
83
+
84
+ this._element = element;
85
+ this._document = element.ownerDocument;
86
+ this._window = this._document.defaultView;
87
+ this._config = { ...config };
88
+ this._listeners = [];
89
+ this._dragListeners = [];
90
+ this._draggingInput = null;
91
+ this._disposed = false;
92
+ this._inputs = Array.from(
93
+ element.querySelectorAll(':scope input[type="range"][data-slider-input]')
94
+ );
95
+ this._track = element.querySelector("[data-slider-track]");
96
+ this._output = element.querySelector("[data-slider-output]");
97
+
98
+ if (this._inputs.length < 1 || this._inputs.length > 2) {
99
+ throw new TypeError("MooSlider requires one or two native range inputs.");
100
+ }
101
+ if (!this._track) {
102
+ throw new TypeError("MooSlider requires a [data-slider-track] element.");
103
+ }
104
+
105
+ instances.set(element, this);
106
+ this._bindEvents();
107
+ this._sync();
108
+ }
109
+
110
+ dispose() {
111
+ if (this._disposed) return;
112
+ this._disposed = true;
113
+ this._clearDragListeners();
114
+ this._clearPointerFocus();
115
+ this._listeners.forEach(({ target, type, handler, options }) => {
116
+ target.removeEventListener(type, handler, options);
117
+ });
118
+ this._listeners = [];
119
+ if (instances.get(this._element) === this) {
120
+ instances.delete(this._element);
121
+ }
122
+ }
123
+
124
+ _listen(target, type, handler, options) {
125
+ if (!target) {
126
+ return;
127
+ }
128
+ target.addEventListener(type, handler, options);
129
+ this._listeners.push({ target, type, handler, options });
130
+ }
131
+
132
+ _listenDuringDrag(target, type, handler, options) {
133
+ if (!target) {
134
+ return;
135
+ }
136
+ target.addEventListener(type, handler, options);
137
+ this._dragListeners.push({ target, type, handler, options });
138
+ }
139
+
140
+ _clearDragListeners() {
141
+ this._dragListeners.forEach(({ target, type, handler, options }) => {
142
+ target.removeEventListener(type, handler, options);
143
+ });
144
+ this._dragListeners = [];
145
+ this._draggingInput = null;
146
+ this._element.removeAttribute("data-slider-dragging");
147
+ }
148
+
149
+ _bindEvents() {
150
+ this._inputs.forEach((input) => {
151
+ this._listen(input, "input", () => this._sync(input));
152
+ this._listen(input, "change", () => {
153
+ this._sync(input);
154
+ this._trigger("change");
155
+ });
156
+ this._listen(input, "keydown", () => this._clearPointerFocus());
157
+ this._listen(input, "focusout", () => this._clearPointerFocus());
158
+ });
159
+ const forms = new Set(
160
+ this._inputs
161
+ .map((input) => input.form || input.closest?.("form"))
162
+ .filter(Boolean),
163
+ );
164
+ forms.forEach((form) => {
165
+ this._listen(form, "reset", () => {
166
+ this._window.setTimeout(() => this._sync(), 0);
167
+ });
168
+ });
169
+ this._listen(this._track, "pointerdown", (event) => this._handleTrackPointer(event));
170
+ }
171
+
172
+ _trigger(name) {
173
+ this._element.dispatchEvent(
174
+ new this._window.CustomEvent(`${name}.moo.slider`, {
175
+ bubbles: true,
176
+ })
177
+ );
178
+ }
179
+
180
+ _isRange() {
181
+ return this._inputs.length === 2;
182
+ }
183
+
184
+ _sync(changedInput = null) {
185
+ if (this._isRange()) {
186
+ const [startInput, endInput] = this._inputs;
187
+ const start = asNumber(startInput.value, inputMinimum(startInput));
188
+ const end = asNumber(endInput.value, inputMaximum(endInput));
189
+ if (start > end) {
190
+ if (changedInput === endInput) {
191
+ endInput.value = startInput.value;
192
+ } else {
193
+ startInput.value = endInput.value;
194
+ }
195
+ }
196
+ this._writeFill(valuePercent(startInput), valuePercent(endInput));
197
+ this._writeOutput(`${displayValue(startInput)} - ${displayValue(endInput)}`);
198
+ this._syncAria(startInput);
199
+ this._syncAria(endInput);
200
+ return;
201
+ }
202
+
203
+ const input = this._inputs[0];
204
+ this._writeFill(0, valuePercent(input));
205
+ this._writeOutput(displayValue(input));
206
+ this._syncAria(input);
207
+ }
208
+
209
+ _syncAria(input) {
210
+ input.setAttribute("aria-valuemin", String(inputMinimum(input)));
211
+ input.setAttribute("aria-valuemax", String(inputMaximum(input)));
212
+ input.setAttribute("aria-valuenow", displayValue(input));
213
+ }
214
+
215
+ _writeFill(start, end) {
216
+ const clampedStart = clamp(start, 0, 100);
217
+ const clampedEnd = clamp(end, 0, 100);
218
+ this._element.style.setProperty("--moo-slider-start", `${Math.min(clampedStart, clampedEnd)}%`);
219
+ this._element.style.setProperty("--moo-slider-end", `${Math.max(clampedStart, clampedEnd)}%`);
220
+ }
221
+
222
+ _writeOutput(value) {
223
+ if (this._output) {
224
+ this._output.textContent = value;
225
+ }
226
+ }
227
+
228
+ _handleTrackPointer(event) {
229
+ if (event.button !== undefined && event.button !== 0) {
230
+ return;
231
+ }
232
+ const enabledInputs = this._inputs.filter((input) => !input.disabled);
233
+ if (!enabledInputs.length) {
234
+ return;
235
+ }
236
+ event.preventDefault?.();
237
+ const percent = this._pointerPercent(event);
238
+ const target = this._nearestInput(percent * 100, enabledInputs);
239
+ this._setPointerFocus();
240
+ this._startDrag(target, event);
241
+ this._setInputFromPointer(target, event);
242
+ }
243
+
244
+ _setPointerFocus() {
245
+ this._element.setAttribute("data-slider-pointer-focus", "true");
246
+ }
247
+
248
+ _clearPointerFocus() {
249
+ this._element.removeAttribute("data-slider-pointer-focus");
250
+ }
251
+
252
+ _startDrag(input, event) {
253
+ this._clearDragListeners();
254
+ this._draggingInput = input;
255
+ this._element.setAttribute("data-slider-dragging", "true");
256
+ this._track.setPointerCapture?.(event.pointerId);
257
+
258
+ const pointerId = event.pointerId;
259
+ const samePointer = (nextEvent) => pointerId === undefined || nextEvent.pointerId === pointerId;
260
+ const onMove = (moveEvent) => {
261
+ if (!samePointer(moveEvent) || this._draggingInput !== input) {
262
+ return;
263
+ }
264
+ moveEvent.preventDefault?.();
265
+ this._setInputFromPointer(input, moveEvent);
266
+ };
267
+ const onEnd = (endEvent) => {
268
+ if (!samePointer(endEvent) || this._draggingInput !== input) {
269
+ return;
270
+ }
271
+ endEvent.preventDefault?.();
272
+ this._setInputFromPointer(input, endEvent, false);
273
+ input.dispatchEvent(new this._window.Event("change", { bubbles: true }));
274
+ this._track.releasePointerCapture?.(pointerId);
275
+ this._clearDragListeners();
276
+ };
277
+
278
+ this._listenDuringDrag(this._document, "pointermove", onMove);
279
+ this._listenDuringDrag(this._document, "pointerup", onEnd);
280
+ this._listenDuringDrag(this._document, "pointercancel", onEnd);
281
+ }
282
+
283
+ _setInputFromPointer(input, event, emitInput = true) {
284
+ const percent = this._pointerPercent(event);
285
+ const min = inputMinimum(input);
286
+ const max = inputMaximum(input);
287
+ input.value = String(snapToStep(min + percent * (max - min), input));
288
+ input.focus({ preventScroll: true });
289
+ this._sync(input);
290
+ if (emitInput) {
291
+ input.dispatchEvent(new this._window.Event("input", { bubbles: true }));
292
+ }
293
+ }
294
+
295
+ _pointerPercent(event) {
296
+ const rect = this._track.getBoundingClientRect();
297
+ const orientation = this._element.dataset.sliderOrientation || "horizontal";
298
+ if (orientation === "vertical") {
299
+ return clamp((rect.bottom - event.clientY) / (rect.height || 1), 0, 1);
300
+ }
301
+ return this._horizontalPointerPercent(event, rect);
302
+ }
303
+
304
+ _horizontalPointerPercent(event, rect) {
305
+ const direction = this._window.getComputedStyle?.(this._element).direction;
306
+ const offset = direction === "rtl" ? rect.right - event.clientX : event.clientX - rect.left;
307
+ return clamp(offset / (rect.width || 1), 0, 1);
308
+ }
309
+
310
+ _nearestInput(percent, inputs) {
311
+ if (inputs.length === 1) {
312
+ return inputs[0];
313
+ }
314
+ const [startInput, endInput] = inputs;
315
+ const startPercent = valuePercent(startInput);
316
+ const endPercent = valuePercent(endInput);
317
+ const startDistance = Math.abs(startPercent - percent);
318
+ const endDistance = Math.abs(endPercent - percent);
319
+ if (startDistance === endDistance) {
320
+ return percent >= startPercent ? endInput : startInput;
321
+ }
322
+ return endDistance < startDistance ? endInput : startInput;
323
+ }
324
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wpmoo/ui",
3
- "version": "1.0.0-rc.2",
3
+ "version": "1.0.0-rc.4",
4
4
  "description": "Bootstrap markup. shadcn feel. A frontend-framework-free component system for server-rendered apps.",
5
5
  "license": "MIT",
6
6
  "author": "WPMoo (https://wpmoo.org)",
@@ -27,11 +27,22 @@
27
27
  "./moo-ui.min.css": "./dist/assets/css/moo-ui.min.css",
28
28
  "./moo.css": "./dist/assets/css/moo.css",
29
29
  "./moo.min.css": "./dist/assets/css/moo.min.css",
30
+ "./moo-ui.js": "./dist/js/moo-ui.js",
31
+ "./moo-ui.min.js": "./dist/js/moo-ui.min.js",
30
32
  "./combobox.js": "./dist/js/combobox.js",
31
33
  "./sidebar.js": "./dist/js/sidebar.js",
32
34
  "./context-menu.js": "./dist/js/context-menu.js",
33
35
  "./datatable.js": "./dist/js/datatable.js",
34
- "./scss/facade-settings": "./scss/_facade-settings.scss",
36
+ "./slider.js": "./dist/js/slider.js",
37
+ "./chart.js": "./dist/js/chart.js",
38
+ "./chart.min.js": "./dist/js/chart.min.js",
39
+ "./datepicker.js": "./dist/js/datepicker.js",
40
+ "./datepicker.min.js": "./dist/js/datepicker.min.js",
41
+ "./scss/config": "./scss/_config.scss",
42
+ "./scss/moo-ui": "./scss/moo-ui.scss",
43
+ "./scss/moo-core": "./scss/moo-core.scss",
44
+ "./scss/components": "./scss/_components.scss",
45
+ "./scss/settings": "./scss/_settings.scss",
35
46
  "./certification.json": "./certification.json",
36
47
  "./package.json": "./package.json"
37
48
  },
@@ -40,12 +51,19 @@
40
51
  "dist/assets/css/moo-ui.min.css",
41
52
  "dist/assets/css/moo.css",
42
53
  "dist/assets/css/moo.min.css",
54
+ "dist/js/moo-ui.js",
55
+ "dist/js/moo-ui.min.js",
43
56
  "dist/js/combobox.js",
44
57
  "dist/js/sidebar.js",
45
58
  "dist/js/context-menu.js",
46
59
  "dist/js/datatable.js",
47
- "scss/_facade-settings.scss",
48
- "scss/settings/_facade_public.scss",
60
+ "dist/js/slider.js",
61
+ "dist/js/chart.js",
62
+ "dist/js/chart.min.js",
63
+ "dist/js/datepicker.js",
64
+ "dist/js/datepicker.min.js",
65
+ "scss/*.scss",
66
+ "scss/**/*.scss",
49
67
  "certification.json",
50
68
  "README.md",
51
69
  "LICENSE",
@@ -75,6 +93,8 @@
75
93
  },
76
94
  "devDependencies": {
77
95
  "axe-core": "4.13.0",
96
+ "chart.js": "4.5.1",
97
+ "esbuild": "0.28.1",
78
98
  "wrangler": "^4.120.0"
79
99
  }
80
100
  }
@@ -0,0 +1,73 @@
1
+ // Bootstrap components
2
+ @import "bootstrap/scss/tables";
3
+ @import "bootstrap/scss/forms/labels";
4
+ @import "bootstrap/scss/forms/form-text";
5
+ @import "bootstrap/scss/forms/form-control";
6
+ @import "bootstrap/scss/forms/form-select";
7
+ @import "bootstrap/scss/forms/form-check";
8
+ @import "bootstrap/scss/forms/input-group";
9
+ @import "bootstrap/scss/forms/validation";
10
+ @import "bootstrap/scss/buttons";
11
+ @import "bootstrap/scss/dropdown";
12
+ @import "bootstrap/scss/button-group";
13
+ @import "bootstrap/scss/nav";
14
+ @import "bootstrap/scss/card";
15
+ @import "bootstrap/scss/accordion";
16
+ @import "bootstrap/scss/breadcrumb";
17
+ @import "bootstrap/scss/pagination";
18
+ @import "bootstrap/scss/badge";
19
+ @import "bootstrap/scss/alert";
20
+ @import "bootstrap/scss/close";
21
+ @import "bootstrap/scss/toasts";
22
+ @import "bootstrap/scss/modal";
23
+ @import "bootstrap/scss/tooltip";
24
+ @import "bootstrap/scss/popover";
25
+ @import "bootstrap/scss/offcanvas";
26
+ @import "bootstrap/scss/helpers/color-bg";
27
+
28
+ // Moo component support
29
+ @import "foundations/focus";
30
+ @import "utilities/scroll_fade";
31
+
32
+ // Moo components
33
+ @import "components/kbd";
34
+ @import "components/input";
35
+ @import "components/textarea";
36
+ @import "components/select";
37
+ @import "components/input_group";
38
+ @import "components/button";
39
+ @import "components/close_button";
40
+ @import "components/button_group";
41
+ @import "components/toggle_group";
42
+ @import "components/card";
43
+ @import "components/table";
44
+ @import "components/dropdown";
45
+ @import "components/menubar";
46
+ @import "components/avatar";
47
+ @import "components/navigation";
48
+ @import "components/skeleton";
49
+ @import "components/sidebar";
50
+ @import "components/alert";
51
+ @import "components/breadcrumb";
52
+ @import "components/pagination";
53
+ @import "components/badge";
54
+ @import "components/progress";
55
+ @import "components/slider";
56
+ @import "components/separator";
57
+ @import "components/checkbox";
58
+ @import "components/radio_group";
59
+ @import "components/switch";
60
+ @import "components/spinner";
61
+ @import "components/accordion";
62
+ @import "components/tabs";
63
+ @import "components/collapsible";
64
+ @import "components/tooltip";
65
+ @import "components/popover";
66
+ @import "components/dialog";
67
+ @import "components/sheet";
68
+ @import "components/toast";
69
+ @import "components/field";
70
+ @import "components/datepicker";
71
+ @import "components/combobox";
72
+ @import "components/context-menu";
73
+ @import "components/datatable";