@wpmoo/ui 1.0.0-rc.8 → 1.0.0

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 (94) hide show
  1. package/ASSET_LICENSE.md +1 -1
  2. package/LICENSE +28 -0
  3. package/README.md +34 -6
  4. package/certification.json +3 -2
  5. package/dist/assets/css/moo-ui.css +634 -33
  6. package/dist/assets/css/moo-ui.min.css +10 -31
  7. package/dist/assets/css/moo.css +624 -30
  8. package/dist/assets/css/moo.min.css +10 -32
  9. package/dist/js/chart.js +23 -21
  10. package/dist/js/chart.min.js +5 -5
  11. package/dist/js/combobox.js +18 -65
  12. package/dist/js/context-menu.js +16 -68
  13. package/dist/js/datatable.js +39 -22
  14. package/dist/js/datepicker.js +4 -3
  15. package/dist/js/datepicker.min.js +4 -3
  16. package/dist/js/moo-ui.js +160 -15402
  17. package/dist/js/moo-ui.min.js +3 -23
  18. package/dist/js/sheet.js +46 -0
  19. package/dist/js/sidebar.js +5 -4
  20. package/dist/js/slider.js +12 -47
  21. package/dist/js/state.js +76 -0
  22. package/dist/release-manifest.json +6 -6
  23. package/package.json +5 -3
  24. package/scss/_components.scss +2 -2
  25. package/scss/_config.scss +15 -21
  26. package/scss/_settings.scss +0 -3
  27. package/scss/components/_accordion.scss +1 -12
  28. package/scss/components/_alert.scss +1 -12
  29. package/scss/components/_avatar.scss +1 -16
  30. package/scss/components/_badge.scss +1 -0
  31. package/scss/components/_breadcrumb.scss +1 -12
  32. package/scss/components/_button.scss +1 -29
  33. package/scss/components/_button_group.scss +1 -25
  34. package/scss/components/_card.scss +1 -29
  35. package/scss/components/_checkbox.scss +1 -38
  36. package/scss/components/_close_button.scss +1 -9
  37. package/scss/components/_collapsible.scss +1 -0
  38. package/scss/components/_combobox.scss +1 -6
  39. package/scss/components/_context-menu.scss +1 -11
  40. package/scss/components/_datatable.scss +46 -85
  41. package/scss/components/_datepicker.scss +1 -0
  42. package/scss/components/_dialog.scss +1 -14
  43. package/scss/components/_dropdown.scss +5 -51
  44. package/scss/components/_field.scss +6 -37
  45. package/scss/components/_input.scss +1 -5
  46. package/scss/components/_input_group.scss +1 -51
  47. package/scss/components/_kbd.scss +1 -0
  48. package/scss/components/_menubar.scss +1 -0
  49. package/scss/components/_navigation.scss +76 -6
  50. package/scss/components/_pagination.scss +1 -13
  51. package/scss/components/_popover.scss +1 -22
  52. package/scss/components/_progress.scss +1 -3
  53. package/scss/components/_radio_group.scss +105 -6
  54. package/scss/components/_search_trigger.scss +1 -2
  55. package/scss/components/_select.scss +1 -0
  56. package/scss/components/_separator.scss +1 -6
  57. package/scss/components/_sheet.scss +1 -17
  58. package/scss/components/_sidebar.scss +1 -2
  59. package/scss/components/_skeleton.scss +1 -8
  60. package/scss/components/_slider.scss +1 -2
  61. package/scss/components/_spinner.scss +1 -7
  62. package/scss/components/_switch.scss +1 -4
  63. package/scss/components/_table.scss +1 -2
  64. package/scss/components/_tabs.scss +1 -24
  65. package/scss/components/_textarea.scss +1 -0
  66. package/scss/components/_toast.scss +1 -4
  67. package/scss/components/_toggle_group.scss +1 -3
  68. package/scss/components/_tooltip.scss +1 -20
  69. package/scss/components/sidebar/_base.scss +0 -7
  70. package/scss/components/sidebar/_collapsed.scss +0 -6
  71. package/scss/components/sidebar/_identity.scss +0 -1
  72. package/scss/components/sidebar/_menus.scss +0 -17
  73. package/scss/foundations/_backdrop.scss +0 -26
  74. package/scss/foundations/_focus.scss +0 -56
  75. package/scss/foundations/_scope.scss +19 -0
  76. package/scss/layouts/_app.scss +5 -7
  77. package/scss/layouts/_page_grid.scss +27 -0
  78. package/scss/layouts/app/sidebar/_base.scss +0 -33
  79. package/scss/layouts/app/sidebar/_default.scss +2 -8
  80. package/scss/layouts/app/sidebar/_floating.scss +1 -9
  81. package/scss/layouts/app/sidebar/_inset.scss +5 -2
  82. package/scss/mixins/_banner.scss +9 -3
  83. package/scss/moo-core.scss +3 -6
  84. package/scss/moo-ui.scss +9 -5
  85. package/scss/settings/_bootstrap_overrides.scss +0 -8
  86. package/scss/settings/_component_variables.scss +4 -266
  87. package/scss/settings/_forms.scss +1 -38
  88. package/scss/settings/_palette.scss +0 -42
  89. package/scss/themes/_root.scss +4 -0
  90. package/scss/themes/_standalone.scss +1 -3
  91. package/scss/themes/_theme.scss +4 -0
  92. package/scss/utilities/_background_color.scss +18 -0
  93. package/scss/utilities/_border.scss +4 -0
  94. package/dist/js/theme-prepaint.js +0 -91
