@m3-baseui/react-tailwind 2.0.0 → 4.0.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 (66) hide show
  1. package/dist/components/badge/index.js +13 -1
  2. package/dist/components/badge/index.js.map +1 -1
  3. package/dist/components/bottom-app-bar/index.js +13 -1
  4. package/dist/components/bottom-app-bar/index.js.map +1 -1
  5. package/dist/components/bottom-sheet/index.js +13 -1
  6. package/dist/components/bottom-sheet/index.js.map +1 -1
  7. package/dist/components/button/index.d.ts +106 -1
  8. package/dist/components/button/index.js +168 -25
  9. package/dist/components/button/index.js.map +1 -1
  10. package/dist/components/button-group/index.js +13 -1
  11. package/dist/components/button-group/index.js.map +1 -1
  12. package/dist/components/card/index.js +13 -1
  13. package/dist/components/card/index.js.map +1 -1
  14. package/dist/components/carousel/index.d.ts +21 -0
  15. package/dist/components/carousel/index.js +20 -2
  16. package/dist/components/carousel/index.js.map +1 -1
  17. package/dist/components/date-picker/index.js +13 -1
  18. package/dist/components/date-picker/index.js.map +1 -1
  19. package/dist/components/dialog/index.js +13 -1
  20. package/dist/components/dialog/index.js.map +1 -1
  21. package/dist/components/fab-menu/index.js +13 -1
  22. package/dist/components/fab-menu/index.js.map +1 -1
  23. package/dist/components/item/index.d.ts +5 -5
  24. package/dist/components/item/index.js +13 -1
  25. package/dist/components/item/index.js.map +1 -1
  26. package/dist/components/list/index.js +13 -1
  27. package/dist/components/list/index.js.map +1 -1
  28. package/dist/components/loading-indicator/index.js +13 -1
  29. package/dist/components/loading-indicator/index.js.map +1 -1
  30. package/dist/components/menu/index.js +13 -1
  31. package/dist/components/menu/index.js.map +1 -1
  32. package/dist/components/navigation-drawer/index.js +13 -1
  33. package/dist/components/navigation-drawer/index.js.map +1 -1
  34. package/dist/components/navigation-rail/index.js +13 -1
  35. package/dist/components/navigation-rail/index.js.map +1 -1
  36. package/dist/components/search/index.js +13 -1
  37. package/dist/components/search/index.js.map +1 -1
  38. package/dist/components/segmented-button/index.js +13 -1
  39. package/dist/components/segmented-button/index.js.map +1 -1
  40. package/dist/components/select/index.d.ts +0 -18
  41. package/dist/components/select/index.js +15 -14
  42. package/dist/components/select/index.js.map +1 -1
  43. package/dist/components/side-sheet/index.js +13 -1
  44. package/dist/components/side-sheet/index.js.map +1 -1
  45. package/dist/components/slider/index.js +49 -15
  46. package/dist/components/slider/index.js.map +1 -1
  47. package/dist/components/snackbar/index.d.ts +5 -5
  48. package/dist/components/split-button/index.js +13 -1
  49. package/dist/components/split-button/index.js.map +1 -1
  50. package/dist/components/tabs/index.js +13 -1
  51. package/dist/components/tabs/index.js.map +1 -1
  52. package/dist/components/time-picker/index.js +13 -1
  53. package/dist/components/time-picker/index.js.map +1 -1
  54. package/dist/components/toolbar/index.js +13 -1
  55. package/dist/components/toolbar/index.js.map +1 -1
  56. package/dist/components/tooltip/index.js +13 -1
  57. package/dist/components/tooltip/index.js.map +1 -1
  58. package/dist/components/top-app-bar/index.js +13 -1
  59. package/dist/components/top-app-bar/index.js.map +1 -1
  60. package/dist/index.d.ts +1 -1
  61. package/dist/index.js +256 -125
  62. package/dist/index.js.map +1 -1
  63. package/dist/tv.d.ts +13 -8
  64. package/dist/tv.js +13 -1
  65. package/dist/tv.js.map +1 -1
  66. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,20 +1,59 @@
1
1
  "use client";
2
- import { createButton, createIconButton, createSwitch, createCheckbox, createRadio, createRadioGroup, createChip, createTooltip, createRichTooltip, createDialog, createMenu, createTabs, createSlider, createSelect, createTextField, createNavigationBar, createFab, createFabMenu, createDivider, createProgress, createLoadingIndicator, createList, createSnackbar, createItem, createBadge, createCard, createSegmentedButton, createButtonGroup, createSplitButton, createNavigationDrawer, createTopAppBar, createBottomAppBar, createNavigationRail, createBottomSheet, createSideSheet, createSearch, createDatePicker, createTimePicker, createToolbar, createCarousel } from '@m3-baseui/core';
2
+ import { createButton, toToggle, createIconButton, createSwitch, createCheckbox, createRadio, createRadioGroup, createChip, createTooltip, createRichTooltip, createDialog, createMenu, createTabs, createSlider, createSelect, createTextField, createNavigationBar, createFab, createFabMenu, createDivider, createProgress, createLoadingIndicator, createList, createSnackbar, createItem, createBadge, createCard, createSegmentedButton, createButtonGroup, createSplitButton, createNavigationDrawer, createTopAppBar, createBottomAppBar, createNavigationRail, createBottomSheet, createSideSheet, createSearch, createDatePicker, createTimePicker, createToolbar, createCarousel } from '@m3-baseui/core';
3
3
  export { ITEM_LEADING_VARIANTS, LIST_LEADING_VARIANTS, Ripple, ThemeProvider, applyScheme, generateScheme, schemeToCssText, useSnackbar, useTheme } from '@m3-baseui/core';
