@windmorph/react 0.2.2 → 0.2.4

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 (134) hide show
  1. package/dist/components/autocomplete/Autocomplete.d.ts +4 -1
  2. package/dist/components/autocomplete/Autocomplete.js +3 -5
  3. package/dist/components/autocomplete/Autocomplete.js.map +1 -1
  4. package/dist/components/badge/Badge.d.ts +5 -2
  5. package/dist/components/badge/Badge.js +7 -3
  6. package/dist/components/badge/Badge.js.map +1 -1
  7. package/dist/components/button/Button.d.ts +4 -2
  8. package/dist/components/button/Button.js.map +1 -1
  9. package/dist/components/button/ButtonContext.d.ts +1 -1
  10. package/dist/components/button/button-pending.js +2 -4
  11. package/dist/components/button/button-pending.js.map +1 -1
  12. package/dist/{composites → components}/button-group/ButtonGroup.d.ts +4 -4
  13. package/dist/{composites → components}/button-group/ButtonGroup.js +9 -7
  14. package/dist/components/button-group/ButtonGroup.js.map +1 -0
  15. package/dist/{composites → components}/button-group/button-group-styles.d.ts +1 -1
  16. package/dist/{composites → components}/button-group/button-group-styles.js +1 -1
  17. package/dist/{composites → components}/button-group/button-group-styles.js.map +1 -1
  18. package/dist/{composites → components}/button-group/lazy-overflow-menu.js +2 -2
  19. package/dist/components/button-group/lazy-overflow-menu.js.map +1 -0
  20. package/dist/{composites → components}/button-group/overflow-menu-list.js +2 -2
  21. package/dist/components/button-group/overflow-menu-list.js.map +1 -0
  22. package/dist/{composites → components}/button-group/use-overflow.js +1 -1
  23. package/dist/{composites → components}/button-group/use-overflow.js.map +1 -1
  24. package/dist/{composites → components}/button-group/use-press-expansion.js +1 -1
  25. package/dist/{composites → components}/button-group/use-press-expansion.js.map +1 -1
  26. package/dist/components/carousel/Carousel.d.ts +4 -1
  27. package/dist/components/carousel/Carousel.js +2 -4
  28. package/dist/components/carousel/Carousel.js.map +1 -1
  29. package/dist/components/checkbox/checkbox-styles.d.ts +3 -3
  30. package/dist/components/chip/Chip.d.ts +8 -2
  31. package/dist/components/chip/Chip.js +3 -8
  32. package/dist/components/chip/Chip.js.map +1 -1
  33. package/dist/components/chip/chip-tokens.d.ts +4 -4
  34. package/dist/components/date-picker/DateField.d.ts +4 -1
  35. package/dist/components/date-picker/DateField.js +3 -1
  36. package/dist/components/date-picker/DateField.js.map +1 -1
  37. package/dist/components/date-picker/DatePicker.d.ts +4 -1
  38. package/dist/components/date-picker/DatePicker.js +5 -2
  39. package/dist/components/date-picker/DatePicker.js.map +1 -1
  40. package/dist/components/date-picker/PickerDialog.d.ts +4 -1
  41. package/dist/components/date-picker/PickerDialog.js +3 -1
  42. package/dist/components/date-picker/PickerDialog.js.map +1 -1
  43. package/dist/components/date-picker/date-picker-styles.d.ts +12 -12
  44. package/dist/components/date-picker/date-picker-tokens.d.ts +1 -1
  45. package/dist/components/dialog/Dialog.d.ts +5 -2
  46. package/dist/components/dialog/Dialog.js +4 -2
  47. package/dist/components/dialog/Dialog.js.map +1 -1
  48. package/dist/components/dialog/dialog-tokens.d.ts +1 -1
  49. package/dist/components/fab-menu/FabMenu.js +2 -2
  50. package/dist/components/fab-menu/FabMenu.js.map +1 -1
  51. package/dist/components/icon-button/IconButton.d.ts +4 -2
  52. package/dist/components/icon-button/IconButton.js.map +1 -1
  53. package/dist/components/labels/LabelsProvider.d.ts +35 -0
  54. package/dist/components/labels/LabelsProvider.js +47 -0
  55. package/dist/components/labels/LabelsProvider.js.map +1 -0
  56. package/dist/components/labels/use-labels.d.ts +16 -0
  57. package/dist/components/labels/use-labels.js +42 -0
  58. package/dist/components/labels/use-labels.js.map +1 -0
  59. package/dist/components/menu/Menu.d.ts +17 -1
  60. package/dist/components/menu/Menu.js +21 -11
  61. package/dist/components/menu/Menu.js.map +1 -1
  62. package/dist/components/menu/menu-styles.js +12 -12
  63. package/dist/components/menu/menu-styles.js.map +1 -1
  64. package/dist/components/menu/menu-tokens.d.ts +1 -1
  65. package/dist/components/menu/menu-tokens.js.map +1 -1
  66. package/dist/components/navigation/NavItem.d.ts +1 -1
  67. package/dist/components/navigation/NavItem.js +9 -6
  68. package/dist/components/navigation/NavItem.js.map +1 -1
  69. package/dist/components/navigation/navigation-styles.js +1 -1
  70. package/dist/components/navigation/navigation-styles.js.map +1 -1
  71. package/dist/components/pull-to-refresh/PullToRefresh.d.ts +1 -1
  72. package/dist/components/pull-to-refresh/PullToRefresh.js +2 -4
  73. package/dist/components/pull-to-refresh/PullToRefresh.js.map +1 -1
  74. package/dist/components/search/SearchField.d.ts +4 -1
  75. package/dist/components/search/SearchField.js +2 -4
  76. package/dist/components/search/SearchField.js.map +1 -1
  77. package/dist/components/search/search-styles.js +2 -2
  78. package/dist/components/search/search-styles.js.map +1 -1
  79. package/dist/components/select/Select.d.ts +4 -1
  80. package/dist/components/select/Select.js +2 -4
  81. package/dist/components/select/Select.js.map +1 -1
  82. package/dist/components/sheet/BottomSheet.d.ts +4 -1
  83. package/dist/components/sheet/BottomSheet.js +2 -4
  84. package/dist/components/sheet/BottomSheet.js.map +1 -1
  85. package/dist/components/sheet/SideSheet.d.ts +4 -1
  86. package/dist/components/sheet/SideSheet.js +2 -4
  87. package/dist/components/sheet/SideSheet.js.map +1 -1
  88. package/dist/components/slider/Slider.d.ts +4 -1
  89. package/dist/components/slider/Slider.js +7 -5
  90. package/dist/components/slider/Slider.js.map +1 -1
  91. package/dist/components/snackbar/Snackbar.d.ts +8 -2
  92. package/dist/components/snackbar/Snackbar.js +2 -4
  93. package/dist/components/snackbar/Snackbar.js.map +1 -1
  94. package/dist/components/snackbar/snackbar-tokens.d.ts +1 -1
  95. package/dist/components/split-button/SplitButton.d.ts +4 -1
  96. package/dist/components/split-button/SplitButton.js +4 -2
  97. package/dist/components/split-button/SplitButton.js.map +1 -1
  98. package/dist/components/switch/switch-styles.d.ts +3 -3
  99. package/dist/components/text-field/TextField.d.ts +4 -1
  100. package/dist/components/text-field/TextField.js +2 -4
  101. package/dist/components/text-field/TextField.js.map +1 -1
  102. package/dist/components/text-field/text-field-styles.js +2 -2
  103. package/dist/components/text-field/text-field-styles.js.map +1 -1
  104. package/dist/components/time-picker/TimeField.d.ts +24 -2
  105. package/dist/components/time-picker/TimeField.js +40 -12
  106. package/dist/components/time-picker/TimeField.js.map +1 -1
  107. package/dist/components/time-picker/TimeFieldList.js +95 -0
  108. package/dist/components/time-picker/TimeFieldList.js.map +1 -0
  109. package/dist/components/time-picker/TimePicker.d.ts +9 -5
  110. package/dist/components/time-picker/TimePicker.js +5 -2
  111. package/dist/components/time-picker/TimePicker.js.map +1 -1
  112. package/dist/components/time-picker/time-list.js +33 -0
  113. package/dist/components/time-picker/time-list.js.map +1 -0
  114. package/dist/components/tooltip/Tooltip.d.ts +1 -1
  115. package/dist/components/tooltip/tooltip-tokens.d.ts +1 -1
  116. package/dist/index.d.ts +40 -38
  117. package/dist/index.js +4 -3
  118. package/dist/primitives/use-m3-interaction.js +10 -6
  119. package/dist/primitives/use-m3-interaction.js.map +1 -1
  120. package/dist/primitives.d.ts +7 -4
  121. package/dist/primitives.js +4 -1
  122. package/dist/styles/utilities.css +22 -15
  123. package/dist/styles.compiled.css +1 -1
  124. package/dist/utils/use-scroll-keys.d.ts +29 -0
  125. package/dist/utils/use-scroll-keys.js +66 -0
  126. package/dist/utils/use-scroll-keys.js.map +1 -0
  127. package/dist/utils/use-scroll-restoration.d.ts +43 -0
  128. package/dist/utils/use-scroll-restoration.js +173 -0
  129. package/dist/utils/use-scroll-restoration.js.map +1 -0
  130. package/dist/windmorph-labels.d.ts +101 -0
  131. package/package.json +1 -1
  132. package/dist/composites/button-group/ButtonGroup.js.map +0 -1
  133. package/dist/composites/button-group/lazy-overflow-menu.js.map +0 -1
  134. package/dist/composites/button-group/overflow-menu-list.js.map +0 -1
