@wpmoo/ui 1.0.0-rc.7 → 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.
@@ -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
+ }
@@ -1,6 +1,6 @@
1
- // Inset Sidebar variant --------------------------------------------------
2
- // The Sidebar owns the navigation surface; the App root owns the sibling
3
- // page geometry. This variant only supplies the page-side visual treatment.
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
4
  @include media-breakpoint-up(lg) {
5
5
  .wrapper[data-layout="app"]:has(> .sidebar[data-variant="inset"]) {
6
6
  background: var(--moo-sidebar);
@@ -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
@@ -1,251 +0,0 @@
1
- // Bootstrap has no native sidebar, so this owned sidebar selector namespace
2
- // styles the app-shell primitive (same precedent as the avatar component).
3
- // Geometry rides the $moo-sidebar-* Sass knobs; every color consumes a
4
- // runtime --moo-* token.
5
-
6
- .wrapper[data-layout="app"] {
7
- display: flex;
8
- width: 100%;
9
- height: 100svh;
10
- min-height: 0;
11
- overflow: hidden;
12
- }
13
-
14
- .wrapper[data-layout="app"][data-shell-mode="contained"] {
15
- min-height: 0;
16
- height: 34rem;
17
- overflow: hidden;
18
- border: var(--bs-border-width) solid var(--moo-border);
19
- border-radius: var(--bs-border-radius-xl);
20
- }
21
-
22
- // Sidebar column ---------------------------------------------------------
23
- .sidebar {
24
- --moo-sidebar-width: #{$moo-sidebar-width};
25
- --moo-sidebar-width-icon: #{$moo-sidebar-width-icon};
26
- --bs-offcanvas-width: var(--moo-sidebar-width);
27
- flex: 0 0 var(--moo-sidebar-width);
28
- width: var(--moo-sidebar-width);
29
- color: var(--moo-sidebar-foreground);
30
- }
31
-
32
- .sidebar[data-side="left"] .sidebar-inner {
33
- // `side` is a physical placement contract. Keep the divider on the
34
- // Sidebar/Page boundary when the document direction is RTL as well.
35
- border-right: var(--bs-border-width) solid var(--moo-sidebar-border);
36
- }
37
-
38
- .sidebar[data-side="right"] {
39
- order: 1;
40
- }
41
-
42
- // `side` is a physical placement contract. `:dir()` reads the wrapper's
43
- // computed direction inside the owner scope, whether it comes from html for a
44
- // document owner or from an embedded owner's own dir attribute.
45
- .wrapper[data-layout="app"]:dir(rtl) > .sidebar[data-side="left"] {
46
- order: 1;
47
- }
48
-
49
- .wrapper[data-layout="app"]:dir(rtl) > .sidebar[data-side="right"] {
50
- order: 0;
51
- }
52
-
53
- .sidebar[data-side="right"] .sidebar-inner {
54
- border-left: var(--bs-border-width) solid var(--moo-sidebar-border);
55
- }
56
-
57
- // Floating variant: the surface detaches from the viewport edge with a
58
- // margin gap on every side and gains a full rounded border and shadow,
59
- // replacing the flush single-edge border the default variant uses. Scoped
60
- // to desktop, matching how the mobile offcanvas drawer ignores variant.
61
- @include media-breakpoint-up(lg) {
62
- .sidebar {
63
- transition: flex-basis 0.2s ease, width 0.2s ease;
64
- }
65
-
66
- .sidebar[data-variant="floating"] .sidebar-inner {
67
- width: auto;
68
- height: calc(100svh - #{$spacer});
69
- max-height: calc(100svh - #{$spacer});
70
- margin: $spacer * 0.5;
71
- border: var(--bs-border-width) solid var(--moo-sidebar-border);
72
- border-radius: var(--bs-border-radius-lg);
73
- box-shadow: var(--bs-box-shadow-sm);
74
- }
75
-
76
- .wrapper[data-layout="app"][data-shell-mode="contained"] .sidebar[data-variant="floating"] .sidebar-inner {
77
- height: calc(100% - #{$spacer});
78
- max-height: calc(100% - #{$spacer});
79
- }
80
-
81
- // At icon-rail width the detached card reads as floating mostly through
82
- // elevation and breathing room, since the margin/border alone are hard to
83
- // read at the base icon width; step up to Bootstrap's base shadow scale
84
- // (still a shared token, no new value) and widen the column by the same
85
- // margin the card's sides consume, so the icon rail itself keeps its full
86
- // width instead of shrinking.
87
- .wrapper[data-layout="app"][data-sidebar-state="collapsed"] .sidebar[data-variant="floating"][data-collapsible="icon"] {
88
- flex-basis: calc(var(--moo-sidebar-width-icon) + #{$spacer});
89
- width: calc(var(--moo-sidebar-width-icon) + #{$spacer});
90
- }
91
-
92
- .wrapper[data-layout="app"][data-sidebar-state="collapsed"] .sidebar[data-variant="floating"][data-collapsible="icon"] .sidebar-inner {
93
- box-shadow: var(--bs-box-shadow);
94
- }
95
- }
96
-
97
- @media (prefers-reduced-motion: reduce) {
98
- .sidebar {
99
- transition: none;
100
- }
101
- }
102
-
103
- .sidebar-inner {
104
- position: sticky;
105
- top: 0;
106
- display: flex;
107
- flex-direction: column;
108
- width: 100%;
109
- height: 100svh;
110
- max-height: 100svh;
111
- background: var(--moo-sidebar);
112
- }
113
-
114
- .wrapper[data-layout="app"][data-shell-mode="contained"] .sidebar-inner {
115
- position: relative;
116
- height: 100%;
117
- max-height: 100%;
118
- }
119
-
120
- .wrapper[data-layout="app"] > [data-slot="page"] {
121
- display: flex;
122
- min-width: 0;
123
- min-height: 0;
124
- flex: 1 1 auto;
125
- flex-direction: column;
126
- overflow-y: auto;
127
- }
128
-
129
- .wrapper[data-layout="app"] > [data-slot="page"] > header,
130
- .wrapper[data-layout="app"] > [data-slot="page"] > main,
131
- .wrapper[data-layout="app"] > [data-slot="page"] > footer {
132
- flex: 0 0 auto;
133
- }
134
-
135
- // The page main region owns the space between the optional header and footer.
136
- // Keep the Bootstrap rail as the flex column too, so app previews and real
137
- // shells can give their caller content a full-height surface without adding
138
- // layout-specific height values.
139
- .wrapper[data-layout="app"] > [data-slot="page"] > main {
140
- display: flex;
141
- min-height: 0;
142
- flex: 1 1 auto;
143
- flex-direction: column;
144
- }
145
-
146
- .wrapper[data-layout="app"] > [data-slot="page"] > main > :is(
147
- .container,
148
- .container-sm,
149
- .container-md,
150
- .container-lg,
151
- .container-xl,
152
- .container-xxl,
153
- .container-fluid
154
- ) {
155
- display: flex;
156
- min-height: 0;
157
- flex: 1 1 auto;
158
- flex-direction: column;
159
- }
160
-
161
- @include media-breakpoint-down(lg) {
162
- .wrapper[data-layout="app"][data-shell-mode="contained"] {
163
- flex-direction: column;
164
- height: auto;
165
- min-height: 0;
166
- overflow: visible;
167
- }
168
-
169
- .wrapper[data-layout="app"][data-shell-mode="contained"] > [data-slot="page"] {
170
- overflow: visible;
171
- }
172
- }
173
-
174
- .sidebar-header,
175
- .sidebar-footer {
176
- display: flex;
177
- flex-direction: column;
178
- gap: $spacer * 0.25;
179
- padding: $spacer * 0.5;
180
- }
181
-
182
- .sidebar-content {
183
- display: flex;
184
- flex: 1 1 auto;
185
- flex-direction: column;
186
- gap: $spacer * 0.5;
187
- min-height: 0;
188
- overflow-y: auto;
189
- }
190
-
191
- .sidebar-input {
192
- width: 100%;
193
- padding: $spacer * 0.25;
194
- }
195
-
196
- .sidebar-separator {
197
- display: flex;
198
- }
199
-
200
- .sidebar-menu-skeleton {
201
- display: flex;
202
- align-items: center;
203
- gap: $spacer * 0.25;
204
- min-height: $spacer * 2;
205
- padding-inline: $spacer * 0.5;
206
- }
207
-
208
- .sidebar-menu-skeleton__icon {
209
- width: $spacer;
210
- height: $spacer;
211
- }
212
-
213
- .sidebar-menu-skeleton__line {
214
- flex: 1 1 auto;
215
- }
216
-
217
- .sidebar-group {
218
- position: relative;
219
- display: flex;
220
- flex-direction: column;
221
- padding: $spacer * 0.5;
222
- }
223
-
224
- .sidebar-group-content {
225
- display: block;
226
- }
227
-
228
- .sidebar-group-content--inline {
229
- display: flex;
230
- align-items: center;
231
- flex-wrap: wrap;
232
- gap: $spacer * 0.25;
233
- }
234
-
235
- .sidebar-group-label {
236
- display: flex;
237
- align-items: center;
238
- height: $spacer * 2;
239
- padding-inline: $spacer * 0.5;
240
- color: var(--moo-muted-foreground);
241
- font-size: $font-size-base * 0.857;
242
- font-weight: $font-weight-medium;
243
- }
244
-
245
- // Reserve room so a long label doesn't run under the absolutely positioned
246
- // group action button (see .sidebar-group-action below). A descendant match
247
- // covers both a group action placed directly in .sidebar-group and one
248
- // nested inside .sidebar-group-content alongside the label.
249
- .sidebar-group:has(.sidebar-group-action) .sidebar-group-label {
250
- padding-inline-end: $spacer * 2.5;
251
- }