4
- import { tv } from 'tailwind-variants';
4
+ import { tv as tv$1 } from 'tailwind-variants';
5
+
6
+ // src/components/button/button.ts
7
+ var TYPESCALE = [
8
+ "display-large",
9
+ "display-medium",
10
+ "display-small",
11
+ "headline-large",
12
+ "headline-medium",
13
+ "headline-small",
14
+ "title-large",
15
+ "title-medium",
16
+ "title-small",
17
+ "body-large",
18
+ "body-medium",
19
+ "body-small",
20
+ "label-large",
21
+ "label-medium",
22
+ "label-small"
23
+ ];
24
+ var SHAPE = [
25
+ "none",
26
+ "extra-small",
27
+ "small",
28
+ "medium",
29
+ "large",
30
+ "large-increased",
31
+ "extra-large",
32
+ "extra-large-increased",
33
+ "full"
34
+ ];
35
+ var tv = (options, config) => tv$1(options, {
36
+ ...config,
37
+ twMergeConfig: {
38
+ extend: {
39
+ classGroups: {
40
+ "font-size": [{ text: [...TYPESCALE] }],
41
+ rounded: [{ rounded: [...SHAPE] }]
42
+ }
43
+ }
44
+ }
45
+ });
5
46
 
6
47
  // src/components/button/button.ts