package/dist/index.js CHANGED
@@ -14,6 +14,7 @@ import { cn, twMergeConfig } from "./utils/cn.js";
14
14
  import { ThemeScope } from "./theme/ThemeScope.js";
15
15
  import { ThemeScript, getThemeScriptSource } from "./theme/ThemeScript.js";
16
16
  import { createTheme } from "./theme/create-theme.js";
17
+ import { LabelsProvider } from "./components/labels/LabelsProvider.js";
17
18
  import { getM3Spring } from "./motion/get-m3-spring.js";
18
19
  import { useM3Spring } from "./motion/use-m3-spring.js";
19
20
  import { tv } from "./utils/tv.js";
@@ -28,9 +29,9 @@ import { TooltipTrigger } from "./components/tooltip/tooltip-trigger.js";
28
29
  import { iconButtonStyles } from "./components/icon-button/icon-button-styles.js";
29
30
  import { IconButton } from "./components/icon-button/IconButton.js";
30
31
  import { iconButtonTokenSet } from "./components/icon-button/icon-button-tokens.js";
31
- import { buttonGroupStyles } from "./composites/button-group/button-group-styles.js";
32
+ import { buttonGroupStyles } from "./components/button-group/button-group-styles.js";
32
33
  import { ContextMenuTrigger, MenuTrigger } from "./components/menu/menu-trigger.js";
33
- import { ButtonGroup } from "./composites/button-group/ButtonGroup.js";
34
+ import { ButtonGroup } from "./components/button-group/ButtonGroup.js";
34
35
  import { extendedFabStyles, fabStyles } from "./components/fab/fab-styles.js";
35
36
  import { ExtendedFab, Fab } from "./components/fab/Fab.js";
36
37
  import { extendedFabTokenSet, fabTokenSet } from "./components/fab/fab-tokens.js";
@@ -136,4 +137,4 @@ import { TimePicker, TimePickerModeToggle, useTimePickerRoom } from "./component
136
137
  import { TimeField } from "./components/time-picker/TimeField.js";
137
138
  import { timePickerTokenSet } from "./components/time-picker/time-picker-tokens.js";
138
139
  import { Time, parseTime } from "@internationalized/date";
