kmaterialize 2.3.3-1.0.31 → 2.3.3-1.0.32

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 (38) hide show
  1. package/components/appbar/appbar.css +48 -40
  2. package/components/appbar/navbar-auto-hide.scss +30 -0
  3. package/components/appbar/navbar-auto-hide.ts +88 -0
  4. package/components/appbar/navbar-content.scss +41 -41
  5. package/components/appbar/navbar-scroll.scss +13 -13
  6. package/components/appbar/navbar-tiny.scss +47 -0
  7. package/components/appbar/navbar-tiny.ts +92 -0
  8. package/components/appbar/navbarAutoHideSpec.js +72 -0
  9. package/components/appbar/navbarTinySpec.js +77 -0
  10. package/components/breadcrumb/_breadcrumb.scss +50 -1
  11. package/components/card/_cards.scss +178 -31
  12. package/components/card/cardsSpec.js +6 -16
  13. package/components/collapsible/_collapsible.scss +21 -4
  14. package/components/collapsible/collapsibleSpec.js +2 -1
  15. package/components/editor/_editor.scss +30 -1
  16. package/components/editor/editorSpec.js +41 -0
  17. package/components/footer/_footer.scss +37 -0
  18. package/components/gantt/_gantt.scss +183 -0
  19. package/components/gantt/gantt-connections.ts +121 -0
  20. package/components/gantt/gantt.ts +867 -0
  21. package/components/gantt/ganttSpec.js +751 -0
  22. package/components/list/_collection.scss +21 -5
  23. package/components/popup/_popup.scss +50 -0
  24. package/components/popup/popupSpec.js +61 -0
  25. package/components/tabs/_tabs.scss +1 -1
  26. package/components/timeline/_timeline.scss +97 -0
  27. package/dist/css/materialize.colors.min.css +1 -1
  28. package/dist/css/materialize.css +1633 -265
  29. package/dist/css/materialize.min.css +2 -2
  30. package/dist/css/materialize.min.css.map +1 -1
  31. package/dist/js/materialize.cjs.js +1190 -2
  32. package/dist/js/materialize.d.ts +195 -3
  33. package/dist/js/materialize.js +1190 -2
  34. package/dist/js/materialize.min.js +3 -3
  35. package/dist/js/materialize.mjs +1188 -3
  36. package/package.json +1 -1
  37. package/sass/_global.scss +6 -4
  38. package/sass/materialize.scss +7 -0
@@ -20,6 +20,8 @@
20
20
  }
21
21
 
