@expressivecss/expressive 0.8.0 → 0.9.0

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 (50) hide show
  1. package/CHANGELOG.md +48 -1
  2. package/README.md +69 -26
  3. package/dist/css/expressive.css +657 -85
  4. package/dist/css/expressive.css.map +1 -1
  5. package/dist/css/expressive.min.css +1 -1
  6. package/dist/css/expressive.min.css.map +1 -1
  7. package/dist/fonts/LICENSE-material-symbols +93 -0
  8. package/dist/fonts/LICENSE-noto-sans +93 -0
  9. package/dist/fonts/LICENSE-roboto +93 -0
  10. package/dist/fonts/material-symbols-outlined.woff2 +0 -0
  11. package/dist/fonts/material-symbols-rounded.woff2 +0 -0
  12. package/dist/fonts/material-symbols-sharp.woff2 +0 -0
  13. package/dist/fonts/noto-sans-latin-400.woff2 +0 -0
  14. package/dist/fonts/noto-sans-latin-500.woff2 +0 -0
  15. package/dist/fonts/roboto-latin-400.woff2 +0 -0
  16. package/dist/fonts/roboto-latin-500.woff2 +0 -0
  17. package/dist/js/expressive.cjs +501 -144
  18. package/dist/js/expressive.cjs.map +4 -4
  19. package/dist/js/expressive.js +501 -144
  20. package/dist/js/expressive.js.map +4 -4
  21. package/dist/js/expressive.min.js +10 -10
  22. package/dist/js/expressive.min.js.map +4 -4
  23. package/dist/js/expressive.mjs +501 -144
  24. package/dist/js/expressive.mjs.map +4 -4
  25. package/dist/types/components/appBar.d.ts +26 -0
  26. package/dist/types/components/buttonGroup.d.ts +39 -0
  27. package/dist/types/components/cards.d.ts +11 -13
  28. package/dist/types/components/expandingCard.d.ts +1 -1
  29. package/dist/types/components/index.d.ts +2 -0
  30. package/dist/types/components/menu.d.ts +4 -0
  31. package/dist/types/components/registry.d.ts +10 -0
  32. package/dist/types/components/timepicker.d.ts +0 -1
  33. package/dist/types/components/tooltip.d.ts +1 -0
  34. package/dist/types/index.d.ts +1 -1
  35. package/package.json +25 -3
  36. package/src/sass/abstracts/_mixins.scss +52 -0
  37. package/src/sass/abstracts/_variables.scss +19 -0
  38. package/src/sass/base/_fonts.scss +63 -0
  39. package/src/sass/components/_badges.scss +1 -2
  40. package/src/sass/components/_button-groups.scss +252 -80
  41. package/src/sass/components/_cards.scss +108 -93
  42. package/src/sass/components/_expanding-card.scss +1 -35
  43. package/src/sass/components/_icon-buttons.scss +2 -24
  44. package/src/sass/components/_icons-material-design.scss +6 -6
  45. package/src/sass/components/_navbar.scss +180 -27
  46. package/src/sass/components/_navigation-bar.scss +9 -1
  47. package/src/sass/components/_navigation-rail.scss +9 -1
  48. package/src/sass/components/_transitions.scss +8 -1
  49. package/src/sass/components/forms/_select.scss +38 -0
  50. package/src/sass/expressive.scss +5 -0
@@ -89,26 +89,27 @@ $_card: "article";
89
89
 
90
90
  :where(#{$_card}).filled {
91
91
  --md-comp-card-container-color: var(--md-comp-filled-card-container-color);
92
- @include z-depth("0");
92
+ box-shadow: none;
93
93
  }
94
94
 