139
- export { AssistChip, Autocomplete, AutocompleteItem, AutocompleteSection, BREAKPOINTS, BREAKPOINT_NAMES, BUILT_IN_THEMES, BUILT_IN_THEME_NAMES, Badge, BadgedBox, BottomSheet, Button, ButtonContext, ButtonGroup, COLOR_MODES, COLOR_ROLES, CONTRAST_LEVELS, CONTRAST_LEVEL_NAMES, CORNERS, CORNER_NAMES, CUSTOM_COLORS, CUSTOM_COLOR_ROLES, Card, Carousel, Checkbox, ChipSet, CircularProgressIndicator, ContextMenuTrigger, DEFAULT_CUSTOM_COLORS, DEFAULT_DENSITY, DEFAULT_MOTION_SCHEME, DEFAULT_STORAGE_KEY, DEFAULT_THEME, DEFAULT_THEME_STATE, DENSITIES, DateField, DatePicker, DateRangePicker, Dialog, DialogActions, DialogContent, DialogHeader, DialogTitle, DialogTrigger, Divider, DockedToolbar, ELEVATION_LEVELS, ELEVATION_LEVEL_NAMES, ExtendedFab, FOCUS_INDICATOR, Fab, FabMenu, FabMenuItem, FilterChip, FloatingToolbar, IconButton, InputChip, LEGACY_DURATIONS, LEGACY_EASINGS, LabeledDivider, LinearProgressIndicator, List, ListItem, ListItemAvatar, ListItemImage, ListItemVideo, ListSection, LoadingIndicator, MOTION_SCHEMES, Menu, MenuGroup, MenuItem, MenuTrigger, NavigationBar, NavigationBarItem, NavigationRail, NavigationRailItem, OptionPopover, PALETTE_NAMES, PickerDialog, PullToRefresh, Radio, RadioGroup, RangeSlider, RichTooltip, RichTooltipTrigger, SCHEME_VARIANTS, SHADOW_AMBIENT_OPACITY, SHADOW_KEY_OPACITY, SPRINGS, SPRING_FAMILIES, SPRING_SPEEDS, SPRING_TOKEN_NAMES, STATE_OPACITIES, SearchAppBar, SearchBar, SearchField, Select, SelectItem, SelectSection, SheetTrigger, SideSheet, Slider, Snackbar, SnackbarHost, SnackbarHostState, SplitButton, SubmenuTrigger, SuggestionChip, Switch, TYPEFACES, TYPE_ROLES, TYPE_SCALE, Tab, Tabs, TextField, ThemeProvider, ThemeScope, ThemeScript, Time, TimeField, TimePicker, TimePickerModeToggle, ToggleGroupStateContext, ToolbarFab, Tooltip, TooltipPlacementContext, TooltipTrigger, TopAppBar, Z_INDEX, appBarTokenSet, assistChipTokenSet, badgeStyles, badgeTokenSet, badgedBoxStyles, bottomSheetStyles, bottomSheetTokenSet, buttonGroupStyles, buttonStyles, buttonTokenSet, buttonVariantClasses, cardStyles, cardTokenSet, carouselStyles, carouselTokenSet, checkboxStyles, checkboxTokenSet, chipSetStyles, chipStyles, circularProgressStyles, cn, color, colorAt, componentTokenList, componentTokensCss, corner, createTheme, datePickerStyles, datePickerTokenSet, defineComponentTokens, densityAttribute, dialogStyles, dialogTokenSet, dividerStyles, dividerTokenSet, dockedDatePickerStyles, dockedToolbarStyles, dockedToolbarTokenSet, elevation, extendedFabStyles, extendedFabTokenSet, fabMenuStyles, fabMenuTokenSet, fabStyles, fabTokenSet, filterChipTokenSet, floatingToolbarStyles, floatingToolbarTokenSet, getM3Spring, getThemeScriptSource, iconButtonStyles, iconButtonTokenSet, inputChipTokenSet, isComponentTokenSet, isDensity, labeledDividerStyles, linearProgressStyles, listMediaStyles, listStyles, listTokenSet, loadingIndicatorStyles, loadingIndicatorTokenSet, matchesSearch, menuStyles, menuTokenSet, navBarTokenSet, navItemStyles, navRailTokenSet, navigationBarStyles, navigationRailStyles, normalizeSearch, parseThemeState, parseTime, pickerDialogStyles, plainTooltipTokenSet, progressIndicatorTokenSet, pullToRefreshStyles, px, radioGroupStyles, radioStyles, radioTokenSet, richTooltipStyles, richTooltipTokenSet, searchAppBarStyles, searchBarStyles, searchBarTokenSet, searchFieldStyles, searchViewTokenSet, serializeThemeState, sideSheetStyles, sideSheetTokenSet, sliderStyles, sliderTokenSet, snackbarHostStyles, snackbarStyles, snackbarTokenSet, splitButtonStyles, splitButtonTokenSet, spring, springPosition, springSettleDuration, springToLinearEasing, suggestionChipTokenSet, switchStyles, switchTokenSet, tabsStyles, tabsTokenSet, textFieldStyles, textFieldTokenSet, themeAttributes, timePickerStyles, timePickerTokenSet, toMotionSpring, toolbarFabStyles, toolbarFabTokenSet, tooltipStyles, topAppBarStyles, tv, twMergeConfig, typeTokens, typescale, useM3Spring, useNavigationRail, useSnackbarHostState, useTheme, useThemeScope, useTimePickerRoom, useToolbarScrollExit, useToolbarScrollExpansion };
140
+ export { AssistChip, Autocomplete, AutocompleteItem, AutocompleteSection, BREAKPOINTS, BREAKPOINT_NAMES, BUILT_IN_THEMES, BUILT_IN_THEME_NAMES, Badge, BadgedBox, BottomSheet, Button, ButtonContext, ButtonGroup, COLOR_MODES, COLOR_ROLES, CONTRAST_LEVELS, CONTRAST_LEVEL_NAMES, CORNERS, CORNER_NAMES, CUSTOM_COLORS, CUSTOM_COLOR_ROLES, Card, Carousel, Checkbox, ChipSet, CircularProgressIndicator, ContextMenuTrigger, DEFAULT_CUSTOM_COLORS, DEFAULT_DENSITY, DEFAULT_MOTION_SCHEME, DEFAULT_STORAGE_KEY, DEFAULT_THEME, DEFAULT_THEME_STATE, DENSITIES, DateField, DatePicker, DateRangePicker, Dialog, DialogActions, DialogContent, DialogHeader, DialogTitle, DialogTrigger, Divider, DockedToolbar, ELEVATION_LEVELS, ELEVATION_LEVEL_NAMES, ExtendedFab, FOCUS_INDICATOR, Fab, FabMenu, FabMenuItem, FilterChip, FloatingToolbar, IconButton, InputChip, LEGACY_DURATIONS, LEGACY_EASINGS, LabeledDivider, LabelsProvider, LinearProgressIndicator, List, ListItem, ListItemAvatar, ListItemImage, ListItemVideo, ListSection, LoadingIndicator, MOTION_SCHEMES, Menu, MenuGroup, MenuItem, MenuTrigger, NavigationBar, NavigationBarItem, NavigationRail, NavigationRailItem, OptionPopover, PALETTE_NAMES, PickerDialog, PullToRefresh, Radio, RadioGroup, RangeSlider, RichTooltip, RichTooltipTrigger, SCHEME_VARIANTS, SHADOW_AMBIENT_OPACITY, SHADOW_KEY_OPACITY, SPRINGS, SPRING_FAMILIES, SPRING_SPEEDS, SPRING_TOKEN_NAMES, STATE_OPACITIES, SearchAppBar, SearchBar, SearchField, Select, SelectItem, SelectSection, SheetTrigger, SideSheet, Slider, Snackbar, SnackbarHost, SnackbarHostState, SplitButton, SubmenuTrigger, SuggestionChip, Switch, TYPEFACES, TYPE_ROLES, TYPE_SCALE, Tab, Tabs, TextField, ThemeProvider, ThemeScope, ThemeScript, Time, TimeField, TimePicker, TimePickerModeToggle, ToggleGroupStateContext, ToolbarFab, Tooltip, TooltipPlacementContext, TooltipTrigger, TopAppBar, Z_INDEX, appBarTokenSet, assistChipTokenSet, badgeStyles, badgeTokenSet, badgedBoxStyles, bottomSheetStyles, bottomSheetTokenSet, buttonGroupStyles, buttonStyles, buttonTokenSet, buttonVariantClasses, cardStyles, cardTokenSet, carouselStyles, carouselTokenSet, checkboxStyles, checkboxTokenSet, chipSetStyles, chipStyles, circularProgressStyles, cn, color, colorAt, componentTokenList, componentTokensCss, corner, createTheme, datePickerStyles, datePickerTokenSet, defineComponentTokens, densityAttribute, dialogStyles, dialogTokenSet, dividerStyles, dividerTokenSet, dockedDatePickerStyles, dockedToolbarStyles, dockedToolbarTokenSet, elevation, extendedFabStyles, extendedFabTokenSet, fabMenuStyles, fabMenuTokenSet, fabStyles, fabTokenSet, filterChipTokenSet, floatingToolbarStyles, floatingToolbarTokenSet, getM3Spring, getThemeScriptSource, iconButtonStyles, iconButtonTokenSet, inputChipTokenSet, isComponentTokenSet, isDensity, labeledDividerStyles, linearProgressStyles, listMediaStyles, listStyles, listTokenSet, loadingIndicatorStyles, loadingIndicatorTokenSet, matchesSearch, menuStyles, menuTokenSet, navBarTokenSet, navItemStyles, navRailTokenSet, navigationBarStyles, navigationRailStyles, normalizeSearch, parseThemeState, parseTime, pickerDialogStyles, plainTooltipTokenSet, progressIndicatorTokenSet, pullToRefreshStyles, px, radioGroupStyles, radioStyles, radioTokenSet, richTooltipStyles, richTooltipTokenSet, searchAppBarStyles, searchBarStyles, searchBarTokenSet, searchFieldStyles, searchViewTokenSet, serializeThemeState, sideSheetStyles, sideSheetTokenSet, sliderStyles, sliderTokenSet, snackbarHostStyles, snackbarStyles, snackbarTokenSet, splitButtonStyles, splitButtonTokenSet, spring, springPosition, springSettleDuration, springToLinearEasing, suggestionChipTokenSet, switchStyles, switchTokenSet, tabsStyles, tabsTokenSet, textFieldStyles, textFieldTokenSet, themeAttributes, timePickerStyles, timePickerTokenSet, toMotionSpring, toolbarFabStyles, toolbarFabTokenSet, tooltipStyles, topAppBarStyles, tv, twMergeConfig, typeTokens, typescale, useM3Spring, useNavigationRail, useSnackbarHostState, useTheme, useThemeScope, useTimePickerRoom, useToolbarScrollExit, useToolbarScrollExpansion };
@@ -15,18 +15,22 @@ const RIPPLE_START = {
15
15
  * one is still growing or fading. The ripple's animated properties are pinned to their start
16
16
  * values with their transitions off and flushed to style, then released: they transition
17
17
  * from this press's start to whatever the state layer's rules say (growing if
18
- * `data-rippling` is on, or once it turns on). Only the ripple's transitions are switched
19
- * off: the component's own (`--m3-transition-property`, such as a running corner morph) keep
20
- * running, so a quick second press doesn't make the corners jump.
18
+ * `data-rippling` is on, or once it turns on). They're pinned with no duration or delay, not by
19
+ * leaving them out of `transition-property`: a running transition whose property drops out of
20
+ * the list is cancelled and jumps to its end, as did a corner morph on a quick second press
21
+ * and a width an app animates through `className` (2026-11-10). A running transition keeps its
22
+ * own timing when the durations change, so nothing else is touched.
21
23
  */