@@ -0,0 +1,46 @@
1
+ /*!
2
+ * Moo UI sheet.js v1.0.0 (https://wpmoo.org/)
3
+ * Copyright 2026 WPMoo Authors
4
+ * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
+ */
6
+
7
+ // src/js/components/sheet.js
8
+ var states = /* @__PURE__ */ new WeakMap();
9
+ function initSheets(root = document) {
10
+ if (states.has(root)) {
11
+ return states.get(root);
12
+ }
13
+ const documentRoot = root.nodeType === 9 ? root : root.ownerDocument;
14
+ const Offcanvas = documentRoot?.defaultView?.bootstrap?.Offcanvas;
15
+ if (!Offcanvas) {
16
+ return () => {
17
+ };
18
+ }
19
+ const sheets = Array.from(root.querySelectorAll(".offcanvas.sheet"));
20
+ const focusInitialField = (event) => {
21
+ if (event.target === event.currentTarget) {
22
+ event.currentTarget.querySelector("[autofocus]:not(:disabled)")?.focus();
23
+ }
24
+ };
25
+ const dispose = () => {
26
+ if (states.get(root) !== dispose) {
27
+ return;
28
+ }
29
+ sheets.forEach((sheet) => {
30
+ sheet.removeEventListener("shown.bs.offcanvas", focusInitialField);
31
+ });
32
+ states.delete(root);
33
+ };
34
+ states.set(root, dispose);
35
+ sheets.forEach((sheet) => {
36
+ sheet.addEventListener("shown.bs.offcanvas", focusInitialField);
37
+ if (sheet.dataset.sheetOpenOnLoad === "true") {
38
+ sheet.removeAttribute("data-sheet-open-on-load");
39
+ Offcanvas.getOrCreateInstance(sheet).show();
40
+ }
41
+ });
42
+ return dispose;
43
+ }
44
+ export {
45
+ initSheets
46
+ };
@@ -1,14 +1,15 @@
1
1
  /*!
2
- * Moo UI sidebar.js v1.0.0-rc.8 (https://ui.wpmoo.org/)
3
- * Copyright 2026 WPMoo (https://wpmoo.org)
2
+ * Moo UI sidebar.js v1.0.0 (https://wpmoo.org/)
3
+ * Copyright 2026 WPMoo Authors
4
4
  * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
5
  */
6
+
6
7
  var __defProp = Object.defineProperty;
7
8
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
9
 
9
10
  // src/js/theme-owner.js
10
11
  var OWNER_SELECTOR = '.moo-ui[data-bs-theme="light"], .moo-ui[data-bs-theme="dark"]';