7
48
  var button = tv({
8
49
  base: [
9
- "relative inline-flex items-center justify-center gap-2",
10
- "h-10 px-6 rounded-full overflow-hidden cursor-pointer select-none border-0",
11
- "text-label-large",
12
- // M3 with-icon padding: the icon side trims to 16dp (label side stays 24dp).
13
- "data-[with-start-icon]:pl-4 data-[with-end-icon]:pr-4",
14
- // Icon slot: 18dp, centered.
50
+ "relative inline-flex items-center justify-center",
51
+ "overflow-hidden cursor-pointer select-none border-0",
52
+ // Icon slot: centered; the svg size comes from the `size` variant.
15
53
  "[&_[data-slot=button-icon]]:inline-flex [&_[data-slot=button-icon]]:items-center [&_[data-slot=button-icon]]:justify-center",
16
- "[&_[data-slot=button-icon]>svg]:size-[18px]",
17
- "transition-[box-shadow,background-color,color,border-color] duration-200 ease-[var(--md-sys-motion-easing-standard)]",
54
+ // Motion: Compose uses DefaultEffects (critically-damped spring, no bounce)
55
+ // for the shape/color/elevation transitions — spring-effects-default here.
56
+ "transition-[box-shadow,background-color,color,border-color,border-radius] duration-200 ease-spring-effects-default",
18
57
  // State layer overlay
19
58
  "before:absolute before:inset-0 before:rounded-[inherit] before:bg-current before:opacity-0 before:pointer-events-none",
20
59
  "before:transition-opacity before:duration-100",
@@ -25,20 +64,23 @@ var button = tv({
25
64
  // Focus ring (M3: 3px secondary, 2px offset)
26
65
  "focus-visible:outline-[3px] focus-visible:outline-offset-2 focus-visible:outline-secondary",
27
66
  // Disabled: no interaction, no state layer, no elevation. Per-variant
28
- // colors (container on-surface/12, label on-surface/38) live on each variant.
67
+ // colors (container on-surface/10, label on-surface-variant/38) live on
68
+ // each variant.
29
69
  "disabled:pointer-events-none disabled:shadow-none disabled:before:opacity-0",
30
70
  "data-[disabled]:pointer-events-none data-[disabled]:shadow-none data-[disabled]:before:opacity-0"
31
71
  ],
32
72
  variants: {
33
73
  // M3 elevation per variant: filled/tonal rest level0→hover level1→pressed level0;
34
- // elevated rest level1→hover level2→pressed level1. Disabled container is
35
- // on-surface/12 and label on-surface/38, matching material-web.
74
+ // elevated rest level1→hover level2→pressed level1. Expressive disabled:
75
+ // container on-surface/10, label on-surface-variant/38 — except tonal, which
76
+ // is unchanged upstream (FilledTonalButtonTokens v0_103) and keeps 0.12 /
77
+ // on-surface. Expressive also moves outlined/text labels to on-surface-variant.
36
78
  variant: {
37
79
  filled: [
38
80
  "bg-primary text-on-primary",
39
81
  "hover:shadow-level1 focus-visible:shadow-none active:shadow-none data-[pressed]:shadow-none",
40
- "disabled:bg-on-surface/12 disabled:text-on-surface/38",
41
- "data-[disabled]:bg-on-surface/12 data-[disabled]:text-on-surface/38"
82
+ "disabled:bg-on-surface/10 disabled:text-on-surface-variant/38",
83
+ "data-[disabled]:bg-on-surface/10 data-[disabled]:text-on-surface-variant/38"
42
84
  ],
43
85
  tonal: [
44
86
  "bg-secondary-container text-on-secondary-container",
@@ -47,28 +89,129 @@ var button = tv({
47
89
  "data-[disabled]:bg-on-surface/12 data-[disabled]:text-on-surface/38"
48
90
  ],
49
91
  outlined: [
50
- "bg-transparent text-primary border border-outline",
51
- "disabled:text-on-surface/38 disabled:border-on-surface/12",
52
- "data-[disabled]:text-on-surface/38 data-[disabled]:border-on-surface/12"
92
+ "bg-transparent text-on-surface-variant border border-outline-variant",
93
+ // Compose outlinedButtonBorder(enabled=false) tints the outline with
94
+ // DisabledContainerOpacity (0.1), so the disabled border is faint.
95
+ "disabled:text-on-surface-variant/38 disabled:border-outline-variant/10",
96
+ "data-[disabled]:text-on-surface-variant/38 data-[disabled]:border-outline-variant/10"
53
97
  ],
54
98
  elevated: [
55
99
  "bg-surface-container-low text-primary shadow-level1",
56
100
  "hover:shadow-level2 focus-visible:shadow-level1 active:shadow-level1 data-[pressed]:shadow-level1",
57
- "disabled:bg-on-surface/12 disabled:text-on-surface/38",
58
- "data-[disabled]:bg-on-surface/12 data-[disabled]:text-on-surface/38"
101
+ "disabled:bg-on-surface/10 disabled:text-on-surface-variant/38",
102
+ "data-[disabled]:bg-on-surface/10 data-[disabled]:text-on-surface-variant/38"
59
103
  ],
60
104
  text: [
61
- "bg-transparent text-primary px-3",
62
- "disabled:text-on-surface/38",
63
- "data-[disabled]:text-on-surface/38"
105
+ "bg-transparent text-on-surface-variant",
106
+ "disabled:text-on-surface-variant/38",
107
+ "data-[disabled]:text-on-surface-variant/38"
64
108
  ]
109
+ },
110
+ // Height / horizontal padding / gap / typescale / icon size per Expressive
111
+ // size. The pressed corner morph (PressedContainerShape: XS·S small 8 /
112
+ // M medium 12 / L·XL large 16) rides on data-[pressed]/active here so its
113
+ // attribute-selector specificity wins over the resting `rounded-*`.
114
+ size: {
115
+ xs: [
116
+ // XS is special-cased in Compose Button.kt: contentPaddingFor returns
117
+ // ExtraSmallContentPadding (12dp) and iconSpacingFor returns
118
+ // ExtraSmallIconSpacing (4dp) — tighter than the ButtonXSmallTokens
119
+ // Leading/TrailingSpace (16) and IconLabelSpace (8). S–XL use their tokens.
120
+ "h-8 px-3 gap-1 text-label-large [&_[data-slot=button-icon]>svg]:size-5",
121
+ "data-[pressed]:rounded-small active:rounded-small"
122
+ ],
123
+ s: [
124
+ "h-10 px-4 gap-2 text-label-large [&_[data-slot=button-icon]>svg]:size-5",
125
+ "data-[pressed]:rounded-small active:rounded-small"
126
+ ],
127
+ m: [
128
+ "h-14 px-6 gap-2 text-title-medium [&_[data-slot=button-icon]>svg]:size-6",
129
+ "data-[pressed]:rounded-medium active:rounded-medium"
130
+ ],
131
+ l: [
132
+ "h-24 px-12 gap-3 text-headline-small [&_[data-slot=button-icon]>svg]:size-8",
133
+ "data-[pressed]:rounded-large active:rounded-large"
134
+ ],
135
+ xl: [
136
+ "h-[136px] px-16 gap-4 text-headline-large [&_[data-slot=button-icon]>svg]:size-10",
137
+ "data-[pressed]:rounded-large active:rounded-large"
138
+ ]
139
+ },
140
+ // round = full pill; the square corner is size-specific (compounds below).
141
+ shape: {
142
+ round: "rounded-full",
143
+ square: ""
144
+ },
145
+ // Toggle state, string-keyed so a plain (non-toggle) button — `toggle`
146
+ // unset — fires neither compound below (a boolean variant would default to
147
+ // `off` in tailwind-variants and wrongly apply the unselected look).
148
+ toggle: {
149
+ on: "",
150
+ off: ""
65
151
  }
66
152
  },
153
+ compoundVariants: [
154
+ // ---- Resting square corner (ContainerShapeSquare) ---------------------
155
+ { shape: "square", size: "xs", class: "rounded-medium" },
156
+ // 12dp
157
+ { shape: "square", size: "s", class: "rounded-medium" },
158
+ // 12dp
159
+ { shape: "square", size: "m", class: "rounded-large" },
160
+ // 16dp
161
+ { shape: "square", size: "l", class: "rounded-extra-large" },
162
+ // 28dp
163
+ { shape: "square", size: "xl", class: "rounded-extra-large" },
164
+ // 28dp
165
+ // ---- Selected shape morph: swap to the opposite shape -----------------
166
+ // (listed after the resting corner so tailwind-merge keeps these).
167
+ { shape: "round", toggle: "on", size: "xs", class: "rounded-medium" },
168
+ { shape: "round", toggle: "on", size: "s", class: "rounded-medium" },
169
+ { shape: "round", toggle: "on", size: "m", class: "rounded-large" },
170
+ { shape: "round", toggle: "on", size: "l", class: "rounded-extra-large" },
171
+ { shape: "round", toggle: "on", size: "xl", class: "rounded-extra-large" },
172
+ { shape: "square", toggle: "on", size: "xs", class: "rounded-full" },
173
+ { shape: "square", toggle: "on", size: "s", class: "rounded-full" },
174
+ { shape: "square", toggle: "on", size: "m", class: "rounded-full" },
175
+ { shape: "square", toggle: "on", size: "l", class: "rounded-full" },
176
+ { shape: "square", toggle: "on", size: "xl", class: "rounded-full" },
177
+ // ---- Outlined border width (OutlinedOutlineWidth: L 2 / XL 3 dp) ------
178
+ { variant: "outlined", size: "l", class: "border-2" },
179
+ { variant: "outlined", size: "xl", class: "border-[3px]" },
180
+ // ---- Toggle colors (Selected*/Unselected* tokens) ---------------------
181
+ // filled/tonal: base = default & selected look; `toggle:off` = unselected.
182
+ { variant: "filled", toggle: "off", class: "bg-surface-container text-on-surface-variant" },
183
+ { variant: "tonal", toggle: "off", class: "bg-surface-container text-on-surface-variant" },
184
+ // elevated: distinct selected (primary) & unselected looks.
185
+ { variant: "elevated", toggle: "on", class: "bg-primary text-on-primary" },
186
+ {
187
+ variant: "elevated",
188
+ toggle: "off",
189
+ class: "bg-surface-container-low text-on-surface-variant"
190
+ },
191
+ // outlined: selected fills with the inverse surface (base = unselected).
192
+ {
193
+ variant: "outlined",
194
+ toggle: "on",
195
+ class: [
196
+ "bg-inverse-surface text-inverse-on-surface border-transparent",
197
+ "disabled:bg-on-surface/10 disabled:border-transparent",
198
+ "data-[disabled]:bg-on-surface/10 data-[disabled]:border-transparent"
199
+ ]
200
+ },
201
+ // text: no Selected/Unselected tokens exist upstream (TextButtonTokens),
202
+ // so selection raises the label emphasis to primary (base = unselected
203
+ // on-surface-variant) to communicate the toggle state.
204
+ { variant: "text", toggle: "on", class: "text-primary" }
205
+ ],
67
206
  defaultVariants: {
68
- variant: "filled"
207
+ variant: "filled",
208
+ size: "s",
209
+ shape: "round"
69
210
  }
70
211
  });
71
- var Button = createButton(({ variant }) => button({ variant }));
212
+ var Button = createButton(
213
+ ({ variant, size, shape, selected }) => button({ variant, size, shape, toggle: toToggle(selected) })
214
+ );
72
215
  var WIDTHS = {
73
216
  xs: { narrow: "w-7", default: "w-8", wide: "w-10" },
74
217
  // 28 / 32 / 40
@@ -88,7 +231,7 @@ var widthCompounds = Object.entries(WIDTHS).flatMap(
88
231
  class: klass
89
232
  }))
90
233
  );
91
- var iconButton = tv({
234
+ var iconButton = tv$1({
92
235
  base: [
93
236
  "relative inline-flex items-center justify-center shrink-0",
94
237
  // No `overflow-hidden`: it would clip the 48dp touch target on small sizes.
@@ -184,7 +327,7 @@ var iconButton = tv({
184
327
  var IconButton = createIconButton(
185
328
  ({ variant, selected, size, width }) => iconButton({ variant, selected, size, width })
186
329
  );
187
- var switchTv = tv({
330
+ var switchTv = tv$1({
188
331
  slots: {
189
332
  root: [
190
333
  "group relative inline-flex shrink-0 w-[52px] h-8 rounded-full border-2 box-border cursor-pointer",
@@ -244,7 +387,7 @@ var Switch = createSwitch({
244
387
  iconChecked: s.iconChecked(),
245
388
  iconUnchecked: s.iconUnchecked()
246
389
  });
247
- var checkboxTv = tv({
390
+ var checkboxTv = tv$1({
248
391
  slots: {
249
392
  root: [
250
393
  "group relative inline-flex items-center justify-center shrink-0 box-border",
@@ -300,7 +443,7 @@ var Checkbox = createCheckbox({
300
443
  indicator: c.indicator(),
301
444
  icon: c.icon()
302
445
  });
303
- var radioTv = tv({
446
+ var radioTv = tv$1({
304
447
  slots: {
305
448
  root: [
306
449
  "group relative inline-flex items-center justify-center shrink-0 box-border",
@@ -343,7 +486,7 @@ var radioTv = tv({
343
486
  var r = radioTv();
344
487
  var Radio = createRadio({ root: r.root(), indicator: r.indicator() });
345
488
  var RadioGroup = createRadioGroup("inline-flex flex-col gap-1");
346
- var chipTv = tv({
489
+ var chipTv = tv$1({
347
490
  slots: {
348
491
  root: [
349
492
  "group relative inline-flex items-center justify-center gap-2 box-border",
@@ -437,41 +580,12 @@ var Chip = createChip(({ variant, elevated }) => {
437
580
  icon: c3.icon()
438
581
  };
439
582
  });
440
- var TYPESCALE = [
441
- "display-large",
442
- "display-medium",
443
- "display-small",
444
- "headline-large",
445
- "headline-medium",
446
- "headline-small",
447
- "title-large",
448
- "title-medium",
449
- "title-small",
450
- "body-large",
451
- "body-medium",
452
- "body-small",
453
- "label-large",
454
- "label-medium",
455
- "label-small"
456
- ];
457
- var tv7 = (options, config) => tv(options, {
458
- ...config,
459
- twMergeConfig: {
460
- extend: {
461
- classGroups: {
462
- "font-size": [{ text: [...TYPESCALE] }]
463
- }
464
- }
465
- }
466
- });
467
-
468
- // src/components/tooltip/tooltip.ts
469
583
  var transition = [
470
584
  "origin-[var(--transform-origin)] transition-[opacity,transform] duration-150 ease-standard",
471
585
  "data-[starting-style]:opacity-0 data-[starting-style]:scale-95",
472
586
  "data-[ending-style]:opacity-0 data-[ending-style]:scale-95"
473
587
  ];
474
- var tooltipTv = tv7({
588
+ var tooltipTv = tv({
475
589
  slots: {
476
590
  popup: [
477
591
  "bg-inverse-surface text-inverse-on-surface text-body-small",
@@ -481,7 +595,7 @@ var tooltipTv = tv7({
481
595
  arrow: ["text-inverse-surface"]
482
596
  }
483
597
  });
484
- var richTooltipTv = tv7({
598
+ var richTooltipTv = tv({
485
599
  slots: {
486
600
  popup: [
487
601
  "bg-surface-container text-on-surface shadow-level2",
@@ -508,7 +622,7 @@ var RichTooltip = createRichTooltip({
508
622
  supportingText: r2.supportingText(),
509
623
  actions: r2.actions()
510
624
  });
511
- var dialogTv = tv7({
625
+ var dialogTv = tv({
512
626
  slots: {
513
627
  backdrop: [
514
628
  "fixed inset-0 z-40 bg-scrim/32",
@@ -613,7 +727,7 @@ var menuSelectableItemBase = [
613
727
  ...menuSelectableItemPositionShapeFallback,
614
728
  ...menuSelectableItemDisabled
615
729
  ];
616
- var menuSelectableItemTv = tv7({
730
+ var menuSelectableItemTv = tv({
617
731
  slots: {
618
732
  /** Select row: check + label + optional trailing meta. */
619
733
  selectItem: ["grid grid-cols-[24px_1fr_auto] items-center gap-3", ...menuSelectableItemBase],
@@ -638,7 +752,7 @@ var menuSurfaceBase = [
638
752
  "data-[ending-style]:opacity-0",
639
753
  "focus:outline-none"
640
754
  ];
641
- var menuSurfaceTv = tv7({
755
+ var menuSurfaceTv = tv({
642
756
  slots: {
643
757
  popup: ["max-w-[280px]", ...menuSurfaceBase],
644
758
  groupLabel: "px-3 py-2 text-label-small text-on-surface-variant"
@@ -666,7 +780,7 @@ menuSurfaceTv();
666
780
  // src/components/menu/menu.ts
667
781
  var surface = menuSurfaceTv({ width: "standard", scroll: "none" });
668
782
  var selectable = menuSelectableItem;
669
- var menuTv = tv7({
783
+ var menuTv = tv({
670
784
  slots: {
671
785
  popup: surface.popup(),
672
786
  item: [
@@ -716,7 +830,7 @@ var Menu = createMenu({
716
830
  radioItem: m.radioItem(),
717
831
  itemIndicator: m.itemIndicator()
718
832
  });
719
- var tabsTv = tv7({
833
+ var tabsTv = tv({
720
834
  slots: {
721
835
  root: "flex flex-col",
722
836
  list: [
@@ -775,36 +889,58 @@ var Tabs = createTabs((variant) => {
775
889
  panel: s14.panel()
776
890
  };
777
891
  });
778
- var sliderTv = tv7({
892
+ var sliderTv = tv({
779
893
  slots: {
780
894
  root: "group relative flex items-center select-none w-full touch-none",
781
- control: "relative flex items-center w-full h-10",
895
+ control: "relative flex items-center w-full h-11",
896
+ // Transparent positioning container; the inactive rail lives on the pseudos.
897
+ // `::before` = the rail after the active end (single + range). `::after` =
898
+ // the rail before the active start (range only; it collapses when
899
+ // `--m3-slider-start` is 0). Both offset by the 8px handle gap and keep a 2dp
900
+ // inside corner / full outside corner. Logical inline insets track RTL.
782
901
  track: [
783
- "relative w-full h-1 rounded-full bg-surface-container-highest",
784
- "group-data-[disabled]:bg-on-surface/[0.12]"
785
- ],
902
+ "relative w-full h-4",
903
+ "before:content-[''] before:absolute before:top-0 before:bottom-0 before:end-0",
904
+ "before:[inset-inline-start:calc(var(--m3-slider-end)_+_8px)]",
905
+ "before:bg-secondary-container before:rounded-s-[2px] before:rounded-e-full",
906
+ "group-data-[disabled]:before:bg-on-surface/[0.12]",
907
+ "after:content-[''] after:absolute after:top-0 after:bottom-0 after:start-0",
908
+ "after:[inset-inline-end:calc(100%_-_var(--m3-slider-start)_+_8px)]",
909
+ "after:bg-secondary-container after:rounded-s-full after:rounded-e-[2px]",
910
+ "group-data-[disabled]:after:bg-on-surface/[0.12]"
911
+ ],
912
+ // Active fill. Geometry (absolute insets built from the active fraction + 8px
913
+ // gap) is set inline by the factory; here we own colour + corners. Outer edge
914
+ // full, inner (handle-facing) edge 2dp; a range slider's start edge is inner
915
+ // too (`data-range`).
786
916
  indicator: [
787
- "absolute h-1 rounded-full bg-primary",
917
+ "bg-primary rounded-s-full rounded-e-[2px]",
918
+ "group-data-[range]:rounded-s-[2px]",
788
919
  "group-data-[disabled]:bg-on-surface/[0.38]"
789
920
  ],
921
+ // 4×44dp bar handle, CornerFull. No state layer: it shrinks to 2dp on
922
+ // pressed (data-dragging) / focus via the fast-spatial spring; hover stays
923
+ // 4dp. Disabled keeps the 4dp width (DisabledHandleWidth) and dims to 0.38.
790
924
  thumb: [
791
- "group/thumb relative size-5 rounded-full bg-primary outline-none",
792
- 'before:content-[""] before:absolute before:left-1/2 before:top-1/2 before:-translate-x-1/2 before:-translate-y-1/2',
793
- "before:size-10 before:rounded-full before:bg-primary before:opacity-0 before:transition-opacity before:duration-100",
794
- "hover:before:opacity-[var(--md-sys-state-hover)]",
795
- "focus-visible:before:opacity-[var(--md-sys-state-focus)]",
796
- "data-[dragging]:before:opacity-[var(--md-sys-state-dragged)]",
925
+ "w-1 h-11 rounded-full bg-primary outline-none",
926
+ "transition-[width] ease-spring-spatial-fast duration-[var(--md-sys-motion-duration-spring-spatial-fast)]",
927
+ "focus-visible:w-0.5 data-[dragging]:w-0.5",
797
928
  "group-data-[disabled]:bg-on-surface/[0.38]"
798
929
  ],
799
930
  value: "text-label-large text-on-surface-variant tabular-nums",
800
931
  tickList: "pointer-events-none absolute inset-0",
932
+ // Stop dots reverse across the tracks: primary on the inactive rail,
933
+ // secondary-container on the active fill; disabled dots are on-surface.
801
934
  tick: [
802
- "absolute size-1 -translate-x-1/2 -translate-y-1/2 rounded-full bg-on-surface-variant",
803
- "data-[active]:bg-on-primary/[0.38]"
935
+ "absolute size-1 -translate-x-1/2 -translate-y-1/2 rounded-full bg-primary",
936
+ "data-[active]:bg-secondary-container",
937
+ "group-data-[disabled]:bg-on-surface"
804
938
  ],
939
+ // Floating value indicator: inverse-surface container / inverse-on-surface
940
+ // text, 12dp above the handle.
805
941
  valueLabel: [
806
- "pointer-events-none absolute bottom-full left-1/2 mb-2 -translate-x-1/2 whitespace-nowrap rounded px-2 py-0.5",
807
- "bg-primary text-label-large text-on-primary tabular-nums opacity-0",
942
+ "pointer-events-none absolute bottom-full left-1/2 mb-3 -translate-x-1/2 whitespace-nowrap rounded px-2 py-0.5",
943
+ "bg-inverse-surface text-label-large text-inverse-on-surface tabular-nums opacity-0",
808
944
  "data-[visible]:opacity-100"
809
945
  ]
810
946
  }
@@ -823,7 +959,7 @@ var Slider = createSlider({
823
959
  });
824
960
  var surface2 = menuSurfaceTv({ width: "anchor", scroll: "auto" });
825
961
  var selectable2 = menuSelectableItem;
826
- var selectTv = tv7({
962
+ var selectTv = tv({
827
963
  slots: {
828
964
  trigger: [
829
965
  "group relative inline-flex items-center justify-between gap-2 box-border",
@@ -846,19 +982,10 @@ var selectTv = tv7({
846
982
  "data-[disabled]:[&_[data-slot=select-trailing]]:text-on-surface/[0.38]"
847
983
  ],
848
984
  itemIndicator: selectable2.itemIndicator(),
849
- groupLabel: surface2.groupLabel(),
850
- // Sticky scroll affordances at the popup edges; surface-tinted with a chevron.
851
- scrollUpArrow: [
852
- "sticky top-0 z-[1] flex items-center justify-center h-6 cursor-default",
853
- "bg-surface-container text-on-surface-variant [&>svg]:size-5"
854
- ],
855
- scrollDownArrow: [
856
- "sticky bottom-0 z-[1] flex items-center justify-center h-6 cursor-default",
857
- "bg-surface-container text-on-surface-variant [&>svg]:size-5"
858
- ]
985
+ groupLabel: surface2.groupLabel()
859
986
  }
860
987
  });
861
- var selectFieldTv = tv7({
988
+ var selectFieldTv = tv({
862
989
  slots: {
863
990
  // The `group` hook lives here (not in engine-neutral core): supporting text
864
991
  // keys its error color off Field.Root's `group-data-[invalid]`.
@@ -946,9 +1073,7 @@ var Select = createSelect(
946
1073
  popup: s3.popup(),
947
1074
  item: s3.item(),
948
1075
  itemIndicator: s3.itemIndicator(),
949
- groupLabel: s3.groupLabel(),
950
- scrollUpArrow: s3.scrollUpArrow(),
951
- scrollDownArrow: s3.scrollDownArrow()
1076
+ groupLabel: s3.groupLabel()
952
1077
  },
953
1078
  ({ variant }) => {
954
1079
  const f = selectFieldTv({ variant });
@@ -966,7 +1091,7 @@ var Select = createSelect(
966
1091
  }
967
1092
  );
968
1093
  var iconVisual = "inline-flex items-center justify-center shrink-0 text-on-surface-variant [&>svg]:size-6";
969
- var textFieldTv = tv({
1094
+ var textFieldTv = tv$1({
970
1095
  slots: {
971
1096
  root: "flex flex-col gap-1 min-w-[210px]",
972
1097
  field: [
@@ -1064,7 +1189,7 @@ var TextField = createTextField(({ variant }) => {
1064
1189
  counter: c3.counter()
1065
1190
  };
1066
1191
  });
1067
- var navigationBarTv = tv({
1192
+ var navigationBarTv = tv$1({
1068
1193
  slots: {
1069
1194
  root: "flex items-stretch justify-around w-full h-20 bg-surface-container",
1070
1195
  item: [
@@ -1119,7 +1244,7 @@ var NavigationBar = createNavigationBar({
1119
1244
  icon: s4.icon(),
1120
1245
  label: s4.label()
1121
1246
  });
1122
- var fabTv = tv({
1247
+ var fabTv = tv$1({
1123
1248
  base: [
1124
1249
  "relative inline-flex items-center justify-center box-border overflow-hidden",
1125
1250
  "border-0 cursor-pointer select-none outline-none",
@@ -1189,7 +1314,7 @@ var fabTv = tv({
1189
1314
  }
1190
1315
  });
1191
1316
  var Fab = createFab(({ size, color, variant }) => fabTv({ size, color, variant }));
1192
- var fabMenuTv = tv7({
1317
+ var fabMenuTv = tv({
1193
1318
  slots: {
1194
1319
  popup: [
1195
1320
  "flex flex-col items-end gap-1 bg-transparent outline-none",
@@ -1228,7 +1353,7 @@ var FabMenu = createFabMenu(({ size, color }) => fabTv({ size, color }), {
1228
1353
  popup: fabMenuTv().popup(),
1229
1354
  item: (color) => fabMenuTv({ color }).item()
1230
1355
  });
1231
- var dividerTv = tv({
1356
+ var dividerTv = tv$1({
1232
1357
  base: "shrink-0 self-stretch border-0 bg-outline-variant",
1233
1358
  variants: {
1234
1359
  orientation: {
@@ -1254,7 +1379,7 @@ var dividerTv = tv({
1254
1379
  }
1255
1380
  });
1256
1381
  var Divider = createDivider(({ inset, orientation }) => dividerTv({ inset, orientation }));
1257
- var linearTv = tv({
1382
+ var linearTv = tv$1({
1258
1383
  slots: {
1259
1384
  // The track-stop dot (primary, full track height) sits at the inline-end via
1260
1385
  // `after:`. It's a determinate-only M3 concept, so it's hidden while
@@ -1310,7 +1435,7 @@ var linearTv = tv({
1310
1435
  ]
1311
1436
  }
1312
1437
  });
1313
- var circularTv = tv({
1438
+ var circularTv = tv$1({
1314
1439
  slots: {
1315
1440
  // Size comes from the factory (inline width/height) so `size` is honored.
1316
1441
  // Indeterminate rotates the whole ring; the arc grows/shrinks via the
@@ -1346,7 +1471,7 @@ var Progress = createProgress({
1346
1471
  },
1347
1472
  circular: { root: c2.root(), track: c2.track(), indicator: c2.indicator() }
1348
1473
  });
1349
- var loadingIndicatorTv = tv7({
1474
+ var loadingIndicatorTv = tv({
1350
1475
  slots: {
1351
1476
  // The SVG is a fixed 38dp active indicator. Uncontained: the box shrinks to
1352
1477
  // the shape. Contained: a 48dp pill wraps it (5dp inset on each side).
@@ -1369,7 +1494,7 @@ var LoadingIndicator = createLoadingIndicator(({ contained }) => {
1369
1494
  const s14 = loadingIndicatorTv({ contained });
1370
1495
  return { root: s14.root(), indicator: s14.indicator() };
1371
1496
  });
1372
- var listTv = tv7({
1497
+ var listTv = tv({
1373
1498
  slots: {
1374
1499
  root: "list-none m-0 px-0 py-2 bg-transparent",
1375
1500
  item: [
@@ -1432,7 +1557,7 @@ var List = createList({
1432
1557
  };
1433
1558
  }
1434
1559
  });
1435
- var snackbarTv = tv({
1560
+ var snackbarTv = tv$1({
1436
1561
  slots: {
1437
1562
  viewport: [
1438
1563
  "fixed bottom-4 left-1/2 -translate-x-1/2 z-50",
@@ -1484,7 +1609,7 @@ var Snackbar = createSnackbar({
1484
1609
  action: s5.action(),
1485
1610
  close: s5.close()
1486
1611
  });
1487
- var itemTv = tv7({
1612
+ var itemTv = tv({
1488
1613
  slots: {
1489
1614
  root: [
1490
1615
  "relative flex w-full items-center gap-4 box-border px-4 py-3 min-h-14 text-left",
@@ -1515,7 +1640,7 @@ var Item = createItem({
1515
1640
  supporting: s6.supporting(),
1516
1641
  trailing: s6.trailing()
1517
1642
  });
1518
- var badgeTv = tv7({
1643
+ var badgeTv = tv({
1519
1644
  base: "pointer-events-none select-none inline-flex items-center justify-center bg-error text-on-error",
1520
1645
  variants: {
1521
1646
  size: {
@@ -1527,7 +1652,7 @@ var badgeTv = tv7({
1527
1652
  var Badge = createBadge({
1528
1653
  root: ({ size }) => badgeTv({ size })
1529
1654
  });
1530
- var cardTv = tv7({
1655
+ var cardTv = tv({
1531
1656
  base: "relative box-border rounded-medium text-on-surface",
1532
1657
  variants: {
1533
1658
  variant: {
@@ -1568,7 +1693,7 @@ var cardTv = tv7({
1568
1693
  var Card = createCard({
1569
1694
  root: ({ variant, interactive }) => cardTv({ variant, interactive })
1570
1695
  });
1571
- var segmentedButtonTv = tv7({
1696
+ var segmentedButtonTv = tv({
1572
1697
  slots: {
1573
1698
  root: "inline-flex items-stretch h-10 rounded-full border border-outline",
1574
1699
  item: [
@@ -1606,7 +1731,7 @@ var SegmentedButton = createSegmentedButton({
1606
1731
  icon: s7.icon(),
1607
1732
  label: s7.label()
1608
1733
  });
1609
- var buttonGroup = tv7({
1734
+ var buttonGroup = tv({
1610
1735
  base: "inline-flex items-center",
1611
1736
  variants: {
1612
1737
  variant: {
@@ -1664,7 +1789,7 @@ var VARIANT_TEXT = [
1664
1789
  "disabled:text-on-surface/38",
1665
1790
  "data-[disabled]:text-on-surface/38"
1666
1791
  ];
1667
- var splitButtonTv = tv7({
1792
+ var splitButtonTv = tv({
1668
1793
  slots: {
1669
1794
  group: "inline-flex items-center gap-0.5",
1670
1795
  // leading: outer (start) corner full, seam (end) corner reduced.
@@ -1714,7 +1839,7 @@ var SplitButton = createSplitButton({
1714
1839
  popup: splitButtonTv().popup(),
1715
1840
  item: splitButtonTv().item()
1716
1841
  });
1717
- var navigationDrawerTv = tv7({
1842
+ var navigationDrawerTv = tv({
1718
1843
  slots: {
1719
1844
  root: "flex flex-col gap-1 box-border w-[360px] p-3 bg-surface-container-low text-on-surface",
1720
1845
  headline: "px-4 pt-4 pb-1 text-title-small text-on-surface-variant",
@@ -1754,7 +1879,7 @@ var NavigationDrawer = createNavigationDrawer({
1754
1879
  label: s8.label(),
1755
1880
  trailing: s8.trailing()
1756
1881
  });
1757
- var topAppBarTv = tv7({
1882
+ var topAppBarTv = tv({
1758
1883
  slots: {
1759
1884
  root: "flex flex-col w-full box-border h-16 bg-surface text-on-surface",
1760
1885
  row: "flex items-center gap-1 h-16 px-1",
@@ -1784,7 +1909,7 @@ var TopAppBar = createTopAppBar((args) => {
1784
1909
  trailing: s14.trailing()
1785
1910
  };
1786
1911
  });
1787
- var bottomAppBarTv = tv7({
1912
+ var bottomAppBarTv = tv({
1788
1913
  slots: {
1789
1914
  root: "flex items-center justify-between w-full box-border h-20 px-1 bg-surface-container text-on-surface-variant",
1790
1915
  actions: "flex items-center gap-1 pl-2 [&_svg]:size-6",
@@ -1797,7 +1922,7 @@ var BottomAppBar = createBottomAppBar({
1797
1922
  actions: s9.actions(),
1798
1923
  fab: s9.fab()
1799
1924
  });
1800
- var navigationRailTv = tv7({
1925
+ var navigationRailTv = tv({
1801
1926
  slots: {
1802
1927
  root: "flex flex-col items-center gap-3 h-full w-20 py-5 bg-surface",
1803
1928
  header: "flex flex-col items-center gap-3 mb-1",
@@ -1851,7 +1976,7 @@ var NavigationRail = createNavigationRail({
1851
1976
  icon: s10.icon(),
1852
1977
  label: s10.label()
1853
1978
  });
1854
- var bottomSheetTv = tv7({
1979
+ var bottomSheetTv = tv({
1855
1980
  slots: {
1856
1981
  backdrop: [
1857
1982
  "fixed inset-0 z-40 bg-scrim/32",
@@ -1883,7 +2008,7 @@ var BottomSheet = createBottomSheet({
1883
2008
  title: s11.title(),
1884
2009
  description: s11.description()
1885
2010
  });
1886
- var sideSheetTv = tv7({
2011
+ var sideSheetTv = tv({
1887
2012
  slots: {
1888
2013
  backdrop: [
1889
2014
  "fixed inset-0 z-40 bg-scrim/32",
@@ -1935,7 +2060,7 @@ var SideSheet = createSideSheet({
1935
2060
  description: s12.description(),
1936
2061
  close: s12.close()
1937
2062
  });
1938
- var searchTv = tv7({
2063
+ var searchTv = tv({
1939
2064
  slots: {
1940
2065
  bar: [
1941
2066
  "flex items-center gap-1 h-14 min-w-[360px] max-w-full pl-4 pr-2",
@@ -2002,7 +2127,7 @@ var Search = createSearch({
2002
2127
  separator: s13.separator(),
2003
2128
  groupLabel: s13.groupLabel()
2004
2129
  });
2005
- var datePickerTv = tv7({
2130
+ var datePickerTv = tv({
2006
2131
  slots: {
2007
2132
  calendar: ["w-[328px] max-w-full p-3 text-on-surface"],
2008
2133
  header: ["flex items-center justify-between gap-2 h-12 pl-3 pr-1"],
@@ -2123,7 +2248,7 @@ var stateLayerBase = [
2123
2248
  "active:before:opacity-[var(--md-sys-state-pressed)]",
2124
2249
  "focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary focus-visible:outline-offset-2"
2125
2250
  ];
2126
- var timePickerTv = tv7({
2251
+ var timePickerTv = tv({
2127
2252
  slots: {
2128
2253
  root: ["inline-flex flex-col items-center p-2 text-on-surface"],
2129
2254
  header: ["flex items-center gap-3 min-h-[98px]"],
@@ -2193,7 +2318,7 @@ var TimePicker = createTimePicker(() => ({
2193
2318
  inputBox: tp.inputBox(),
2194
2319
  inputCaption: tp.inputCaption()
2195
2320
  }));
2196
- var toolbarTv = tv7({
2321
+ var toolbarTv = tv({
2197
2322
  base: "inline-flex items-center justify-center gap-1 box-border rounded-full shadow-level3 [&_svg]:size-6",
2198
2323
  variants: {
2199
2324
  variant: {
@@ -2210,17 +2335,23 @@ var toolbarTv = tv7({
2210
2335
  var Toolbar = createToolbar(
2211
2336
  ({ variant, orientation }) => toolbarTv({ variant, orientation })
2212
2337
  );
2213
- var carouselTv = tv7({
2338
+ var carouselTv = tv({
2214
2339
  slots: {
2215
2340
  root: [
2216
2341
  "flex gap-2 overflow-x-auto snap-x snap-mandatory scroll-smooth",
2217
- "[scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
2342
+ "[scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
2343
+ // Keyboard focus ring (M3: 3px secondary, 2px offset); keyboard-only.
2344
+ "outline-none focus-visible:outline-[3px] focus-visible:outline-offset-2 focus-visible:outline-secondary",
2345
+ // Reduced motion: jump instead of smooth-scrolling between snap cells.
2346
+ "motion-reduce:scroll-auto"
2218
2347
  ],
2219
2348
  item: "snap-start shrink-0 overflow-hidden rounded-large"
2220
2349
  },
2221
2350
  variants: {
2222
2351
  variant: {
2223
2352
  "multi-browse": { item: "w-40 h-56" },
2353
+ // Uniform, wider cells that scroll past the container edge.
2354
+ uncontained: { item: "w-56 h-56" },
2224
2355
  hero: { item: "w-72 h-56 snap-center" },
2225
2356
  "full-screen": {
2226
2357
  // gap-0: full-screen slides fill the viewport with no inter-slide gap.