22
24
  function restartRipple(element) {
23
25
  const { style } = element;
24
- const transitionProperty = style.transitionProperty;
25
- style.transitionProperty = "var(--m3-transition-property, --m3-none)";
26
+ const { transitionDuration, transitionDelay } = style;
27
+ style.transitionDuration = "0s";
28
+ style.transitionDelay = "0s";
26
29
  for (const [name, value] of Object.entries(RIPPLE_START)) style.setProperty(name, value);
27
30
  getComputedStyle(element).getPropertyValue("--m3-ripple-x");
28
31
  for (const name of Object.keys(RIPPLE_START)) style.removeProperty(name);
29
- style.transitionProperty = transitionProperty;
32
+ style.transitionDuration = transitionDuration;
33
+ style.transitionDelay = transitionDelay;
30
34
  }
31
35
  /**
32
36
  * Positions a new ripple at the press point (Compose `RippleAnimation`): it grows from 30%
@@ -1 +1 @@
1
- {"version":3,"file":"use-m3-interaction.js","names":[],"sources":["../../src/primitives/use-m3-interaction.ts"],"sourcesContent":["'use client';\n\nimport { mergeProps, useFocusRing, useHover, usePress, type PressEvents } from 'react-aria';\nimport {\n useEffect,\n useState,\n type DOMAttributes,\n type KeyboardEvent,\n type PointerEvent,\n type RefObject,\n} from 'react';\n\nexport interface M3InteractionOptions extends PressEvents {\n isDisabled?: boolean;\n isSelected?: boolean;\n isDragged?: boolean;\n /**\n * Pressed state from another React Aria hook (e.g. `useButton`). When provided,\n * this hook does not attach its own press handling.\n */\n isPressed?: boolean;\n /** Treat focus inside the element as focus on the element (e.g. text fields). */\n within?: boolean;\n /** Whether the element is a text input; focus is then always visible. */\n isTextInput?: boolean;\n autoFocus?: boolean;\n}\n\nexport interface M3InteractionState {\n isHovered: boolean;\n isPressed: boolean;\n isFocused: boolean;\n isFocusVisible: boolean;\n}\n\n/** `data-*` attributes read by the `state-layer` and `focus-ring` utilities. */\nexport interface M3InteractionDataAttributes {\n 'data-hovered'?: true;\n 'data-pressed'?: true;\n /** The ripple is showing: from press start until release, but at least 225ms. */\n 'data-rippling'?: true;\n 'data-focused'?: true;\n 'data-focus-visible'?: true;\n 'data-disabled'?: true;\n 'data-selected'?: true;\n 'data-dragged'?: true;\n}\n\nexport interface M3InteractionResult {\n /** Event handlers to spread on the interactive element. */\n interactionProps: DOMAttributes<HTMLElement>;\n dataAttributes: M3InteractionDataAttributes;\n state: M3InteractionState;\n}\n\nconst flag = (value: boolean | undefined): true | undefined => (value ? true : undefined);\n\n/** Compose `RippleAnimation`: the radius grows (and the centre travels) over 225ms. */\nexport const RIPPLE_GROW_MS = 225;\n\n/** The ripple's animated properties, pinned at the start of a new ripple. */\nconst RIPPLE_START = {\n '--m3-ripple-opacity': '0',\n '--m3-ripple-radius': 'var(--m3-ripple-start, 0px)',\n '--m3-ripple-x': 'var(--m3-ripple-origin-x, 50%)',\n '--m3-ripple-y': 'var(--m3-ripple-origin-y, 50%)',\n} as const;\n\n/**\n * Starts a fresh ripple on `element`, as Compose does for every press, even while the last\n * one is still growing or fading. The ripple's animated properties are pinned to their start\n * values with their transitions off and flushed to style, then released: they transition\n * from this press's start to whatever the state layer's rules say (growing if\n * `data-rippling` is on, or once it turns on). Only the ripple's transitions are switched\n * off: the component's own (`--m3-transition-property`, such as a running corner morph) keep\n * running, so a quick second press doesn't make the corners jump.\n */\nexport function restartRipple(element: HTMLElement) {\n const { style } = element;\n const transitionProperty = style.transitionProperty;\n style.transitionProperty = 'var(--m3-transition-property, --m3-none)';\n for (const [name, value] of Object.entries(RIPPLE_START)) style.setProperty(name, value);\n getComputedStyle(element).getPropertyValue('--m3-ripple-x');\n for (const name of Object.keys(RIPPLE_START)) style.removeProperty(name);\n style.transitionProperty = transitionProperty;\n}\n\n/**\n * Positions a new ripple at the press point (Compose `RippleAnimation`): it grows from 30%\n * of the element's longer side to half its diagonal plus 10px while its centre moves to the\n * middle. Without a point (a key press) it starts in the middle. For a state layer on a\n * child of the pressed element (a navigation item's pill), pass that child.\n */\nexport function setRippleOrigin(element: HTMLElement, clientX?: number, clientY?: number) {\n const rect = element.getBoundingClientRect();\n const x = clientX === undefined ? rect.width / 2 : clientX - rect.left;\n const y = clientY === undefined ? rect.height / 2 : clientY - rect.top;\n const { style } = element;\n style.setProperty('--m3-ripple-origin-x', `${x}px`);\n style.setProperty('--m3-ripple-origin-y', `${y}px`);\n style.setProperty('--m3-ripple-center-x', `${rect.width / 2}px`);\n style.setProperty('--m3-ripple-center-y', `${rect.height / 2}px`);\n style.setProperty('--m3-ripple-start', `${Math.max(rect.width, rect.height) * 0.3}px`);\n style.setProperty(\n '--m3-ripple-size',\n `${Math.ceil(Math.hypot(rect.width, rect.height) / 2 + 10)}px`,\n );\n restartRipple(element);\n}\n\n/**\n * Flags a press that starts while the element's corner morph is still running\n * (`data-rapid-press`). M3's buttons note that the web can use \"a modified motion curve to\n * avoid resonant effects from overlapping animations\": the `container-motion` utility then\n * morphs on the fast effects spring, which doesn't overshoot, instead of the fast spatial\n * one. The attribute is set on the element directly, before React renders the press, so\n * the morph that press starts already uses the modified curve. Call it before anything\n * that resets the element's transitions (such as `restartRipple`).\n */\nexport function markRapidPress(element: HTMLElement) {\n const morphing =\n typeof element.getAnimations === 'function' &&\n element\n .getAnimations()\n .some(\n (animation) =>\n animation instanceof CSSTransition &&\n animation.transitionProperty.endsWith('radius') &&\n animation.playState === 'running',\n );\n element.toggleAttribute('data-rapid-press', morphing);\n}\n\n/**\n * Whether a ripple should be showing. Compose always finishes a ripple's 225ms growth\n * before fading it out, so a quick tap still reaches the edges: this stays true from press\n * start until release, but for at least 225ms.\n */\nexport function useRippleHold(isPressed: boolean): boolean {\n const [wasPressed, setWasPressed] = useState(isPressed);\n const [held, setHeld] = useState(false);\n const [presses, setPresses] = useState(0);\n // Adjust state while rendering when a press starts (no effect, no extra paint).\n if (isPressed !== wasPressed) {\n setWasPressed(isPressed);\n if (isPressed) {\n setHeld(true);\n setPresses((n) => n + 1);\n }\n }\n useEffect(() => {\n if (!held) return;\n const timer = setTimeout(() => setHeld(false), RIPPLE_GROW_MS);\n return () => clearTimeout(timer);\n }, [held, presses]);\n return isPressed || held;\n}\n\n/**\n * M3 interaction states for any element: hover, press, focus-visible, selected,\n * dragged and disabled, exposed as `data-*` attributes, plus the ripple origin.\n * Pair with the `state-layer` and `focus-ring` utilities, which paint the state\n * layer and ripple as background layers on the element itself (no child nodes).\n */\nexport function useM3Interaction(\n options: M3InteractionOptions,\n ref: RefObject<HTMLElement | null>,\n): M3InteractionResult {\n const {\n isDisabled,\n isSelected,\n isDragged,\n within,\n isTextInput,\n autoFocus,\n onPress,\n onPressStart,\n onPressEnd,\n onPressChange,\n onPressUp,\n onClick,\n } = options;\n const hasExternalPress = options.isPressed !== undefined;\n\n // Only `usePress`'s own options: it spreads any others onto the props it returns, so this\n // hook's options (`isDragged`, `within` …) would reach the DOM as unknown attributes.\n const { pressProps, isPressed: isOwnPressed } = usePress({\n onPress,\n onPressStart,\n onPressEnd,\n onPressChange,\n onPressUp,\n onClick,\n ref,\n isDisabled: isDisabled || hasExternalPress,\n });\n const { hoverProps, isHovered } = useHover({ isDisabled });\n const { focusProps, isFocused, isFocusVisible } = useFocusRing({\n within,\n isTextInput,\n autoFocus,\n });\n\n const isPressed = hasExternalPress ? Boolean(options.isPressed) : isOwnPressed;\n const isRippling = useRippleHold(isPressed && !isDisabled);\n\n const rippleProps: DOMAttributes<HTMLElement> = {\n onPointerDown: (event: PointerEvent<HTMLElement>) => {\n if (!isDisabled && event.button === 0) {\n markRapidPress(event.currentTarget);\n setRippleOrigin(event.currentTarget, event.clientX, event.clientY);\n }\n },\n onKeyDown: (event: KeyboardEvent<HTMLElement>) => {\n if (!isDisabled && (event.key === 'Enter' || event.key === ' ')) {\n markRapidPress(event.currentTarget);\n setRippleOrigin(event.currentTarget);\n }\n },\n };\n\n return {\n interactionProps: mergeProps(\n hasExternalPress ? {} : pressProps,\n hoverProps,\n focusProps,\n rippleProps,\n ),\n dataAttributes: {\n 'data-hovered': flag(isHovered && !isDisabled),\n 'data-pressed': flag(isPressed && !isDisabled),\n 'data-rippling': flag(isRippling),\n 'data-focused': flag(isFocused),\n 'data-focus-visible': flag(isFocusVisible),\n 'data-disabled': flag(isDisabled),\n 'data-selected': flag(isSelected),\n 'data-dragged': flag(isDragged),\n },\n state: { isHovered, isPressed, isFocused, isFocusVisible },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-m3-interaction.js","names":[],"sources":["../../src/primitives/use-m3-interaction.ts"],"sourcesContent":["'use client';\n\nimport { mergeProps, useFocusRing, useHover, usePress, type PressEvents } from 'react-aria';\nimport {\n useEffect,\n useState,\n type DOMAttributes,\n type KeyboardEvent,\n type PointerEvent,\n type RefObject,\n} from 'react';\n\nexport interface M3InteractionOptions extends PressEvents {\n isDisabled?: boolean;\n isSelected?: boolean;\n isDragged?: boolean;\n /**\n * Pressed state from another React Aria hook (e.g. `useButton`). When provided,\n * this hook does not attach its own press handling.\n */\n isPressed?: boolean;\n /** Treat focus inside the element as focus on the element (e.g. text fields). */\n within?: boolean;\n /** Whether the element is a text input; focus is then always visible. */\n isTextInput?: boolean;\n autoFocus?: boolean;\n}\n\nexport interface M3InteractionState {\n isHovered: boolean;\n isPressed: boolean;\n isFocused: boolean;\n isFocusVisible: boolean;\n}\n\n/** `data-*` attributes read by the `state-layer` and `focus-ring` utilities. */\nexport interface M3InteractionDataAttributes {\n 'data-hovered'?: true;\n 'data-pressed'?: true;\n /** The ripple is showing: from press start until release, but at least 225ms. */\n 'data-rippling'?: true;\n 'data-focused'?: true;\n 'data-focus-visible'?: true;\n 'data-disabled'?: true;\n 'data-selected'?: true;\n 'data-dragged'?: true;\n}\n\nexport interface M3InteractionResult {\n /** Event handlers to spread on the interactive element. */\n interactionProps: DOMAttributes<HTMLElement>;\n dataAttributes: M3InteractionDataAttributes;\n state: M3InteractionState;\n}\n\nconst flag = (value: boolean | undefined): true | undefined => (value ? true : undefined);\n\n/** Compose `RippleAnimation`: the radius grows (and the centre travels) over 225ms. */\nexport const RIPPLE_GROW_MS = 225;\n\n/** The ripple's animated properties, pinned at the start of a new ripple. */\nconst RIPPLE_START = {\n '--m3-ripple-opacity': '0',\n '--m3-ripple-radius': 'var(--m3-ripple-start, 0px)',\n '--m3-ripple-x': 'var(--m3-ripple-origin-x, 50%)',\n '--m3-ripple-y': 'var(--m3-ripple-origin-y, 50%)',\n} as const;\n\n/**\n * Starts a fresh ripple on `element`, as Compose does for every press, even while the last\n * one is still growing or fading. The ripple's animated properties are pinned to their start\n * values with their transitions off and flushed to style, then released: they transition\n * from this press's start to whatever the state layer's rules say (growing if\n * `data-rippling` is on, or once it turns on). They're pinned with no duration or delay, not by\n * leaving them out of `transition-property`: a running transition whose property drops out of\n * the list is cancelled and jumps to its end, as did a corner morph on a quick second press\n * and a width an app animates through `className` (2026-11-10). A running transition keeps its\n * own timing when the durations change, so nothing else is touched.\n */\nexport function restartRipple(element: HTMLElement) {\n const { style } = element;\n const { transitionDuration, transitionDelay } = style;\n style.transitionDuration = '0s';\n style.transitionDelay = '0s';\n for (const [name, value] of Object.entries(RIPPLE_START)) style.setProperty(name, value);\n getComputedStyle(element).getPropertyValue('--m3-ripple-x');\n for (const name of Object.keys(RIPPLE_START)) style.removeProperty(name);\n style.transitionDuration = transitionDuration;\n style.transitionDelay = transitionDelay;\n}\n\n/**\n * Positions a new ripple at the press point (Compose `RippleAnimation`): it grows from 30%\n * of the element's longer side to half its diagonal plus 10px while its centre moves to the\n * middle. Without a point (a key press) it starts in the middle. For a state layer on a\n * child of the pressed element (a navigation item's pill), pass that child.\n */\nexport function setRippleOrigin(element: HTMLElement, clientX?: number, clientY?: number) {\n const rect = element.getBoundingClientRect();\n const x = clientX === undefined ? rect.width / 2 : clientX - rect.left;\n const y = clientY === undefined ? rect.height / 2 : clientY - rect.top;\n const { style } = element;\n style.setProperty('--m3-ripple-origin-x', `${x}px`);\n style.setProperty('--m3-ripple-origin-y', `${y}px`);\n style.setProperty('--m3-ripple-center-x', `${rect.width / 2}px`);\n style.setProperty('--m3-ripple-center-y', `${rect.height / 2}px`);\n style.setProperty('--m3-ripple-start', `${Math.max(rect.width, rect.height) * 0.3}px`);\n style.setProperty(\n '--m3-ripple-size',\n `${Math.ceil(Math.hypot(rect.width, rect.height) / 2 + 10)}px`,\n );\n restartRipple(element);\n}\n\n/**\n * Flags a press that starts while the element's corner morph is still running\n * (`data-rapid-press`). M3's buttons note that the web can use \"a modified motion curve to\n * avoid resonant effects from overlapping animations\": the `container-motion` utility then\n * morphs on the fast effects spring, which doesn't overshoot, instead of the fast spatial\n * one. The attribute is set on the element directly, before React renders the press, so\n * the morph that press starts already uses the modified curve. Call it before anything\n * that resets the element's transitions (such as `restartRipple`).\n */\nexport function markRapidPress(element: HTMLElement) {\n const morphing =\n typeof element.getAnimations === 'function' &&\n element\n .getAnimations()\n .some(\n (animation) =>\n animation instanceof CSSTransition &&\n animation.transitionProperty.endsWith('radius') &&\n animation.playState === 'running',\n );\n element.toggleAttribute('data-rapid-press', morphing);\n}\n\n/**\n * Whether a ripple should be showing. Compose always finishes a ripple's 225ms growth\n * before fading it out, so a quick tap still reaches the edges: this stays true from press\n * start until release, but for at least 225ms.\n */\nexport function useRippleHold(isPressed: boolean): boolean {\n const [wasPressed, setWasPressed] = useState(isPressed);\n const [held, setHeld] = useState(false);\n const [presses, setPresses] = useState(0);\n // Adjust state while rendering when a press starts (no effect, no extra paint).\n if (isPressed !== wasPressed) {\n setWasPressed(isPressed);\n if (isPressed) {\n setHeld(true);\n setPresses((n) => n + 1);\n }\n }\n useEffect(() => {\n if (!held) return;\n const timer = setTimeout(() => setHeld(false), RIPPLE_GROW_MS);\n return () => clearTimeout(timer);\n }, [held, presses]);\n return isPressed || held;\n}\n\n/**\n * M3 interaction states for any element: hover, press, focus-visible, selected,\n * dragged and disabled, exposed as `data-*` attributes, plus the ripple origin.\n * Pair with the `state-layer` and `focus-ring` utilities, which paint the state\n * layer and ripple as background layers on the element itself (no child nodes).\n */\nexport function useM3Interaction(\n options: M3InteractionOptions,\n ref: RefObject<HTMLElement | null>,\n): M3InteractionResult {\n const {\n isDisabled,\n isSelected,\n isDragged,\n within,\n isTextInput,\n autoFocus,\n onPress,\n onPressStart,\n onPressEnd,\n onPressChange,\n onPressUp,\n onClick,\n } = options;\n const hasExternalPress = options.isPressed !== undefined;\n\n // Only `usePress`'s own options: it spreads any others onto the props it returns, so this\n // hook's options (`isDragged`, `within` …) would reach the DOM as unknown attributes.\n const { pressProps, isPressed: isOwnPressed } = usePress({\n onPress,\n onPressStart,\n onPressEnd,\n onPressChange,\n onPressUp,\n onClick,\n ref,\n isDisabled: isDisabled || hasExternalPress,\n });\n const { hoverProps, isHovered } = useHover({ isDisabled });\n const { focusProps, isFocused, isFocusVisible } = useFocusRing({\n within,\n isTextInput,\n autoFocus,\n });\n\n const isPressed = hasExternalPress ? Boolean(options.isPressed) : isOwnPressed;\n const isRippling = useRippleHold(isPressed && !isDisabled);\n\n const rippleProps: DOMAttributes<HTMLElement> = {\n onPointerDown: (event: PointerEvent<HTMLElement>) => {\n if (!isDisabled && event.button === 0) {\n markRapidPress(event.currentTarget);\n setRippleOrigin(event.currentTarget, event.clientX, event.clientY);\n }\n },\n onKeyDown: (event: KeyboardEvent<HTMLElement>) => {\n if (!isDisabled && (event.key === 'Enter' || event.key === ' ')) {\n markRapidPress(event.currentTarget);\n setRippleOrigin(event.currentTarget);\n }\n },\n };\n\n return {\n interactionProps: mergeProps(\n hasExternalPress ? {} : pressProps,\n hoverProps,\n focusProps,\n rippleProps,\n ),\n dataAttributes: {\n 'data-hovered': flag(isHovered && !isDisabled),\n 'data-pressed': flag(isPressed && !isDisabled),\n 'data-rippling': flag(isRippling),\n 'data-focused': flag(isFocused),\n 'data-focus-visible': flag(isFocusVisible),\n 'data-disabled': flag(isDisabled),\n 'data-selected': flag(isSelected),\n 'data-dragged': flag(isDragged),\n },\n state: { isHovered, isPressed, isFocused, isFocusVisible },\n };\n}\n"],"mappings":"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"}
@@ -1,8 +1,9 @@
1
1
  import { ThemeScopeContext } from "./theme/context.js";
2
+ import { DescriptionAria, RootDOMProps, SplitRootProps, SplitRootPropsOptions, WidgetAria, WrapperRootDOMProps, pickDescriptionAria, pickWidgetAria, splitRootProps } from "./utils/root-props.js";
3
+ import { ButtonBase, ButtonBaseActionProps, ButtonBaseDivActionProps, ButtonBaseLinkProps, ButtonBasePendingProps, ButtonBaseProps, ButtonBaseRenderState, ButtonBaseToggleProps } from "./primitives/ButtonBase.js";
4
+ import { closedByOverlayOptions } from "./utils/closed-by.js";
2
5
  import { getM3Spring } from "./motion/get-m3-spring.js";
3
6
  import { useM3Spring } from "./motion/use-m3-spring.js";
4
- import { ButtonBase, ButtonBaseActionProps, ButtonBaseDivActionProps, ButtonBaseLinkProps, ButtonBasePendingProps, ButtonBaseProps, ButtonBaseRenderState, ButtonBaseToggleProps } from "./primitives/ButtonBase.js";
5
- import { DescriptionAria, RootDOMProps, SplitRootProps, SplitRootPropsOptions, WidgetAria, WrapperRootDOMProps, pickDescriptionAria, pickWidgetAria, splitRootProps } from "./utils/root-props.js";
6
7
  import { CornerRounding } from "./shapes/corner-rounding.js";
7
8
  import { PointTransformer } from "./shapes/point.js";
8
9
  import { Cubic } from "./shapes/cubic.js";
@@ -13,7 +14,6 @@ import { MaterialShapes } from "./shapes/material-shapes.js";
13
14
  import { Morph } from "./shapes/morph.js";
14
15
  import { M3MorphOptions, MorphShape, getMorph, morphPathAt } from "./primitives/morph-path.js";
15
16
  import { SelectionControl, SelectionControlClassNames, SelectionControlProps } from "./primitives/SelectionControl.js";
16
- import { closedByOverlayOptions } from "./utils/closed-by.js";
17
17
  import { M3InteractionDataAttributes, M3InteractionOptions, M3InteractionResult, M3InteractionState, useM3Interaction } from "./primitives/use-m3-interaction.js";
18
18
  import { Surface, SurfaceProps, SurfaceVariants, surfaceStyles } from "./primitives/Surface.js";
19
19
  import { Overlay, OverlayProps } from "./primitives/Overlay.js";
@@ -29,6 +29,9 @@ import { DomDirectionLocale, DomDirectionLocaleProps } from "./primitives/DomDir
29
29
  import { localeWithDirection } from "./primitives/locale-with-direction.js";
30
30
  import { useM3Morph } from "./primitives/use-m3-morph.js";
31
31
  import { KeepPressedInPlaceResult, useKeepPressedInPlace } from "./utils/keep-pressed-in-place.js";
32
+ import { ScrollKeysResult, useScrollKeys } from "./utils/use-scroll-keys.js";
33
+ import { ScrollRestorationOptions, useScrollRestoration } from "./utils/use-scroll-restoration.js";
34
+ import { LabelsKey, LabelsOf, useLabels } from "./components/labels/use-labels.js";
32
35
  import { mergeDataTokens } from "./utils/merge-data-tokens.js";
33
36
  import { splitDataAttributes } from "./utils/split-data-attributes.js";
34
37
  import { generateSchemeColors } from "./theme/scheme.js";
@@ -36,4 +39,4 @@ import { materialShapeMask } from "./shapes/mask.js";
36
39
  import { materialShapePaths } from "./shapes/generated/material-shape-path-record.js";
37
40
  import { MorphPathOptions, PathOptions, cubicsToPath, morphToPath, polygonToPath } from "./shapes/path.js";
38
41
  import { circle, pill, pillStar, rectangle, star } from "./shapes/shapes.js";
39
- export { ButtonBase, type ButtonBaseActionProps, type ButtonBaseDivActionProps, type ButtonBaseLinkProps, type ButtonBasePendingProps, type ButtonBaseProps, type ButtonBaseRenderState, type ButtonBaseToggleProps, CharacterCounter, type CharacterCounterProps, CornerRounding, Cubic, type DescriptionAria, DomDirectionLocale, type DomDirectionLocaleProps, ErrorText, type ErrorTextProps, FieldErrorIcon, type FieldErrorIconProps, FieldLabel, type FieldLabelProps, type KeepPressedInPlaceResult, type M3InteractionDataAttributes, type M3InteractionOptions, type M3InteractionResult, type M3InteractionState, type M3MorphOptions, MaterialShapeName, type MaterialShapePath, MaterialShapes, Morph, type MorphPathOptions, type MorphShape, Overlay, type OverlayProps, type PathOptions, type PointTransformer, type RootDOMProps, RoundedPolygon, SelectionControl, type SelectionControlClassNames, type SelectionControlProps, type SplitRootProps, type SplitRootPropsOptions, SupportingText, type SupportingTextProps, Surface, type SurfaceProps, type SurfaceVariants, ThemeScopeContext, TouchTarget, type TouchTargetProps, TriggerContext, type TriggerContextValue, type WidgetAria, type WrapperRootDOMProps, archShape, arrowShape, boomShape, bunShape, burstShape, circle, circleShape, clamShellShape, closedByOverlayOptions, clover4LeafShape, clover8LeafShape, cookie12SidedShape, cookie4SidedShape, cookie6SidedShape, cookie7SidedShape, cookie9SidedShape, cubicsToPath, diamondShape, fanShape, flowerShape, gemShape, generateSchemeColors, getM3Spring, getMorph, ghostishShape, heartShape, localeWithDirection, materialShapeMask, materialShapeNames, materialShapePaths, mergeDataTokens, morphPathAt, morphToPath, ovalShape, pentagonShape, pickDescriptionAria, pickWidgetAria, pill, pillShape, pillStar, pixelCircleShape, pixelTriangleShape, polygonToPath, puffyDiamondShape, puffyShape, rectangle, selectionControlStyles, semiCircleShape, slantedShape, softBoomShape, softBurstShape, splitDataAttributes, splitRootProps, springProgressWithVelocity, springWithVelocityToLinearEasing, squareShape, star, sunnyShape, surfaceStyles, toAriaPlacement, triangleShape, useKeepPressedInPlace, useM3Interaction, useM3Morph, useM3Spring, usePresence, useRevealEntering, useTriggerProps, verySunnyShape };
42
+ export { ButtonBase, type ButtonBaseActionProps, type ButtonBaseDivActionProps, type ButtonBaseLinkProps, type ButtonBasePendingProps, type ButtonBaseProps, type ButtonBaseRenderState, type ButtonBaseToggleProps, CharacterCounter, type CharacterCounterProps, CornerRounding, Cubic, type DescriptionAria, DomDirectionLocale, type DomDirectionLocaleProps, ErrorText, type ErrorTextProps, FieldErrorIcon, type FieldErrorIconProps, FieldLabel, type FieldLabelProps, type KeepPressedInPlaceResult, type LabelsKey, type LabelsOf, type M3InteractionDataAttributes, type M3InteractionOptions, type M3InteractionResult, type M3InteractionState, type M3MorphOptions, MaterialShapeName, type MaterialShapePath, MaterialShapes, Morph, type MorphPathOptions, type MorphShape, Overlay, type OverlayProps, type PathOptions, type PointTransformer, type RootDOMProps, RoundedPolygon, type ScrollKeysResult, type ScrollRestorationOptions, SelectionControl, type SelectionControlClassNames, type SelectionControlProps, type SplitRootProps, type SplitRootPropsOptions, SupportingText, type SupportingTextProps, Surface, type SurfaceProps, type SurfaceVariants, ThemeScopeContext, TouchTarget, type TouchTargetProps, TriggerContext, type TriggerContextValue, type WidgetAria, type WrapperRootDOMProps, archShape, arrowShape, boomShape, bunShape, burstShape, circle, circleShape, clamShellShape, closedByOverlayOptions, clover4LeafShape, clover8LeafShape, cookie12SidedShape, cookie4SidedShape, cookie6SidedShape, cookie7SidedShape, cookie9SidedShape, cubicsToPath, diamondShape, fanShape, flowerShape, gemShape, generateSchemeColors, getM3Spring, getMorph, ghostishShape, heartShape, localeWithDirection, materialShapeMask, materialShapeNames, materialShapePaths, mergeDataTokens, morphPathAt, morphToPath, ovalShape, pentagonShape, pickDescriptionAria, pickWidgetAria, pill, pillShape, pillStar, pixelCircleShape, pixelTriangleShape, polygonToPath, puffyDiamondShape, puffyShape, rectangle, selectionControlStyles, semiCircleShape, slantedShape, softBoomShape, softBurstShape, splitDataAttributes, splitRootProps, springProgressWithVelocity, springWithVelocityToLinearEasing, squareShape, star, sunnyShape, surfaceStyles, toAriaPlacement, triangleShape, useKeepPressedInPlace, useLabels, useM3Interaction, useM3Morph, useM3Spring, usePresence, useRevealEntering, useScrollKeys, useScrollRestoration, useTriggerProps, verySunnyShape };
@@ -1,5 +1,6 @@
1
1
  import { ThemeScopeContext } from "./theme/context.js";
2
2
  import { generateSchemeColors } from "./theme/scheme.js";
3
+ import { useLabels } from "./components/labels/use-labels.js";
3
4
  import { getM3Spring } from "./motion/get-m3-spring.js";
4
5
  import { useM3Spring } from "./motion/use-m3-spring.js";
5
6
  import { TriggerContext, useTriggerProps } from "./primitives/TriggerContext.js";
@@ -30,8 +31,10 @@ import { useKeepPressedInPlace } from "./utils/keep-pressed-in-place.js";
30
31
  import { springProgressWithVelocity, springWithVelocityToLinearEasing } from "./tokens/spring-velocity.js";
31
32
  import { Surface, surfaceStyles } from "./primitives/Surface.js";
32
33
  import { useM3Morph } from "./primitives/use-m3-morph.js";
34
+ import { useScrollKeys } from "./utils/use-scroll-keys.js";
35
+ import { useScrollRestoration } from "./utils/use-scroll-restoration.js";
33
36
  import { splitDataAttributes } from "./utils/split-data-attributes.js";
34
37
  import { materialShapeMask } from "./shapes/mask.js";
35
38
  import { archShape, arrowShape, boomShape, bunShape, burstShape, circleShape, clamShellShape, clover4LeafShape, clover8LeafShape, cookie12SidedShape, cookie4SidedShape, cookie6SidedShape, cookie7SidedShape, cookie9SidedShape, diamondShape, fanShape, flowerShape, gemShape, ghostishShape, heartShape, materialShapeNames, ovalShape, pentagonShape, pillShape, pixelCircleShape, pixelTriangleShape, puffyDiamondShape, puffyShape, semiCircleShape, slantedShape, softBoomShape, softBurstShape, squareShape, sunnyShape, triangleShape, verySunnyShape } from "./shapes/generated/material-shape-paths.js";
36
39
  import { materialShapePaths } from "./shapes/generated/material-shape-path-record.js";
37
- export { ButtonBase, CharacterCounter, CornerRounding, Cubic, DomDirectionLocale, ErrorText, FieldErrorIcon, FieldLabel, MaterialShapes, Morph, Overlay, RoundedPolygon, SelectionControl, SupportingText, Surface, ThemeScopeContext, TouchTarget, TriggerContext, archShape, arrowShape, boomShape, bunShape, burstShape, circle, circleShape, clamShellShape, closedByOverlayOptions, clover4LeafShape, clover8LeafShape, cookie12SidedShape, cookie4SidedShape, cookie6SidedShape, cookie7SidedShape, cookie9SidedShape, cubicsToPath, diamondShape, fanShape, flowerShape, gemShape, generateSchemeColors, getM3Spring, getMorph, ghostishShape, heartShape, localeWithDirection, materialShapeMask, materialShapeNames, materialShapePaths, mergeDataTokens, morphPathAt, morphToPath, ovalShape, pentagonShape, pickDescriptionAria, pickWidgetAria, pill, pillShape, pillStar, pixelCircleShape, pixelTriangleShape, polygonToPath, puffyDiamondShape, puffyShape, rectangle, selectionControlStyles, semiCircleShape, slantedShape, softBoomShape, softBurstShape, splitDataAttributes, splitRootProps, springProgressWithVelocity, springWithVelocityToLinearEasing, squareShape, star, sunnyShape, surfaceStyles, toAriaPlacement, triangleShape, useKeepPressedInPlace, useM3Interaction, useM3Morph, useM3Spring, usePresence, useRevealEntering, useTriggerProps, verySunnyShape };
40
+ export { ButtonBase, CharacterCounter, CornerRounding, Cubic, DomDirectionLocale, ErrorText, FieldErrorIcon, FieldLabel, MaterialShapes, Morph, Overlay, RoundedPolygon, SelectionControl, SupportingText, Surface, ThemeScopeContext, TouchTarget, TriggerContext, archShape, arrowShape, boomShape, bunShape, burstShape, circle, circleShape, clamShellShape, closedByOverlayOptions, clover4LeafShape, clover8LeafShape, cookie12SidedShape, cookie4SidedShape, cookie6SidedShape, cookie7SidedShape, cookie9SidedShape, cubicsToPath, diamondShape, fanShape, flowerShape, gemShape, generateSchemeColors, getM3Spring, getMorph, ghostishShape, heartShape, localeWithDirection, materialShapeMask, materialShapeNames, materialShapePaths, mergeDataTokens, morphPathAt, morphToPath, ovalShape, pentagonShape, pickDescriptionAria, pickWidgetAria, pill, pillShape, pillStar, pixelCircleShape, pixelTriangleShape, polygonToPath, puffyDiamondShape, puffyShape, rectangle, selectionControlStyles, semiCircleShape, slantedShape, softBoomShape, softBurstShape, splitDataAttributes, splitRootProps, springProgressWithVelocity, springWithVelocityToLinearEasing, squareShape, star, sunnyShape, surfaceStyles, toAriaPlacement, triangleShape, useKeepPressedInPlace, useLabels, useM3Interaction, useM3Morph, useM3Spring, usePresence, useRevealEntering, useScrollKeys, useScrollRestoration, useTriggerProps, verySunnyShape };
@@ -147,18 +147,30 @@
147
147
  transparent
148
148
  )
