@wpmoo/ui 1.0.0-rc.6 → 1.0.0-rc.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/ASSET_LICENSE.md +1 -1
  2. package/README.md +37 -6
  3. package/certification.json +6 -2
  4. package/dist/assets/css/moo-ui.css +7799 -8113
  5. package/dist/assets/css/moo-ui.min.css +5 -5
  6. package/dist/assets/css/moo.css +707 -685
  7. package/dist/assets/css/moo.min.css +5 -5
  8. package/dist/js/chart.js +57 -5
  9. package/dist/js/chart.min.js +3 -3
  10. package/dist/js/combobox.js +1 -1
  11. package/dist/js/context-menu.js +1 -1
  12. package/dist/js/datatable.js +114 -213
  13. package/dist/js/datepicker.js +79 -37
  14. package/dist/js/datepicker.min.js +2 -2
  15. package/dist/js/moo-ui.js +169 -52
  16. package/dist/js/moo-ui.min.js +3 -3
  17. package/dist/js/sidebar.js +122 -175
  18. package/dist/js/slider.js +1 -1
  19. package/dist/js/theme-prepaint.js +91 -0
  20. package/dist/release-manifest.json +24 -0
  21. package/package.json +12 -8
  22. package/scss/_components.scss +1 -4
  23. package/scss/components/_alert.scss +1 -2
  24. package/scss/components/_card.scss +5 -5
  25. package/scss/components/_close_button.scss +8 -3
  26. package/scss/components/_dialog.scss +16 -0
  27. package/scss/components/_dropdown.scss +12 -7
  28. package/scss/components/_search_trigger.scss +62 -0
  29. package/scss/components/_sidebar.scss +1 -2
  30. package/scss/components/_switch.scss +13 -5
  31. package/scss/components/_tabs.scss +1 -1
  32. package/scss/components/sidebar/_base.scss +93 -0
  33. package/scss/components/sidebar/_collapsed.scss +9 -90
  34. package/scss/foundations/_backdrop.scss +128 -0
  35. package/scss/foundations/_scope.scss +8 -0
  36. package/scss/layouts/_app.scss +77 -0
  37. package/scss/layouts/app/sidebar/_base.scss +117 -0
  38. package/scss/layouts/app/sidebar/_default.scss +26 -0
  39. package/scss/layouts/app/sidebar/_floating.scss +44 -0
  40. package/scss/layouts/app/sidebar/_inset.scss +29 -0
  41. package/scss/mixins/_banner.scss +3 -0
  42. package/scss/moo-core.scss +6 -34
  43. package/scss/moo-ui.scss +6 -6
  44. package/scss/settings/_bootstrap_overrides.scss +4 -0
  45. package/scss/settings/_component_variables.scss +20 -1
  46. package/scss/settings/_options.scss +2 -0
  47. package/scss/settings/_palette.scss +1 -1
  48. package/scss/themes/_forms.scss +15 -0
  49. package/scss/themes/_root.scss +16 -0
  50. package/scss/themes/_standalone.scss +5 -0
  51. package/scss/themes/{_scoped_core.scss → _theme.scss} +1 -0
  52. package/scss/components/sidebar/_inset.scss +0 -59
  53. package/scss/components/sidebar/_layout.scss +0 -176
  54. package/scss/foundations/_core_state_layer.scss +0 -25
  55. package/scss/foundations/_overlay_backdrop.scss +0 -19
  56. package/scss/themes/_standalone_root.scss +0 -119
  57. /package/scss/foundations/{_core_global_primitives.scss → _globals.scss} +0 -0
