@wpmoo/ui 1.0.0-rc.9 → 1.1.0-dev.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.
- package/ASSET_LICENSE.md +1 -1
- package/LICENSE +28 -0
- package/README.md +38 -3
- package/certification.json +3 -1
- package/dist/assets/css/moo-ui.css +436 -25
- package/dist/assets/css/moo-ui.min.css +10 -31
- package/dist/assets/css/moo.css +428 -24
- package/dist/assets/css/moo.min.css +10 -32
- package/dist/js/chart.js +23 -21
- package/dist/js/chart.min.js +5 -5
- package/dist/js/combobox.js +18 -65
- package/dist/js/context-menu.js +16 -68
- package/dist/js/datatable.js +38 -21
- package/dist/js/datepicker.js +5 -4
- package/dist/js/datepicker.min.js +4 -3
- package/dist/js/moo-ui.js +350 -15402
- package/dist/js/moo-ui.min.js +3 -23
- package/dist/js/sheet.js +46 -0
- package/dist/js/sidebar.js +3 -2
- package/dist/js/slider.js +12 -47
- package/dist/js/state.js +15 -41
- package/dist/js/table-of-contents.js +195 -0
- package/dist/release-manifest.json +4 -4
- package/package.json +5 -1
- package/scss/_components.scss +3 -2
- package/scss/_config.scss +15 -21
- package/scss/_settings.scss +0 -3
- package/scss/components/_accordion.scss +1 -12
- package/scss/components/_alert.scss +1 -12
- package/scss/components/_avatar.scss +1 -16
- package/scss/components/_badge.scss +1 -0
- package/scss/components/_breadcrumb.scss +1 -12
- package/scss/components/_button.scss +1 -29
- package/scss/components/_button_group.scss +1 -25
- package/scss/components/_card.scss +1 -29
- package/scss/components/_checkbox.scss +1 -38
- package/scss/components/_close_button.scss +1 -9
- package/scss/components/_collapsible.scss +1 -0
- package/scss/components/_combobox.scss +1 -6
- package/scss/components/_context-menu.scss +1 -11
- package/scss/components/_datatable.scss +46 -85
- package/scss/components/_datepicker.scss +1 -0
- package/scss/components/_dialog.scss +1 -14
- package/scss/components/_dropdown.scss +5 -51
- package/scss/components/_field.scss +1 -40
- package/scss/components/_input.scss +1 -5
- package/scss/components/_input_group.scss +1 -51
- package/scss/components/_kbd.scss +1 -0
- package/scss/components/_menubar.scss +1 -0
- package/scss/components/_navigation.scss +76 -6
- package/scss/components/_pagination.scss +1 -13
- package/scss/components/_popover.scss +1 -22
- package/scss/components/_progress.scss +1 -3
- package/scss/components/_radio_group.scss +105 -6
- package/scss/components/_search_trigger.scss +1 -2
- package/scss/components/_select.scss +1 -0
- package/scss/components/_separator.scss +1 -6
- package/scss/components/_sheet.scss +1 -17
- package/scss/components/_sidebar.scss +1 -2
- package/scss/components/_skeleton.scss +1 -8
- package/scss/components/_slider.scss +1 -2
- package/scss/components/_spinner.scss +1 -7
- package/scss/components/_switch.scss +1 -4
- package/scss/components/_table.scss +1 -2
- package/scss/components/_tabs.scss +1 -24
- package/scss/components/_textarea.scss +1 -0
- package/scss/components/_toast.scss +1 -4
- package/scss/components/_toc.scss +48 -0
- package/scss/components/_toggle_group.scss +1 -3
- package/scss/components/_tooltip.scss +1 -20
- package/scss/components/sidebar/_base.scss +0 -7
- package/scss/components/sidebar/_collapsed.scss +0 -6
- package/scss/components/sidebar/_identity.scss +0 -1
- package/scss/components/sidebar/_menus.scss +0 -17
- package/scss/foundations/_backdrop.scss +0 -26
- package/scss/foundations/_focus.scss +0 -56
- package/scss/foundations/_scope.scss +15 -0
- package/scss/layouts/_app.scss +0 -6
- package/scss/layouts/_page_grid.scss +0 -3
- package/scss/layouts/app/sidebar/_base.scss +0 -37
- package/scss/layouts/app/sidebar/_default.scss +0 -6
- package/scss/layouts/app/sidebar/_floating.scss +0 -11
- package/scss/layouts/app/sidebar/_inset.scss +0 -2
- package/scss/mixins/_banner.scss +9 -3
- package/scss/moo-core.scss +3 -6
- package/scss/moo-ui.scss +9 -5
- package/scss/settings/_bootstrap_overrides.scss +0 -8
- package/scss/settings/_component_variables.scss +4 -266
- package/scss/settings/_forms.scss +0 -37
- package/scss/settings/_palette.scss +0 -42
- package/scss/themes/_root.scss +3 -0
- package/scss/themes/_standalone.scss +0 -2
- package/scss/themes/_theme.scss +3 -2
- package/scss/utilities/_background_color.scss +18 -0
- package/scss/utilities/_border.scss +4 -0
- package/scss/utilities/_scroll_smooth.scss +9 -0
package/dist/js/sheet.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Moo UI sheet.js v1.1.0-dev.1 (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
|
+
};
|
package/dist/js/sidebar.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Moo UI sidebar.js v1.
|
|
3
|
-
* Copyright 2026 WPMoo
|
|
2
|
+
* Moo UI sidebar.js v1.1.0-dev.1 (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
|
|
package/dist/js/slider.js
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Moo UI slider.js v1.
|
|
3
|
-
* Copyright 2026 WPMoo
|
|
2
|
+
* Moo UI slider.js v1.1.0-dev.1 (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 (
|
|
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 !==
|
|
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 ===
|
|
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
|
+
};
|
package/dist/js/state.js
CHANGED
|
@@ -1,80 +1,56 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Moo UI state
|
|
3
|
-
* Copyright 2026 WPMoo
|
|
2
|
+
* Moo UI state.js v1.1.0-dev.1 (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
|
(() => {
|
|
7
8
|
const ownerDocument = typeof document === "undefined" ? null : document;
|
|
8
9
|
const owner = ownerDocument?.currentScript?.parentElement;
|
|
9
10
|
if (!owner) return;
|
|
10
|
-
|
|
11
|
-
const view =
|
|
12
|
-
ownerDocument?.defaultView ||
|
|
13
|
-
(typeof window === "undefined" ? null : window);
|
|
14
|
-
|
|
11
|
+
const view = ownerDocument?.defaultView || (typeof window === "undefined" ? null : window);
|
|
15
12
|
if (owner.matches?.('.moo-ui[data-bs-theme="light"], .moo-ui[data-bs-theme="dark"]')) {
|
|
16
13
|
const body = ownerDocument?.body;
|
|
17
|
-
const documentOwner =
|
|
18
|
-
|
|
19
|
-
owner.parentElement === body &&
|
|
20
|
-
owner === body?.firstElementChild;
|
|
21
|
-
const normalizeDirection = (value) =>
|
|
22
|
-
value === "ltr" || value === "rtl" ? value : null;
|
|
14
|
+
const documentOwner = owner.dataset?.mooDocumentOwner === "true" && owner.parentElement === body && owner === body?.firstElementChild;
|
|
15
|
+
const normalizeDirection = (value) => value === "ltr" || value === "rtl" ? value : null;
|
|
23
16
|
const ownerDirection = normalizeDirection(
|
|
24
|
-
owner.getAttribute?.("dir") || owner.dir
|
|
17
|
+
owner.getAttribute?.("dir") || owner.dir
|
|
25
18
|
);
|
|
26
19
|
const documentDirection = normalizeDirection(
|
|
27
|
-
ownerDocument?.documentElement?.getAttribute?.("dir") ||
|
|
28
|
-
ownerDocument?.documentElement?.dir,
|
|
20
|
+
ownerDocument?.documentElement?.getAttribute?.("dir") || ownerDocument?.documentElement?.dir
|
|
29
21
|
);
|
|
30
22
|
owner.__mooStateBaseline = {
|
|
31
23
|
theme: owner.dataset.bsTheme === "dark" ? "dark" : "light",
|
|
32
|
-
direction: documentOwner ? documentDirection || "ltr" : ownerDirection
|
|
24
|
+
direction: documentOwner ? documentDirection || "ltr" : ownerDirection
|
|
33
25
|
};
|
|
34
|
-
|
|
35
26
|
const readPreference = (axis, allowed) => {
|
|
36
27
|
const dataKey = axis === "theme" ? "mooThemeKey" : "mooDirectionKey";
|
|
37
28
|
const explicit = owner.dataset?.[dataKey]?.trim();
|
|
38
|
-
const
|
|
39
|
-
if (!
|
|
29
|
+
const key2 = explicit || (documentOwner ? `moo:${axis}` : null);
|
|
30
|
+
if (!key2) return null;
|
|
40
31
|
try {
|
|
41
|
-
const value = view?.localStorage?.getItem(
|
|
32
|
+
const value = view?.localStorage?.getItem(key2);
|
|
42
33
|
return allowed.includes(value) ? value : null;
|
|
43
34
|
} catch (_) {
|
|
44
35
|
return null;
|
|
45
36
|
}
|
|
46
37
|
};
|
|
47
|
-
|
|
48
38
|
const systemPrefersDark = () => {
|
|
49
39
|
try {
|
|
50
40
|
const matchMedia = view?.matchMedia;
|
|
51
41
|
if (typeof matchMedia !== "function") return null;
|
|
52
42
|
return Boolean(
|
|
53
|
-
matchMedia.call(view, "(prefers-color-scheme: dark)")?.matches
|
|
43
|
+
matchMedia.call(view, "(prefers-color-scheme: dark)")?.matches
|
|
54
44
|
);
|
|
55
45
|
} catch (_) {
|
|
56
46
|
return null;
|
|
57
47
|
}
|
|
58
48
|
};
|
|
59
|
-
|
|
60
49
|
try {
|
|
61
50
|
const storedTheme = readPreference("theme", ["light", "dark", "system"]);
|
|
62
|
-
const mediaPrefersDark =
|
|
63
|
-
|
|
64
|
-
const resolvedTheme =
|
|
65
|
-
storedTheme === "dark"
|
|
66
|
-
? "dark"
|
|
67
|
-
: storedTheme === "light"
|
|
68
|
-
? "light"
|
|
69
|
-
: storedTheme === "system" && mediaPrefersDark !== null
|
|
70
|
-
? mediaPrefersDark
|
|
71
|
-
? "dark"
|
|
72
|
-
: "light"
|
|
73
|
-
: owner.dataset.bsTheme === "dark"
|
|
74
|
-
? "dark"
|
|
75
|
-
: "light";
|
|
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";
|
|
76
53
|
owner.dataset.bsTheme = resolvedTheme;
|
|
77
|
-
|
|
78
54
|
const storedDirection = readPreference("direction", ["ltr", "rtl"]);
|
|
79
55
|
if (storedDirection) {
|
|
80
56
|
if (documentOwner) ownerDocument.documentElement.dir = storedDirection;
|
|
@@ -85,7 +61,6 @@
|
|
|
85
61
|
}
|
|
86
62
|
return;
|
|
87
63
|
}
|
|
88
|
-
|
|
89
64
|
if (!owner.matches?.('[data-slot="sidebar-wrapper"][data-sidebar-key]')) return;
|
|
90
65
|
const key = owner.dataset?.sidebarKey;
|
|
91
66
|
if (!key) return;
|
|
@@ -95,7 +70,6 @@
|
|
|
95
70
|
owner.dataset.sidebarState = state;
|
|
96
71
|
}
|
|
97
72
|
} catch (_) {
|
|
98
|
-
// Restricted browsing contexts may deny localStorage.
|
|
99
73
|
} finally {
|
|
100
74
|
owner.dataset.sidebarStateReady = "";
|
|
101
75
|
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Moo UI table-of-contents.js v1.1.0-dev.1 (https://wpmoo.org/)
|
|
3
|
+
* Copyright 2026 WPMoo Authors
|
|
4
|
+
* Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const instances = /* @__PURE__ */ new WeakMap();
|
|
8
|
+
const ownerSelector = '.moo-ui[data-bs-theme="light"], .moo-ui[data-bs-theme="dark"]';
|
|
9
|
+
function activationOffset(options, previous = 0) {
|
|
10
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
11
|
+
throw new TypeError("TableOfContents options must be an object.");
|
|
12
|
+
}
|
|
13
|
+
const value = options.activationOffset === void 0 ? previous : options.activationOffset;
|
|
14
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
15
|
+
throw new TypeError("TableOfContents activationOffset must be a finite nonnegative number.");
|
|
16
|
+
}
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
function fragmentId(href) {
|
|
20
|
+
if (!href?.startsWith("#") || href.length === 1) return null;
|
|
21
|
+
try {
|
|
22
|
+
return decodeURIComponent(href.slice(1));
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
class TableOfContents {
|
|
28
|
+
static getInstance(element) {
|
|
29
|
+
return element?.nodeType === 1 ? instances.get(element) || null : null;
|
|
30
|
+
}
|
|
31
|
+
static getOrCreateInstance(element, options = {}) {
|
|
32
|
+
return TableOfContents.getInstance(element) || new TableOfContents(element, options);
|
|
33
|
+
}
|
|
34
|
+
constructor(element, options = {}) {
|
|
35
|
+
if (element?.nodeType !== 1 || !element.matches("[data-toc]")) {
|
|
36
|
+
throw new TypeError("TableOfContents requires a [data-toc] root element.");
|
|
37
|
+
}
|
|
38
|
+
const existing = instances.get(element);
|
|
39
|
+
if (existing) return existing;
|
|
40
|
+
this._element = element;
|
|
41
|
+
this._document = element.ownerDocument;
|
|
42
|
+
this._window = this._document.defaultView;
|
|
43
|
+
this._offset = activationOffset(options);
|
|
44
|
+
this._listeners = [];
|
|
45
|
+
this._originalLinks = /* @__PURE__ */ new Map();
|
|
46
|
+
this._originalStatus = /* @__PURE__ */ new Map();
|
|
47
|
+
this._originalMarker = {
|
|
48
|
+
attribute: element.getAttribute("data-toc-marker"),
|
|
49
|
+
properties: ["--moo-toc-marker-offset", "--moo-toc-marker-height"].map((name) => ({
|
|
50
|
+
name,
|
|
51
|
+
value: element.style.getPropertyValue(name),
|
|
52
|
+
priority: element.style.getPropertyPriority(name)
|
|
53
|
+
}))
|
|
54
|
+
};
|
|
55
|
+
this._links = [];
|
|
56
|
+
this._targets = [];
|
|
57
|
+
this._frame = 0;
|
|
58
|
+
this._disposed = false;
|
|
59
|
+
instances.set(element, this);
|
|
60
|
+
this.refresh();
|
|
61
|
+
}
|
|
62
|
+
refresh(options = {}) {
|
|
63
|
+
if (this._disposed) return this;
|
|
64
|
+
const offset = activationOffset(options, this._offset);
|
|
65
|
+
this._clearListeners();
|
|
66
|
+
this._offset = offset;
|
|
67
|
+
const owner = this._element.closest(ownerSelector);
|
|
68
|
+
const contentId = this._element.getAttribute("data-toc-content");
|
|
69
|
+
const scope = contentId ? this._document.getElementById(contentId) : owner;
|
|
70
|
+
const rootId = this._element.getAttribute("data-toc-scroll-root");
|
|
71
|
+
this._scrollElement = rootId ? this._document.getElementById(rootId) : null;
|
|
72
|
+
this._status = Array.from(this._element.querySelectorAll("[data-toc-current]")).find((node) => node.closest("[data-toc]") === this._element) || null;
|
|
73
|
+
if (this._status && !this._originalStatus.has(this._status)) {
|
|
74
|
+
this._originalStatus.set(this._status, this._status.textContent);
|
|
75
|
+
}
|
|
76
|
+
this._overview = this._status ? this._originalStatus.get(this._status) : "";
|
|
77
|
+
this._links = Array.from(this._element.querySelectorAll('a[href^="#"]')).filter((link) => link.closest("[data-toc]") === this._element).map((link) => ({ link, id: fragmentId(link.getAttribute("href")) }));
|
|
78
|
+
this._links.forEach(({ link }) => {
|
|
79
|
+
if (!this._originalLinks.has(link)) {
|
|
80
|
+
this._originalLinks.set(link, {
|
|
81
|
+
active: link.classList.contains("active"),
|
|
82
|
+
current: link.getAttribute("aria-current")
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
this._targets = [];
|
|
87
|
+
this._activate(null);
|
|
88
|
+
if (!owner || !scope || scope.closest(ownerSelector) !== owner || rootId && (!this._scrollElement || !this._scrollElement.contains(scope))) {
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
const seen = /* @__PURE__ */ new Set();
|
|
92
|
+
this._links.forEach(({ id, link }) => {
|
|
93
|
+
const target = id ? this._document.getElementById(id) : null;
|
|
94
|
+
if (!target || seen.has(id) || !scope.contains(target) || target.closest(ownerSelector) !== owner) return;
|
|
95
|
+
seen.add(id);
|
|
96
|
+
this._targets.push({ id, target, label: link.textContent.trim() });
|
|
97
|
+
});
|
|
98
|
+
if (!this._targets.length) return this;
|
|
99
|
+
const queue = () => this._requestUpdate();
|
|
100
|
+
this._listen(this._scrollElement || this._window, "scroll", queue, { passive: true });
|
|
101
|
+
this._listen(this._window, "resize", queue);
|
|
102
|
+
this._listen(this._window, "hashchange", queue);
|
|
103
|
+
this._listen(this._element, "click", queue);
|
|
104
|
+
this._update();
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
107
|
+
dispose() {
|
|
108
|
+
if (this._disposed) return;
|
|
109
|
+
this._disposed = true;
|
|
110
|
+
this._clearListeners();
|
|
111
|
+
this._originalLinks.forEach(({ active, current }, link) => {
|
|
112
|
+
link.classList.toggle("active", active);
|
|
113
|
+
if (current === null) link.removeAttribute("aria-current");
|
|
114
|
+
else link.setAttribute("aria-current", current);
|
|
115
|
+
});
|
|
116
|
+
this._originalStatus.forEach((text, node) => {
|
|
117
|
+
node.textContent = text;
|
|
118
|
+
});
|
|
119
|
+
const { attribute, properties } = this._originalMarker;
|
|
120
|
+
if (attribute === null) this._element.removeAttribute("data-toc-marker");
|
|
121
|
+
else this._element.setAttribute("data-toc-marker", attribute);
|
|
122
|
+
properties.forEach(({ name, value, priority }) => {
|
|
123
|
+
if (value) this._element.style.setProperty(name, value, priority);
|
|
124
|
+
else this._element.style.removeProperty(name);
|
|
125
|
+
});
|
|
126
|
+
this._originalLinks.clear();
|
|
127
|
+
this._originalStatus.clear();
|
|
128
|
+
this._targets = [];
|
|
129
|
+
this._links = [];
|
|
130
|
+
if (instances.get(this._element) === this) instances.delete(this._element);
|
|
131
|
+
}
|
|
132
|
+
_listen(target, type, handler, options) {
|
|
133
|
+
target.addEventListener(type, handler, options);
|
|
134
|
+
this._listeners.push({ target, type, handler, options });
|
|
135
|
+
}
|
|
136
|
+
_clearListeners() {
|
|
137
|
+
this._listeners.forEach(({ target, type, handler, options }) => target.removeEventListener(type, handler, options));
|
|
138
|
+
this._listeners = [];
|
|
139
|
+
if (this._frame) this._window.cancelAnimationFrame(this._frame);
|
|
140
|
+
this._frame = 0;
|
|
141
|
+
}
|
|
142
|
+
_requestUpdate() {
|
|
143
|
+
if (this._disposed || this._frame) return;
|
|
144
|
+
this._frame = this._window.requestAnimationFrame(() => {
|
|
145
|
+
this._frame = 0;
|
|
146
|
+
this._update();
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
_update() {
|
|
150
|
+
if (this._disposed) return;
|
|
151
|
+
const targets = this._targets.filter(({ target }) => target.isConnected && target.getClientRects().length > 0);
|
|
152
|
+
const scroller = this._scrollElement || this._document.scrollingElement;
|
|
153
|
+
const line = (this._scrollElement ? this._scrollElement.getBoundingClientRect().top + this._scrollElement.clientTop : 0) + this._offset;
|
|
154
|
+
let active = null;
|
|
155
|
+
targets.forEach((entry) => {
|
|
156
|
+
if (entry.target.getBoundingClientRect().top <= line + 1) active = entry;
|
|
157
|
+
});
|
|
158
|
+
const canScroll = scroller && scroller.scrollHeight > scroller.clientHeight + 1;
|
|
159
|
+
if (!canScroll) {
|
|
160
|
+
const hashId = fragmentId(this._window.location.hash);
|
|
161
|
+
active = targets.find(({ id }) => id === hashId) || active;
|
|
162
|
+
}
|
|
163
|
+
if (targets.length && canScroll && scroller.scrollTop + scroller.clientHeight >= scroller.scrollHeight - 1) {
|
|
164
|
+
active = targets[targets.length - 1];
|
|
165
|
+
}
|
|
166
|
+
this._activate(active);
|
|
167
|
+
}
|
|
168
|
+
_activate(active) {
|
|
169
|
+
let activeLink = null;
|
|
170
|
+
this._links.forEach(({ link, id }) => {
|
|
171
|
+
const current = active !== null && id === active.id;
|
|
172
|
+
link.classList.toggle("active", current);
|
|
173
|
+
if (current) {
|
|
174
|
+
link.setAttribute("aria-current", "location");
|
|
175
|
+
activeLink || (activeLink = link);
|
|
176
|
+
} else link.removeAttribute("aria-current");
|
|
177
|
+
});
|
|
178
|
+
if (this._status) this._status.textContent = active ? active.label : this._overview;
|
|
179
|
+
this._updateMarker(activeLink);
|
|
180
|
+
}
|
|
181
|
+
_updateMarker(link) {
|
|
182
|
+
const list = this._element.querySelector(":scope > .nav");
|
|
183
|
+
const text = link?.querySelector("span");
|
|
184
|
+
if (!list?.contains(link) || !text?.offsetHeight || !this._element.getClientRects().length) {
|
|
185
|
+
this._element.removeAttribute("data-toc-marker");
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
this._element.style.setProperty("--moo-toc-marker-offset", `${link.offsetTop + text.offsetTop}px`);
|
|
189
|
+
this._element.style.setProperty("--moo-toc-marker-height", `${text.offsetHeight}px`);
|
|
190
|
+
this._element.setAttribute("data-toc-marker", "");
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
export {
|
|
194
|
+
TableOfContents as default
|
|
195
|
+
};
|
|
@@ -3,22 +3,22 @@
|
|
|
3
3
|
{
|
|
4
4
|
"export": "./moo.css",
|
|
5
5
|
"path": "dist/assets/css/moo.css",
|
|
6
|
-
"sha256": "
|
|
6
|
+
"sha256": "38bb85c89e2f1f2f043119a9290cb58dd74a1572090b5fc41930c7c57a90c894"
|
|
7
7
|
},
|
|
8
8
|
{
|
|
9
9
|
"export": "./moo-ui.css",
|
|
10
10
|
"path": "dist/assets/css/moo-ui.css",
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "d6947a3a27a4315591cf9f6b92e1fd1d958a5fceb1523b709487d54fcbefc815"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"export": "./state.js",
|
|
15
15
|
"path": "dist/js/state.js",
|
|
16
|
-
"sha256": "
|
|
16
|
+
"sha256": "3560c86c8623a3d523ec763456d984e009d8a7fa5834de168b153ba9d242f1c2"
|
|
17
17
|
}
|
|
18
18
|
],
|
|
19
19
|
"package": {
|
|
20
20
|
"name": "@wpmoo/ui",
|
|
21
|
-
"version": "1.
|
|
21
|
+
"version": "1.1.0-dev.1"
|
|
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.
|
|
3
|
+
"version": "1.1.0-dev.1",
|
|
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,6 +38,8 @@
|
|
|
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
|
+
"./table-of-contents.js": "./dist/js/table-of-contents.js",
|
|
42
|
+
"./sheet.js": "./dist/js/sheet.js",
|
|
41
43
|
"./chart.js": "./dist/js/chart.js",
|
|
42
44
|
"./chart.min.js": "./dist/js/chart.min.js",
|
|
43
45
|
"./datepicker.js": "./dist/js/datepicker.js",
|
|
@@ -64,6 +66,8 @@
|
|
|
64
66
|
"dist/js/context-menu.js",
|
|
65
67
|
"dist/js/datatable.js",
|
|
66
68
|
"dist/js/slider.js",
|
|
69
|
+
"dist/js/table-of-contents.js",
|
|
70
|
+
"dist/js/sheet.js",
|
|
67
71
|
"dist/js/chart.js",
|
|
68
72
|
"dist/js/chart.min.js",
|
|
69
73
|
"dist/js/datepicker.js",
|