149
149
  );
150
- /* After the ripple: fade it out, then reset its radius and centre once it is invisible. */
150
+ /*
151
+ * After the ripple: fade it out, then reset its radius and centre once it is invisible. The
152
+ * states below change only these variables, never the transition itself, so an app's own
153
+ * transition through `className` (one class, which wins over this one at rest) keeps its
154
+ * timing while the element is pressed too (2026-11-10).
155
+ */
156
+ --m3-ripple-fade-duration: 150ms;
157
+ --m3-ripple-grow-duration: 0s;
158
+ --m3-ripple-grow-delay: 150ms;
159
+ --m3-ripple-grow-easing: linear;
151
160
  /* Components append their own transitions through the --m3-transition-* lists. */
152
161
  transition-property:
153
162
  --m3-state-opacity, --m3-ripple-opacity, --m3-ripple-radius, --m3-ripple-x, --m3-ripple-y,
154
163
  var(--m3-transition-property, --m3-none);
155
164
  transition-duration:
156
- var(--md-sys-motion-spring-effects-fast-duration), 150ms, 0s, 0s, 0s,
165
+ var(--md-sys-motion-spring-effects-fast-duration), var(--m3-ripple-fade-duration),
166
+ var(--m3-ripple-grow-duration), var(--m3-ripple-grow-duration), var(--m3-ripple-grow-duration),
157
167
  var(--m3-transition-duration, 0s);
