@wpmoo/ui 0.9.0 → 1.0.0-rc.10
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 +4 -2
- package/LICENSE +28 -0
- package/README.md +105 -100
- package/certification.json +25 -3
- package/dist/assets/css/moo-ui.css +14005 -12457
- package/dist/assets/css/moo-ui.min.css +10 -28
- package/dist/assets/css/moo.css +2606 -902
- package/dist/assets/css/moo.min.css +10 -29
- package/dist/js/chart.js +15312 -0
- package/dist/js/chart.min.js +27 -0
- package/dist/js/combobox.js +129 -85
- package/dist/js/context-menu.js +35 -66
- package/dist/js/datatable.js +390 -188
- package/dist/js/datepicker.js +1197 -0
- package/dist/js/datepicker.min.js +7 -0
- package/dist/js/moo-ui.js +3947 -0
- package/dist/js/moo-ui.min.js +7 -0
- package/dist/js/sheet.js +46 -0
- package/dist/js/sidebar.js +190 -172
- package/dist/js/slider.js +289 -0
- package/dist/js/state.js +76 -0
- package/dist/release-manifest.json +24 -0
- package/package.json +39 -9
- package/scss/_components.scss +70 -0
- package/scss/_config.scss +18 -0
- package/scss/_settings.scss +5 -0
- package/scss/components/_accordion.scss +54 -0
- package/scss/components/_alert.scss +82 -0
- package/scss/components/_avatar.scss +139 -0
- package/scss/components/_badge.scss +34 -0
- package/scss/components/_breadcrumb.scss +119 -0
- package/scss/components/_button.scss +200 -0
- package/scss/components/_button_group.scss +57 -0
- package/scss/components/_card.scss +114 -0
- package/scss/components/_checkbox.scss +78 -0
- package/scss/components/_close_button.scss +56 -0
- package/scss/components/_collapsible.scss +44 -0
- package/scss/components/_combobox.scss +253 -0
- package/scss/components/_context-menu.scss +18 -0
- package/scss/components/_datatable.scss +1067 -0
- package/scss/components/_datepicker.scss +237 -0
- package/scss/components/_dialog.scss +69 -0
- package/scss/components/_dropdown.scss +201 -0
- package/scss/components/_field.scss +94 -0
- package/scss/components/_input.scss +31 -0
- package/scss/components/_input_group.scss +151 -0
- package/scss/components/_kbd.scss +11 -0
- package/scss/components/_menubar.scss +17 -0
- package/scss/components/_navigation.scss +36 -0
- package/scss/components/_pagination.scss +58 -0
- package/scss/components/_popover.scss +26 -0
- package/scss/components/_progress.scss +5 -0
- package/scss/components/_radio_group.scss +108 -0
- package/scss/components/_search_trigger.scss +61 -0
- package/scss/components/_select.scss +8 -0
- package/scss/components/_separator.scss +10 -0
- package/scss/components/_sheet.scss +16 -0
- package/scss/components/_sidebar.scss +5 -0
- package/scss/components/_skeleton.scss +10 -0
- package/scss/components/_slider.scss +213 -0
- package/scss/components/_spinner.scss +11 -0
- package/scss/components/_switch.scss +30 -0
- package/scss/components/_table.scss +12 -0
- package/scss/components/_tabs.scss +116 -0
- package/scss/components/_textarea.scss +8 -0
- package/scss/components/_toast.scss +116 -0
- package/scss/components/_toggle_group.scss +17 -0
- package/scss/components/_tooltip.scss +64 -0
- package/scss/components/sidebar/_base.scss +86 -0
- package/scss/components/sidebar/_collapsed.scss +112 -0
- package/scss/components/sidebar/_identity.scss +71 -0
- package/scss/components/sidebar/_menus.scss +219 -0
- package/scss/foundations/_backdrop.scss +102 -0
- package/scss/foundations/_focus.scss +83 -0
- package/scss/foundations/_globals.scss +5 -0
- package/scss/foundations/_scope.scss +26 -0
- package/scss/layouts/_app.scss +75 -0
- package/scss/layouts/_page_grid.scss +27 -0
- package/scss/layouts/app/sidebar/_base.scss +84 -0
- package/scss/layouts/app/sidebar/_default.scss +20 -0
- package/scss/layouts/app/sidebar/_floating.scss +36 -0
- package/scss/layouts/app/sidebar/_inset.scss +32 -0
- package/scss/mixins/_banner.scss +9 -0
- package/scss/moo-core.scss +16 -0
- package/scss/moo-ui.scss +54 -0
- package/scss/settings/_bootstrap_overrides.scss +7 -0
- package/scss/settings/_component_variables.scss +244 -0
- package/scss/settings/_forms.scss +28 -0
- package/scss/settings/_options.scss +2 -0
- package/scss/settings/_palette.scss +90 -0
- package/scss/themes/_forms.scss +15 -0
- package/scss/themes/_root.scss +20 -0
- package/scss/themes/_standalone.scss +3 -0
- package/scss/themes/_theme.scss +244 -0
- package/scss/utilities/_background_color.scss +18 -0
- package/scss/utilities/_scroll_fade.scss +193 -0
- package/scss/utilities/_scroll_fade_primitives.scss +43 -0
- package/scss/_facade-settings.scss +0 -51
- package/scss/settings/_facade_public.scss +0 -23
package/dist/js/context-menu.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
/*!
|
|
2
|
+
* Moo UI context-menu.js v1.0.0-rc.10 (https://wpmoo.org/)
|
|
3
|
+
* Copyright 2026 WPMoo Authors
|
|
4
|
+
* Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
|
|
5
|
+
*/
|
|
2
6
|
|
|
7
|
+
const instances = /* @__PURE__ */ new WeakMap();
|
|
3
8
|
function pointerRect(event) {
|
|
4
9
|
const { clientX: x, clientY: y } = event;
|
|
5
10
|
return { top: y, left: x, right: x, bottom: y, width: 0, height: 0, x, y };
|
|
6
11
|
}
|
|
7
|
-
|
|
8
12
|
function isDisabledTrigger(trigger) {
|
|
9
13
|
return Boolean(trigger?.disabled || trigger?.getAttribute?.("aria-disabled") === "true");
|
|
10
14
|
}
|
|
11
|
-
|
|
12
15
|
function menuItemFromEvent(event) {
|
|
13
16
|
const target = event.target;
|
|
14
17
|
const item = target.closest?.(".dropdown-item");
|
|
@@ -17,16 +20,13 @@ function menuItemFromEvent(event) {
|
|
|
17
20
|
}
|
|
18
21
|
return target.closest?.("li")?.querySelector(":scope > .dropdown-item") || null;
|
|
19
22
|
}
|
|
20
|
-
|
|
21
|
-
export default class ContextMenu {
|
|
23
|
+
class ContextMenu {
|
|
22
24
|
static getInstance(element) {
|
|
23
25
|
return element?.nodeType === 1 ? instances.get(element) || null : null;
|
|
24
26
|
}
|
|
25
|
-
|
|
26
27
|
static getOrCreateInstance(element, config = {}) {
|
|
27
28
|
return ContextMenu.getInstance(element) || new ContextMenu(element, config);
|
|
28
29
|
}
|
|
29
|
-
|
|
30
30
|
constructor(element, config = {}) {
|
|
31
31
|
if (element?.nodeType !== 1 || !element.matches(".context-menu")) {
|
|
32
32
|
throw new TypeError("ContextMenu requires a .context-menu root element.");
|
|
@@ -35,7 +35,6 @@ export default class ContextMenu {
|
|
|
35
35
|
if (existing) {
|
|
36
36
|
return existing;
|
|
37
37
|
}
|
|
38
|
-
|
|
39
38
|
this._element = element;
|
|
40
39
|
this._document = element.ownerDocument;
|
|
41
40
|
this._window = this._document.defaultView;
|
|
@@ -47,12 +46,10 @@ export default class ContextMenu {
|
|
|
47
46
|
if (!this._fallback) {
|
|
48
47
|
throw new TypeError("ContextMenu requires an explicit fallback trigger.");
|
|
49
48
|
}
|
|
50
|
-
|
|
51
49
|
const Dropdown = this._bootstrap("Dropdown");
|
|
52
50
|
if (!Dropdown) {
|
|
53
51
|
throw new TypeError("ContextMenu requires bootstrap.Dropdown (bootstrap.bundle.js).");
|
|
54
52
|
}
|
|
55
|
-
|
|
56
53
|
this._config = { ...config };
|
|
57
54
|
this._listeners = [];
|
|
58
55
|
this._invoker = null;
|
|
@@ -60,17 +57,15 @@ export default class ContextMenu {
|
|
|
60
57
|
this._openMethod = null;
|
|
61
58
|
this._reference = {
|
|
62
59
|
getBoundingClientRect: () => this._currentRect(),
|
|
63
|
-
contextElement: this._fallback
|
|
60
|
+
contextElement: this._fallback
|
|
64
61
|
};
|
|
65
62
|
this._dropdown = new Dropdown(this._fallback, {
|
|
66
63
|
reference: this._reference,
|
|
67
|
-
autoClose: "outside"
|
|
64
|
+
autoClose: "outside"
|
|
68
65
|
});
|
|
69
|
-
|
|
70
66
|
instances.set(element, this);
|
|
71
67
|
this._bindEvents();
|
|
72
68
|
}
|
|
73
|
-
|
|
74
69
|
dispose() {
|
|
75
70
|
this._listeners.forEach(({ target, type, handler, options }) => {
|
|
76
71
|
target.removeEventListener(type, handler, options);
|
|
@@ -82,56 +77,46 @@ export default class ContextMenu {
|
|
|
82
77
|
this._pointerRect = null;
|
|
83
78
|
instances.delete(this._element);
|
|
84
79
|
}
|
|
85
|
-
|
|
86
80
|
show(anchor = this._fallback) {
|
|
87
81
|
this._open(anchor, null);
|
|
88
82
|
}
|
|
89
|
-
|
|
90
83
|
hide() {
|
|
91
84
|
this._dropdown.hide();
|
|
92
85
|
}
|
|
93
|
-
|
|
94
86
|
_listen(target, type, handler, options) {
|
|
95
87
|
target.addEventListener(type, handler, options);
|
|
96
88
|
this._listeners.push({ target, type, handler, options });
|
|
97
89
|
}
|
|
98
|
-
|
|
99
90
|
_bootstrap(name) {
|
|
100
91
|
return this._window.bootstrap?.[name] || null;
|
|
101
92
|
}
|
|
102
|
-
|
|
103
93
|
_currentRect() {
|
|
104
94
|
if (this._pointerRect) {
|
|
105
95
|
return this._pointerRect;
|
|
106
96
|
}
|
|
107
97
|
return (this._invoker || this._fallback).getBoundingClientRect();
|
|
108
98
|
}
|
|
109
|
-
|
|
110
99
|
_trigger(name, cancelable = false) {
|
|
111
100
|
return this._element.dispatchEvent(
|
|
112
101
|
new this._window.CustomEvent(`${name}.moo.context-menu`, {
|
|
113
102
|
bubbles: true,
|
|
114
|
-
cancelable
|
|
103
|
+
cancelable
|
|
115
104
|
})
|
|
116
105
|
);
|
|
117
106
|
}
|
|
118
|
-
|
|
119
107
|
_triggers() {
|
|
120
108
|
return Array.from(this._element.querySelectorAll(":scope > .context-menu-trigger"));
|
|
121
109
|
}
|
|
122
|
-
|
|
123
110
|
_syncExpanded(expanded) {
|
|
124
111
|
this._triggers().forEach((trigger) => {
|
|
125
112
|
trigger.setAttribute("aria-expanded", String(expanded));
|
|
126
113
|
});
|
|
127
114
|
}
|
|
128
|
-
|
|
129
115
|
_menuItems() {
|
|
130
116
|
return Array.from(this._menu.querySelectorAll(".dropdown-item")).filter(
|
|
131
117
|
(item) => !isDisabledTrigger(item) && !item.classList.contains("disabled")
|
|
132
118
|
);
|
|
133
119
|
}
|
|
134
|
-
|
|
135
120
|
_open(trigger, pointerEvent, openMethod) {
|
|
136
121
|
if (isDisabledTrigger(trigger)) {
|
|
137
122
|
return;
|
|
@@ -144,7 +129,6 @@ export default class ContextMenu {
|
|
|
144
129
|
this._openMethod = openMethod;
|
|
145
130
|
this._dropdown.show();
|
|
146
131
|
}
|
|
147
|
-
|
|
148
132
|
_handleContextMenu(event) {
|
|
149
133
|
const trigger = event.target.closest(".context-menu-trigger");
|
|
150
134
|
if (!trigger || !this._element.contains(trigger)) {
|
|
@@ -153,7 +137,6 @@ export default class ContextMenu {
|
|
|
153
137
|
event.preventDefault();
|
|
154
138
|
this._open(trigger, event, "pointer");
|
|
155
139
|
}
|
|
156
|
-
|
|
157
140
|
_handleKeydown(event) {
|
|
158
141
|
const trigger = event.target.closest(".context-menu-trigger");
|
|
159
142
|
if (!trigger || !this._element.contains(trigger)) {
|
|
@@ -167,44 +150,45 @@ export default class ContextMenu {
|
|
|
167
150
|
event.preventDefault();
|
|
168
151
|
this._open(trigger, null, "keyboard");
|
|
169
152
|
}
|
|
170
|
-
|
|
171
153
|
_handleFallbackClick() {
|
|
172
154
|
this._invoker = this._fallback;
|
|
173
155
|
this._pointerRect = null;
|
|
174
156
|
this._openMethod = "pointer";
|
|
175
157
|
}
|
|
176
|
-
|
|
158
|
+
_handleFallbackKeydown(event) {
|
|
159
|
+
if (event.key !== " " && event.key !== "Spacebar") {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
event.preventDefault();
|
|
163
|
+
event.stopPropagation();
|
|
164
|
+
if (this._menu.classList.contains("show")) {
|
|
165
|
+
this._dropdown.hide();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
this._open(this._fallback, null, "fallback-keyboard");
|
|
169
|
+
}
|
|
177
170
|
_handleMenuClick(event) {
|
|
178
171
|
const item = menuItemFromEvent(event);
|
|
179
172
|
if (!item) {
|
|
180
173
|
return;
|
|
181
174
|
}
|
|
182
175
|
const persistentItem = item.matches(".dropdown-item-check, [data-context-menu-persistent]");
|
|
183
|
-
const disabledItem =
|
|
184
|
-
item.matches('.dropdown-item.disabled, .dropdown-item[aria-disabled="true"], .dropdown-item:disabled') ||
|
|
185
|
-
isDisabledTrigger(item);
|
|
176
|
+
const disabledItem = item.matches('.dropdown-item.disabled, .dropdown-item[aria-disabled="true"], .dropdown-item:disabled') || isDisabledTrigger(item);
|
|
186
177
|
if (disabledItem) {
|
|
187
178
|
event.preventDefault();
|
|
188
179
|
event.stopPropagation();
|
|
189
180
|
return;
|
|
190
181
|
}
|
|
191
|
-
// Radio-grouped toggle buttons reuse the dropdown_toggle_item() button
|
|
192
|
-
// Bootstrap's own roving arrow-key focus already picks up (it only ever
|
|
193
|
-
// matches real .dropdown-item elements); Moo adds only the missing
|
|
194
|
-
// mutual-exclusivity Bootstrap's independent button-toggle plugin does
|
|
195
|
-
// not provide.
|
|
196
182
|
const radioButton = item.matches("[data-context-menu-radio-group]") ? item : null;
|
|
197
183
|
if (radioButton) {
|
|
198
184
|
event.preventDefault();
|
|
199
185
|
event.stopPropagation();
|
|
200
186
|
const group = radioButton.dataset.contextMenuRadioGroup;
|
|
201
|
-
this._menu
|
|
202
|
-
|
|
203
|
-
.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
button.setAttribute("aria-pressed", String(checked));
|
|
207
|
-
});
|
|
187
|
+
this._menu.querySelectorAll(`[data-context-menu-radio-group="${group}"]`).forEach((button) => {
|
|
188
|
+
const checked = button === radioButton;
|
|
189
|
+
button.classList.toggle("active", checked);
|
|
190
|
+
button.setAttribute("aria-pressed", String(checked));
|
|
191
|
+
});
|
|
208
192
|
return;
|
|
209
193
|
}
|
|
210
194
|
if (persistentItem) {
|
|
@@ -212,11 +196,11 @@ export default class ContextMenu {
|
|
|
212
196
|
}
|
|
213
197
|
this._dropdown.hide();
|
|
214
198
|
}
|
|
215
|
-
|
|
216
199
|
_bindEvents() {
|
|
217
200
|
this._listen(this._element, "contextmenu", (event) => this._handleContextMenu(event));
|
|
218
201
|
this._listen(this._element, "keydown", (event) => this._handleKeydown(event));
|
|
219
202
|
this._listen(this._fallback, "click", () => this._handleFallbackClick());
|
|
203
|
+
this._listen(this._fallback, "keydown", (event) => this._handleFallbackKeydown(event));
|
|
220
204
|
this._listen(this._menu, "click", (event) => this._handleMenuClick(event));
|
|
221
205
|
this._listen(this._fallback, "show.bs.dropdown", (event) => {
|
|
222
206
|
if (!this._trigger("show", true)) {
|
|
@@ -225,13 +209,9 @@ export default class ContextMenu {
|
|
|
225
209
|
});
|
|
226
210
|
this._listen(this._fallback, "shown.bs.dropdown", () => {
|
|
227
211
|
this._syncExpanded(true);
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
// highlight instead of a focus ring competing with it. A keyboard-
|
|
232
|
-
// driven open (Shift+F10/ContextMenu key) still lands on the first
|
|
233
|
-
// item, matching that same native arrow-key-open convention.
|
|
234
|
-
if (this._openMethod === "keyboard") {
|
|
212
|
+
if (this._openMethod === "fallback-keyboard") {
|
|
213
|
+
this._fallback.focus();
|
|
214
|
+
} else if (this._openMethod === "keyboard") {
|
|
235
215
|
this._menuItems()[0]?.focus();
|
|
236
216
|
} else {
|
|
237
217
|
this._menu.focus();
|
|
@@ -248,22 +228,8 @@ export default class ContextMenu {
|
|
|
248
228
|
const invoker = this._invoker;
|
|
249
229
|
this._pointerRect = null;
|
|
250
230
|
this._invoker = null;
|
|
251
|
-
// A native Bootstrap click on the fallback trigger bypasses _open()
|
|
252
|
-
// entirely (Bootstrap's own capture-phase click-to-toggle handler
|
|
253
|
-
// calls show() directly), so _handleFallbackClick's bubble-phase
|
|
254
|
-
// "click" listener always runs too late to set _openMethod before
|
|
255
|
-
// shown.bs.dropdown reads it. Resetting it here, back to the neutral
|
|
256
|
-
// pointer default, is what keeps that path correct rather than
|
|
257
|
-
// inheriting whatever a prior keyboard-triggered open last set.
|
|
258
231
|
this._openMethod = null;
|
|
259
232
|
this._trigger("hidden");
|
|
260
|
-
// Bootstrap's own dataApiKeydownHandler (js/src/dropdown.js) intercepts
|
|
261
|
-
// Escape in the document capture phase and hardcodes
|
|
262
|
-
// `getToggleButton.focus()` (our fallback trigger) after hide().
|
|
263
|
-
// Nothing downstream of a capture-phase stopPropagation() can observe
|
|
264
|
-
// that keydown to redirect focus, so correct it in a microtask, which
|
|
265
|
-
// still runs before the next paint: if focus landed on the fallback
|
|
266
|
-
// but a different trigger invoked this menu, return focus there.
|
|
267
233
|
queueMicrotask(() => {
|
|
268
234
|
if (invoker && invoker !== this._fallback && this._document.activeElement === this._fallback) {
|
|
269
235
|
invoker.focus();
|
|
@@ -272,3 +238,6 @@ export default class ContextMenu {
|
|
|
272
238
|
});
|
|
273
239
|
}
|
|
274
240
|
}
|
|
241
|
+
export {
|
|
242
|
+
ContextMenu as default
|
|
243
|
+
};
|