11
- var PORTAL_SELECTOR = "[data-moo-overlay-portal-host]";
12
+ var PORTAL_SELECTOR = "[data-moo-overlay-host]";
12
13
  function documentFor(node) {
13
14
  if (node?.nodeType === 9) return node;
14
15
  if (node?.ownerDocument) return node.ownerDocument;
@@ -249,7 +250,7 @@ var _Sidebar = class _Sidebar {
249
250
  _positionDropdown(control) {
250
251
  const item = control?.closest?.(".sidebar-menu-item");
251
252
  const isHeaderWorkspace = control?.classList.contains("sidebar-menu-button--workspace") && control.closest('[data-slot="sidebar-header"]');
252
- const isFooterAccount = control?.classList.contains("sidebar-menu-button--account") && control.closest('[data-slot="sidebar-footer"]');
253
+ const isFooterAccount = control?.closest(".sidebar-menu-item--account") && control.closest('[data-slot="sidebar-footer"]');
253
254
  if (!control || !item || !(isHeaderWorkspace || isFooterAccount) || !this._isDesktop()) {
254
255
  this._clearDropdownPosition(control);
255
256
  return;
package/dist/js/slider.js CHANGED
@@ -1,23 +1,20 @@
1
1
  /*!
2
- * Moo UI slider.js v1.0.0-rc.8 (https://ui.wpmoo.org/)
3
- * Copyright 2026 WPMoo (https://wpmoo.org)
2
+ * Moo UI slider.js v1.0.0 (https://wpmoo.org/)
3
+ * Copyright 2026 WPMoo Authors
4
4
  * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
5
  */
6
- const instances = new WeakMap();
7
6
 
7
+ const instances = /* @__PURE__ */ new WeakMap();
8
8
  function asNumber(value, fallback) {
9
9
  const number = Number(value);
10
10
  return Number.isFinite(number) ? number : fallback;
11
11
  }
12
-
13
12
  function inputMinimum(input) {
14
13
  return asNumber(input.min, 0);
15
14
  }
16
-
17
15
  function inputMaximum(input) {
18
16
  return asNumber(input.max, 100);
19
17
  }
20
-
21
18
  function inputStep(input) {
22
19
  if (!input.step || input.step === "any") {
23
20
  return 1;
@@ -25,11 +22,9 @@ function inputStep(input) {
25
22
  const step = Number(input.step);
26
23
  return Number.isFinite(step) && step > 0 ? step : 1;
27
24
  }
28
-
29
25
  function clamp(value, min, max) {
30
26
  return Math.min(Math.max(value, min), max);
31
27
  }
32
-
33
28
  function decimalPlaces(value) {
34
29
  const text = String(value);
35
30
  if (!text.includes(".")) {
@@ -37,7 +32,6 @@ function decimalPlaces(value) {
37
32
  }
38
33
  return text.split(".").at(-1).length;
39
34
  }
40
-
41
35
  function snapToStep(value, input) {
42
36
  const min = inputMinimum(input);
43
37
  const max = inputMaximum(input);
@@ -49,29 +43,24 @@ function snapToStep(value, input) {
49
43
  const precision = Math.max(decimalPlaces(step), decimalPlaces(min));
50
44
  return clamp(Number(snapped.toFixed(precision)), min, max);
51
45
  }
52
-
53
46
  function valuePercent(input) {
54
47
  const min = inputMinimum(input);
55
48
  const max = inputMaximum(input);
56
49
  if (max <= min) {
57
50
  return 0;
58
51
  }
59
- return ((asNumber(input.value, min) - min) / (max - min)) * 100;
52
+ return (asNumber(input.value, min) - min) / (max - min) * 100;
60
53
  }
61
-
62
54
  function displayValue(input) {
63
55
  return input.value || String(inputMinimum(input));
64
56
  }
65
-
66
- export default class MooSlider {
57
+ class MooSlider {
67
58
  static getInstance(element) {
68
59
  return element?.nodeType === 1 ? instances.get(element) || null : null;
69
60
  }
70
-
71
61
  static getOrCreateInstance(element, config = {}) {
72
62
  return MooSlider.getInstance(element) || new MooSlider(element, config);
73
63
  }
74
-
75
64
  constructor(element, config = {}) {
76
65
  if (element?.nodeType !== 1 || !element.matches("[data-slider]")) {
77
66
  throw new TypeError("MooSlider requires a [data-slider] root element.");
@@ -80,7 +69,6 @@ export default class MooSlider {
80
69
  if (existing) {
81
70
  return existing;
82
71
  }
83
-
84
72
  this._element = element;
85
73
  this._document = element.ownerDocument;
86
74
  this._window = this._document.defaultView;
@@ -94,19 +82,16 @@ export default class MooSlider {
94
82
  );
95
83
  this._track = element.querySelector("[data-slider-track]");
96
84
  this._output = element.querySelector("[data-slider-output]");
97
-
98
85
  if (this._inputs.length < 1 || this._inputs.length > 2) {
99
86
  throw new TypeError("MooSlider requires one or two native range inputs.");
100
87
  }
101
88
  if (!this._track) {
102
89
  throw new TypeError("MooSlider requires a [data-slider-track] element.");
103
90
  }
104
-
105
91
  instances.set(element, this);
106
92
  this._bindEvents();
107
93
  this._sync();
108
94
  }
109
-
110
95
  dispose() {
111
96
  if (this._disposed) return;
112
97
  this._disposed = true;
@@ -120,7 +105,6 @@ export default class MooSlider {
120
105
  instances.delete(this._element);
121
106
  }
122
107
  }
123
-
124
108
  _listen(target, type, handler, options) {
125
109
  if (!target) {
126
110
  return;
@@ -128,7 +112,6 @@ export default class MooSlider {
128
112
  target.addEventListener(type, handler, options);
129
113
  this._listeners.push({ target, type, handler, options });
130
114
  }
131
-
132
115
  _listenDuringDrag(target, type, handler, options) {
133
116
  if (!target) {
134
117
  return;
@@ -136,7 +119,6 @@ export default class MooSlider {
136
119
  target.addEventListener(type, handler, options);
137
120
  this._dragListeners.push({ target, type, handler, options });
138
121
  }
139
-
140
122
  _clearDragListeners() {
141
123
  this._dragListeners.forEach(({ target, type, handler, options }) => {
142
124
  target.removeEventListener(type, handler, options);
@@ -145,7 +127,6 @@ export default class MooSlider {
145
127
  this._draggingInput = null;
146
128
  this._element.removeAttribute("data-slider-dragging");
147
129
  }
148
-
149
130
  _bindEvents() {
150
131
  this._inputs.forEach((input) => {
151
132
  this._listen(input, "input", () => this._sync(input));
@@ -157,9 +138,7 @@ export default class MooSlider {
157
138
  this._listen(input, "focusout", () => this._clearPointerFocus());
158
139
  });
159
140
  const forms = new Set(
160
- this._inputs
161
- .map((input) => input.form || input.closest?.("form"))
162
- .filter(Boolean),
141
+ this._inputs.map((input) => input.form || input.closest?.("form")).filter(Boolean)
163
142
  );
164
143
  forms.forEach((form) => {
165
144
  this._listen(form, "reset", () => {
@@ -168,19 +147,16 @@ export default class MooSlider {
168
147
  });
169
148
  this._listen(this._track, "pointerdown", (event) => this._handleTrackPointer(event));
170
149
  }
171
-
172
150
  _trigger(name) {
173
151
  this._element.dispatchEvent(
174
152
  new this._window.CustomEvent(`${name}.moo.slider`, {
175
- bubbles: true,
153
+ bubbles: true
176
154
  })
177
155
  );
178
156
  }
179
-
180
157
  _isRange() {
181
158
  return this._inputs.length === 2;
182
159
  }
183
-
184
160
  _sync(changedInput = null) {
185
161
  if (this._isRange()) {
186
162
  const [startInput, endInput] = this._inputs;
@@ -199,34 +175,29 @@ export default class MooSlider {
199
175
  this._syncAria(endInput);
200
176
  return;
201
177
  }
202
-
203
178
  const input = this._inputs[0];
204
179
  this._writeFill(0, valuePercent(input));
205
180
  this._writeOutput(displayValue(input));
206
181
  this._syncAria(input);
207
182
  }
208
-
209
183
  _syncAria(input) {
210
184
  input.setAttribute("aria-valuemin", String(inputMinimum(input)));
211
185
  input.setAttribute("aria-valuemax", String(inputMaximum(input)));
212
186
  input.setAttribute("aria-valuenow", displayValue(input));
213
187
  }
214
-
215
188
  _writeFill(start, end) {
216
189
  const clampedStart = clamp(start, 0, 100);
217
190
  const clampedEnd = clamp(end, 0, 100);
218
191
  this._element.style.setProperty("--moo-slider-start", `${Math.min(clampedStart, clampedEnd)}%`);
219
192
  this._element.style.setProperty("--moo-slider-end", `${Math.max(clampedStart, clampedEnd)}%`);
220
193
  }
221
-
222
194
  _writeOutput(value) {
223
195
  if (this._output) {
224
196
  this._output.textContent = value;
225
197
  }
226
198
  }
227
-
228
199
  _handleTrackPointer(event) {
229
- if (event.button !== undefined && event.button !== 0) {
200
+ if (event.button !== void 0 && event.button !== 0) {
230
201
  return;
231
202
  }
232
203
  const enabledInputs = this._inputs.filter((input) => !input.disabled);
@@ -240,23 +211,19 @@ export default class MooSlider {
240
211
  this._startDrag(target, event);
241
212
  this._setInputFromPointer(target, event);
242
213
  }
243
-
244
214
  _setPointerFocus() {
245
215
  this._element.setAttribute("data-slider-pointer-focus", "true");
246
216
  }
247
-
248
217
  _clearPointerFocus() {
249
218
  this._element.removeAttribute("data-slider-pointer-focus");
250
219
  }
251
-
252
220
  _startDrag(input, event) {
253
221
  this._clearDragListeners();
254
222
  this._draggingInput = input;
255
223
  this._element.setAttribute("data-slider-dragging", "true");
256
224
  this._track.setPointerCapture?.(event.pointerId);
257
-
258
225
  const pointerId = event.pointerId;
259
- const samePointer = (nextEvent) => pointerId === undefined || nextEvent.pointerId === pointerId;
226
+ const samePointer = (nextEvent) => pointerId === void 0 || nextEvent.pointerId === pointerId;
260
227
  const onMove = (moveEvent) => {
261
228
  if (!samePointer(moveEvent) || this._draggingInput !== input) {
262
229
  return;
@@ -274,12 +241,10 @@ export default class MooSlider {
274
241
  this._track.releasePointerCapture?.(pointerId);
275
242
  this._clearDragListeners();
276
243
  };
277
-
278
244
  this._listenDuringDrag(this._document, "pointermove", onMove);
279
245
  this._listenDuringDrag(this._document, "pointerup", onEnd);
280
246
  this._listenDuringDrag(this._document, "pointercancel", onEnd);
281
247
  }
282
-
283
248
  _setInputFromPointer(input, event, emitInput = true) {
284
249
  const percent = this._pointerPercent(event);
285
250
  const min = inputMinimum(input);
@@ -291,7 +256,6 @@ export default class MooSlider {
291
256
  input.dispatchEvent(new this._window.Event("input", { bubbles: true }));
292
257
  }
293
258
  }
294
-
295
259
  _pointerPercent(event) {
296
260
  const rect = this._track.getBoundingClientRect();
297
261
  const orientation = this._element.dataset.sliderOrientation || "horizontal";
@@ -300,13 +264,11 @@ export default class MooSlider {
300
264
  }
301
265
  return this._horizontalPointerPercent(event, rect);
302
266
  }
303
-
304
267
  _horizontalPointerPercent(event, rect) {
305
268
  const direction = this._window.getComputedStyle?.(this._element).direction;
306
269
  const offset = direction === "rtl" ? rect.right - event.clientX : event.clientX - rect.left;
307
270
  return clamp(offset / (rect.width || 1), 0, 1);
308
271
  }
309
-
310
272
  _nearestInput(percent, inputs) {
311
273
  if (inputs.length === 1) {
312
274
  return inputs[0];
@@ -322,3 +284,6 @@ export default class MooSlider {
322
284
  return endDistance < startDistance ? endInput : startInput;
323
285
  }
324
286
  }
287
+ export {
288
+ MooSlider as default
289
+ };
@@ -0,0 +1,76 @@
1
+ /*!
2
+ * Moo UI state.js v1.0.0 (https://wpmoo.org/)
3
+ * Copyright 2026 WPMoo Authors
4
+ * Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
5
+ */
6
+
7
+ (() => {
8
+ const ownerDocument = typeof document === "undefined" ? null : document;
9
+ const owner = ownerDocument?.currentScript?.parentElement;
10
+ if (!owner) return;
11
+ const view = ownerDocument?.defaultView || (typeof window === "undefined" ? null : window);
12
+ if (owner.matches?.('.moo-ui[data-bs-theme="light"], .moo-ui[data-bs-theme="dark"]')) {
13
+ const body = ownerDocument?.body;
14
+ const documentOwner = owner.dataset?.mooDocumentOwner === "true" && owner.parentElement === body && owner === body?.firstElementChild;
15
+ const normalizeDirection = (value) => value === "ltr" || value === "rtl" ? value : null;
16
+ const ownerDirection = normalizeDirection(
17
+ owner.getAttribute?.("dir") || owner.dir
18
+ );
19
+ const documentDirection = normalizeDirection(
20
+ ownerDocument?.documentElement?.getAttribute?.("dir") || ownerDocument?.documentElement?.dir
21
+ );
22
+ owner.__mooStateBaseline = {
23
+ theme: owner.dataset.bsTheme === "dark" ? "dark" : "light",
24
+ direction: documentOwner ? documentDirection || "ltr" : ownerDirection
25
+ };
26
+ const readPreference = (axis, allowed) => {
27
+ const dataKey = axis === "theme" ? "mooThemeKey" : "mooDirectionKey";
28
+ const explicit = owner.dataset?.[dataKey]?.trim();
29
+ const key2 = explicit || (documentOwner ? `moo:${axis}` : null);
30
+ if (!key2) return null;
31
+ try {
32
+ const value = view?.localStorage?.getItem(key2);
33
+ return allowed.includes(value) ? value : null;
34
+ } catch (_) {
35
+ return null;
36
+ }
37
+ };
38
+ const systemPrefersDark = () => {
39
+ try {
40
+ const matchMedia = view?.matchMedia;
41
+ if (typeof matchMedia !== "function") return null;
42
+ return Boolean(
43
+ matchMedia.call(view, "(prefers-color-scheme: dark)")?.matches
44
+ );
45
+ } catch (_) {
46
+ return null;
47
+ }
48
+ };
49
+ try {
50
+ const storedTheme = readPreference("theme", ["light", "dark", "system"]);
51
+ const mediaPrefersDark = storedTheme === "system" ? systemPrefersDark() : null;
52
+ const resolvedTheme = storedTheme === "dark" ? "dark" : storedTheme === "light" ? "light" : storedTheme === "system" && mediaPrefersDark !== null ? mediaPrefersDark ? "dark" : "light" : owner.dataset.bsTheme === "dark" ? "dark" : "light";
53
+ owner.dataset.bsTheme = resolvedTheme;
54
+ const storedDirection = readPreference("direction", ["ltr", "rtl"]);
55
+ if (storedDirection) {
56
+ if (documentOwner) ownerDocument.documentElement.dir = storedDirection;
57
+ else owner.dir = storedDirection;
58
+ }
59
+ } finally {
60
+ owner.dataset.mooState = "ready";
61
+ }
62
+ return;
63
+ }
64
+ if (!owner.matches?.('[data-slot="sidebar-wrapper"][data-sidebar-key]')) return;
65
+ const key = owner.dataset?.sidebarKey;
66
+ if (!key) return;
67
+ try {
68
+ const state = view?.localStorage?.getItem(`moo-sidebar:${key}`);
69
+ if (state === "expanded" || state === "collapsed") {
70
+ owner.dataset.sidebarState = state;
71
+ }
72
+ } catch (_) {
73
+ } finally {
74
+ owner.dataset.sidebarStateReady = "";
75
+ }
76
+ })();
@@ -3,22 +3,22 @@
3
3
  {
4
4
  "export": "./moo.css",
5
5
  "path": "dist/assets/css/moo.css",
6
- "sha256": "29c92bd75db1e4990745796aeef4d6a0b3313d1b9d2e3c929f559f8687a5fe6f"
6
+ "sha256": "32108d9a95122382228038cd4fe4ca48736a8c0b6219375a08e7697d96d9abd3"
7
7
  },
8
8
  {
9
9
  "export": "./moo-ui.css",
10
10
  "path": "dist/assets/css/moo-ui.css",
11
- "sha256": "00db81fad96811182874b9207746a3154adb0f457c965a08e639a04af83f95a4"
11
+ "sha256": "5824bc488463bc6e6d967e4079b30d8053c9d67cba01479c10cde3830865a1bb"
12
12
  },
13
13
  {
14
- "export": "./theme-prepaint.js",
15
- "path": "dist/js/theme-prepaint.js",
16
- "sha256": "e40ce7caa83112498c0819719e63ee8d0f23f58236f02ec038ccabf7a128121a"
14
+ "export": "./state.js",
15
+ "path": "dist/js/state.js",
16
+ "sha256": "85b12aea0f22f1a29c9ffe791b0d53d53cc7ab55b08ede10029edc558c8786a6"
17
17
  }
18
18
  ],
19
19
  "package": {
20
20
  "name": "@wpmoo/ui",
21
- "version": "1.0.0-rc.8"
21
+ "version": "1.0.0"
22
22
  },
23
23
  "schemaVersion": 1
24
24
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wpmoo/ui",
3
- "version": "1.0.0-rc.8",
3
+ "version": "1.0.0",
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)",
@@ -38,11 +38,12 @@
38
38
  "./context-menu.js": "./dist/js/context-menu.js",
39
39
  "./datatable.js": "./dist/js/datatable.js",
40
40
  "./slider.js": "./dist/js/slider.js",
41
+ "./sheet.js": "./dist/js/sheet.js",
41
42
  "./chart.js": "./dist/js/chart.js",
42
43
  "./chart.min.js": "./dist/js/chart.min.js",
43
44
  "./datepicker.js": "./dist/js/datepicker.js",
44
45
  "./datepicker.min.js": "./dist/js/datepicker.min.js",
45
- "./theme-prepaint.js": "./dist/js/theme-prepaint.js",
46
+ "./state.js": "./dist/js/state.js",
46
47
  "./release-manifest.json": "./dist/release-manifest.json",
47
48
  "./scss/config": "./scss/_config.scss",
48
49
  "./scss/moo-ui": "./scss/moo-ui.scss",
@@ -64,11 +65,12 @@
64
65
  "dist/js/context-menu.js",
65
66
  "dist/js/datatable.js",
66
67
  "dist/js/slider.js",
68
+ "dist/js/sheet.js",
67
69
  "dist/js/chart.js",
68
70
  "dist/js/chart.min.js",
69
71
  "dist/js/datepicker.js",
70
72
  "dist/js/datepicker.min.js",
71
- "dist/js/theme-prepaint.js",
73
+ "dist/js/state.js",
72
74
  "dist/release-manifest.json",
73
75
  "scss/*.scss",
74
76
  "scss/**/*.scss",
@@ -1,4 +1,4 @@
1
- // Bootstrap components
1
+ /* Bootstrap Components */
2
2
  @import "bootstrap/scss/tables";
3
3
  @import "bootstrap/scss/forms/labels";
4
4
  @import "bootstrap/scss/forms/form-text";
@@ -25,7 +25,7 @@
25
25
  @import "bootstrap/scss/offcanvas";
26
26
  @import "bootstrap/scss/helpers/color-bg";
27
27
 
28
- // Moo components
28
+ /* Moo Components */
29
29
  @import "components/kbd";
30
30
  @import "components/input";
31
31
  @import "components/textarea";
package/scss/_config.scss CHANGED
@@ -1,24 +1,18 @@
1
- // Moo UI public Sass config
2
- //
3
- // Import this before Bootstrap variables so overrides take precedence.
4
- //
5
- // Only the variables below are public. Derived $moo-* tokens and component
6
- // knobs are internal and may change without notice.
7
1
 
8
- $primary: #171717 !default; // Brand color
9
- $secondary: #f4f4f5 !default; // Secondary surface color
10
- $success: #047857 !default; // Success color
11
- $info: #0369a1 !default; // Informational color
12
- $warning: #b45309 !default; // Warning color
13
- $danger: #e7000b !default; // Destructive color
14
- $light: #fafafa !default; // Light surface color
15
- $dark: #18181b !default; // Dark surface color
2
+ $primary: #171717 !default;
3
+ $secondary: #f4f4f5 !default;
4
+ $success: #047857 !default;
5
+ $info: #0369a1 !default;
6
+ $warning: #b45309 !default;
7
+ $danger: #e7000b !default;
8
+ $light: #fafafa !default;
9
+ $dark: #18181b !default;
16
10
 
17
- $body-color: #18181b !default; // Document text color
18
- $body-bg: #fff !default; // Document background color
19
- $font-size-base: 0.875rem !default; // Bootstrap-compatible base font size
11
+ $body-color: #18181b !default;
12
+ $body-bg: #fff !default;
13
+ $font-size-base: 0.875rem !default;
20
14
 
21
- $border-color: #e4e4e7 !default; // Default border color
22
- $border-radius: 0.5rem !default; // Default radius
23
- $border-radius-sm: 0.375rem !default; // Small radius
24
- $border-radius-lg: 0.625rem !default; // Large radius
15
+ $border-color: #e4e4e7 !default;
16
+ $border-radius: 0.5rem !default;
17
+ $border-radius-sm: 0.375rem !default;
18
+ $border-radius-lg: 0.625rem !default;
@@ -1,6 +1,3 @@
1
- // Ordered Sass settings aggregate. These partials emit variables only; preserve
2
- // this sequence because later component and catalog knobs depend on earlier
3
- // palette and form values before Bootstrap's own defaults are loaded.
4
1
  @import "config";
5
2
  @import "settings/palette";
6
3
  @import "settings/forms";
@@ -1,7 +1,4 @@
1
- // The reference trigger uses a real Lucide chevron-down icon that rotates
2
- // on expand, not Bootstrap's baked-in ::after background-image glyph.
3
- // Render the same icon our other components use and drive the rotation
4
- // off Bootstrap's own :not(.collapsed) state hook instead.
1
+ /* Accordion */
5
2
  .accordion-button::after {
6
3
  content: none;
7
4
  }
@@ -27,8 +24,6 @@
27
24
  text-align: start;
28
25
  }
29
26
 
30
- // The reference trigger has no active/pressed background — only a hover
31
- // underline signals interactivity, matching a plain text-link affordance.
32
27
  .accordion-button:hover {
33
28
  text-decoration: underline;
34
29
  }
@@ -43,10 +38,6 @@
43
38
  text-decoration: none;
44
39
  }
45
40
 
46
- // The reference's flush trigger and body sit edge-to-edge with no
47
- // horizontal padding, and the trigger reads as medium weight, not
48
- // Bootstrap's own regular default -- both retune existing Bootstrap
49
- // accordion tokens/properties, not new selectors.
50
41
  .accordion-flush {
51
42
  --bs-accordion-btn-padding-x: 0;
52
43
  --bs-accordion-btn-padding-y: #{$spacer * 0.625};
@@ -58,8 +49,6 @@
58
49
  font-weight: $font-weight-medium;
59
50
  }
60
51
 
61
- // A card owns its own surface, so a nested accordion must let that surface
62
- // show through instead of painting Bootstrap's body background on top of it.
63
52
  .card .accordion {
64
53
  --bs-accordion-bg: #{$moo-accordion-contained-bg};
65
54
  }
@@ -1,6 +1,4 @@
1
- // Bootstrap's base .alert has a transparent bg/border until a contextual
2
- // .alert-{state} modifier sets them; the design reference's quiet style
3
- // keeps a visible neutral border even on the unmodified/default alert.
1
+ /* Alert */
4
2
  $moo-alert-dismissible-close-space: $btn-close-width + ($btn-close-padding-x * 2) + 0.5rem !default;
5
3
 
6
4
  .alert {
@@ -29,21 +27,12 @@ $moo-alert-dismissible-close-space: $btn-close-width + ($btn-close-padding-x * 2
29
27
  padding: $btn-close-padding-y $btn-close-padding-x;
30
28
  }
31
29
 
32
- // The reference's destructive alert keeps the same neutral surface and
33
- // border as the default alert and tints only the text/icon color —
34
- // verified against the live reference page's Destructive example (bg-card,
35
- // text-destructive). Bootstrap's own alert-danger class instead fills a
36
- // saturated subtle-danger background, so re-anchor its consumption
37
- // variables back to the neutral ones and layer only the color shift on top.
38
30
  .alert-danger {
39
31
  --bs-alert-bg: transparent;
40
32
  --bs-alert-border-color: var(--moo-border);
41
33
  --bs-alert-color: var(--moo-destructive);
42
34
  }
43
35
 
44
- // Warning and success alerts follow the same quiet pattern as destructive:
45
- // neutral border, tinted alpha surface, hue-colored text. Matches the
46
- // reference's alert variants (amber for warning, green for success).
47
36
  .alert-warning {
48
37
  --bs-alert-bg: var(--moo-warning-surface);
49
38
  --bs-alert-border-color: var(--moo-border);
@@ -1,5 +1,4 @@
1
- // Bootstrap has no native avatar component. This public `.avatar` namespace is
2
- // intentionally small and consumes the shared Bootstrap radius/border primitives.
1
+ /* Avatar */
3
2
  .avatar {
4
3
  position: relative;
5
4
  display: inline-flex;
@@ -8,9 +7,6 @@
8
7
  width: $avatar-size;
9
8
  height: $avatar-size;
10
9
  flex: 0 0 auto;
11
- // A badge (such as a presence dot) sits at the avatar's corner and must
12
- // stay visible outside the circle; the image/fallback clip to the circle
13
- // on their own, so the root itself does not need to clip its children.
14
10
  overflow: visible;
15
11
  border: 0;
16
12
  border-radius: var(--bs-border-radius-pill);
@@ -66,10 +62,6 @@
66
62
  padding-inline: 0.2rem;
67
63
  border: 0;
68
64
  border-radius: var(--bs-border-radius-pill);
69
- // Mirrors the reference's ring-2 treatment: the badge keeps its own
70
- // 10px/12px/15px box while the page-background ring paints outside it.
71
- // box-shadow (not border) keeps the ring out of the layout box, matching
72
- // the .avatar-group ring below and Tailwind's own ring-* technique.
73
65
  box-shadow: $avatar-badge-ring-shadow;
74
66
  background-color: var(--moo-muted-surface);
75
67
  color: var(--moo-foreground);
@@ -83,9 +75,6 @@
83
75
  height: 0.625rem;
84
76
  }
85
77
 
86
- // A plain presence/status dot (no text or icon content) -- the reference's
87
- // own AvatarBadge with no children, recolored per use via badge_class
88
- // (such as a Bootstrap bg-success utility) rather than a hardcoded color here.
89
78
  .avatar-badge--dot {
90
79
  height: $avatar-badge-dot-size;
91
80
  min-width: $avatar-badge-dot-size;
@@ -121,10 +110,6 @@
121
110
  align-items: center;
122
111
  }
123
112
 
124
- // Matches the reference's ring-2 ring-background: each avatar in a group
125
- // carries a page-background ring (light = white, dark = black) so stacked
126
- // avatars stay visibly separated. --bs-body-bg is theme-aware in both the
127
- // standalone and scoped builds, mirroring the badge ring treatment.
128
113
  .avatar-group > .avatar {
129
114
  box-shadow: $avatar-group-ring-shadow;
130
115
  z-index: 0;
@@ -1,3 +1,4 @@
1
+ /* Badge */
1
2
  .badge {
2
3
  display: inline-flex;
3
4
  height: $moo-chip-height;