@@ -0,0 +1,128 @@
1
+ // Bootstrap owns the overlay lifecycle for Dialog / Alert Dialog (Modal) and
2
+ // Sheet (Offcanvas). Moo only retunes the native backdrop appearance through a
3
+ // shared token primitive, so every opening surface gets the same treatment
4
+ // without component-specific backdrop selectors.
5
+ //
6
+ // Modal waits for the real `.modal-backdrop` transition before it starts the
7
+ // dialog panel. Keep that lifecycle element visually inert and animate a
8
+ // pseudo-element instead: the panel and visible blur/dim can then start from
9
+ // the same Bootstrap motion token, while the native backdrop is still retained
10
+ // long enough to fade the visual layer out on close. Use keyframe animation
11
+ // rather than a pseudo-element transition: transitionend events from a pseudo
12
+ // element bubble to its originating backdrop and would make Bootstrap wait for
13
+ // the visual layer before showing the panel.
14
+ @mixin moo-overlay-backdrop-appearance {
15
+ --#{$prefix}backdrop-opacity: var(--moo-overlay-backdrop-opacity, #{$moo-overlay-backdrop-opacity});
16
+ opacity: 1;
17
+ color: transparent;
18
+ background-color: transparent;
19
+
20
+ &.fade,
21
+ &.fade:not(.show) {
22
+ opacity: 1;
23
+ }
24
+
25
+ // Bootstrap reads this duration to decide when to reveal a Modal panel.
26
+ // Keep entry instant; the visual transition below belongs to ::before.
27
+ &.show {
28
+ transition: none;
29
+ }
30
+
31
+ // On close, Bootstrap keeps the lifecycle layer in the DOM for this token
32
+ // duration while ::before fades out. Color has no visible effect on the
33
+ // empty backdrop but supplies Bootstrap's native transition lifecycle
34
+ // without multiplying the pseudo-element's visual fade.
35
+ &.fade:not(.show) {
36
+ color: var(--bs-body-color, currentcolor);
37
+ transition: color var(--moo-overlay-motion-duration, #{$moo-overlay-motion-duration}) ease-out;
38
+ }
39
+
40
+ &::before {
41
+ position: absolute;
42
+ inset: 0;
43
+ content: "";
44
+ opacity: 0;
45
+ background-color: var(--moo-overlay-backdrop-bg, #{$moo-overlay-backdrop-bg});
46
+ -webkit-backdrop-filter: blur(0);
47
+ backdrop-filter: blur(0);
48
+ animation: moo-overlay-backdrop-exit var(--moo-overlay-motion-duration, #{$moo-overlay-motion-duration}) ease-out both;
49
+ }
50
+ }
51
+
52
+ @mixin moo-overlay-backdrop-shown {
53
+ // Bootstrap Modal routes opacity through --bs-backdrop-opacity, but
54
+ // Offcanvas 5.3 compiles the same state to a literal .5. Restate the shared
55
+ // token on both native show selectors so Dialog and Sheet dim equally.
56
+ &::before {
57
+ animation: moo-overlay-backdrop-enter var(--moo-overlay-motion-duration, #{$moo-overlay-motion-duration}) ease-out both;
58
+ }
59
+ }
60
+
61
+ @mixin moo-overlay-backdrop-reduced-motion {
62
+ transition: none;
63
+
64
+ &::before {
65
+ animation: none;
66
+ }
67
+ }
68
+
69
+ @keyframes moo-overlay-backdrop-enter {
70
+ from {
71
+ opacity: 0;
72
+ -webkit-backdrop-filter: blur(0);
73
+ backdrop-filter: blur(0);
74
+ }
75
+
76
+ to {
77
+ opacity: var(--moo-overlay-backdrop-opacity, #{$moo-overlay-backdrop-opacity});
78
+ -webkit-backdrop-filter: var(--moo-overlay-backdrop-filter, #{$moo-overlay-backdrop-filter});
79
+ backdrop-filter: var(--moo-overlay-backdrop-filter, #{$moo-overlay-backdrop-filter});
80
+ }
81
+ }
82
+
83
+ @keyframes moo-overlay-backdrop-exit {
84
+ from {
85
+ opacity: var(--moo-overlay-backdrop-opacity, #{$moo-overlay-backdrop-opacity});
86
+ -webkit-backdrop-filter: var(--moo-overlay-backdrop-filter, #{$moo-overlay-backdrop-filter});
87
+ backdrop-filter: var(--moo-overlay-backdrop-filter, #{$moo-overlay-backdrop-filter});
88
+ }
89
+
90
+ to {
91
+ opacity: 0;
92
+ -webkit-backdrop-filter: blur(0);
93
+ backdrop-filter: blur(0);
94
+ }
95
+ }
96
+
97
+ .modal-backdrop,
98
+ .offcanvas-backdrop {
99
+ @include moo-overlay-backdrop-appearance;
100
+ }
101
+
102
+ .modal-backdrop.show,
103
+ .offcanvas-backdrop.show {
104
+ @include moo-overlay-backdrop-shown;
105
+ }
106
+
107
+ // Backdrops that are portaled into a resolved owner still need to outrank
108
+ // Bootstrap's scoped `.fade` and `.show` rules. Entry points include this
109
+ // mixin inside their single native Moo scope; the global rules above remain
110
+ // available for hosts that intentionally keep Bootstrap's body-level portal.
111
+ @mixin moo-overlay-backdrop-scoped {
112
+ .modal-backdrop,
113
+ .offcanvas-backdrop {
114
+ @include moo-overlay-backdrop-appearance;
115
+ }
116
+
117
+ .modal-backdrop.show,
118
+ .offcanvas-backdrop.show {
119
+ @include moo-overlay-backdrop-shown;
120
+ }
121
+ }
122
+
123
+ @media (prefers-reduced-motion: reduce) {
124
+ .modal-backdrop,
125
+ .offcanvas-backdrop {
126
+ @include moo-overlay-backdrop-reduced-motion;
127
+ }
128
+ }
@@ -0,0 +1,8 @@
1
+ @scope (.moo-ui) to (:where(.moo-ui[data-bs-theme="light"], .moo-ui[data-bs-theme="dark"])) {
2
+ @import "../components";
3
+ @import "../foundations/focus";
4
+ @import "../utilities/scroll_fade";
5
+ @import "../layouts/app";
6
+ @import "../themes/forms";
7
+ @include moo-overlay-backdrop-scoped;
8
+ }
@@ -0,0 +1,77 @@
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
+ overflow-y: auto;
32
+ }
33
+
34
+ .wrapper[data-layout="app"] > [data-slot="page"] > header,
35
+ .wrapper[data-layout="app"] > [data-slot="page"] > main,
36
+ .wrapper[data-layout="app"] > [data-slot="page"] > footer {
37
+ flex: 0 0 auto;
38
+ }
39
+
40
+ // The page main region owns the space between the optional header and footer.
41
+ // Keep the Bootstrap rail as the flex column too, so app previews and real
42
+ // shells can give their caller content a full-height surface without adding
43
+ // layout-specific height values.
44
+ .wrapper[data-layout="app"] > [data-slot="page"] > main {
45
+ display: flex;
46
+ min-height: 0;
47
+ flex: 1 1 auto;
48
+ flex-direction: column;
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
+ }
@@ -0,0 +1,117 @@
1
+ // Shared App-owned Sidebar shell geometry. Sidebar's component partials own
2
+ // only the inner surface and navigation anatomy.
3
+
4
+ .sidebar {
5
+ --moo-sidebar-width: #{$moo-sidebar-width};
6
+ --moo-sidebar-width-icon: #{$moo-sidebar-width-icon};
7
+ --bs-offcanvas-width: var(--moo-sidebar-width);
8
+ flex: 0 0 var(--moo-sidebar-width);
9
+ width: var(--moo-sidebar-width);
10
+ color: var(--moo-sidebar-foreground);
11
+ }
12
+
13
+ // Rail: a thin toggle strip straddling the Sidebar's inline-end edge.
14
+ .sidebar-rail {
15
+ position: absolute;
16
+ inset-block: 0;
17
+ inset-inline-end: 0;
18
+ z-index: 20;
19
+ width: $spacer;
20
+ padding: 0;
21
+ transform: translateX(50%);
22
+ border: 0;
23
+ background: transparent;
24
+ cursor: pointer;
25
+ }
26
+
27
+ // Read the Sidebar's computed direction so this remains valid inside the
28
+ // resolved-owner @scope as well as under a full-document html[dir] owner.
29
+ .sidebar:dir(rtl) .sidebar-rail {
30
+ transform: translateX(-50%);
31
+ }
32
+
33
+ .sidebar-rail::after {
34
+ content: "";
35
+ position: absolute;
36
+ inset-block: 0;
37
+ inset-inline-start: 50%;
38
+ width: var(--bs-border-width);
39
+ background: transparent;
40
+ transition: background 0.15s ease;
41
+ }
42
+
43
+ .sidebar-rail:hover::after {
44
+ background: var(--moo-sidebar-border);
45
+ }
46
+
47
+ .wrapper[data-layout="app"][data-shell-mode="contained"] .sidebar-inner {
48
+ position: relative;
49
+ height: 100%;
50
+ max-height: 100%;
51
+ }
52
+
53
+ // The outer shell owns stacking, collapse width, and the contained-shell
54
+ // geometry. Inner collapsed content remains in components/sidebar/_collapsed.
55
+ @include media-breakpoint-up(lg) {
56
+ .sidebar {
57
+ position: relative;
58
+ }
59
+
60
+ // `offcanvas` is a collapsible mode, not a visual Sidebar variant. On
61
+ // desktop the App keeps the shell in normal flow and uses the shared App
62
+ // state attribute to collapse the column; below lg Bootstrap's native
63
+ // Offcanvas plugin continues to own the drawer transition.
64
+ .sidebar.offcanvas-lg[data-collapsible="offcanvas"] {
65
+ visibility: visible;
66
+ transform: none;
67
+ }
68
+
69
+ .wrapper[data-layout="app"][data-sidebar-state="collapsed"] > .sidebar.offcanvas-lg[data-collapsible="offcanvas"] {
70
+ flex-basis: 0;
71
+ width: 0;
72
+ overflow: hidden;
73
+ visibility: hidden;
74
+ }
75
+
76
+ .wrapper[data-layout="app"]:has([data-sidebar-dropdown-positioned] > .dropdown-menu.show) > .sidebar {
77
+ position: relative;
78
+ // Catalog page headers are sticky at $zindex-fixed. The Sidebar root must
79
+ // sit above that page-level stacking context while an identity menu is
80
+ // open, otherwise the workspace menu is painted underneath the header
81
+ // even though the menu itself is fixed and has dropdown z-index.
82
+ z-index: $zindex-fixed + 1;
83
+ }
84
+
85
+ // The sticky inner surface is its own stacking context. Elevate that
86
+ // context while an identity menu is open so the rail's hover indicator
87
+ // remains behind the fixed dropdown instead of painting across it.
88
+ .wrapper[data-layout="app"]:has([data-sidebar-dropdown-positioned] > .dropdown-menu.show) > .sidebar > .sidebar-inner {
89
+ z-index: $zindex-fixed + 1;
90
+ }
91
+
92
+ .wrapper[data-layout="app"][data-sidebar-state="collapsed"] .sidebar[data-collapsible="icon"] {
93
+ flex-basis: var(--moo-sidebar-width-icon);
94
+ width: var(--moo-sidebar-width-icon);
95
+ }
96
+ }
97
+
98
+ @include media-breakpoint-down(lg) {
99
+ .sidebar-rail {
100
+ display: none;
101
+ }
102
+
103
+ .wrapper[data-layout="app"][data-shell-mode="contained"] .sidebar {
104
+ position: relative;
105
+ inset: auto;
106
+ flex: 0 0 auto;
107
+ width: 100%;
108
+ height: auto;
109
+ visibility: visible;
110
+ transform: none;
111
+ }
112
+
113
+ .wrapper[data-layout="app"][data-shell-mode="contained"] .sidebar-inner {
114
+ height: auto;
115
+ max-height: none;
116
+ }
117
+ }
@@ -0,0 +1,26 @@
1
+ // Default App Sidebar variant: attached to the shell edge with one divider.
2
+
3
+ .sidebar[data-side="left"] .sidebar-inner {
4
+ // `side` is a physical placement contract. Keep the divider on the
5
+ // Sidebar/Page boundary when the document direction is RTL as well.
6
+ border-right: var(--bs-border-width) solid var(--moo-sidebar-border);
7
+ }
8
+
9
+ .sidebar[data-side="right"] {
10
+ order: 1;
11
+ }
12
+
13
+ // `side` is a physical placement contract. `:dir()` reads the wrapper's
14
+ // computed direction inside the owner scope, whether it comes from html for a
15
+ // document owner or from an embedded owner's own dir attribute.
16
+ .wrapper[data-layout="app"]:dir(rtl) > .sidebar[data-side="left"] {
17
+ order: 1;
18
+ }
19
+
20
+ .wrapper[data-layout="app"]:dir(rtl) > .sidebar[data-side="right"] {
21
+ order: 0;
22
+ }
23
+
24
+ .sidebar[data-side="right"] .sidebar-inner {
25
+ border-left: var(--bs-border-width) solid var(--moo-sidebar-border);
26
+ }
@@ -0,0 +1,44 @@
1
+ // Floating App Sidebar variant: the shell detaches the inner surface from
2
+ // the viewport edge with a margin, border, radius, and shadow.
3
+
4
+ @include media-breakpoint-up(lg) {
5
+ .sidebar {
6
+ transition: flex-basis 0.2s ease, width 0.2s ease;
7
+ }
8
+
9
+ .sidebar[data-variant="floating"] .sidebar-inner {
10
+ width: auto;
11
+ height: calc(100svh - #{$spacer});
12
+ max-height: calc(100svh - #{$spacer});
13
+ margin: $spacer * 0.5;
14
+ border: var(--bs-border-width) solid var(--moo-sidebar-border);
15
+ border-radius: var(--bs-border-radius-lg);
16
+ box-shadow: var(--bs-box-shadow-sm);
17
+ }
18
+
19
+ .wrapper[data-layout="app"][data-shell-mode="contained"] .sidebar[data-variant="floating"] .sidebar-inner {
20
+ height: calc(100% - #{$spacer});
21
+ max-height: calc(100% - #{$spacer});
22
+ }
23
+
24
+ // At icon-rail width the detached card reads as floating mostly through
25
+ // elevation and breathing room, since the margin/border alone are hard to
26
+ // read at the base icon width; step up to Bootstrap's base shadow scale
27
+ // (still a shared token, no new value) and widen the column by the same
28
+ // margin the card's sides consume, so the icon rail itself keeps its full
29
+ // width instead of shrinking.
30
+ .wrapper[data-layout="app"][data-sidebar-state="collapsed"] .sidebar[data-variant="floating"][data-collapsible="icon"] {
31
+ flex-basis: calc(var(--moo-sidebar-width-icon) + #{$spacer});
32
+ width: calc(var(--moo-sidebar-width-icon) + #{$spacer});
33
+ }
34
+
35
+ .wrapper[data-layout="app"][data-sidebar-state="collapsed"] .sidebar[data-variant="floating"][data-collapsible="icon"] .sidebar-inner {
36
+ box-shadow: var(--bs-box-shadow);
37
+ }
38
+ }
39
+
40
+ @media (prefers-reduced-motion: reduce) {
41
+ .sidebar {
42
+ transition: none;
43
+ }
44
+ }
@@ -0,0 +1,29 @@
1
+ // Inset App variant: the App shell owns the background and makes the Page a
2
+ // sibling inset surface. Sidebar keeps only its inner navigation anatomy.
3
+
4
+ @include media-breakpoint-up(lg) {
5
+ .wrapper[data-layout="app"]:has(> .sidebar[data-variant="inset"]) {
6
+ background: var(--moo-sidebar);
7
+ }
8
+
9
+ .wrapper[data-layout="app"]:has(> .sidebar[data-variant="inset"]) > [data-slot="page"] {
10
+ margin: $spacer * 0.5;
11
+ margin-left: 0;
12
+ border-radius: var(--bs-border-radius-xl);
13
+ box-shadow: var(--bs-box-shadow-sm);
14
+ background: var(--bs-body-bg);
15
+ }
16
+
17
+ .wrapper[data-layout="app"][data-sidebar-state="collapsed"]:has(> .sidebar[data-variant="inset"]) > [data-slot="page"] {
18
+ margin-left: $spacer * 0.5;
19
+ }
20
+
21
+ .wrapper[data-layout="app"]:has(> .sidebar[data-variant="inset"][data-side="right"]) > [data-slot="page"] {
22
+ margin-left: $spacer * 0.5;
23
+ margin-right: 0;
24
+ }
25
+
26
+ .wrapper[data-layout="app"][data-sidebar-state="collapsed"]:has(> .sidebar[data-variant="inset"][data-side="right"]) > [data-slot="page"] {
27
+ margin-right: $spacer * 0.5;
28
+ }
29
+ }
@@ -0,0 +1,3 @@
1
+ @import "bootstrap/scss/mixins/banner";
2
+
3
+ @include bsBanner("");
@@ -4,9 +4,7 @@
4
4
  * Includes Bootstrap 5.3.3 component output
5
5
  * SPDX-License-Identifier: MIT
6
6
  */
7
- $enable-dark-mode: false;
8
- $moo-spinner-animation-name: moo-spinner-rotate;
9
-
7
+ @import "settings/options";
10
8
  @import "bootstrap/scss/functions";
11
9
  @import "settings";
12
10
  @import "bootstrap/scss/variables";
@@ -14,34 +12,8 @@ $moo-spinner-animation-name: moo-spinner-rotate;
14
12
  @import "bootstrap/scss/maps";
15
13
  @import "bootstrap/scss/mixins";
16
14
  @import "bootstrap/scss/utilities";
17
- @import "themes/scoped_core";
18
- @import "foundations/core_global_primitives";
19
-
20
- .moo-ui {
21
- @include moo-core-scales;
22
- @include moo-core-shared;
23
- @include moo-core-light;
24
- }
25
-
26
- :where(html, body)[data-bs-theme="dark"] .moo-ui:not([data-bs-theme]) {
27
- @include moo-core-dark;
28
- }
29
-
30
- .moo-ui[data-bs-theme="light"] {
31
- @include moo-core-light;
32
- }
33
-
34
- .moo-ui[data-bs-theme="dark"] {
35
- @include moo-core-dark;
36
- }
37
-
38
- .moo-ui[dir="rtl"] {
39
- direction: rtl;
40
- }
41
-
42
- @scope (.moo-ui) {
43
- @import "components";
44
- }
45
-
46
- @import "foundations/core_state_layer";
47
- @import "foundations/overlay_backdrop";
15
+ @import "themes/theme";
16
+ @import "foundations/globals";
17
+ @import "foundations/backdrop";
18
+ @import "themes/root";
19
+ @import "foundations/scope";
package/scss/moo-ui.scss CHANGED
@@ -1,7 +1,5 @@
1
1
  @import "settings";
2
-
3
- @import "bootstrap/scss/mixins/banner";
4
- @include bsBanner("");
2
+ @import "mixins/banner";
5
3
 
6
4
  // Bootstrap configuration
7
5
  @import "bootstrap/scss/functions";
@@ -10,10 +8,12 @@
10
8
  @import "bootstrap/scss/maps";
11
9
  @import "bootstrap/scss/mixins";
12
10
  @import "bootstrap/scss/utilities";
11
+ @import "themes/theme";
13
12
 
14
13
  // Bootstrap layout and standalone-only components
15
14
  @import "bootstrap/scss/root";
16
- @import "themes/standalone_root";
15
+ @import "themes/root";
16
+ @import "themes/standalone";
17
17
  @import "bootstrap/scss/reboot";
18
18
  @import "bootstrap/scss/type";
19
19
  @import "bootstrap/scss/images";
@@ -46,5 +46,5 @@
46
46
  @import "bootstrap/scss/utilities/api";
47
47
 
48
48
  @import "utilities/scroll_fade_primitives";
49
- @import "components";
50
- @import "foundations/overlay_backdrop";
49
+ @import "foundations/backdrop";
50
+ @import "foundations/scope";
@@ -4,6 +4,10 @@ $btn-box-shadow: none !default;
4
4
  $btn-focus-box-shadow: none !default;
5
5
  $btn-active-box-shadow: none !default;
6
6
 
7
+ // Keep Bootstrap's CSS Grid utility layer available alongside the Flexbox
8
+ // grid so native .grid and .g-col-* markup works in Moo UI hosts.
9
+ $enable-cssgrid: true !default;
10
+
7
11
  // Bootstrap validation icons are background images injected by the native
8
12
  // validation mixin. Reference-style invalid fields use border/ring + error text
9
13
  // without a trailing status glyph, so disable the Bootstrap icon branch at the
@@ -255,6 +255,20 @@ $btn-padding-y-sm: 0.3125rem !default;
255
255
  $btn-padding-x-sm: 0.625rem !default;
256
256
  $btn-padding-y-lg: 0.4375rem !default;
257
257
  $btn-padding-x-lg: 0.625rem !default;
258
+
259
+ // Bootstrap exposes button padding, but it has no command/search-trigger
260
+ // composition or responsive width scale. Keep this shared control's geometry
261
+ // on private knobs so Catalog and Odoo consume one Core contract instead of
262
+ // copying chrome-specific literals into their own stylesheets.
263
+ $moo-search-trigger-height: 2rem !default;
264
+ $moo-search-trigger-width: 10rem !default;
265
+ $moo-search-trigger-width-lg: 13rem !default;
266
+ $moo-search-trigger-width-xxl: 16rem !default;
267
+ $moo-search-trigger-padding-y: 0.5rem !default;
268
+ $moo-search-trigger-padding-x: 0.75rem !default;
269
+ $moo-search-trigger-border-color: transparent !default;
270
+ $moo-search-trigger-label-gap: 0.5rem !default;
271
+ $moo-search-trigger-shortcut-gap: 0.25rem !default;
258
272
  // Icon-only buttons are squares whose side equals the token-driven button
259
273
  // height (line-height + 2*padding-y + 2*border), matching sibling text
260
274
  // buttons. Bootstrap exposes no single icon-button size knob; the side is a
@@ -305,9 +319,14 @@ $moo-form-focus-ring-color: var(--moo-ring) !default;
305
319
  // backdrops. Bootstrap exposes separate .modal-backdrop and
306
320
  // .offcanvas-backdrop selectors; Moo keeps their visual treatment aligned via
307
321
  // one token set instead of per-component backdrop rules.
322
+ // Bootstrap defaults both native panels to .3s; retain that default while
323
+ // exposing one runtime duration token for the panel and its backdrop.
324
+ $moo-overlay-motion-duration: .3s !default;
325
+ $modal-transition: transform var(--moo-overlay-motion-duration, #{$moo-overlay-motion-duration}) ease-out !default;
326
+ $offcanvas-transition-duration: var(--moo-overlay-motion-duration, #{$moo-overlay-motion-duration}) !default;
308
327
  $moo-overlay-backdrop-opacity: 1 !default;
309
328
  $moo-overlay-backdrop-bg: color-mix(in srgb, #0a0a0a 10%, transparent) !default;
310
- $moo-overlay-backdrop-filter: blur(8px) !default;
329
+ $moo-overlay-backdrop-filter: blur(6px) !default;
311
330
 
312
331
  // A quieter elevation scale and the extra radius step, applied UI-wide through
313
332
  // Bootstrap's own scales so every component consumes one shared primitive.
@@ -0,0 +1,2 @@
1
+ $enable-dark-mode: false;
2
+ $moo-spinner-animation-name: moo-spinner-rotate;
@@ -112,7 +112,7 @@ $moo-sidebar-dark: #1c1c1f !default;
112
112
  $moo-input-bg-dark: color-mix(in srgb, $moo-muted-surface-dark 50%, $moo-surface-dark) !default;
113
113
 
114
114
  // Bootstrap root variables consumed by the scoped core build. Define them
115
- // here so themes/_scoped_core.scss can emit Bootstrap's root contract without
115
+ // here so themes/_theme.scss can emit Bootstrap's root contract without
116
116
  // hardcoded consumer-side literals.
117
117
  $body-tertiary-color: #a1a1aa !default;
118
118
  $body-tertiary-bg: $light !default;
@@ -0,0 +1,15 @@
1
+ :scope[data-bs-theme="light"] .form-select {
2
+ --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator)};
3
+ }
4
+
5
+ :scope[data-bs-theme="dark"] .form-select {
6
+ --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator-dark)};
7
+ }
8
+
9
+ :scope[data-bs-theme="light"] .form-switch .form-check-input:not(:checked):not(:focus) {
10
+ --#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image)};
11
+ }
12
+
13
+ :scope[data-bs-theme="dark"] .form-switch .form-check-input:not(:checked):not(:focus) {
14
+ --#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image-dark)};
15
+ }
@@ -0,0 +1,16 @@
1
+ .moo-ui[data-bs-theme] {
2
+ @include moo-core-scales;
3
+ @include moo-core-shared;
4
+ }
5
+
6
+ .moo-ui[data-bs-theme="light"] {
7
+ @include moo-core-light;
8
+ }
9
+
10
+ .moo-ui[data-bs-theme="dark"] {
11
+ @include moo-core-dark;
12
+ }
13
+
14
+ .moo-ui[data-bs-theme][dir="rtl"] {
15
+ direction: rtl;
16
+ }
@@ -0,0 +1,5 @@
1
+ // A complete document places its resolved owner directly inside body. The
2
+ // owner, rather than body, supplies the viewport-sized foreground surface.
3
+ body > .moo-ui[data-bs-theme] {
4
+ min-block-size: 100dvh;
5
+ }
@@ -77,6 +77,7 @@ $moo-theme-colors-border-subtle-dark: (
77
77
  }
78
78
 
79
79
  @mixin moo-core-shared {
80
+ --moo-overlay-motion-duration: #{$moo-overlay-motion-duration};
80
81
  --moo-overlay-backdrop-opacity: #{$moo-overlay-backdrop-opacity};
81
82
  --moo-overlay-backdrop-bg: #{$moo-overlay-backdrop-bg};
82
83
  --moo-overlay-backdrop-filter: #{$moo-overlay-backdrop-filter};