22
22
  .navbar {
23
+ border: 0;
24
+ border-radius: 0;
23
25
  color: var(--md-sys-color-on-primary);
24
26
  background-color: var(--md-sys-color-secondary-container);
25
27
  width: 100%;
@@ -150,14 +152,14 @@
150
152
  /* Collision-safe centered app bar: the left link region and the generated
151
153
  right spacer share the available width, keeping the logo truly centered
152
154
  without taking it out of the flex layout. */
153
- .navbar.appbar-bordered .nav-wrapper.nav-wrapper-centered::after {
155
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper.nav-wrapper-centered::after {
154
156
  content: '';
155
157
  order: 3;
156
158
  flex: 1 1 0;
157
159
  min-width: 0;
158
160
  }
159
161
 
160
- .navbar.appbar-bordered .nav-wrapper.nav-wrapper-centered > ul {
162
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper.nav-wrapper-centered > ul {
161
163
  order: 1;
162
164
  flex: 1 1 0;
163
165
  min-width: 0;
@@ -166,15 +168,15 @@
166
168
  scrollbar-width: none;
167
169
  }
168
170
 
169
- .navbar.appbar-bordered .nav-wrapper.nav-wrapper-centered > ul::-webkit-scrollbar {
171
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper.nav-wrapper-centered > ul::-webkit-scrollbar {
170
172
  display: none;
171
173
  }
172
174
 
173
- .navbar.appbar-bordered .nav-wrapper.nav-wrapper-centered > ul > li > a {
175
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper.nav-wrapper-centered > ul > li > a {
174
176
  white-space: nowrap;
175
177
  }
176
178
 
177
- .navbar.appbar-bordered .nav-wrapper.nav-wrapper-centered > .brand-logo.center {
179
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper.nav-wrapper-centered > .brand-logo.center {
178
180
  position: static;
179
181
  order: 2;
180
182
  flex: 0 0 auto;
@@ -206,23 +208,29 @@
206
208
 
207
209
  /* Structured MD3 app-bar content. These hooks keep branded demos and app
208
210
  shells from falling back to bare, loosely spaced anchor elements. */
209
- .navbar.appbar-bordered {
211
+ .navbar:is(.appbar, .appbar-bordered) {
210
212
  overflow: visible;
211
213
  background: var(--md-sys-color-surface-variant);
212
- border: 1px solid var(--md-sys-color-outline-variant);
214
+ border: 0;
213
215
  border-radius: 0;
214
- box-shadow: 0 1px 2px color-mix(in srgb, var(--md-sys-color-shadow) 18%, transparent);
216
+ box-shadow: none;
217
+ }
218
+
219
+ /* Retain the original class as an explicit outline option. */
220
+ .navbar.appbar-bordered {
221
+ border: 1px solid var(--md-sys-color-outline-variant);
215
222
  }
216
223
 
217
224
  /* Layout variants. `navbar-rounded` adds the inset treatment; use
218
225
  `navbar-full` for a flush, full-width rectangle. */
219
- .navbar.appbar-bordered.navbar-rounded {
226
+ .navbar:is(.appbar, .appbar-bordered).navbar-rounded {
220
227
  margin: 8px 0;
221
228
  padding: 4px;
222
229
  border-radius: 16px;
230
+ box-shadow: 0 1px 2px color-mix(in srgb, var(--md-sys-color-shadow) 18%, transparent);
223
231
  }
224
232
 
225
- .navbar.appbar-bordered.navbar-full {
233
+ .navbar:is(.appbar, .appbar-bordered).navbar-full {
226
234
  width: 100%;
227
235
  margin: 0;
228
236
  padding: 0;
@@ -233,21 +241,21 @@
233
241
 
234
242
  /* Extended app bars may contain tabs and a halfway FAB. Keep the rounded
235
243
  surface on its children, but let the FAB extend below the bar. */
236
- .navbar.appbar-bordered.nav-extended {
244
+ .navbar:is(.appbar, .appbar-bordered).nav-extended {
237
245
  overflow: visible;
238
246
  }
239
247
 
240
- .navbar.appbar-bordered.nav-extended.navbar-rounded .nav-wrapper {
248
+ .navbar:is(.appbar, .appbar-bordered).nav-extended.navbar-rounded .nav-wrapper {
241
249
  border-radius: 15px 15px 0 0;
242
250
  }
243
251
 
244
- .navbar.appbar-bordered.nav-extended.navbar-rounded .nav-content {
252
+ .navbar:is(.appbar, .appbar-bordered).nav-extended.navbar-rounded .nav-content {
245
253
  color: var(--md-sys-color-on-surface);
246
254
  background: var(--md-sys-color-surface-variant);
247
255
  border-radius: 0 0 15px 15px;
248
256
  }
249
257
 
250
- .navbar.appbar-bordered .nav-wrapper {
258
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper {
251
259
  gap: 12px;
252
260
  padding-inline: 12px;
253
261
  background: var(--md-sys-color-surface-variant);
@@ -258,40 +266,40 @@
258
266
  scrollbar-width: none;
259
267
  }
260
268
 
261
- .navbar.appbar-bordered .nav-wrapper > .brand-logo,
262
- .navbar.appbar-bordered .nav-wrapper > ul:not(.dropdown-content),
263
- .navbar.appbar-bordered .nav-actions > li {
269
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > .brand-logo,
270
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul:not(.dropdown-content),
271
+ .navbar:is(.appbar, .appbar-bordered) .nav-actions > li {
264
272
  align-self: center;
265
273
  }
266
274
 
267
- .navbar.appbar-bordered:not(.nav-extended) .nav-wrapper > .brand-logo,
268
- .navbar.appbar-bordered:not(.nav-extended) .nav-wrapper > ul:not(.dropdown-content),
269
- .navbar.appbar-bordered:not(.nav-extended) .nav-wrapper > ul:not(.dropdown-content) > li {
275
+ .navbar:is(.appbar, .appbar-bordered):not(.nav-extended) .nav-wrapper > .brand-logo,
276
+ .navbar:is(.appbar, .appbar-bordered):not(.nav-extended) .nav-wrapper > ul:not(.dropdown-content),
277
+ .navbar:is(.appbar, .appbar-bordered):not(.nav-extended) .nav-wrapper > ul:not(.dropdown-content) > li {
270
278
  height: 40px;
271
279
  }
272
280
 
273
- .navbar.appbar-bordered .nav-actions > li {
281
+ .navbar:is(.appbar, .appbar-bordered) .nav-actions > li {
274
282
  display: flex;
275
283
  align-items: center;
276
284
  }
277
285
 
278
- .navbar.appbar-bordered .nav-wrapper::-webkit-scrollbar {
286
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper::-webkit-scrollbar {
279
287
  display: none;
280
288
  }
281
289
 
282
- .navbar.appbar-bordered .nav-wrapper > ul:not(.dropdown-content) {
290
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul:not(.dropdown-content) {
283
291
  min-width: 0;
284
292
  flex-shrink: 1;
285
293
  }
286
294
 
287
- .navbar.appbar-bordered.navbar-wrap .nav-wrapper {
295
+ .navbar:is(.appbar, .appbar-bordered).navbar-wrap .nav-wrapper {
288
296
  flex-wrap: wrap;
289
297
  height: auto;
290
298
  row-gap: 8px;
291
299
  overflow: visible;
292
300
  }
293
301
 
294
- .navbar.appbar-bordered.navbar-wrap .nav-wrapper > ul:not(.dropdown-content) {
302
+ .navbar:is(.appbar, .appbar-bordered).navbar-wrap .nav-wrapper > ul:not(.dropdown-content) {
295
303
  flex-wrap: wrap;
296
304
  white-space: normal;
297
305
  }
@@ -325,7 +333,7 @@
325
333
  gap: 8px;
326
334
  }
327
335
 
328
- .navbar.appbar-bordered ul:not(.dropdown-content):not(.nav-actions):not(.tabs) > li > a:not(.btn):not(.btn-floating) {
336
+ .navbar:is(.appbar, .appbar-bordered) ul:not(.dropdown-content):not(.nav-actions):not(.tabs) > li > a:not(.btn):not(.btn-floating) {
329
337
  box-sizing: border-box;
330
338
  height: 40px;
331
339
  padding-inline: 12px;
@@ -333,11 +341,11 @@
333
341
  border-radius: 20px;
334
342
  }
335
343
 
336
- .navbar.appbar-bordered ul:not(.dropdown-content):not(.nav-actions):not(.tabs) > li > a:not(.btn):not(.btn-floating):hover {
344
+ .navbar:is(.appbar, .appbar-bordered) ul:not(.dropdown-content):not(.nav-actions):not(.tabs) > li > a:not(.btn):not(.btn-floating):hover {
337
345
  background: color-mix(in srgb, var(--md-sys-color-on-surface) 8%, transparent);
338
346
  }
339
347
 
340
- .navbar.appbar-bordered ul:not(.dropdown-content):not(.nav-actions):not(.tabs) > li.active > a:not(.btn):not(.btn-floating) {
348
+ .navbar:is(.appbar, .appbar-bordered) ul:not(.dropdown-content):not(.nav-actions):not(.tabs) > li.active > a:not(.btn):not(.btn-floating) {
341
349
  color: var(--md-sys-color-on-primary-container);
342
350
  background: var(--md-sys-color-primary-container);
343
351
  }
@@ -345,9 +353,9 @@
345
353
  /* Text links use the same centred row as the app bar. The global navbar icon
346
354
  rule intentionally sizes standalone icons to the full bar; undo that for
347
355
  icons embedded beside link text. */
348
- .navbar.appbar-bordered ul:not(.dropdown-content):not(.tabs) > li > a:not(.btn):not(.btn-floating):has(> .material-icons.left),
349
- .navbar.appbar-bordered ul:not(.dropdown-content):not(.tabs) > li > a:not(.btn):not(.btn-floating):has(> .material-icons.right),
350
- .navbar.appbar-bordered .dropdown-trigger:has(> .material-icons) {
356
+ .navbar:is(.appbar, .appbar-bordered) ul:not(.dropdown-content):not(.tabs) > li > a:not(.btn):not(.btn-floating):has(> .material-icons.left),
357
+ .navbar:is(.appbar, .appbar-bordered) ul:not(.dropdown-content):not(.tabs) > li > a:not(.btn):not(.btn-floating):has(> .material-icons.right),
358
+ .navbar:is(.appbar, .appbar-bordered) .dropdown-trigger:has(> .material-icons) {
351
359
  display: inline-flex;
352
360
  align-items: center;
353
361
  gap: 8px;
@@ -356,25 +364,25 @@
356
364
  line-height: 1;
357
365
  }
358
366
 
359
- .navbar.appbar-bordered ul:not(.dropdown-content):not(.tabs) > li > a > .material-icons:is(.left, .right) {
367
+ .navbar:is(.appbar, .appbar-bordered) ul:not(.dropdown-content):not(.tabs) > li > a > .material-icons:is(.left, .right) {
360
368
  width: 24px;
361
369
  height: 24px;
362
370
  margin: 0;
363
371
  line-height: 24px;
364
372
  }
365
373
 
366
- .navbar.appbar-bordered ul:not(.dropdown-content):not(.tabs) > li > a > .material-icons.right {
374
+ .navbar:is(.appbar, .appbar-bordered) ul:not(.dropdown-content):not(.tabs) > li > a > .material-icons.right {
367
375
  order: 1;
368
376
  }
369
377
 
370
378
  /* Tabs retain their component geometry and click target instead of inheriting
371
379
  navigation-pill spacing. */
372
- .navbar.appbar-bordered .tabs {
380
+ .navbar:is(.appbar, .appbar-bordered) .tabs {
373
381
  gap: 0;
374
382
  background: transparent;
375
383
  }
376
384
 
377
- .navbar.appbar-bordered .tabs .tab > a {
385
+ .navbar:is(.appbar, .appbar-bordered) .tabs .tab > a {
378
386
  height: 48px;
379
387
  min-height: 48px;
380
388
  padding-inline: 24px;
@@ -384,7 +392,7 @@
384
392
 
385
393
  /* Buttons must remain legible and vertically centred in the constrained app
386
394
  bar row, including legacy examples using btn-large. */
387
- .navbar.appbar-bordered ul:not(.dropdown-content) > li > :is(.btn, .btn-large) {
395
+ .navbar:is(.appbar, .appbar-bordered) ul:not(.dropdown-content) > li > :is(.btn, .btn-large) {
388
396
  box-sizing: border-box;
389
397
  max-height: 48px;
390
398
  margin: 0;
@@ -396,7 +404,7 @@
396
404
  gap: 8px;
397
405
  }
398
406
 
399
- .navbar.appbar-bordered ul:not(.dropdown-content) > li > :is(.btn, .btn-large) > .material-icons {
407
+ .navbar:is(.appbar, .appbar-bordered) ul:not(.dropdown-content) > li > :is(.btn, .btn-large) > .material-icons {
400
408
  flex: 0 0 20px;
401
409
  width: 20px;
402
410
  height: 20px;
@@ -404,19 +412,19 @@
404
412
  line-height: 20px;
405
413
  }
406
414
 
407
- .navbar.appbar-bordered .dropdown-trigger {
415
+ .navbar:is(.appbar, .appbar-bordered) .dropdown-trigger {
408
416
  flex: 0 0 auto;
409
417
  white-space: nowrap;
410
418
  }
411
419
 
412
- .navbar.appbar-bordered ul:not(.dropdown-content) > li > a:has(> .material-icons:only-child) {
420
+ .navbar:is(.appbar, .appbar-bordered) ul:not(.dropdown-content) > li > a:has(> .material-icons:only-child) {
413
421
  display: grid;
414
422
  place-items: center;
415
423
  width: 40px;
416
424
  padding: 0;
417
425
  }
418
426
 
419
- .navbar.appbar-bordered ul:not(.dropdown-content) > li > a:has(> .material-icons:only-child) > .material-icons {
427
+ .navbar:is(.appbar, .appbar-bordered) ul:not(.dropdown-content) > li > a:has(> .material-icons:only-child) > .material-icons {
420
428
  width: 24px;
421
429
  height: 24px;
422
430
  line-height: 24px;
@@ -0,0 +1,30 @@
1
+ // Sticky positioning preserves the navbar's space without a fixed-height spacer.
2
+ .navbar.navbar-hide-on-scroll {
3
+ position: sticky;
4
+ top: var(--navbar-hide-offset, 0px);
5
+ z-index: 997;
6
+ translate: 0 0;
7
+ transition: translate 180ms ease;
8
+
9
+ &.is-navbar-hidden {
10
+ translate: 0 calc(-100% - var(--navbar-hide-offset, 0px) - 2px);
11
+ pointer-events: none;
12
+ }
13
+
14
+ // Keep offscreen links reachable by Tab, and reveal them immediately on focus.
15
+ &:focus-within { translate: 0 0; pointer-events: auto; transition: none; }
16
+ }
17
+
18
+ // Preserve sticky positioning when horizontal overflow styles are also enabled.
19
+ .navbar.navbar-hide-on-scroll.navbar-scroll { position: sticky; }
20
+
21
+ // Retain the existing fixed-navbar wrapper behavior.
22
+ .navbar-fixed > .navbar.navbar-hide-on-scroll { position: fixed; }
23
+
24
+ @media (prefers-reduced-motion: reduce) {
25
+ .navbar.navbar-hide-on-scroll { transition: none; }
26
+ }
27
+
28
+ @media print {
29
+ .navbar.navbar-hide-on-scroll, .navbar-fixed > .navbar.navbar-hide-on-scroll { position: static; translate: none; }
30
+ }
@@ -0,0 +1,88 @@
1
+ import { BaseOptions, Component, InitElements, MElement } from '../../src/component';
2
+
3
+ export interface NavbarAutoHideOptions extends BaseOptions {
4
+ /** Null watches the page. Supply an element for an independently scrolling panel. */
5
+ scrollTarget: HTMLElement | null;
6
+ /** Accumulated pixels in one direction before changing visibility. */
7
+ tolerance: number;
8
+ /** Keep the navbar visible within this many pixels of the top. */
9
+ offset: number;
10
+ }
11
+
12
+ /** A sticky navbar that hides going down and returns going up. */
13
+ export class NavbarAutoHide extends Component<NavbarAutoHideOptions> {
14
+ private _target: HTMLElement | Window;
15
+ private _events = new AbortController();
16
+ private _frame = 0;
17
+ private _last = 0;
18
+ private _distance = 0;
19
+ private _direction = 0;
20
+ private _originalClasses: string[];
21
+
22
+ constructor(el: HTMLElement, options: Partial<NavbarAutoHideOptions> = {}) {
23
+ const settings = { ...NavbarAutoHide.defaults, ...options };
24
+ if (!Number.isFinite(settings.tolerance) || settings.tolerance < 0) throw new Error('Navbar scroll tolerance must be a non-negative number.');
25
+ if (!Number.isFinite(settings.offset) || settings.offset < 0) throw new Error('Navbar scroll offset must be a non-negative number.');
26
+ if (settings.scrollTarget !== null && !(settings.scrollTarget instanceof HTMLElement)) throw new Error('Navbar scrollTarget must be an HTMLElement or null.');
27
+ super(el, options, NavbarAutoHide);
28
+ this.options = settings;
29
+ this._target = settings.scrollTarget || window;
30
+ this._originalClasses = ['navbar-hide-on-scroll', 'is-navbar-hidden'].filter(name => el.classList.contains(name));
31
+ el.classList.add('navbar-hide-on-scroll');
32
+ el.classList.remove('is-navbar-hidden');
33
+ el['M_NavbarAutoHide'] = this;
34
+ this._last = this._position();
35
+ const signal = this._events.signal;
36
+ this._target.addEventListener('scroll', this._schedule, { passive: true, signal });
37
+ window.addEventListener('resize', this._reset, { signal });
38
+ window.addEventListener('pageshow', this._reset, { signal });
39
+ el.addEventListener('focusin', this._reset, { signal });
40
+ el.addEventListener('focusout', this._reset, { signal });
41
+ }
42
+
43
+ static get defaults(): NavbarAutoHideOptions { return { scrollTarget: null, tolerance: 4, offset: 0 }; }
44
+ static init(el: HTMLElement, options?: Partial<NavbarAutoHideOptions>): NavbarAutoHide;
45
+ static init(els: InitElements<MElement>, options?: Partial<NavbarAutoHideOptions>): NavbarAutoHide[];
46
+ static init(els: HTMLElement | InitElements<MElement>, options: Partial<NavbarAutoHideOptions> = {}): NavbarAutoHide | NavbarAutoHide[] {
47
+ return super.init(els, options, NavbarAutoHide);
48
+ }
49
+ static getInstance(el: HTMLElement): NavbarAutoHide { return el['M_NavbarAutoHide']; }
50
+
51
+ private _position(): number {
52
+ const target = this.options.scrollTarget;
53
+ const max = target ? target.scrollHeight - target.clientHeight : (document.scrollingElement?.scrollHeight || 0) - window.innerHeight;
54
+ return Math.max(0, Math.min(Math.max(0, max), target ? target.scrollTop : window.scrollY));
55
+ }
56
+
57
+ private _reset = (): void => {
58
+ cancelAnimationFrame(this._frame); this._frame = 0;
59
+ this._last = this._position(); this._distance = 0; this._direction = 0;
60
+ this.el.classList.remove('is-navbar-hidden');
61
+ };
62
+
63
+ private _schedule = (): void => {
64
+ if (!this._frame) this._frame = requestAnimationFrame(this._update);
65
+ };
66
+
67
+ private _update = (): void => {
68
+ this._frame = 0;
69
+ const position = this._position(), delta = position - this._last;
70
+ this._last = position;
71
+ if (position <= this.options.offset || this.el.contains(document.activeElement)) { this._reset(); return; }
72
+ if (!delta) return;
73
+ const direction = Math.sign(delta);
74
+ if (direction !== this._direction) this._distance = 0;
75
+ this._direction = direction;
76
+ this._distance += Math.abs(delta);
77
+ if (this._distance >= this.options.tolerance) {
78
+ this.el.classList.toggle('is-navbar-hidden', direction > 0);
79
+ this._distance = 0;
80
+ }
81
+ };
82
+
83
+ destroy(): void {
84
+ this._events.abort(); cancelAnimationFrame(this._frame);
85
+ for (const name of ['navbar-hide-on-scroll', 'is-navbar-hidden']) this.el.classList.toggle(name, this._originalClasses.includes(name));
86
+ delete this.el['M_NavbarAutoHide'];
87
+ }
88
+ }
@@ -14,7 +14,7 @@
14
14
  }
15
15
 
16
16
  /* Inset surfaces retain their height at desktop and mobile sizes. */
17
- .navbar.appbar-bordered.navbar-rounded:not(.nav-extended):not(.navbar-wrap) {
17
+ .navbar:is(.appbar, .appbar-bordered).navbar-rounded:not(.nav-extended):not(.navbar-wrap) {
18
18
  box-sizing: border-box;
19
19
  height: 64px;
20
20
  margin: 8px 0;
@@ -23,7 +23,7 @@
23
23
  overflow: hidden;
24
24
  }
25
25
 
26
- .navbar.appbar-bordered.navbar-rounded:not(.nav-extended):not(.navbar-wrap) > .nav-wrapper {
26
+ .navbar:is(.appbar, .appbar-bordered).navbar-rounded:not(.nav-extended):not(.navbar-wrap) > .nav-wrapper {
27
27
  box-sizing: border-box;
28
28
  flex: 0 0 56px;
29
29
  height: 56px;
@@ -31,7 +31,7 @@
31
31
  transform: none;
32
32
  }
33
33
 
34
- .navbar.appbar-bordered.navbar-full {
34
+ .navbar:is(.appbar, .appbar-bordered).navbar-full {
35
35
  width: 100%;
36
36
  margin: 0;
37
37
  padding: 0;
@@ -42,7 +42,7 @@
42
42
 
43
43
  /* Dropdown triggers: keep the label and arrow in one predictable hit
44
44
  target instead of inheriting the legacy floated-icon offsets. */
45
- .navbar.appbar-bordered .dropdown-trigger {
45
+ .navbar:is(.appbar, .appbar-bordered) .dropdown-trigger {
46
46
  display: inline-flex !important;
47
47
  align-items: center;
48
48
  justify-content: center;
@@ -55,7 +55,7 @@
55
55
  line-height: 1;
56
56
  }
57
57
 
58
- .navbar.appbar-bordered .dropdown-trigger > .material-icons {
58
+ .navbar:is(.appbar, .appbar-bordered) .dropdown-trigger > .material-icons {
59
59
  display: inline-block !important;
60
60
  position: static !important;
61
61
  float: none !important;
@@ -66,7 +66,7 @@
66
66
  transition: transform 160ms ease;
67
67
  }
68
68
 
69
- .navbar.appbar-bordered .nav-wrapper > ul > li:has(> .dropdown-trigger) {
69
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li:has(> .dropdown-trigger) {
70
70
  flex: 0 0 auto;
71
71
  display: flex;
72
72
  align-items: center;
@@ -75,18 +75,18 @@
75
75
  padding: 0;
76
76
  }
77
77
 
78
- .navbar.appbar-bordered .nav-wrapper > ul > li:has(> .dropdown-trigger) > .dropdown-trigger {
78
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li:has(> .dropdown-trigger) > .dropdown-trigger {
79
79
  flex: 0 0 auto;
80
80
  align-self: center;
81
81
  margin: 0;
82
82
  }
83
83
 
84
- .navbar.appbar-bordered .dropdown-trigger[aria-expanded="true"] > .material-icons.right {
84
+ .navbar:is(.appbar, .appbar-bordered) .dropdown-trigger[aria-expanded="true"] > .material-icons.right {
85
85
  transform: rotate(180deg);
86
86
  }
87
87
 
88
88
  /* Icon links: center standalone icons inside their 40px hit targets. */
89
- .navbar.appbar-bordered .nav-wrapper > ul > li:has(> a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger) > .material-icons:only-child) {
89
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li:has(> a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger) > .material-icons:only-child) {
90
90
  display: flex;
91
91
  align-items: center;
92
92
  justify-content: center;
@@ -97,7 +97,7 @@
97
97
  padding: 0;
98
98
  }
99
99
 
100
- .navbar.appbar-bordered .nav-wrapper > ul > li > a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger):has(> .material-icons:only-child) {
100
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li > a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger):has(> .material-icons:only-child) {
101
101
  display: inline-grid !important;
102
102
  place-items: center;
103
103
  box-sizing: border-box;
@@ -108,7 +108,7 @@
108
108
  line-height: 1;
109
109
  }
110
110
 
111
- .navbar.appbar-bordered .nav-wrapper > ul > li > a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger) > .material-icons:only-child {
111
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li > a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger) > .material-icons:only-child {
112
112
  display: block !important;
113
113
  position: static !important;
114
114
  float: none !important;
@@ -119,8 +119,8 @@
119
119
  text-align: center;
120
120
  }
121
121
 
122
- .navbar.appbar-bordered .nav-wrapper > ul > li > a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger):has(> .material-icons.left),
123
- .navbar.appbar-bordered .nav-wrapper > ul > li > a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger):has(> .material-icons.right) {
122
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li > a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger):has(> .material-icons.left),
123
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li > a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger):has(> .material-icons.right) {
124
124
  display: inline-flex !important;
125
125
  align-items: center;
126
126
  gap: 8px;
@@ -134,8 +134,8 @@
134
134
  white-space: nowrap;
135
135
  }
136
136
 
137
- .navbar.appbar-bordered .nav-wrapper > ul > li > a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger) > .material-icons.left,
138
- .navbar.appbar-bordered .nav-wrapper > ul > li > a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger) > .material-icons.right {
137
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li > a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger) > .material-icons.left,
138
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li > a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger) > .material-icons.right {
139
139
  display: block !important;
140
140
  position: static !important;
141
141
  float: none !important;
@@ -147,8 +147,8 @@
147
147
  text-align: center;
148
148
  }
149
149
 
150
- .navbar.appbar-bordered .nav-wrapper > ul > li:has(> a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger) > .material-icons.left),
151
- .navbar.appbar-bordered .nav-wrapper > ul > li:has(> a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger) > .material-icons.right) {
150
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li:has(> a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger) > .material-icons.left),
151
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li:has(> a:not(.btn):not(.btn-large):not(.btn-floating):not(.dropdown-trigger) > .material-icons.right) {
152
152
  flex: 0 0 auto;
153
153
  width: max-content;
154
154
  height: 40px;
@@ -156,7 +156,7 @@
156
156
 
157
157
  /* Button rows: normalize the item row and prevent text-plus-icon buttons
158
158
  from being mistaken for standalone icon buttons. */
159
- .navbar.appbar-bordered .nav-wrapper > ul > li:has(> :is(.btn, .btn-large)) {
159
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li:has(> :is(.btn, .btn-large)) {
160
160
  display: flex;
161
161
  align-items: center;
162
162
  flex: 0 0 auto;
@@ -165,8 +165,8 @@
165
165
  padding: 0;
166
166
  }
167
167
 
168
- .navbar.appbar-bordered .nav-wrapper > ul > li > a.btn,
169
- .navbar.appbar-bordered .nav-wrapper > ul > li > a.btn-large {
168
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li > a.btn,
169
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li > a.btn-large {
170
170
  display: inline-flex !important;
171
171
  align-items: center;
172
172
  justify-content: center;
@@ -181,20 +181,20 @@
181
181
  white-space: nowrap;
182
182
  }
183
183
 
184
- .navbar.appbar-bordered .nav-wrapper > ul > li > a.btn-large {
184
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li > a.btn-large {
185
185
  min-width: 144px;
186
186
  height: 48px;
187
187
  min-height: 48px;
188
188
  padding-inline: 24px !important;
189
189
  }
190
190
 
191
- .navbar.appbar-bordered .nav-wrapper > ul > li > a.btn:has(> .material-icons),
192
- .navbar.appbar-bordered .nav-wrapper > ul > li > a.btn-large:has(> .material-icons) {
191
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li > a.btn:has(> .material-icons),
192
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li > a.btn-large:has(> .material-icons) {
193
193
  gap: 8px;
194
194
  }
195
195
 
196
- .navbar.appbar-bordered .nav-wrapper > ul > li > a.btn > .material-icons,
197
- .navbar.appbar-bordered .nav-wrapper > ul > li > a.btn-large > .material-icons {
196
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li > a.btn > .material-icons,
197
+ .navbar:is(.appbar, .appbar-bordered) .nav-wrapper > ul > li > a.btn-large > .material-icons {
198
198
  display: block !important;
199
199
  position: static !important;
200
200
  float: none !important;
@@ -207,32 +207,32 @@
207
207
 
208
208
  /* Extended navbar tabs: use the navbar's readable foreground instead of the
209
209
  low-contrast primary token inherited by transparent tabs. */
210
- .navbar.appbar-bordered .nav-content,
211
- .navbar.appbar-bordered .nav-content .tabs {
210
+ .navbar:is(.appbar, .appbar-bordered) .nav-content,
211
+ .navbar:is(.appbar, .appbar-bordered) .nav-content .tabs {
212
212
  background: var(--md-sys-color-surface-variant);
213
213
  }
214
214
 
215
- .navbar.appbar-bordered .nav-content .tabs > .tab > a {
215
+ .navbar:is(.appbar, .appbar-bordered) .nav-content .tabs > .tab > a {
216
216
  color: var(--md-sys-color-on-surface) !important;
217
217
  opacity: 0.92;
218
218
  }
219
219
 
220
- .navbar.appbar-bordered .nav-content .tabs > .tab > a.active {
220
+ .navbar:is(.appbar, .appbar-bordered) .nav-content .tabs > .tab > a.active {
221
221
  color: var(--md-sys-color-on-surface) !important;
222
222
  opacity: 1;
223
223
  font-weight: 600;
224
224
  }
225
225
 
226
- .navbar.appbar-bordered .nav-content .tabs > .tab.disabled > a {
226
+ .navbar:is(.appbar, .appbar-bordered) .nav-content .tabs > .tab.disabled > a {
227
227
  color: var(--md-sys-color-on-surface) !important;
228
228
  opacity: 0.5;
229
229
  }
230
230
 
231
- .navbar.appbar-bordered .nav-content .tabs > .indicator {
231
+ .navbar:is(.appbar, .appbar-bordered) .nav-content .tabs > .indicator {
232
232
  background-color: var(--md-sys-color-on-surface) !important;
233
233
  }
234
234
 
235
- .navbar.appbar-bordered .sidenav-trigger {
235
+ .navbar:is(.appbar, .appbar-bordered) .sidenav-trigger {
236
236
  display: inline-flex !important;
237
237
  align-items: center;
238
238
  justify-content: center;
@@ -246,7 +246,7 @@
246
246
  color: var(--md-sys-color-on-surface) !important;
247
247
  }
248
248
 
249
- .navbar.appbar-bordered .sidenav-trigger > .material-icons {
249
+ .navbar:is(.appbar, .appbar-bordered) .sidenav-trigger > .material-icons {
250
250
  display: block !important;
251
251
  position: static !important;
252
252
  float: none !important;
@@ -257,7 +257,7 @@
257
257
  text-align: center;
258
258
  }
259
259
 
260
- .navbar.appbar-bordered.navbar-wrap > .nav-wrapper {
260
+ .navbar:is(.appbar, .appbar-bordered).navbar-wrap > .nav-wrapper {
261
261
  flex-wrap: wrap;
262
262
  height: auto;
263
263
  min-height: 56px;
@@ -266,12 +266,12 @@
266
266
  row-gap: 8px;
267
267
  }
268
268
 
269
- .navbar.appbar-bordered.navbar-wrap {
269
+ .navbar:is(.appbar, .appbar-bordered).navbar-wrap {
270
270
  height: auto;
271
271
  min-height: 56px;
272
272
  }
273
273
 
274
- .navbar.appbar-bordered.navbar-wrap > .nav-wrapper > ul:not(.dropdown-content) {
274
+ .navbar:is(.appbar, .appbar-bordered).navbar-wrap > .nav-wrapper > ul:not(.dropdown-content) {
275
275
  box-sizing: border-box;
276
276
  width: 100%;
277
277
  max-width: 100%;
@@ -283,15 +283,15 @@
283
283
  white-space: normal;
284
284
  }
285
285
 
286
- .navbar.appbar-bordered.navbar-wrap > .nav-wrapper > ul:not(.dropdown-content) > li {
286
+ .navbar:is(.appbar, .appbar-bordered).navbar-wrap > .nav-wrapper > ul:not(.dropdown-content) > li {
287
287
  height: auto !important;
288
288
  }
289
289
 
290
- .navbar.appbar-bordered ul:not(.dropdown-content) > li > a {
290
+ .navbar:is(.appbar, .appbar-bordered) ul:not(.dropdown-content) > li > a {
291
291
  white-space: nowrap;
292
292
  }
293
293
 
294
- .navbar.appbar-bordered:not(.navbar-wrap) .nav-wrapper > ul.ml-auto:not(.nav-actions):not(.dropdown-content) {
294
+ .navbar:is(.appbar, .appbar-bordered):not(.navbar-wrap) .nav-wrapper > ul.ml-auto:not(.nav-actions):not(.dropdown-content) {
295
295
  flex: 0 0 auto;
296
296
  width: max-content;
297
297
  max-width: none;
@@ -299,7 +299,7 @@
299
299
 
300
300
  /* Separators used as list items need an explicit display/height; otherwise
301
301
  navbar item rules can collapse the one-pixel divider. */
302
- .navbar.appbar-bordered .nav-actions > li.nav-separator {
302
+ .navbar:is(.appbar, .appbar-bordered) .nav-actions > li.nav-separator {
303
303
  display: block !important;
304
304
  flex: 0 0 1px;
305
305
  width: 1px;
@@ -313,5 +313,5 @@
313
313
  }
314
314
 
315
315
  @media (prefers-reduced-motion: reduce) {
316
- .navbar.appbar-bordered .dropdown-trigger > .material-icons { transition: none; }
316
+ .navbar:is(.appbar, .appbar-bordered) .dropdown-trigger > .material-icons { transition: none; }
317
317
  }