@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/sidebar.js
CHANGED
|
@@ -1,14 +1,57 @@
|
|
|
1
|
-
|
|
1
|
+
/*!
|
|
2
|
+
* Moo UI sidebar.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
|
+
*/
|
|
6
|
+
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
+
|
|
10
|
+
// src/js/theme-owner.js
|
|
11
|
+
var OWNER_SELECTOR = '.moo-ui[data-bs-theme="light"], .moo-ui[data-bs-theme="dark"]';
|
|
12
|
+
var PORTAL_SELECTOR = "[data-moo-overlay-host]";
|
|
13
|
+
function documentFor(node) {
|
|
14
|
+
if (node?.nodeType === 9) return node;
|
|
15
|
+
if (node?.ownerDocument) return node.ownerDocument;
|
|
16
|
+
return typeof document === "undefined" ? null : document;
|
|
17
|
+
}
|
|
18
|
+
__name(documentFor, "documentFor");
|
|
19
|
+
function isResolvedOwner(node) {
|
|
20
|
+
return Boolean(node?.matches?.(OWNER_SELECTOR));
|
|
21
|
+
}
|
|
22
|
+
__name(isResolvedOwner, "isResolvedOwner");
|
|
23
|
+
function ownerRootFor(node) {
|
|
24
|
+
const ownerDocument = documentFor(node);
|
|
25
|
+
if (node?.nodeType === 9 || node === ownerDocument?.body) {
|
|
26
|
+
return ownerDocument?.body?.firstElementChild || null;
|
|
27
|
+
}
|
|
28
|
+
return node;
|
|
29
|
+
}
|
|
30
|
+
__name(ownerRootFor, "ownerRootFor");
|
|
31
|
+
function findThemeOwner(node = typeof document === "undefined" ? null : document) {
|
|
32
|
+
const start = ownerRootFor(node);
|
|
33
|
+
if (!start) return null;
|
|
34
|
+
if (isResolvedOwner(start)) return start;
|
|
35
|
+
return start.closest?.(OWNER_SELECTOR) || null;
|
|
36
|
+
}
|
|
37
|
+
__name(findThemeOwner, "findThemeOwner");
|
|
38
|
+
function ownerPortalRoot(owner) {
|
|
39
|
+
if (!owner) return null;
|
|
40
|
+
return Array.from(owner.children || []).find(
|
|
41
|
+
(child) => child.matches?.(PORTAL_SELECTOR)
|
|
42
|
+
) || owner;
|
|
43
|
+
}
|
|
44
|
+
__name(ownerPortalRoot, "ownerPortalRoot");
|
|
2
45
|
|
|
3
|
-
|
|
46
|
+
// src/js/components/sidebar.js
|
|
47
|
+
var instances = /* @__PURE__ */ new WeakMap();
|
|
48
|
+
var _Sidebar = class _Sidebar {
|
|
4
49
|
static getInstance(element) {
|
|
5
50
|
return element?.nodeType === 1 ? instances.get(element) || null : null;
|
|
6
51
|
}
|
|
7
|
-
|
|
8
52
|
static getOrCreateInstance(element, config = {}) {
|
|
9
|
-
return
|
|
53
|
+
return _Sidebar.getInstance(element) || new _Sidebar(element, config);
|
|
10
54
|
}
|
|
11
|
-
|
|
12
55
|
constructor(element, config = {}) {
|
|
13
56
|
if (element?.nodeType !== 1 || !element.matches('[data-slot="sidebar-wrapper"]')) {
|
|
14
57
|
throw new TypeError("Sidebar requires a [data-slot=sidebar-wrapper] root.");
|
|
@@ -17,32 +60,31 @@ export default class Sidebar {
|
|
|
17
60
|
if (existing) {
|
|
18
61
|
return existing;
|
|
19
62
|
}
|
|
20
|
-
|
|
21
63
|
this._element = element;
|
|
22
64
|
this._document = element.ownerDocument;
|
|
23
65
|
this._window = this._document.defaultView;
|
|
24
|
-
this.
|
|
66
|
+
this._documentElement = this._document.documentElement;
|
|
67
|
+
this._root = findThemeOwner(element) || this._document.body || this._documentElement;
|
|
25
68
|
this._sidebar = element.querySelector('[data-slot="sidebar"]');
|
|
26
69
|
this._config = {
|
|
27
70
|
breakpoint: "(min-width: 992px)",
|
|
28
71
|
storagePrefix: "moo-sidebar:",
|
|
29
72
|
keyboard: true,
|
|
30
|
-
...config
|
|
73
|
+
...config
|
|
31
74
|
};
|
|
32
75
|
this._listeners = [];
|
|
33
|
-
this._tooltipAnchors = new Set();
|
|
76
|
+
this._tooltipAnchors = /* @__PURE__ */ new Set();
|
|
34
77
|
this._flyout = null;
|
|
35
78
|
this._flyoutOwner = null;
|
|
36
79
|
this._offcanvas = null;
|
|
37
80
|
this._offcanvasTrigger = null;
|
|
38
|
-
|
|
39
81
|
instances.set(element, this);
|
|
40
82
|
this._bindEvents();
|
|
41
83
|
this._restoreState();
|
|
42
|
-
this.
|
|
84
|
+
this._scrollActiveItemIntoView();
|
|
85
|
+
this._element.setAttribute("data-sidebar-ready", "");
|
|
43
86
|
this._observeDirection();
|
|
44
87
|
}
|
|
45
|
-
|
|
46
88
|
dispose() {
|
|
47
89
|
this._listeners.forEach(({ target, type, handler, options }) => {
|
|
48
90
|
target.removeEventListener(type, handler, options);
|
|
@@ -50,48 +92,41 @@ export default class Sidebar {
|
|
|
50
92
|
this._listeners = [];
|
|
51
93
|
this._directionObserver?.disconnect();
|
|
52
94
|
this._closeFlyouts();
|
|
53
|
-
this._element
|
|
54
|
-
|
|
55
|
-
.forEach((item) => this._clearDropdownPosition(item));
|
|
56
|
-
this._element
|
|
57
|
-
.querySelectorAll("[data-moo-sidebar-tooltip]")
|
|
58
|
-
.forEach((control) => this._disposeTooltip(control));
|
|
95
|
+
this._element.querySelectorAll("[data-sidebar-dropdown-positioned]").forEach((item) => this._clearDropdownPosition(item));
|
|
96
|
+
this._element.querySelectorAll("[data-sidebar-tooltip]").forEach((control) => this._disposeTooltip(control));
|
|
59
97
|
this._offcanvas?.dispose();
|
|
60
98
|
this._offcanvas = null;
|
|
61
99
|
this._offcanvasTrigger = null;
|
|
62
|
-
this._element.removeAttribute("data-
|
|
100
|
+
this._element.removeAttribute("data-sidebar-ready");
|
|
63
101
|
instances.delete(this._element);
|
|
64
102
|
}
|
|
65
|
-
|
|
66
103
|
_listen(target, type, handler, options) {
|
|
67
104
|
target?.addEventListener(type, handler, options);
|
|
68
105
|
if (target) {
|
|
69
106
|
this._listeners.push({ target, type, handler, options });
|
|
70
107
|
}
|
|
71
108
|
}
|
|
72
|
-
|
|
73
109
|
_bootstrap(name) {
|
|
74
110
|
return this._window.bootstrap?.[name] || null;
|
|
75
111
|
}
|
|
76
|
-
|
|
112
|
+
_portalRoot(trigger = this._element) {
|
|
113
|
+
return ownerPortalRoot(findThemeOwner(trigger)) || this._document.body || this._documentElement;
|
|
114
|
+
}
|
|
77
115
|
_isDesktop() {
|
|
78
116
|
return this._window.matchMedia(this._config.breakpoint).matches;
|
|
79
117
|
}
|
|
80
|
-
|
|
81
118
|
_isCollapsed() {
|
|
82
|
-
return this._isDesktop() && this._element.dataset.
|
|
119
|
+
return this._isDesktop() && this._sidebar?.dataset?.collapsible === "icon" && this._element.dataset.sidebarState === "collapsed";
|
|
83
120
|
}
|
|
84
|
-
|
|
85
121
|
_trigger(name, detail = {}) {
|
|
86
122
|
return this._element.dispatchEvent(
|
|
87
123
|
new this._window.CustomEvent(`${name}.moo.sidebar`, {
|
|
88
124
|
bubbles: true,
|
|
89
125
|
cancelable: name === "show" || name === "hide",
|
|
90
|
-
detail
|
|
126
|
+
detail
|
|
91
127
|
})
|
|
92
128
|
);
|
|
93
129
|
}
|
|
94
|
-
|
|
95
130
|
_observeDirection() {
|
|
96
131
|
const Observer = this._window.MutationObserver;
|
|
97
132
|
if (!Observer) {
|
|
@@ -101,14 +136,13 @@ export default class Sidebar {
|
|
|
101
136
|
this._closeFlyouts();
|
|
102
137
|
this._syncTooltips();
|
|
103
138
|
});
|
|
104
|
-
this._directionObserver.observe(this.
|
|
139
|
+
this._directionObserver.observe(this._documentElement, {
|
|
105
140
|
attributes: true,
|
|
106
|
-
attributeFilter: ["dir"]
|
|
141
|
+
attributeFilter: ["dir"]
|
|
107
142
|
});
|
|
108
143
|
}
|
|
109
|
-
|
|
110
144
|
_restoreState() {
|
|
111
|
-
const key = this._element.dataset.
|
|
145
|
+
const key = this._element.dataset.sidebarKey;
|
|
112
146
|
let stored = null;
|
|
113
147
|
if (key) {
|
|
114
148
|
try {
|
|
@@ -117,57 +151,66 @@ export default class Sidebar {
|
|
|
117
151
|
stored = null;
|
|
118
152
|
}
|
|
119
153
|
}
|
|
120
|
-
const initial =
|
|
121
|
-
stored === "collapsed" || stored === "expanded"
|
|
122
|
-
? stored
|
|
123
|
-
: this._element.dataset.mooSidebarState === "collapsed"
|
|
124
|
-
? "collapsed"
|
|
125
|
-
: "expanded";
|
|
154
|
+
const initial = stored === "collapsed" || stored === "expanded" ? stored : this._element.dataset.sidebarState === "collapsed" ? "collapsed" : "expanded";
|
|
126
155
|
this._setState(initial, false, false);
|
|
127
156
|
}
|
|
128
|
-
|
|
157
|
+
_scrollActiveItemIntoView() {
|
|
158
|
+
const activeRoute = this._element.querySelector(
|
|
159
|
+
'[data-slot="sidebar-content"] a[data-slot="sidebar-menu-button"][aria-current="page"], [data-slot="sidebar-content"] a.sidebar-menu-button[aria-current="page"], [data-slot="sidebar-content"] a.sidebar-menu-button.active'
|
|
160
|
+
);
|
|
161
|
+
const active = activeRoute || this._element.querySelector(
|
|
162
|
+
'[data-slot="sidebar-content"] [data-slot="sidebar-menu-button"][aria-current="page"], [data-slot="sidebar-content"] .sidebar-menu-button[aria-current="page"], [data-slot="sidebar-content"] .sidebar-menu-button.active'
|
|
163
|
+
);
|
|
164
|
+
const content = active?.closest?.('[data-slot="sidebar-content"]');
|
|
165
|
+
if (!active || !content || content.clientHeight <= 0) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const maxScrollTop = content.scrollHeight - content.clientHeight;
|
|
169
|
+
if (maxScrollTop <= 0) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const contentRect = content.getBoundingClientRect();
|
|
173
|
+
const activeRect = active.getBoundingClientRect();
|
|
174
|
+
if (contentRect.height <= 0 || activeRect.height <= 0) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const targetScrollTop = content.scrollTop + activeRect.top - contentRect.top - (content.clientHeight - activeRect.height) / 2;
|
|
178
|
+
content.scrollTop = Math.round(
|
|
179
|
+
Math.min(Math.max(targetScrollTop, 0), maxScrollTop)
|
|
180
|
+
);
|
|
181
|
+
}
|
|
129
182
|
_setState(state, persist = true, emit = true) {
|
|
130
183
|
const next = state === "collapsed" ? "collapsed" : "expanded";
|
|
131
|
-
const previous = this._element.dataset.
|
|
132
|
-
this._element.dataset.
|
|
133
|
-
const key = this._element.dataset.
|
|
184
|
+
const previous = this._element.dataset.sidebarState;
|
|
185
|
+
this._element.dataset.sidebarState = next;
|
|
186
|
+
const key = this._element.dataset.sidebarKey;
|
|
134
187
|
if (key === "catalog-shell") {
|
|
135
|
-
this._root.dataset.
|
|
188
|
+
this._root.dataset.sidebarCatalogState = next;
|
|
136
189
|
}
|
|
137
190
|
if (persist && key) {
|
|
138
191
|
try {
|
|
139
192
|
this._window.localStorage.setItem(this._config.storagePrefix + key, next);
|
|
140
193
|
} catch (_) {
|
|
141
|
-
/* Storage is best-effort in restricted browsing contexts. */
|
|
142
194
|
}
|
|
143
195
|
}
|
|
144
196
|
this._syncControls();
|
|
145
197
|
if (next === "expanded") {
|
|
146
|
-
this._element
|
|
147
|
-
.querySelectorAll(".sidebar-menu-item")
|
|
148
|
-
.forEach((item) => this._resetFlyoutTrigger(item));
|
|
198
|
+
this._element.querySelectorAll(".sidebar-menu-item").forEach((item) => this._resetFlyoutTrigger(item));
|
|
149
199
|
}
|
|
150
200
|
this._syncTooltips();
|
|
151
201
|
if (emit && previous !== next) {
|
|
152
202
|
this._trigger("change", { state: next, previousState: previous || null });
|
|
153
203
|
}
|
|
154
204
|
}
|
|
155
|
-
|
|
156
205
|
_toggle() {
|
|
157
206
|
this._setState(
|
|
158
|
-
this._element.dataset.
|
|
207
|
+
this._element.dataset.sidebarState === "collapsed" ? "expanded" : "collapsed"
|
|
159
208
|
);
|
|
160
209
|
}
|
|
161
|
-
|
|
162
210
|
_syncControls() {
|
|
163
|
-
const expanded = this._isDesktop()
|
|
164
|
-
|
|
165
|
-
: this._sidebar?.classList.contains("show") || false;
|
|
166
|
-
this._element
|
|
167
|
-
.querySelectorAll("[data-moo-sidebar-trigger], [data-moo-sidebar-rail]")
|
|
168
|
-
.forEach((control) => control.setAttribute("aria-expanded", String(expanded)));
|
|
211
|
+
const expanded = this._isDesktop() ? this._element.dataset.sidebarState === "expanded" : this._sidebar?.classList.contains("show") || false;
|
|
212
|
+
this._element.querySelectorAll("[data-sidebar-trigger], [data-sidebar-rail]").forEach((control) => control.setAttribute("aria-expanded", String(expanded)));
|
|
169
213
|
}
|
|
170
|
-
|
|
171
214
|
_resetFlyoutTrigger(item, expanded = null) {
|
|
172
215
|
const trigger = item?.querySelector(":scope > .sidebar-menu-sub-trigger");
|
|
173
216
|
const submenu = item?.querySelector(":scope > .sidebar-menu-sub");
|
|
@@ -178,68 +221,75 @@ export default class Sidebar {
|
|
|
178
221
|
);
|
|
179
222
|
}
|
|
180
223
|
}
|
|
181
|
-
|
|
182
224
|
_clearDropdownPosition(control) {
|
|
183
|
-
const item = control?.matches?.(".sidebar-menu-item")
|
|
184
|
-
? control
|
|
185
|
-
: control?.closest?.(".sidebar-menu-item");
|
|
225
|
+
const item = control?.matches?.(".sidebar-menu-item") ? control : control?.closest?.(".sidebar-menu-item");
|
|
186
226
|
if (!item) {
|
|
187
227
|
return;
|
|
188
228
|
}
|
|
189
|
-
delete item.dataset.
|
|
229
|
+
delete item.dataset.sidebarDropdownPositioned;
|
|
190
230
|
item.style.removeProperty("--moo-sidebar-dropdown-block-start");
|
|
191
|
-
item.style.removeProperty("--moo-sidebar-dropdown-
|
|
231
|
+
item.style.removeProperty("--moo-sidebar-dropdown-block-end");
|
|
232
|
+
item.style.removeProperty("--moo-sidebar-dropdown-left");
|
|
233
|
+
item.style.removeProperty("--moo-sidebar-dropdown-right");
|
|
192
234
|
}
|
|
193
|
-
|
|
194
235
|
_closeDropdowns(exceptControl = null) {
|
|
195
236
|
const Dropdown = this._bootstrap("Dropdown");
|
|
196
|
-
this._element
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
?.querySelector(".dropdown-menu.show")
|
|
209
|
-
?.classList.remove("show");
|
|
210
|
-
this._clearDropdownPosition(control);
|
|
211
|
-
}
|
|
212
|
-
});
|
|
237
|
+
this._element.querySelectorAll('[data-bs-toggle="dropdown"][aria-expanded="true"]').forEach((control) => {
|
|
238
|
+
if (control === exceptControl) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (Dropdown) {
|
|
242
|
+
Dropdown.getOrCreateInstance(control).hide();
|
|
243
|
+
} else {
|
|
244
|
+
control.setAttribute("aria-expanded", "false");
|
|
245
|
+
control.closest(".dropdown")?.querySelector(".dropdown-menu.show")?.classList.remove("show");
|
|
246
|
+
this._clearDropdownPosition(control);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
213
249
|
}
|
|
214
|
-
|
|
215
250
|
_positionDropdown(control) {
|
|
216
251
|
const item = control?.closest?.(".sidebar-menu-item");
|
|
217
|
-
const isHeaderWorkspace =
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (!control || !item || !isHeaderWorkspace || !this._isDesktop()) {
|
|
252
|
+
const isHeaderWorkspace = control?.classList.contains("sidebar-menu-button--workspace") && control.closest('[data-slot="sidebar-header"]');
|
|
253
|
+
const isFooterAccount = control?.closest(".sidebar-menu-item--account") && control.closest('[data-slot="sidebar-footer"]');
|
|
254
|
+
if (!control || !item || !(isHeaderWorkspace || isFooterAccount) || !this._isDesktop()) {
|
|
221
255
|
this._clearDropdownPosition(control);
|
|
222
256
|
return;
|
|
223
257
|
}
|
|
224
|
-
|
|
225
258
|
this._closeFlyouts();
|
|
226
259
|
const rect = control.getBoundingClientRect();
|
|
227
260
|
const gap = 4;
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
261
|
+
const sidebar = control.closest('[data-slot="sidebar"]');
|
|
262
|
+
const side = sidebar?.dataset.side || "left";
|
|
263
|
+
if (side === "right") {
|
|
264
|
+
const right = this._window.innerWidth - rect.left + gap;
|
|
265
|
+
item.style.setProperty(
|
|
266
|
+
"--moo-sidebar-dropdown-right",
|
|
267
|
+
`${Math.round(right)}px`
|
|
268
|
+
);
|
|
269
|
+
item.style.removeProperty("--moo-sidebar-dropdown-left");
|
|
270
|
+
} else {
|
|
271
|
+
const left = rect.right + gap;
|
|
272
|
+
item.style.setProperty(
|
|
273
|
+
"--moo-sidebar-dropdown-left",
|
|
274
|
+
`${Math.round(left)}px`
|
|
275
|
+
);
|
|
276
|
+
item.style.removeProperty("--moo-sidebar-dropdown-right");
|
|
277
|
+
}
|
|
278
|
+
if (isHeaderWorkspace) {
|
|
279
|
+
item.style.setProperty(
|
|
280
|
+
"--moo-sidebar-dropdown-block-start",
|
|
281
|
+
`${Math.round(rect.bottom + gap)}px`
|
|
282
|
+
);
|
|
283
|
+
item.style.removeProperty("--moo-sidebar-dropdown-block-end");
|
|
284
|
+
} else {
|
|
285
|
+
item.style.setProperty(
|
|
286
|
+
"--moo-sidebar-dropdown-block-end",
|
|
287
|
+
`${Math.round(this._window.innerHeight - rect.top + gap)}px`
|
|
288
|
+
);
|
|
289
|
+
item.style.removeProperty("--moo-sidebar-dropdown-block-start");
|
|
290
|
+
}
|
|
291
|
+
item.dataset.sidebarDropdownPositioned = "";
|
|
241
292
|
}
|
|
242
|
-
|
|
243
293
|
_removeFlyoutPortal() {
|
|
244
294
|
this._flyout?.remove();
|
|
245
295
|
if (this._flyoutOwner) {
|
|
@@ -248,17 +298,15 @@ export default class Sidebar {
|
|
|
248
298
|
this._flyout = null;
|
|
249
299
|
this._flyoutOwner = null;
|
|
250
300
|
}
|
|
251
|
-
|
|
252
301
|
_closeFlyouts() {
|
|
253
302
|
this._removeFlyoutPortal();
|
|
254
303
|
this._element.querySelectorAll(".sidebar-menu-item--flyout-open").forEach((item) => {
|
|
255
304
|
item.classList.remove("sidebar-menu-item--flyout-open");
|
|
256
305
|
item.style.removeProperty("--moo-sidebar-flyout-block-start");
|
|
257
|
-
item.style.removeProperty("--moo-sidebar-flyout-
|
|
306
|
+
item.style.removeProperty("--moo-sidebar-flyout-left");
|
|
258
307
|
this._resetFlyoutTrigger(item, false);
|
|
259
308
|
});
|
|
260
309
|
}
|
|
261
|
-
|
|
262
310
|
_openFlyout(item) {
|
|
263
311
|
const submenu = item?.querySelector(":scope > .sidebar-menu-sub");
|
|
264
312
|
const trigger = item?.querySelector(":scope > .sidebar-menu-sub-trigger");
|
|
@@ -268,45 +316,36 @@ export default class Sidebar {
|
|
|
268
316
|
if (this._flyoutOwner === item && this._flyout) {
|
|
269
317
|
return;
|
|
270
318
|
}
|
|
271
|
-
|
|
272
319
|
this._closeDropdowns();
|
|
273
320
|
this._closeFlyouts();
|
|
274
321
|
const rect = item.getBoundingClientRect();
|
|
322
|
+
const sidebar = this._sidebar;
|
|
323
|
+
const sidebarRect = sidebar?.getBoundingClientRect() || rect;
|
|
275
324
|
const gap = 4;
|
|
276
|
-
const inlineStart =
|
|
277
|
-
this._root.dir === "rtl"
|
|
278
|
-
? this._window.innerWidth - rect.left + gap
|
|
279
|
-
: rect.right + gap;
|
|
280
325
|
const flyout = submenu.cloneNode(true);
|
|
281
326
|
flyout.removeAttribute("id");
|
|
282
327
|
flyout.classList.remove("collapse", "show", "collapsing");
|
|
283
328
|
flyout.classList.add("sidebar-menu-flyout");
|
|
284
|
-
flyout.dataset.
|
|
329
|
+
flyout.dataset.sidebarFlyout = "";
|
|
285
330
|
flyout.removeAttribute("style");
|
|
286
331
|
flyout.style.setProperty("--moo-sidebar-flyout-block-start", `${Math.round(rect.top)}px`);
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const
|
|
292
|
-
|
|
332
|
+
const side = sidebar?.dataset.side || "left";
|
|
333
|
+
this._portalRoot(item).appendChild(flyout);
|
|
334
|
+
const flyoutWidth = flyout.getBoundingClientRect().width;
|
|
335
|
+
const left = side === "right" ? sidebarRect.left - flyoutWidth - gap : sidebarRect.right + gap;
|
|
336
|
+
const boundedLeft = Math.max(0, Math.min(this._window.innerWidth - flyoutWidth, left));
|
|
337
|
+
flyout.style.setProperty("--moo-sidebar-flyout-left", `${Math.round(boundedLeft)}px`);
|
|
293
338
|
this._flyout = flyout;
|
|
294
339
|
this._flyoutOwner = item;
|
|
295
340
|
item.classList.add("sidebar-menu-item--flyout-open");
|
|
296
341
|
trigger?.setAttribute("aria-expanded", "true");
|
|
297
342
|
}
|
|
298
|
-
|
|
299
343
|
_tooltipAnchor(control) {
|
|
300
344
|
return control.closest("li") || control;
|
|
301
345
|
}
|
|
302
|
-
|
|
303
346
|
_isIdentityTrigger(control) {
|
|
304
|
-
return (
|
|
305
|
-
control.closest(".sidebar-menu-item--account") ||
|
|
306
|
-
control.classList.contains("sidebar-menu-button--workspace")
|
|
307
|
-
);
|
|
347
|
+
return control.closest(".sidebar-menu-item--account") || control.classList.contains("sidebar-menu-button--workspace");
|
|
308
348
|
}
|
|
309
|
-
|
|
310
349
|
_disposeTooltip(control) {
|
|
311
350
|
const Tooltip = this._bootstrap("Tooltip");
|
|
312
351
|
if (!Tooltip || !control) {
|
|
@@ -320,38 +359,34 @@ export default class Sidebar {
|
|
|
320
359
|
anchor.removeAttribute("data-bs-original-title");
|
|
321
360
|
anchor.removeAttribute("aria-describedby");
|
|
322
361
|
}
|
|
323
|
-
|
|
324
362
|
_syncTooltips() {
|
|
325
363
|
const Tooltip = this._bootstrap("Tooltip");
|
|
326
364
|
if (!Tooltip) {
|
|
327
365
|
return;
|
|
328
366
|
}
|
|
329
367
|
const collapsed = this._isCollapsed();
|
|
330
|
-
const
|
|
331
|
-
|
|
368
|
+
const side = this._sidebar?.dataset.side || "left";
|
|
369
|
+
const placement = side === "right" ? "left" : "right";
|
|
370
|
+
this._element.querySelectorAll("[data-sidebar-tooltip]").forEach((control) => {
|
|
332
371
|
this._disposeTooltip(control);
|
|
333
|
-
if (
|
|
334
|
-
!collapsed ||
|
|
335
|
-
this._isIdentityTrigger(control) ||
|
|
336
|
-
control.closest(".sidebar-menu-item")?.querySelector(":scope > .sidebar-menu-sub")
|
|
337
|
-
) {
|
|
372
|
+
if (!collapsed || this._isIdentityTrigger(control) || control.closest(".sidebar-menu-item")?.querySelector(":scope > .sidebar-menu-sub")) {
|
|
338
373
|
return;
|
|
339
374
|
}
|
|
340
|
-
|
|
341
|
-
// Bootstrap permits one plugin instance per element. A dropdown or
|
|
342
|
-
// collapse trigger keeps that instance slot; its neutral <li> owns the
|
|
343
|
-
// state-driven Sidebar tooltip instead.
|
|
344
375
|
const anchor = this._tooltipAnchor(control);
|
|
345
376
|
new Tooltip(anchor, {
|
|
346
|
-
title: control.getAttribute("data-
|
|
377
|
+
title: control.getAttribute("data-sidebar-tooltip"),
|
|
347
378
|
placement,
|
|
348
|
-
|
|
349
|
-
|
|
379
|
+
// Bootstrap's default tooltip offset is 6px. The icon rail's
|
|
380
|
+
// boundary calculation still lets the tooltip box overlap the
|
|
381
|
+
// physical Sidebar edge at that distance, so keep an explicit 8px
|
|
382
|
+
// separation for both physical placements.
|
|
383
|
+
offset: [0, 8],
|
|
384
|
+
container: this._portalRoot(control),
|
|
385
|
+
trigger: "hover focus"
|
|
350
386
|
});
|
|
351
387
|
this._tooltipAnchors.add(anchor);
|
|
352
388
|
});
|
|
353
389
|
}
|
|
354
|
-
|
|
355
390
|
_bindEvents() {
|
|
356
391
|
this._listen(this._sidebar, "shown.bs.offcanvas", () => this._syncControls());
|
|
357
392
|
this._listen(this._sidebar, "hidden.bs.offcanvas", () => {
|
|
@@ -385,31 +420,25 @@ export default class Sidebar {
|
|
|
385
420
|
this._listen(this._document, "keydown", (event) => this._handleShortcut(event));
|
|
386
421
|
this._listen(this._window, "resize", () => {
|
|
387
422
|
this._closeFlyouts();
|
|
388
|
-
this._element
|
|
389
|
-
.querySelectorAll("[data-moo-sidebar-dropdown-positioned]")
|
|
390
|
-
.forEach((item) => this._clearDropdownPosition(item));
|
|
423
|
+
this._element.querySelectorAll("[data-sidebar-dropdown-positioned]").forEach((item) => this._clearDropdownPosition(item));
|
|
391
424
|
this._syncControls();
|
|
392
425
|
this._syncTooltips();
|
|
393
426
|
});
|
|
394
427
|
}
|
|
395
|
-
|
|
396
428
|
_dropdownControl(target) {
|
|
397
429
|
if (!(target instanceof this._window.Element) || !this._element.contains(target)) {
|
|
398
430
|
return null;
|
|
399
431
|
}
|
|
400
|
-
if (target.matches('[data-bs-toggle="dropdown"][data-
|
|
432
|
+
if (target.matches('[data-bs-toggle="dropdown"][data-sidebar-tooltip]')) {
|
|
401
433
|
return target;
|
|
402
434
|
}
|
|
403
435
|
return target.querySelector?.(
|
|
404
|
-
'[data-bs-toggle="dropdown"][data-
|
|
436
|
+
'[data-bs-toggle="dropdown"][data-sidebar-tooltip]'
|
|
405
437
|
) || null;
|
|
406
438
|
}
|
|
407
|
-
|
|
408
439
|
_handleControlClick(event) {
|
|
409
440
|
const target = event.target;
|
|
410
|
-
const control = target instanceof this._window.Element
|
|
411
|
-
? target.closest("[data-moo-sidebar-trigger], [data-moo-sidebar-rail]")
|
|
412
|
-
: null;
|
|
441
|
+
const control = target instanceof this._window.Element ? target.closest("[data-sidebar-trigger], [data-sidebar-rail]") : null;
|
|
413
442
|
if (!control || !this._element.contains(control)) {
|
|
414
443
|
return;
|
|
415
444
|
}
|
|
@@ -419,7 +448,7 @@ export default class Sidebar {
|
|
|
419
448
|
this._toggle();
|
|
420
449
|
return;
|
|
421
450
|
}
|
|
422
|
-
if (!control.matches("[data-
|
|
451
|
+
if (!control.matches("[data-sidebar-trigger]")) {
|
|
423
452
|
return;
|
|
424
453
|
}
|
|
425
454
|
const sidebar = this._document.getElementById(control.getAttribute("aria-controls"));
|
|
@@ -430,12 +459,9 @@ export default class Sidebar {
|
|
|
430
459
|
this._offcanvas.toggle();
|
|
431
460
|
}
|
|
432
461
|
}
|
|
433
|
-
|
|
434
462
|
_handleSubmenuClick(event) {
|
|
435
463
|
const target = event.target;
|
|
436
|
-
const trigger = target instanceof this._window.Element
|
|
437
|
-
? target.closest(".sidebar-menu-sub-trigger")
|
|
438
|
-
: null;
|
|
464
|
+
const trigger = target instanceof this._window.Element ? target.closest(".sidebar-menu-sub-trigger") : null;
|
|
439
465
|
const item = trigger?.closest(".sidebar-menu-item");
|
|
440
466
|
if (!trigger || !item || !this._element.contains(item) || !this._isCollapsed()) {
|
|
441
467
|
return;
|
|
@@ -448,7 +474,6 @@ export default class Sidebar {
|
|
|
448
474
|
this._openFlyout(item);
|
|
449
475
|
}
|
|
450
476
|
}
|
|
451
|
-
|
|
452
477
|
_handleOutsideFlyoutClick(event) {
|
|
453
478
|
if (!this._flyout) {
|
|
454
479
|
return;
|
|
@@ -459,27 +484,15 @@ export default class Sidebar {
|
|
|
459
484
|
this._closeFlyouts();
|
|
460
485
|
}
|
|
461
486
|
}
|
|
462
|
-
|
|
463
487
|
_handleShortcut(event) {
|
|
464
488
|
const target = event.target;
|
|
465
|
-
const isEditable =
|
|
466
|
-
|
|
467
|
-
(target.matches("input, textarea, select") || target.isContentEditable);
|
|
468
|
-
if (
|
|
469
|
-
event.defaultPrevented ||
|
|
470
|
-
event.isComposing ||
|
|
471
|
-
isEditable ||
|
|
472
|
-
!this._config.keyboard ||
|
|
473
|
-
!(event.metaKey || event.ctrlKey) ||
|
|
474
|
-
event.key.toLowerCase() !== "b" ||
|
|
475
|
-
!this._isDesktop()
|
|
476
|
-
) {
|
|
489
|
+
const isEditable = target instanceof this._window.Element && (target.matches("input, textarea, select") || target.isContentEditable);
|
|
490
|
+
if (event.defaultPrevented || event.isComposing || isEditable || !this._config.keyboard || !(event.metaKey || event.ctrlKey) || event.key.toLowerCase() !== "b" || !this._isDesktop()) {
|
|
477
491
|
return;
|
|
478
492
|
}
|
|
479
|
-
const preferred =
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
) || this._document.querySelector('[data-slot="sidebar-wrapper"]');
|
|
493
|
+
const preferred = this._document.querySelector(
|
|
494
|
+
'[data-slot="sidebar-wrapper"][data-sidebar-key]'
|
|
495
|
+
) || this._document.querySelector('[data-slot="sidebar-wrapper"]');
|
|
483
496
|
if (preferred !== this._element) {
|
|
484
497
|
return;
|
|
485
498
|
}
|
|
@@ -487,4 +500,9 @@ export default class Sidebar {
|
|
|
487
500
|
this._closeFlyouts();
|
|
488
501
|
this._toggle();
|
|
489
502
|
}
|
|
490
|
-
}
|
|
503
|
+
};
|
|
504
|
+
__name(_Sidebar, "Sidebar");
|
|
505
|
+
var Sidebar = _Sidebar;
|
|
506
|
+
export {
|
|
507
|
+
Sidebar as default
|
|
508
|
+
};
|