95
95
  :where(#{$_card}).outlined,
96
96
  :where(#{$_card}).border {
97
97
  --md-comp-card-container-color: var(--md-comp-outlined-card-container-color);
98
- @include z-depth("0");
98
+ box-shadow: none;
99
99
  border: 1px solid var(--md-comp-outlined-card-outline-color);
100
100
  }
101
101
 
102
- // Hovered cards lift one level and apply an 8% on-surface state layer.
103
- :where(#{$_card}):not(.filled, .outlined, .border):has(> .primary-action:hover) {
102
+ // Hovered cards lift one level and apply an 8% on-surface state layer. Dragged
103
+ // and picked-up states take precedence over retained pointer state.
104
+ :where(#{$_card}):not(.dragged, .picked-up):not(.filled, .outlined, .border):has(> .primary-action:hover) {
104
105
  @include z-depth("2");
105
106
  }
106
107
 
107
- :where(#{$_card}):is(.filled, .outlined, .border):has(> .primary-action:hover) {
108
+ :where(#{$_card}):not(.dragged, .picked-up):is(.filled, .outlined, .border):has(> .primary-action:hover) {
108
109
  @include z-depth("1");
109
110
  }
110
111
 
111
- :where(#{$_card}):has(> .primary-action:hover)::after {
112
+ :where(#{$_card}):not(.dragged, .picked-up):has(> .primary-action:hover)::after {
112
113
  opacity: var(--md-comp-card-hover-state-layer-opacity);
113
114
  }
114
115
 
@@ -119,7 +120,7 @@ $_card: "article";
119
120
  outline-offset: var(--md-comp-card-focus-indicator-offset);
120
121
  }
121
122
 
122
- :where(#{$_card}):has(> .primary-action:focus-visible)::after {
123
+ :where(#{$_card}):not(.dragged, .picked-up):has(> .primary-action:focus-visible)::after {
123
124
  opacity: var(--md-comp-card-focus-state-layer-opacity);
124
125
  }
125
126
 
@@ -127,16 +128,31 @@ $_card: "article";
127
128
  border-color: var(--md-sys-color-on-surface);
128
129
  }
129
130
 
130
- :where(#{$_card}):has(> .primary-action:active)::after {
131
+ :where(#{$_card}):not(.dragged, .picked-up):has(> .primary-action:active)::after {
131
132
  opacity: var(--md-comp-card-pressed-state-layer-opacity);
132
133
  }
133
134
 
134
- // A reorder interaction toggles `.dragged`; every variant rises to level 3.
135
- :where(#{$_card}).dragged {
135
+ :where(#{$_card}):not(.dragged, .picked-up):not(.filled, .outlined, .border):has(> .primary-action:active) {
136
+ @include z-depth("1");
137
+ }
138
+
139
+ :where(#{$_card}):not(.dragged, .picked-up):is(.filled, .outlined, .border):has(> .primary-action:active) {
140
+ @include z-depth("0");
141
+ }
142
+
143
+ // A reorder interaction toggles `.dragged` or `.picked-up`. The elevated
144
+ // variant rises to level 4; filled and outlined variants rise to level 3.
145
+ :where(#{$_card}):not(.filled, .outlined, .border):is(.dragged, .picked-up) {
146
+ z-index: 4;
147
+ @include z-depth("4");
148
+ }
149
+
150
+ :where(#{$_card}):is(.filled, .outlined, .border):is(.dragged, .picked-up) {
151
+ z-index: 4;
136
152
  @include z-depth("3");
137
153
  }
138
154
 
139
- :where(#{$_card}).dragged::after {
155
+ :where(#{$_card}):is(.dragged, .picked-up)::after {
140
156
  opacity: var(--md-comp-card-dragged-state-layer-opacity);
141
157
  }
142
158
 
@@ -145,12 +161,12 @@ $_card: "article";
145
161
  // cards that do not use a link.
146
162
  :where(#{$_card}):is(.disabled, [aria-disabled="true"]),
147
163
  :where(#{$_card}):has(> .primary-action[aria-disabled="true"]) {
148
- @include z-depth("0");
149
164
  outline: 0;
150
165
  }
151
166
 
152
167
  :where(#{$_card}):not(.filled, .outlined, .border):is(.disabled, [aria-disabled="true"]),
153
168
  :where(#{$_card}):not(.filled, .outlined, .border):has(> .primary-action[aria-disabled="true"]) {
169
+ @include z-depth("1");
154
170
  background-color: color-mix(
155
171
  in oklab,
156
172
  var(--md-sys-color-surface) var(--md-comp-card-disabled-container-opacity),
@@ -160,15 +176,17 @@ $_card: "article";
160
176
 
161
177
  :where(#{$_card}).filled:is(.disabled, [aria-disabled="true"]),
162
178
  :where(#{$_card}).filled:has(> .primary-action[aria-disabled="true"]) {
179
+ @include z-depth("0");
163
180
  background-color: color-mix(
164
181
  in oklab,
165
- var(--md-sys-color-on-surface) var(--md-comp-card-disabled-container-opacity),
182
+ var(--md-sys-color-surface-variant) var(--md-comp-card-disabled-container-opacity),
166
183
  transparent
167
184
  );
168
185
  }
169
186
 
170
187
  :where(#{$_card}):is(.outlined, .border):is(.disabled, [aria-disabled="true"]),
171
188
  :where(#{$_card}):is(.outlined, .border):has(> .primary-action[aria-disabled="true"]) {
189
+ @include z-depth("0");
172
190
  background-color: var(--md-comp-outlined-card-container-color);
173
191
  border-color: color-mix(
174
192
  in oklab,
@@ -331,8 +349,8 @@ article > .primary-action > figure > figcaption > svg {
331
349
 
332
350
  // Collections are a grid by default. The full track definition is a token so
333
351
  // applications can supply fixed, responsive, or asymmetric columns without
334
- // fighting component selectors. Every card rests on the same plane; only the
335
- // picked-up / dragged state rises above its neighbours.
352
+ // fighting component selectors. Each card keeps its variant-specific resting
353
+ // elevation; picked-up / dragged state raises each variant above its rest.
336
354
  :where(.card-collection) {
337
355
  --md-comp-card-collection-gap: 8px;
338
356
  --md-comp-card-collection-min-card-width: 240px;
@@ -340,11 +358,6 @@ article > .primary-action > figure > figcaption > svg {
340
358
  auto-fit,
341
359
  minmax(min(100%, var(--md-comp-card-collection-min-card-width)), 1fr)
342
360
  );
343
- --md-comp-card-collection-resting-shadow: none;
344
- --md-comp-card-collection-picked-up-shadow:
345
- 0 8px 17px 2px rgba(0, 0, 0, 0.14),
346
- 0 3px 14px 2px rgba(0, 0, 0, 0.12),
347
- 0 5px 5px -3px rgba(0, 0, 0, 0.2);
348
361
  --md-comp-card-collection-mosaic-row-size: 80px;
349
362
  --md-comp-card-collection-carousel-height: 320px;
350
363
  --md-comp-card-collection-carousel-card-width: min(82%, 360px);
@@ -357,15 +370,6 @@ article > .primary-action > figure > figcaption > svg {
357
370
  padding: 0;
358
371
  }
359
372
 
360
- :where(.card-collection article):not(.dragged, .picked-up) {
361
- box-shadow: var(--md-comp-card-collection-resting-shadow) !important;
362
- }
363
-
364
- :where(.card-collection article):is(.dragged, .picked-up) {
365
- z-index: 4;
366
- box-shadow: var(--md-comp-card-collection-picked-up-shadow) !important;
367
- }
368
-
369
373
  :where(.card-collection article):not(.horizontal) {
370
374
  display: flex;
371
375
  flex-direction: column;
@@ -425,10 +429,9 @@ article > .primary-action > figure > figcaption > svg {
425
429
  display: block;
426
430
  }
427
431
 
428
- // Horizontal uses the same direct semantic slots as the vertical card. Grid
429
- // moves the media to the start and stacks headline, subhead, supporting text,
430
- // and actions beside it without requiring a second content wrapper.
431
- article.horizontal {
432
+ // Horizontal uses the same semantic slots as the vertical card. They may be
433
+ // direct children or children of the direct primary-action link.
434
+ @mixin horizontal-card-layout($with-actions: true) {
432
435
  display: grid;
433
436
  grid-template-columns:
434
437
  minmax(0, var(--md-comp-card-horizontal-media-width))
@@ -470,14 +473,31 @@ article.horizontal {
470
473
  grid-row: 3;
471
474
  }
472
475
 
473
- > .actions {
474
- grid-column: 2;
475
- grid-row: 4;
476
- align-self: end;
477
- justify-content: flex-end;
476
+ @if $with-actions {
477
+ > .actions {
478
+ grid-column: 2;
479
+ grid-row: 4;
480
+ align-self: end;
481
+ justify-content: flex-end;
482
+ }
478
483
  }
479
484
  }
480
485
 
486
+ article.horizontal {
487
+ @include horizontal-card-layout;
488
+ }
489
+
490
+ article.horizontal:has(> .primary-action) {
491
+ display: block;
492
+ }
493
+
494
+ article.horizontal > .primary-action {
495
+ @include horizontal-card-layout(false);
496
+
497
+ width: 100%;
498
+ min-height: inherit;
499
+ }
500
+
481
501
  // Fixed heights for uniform grids.
482
502
  article.small { height: 300px; }
483
503
  article.medium { height: 400px; }
@@ -493,7 +513,7 @@ article.small, article.medium, article.large {
493
513
  overflow: hidden;
494
514
  }
495
515
 
496
- > img, > figure img {
516
+ > img, > picture img, > figure img {
497
517
  height: 100%;
498
518
  }
499
519
 
@@ -518,15 +538,46 @@ article.horizontal.large {
518
538
  }
519
539
  }
520
540
 
521
- // Reveal panel. The summary and media remain in place while the card grows
522
- // downward to expose additional actions, matching the M3 expand/collapse
523
- // example. `interpolate-size` lets intrinsic content height animate without a
524
- // fixed cap; the @supports fallback keeps the interaction functional.
525
- :where(#{$_card}):has(> aside) {
541
+ article.horizontal:is(.small, .medium, .large):has(> .primary-action) {
542
+ display: block;
543
+ }
544
+
545
+ article.horizontal:is(.small, .medium, .large) > .primary-action {
546
+ height: 100%;
547
+ }
548
+
549
+ // Compact windows use the vertical spelling. This keeps media and controls
550
+ // large enough to scan and operate without changing their source order.
551
+ @include bp-down("medium") {
552
+ article.horizontal,
553
+ article.horizontal.small,
554
+ article.horizontal.medium,
555
+ article.horizontal.large {
556
+ display: flex;
557
+ flex-direction: column;
558
+ height: auto;
559
+ min-height: auto;
560
+ }
561
+
562
+ article.horizontal > .primary-action,
563
+ article.horizontal:is(.small, .medium, .large) > .primary-action {
564
+ display: flex;
565
+ flex-direction: column;
566
+ height: auto;
567
+ min-height: auto;
568
+ }
569
+ }
570
+
571
+ // Reveal panel. Panels stay available until Cards confirms the disclosure
572
+ // contract and adds its runtime marker. The summary and media remain in place
573
+ // while the initialized card grows downward to expose additional actions.
574
+ // `interpolate-size` lets intrinsic content height animate without a fixed cap;
575
+ // the @supports fallback keeps the interaction functional.
576
+ :where(#{$_card}.card-reveal-initialized) {
526
577
  interpolate-size: allow-keywords;
527
578
  }
528
579
 
529
- article > aside {
580
+ article.card-reveal-initialized > aside {
530
581
  --md-comp-card-reveal-duration: 500ms;
531
582
  --md-comp-card-reveal-easing: cubic-bezier(0.2, 0, 0, 1);
532
583
 
@@ -550,7 +601,7 @@ article > aside {
550
601
  visibility 0s var(--md-comp-card-reveal-duration);
551
602
  }
552
603
 
553
- article > aside[aria-expanded="true"] {
604
+ article.card-reveal-initialized > aside.open {
554
605
  height: auto;
555
606
  padding-block: 0 var(--md-comp-card-content-padding);
556
607
  opacity: 1;
@@ -564,60 +615,21 @@ article > aside[aria-expanded="true"] {
564
615
  }
565
616
 
566
617
  @supports not (interpolate-size: allow-keywords) {
567
- article > aside {
618
+ article.card-reveal-initialized > aside {
619
+ display: none;
568
620
  height: auto;
569
- max-height: 0;
570
- transition:
571
- max-height var(--md-comp-card-reveal-duration) var(--md-comp-card-reveal-easing),
572
- padding-block var(--md-comp-card-reveal-duration) var(--md-comp-card-reveal-easing),
573
- opacity 150ms ease-out,
574
- visibility 0s var(--md-comp-card-reveal-duration);
621
+ transition: none;
575
622
  }
576
623
 
577
- article > aside[aria-expanded="true"] {
578
- max-height: var(--md-comp-card-reveal-fallback-height, 320px);
624
+ article.card-reveal-initialized > aside.open {
625
+ display: block;
579
626
  }
580
627
  }
581
628
 
582
629
  // A media-sized button supplies the repeated open/close target and carries the
583
630
  // state layer for the tap feedback shown by the M3 example.
584
631
  article > figure > .card-reveal-trigger {
585
- position: absolute;
586
- inset: 0;
587
- z-index: 1;
588
- display: block;
589
- width: 100%;
590
- height: 100%;
591
- min-width: 0;
592
- min-height: 0;
593
- margin: 0;
594
- padding: 0;
595
- background: none;
596
- border: 0;
597
- border-radius: inherit;
598
- box-shadow: none;
599
- color: transparent;
600
- cursor: pointer;
601
- }
602
-
603
- // The trigger paints its own state layer: the card's `::after` keys on
604
- // `> .primary-action`, which this is not. It reads the same `--md-comp-card-*`
605
- // opacities, so tuning one card still reaches it.
606
- article > figure > .card-reveal-trigger:hover {
607
- background-color: color-mix(in oklab, var(--md-comp-card-state-layer-color) calc(var(--md-comp-card-hover-state-layer-opacity) * 100%), transparent);
608
- box-shadow: none;
609
- }
610
-
611
- article > figure > .card-reveal-trigger:focus-visible {
612
- background-color: color-mix(in oklab, var(--md-comp-card-state-layer-color) calc(var(--md-comp-card-focus-state-layer-opacity) * 100%), transparent);
613
- box-shadow: none;
614
- outline: var(--md-comp-card-focus-indicator-thickness) solid var(--md-comp-card-focus-indicator-color);
615
- outline-offset: calc(-1 * var(--md-comp-card-focus-indicator-thickness));
616
- }
617
-
618
- article > figure > .card-reveal-trigger:active {
619
- background-color: color-mix(in oklab, var(--md-comp-card-state-layer-color) calc(var(--md-comp-card-pressed-state-layer-opacity) * 100%), transparent);
620
- box-shadow: none;
632
+ @include card-media-trigger;
621
633
  }
622
634
 
623
635
  article > header.card-reveal-summary {
@@ -664,12 +676,15 @@ article > aside > .reveal-actions > .reveal-action > :is(.material-symbols, .car
664
676
  }
665
677
 
666
678
  @media (prefers-reduced-motion: reduce) {
667
- article > aside {
679
+ :where(#{$_card}),
680
+ :where(#{$_card})::after,
681
+ article > figure > .card-reveal-trigger,
682
+ article.card-reveal-initialized > aside {
668
683
  transition: none;
669
684
  }
670
685
  }
671
686
 
672
- article.sticky > :is(nav, .actions) {
687
+ article.sticky > .actions {
673
688
  position: relative;
674
689
  z-index: 4;
675
690
  background-color: inherit;
@@ -16,41 +16,7 @@ article.expanding-card {
16
16
  }
17
17
 
18
18
  article.expanding-card > figure > .expanding-card-trigger {
19
- position: absolute;
20
- inset: 0;
21
- z-index: 1;
22
- display: block;
23
- width: 100%;
24
- height: 100%;
25
- min-width: 0;
26
- min-height: 0;
27
- margin: 0;
28
- padding: 0;
29
- background: none;
30
- border: 0;
31
- border-radius: inherit;
32
- box-shadow: none;
33
- color: transparent;
34
- cursor: pointer;
35
- }
36
-
37
- // The trigger covers the media, so it carries the state layer itself, off the
38
- // same `--md-comp-card-*` opacities the card's own layer reads.
39
- article.expanding-card > figure > .expanding-card-trigger:hover {
40
- background-color: color-mix(in oklab, var(--md-comp-card-state-layer-color) calc(var(--md-comp-card-hover-state-layer-opacity) * 100%), transparent);
41
- box-shadow: none;
42
- }
43
-
44
- article.expanding-card > figure > .expanding-card-trigger:focus-visible {
45
- background-color: color-mix(in oklab, var(--md-comp-card-state-layer-color) calc(var(--md-comp-card-focus-state-layer-opacity) * 100%), transparent);
46
- box-shadow: none;
47
- outline: var(--md-comp-card-focus-indicator-thickness) solid var(--md-comp-card-focus-indicator-color);
48
- outline-offset: calc(-1 * var(--md-comp-card-focus-indicator-thickness));
49
- }
50
-
51
- article.expanding-card > figure > .expanding-card-trigger:active {
52
- background-color: color-mix(in oklab, var(--md-comp-card-state-layer-color) calc(var(--md-comp-card-pressed-state-layer-opacity) * 100%), transparent);
53
- box-shadow: none;
19
+ @include card-media-trigger;
54
20
  }
55
21
 
56
22
  article.expanding-card > header.expanding-card-summary {
@@ -42,32 +42,10 @@
42
42
  // Width is not a token: it is leading + icon + trailing. That is why every
43
43
  // size's default width equals its height, and why `.narrow` / `.wide` need
44
44
  // nothing but a different inset.
45
- $_sizes: (
46
- "xsmall": (height: 32px, icon: 20px, space: 6px, narrow: 4px, wide: 10px, square: 12px, pressed: 8px, outline: 1px),
47
- "small": (height: 40px, icon: 24px, space: 8px, narrow: 4px, wide: 14px, square: 12px, pressed: 8px, outline: 1px),
48
- "medium": (height: 56px, icon: 24px, space: 16px, narrow: 12px, wide: 24px, square: 16px, pressed: 12px, outline: 1px),
49
- "large": (height: 96px, icon: 32px, space: 32px, narrow: 16px, wide: 48px, square: 28px, pressed: 16px, outline: 2px),
50
- "xlarge": (height: 136px, icon: 40px, space: 48px, narrow: 32px, wide: 72px, square: 28px, pressed: 16px, outline: 3px),
51
- );
52
-
53
- @mixin _size($name) {
54
- $s: map.get($_sizes, $name);
55
-
56
- --md-comp-icon-button-container-height: #{map.get($s, height)};
57
- --md-comp-icon-button-icon-size: #{map.get($s, icon)};
58
- --md-comp-icon-button-leading-space: #{map.get($s, space)};
59
- --md-comp-icon-button-trailing-space: #{map.get($s, space)};
60
- --md-comp-icon-button-narrow-space: #{map.get($s, narrow)};
61
- --md-comp-icon-button-wide-space: #{map.get($s, wide)};
62
- --md-comp-icon-button-container-shape-square: #{map.get($s, square)};
63
- --md-comp-icon-button-pressed-container-shape: #{map.get($s, pressed)};
64
- --md-comp-icon-button-outline-width: #{map.get($s, outline)};
65
- }
66
-
67
45
  // Standard is the default style: no container, `on-surface-variant` icon. Every
68
46
  // other style is two tokens.
69
47
  .icon-button {
70
- @include _size("small");
48
+ @include icon-button-size("small");
71
49
 
72
50
  --md-comp-icon-button-color: var(--md-sys-color-on-surface-variant);
73
51
  --md-comp-icon-button-container-color: transparent;
@@ -145,7 +123,7 @@ $_sizes: (
145
123
  // Sizes. Default is small (40dp), which is M3's default icon button.
146
124
  @each $name in ("xsmall", "medium", "large", "xlarge") {
147
125
  .icon-button.#{$name} {
148
- @include _size($name);
126
+ @include icon-button-size($name);
149
127
  }
150
128
  }
151
129
 
@@ -1,11 +1,11 @@
1
1
  @use "../abstracts" as *;
2
2
 
3
- // Material Symbols. The framework does not ship the font files — outlined,
4
- // rounded, and sharp are three separate variable fonts, and pulling all
5
- // three into the main sheet would dwarf the rest of the CSS. Load the
6
- // families you use (see the Icons docs). Outlined with every axis:
7
- //
8
- // fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200
3
+ // Material Symbols. The compiled sheet ships @font-face rules for outlined,
4
+ // rounded, and sharp variable fonts (opsz / wght / FILL / GRAD) plus Roboto
5
+ // and Noto Sans. Browsers only download a family after markup uses it, so
6
+ // rounded and sharp stay cheap until `icon-style` or a family class asks
7
+ // for them. Override $expressive-include-fonts when compiling Sass if the
8
+ // page already loads these families.
9
9
  //
10
10
  // Style (outlined / rounded / sharp) is the font family, not a variation
11
11
  // axis. Switch it with the `icon-style` attribute (same idea as `theme`)