158
- transition-delay: 0s, 0s, 150ms, 150ms, 150ms, var(--m3-transition-delay, 0s);
168
+ transition-delay:
169
+ 0s, 0s, var(--m3-ripple-grow-delay), var(--m3-ripple-grow-delay), var(--m3-ripple-grow-delay),
170
+ var(--m3-transition-delay, 0s);
159
171
  transition-timing-function:
160
- var(--md-sys-motion-spring-effects-fast-easing), linear, linear, linear, linear,
161
- var(--m3-transition-easing, linear);
172
+ var(--md-sys-motion-spring-effects-fast-easing), linear, var(--m3-ripple-grow-easing), linear,
173
+ linear, var(--m3-transition-easing, linear);
162
174
 
163
175
  &[data-hovered] {
164
176
  --m3-state-opacity: var(--md-sys-state-hover-state-layer-opacity);
@@ -181,13 +193,10 @@
181
193
  --m3-ripple-radius: var(--m3-ripple-size, 0px);
182
194
  --m3-ripple-x: var(--m3-ripple-center-x, 50%);
183
195
  --m3-ripple-y: var(--m3-ripple-center-y, 50%);
184
- transition-duration:
185
- var(--md-sys-motion-spring-effects-fast-duration), 75ms, 225ms, 225ms, 225ms,
186
- var(--m3-transition-duration, 0s);
187
- transition-delay: 0s, 0s, 0s, 0s, 0s, var(--m3-transition-delay, 0s);
188
- transition-timing-function:
189
- var(--md-sys-motion-spring-effects-fast-easing), linear, cubic-bezier(0.4, 0, 0.2, 1), linear,
190
- linear, var(--m3-transition-easing, linear);
196
+ --m3-ripple-fade-duration: 75ms;
197
+ --m3-ripple-grow-duration: 225ms;
198
+ --m3-ripple-grow-delay: 0s;
199
+ --m3-ripple-grow-easing: cubic-bezier(0.4, 0, 0.2, 1);
191
200
  }
192
201
  &[data-disabled] {
193
202
  --m3-state-opacity: 0;
@@ -197,9 +206,7 @@
197
206
  /* Reduced motion: the ripple appears at full size where it ends, with no growth or travel. */
198
207
  @media (prefers-reduced-motion: reduce) {
199
208
  &[data-rippling] {
200
- transition-duration:
201
- var(--md-sys-motion-spring-effects-fast-duration), 75ms, 0s, 0s, 0s,
202
- var(--m3-transition-duration, 0s);
209
+ --m3-ripple-grow-duration: 0s;
203
210
  }
204
211
  }
205
212
  }