@wpmoo/ui 1.0.0-rc.3 → 1.0.0-rc.5

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 (82) hide show
  1. package/ASSET_LICENSE.md +3 -1
  2. package/README.md +55 -123
  3. package/certification.json +14 -2
  4. package/dist/assets/css/moo-ui.css +189 -122
  5. package/dist/assets/css/moo-ui.min.css +3 -3
  6. package/dist/assets/css/moo.css +72 -17
  7. package/dist/assets/css/moo.min.css +3 -3
  8. package/dist/js/chart.js +1 -1
  9. package/dist/js/chart.min.js +1 -1
  10. package/dist/js/combobox.js +71 -18
  11. package/dist/js/context-menu.js +1 -1
  12. package/dist/js/datatable.js +135 -25
  13. package/dist/js/datepicker.js +1 -1
  14. package/dist/js/datepicker.min.js +1 -1
  15. package/dist/js/moo-ui.js +19047 -0
  16. package/dist/js/moo-ui.min.js +27 -0
  17. package/dist/js/sidebar.js +1 -1
  18. package/dist/js/slider.js +1 -1
  19. package/package.json +18 -6
  20. package/scss/_components.scss +73 -0
  21. package/scss/_settings.scss +8 -0
  22. package/scss/components/_accordion.scss +65 -0
  23. package/scss/components/_alert.scss +94 -0
  24. package/scss/components/_avatar.scss +154 -0
  25. package/scss/components/_badge.scss +33 -0
  26. package/scss/components/_breadcrumb.scss +130 -0
  27. package/scss/components/_button.scss +228 -0
  28. package/scss/components/_button_group.scss +81 -0
  29. package/scss/components/_card.scss +142 -0
  30. package/scss/components/_checkbox.scss +115 -0
  31. package/scss/components/_close_button.scss +59 -0
  32. package/scss/components/_collapsible.scss +43 -0
  33. package/scss/components/_combobox.scss +258 -0
  34. package/scss/components/_context-menu.scss +28 -0
  35. package/scss/components/_datatable.scss +1082 -0
  36. package/scss/components/_datepicker.scss +236 -0
  37. package/scss/components/_dialog.scss +66 -0
  38. package/scss/components/_dropdown.scss +202 -0
  39. package/scss/components/_field.scss +125 -0
  40. package/scss/components/_input.scss +35 -0
  41. package/scss/components/_input_group.scss +201 -0
  42. package/scss/components/_kbd.scss +10 -0
  43. package/scss/components/_menubar.scss +16 -0
  44. package/scss/components/_navigation.scss +41 -0
  45. package/scss/components/_pagination.scss +70 -0
  46. package/scss/components/_popover.scss +47 -0
  47. package/scss/components/_progress.scss +7 -0
  48. package/scss/components/_radio_group.scss +9 -0
  49. package/scss/components/_select.scss +7 -0
  50. package/scss/components/_separator.scss +15 -0
  51. package/scss/components/_sheet.scss +32 -0
  52. package/scss/components/_sidebar.scss +7 -0
  53. package/scss/components/_skeleton.scss +17 -0
  54. package/scss/components/_slider.scss +214 -0
  55. package/scss/components/_spinner.scss +17 -0
  56. package/scss/components/_switch.scss +25 -0
  57. package/scss/components/_table.scss +7 -0
  58. package/scss/components/_tabs.scss +139 -0
  59. package/scss/components/_textarea.scss +7 -0
  60. package/scss/components/_toast.scss +119 -0
  61. package/scss/components/_toggle_group.scss +19 -0
  62. package/scss/components/_tooltip.scss +83 -0
  63. package/scss/components/sidebar/_collapsed.scss +187 -0
  64. package/scss/components/sidebar/_identity.scss +72 -0
  65. package/scss/components/sidebar/_inset.scss +59 -0
  66. package/scss/components/sidebar/_layout.scss +176 -0
  67. package/scss/components/sidebar/_menus.scss +236 -0
  68. package/scss/foundations/_core_global_primitives.scss +5 -0
  69. package/scss/foundations/_core_state_layer.scss +25 -0
  70. package/scss/foundations/_focus.scss +139 -0
  71. package/scss/foundations/_overlay_backdrop.scss +19 -0
  72. package/scss/moo-core.scss +47 -0
  73. package/scss/moo-ui.scss +50 -0
  74. package/scss/settings/_bootstrap_overrides.scss +11 -0
  75. package/scss/settings/_component_variables.scss +480 -0
  76. package/scss/settings/_forms.scss +65 -0
  77. package/scss/settings/_palette.scss +132 -0
  78. package/scss/themes/_scoped_core.scss +239 -0
  79. package/scss/themes/_standalone_root.scss +119 -0
  80. package/scss/utilities/_scroll_fade.scss +193 -0
  81. package/scss/utilities/_scroll_fade_primitives.scss +43 -0
  82. package/THIRD_PARTY_NOTICES.md +0 -53
