@wpmoo/ui 1.0.0-rc.7 → 1.0.0-rc.9
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/README.md +37 -6
- package/certification.json +6 -2
- package/dist/assets/css/moo-ui.css +764 -452
- package/dist/assets/css/moo-ui.min.css +5 -5
- package/dist/assets/css/moo.css +762 -450
- package/dist/assets/css/moo.min.css +5 -5
- package/dist/js/chart.js +1 -1
- package/dist/js/chart.min.js +1 -1
- package/dist/js/combobox.js +1 -1
- package/dist/js/context-menu.js +1 -1
- package/dist/js/datatable.js +2 -2
- package/dist/js/datepicker.js +2 -2
- package/dist/js/datepicker.min.js +2 -2
- package/dist/js/moo-ui.js +4 -4
- package/dist/js/moo-ui.min.js +2 -2
- package/dist/js/sidebar.js +4 -4
- package/dist/js/slider.js +1 -1
- package/dist/js/state.js +102 -0
- package/dist/release-manifest.json +24 -0
- package/package.json +5 -1
- package/scss/_components.scss +1 -4
- package/scss/components/_dropdown.scss +10 -0
- package/scss/components/_field.scss +8 -0
- package/scss/components/_search_trigger.scss +62 -0
- package/scss/components/_sidebar.scss +1 -2
- package/scss/components/sidebar/_base.scss +93 -0
- package/scss/components/sidebar/_collapsed.scss +3 -81
- package/scss/foundations/_scope.scss +8 -0
- package/scss/layouts/_app.scss +81 -0
- package/scss/layouts/_page_grid.scss +30 -0
- package/scss/layouts/app/sidebar/_base.scss +117 -0
- package/scss/layouts/app/sidebar/_default.scss +26 -0
- package/scss/layouts/app/sidebar/_floating.scss +47 -0
- package/scss/{components → layouts/app}/sidebar/_inset.scss +8 -3
- package/scss/settings/_component_variables.scss +14 -0
- package/scss/settings/_forms.scss +1 -1
- package/scss/themes/_root.scss +1 -0
- package/scss/themes/_standalone.scss +3 -3
- package/scss/themes/_theme.scss +3 -0
- package/scss/components/sidebar/_layout.scss +0 -251
package/dist/js/sidebar.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Moo UI sidebar.js v1.0.0-rc.
|
|
2
|
+
* Moo UI sidebar.js v1.0.0-rc.9 (https://ui.wpmoo.org/)
|
|
3
3
|
* Copyright 2026 WPMoo (https://wpmoo.org)
|
|
4
4
|
* Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
|
|
5
5
|
*/
|
|
@@ -8,7 +8,7 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
|
|
|
8
8
|
|
|
9
9
|
// src/js/theme-owner.js
|
|
10
10
|
var OWNER_SELECTOR = '.moo-ui[data-bs-theme="light"], .moo-ui[data-bs-theme="dark"]';
|
|
11
|
-
var PORTAL_SELECTOR = "[data-moo-overlay-
|
|
11
|
+
var PORTAL_SELECTOR = "[data-moo-overlay-host]";
|
|
12
12
|
function documentFor(node) {
|
|
13
13
|
if (node?.nodeType === 9) return node;
|
|
14
14
|
if (node?.ownerDocument) return node.ownerDocument;
|
|
@@ -115,7 +115,7 @@ var _Sidebar = class _Sidebar {
|
|
|
115
115
|
return this._window.matchMedia(this._config.breakpoint).matches;
|
|
116
116
|
}
|
|
117
117
|
_isCollapsed() {
|
|
118
|
-
return this._isDesktop() && this._element.dataset.sidebarState === "collapsed";
|
|
118
|
+
return this._isDesktop() && this._sidebar?.dataset?.collapsible === "icon" && this._element.dataset.sidebarState === "collapsed";
|
|
119
119
|
}
|
|
120
120
|
_trigger(name, detail = {}) {
|
|
121
121
|
return this._element.dispatchEvent(
|
|
@@ -249,7 +249,7 @@ var _Sidebar = class _Sidebar {
|
|
|
249
249
|
_positionDropdown(control) {
|
|
250
250
|
const item = control?.closest?.(".sidebar-menu-item");
|
|
251
251
|
const isHeaderWorkspace = control?.classList.contains("sidebar-menu-button--workspace") && control.closest('[data-slot="sidebar-header"]');
|
|
252
|
-
const isFooterAccount = control?.
|
|
252
|
+
const isFooterAccount = control?.closest(".sidebar-menu-item--account") && control.closest('[data-slot="sidebar-footer"]');
|
|
253
253
|
if (!control || !item || !(isHeaderWorkspace || isFooterAccount) || !this._isDesktop()) {
|
|
254
254
|
this._clearDropdownPosition(control);
|
|
255
255
|
return;
|
package/dist/js/slider.js
CHANGED
package/dist/js/state.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Moo UI state bootstrap
|
|
3
|
+
* Copyright 2026 WPMoo (https://wpmoo.org)
|
|
4
|
+
* Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
|
|
5
|
+
*/
|
|
6
|
+
(() => {
|
|
7
|
+
const ownerDocument = typeof document === "undefined" ? null : document;
|
|
8
|
+
const owner = ownerDocument?.currentScript?.parentElement;
|
|
9
|
+
if (!owner) return;
|
|
10
|
+
|
|
11
|
+
const view =
|
|
12
|
+
ownerDocument?.defaultView ||
|
|
13
|
+
(typeof window === "undefined" ? null : window);
|
|
14
|
+
|
|
15
|
+
if (owner.matches?.('.moo-ui[data-bs-theme="light"], .moo-ui[data-bs-theme="dark"]')) {
|
|
16
|
+
const body = ownerDocument?.body;
|
|
17
|
+
const documentOwner =
|
|
18
|
+
owner.dataset?.mooDocumentOwner === "true" &&
|
|
19
|
+
owner.parentElement === body &&
|
|
20
|
+
owner === body?.firstElementChild;
|
|
21
|
+
const normalizeDirection = (value) =>
|
|
22
|
+
value === "ltr" || value === "rtl" ? value : null;
|
|
23
|
+
const ownerDirection = normalizeDirection(
|
|
24
|
+
owner.getAttribute?.("dir") || owner.dir,
|
|
25
|
+
);
|
|
26
|
+
const documentDirection = normalizeDirection(
|
|
27
|
+
ownerDocument?.documentElement?.getAttribute?.("dir") ||
|
|
28
|
+
ownerDocument?.documentElement?.dir,
|
|
29
|
+
);
|
|
30
|
+
owner.__mooStateBaseline = {
|
|
31
|
+
theme: owner.dataset.bsTheme === "dark" ? "dark" : "light",
|
|
32
|
+
direction: documentOwner ? documentDirection || "ltr" : ownerDirection,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const readPreference = (axis, allowed) => {
|
|
36
|
+
const dataKey = axis === "theme" ? "mooThemeKey" : "mooDirectionKey";
|
|
37
|
+
const explicit = owner.dataset?.[dataKey]?.trim();
|
|
38
|
+
const key = explicit || (documentOwner ? `moo:${axis}` : null);
|
|
39
|
+
if (!key) return null;
|
|
40
|
+
try {
|
|
41
|
+
const value = view?.localStorage?.getItem(key);
|
|
42
|
+
return allowed.includes(value) ? value : null;
|
|
43
|
+
} catch (_) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const systemPrefersDark = () => {
|
|
49
|
+
try {
|
|
50
|
+
const matchMedia = view?.matchMedia;
|
|
51
|
+
if (typeof matchMedia !== "function") return null;
|
|
52
|
+
return Boolean(
|
|
53
|
+
matchMedia.call(view, "(prefers-color-scheme: dark)")?.matches,
|
|
54
|
+
);
|
|
55
|
+
} catch (_) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const storedTheme = readPreference("theme", ["light", "dark", "system"]);
|
|
62
|
+
const mediaPrefersDark =
|
|
63
|
+
storedTheme === "system" ? systemPrefersDark() : null;
|
|
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";
|
|
76
|
+
owner.dataset.bsTheme = resolvedTheme;
|
|
77
|
+
|
|
78
|
+
const storedDirection = readPreference("direction", ["ltr", "rtl"]);
|
|
79
|
+
if (storedDirection) {
|
|
80
|
+
if (documentOwner) ownerDocument.documentElement.dir = storedDirection;
|
|
81
|
+
else owner.dir = storedDirection;
|
|
82
|
+
}
|
|
83
|
+
} finally {
|
|
84
|
+
owner.dataset.mooState = "ready";
|
|
85
|
+
}
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!owner.matches?.('[data-slot="sidebar-wrapper"][data-sidebar-key]')) return;
|
|
90
|
+
const key = owner.dataset?.sidebarKey;
|
|
91
|
+
if (!key) return;
|
|
92
|
+
try {
|
|
93
|
+
const state = view?.localStorage?.getItem(`moo-sidebar:${key}`);
|
|
94
|
+
if (state === "expanded" || state === "collapsed") {
|
|
95
|
+
owner.dataset.sidebarState = state;
|
|
96
|
+
}
|
|
97
|
+
} catch (_) {
|
|
98
|
+
// Restricted browsing contexts may deny localStorage.
|
|
99
|
+
} finally {
|
|
100
|
+
owner.dataset.sidebarStateReady = "";
|
|
101
|
+
}
|
|
102
|
+
})();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"artifacts": [
|
|
3
|
+
{
|
|
4
|
+
"export": "./moo.css",
|
|
5
|
+
"path": "dist/assets/css/moo.css",
|
|
6
|
+
"sha256": "9f5228c6387b728efe2f341aea9ff09c193f621e778ac413fee9f1cd84992791"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"export": "./moo-ui.css",
|
|
10
|
+
"path": "dist/assets/css/moo-ui.css",
|
|
11
|
+
"sha256": "ca54a5ff1e8a1fa2ac704e3b55e63aa4517353aede35c0bf509c485e6d04a2c6"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"export": "./state.js",
|
|
15
|
+
"path": "dist/js/state.js",
|
|
16
|
+
"sha256": "094cc7bdce8934b846d77476727fd7627062538612f7fcfa8fbd873e44c5e264"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"package": {
|
|
20
|
+
"name": "@wpmoo/ui",
|
|
21
|
+
"version": "1.0.0-rc.9"
|
|
22
|
+
},
|
|
23
|
+
"schemaVersion": 1
|
|
24
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wpmoo/ui",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.9",
|
|
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)",
|
|
@@ -42,6 +42,8 @@
|
|
|
42
42
|
"./chart.min.js": "./dist/js/chart.min.js",
|
|
43
43
|
"./datepicker.js": "./dist/js/datepicker.js",
|
|
44
44
|
"./datepicker.min.js": "./dist/js/datepicker.min.js",
|
|
45
|
+
"./state.js": "./dist/js/state.js",
|
|
46
|
+
"./release-manifest.json": "./dist/release-manifest.json",
|
|
45
47
|
"./scss/config": "./scss/_config.scss",
|
|
46
48
|
"./scss/moo-ui": "./scss/moo-ui.scss",
|
|
47
49
|
"./scss/moo-core": "./scss/moo-core.scss",
|
|
@@ -66,6 +68,8 @@
|
|
|
66
68
|
"dist/js/chart.min.js",
|
|
67
69
|
"dist/js/datepicker.js",
|
|
68
70
|
"dist/js/datepicker.min.js",
|
|
71
|
+
"dist/js/state.js",
|
|
72
|
+
"dist/release-manifest.json",
|
|
69
73
|
"scss/*.scss",
|
|
70
74
|
"scss/**/*.scss",
|
|
71
75
|
"certification.json",
|
package/scss/_components.scss
CHANGED
|
@@ -25,10 +25,6 @@
|
|
|
25
25
|
@import "bootstrap/scss/offcanvas";
|
|
26
26
|
@import "bootstrap/scss/helpers/color-bg";
|
|
27
27
|
|
|
28
|
-
// Moo component support
|
|
29
|
-
@import "foundations/focus";
|
|
30
|
-
@import "utilities/scroll_fade";
|
|
31
|
-
|
|
32
28
|
// Moo components
|
|
33
29
|
@import "components/kbd";
|
|
34
30
|
@import "components/input";
|
|
@@ -36,6 +32,7 @@
|
|
|
36
32
|
@import "components/select";
|
|
37
33
|
@import "components/input_group";
|
|
38
34
|
@import "components/button";
|
|
35
|
+
@import "components/search_trigger";
|
|
39
36
|
@import "components/close_button";
|
|
40
37
|
@import "components/button_group";
|
|
41
38
|
@import "components/toggle_group";
|
|
@@ -167,6 +167,16 @@
|
|
|
167
167
|
min-width: #{unquote("max(100%, var(--moo-dropdown-sidebar-min-width))")};
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
// Header identity menus reuse the Sidebar account-menu body. Keep the same
|
|
171
|
+
// comfortable width when the shared body is hosted by the global navbar
|
|
172
|
+
// instead of a Sidebar slot; ordinary Header dropdowns remain content-sized.
|
|
173
|
+
// The trigger marker is the integration contract, so Dropdown does not reach
|
|
174
|
+
// into Sidebar's private class namespace to identify the menu body.
|
|
175
|
+
[data-identity-trigger="1"] + .dropdown-menu {
|
|
176
|
+
--moo-dropdown-sidebar-min-width: #{$moo-dropdown-sidebar-min-width};
|
|
177
|
+
min-width: var(--moo-dropdown-sidebar-min-width);
|
|
178
|
+
}
|
|
179
|
+
|
|
170
180
|
@include media-breakpoint-down(sm) {
|
|
171
181
|
[data-slot="sidebar-header"] .dropend > .dropdown-menu,
|
|
172
182
|
[data-slot="sidebar-footer"] .dropend > .dropdown-menu {
|
|
@@ -74,6 +74,14 @@
|
|
|
74
74
|
> hr {
|
|
75
75
|
margin-block: 0;
|
|
76
76
|
}
|
|
77
|
+
|
|
78
|
+
// A public Bootstrap .row is an explicit layout request from the consumer.
|
|
79
|
+
// Preserve its responsive columns and let Bootstrap's gutters own spacing
|
|
80
|
+
// instead of turning the row back into a vertical, gap-managed field stack.
|
|
81
|
+
&.row {
|
|
82
|
+
flex-direction: row;
|
|
83
|
+
gap: 0;
|
|
84
|
+
}
|
|
77
85
|
}
|
|
78
86
|
|
|
79
87
|
.field-form {
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Shared command/search trigger composition. The host supplies the semantic
|
|
2
|
+
// button markup and behavior; Core owns only the reusable visual contract.
|
|
3
|
+
.search-trigger {
|
|
4
|
+
width: $moo-search-trigger-width;
|
|
5
|
+
max-width: 100%;
|
|
6
|
+
flex: 0 1 $moo-search-trigger-width;
|
|
7
|
+
min-width: 0;
|
|
8
|
+
justify-content: space-between;
|
|
9
|
+
height: $moo-search-trigger-height;
|
|
10
|
+
padding: $moo-search-trigger-padding-y $moo-search-trigger-padding-x;
|
|
11
|
+
color: var(--bs-secondary-color);
|
|
12
|
+
border: var(--bs-border-width) solid $moo-search-trigger-border-color;
|
|
13
|
+
border-radius: var(--bs-border-radius);
|
|
14
|
+
background: color-mix(in srgb, var(--bs-secondary-bg) 55%, var(--bs-body-bg));
|
|
15
|
+
font-size: $font-size-base;
|
|
16
|
+
font-weight: $font-weight-normal;
|
|
17
|
+
box-shadow: none;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.search-trigger:hover {
|
|
21
|
+
color: var(--bs-secondary-color);
|
|
22
|
+
border-color: $moo-search-trigger-border-color;
|
|
23
|
+
background: color-mix(in srgb, var(--bs-secondary-bg) 78%, var(--bs-body-bg));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.search-trigger:focus-visible {
|
|
27
|
+
color: var(--bs-secondary-color);
|
|
28
|
+
border-color: $moo-search-trigger-border-color;
|
|
29
|
+
background: color-mix(in srgb, var(--bs-secondary-bg) 78%, var(--bs-body-bg));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.search-trigger__label {
|
|
33
|
+
display: inline-flex;
|
|
34
|
+
min-width: 0;
|
|
35
|
+
align-items: center;
|
|
36
|
+
gap: $moo-search-trigger-label-gap;
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
text-overflow: ellipsis;
|
|
39
|
+
white-space: nowrap;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.search-trigger__shortcut {
|
|
43
|
+
display: inline-flex;
|
|
44
|
+
flex: 0 0 auto;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: $moo-search-trigger-shortcut-gap;
|
|
47
|
+
margin-inline-start: auto;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@include media-breakpoint-up(lg) {
|
|
51
|
+
.search-trigger {
|
|
52
|
+
width: $moo-search-trigger-width-lg;
|
|
53
|
+
flex-basis: $moo-search-trigger-width-lg;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@include media-breakpoint-up(xxl) {
|
|
58
|
+
.search-trigger {
|
|
59
|
+
width: $moo-search-trigger-width-xxl;
|
|
60
|
+
flex-basis: $moo-search-trigger-width-xxl;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Bootstrap has no native sidebar, so this owned selector namespace is split
|
|
2
2
|
// by responsibility while preserving one deterministic emission order.
|
|
3
|
-
@import "sidebar/
|
|
3
|
+
@import "sidebar/base";
|
|
4
4
|
@import "sidebar/menus";
|
|
5
5
|
@import "sidebar/identity";
|
|
6
|
-
@import "sidebar/inset";
|
|
7
6
|
@import "sidebar/collapsed";
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// Bootstrap has no native sidebar, so this owned sidebar selector namespace
|
|
2
|
+
// provides the inner surface and anatomy. The App layout owns the outer
|
|
3
|
+
// <aside>, placement, width, visual variant, and collapse mode.
|
|
4
|
+
|
|
5
|
+
.sidebar-inner {
|
|
6
|
+
position: sticky;
|
|
7
|
+
top: 0;
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
width: 100%;
|
|
11
|
+
height: 100svh;
|
|
12
|
+
max-height: 100svh;
|
|
13
|
+
background: var(--moo-sidebar);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.sidebar-header,
|
|
17
|
+
.sidebar-footer {
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
gap: $spacer * 0.25;
|
|
21
|
+
padding: $spacer * 0.5;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.sidebar-content {
|
|
25
|
+
display: flex;
|
|
26
|
+
flex: 1 1 auto;
|
|
27
|
+
flex-direction: column;
|
|
28
|
+
gap: $spacer * 0.5;
|
|
29
|
+
min-height: 0;
|
|
30
|
+
overflow-y: auto;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.sidebar-input {
|
|
34
|
+
width: 100%;
|
|
35
|
+
padding: $spacer * 0.25;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.sidebar-separator {
|
|
39
|
+
display: flex;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.sidebar-menu-skeleton {
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
gap: $spacer * 0.25;
|
|
46
|
+
min-height: $spacer * 2;
|
|
47
|
+
padding-inline: $spacer * 0.5;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.sidebar-menu-skeleton__icon {
|
|
51
|
+
width: $spacer;
|
|
52
|
+
height: $spacer;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.sidebar-menu-skeleton__line {
|
|
56
|
+
flex: 1 1 auto;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.sidebar-group {
|
|
60
|
+
position: relative;
|
|
61
|
+
display: flex;
|
|
62
|
+
flex-direction: column;
|
|
63
|
+
padding: $spacer * 0.5;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.sidebar-group-content {
|
|
67
|
+
display: block;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.sidebar-group-content--inline {
|
|
71
|
+
display: flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
flex-wrap: wrap;
|
|
74
|
+
gap: $spacer * 0.25;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.sidebar-group-label {
|
|
78
|
+
display: flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
height: $spacer * 2;
|
|
81
|
+
padding-inline: $spacer * 0.5;
|
|
82
|
+
color: var(--moo-muted-foreground);
|
|
83
|
+
font-size: $font-size-base * 0.857;
|
|
84
|
+
font-weight: $font-weight-medium;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Reserve room so a long label doesn't run under the absolutely positioned
|
|
88
|
+
// group action button (see .sidebar-group-action below). A descendant match
|
|
89
|
+
// covers both a group action placed directly in .sidebar-group and one
|
|
90
|
+
// nested inside .sidebar-group-content alongside the label.
|
|
91
|
+
.sidebar-group:has(.sidebar-group-action) .sidebar-group-label {
|
|
92
|
+
padding-inline-end: $spacer * 2.5;
|
|
93
|
+
}
|
|
@@ -1,65 +1,8 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
inset-block: 0;
|
|
5
|
-
inset-inline-end: 0;
|
|
6
|
-
z-index: 20;
|
|
7
|
-
width: $spacer;
|
|
8
|
-
padding: 0;
|
|
9
|
-
transform: translateX(50%);
|
|
10
|
-
border: 0;
|
|
11
|
-
background: transparent;
|
|
12
|
-
cursor: pointer;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Read the Sidebar's computed direction so this remains valid inside the
|
|
16
|
-
// resolved-owner @scope as well as under a full-document html[dir] owner.
|
|
17
|
-
.sidebar:dir(rtl) .sidebar-rail {
|
|
18
|
-
transform: translateX(-50%);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.sidebar-rail::after {
|
|
22
|
-
content: "";
|
|
23
|
-
position: absolute;
|
|
24
|
-
inset-block: 0;
|
|
25
|
-
inset-inline-start: 50%;
|
|
26
|
-
width: var(--bs-border-width);
|
|
27
|
-
background: transparent;
|
|
28
|
-
transition: background 0.15s ease;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.sidebar-rail:hover::after {
|
|
32
|
-
background: var(--moo-sidebar-border);
|
|
33
|
-
}
|
|
1
|
+
// Collapsed-to-icon inner state (desktop). App owns the outer shell width,
|
|
2
|
+
// rail, stacking, and responsive placement; Sidebar owns the inner content
|
|
3
|
+
// visibility and flyout anatomy.
|
|
34
4
|
|
|
35
|
-
// Collapsed-to-icon rail (desktop). Text, labels, and the rail's disclosure
|
|
36
|
-
// chevrons hide; every remaining control centers on its icon.
|
|
37
5
|
@include media-breakpoint-up(lg) {
|
|
38
|
-
.sidebar {
|
|
39
|
-
position: relative;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
.wrapper[data-layout="app"]:has([data-sidebar-dropdown-positioned] > .dropdown-menu.show) > .sidebar {
|
|
43
|
-
position: relative;
|
|
44
|
-
// Catalog page headers are sticky at $zindex-fixed. The Sidebar root must
|
|
45
|
-
// sit above that page-level stacking context while an identity menu is
|
|
46
|
-
// open, otherwise the workspace menu is painted underneath the header
|
|
47
|
-
// even though the menu itself is fixed and has dropdown z-index.
|
|
48
|
-
z-index: $zindex-fixed + 1;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// The sticky inner surface is its own stacking context. Elevate that
|
|
52
|
-
// context while an identity menu is open so the rail's hover indicator
|
|
53
|
-
// remains behind the fixed dropdown instead of painting across it.
|
|
54
|
-
.wrapper[data-layout="app"]:has([data-sidebar-dropdown-positioned] > .dropdown-menu.show) > .sidebar > .sidebar-inner {
|
|
55
|
-
z-index: $zindex-fixed + 1;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.wrapper[data-layout="app"][data-sidebar-state="collapsed"] .sidebar[data-collapsible="icon"] {
|
|
59
|
-
flex-basis: var(--moo-sidebar-width-icon);
|
|
60
|
-
width: var(--moo-sidebar-width-icon);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
6
|
[data-sidebar-state="collapsed"] .sidebar[data-collapsible="icon"] .sidebar-group-label,
|
|
64
7
|
[data-sidebar-state="collapsed"] .sidebar[data-collapsible="icon"] .sidebar-menu-button__text,
|
|
65
8
|
[data-sidebar-state="collapsed"] .sidebar[data-collapsible="icon"] .sidebar-menu-button__subtitle,
|
|
@@ -173,24 +116,3 @@
|
|
|
173
116
|
display: none;
|
|
174
117
|
}
|
|
175
118
|
}
|
|
176
|
-
|
|
177
|
-
@include media-breakpoint-down(lg) {
|
|
178
|
-
.sidebar-rail {
|
|
179
|
-
display: none;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
.wrapper[data-layout="app"][data-shell-mode="contained"] .sidebar {
|
|
183
|
-
position: relative;
|
|
184
|
-
inset: auto;
|
|
185
|
-
flex: 0 0 auto;
|
|
186
|
-
width: 100%;
|
|
187
|
-
height: auto;
|
|
188
|
-
visibility: visible;
|
|
189
|
-
transform: none;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
.wrapper[data-layout="app"][data-shell-mode="contained"] .sidebar-inner {
|
|
193
|
-
height: auto;
|
|
194
|
-
max-height: none;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
@scope (.moo-ui) to (:where(.moo-ui[data-bs-theme="light"], .moo-ui[data-bs-theme="dark"])) {
|
|
2
2
|
@import "../components";
|
|
3
|
+
@import "../foundations/focus";
|
|
4
|
+
@import "../utilities/scroll_fade";
|
|
5
|
+
@import "../layouts/app";
|
|
6
|
+
@import "../layouts/page_grid";
|
|
3
7
|
@import "../themes/forms";
|
|
4
8
|
@include moo-overlay-backdrop-scoped;
|
|
9
|
+
:where(h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6,
|
|
10
|
+
.display-1, .display-2, .display-3, .display-4, .display-5, .display-6) {
|
|
11
|
+
font-family: var(--moo-heading-font-family, var(--bs-body-font-family));
|
|
12
|
+
}
|
|
5
13
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Application layout owns the shell and page geometry.
|
|
2
|
+
// It is intentionally separate from component surfaces such as Sidebar.
|
|
3
|
+
|
|
4
|
+
@import "app/sidebar/base";
|
|
5
|
+
@import "app/sidebar/default";
|
|
6
|
+
@import "app/sidebar/floating";
|
|
7
|
+
@import "app/sidebar/inset";
|
|
8
|
+
|
|
9
|
+
.wrapper[data-layout="app"] {
|
|
10
|
+
display: flex;
|
|
11
|
+
width: 100%;
|
|
12
|
+
height: 100svh;
|
|
13
|
+
min-height: 0;
|
|
14
|
+
overflow: hidden;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.wrapper[data-layout="app"][data-shell-mode="contained"] {
|
|
18
|
+
min-height: 0;
|
|
19
|
+
height: 34rem;
|
|
20
|
+
overflow: hidden;
|
|
21
|
+
border: var(--bs-border-width) solid var(--moo-border);
|
|
22
|
+
border-radius: var(--bs-border-radius-xl);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.wrapper[data-layout="app"] > [data-slot="page"] {
|
|
26
|
+
display: flex;
|
|
27
|
+
min-width: 0;
|
|
28
|
+
min-height: 0;
|
|
29
|
+
flex: 1 1 auto;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.wrapper[data-layout="app"] > [data-slot="page"] > header,
|
|
34
|
+
.wrapper[data-layout="app"] > [data-slot="page"] > main,
|
|
35
|
+
.wrapper[data-layout="app"] > [data-slot="page"] > footer {
|
|
36
|
+
flex: 0 0 auto;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// The page main region owns the space between the optional header and footer.
|
|
40
|
+
// Keep the Bootstrap rail as the flex column too, so app previews and real
|
|
41
|
+
// shells can give their caller content a full-height surface without adding
|
|
42
|
+
// layout-specific height values.
|
|
43
|
+
.wrapper[data-layout="app"] > [data-slot="page"] > main {
|
|
44
|
+
display: flex;
|
|
45
|
+
min-height: 0;
|
|
46
|
+
flex: 1 1 auto;
|
|
47
|
+
flex-direction: column;
|
|
48
|
+
overflow-y: auto;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.wrapper[data-layout="app"] > [data-slot="page"] > main > :is(
|
|
52
|
+
.container,
|
|
53
|
+
.container-sm,
|
|
54
|
+
.container-md,
|
|
55
|
+
.container-lg,
|
|
56
|
+
.container-xl,
|
|
57
|
+
.container-xxl,
|
|
58
|
+
.container-fluid
|
|
59
|
+
) {
|
|
60
|
+
display: flex;
|
|
61
|
+
min-height: 0;
|
|
62
|
+
flex: 1 1 auto;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@include media-breakpoint-down(lg) {
|
|
67
|
+
.wrapper[data-layout="app"][data-shell-mode="contained"] {
|
|
68
|
+
flex-direction: column;
|
|
69
|
+
height: auto;
|
|
70
|
+
min-height: 0;
|
|
71
|
+
overflow: visible;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.wrapper[data-layout="app"][data-shell-mode="contained"] > [data-slot="page"] {
|
|
75
|
+
overflow: visible;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.wrapper[data-layout="app"][data-shell-mode="contained"] > [data-slot="page"] > main {
|
|
79
|
+
overflow: visible;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Opt-in Bootstrap row geometry keyed to the usable Moo Page rail, not the
|
|
2
|
+
// viewport or the optional Sidebar state. The rail itself is the query owner.
|
|
3
|
+
[data-page-container] {
|
|
4
|
+
container: moo-page / inline-size;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// Keep the compact branch usable in browsers without container queries.
|
|
8
|
+
[data-page-container] [data-page-show-from] {
|
|
9
|
+
display: none !important;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@each $breakpoint, $min-width in $grid-breakpoints {
|
|
13
|
+
@if $breakpoint != xs {
|
|
14
|
+
@container moo-page (min-width: #{$min-width}) {
|
|
15
|
+
@for $span from 1 through $grid-columns {
|
|
16
|
+
[data-page-container] .row[data-layout="page-grid"] > [data-page-col-#{$breakpoint}="#{$span}"] {
|
|
17
|
+
width: percentage(divide($span, $grid-columns));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
[data-page-container] [data-page-show-from="#{$breakpoint}"] {
|
|
22
|
+
display: block !important;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
[data-page-container] [data-page-hide-from="#{$breakpoint}"] {
|
|
26
|
+
display: none !important;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|