@@ -0,0 +1,236 @@
1
+ // Menus ------------------------------------------------------------------
2
+ .sidebar-menu {
3
+ display: flex;
4
+ flex-direction: column;
5
+ gap: $spacer * 0.25;
6
+ width: 100%;
7
+ min-width: 0;
8
+ margin: 0;
9
+ padding: 0;
10
+ list-style: none;
11
+ }
12
+
13
+ .sidebar-menu-item {
14
+ position: relative;
15
+ }
16
+
17
+ // Auto-detect a trailing action so a public consumer doesn't need to
18
+ // remember an extra class for the button to reserve room for it.
19
+ .sidebar-menu-item:has(> .sidebar-menu-action) > .sidebar-menu-button {
20
+ padding-inline-end: $spacer * 2.5;
21
+ }
22
+
23
+ .sidebar-menu-button {
24
+ display: flex;
25
+ align-items: center;
26
+ gap: $spacer * 0.5;
27
+ width: 100%;
28
+ min-width: 0;
29
+ height: $spacer * 2;
30
+ padding-inline: $spacer * 0.5;
31
+ overflow: hidden;
32
+ color: var(--moo-sidebar-foreground);
33
+ font-size: $font-size-base;
34
+ text-align: start;
35
+ text-decoration: none;
36
+ border: 0;
37
+ border-radius: var(--bs-border-radius);
38
+ background: transparent;
39
+ }
40
+
41
+ .sidebar-menu-button:hover {
42
+ color: var(--moo-sidebar-foreground);
43
+ background: var(--moo-sidebar-accent);
44
+ }
45
+
46
+ .sidebar-menu-button--account[aria-expanded="true"] {
47
+ color: var(--moo-sidebar-foreground);
48
+ background: var(--moo-sidebar-accent);
49
+ }
50
+
51
+ .sidebar-menu-button--account[aria-expanded="true"] .sidebar-menu-button__end [data-icon] {
52
+ color: var(--moo-sidebar-foreground);
53
+ }
54
+
55
+ .sidebar-menu-button.sidebar-menu-button--account,
56
+ .sidebar-menu-button.sidebar-menu-button--workspace {
57
+ cursor: default;
58
+ }
59
+
60
+ .sidebar-menu-item--account {
61
+ padding-inline: 0;
62
+ }
63
+
64
+ .sidebar-menu-item--account > .sidebar-menu-button--account {
65
+ height: $spacer * 3;
66
+ min-height: $spacer * 3;
67
+ padding: $spacer * 0.5;
68
+ }
69
+
70
+ // A fixed brand lockup, not an interactive control: no hover affordance.
71
+ .sidebar-menu-button--static:hover {
72
+ background: transparent;
73
+ }
74
+
75
+ .sidebar-menu-button[aria-current="page"] {
76
+ font-weight: $font-weight-medium;
77
+ background: var(--moo-sidebar-accent);
78
+ }
79
+
80
+ .sidebar-content:has(.sidebar-menu:is(:hover, :focus-within)) .sidebar-menu-button[aria-current="page"]:not(:hover):not(:focus-visible),
81
+ .sidebar-content:has(.sidebar-menu-button:not([aria-current="page"]):is(:hover, :focus-visible)) .sidebar-menu-button[aria-current="page"]:not(:hover):not(:focus-visible) {
82
+ background: transparent;
83
+ }
84
+
85
+ .sidebar-menu-button--lg {
86
+ height: $spacer * 3;
87
+ padding: $spacer * 0.5;
88
+ }
89
+
90
+ .sidebar-menu-button__lead {
91
+ display: inline-flex;
92
+ flex: 0 0 auto;
93
+ align-items: center;
94
+ justify-content: center;
95
+ }
96
+
97
+ .sidebar-menu-button__lead [data-icon] {
98
+ width: $font-size-base;
99
+ height: $font-size-base;
100
+ }
101
+
102
+ .sidebar-menu-button[aria-current="page"] .sidebar-menu-button__lead [data-icon] {
103
+ color: var(--moo-sidebar-foreground);
104
+ }
105
+
106
+ .sidebar-menu-button__text {
107
+ display: grid;
108
+ flex: 1 1 auto;
109
+ min-width: 0;
110
+ line-height: 1.2;
111
+ }
112
+
113
+ .sidebar-menu-button__title {
114
+ overflow: hidden;
115
+ font-size: $font-size-base;
116
+ text-overflow: ellipsis;
117
+ white-space: nowrap;
118
+ }
119
+
120
+ .sidebar-menu-button--lg .sidebar-menu-button__title {
121
+ font-weight: $font-weight-medium;
122
+ }
123
+
124
+ .sidebar-menu-button__subtitle {
125
+ overflow: hidden;
126
+ color: var(--moo-muted-foreground);
127
+ font-size: $font-size-base * 0.857;
128
+ text-overflow: ellipsis;
129
+ white-space: nowrap;
130
+ }
131
+
132
+ .sidebar-menu-button__end {
133
+ display: inline-flex;
134
+ flex: 0 0 auto;
135
+ align-items: center;
136
+ margin-inline-start: auto;
137
+ }
138
+
139
+ .sidebar-menu-button__end [data-icon] {
140
+ width: $font-size-base;
141
+ height: $font-size-base;
142
+ color: var(--moo-muted-foreground);
143
+ }
144
+
145
+ .sidebar-menu-button--disclosure[aria-expanded="true"] .sidebar-menu-button__end [data-icon] {
146
+ transform: rotate(90deg);
147
+ }
148
+
149
+ .sidebar-menu-button__end [data-icon] {
150
+ transition: transform 0.15s ease;
151
+ }
152
+
153
+ .sidebar-menu-sub {
154
+ gap: 0;
155
+ margin: 0;
156
+ // Aligns the indent line with the center of the parent disclosure
157
+ // button's icon (padding-inline-start + half the icon width), so the
158
+ // line reads as a continuation of the icon column above it instead of
159
+ // sitting flush with the group edge.
160
+ margin-inline-start: $spacer * 0.5 + $font-size-base * 0.5;
161
+ padding-inline-start: $spacer * 0.5;
162
+ border-inline-start: var(--bs-border-width) solid var(--moo-border);
163
+ list-style: none;
164
+ }
165
+
166
+ .sidebar-menu-sub-button {
167
+ height: $spacer * 1.75;
168
+ font-size: $font-size-base * 0.929;
169
+ }
170
+
171
+ .sidebar-menu-sub-item {
172
+ position: relative;
173
+ }
174
+
175
+ .sidebar-menu-action {
176
+ position: absolute;
177
+ inset-inline-end: $spacer * 0.25;
178
+ inset-block: 0;
179
+ display: flex;
180
+ align-items: center;
181
+ z-index: 1;
182
+ }
183
+
184
+ .sidebar-menu-action:has(> [data-popper-placement]) {
185
+ z-index: 2;
186
+ }
187
+
188
+ .sidebar-menu-action > button {
189
+ color: var(--moo-muted-foreground);
190
+ }
191
+
192
+ .sidebar-menu-action > button:hover {
193
+ color: var(--moo-sidebar-foreground);
194
+ }
195
+
196
+ // Overlays the group's top-right corner, vertically centered against the
197
+ // group label row ($moo group padding + half the label/button height delta).
198
+ .sidebar-group-action {
199
+ position: absolute;
200
+ z-index: 1;
201
+ top: $spacer * 0.75;
202
+ inset-inline-end: $spacer * 0.5;
203
+ }
204
+
205
+ // Overlays the trailing edge of the menu row it belongs to, matching
206
+ // .sidebar-menu-action's slot so both compose the same visual contract.
207
+ .sidebar-menu-badge {
208
+ position: absolute;
209
+ inset-inline-end: $spacer * 0.25;
210
+ inset-block: 0;
211
+ z-index: 1;
212
+ display: flex;
213
+ align-items: center;
214
+ pointer-events: none;
215
+ }
216
+
217
+ // Reserve room so a long title doesn't run under the badge.
218
+ .sidebar-menu-item:has(> .sidebar-menu-badge) > .sidebar-menu-button {
219
+ padding-inline-end: $spacer * 2.5;
220
+ }
221
+
222
+ .sidebar-menu-sub-item:has(> .sidebar-menu-badge) > .sidebar-menu-button {
223
+ padding-inline-end: $spacer * 2.5;
224
+ }
225
+
226
+ // A menu item can combine a trailing action with a badge, such as an unread
227
+ // count beside a "..." overflow menu. Both default to the same trailing
228
+ // slot, so shift the badge inward past the action's footprint and reserve
229
+ // extra title space for the pair instead of just one accessory's width.
230
+ .sidebar-menu-item:has(> .sidebar-menu-action) > .sidebar-menu-badge {
231
+ inset-inline-end: $spacer * 2;
232
+ }
233
+
234
+ .sidebar-menu-item:has(> .sidebar-menu-action):has(> .sidebar-menu-badge) > .sidebar-menu-button {
235
+ padding-inline-end: $spacer * 4.5;
236
+ }
@@ -0,0 +1,5 @@
1
+ @import "../utilities/scroll_fade_primitives";
2
+
3
+ @keyframes moo-spinner-rotate {
4
+ to { transform: rotate(360deg) #{"/* rtl:ignore */"}; }
5
+ }
@@ -0,0 +1,25 @@
1
+ :where(html, body)[data-bs-theme="dark"] .moo-ui:not([data-bs-theme]) .form-select,
2
+ .moo-ui[data-bs-theme="dark"] .form-select {
3
+ --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator-dark)};
4
+ }
5
+
6
+ :where(html, body)[data-bs-theme="dark"] .moo-ui:not([data-bs-theme]) .form-switch .form-check-input:not(:checked):not(:focus),
7
+ .moo-ui[data-bs-theme="dark"] .form-switch .form-check-input:not(:checked):not(:focus) {
8
+ --#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image-dark)};
9
+ }
10
+
11
+ :where(html, body)[data-bs-theme="dark"] .moo-ui:not([data-bs-theme]) .form-switch .form-check-input:checked,
12
+ .moo-ui[data-bs-theme="dark"] .form-switch .form-check-input:checked {
13
+ --#{$prefix}form-switch-bg: #{escape-svg($moo-switch-checked-bg-image-dark)};
14
+
15
+ background-color: var(--moo-primary);
16
+ border-color: var(--moo-primary);
17
+ filter: none;
18
+ }
19
+
20
+ :where(html, body)[data-bs-theme="dark"] .moo-ui:not([data-bs-theme]) .form-switch .form-check-input:focus:active:not(:checked),
21
+ :where(html, body)[data-bs-theme="dark"] .moo-ui:not([data-bs-theme]) .form-switch .form-check-input:focus:not(:focus-visible):not(:checked),
22
+ .moo-ui[data-bs-theme="dark"] .form-switch .form-check-input:focus:active:not(:checked),
23
+ .moo-ui[data-bs-theme="dark"] .form-switch .form-check-input:focus:not(:focus-visible):not(:checked) {
24
+ --#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image-dark)};
25
+ }
@@ -0,0 +1,139 @@
1
+ // Bootstrap form labels and check/radio/switch labels sit inside clickable
2
+ // control surfaces in Moo UI, so keep them from selecting text during pointer
3
+ // interaction without making Field own every label selector.
4
+ .form-label,
5
+ .form-check-label {
6
+ user-select: none;
7
+ }
8
+
9
+ // One shared focus-visible recipe for essentially every focusable surface --
10
+ // border swaps to the ring color and a 3px/50%-opacity ring surrounds the
11
+ // control. Matches the reference exactly, which repeats this same
12
+ // identical recipe (border-ring + ring-[3px] + ring-ring/50) across buttons,
13
+ // links, dialog/dropdown/popover/select triggers, tabs, and toggle-group
14
+ // items as well as native form controls, rather than a different treatment
15
+ // per component family. Placed ahead of the is-invalid rule below so that
16
+ // invalid controls can keep the same ring width while swapping only the
17
+ // color. The explicit
18
+ // outline: 0 replaces the browser's own default focus ring (an amber
19
+ // auto-style outline on Chromium) that would otherwise show through on any
20
+ // element -- plain sidebar/nav <a> tags included -- that Bootstrap doesn't
21
+ // already reset at the .btn level.
22
+ :is(.btn, a, button, summary, [tabindex]):not(input, textarea, select):focus-visible,
23
+ :is(.form-control, .form-select, .form-check-input):focus-visible {
24
+ border-color: var(--moo-ring);
25
+ outline: 0;
26
+ box-shadow: 0 0 0 #{$moo-form-focus-ring-width} color-mix(in srgb, #{$moo-form-focus-ring-color} 50%, transparent);
27
+ }
28
+
29
+ // Buttons keep their hover/open treatment after pointer clicks; the ring is
30
+ // reserved for keyboard focus on the resting control.
31
+ .btn:focus-visible:hover,
32
+ .btn.show:focus-visible {
33
+ border-color: var(--bs-btn-hover-border-color);
34
+ box-shadow: none;
35
+ }
36
+
37
+ // Mouse-triggered focus keeps the resting border and shows no ring, same
38
+ // as every other interactive surface on the site (.form-check-input's own
39
+ // equivalent lives in components/_checkbox.scss, next to its checked/
40
+ // indeterminate border-color variants).
41
+ .form-control:focus:not(:focus-visible),
42
+ .form-select:focus:not(:focus-visible) {
43
+ border-color: var(--moo-border);
44
+ box-shadow: none;
45
+ }
46
+
47
+ // Bootstrap's own .page-link:focus (vendor/bootstrap/scss/_pagination.scss)
48
+ // applies its background/color/outline/box-shadow on any focus, including
49
+ // mouse clicks -- unlike every other control here, it was never gated
50
+ // behind :focus-visible, so clicking a page number (which also makes it the
51
+ // active page) showed a ring the reference only shows for keyboard focus.
52
+ // The ring/outline never carries active-state meaning (Bootstrap's own
53
+ // ".active > &" rule never sets box-shadow), so it's always safe to drop on
54
+ // non-keyboard focus, active page included. color/bg/border only revert to
55
+ // resting when the page isn't the current one, so the active page keeps its
56
+ // own look while it holds mouse focus. Real keyboard focus still gets the
57
+ // shared ring above, since .page-link is a <button> and already matches
58
+ // that selector.
59
+ .page-link:focus:not(:focus-visible) {
60
+ outline: 0;
61
+ box-shadow: none;
62
+ }
63
+
64
+ .page-item:not(.active) > .page-link:focus:not(:focus-visible) {
65
+ color: var(--bs-pagination-color);
66
+ background-color: var(--bs-pagination-bg);
67
+ border-color: var(--bs-pagination-border-color);
68
+ }
69
+
70
+ // Bootstrap shows validation glow only on :focus, while the reference keeps a
71
+ // subtle destructive ring visible for invalid controls. Keep it on native
72
+ // form-control/form-select classes so Input, Select, Field, and Combobox share
73
+ // the same validation affordance.
74
+ .form-control.is-invalid,
75
+ .form-control.is-invalid:focus,
76
+ .was-validated .form-control:invalid,
77
+ .was-validated .form-control:invalid:focus,
78
+ .form-select.is-invalid,
79
+ .form-select.is-invalid:focus,
80
+ .was-validated .form-select:invalid,
81
+ .was-validated .form-select:invalid:focus {
82
+ box-shadow: 0 0 0 #{$moo-form-focus-ring-width} var(--moo-form-invalid-ring-color);
83
+ }
84
+
85
+ // .btn-check toggle buttons (Toggle Group) put focus on the hidden input,
86
+ // never the visible label, so the rule above can never match them; only
87
+ // variants generated through Bootstrap's button-variant mixin (real theme
88
+ // colors) get a working native focus glow, so btn-ghost/outline consumers
89
+ // would otherwise show no ring at all. Share the same ring here instead of
90
+ // patching --bs-btn-focus-box-shadow per variant.
91
+ .btn-check:focus:not(:focus-visible) + .btn {
92
+ outline: 0;
93
+ box-shadow: none;
94
+ }
95
+
96
+ .btn-check:focus-visible + .btn {
97
+ border-color: var(--moo-ring);
98
+ outline: 0;
99
+ box-shadow: 0 0 0 #{$moo-form-focus-ring-width} color-mix(in srgb, #{$moo-form-focus-ring-color} 50%, transparent);
100
+ }
101
+
102
+ .input-group > .dropdown-toggle[aria-expanded="true"]:focus-visible {
103
+ box-shadow: none;
104
+ }
105
+
106
+ // Compound controls whose native input isn't the outer visual box (Combobox's
107
+ // chip row, Input Group's addon-wrapped control) need the same ring painted
108
+ // on the wrapper instead of the child. Kept here rather than in each
109
+ // component's own partial so every focus-ring declaration in the project
110
+ // stays in one file instead of the recipe being copy-pasted per component --
111
+ // component partials contract-test that their own box-shadow declarations
112
+ // stick to Bootstrap's native primitives (test_catalog.py's
113
+ // test_component_styles_use_bootstrap_visual_primitives), and this recipe
114
+ // isn't one of those.
115
+ .combobox-chips:focus-within {
116
+ border-color: var(--moo-ring);
117
+ outline: 0;
118
+ box-shadow: 0 0 0 #{$moo-form-focus-ring-width} color-mix(in srgb, #{$moo-form-focus-ring-color} 50%, transparent);
119
+ }
120
+
121
+ .input-group:has(> .form-control:focus):not(:has(> .form-control[type="file"])) {
122
+ border-color: var(--moo-ring);
123
+ outline: 0;
124
+ box-shadow: 0 0 0 #{$moo-form-focus-ring-width} color-mix(in srgb, #{$moo-form-focus-ring-color} 50%, transparent);
125
+ }
126
+
127
+ // Validation input groups are also one visual control. Keep feedback outside the
128
+ // grouped control, then paint the destructive ring on the wrapper and suppress
129
+ // the child ring.
130
+ .input-group.has-validation:not(:has(> :is(.valid-feedback, .invalid-feedback, .valid-tooltip, .invalid-tooltip))):has(> :is(.form-control, .form-select).is-invalid),
131
+ .was-validated .input-group.has-validation:not(:has(> :is(.valid-feedback, .invalid-feedback, .valid-tooltip, .invalid-tooltip))):has(> :is(.form-control, .form-select):invalid) {
132
+ border-color: var(--bs-form-invalid-border-color);
133
+ box-shadow: 0 0 0 #{$moo-form-focus-ring-width} var(--moo-form-invalid-ring-color);
134
+ }
135
+
136
+ .input-group.has-validation:not(:has(> :is(.valid-feedback, .invalid-feedback, .valid-tooltip, .invalid-tooltip))) > :is(.form-control, .form-select).is-invalid,
137
+ .was-validated .input-group.has-validation:not(:has(> :is(.valid-feedback, .invalid-feedback, .valid-tooltip, .invalid-tooltip))) > :is(.form-control, .form-select):invalid {
138
+ box-shadow: none;
139
+ }
@@ -0,0 +1,19 @@
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
+ .modal-backdrop,
6
+ .offcanvas-backdrop {
7
+ --#{$prefix}backdrop-opacity: var(--moo-overlay-backdrop-opacity, #{$moo-overlay-backdrop-opacity});
8
+ background-color: var(--moo-overlay-backdrop-bg, #{$moo-overlay-backdrop-bg});
9
+ -webkit-backdrop-filter: var(--moo-overlay-backdrop-filter, #{$moo-overlay-backdrop-filter});
10
+ backdrop-filter: var(--moo-overlay-backdrop-filter, #{$moo-overlay-backdrop-filter});
11
+ }
12
+
13
+ .modal-backdrop.show,
14
+ .offcanvas-backdrop.show {
15
+ // Bootstrap Modal routes opacity through --bs-backdrop-opacity, but
16
+ // Offcanvas 5.3 compiles the same state to a literal .5. Restate the shared
17
+ // token on both native show selectors so Dialog and Sheet dim equally.
18
+ opacity: var(--moo-overlay-backdrop-opacity, #{$moo-overlay-backdrop-opacity});
19
+ }
@@ -0,0 +1,47 @@
1
+ /*!
2
+ * Moo UI core
3
+ * Copyright (c) 2026 WPMoo (wpmoo.org)
4
+ * Includes Bootstrap 5.3.3 component output
5
+ * SPDX-License-Identifier: MIT
6
+ */
7
+ $enable-dark-mode: false;
8
+ $moo-spinner-animation-name: moo-spinner-rotate;
9
+
10
+ @import "bootstrap/scss/functions";
11
+ @import "settings";
12
+ @import "bootstrap/scss/variables";
13
+ @import "bootstrap/scss/variables-dark";
14
+ @import "bootstrap/scss/maps";
15
+ @import "bootstrap/scss/mixins";
16
+ @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";
@@ -0,0 +1,50 @@
1
+ @import "settings";
2
+
3
+ @import "bootstrap/scss/mixins/banner";
4
+ @include bsBanner("");
5
+
6
+ // Bootstrap configuration
7
+ @import "bootstrap/scss/functions";
8
+ @import "bootstrap/scss/variables";
9
+ @import "bootstrap/scss/variables-dark";
10
+ @import "bootstrap/scss/maps";
11
+ @import "bootstrap/scss/mixins";
12
+ @import "bootstrap/scss/utilities";
13
+
14
+ // Bootstrap layout and standalone-only components
15
+ @import "bootstrap/scss/root";
16
+ @import "themes/standalone_root";
17
+ @import "bootstrap/scss/reboot";
18
+ @import "bootstrap/scss/type";
19
+ @import "bootstrap/scss/images";
20
+ @import "bootstrap/scss/containers";
21
+ @import "bootstrap/scss/grid";
22
+ @import "bootstrap/scss/forms/form-range";
23
+ @import "bootstrap/scss/forms/floating-labels";
24
+ @import "bootstrap/scss/transitions";
25
+ @import "bootstrap/scss/navbar";
26
+ @import "bootstrap/scss/progress";
27
+ @import "bootstrap/scss/list-group";
28
+ @import "bootstrap/scss/carousel";
29
+ @import "bootstrap/scss/spinners";
30
+ @import "bootstrap/scss/placeholders";
31
+
32
+ // Bootstrap helpers
33
+ @import "bootstrap/scss/helpers/clearfix";
34
+ @import "bootstrap/scss/helpers/colored-links";
35
+ @import "bootstrap/scss/helpers/focus-ring";
36
+ @import "bootstrap/scss/helpers/icon-link";
37
+ @import "bootstrap/scss/helpers/ratio";
38
+ @import "bootstrap/scss/helpers/position";
39
+ @import "bootstrap/scss/helpers/stacks";
40
+ @import "bootstrap/scss/helpers/visually-hidden";
41
+ @import "bootstrap/scss/helpers/stretched-link";
42
+ @import "bootstrap/scss/helpers/text-truncation";
43
+ @import "bootstrap/scss/helpers/vr";
44
+
45
+ // Bootstrap utilities
46
+ @import "bootstrap/scss/utilities/api";
47
+
48
+ @import "utilities/scroll_fade_primitives";
49
+ @import "components";
50
+ @import "foundations/overlay_backdrop";
@@ -0,0 +1,11 @@
1
+ // Moo buttons use a subtle transform for the pressed state, so Bootstrap's
2
+ // native inset shadow press effect is disabled at the source.
3
+ $btn-box-shadow: none !default;
4
+ $btn-focus-box-shadow: none !default;
5
+ $btn-active-box-shadow: none !default;
6
+
7
+ // Bootstrap validation icons are background images injected by the native
8
+ // validation mixin. Reference-style invalid fields use border/ring + error text
9
+ // without a trailing status glyph, so disable the Bootstrap icon branch at the
10
+ // source while keeping .is-invalid/.invalid-feedback behavior.
11
+ $enable-validation-icons: false !default;