@react-md/core 6.3.3 → 6.4.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.
- package/dist/CoreProviders.d.ts +1 -0
- package/dist/CoreProviders.js.map +1 -1
- package/dist/_base.scss +3 -0
- package/dist/_core.scss +1 -0
- package/dist/_utils.scss +15 -7
- package/dist/app-bar/AppBar.js.map +1 -1
- package/dist/app-bar/AppBarTitle.js.map +1 -1
- package/dist/autocomplete/AutocompleteListboxChildren.js.map +1 -1
- package/dist/autocomplete/types.js.map +1 -1
- package/dist/autocomplete/utils.js.map +1 -1
- package/dist/avatar/Avatar.js.map +1 -1
- package/dist/box/_box.scss +20 -1
- package/dist/box/styles.d.ts +39 -0
- package/dist/box/styles.js +39 -0
- package/dist/box/styles.js.map +1 -1
- package/dist/button/Button.js.map +1 -1
- package/dist/button/FloatingActionButton.js.map +1 -1
- package/dist/card/Card.js.map +1 -1
- package/dist/card/CardContent.js.map +1 -1
- package/dist/card/ClickableCard.js.map +1 -1
- package/dist/chip/Chip.js.map +1 -1
- package/dist/datetime/NativeDateField.js.map +1 -1
- package/dist/datetime/NativeTimeField.js.map +1 -1
- package/dist/datetime/useDateField.js.map +1 -1
- package/dist/datetime/useTimeField.js.map +1 -1
- package/dist/dialog/Dialog.js.map +1 -1
- package/dist/dialog/DialogContainer.js.map +1 -1
- package/dist/dialog/DialogContent.js.map +1 -1
- package/dist/dialog/DialogFooter.js.map +1 -1
- package/dist/divider/Divider.js.map +1 -1
- package/dist/draggable/useDraggable.js.map +1 -1
- package/dist/draggable/utils.js.map +1 -1
- package/dist/expansion-panel/ExpansionPanelHeader.js.map +1 -1
- package/dist/files/FileInput.js.map +1 -1
- package/dist/files/useFileUpload.js.map +1 -1
- package/dist/files/validation.js.map +1 -1
- package/dist/focus/useFocusContainer.js.map +1 -1
- package/dist/form/Fieldset.d.ts +19 -0
- package/dist/form/Fieldset.js +22 -2
- package/dist/form/Fieldset.js.map +1 -1
- package/dist/form/FormMessageContainer.js.map +1 -1
- package/dist/form/FormMessageCounter.js.map +1 -1
- package/dist/form/InputToggle.js.map +1 -1
- package/dist/form/Legend.d.ts +27 -5
- package/dist/form/Legend.js +39 -6
- package/dist/form/Legend.js.map +1 -1
- package/dist/form/Listbox.js.map +1 -1
- package/dist/form/ListboxProvider.js.map +1 -1
- package/dist/form/NativeSelect.js.map +1 -1
- package/dist/form/Password.js.map +1 -1
- package/dist/form/ResizingTextAreaWrapper.js.map +1 -1
- package/dist/form/Select.js.map +1 -1
- package/dist/form/Slider.js.map +1 -1
- package/dist/form/SliderContainer.js.map +1 -1
- package/dist/form/SliderThumb.js.map +1 -1
- package/dist/form/SliderTrack.js.map +1 -1
- package/dist/form/SliderValueMarks.js.map +1 -1
- package/dist/form/Switch.js.map +1 -1
- package/dist/form/TextArea.js.map +1 -1
- package/dist/form/TextField.js.map +1 -1
- package/dist/form/TextFieldContainer.js.map +1 -1
- package/dist/form/_fieldset.scss +7 -0
- package/dist/form/_legend.scss +68 -0
- package/dist/form/_text-field.scss +39 -4
- package/dist/form/fieldsetStyles.d.ts +6 -1
- package/dist/form/fieldsetStyles.js +3 -2
- package/dist/form/fieldsetStyles.js.map +1 -1
- package/dist/form/inputToggleStyles.js.map +1 -1
- package/dist/form/labelStyles.d.ts +1 -1
- package/dist/form/labelStyles.js +1 -1
- package/dist/form/labelStyles.js.map +1 -1
- package/dist/form/legendStyles.d.ts +83 -0
- package/dist/form/legendStyles.js +25 -0
- package/dist/form/legendStyles.js.map +1 -0
- package/dist/form/selectUtils.js.map +1 -1
- package/dist/form/textFieldContainerStyles.js.map +1 -1
- package/dist/form/types.d.ts +28 -6
- package/dist/form/types.js.map +1 -1
- package/dist/form/useCheckboxGroup.js.map +1 -1
- package/dist/form/useCombobox.js.map +1 -1
- package/dist/form/useNumberField.js +16 -19
- package/dist/form/useNumberField.js.map +1 -1
- package/dist/form/useRangeSlider.js.map +1 -1
- package/dist/form/useSlider.js.map +1 -1
- package/dist/form/useTextField.d.ts +1 -1
- package/dist/form/useTextField.js.map +1 -1
- package/dist/hoverMode/useHoverMode.js.map +1 -1
- package/dist/icon/FontIcon.js.map +1 -1
- package/dist/icon/IconRotator.js.map +1 -1
- package/dist/icon/MaterialIcon.js.map +1 -1
- package/dist/icon/MaterialSymbol.js.map +1 -1
- package/dist/icon/SVGIcon.js.map +1 -1
- package/dist/icon/config.d.ts +0 -1
- package/dist/icon/config.js +10 -7
- package/dist/icon/config.js.map +1 -1
- package/dist/icon/materialConfig.js.map +1 -1
- package/dist/icon/styles.js.map +1 -1
- package/dist/interaction/UserInteractionModeProvider.js +6 -4
- package/dist/interaction/UserInteractionModeProvider.js.map +1 -1
- package/dist/interaction/types.js.map +1 -1
- package/dist/interaction/useElementInteraction.js.map +1 -1
- package/dist/layout/LayoutAppBar.d.ts +6 -6
- package/dist/layout/LayoutAppBar.js +6 -6
- package/dist/layout/LayoutAppBar.js.map +1 -1
- package/dist/layout/LayoutNav.js.map +1 -1
- package/dist/layout/LayoutWindowSplitter.js.map +1 -1
- package/dist/layout/Main.js.map +1 -1
- package/dist/layout/useExpandableLayout.js +43 -0
- package/dist/layout/useExpandableLayout.js.map +1 -1
- package/dist/layout/useHorizontalLayoutTransition.js.map +1 -1
- package/dist/layout/useLayoutTree.js.map +1 -1
- package/dist/layout/useLayoutWindowSplitter.js.map +1 -1
- package/dist/layout/useResizableLayout.js.map +1 -1
- package/dist/link/Link.js.map +1 -1
- package/dist/link/SkipToMainContent.js +19 -21
- package/dist/link/SkipToMainContent.js.map +1 -1
- package/dist/list/List.js.map +1 -1
- package/dist/list/ListItem.js.map +1 -1
- package/dist/list/ListItemAddon.js.map +1 -1
- package/dist/list/ListItemLink.js.map +1 -1
- package/dist/list/ListSubheader.js.map +1 -1
- package/dist/list/getListItemHeight.js.map +1 -1
- package/dist/list/listItemStyles.js.map +1 -1
- package/dist/list/types.js.map +1 -1
- package/dist/media-queries/AppSizeProvider.d.ts +2 -0
- package/dist/media-queries/AppSizeProvider.js +3 -2
- package/dist/media-queries/AppSizeProvider.js.map +1 -1
- package/dist/media-queries/appSize.d.ts +3 -0
- package/dist/media-queries/appSize.js +3 -1
- package/dist/media-queries/appSize.js.map +1 -1
- package/dist/media-queries/config.d.ts +11 -0
- package/dist/media-queries/config.js +26 -0
- package/dist/media-queries/config.js.map +1 -0
- package/dist/menu/DropdownMenu.js.map +1 -1
- package/dist/menu/Menu.js.map +1 -1
- package/dist/menu/MenuItemButton.js.map +1 -1
- package/dist/menu/MenuItemFileInput.js.map +1 -1
- package/dist/menu/MenuItemInputToggle.js.map +1 -1
- package/dist/menu/MenuItemSeparator.js.map +1 -1
- package/dist/menu/MenuVisibilityProvider.js.map +1 -1
- package/dist/menu/MenuWidget.js.map +1 -1
- package/dist/menu/useContextMenu.js.map +1 -1
- package/dist/movement/types.d.ts +28 -3
- package/dist/movement/types.js.map +1 -1
- package/dist/movement/useKeyboardMovementProvider.js +96 -47
- package/dist/movement/useKeyboardMovementProvider.js.map +1 -1
- package/dist/navigation/CollapsibleNavGroup.js.map +1 -1
- package/dist/navigation/NavItem.js.map +1 -1
- package/dist/navigation/NavItemButton.js.map +1 -1
- package/dist/navigation/NavItemLink.js.map +1 -1
- package/dist/navigation/getTableOfContentsHeadings.js.map +1 -1
- package/dist/navigation/types.js.map +1 -1
- package/dist/overlay/Overlay.js.map +1 -1
- package/dist/positioning/createHorizontalPosition.js.map +1 -1
- package/dist/positioning/createVerticalPosition.js.map +1 -1
- package/dist/positioning/useFixedPositioning.js.map +1 -1
- package/dist/progress/CircularProgress.js.map +1 -1
- package/dist/progress/LinearProgress.js.map +1 -1
- package/dist/progress/linearProgressStyles.js.map +1 -1
- package/dist/responsive-item/ResponsiveItem.js.map +1 -1
- package/dist/responsive-item/ResponsiveItemOverlay.js.map +1 -1
- package/dist/searching/caseInsensitive.js.map +1 -1
- package/dist/segmented-button/SegmentedButton.js.map +1 -1
- package/dist/segmented-button/SegmentedButtonContainer.js.map +1 -1
- package/dist/segmented-button/segmentedButtonStyles.js.map +1 -1
- package/dist/sheet/Sheet.js.map +1 -1
- package/dist/snackbar/Toast.js.map +1 -1
- package/dist/spinbutton/SpinButton.d.ts +16 -0
- package/dist/spinbutton/SpinButton.js +55 -0
- package/dist/spinbutton/SpinButton.js.map +1 -0
- package/dist/spinbutton/SpinButtonGroupProvider.d.ts +17 -0
- package/dist/spinbutton/SpinButtonGroupProvider.js +19 -0
- package/dist/spinbutton/SpinButtonGroupProvider.js.map +1 -0
- package/dist/spinbutton/defaults.d.ts +9 -0
- package/dist/spinbutton/defaults.js +25 -0
- package/dist/spinbutton/defaults.js.map +1 -0
- package/dist/spinbutton/types.d.ts +324 -0
- package/dist/spinbutton/types.js +5 -0
- package/dist/spinbutton/types.js.map +1 -0
- package/dist/spinbutton/useSpinButton.d.ts +5 -0
- package/dist/spinbutton/useSpinButton.js +260 -0
- package/dist/spinbutton/useSpinButton.js.map +1 -0
- package/dist/spinbutton/useSpinButtonGroupProvider.d.ts +27 -0
- package/dist/spinbutton/useSpinButtonGroupProvider.js +49 -0
- package/dist/spinbutton/useSpinButtonGroupProvider.js.map +1 -0
- package/dist/spinbutton/utils/deselectNode.d.ts +5 -0
- package/dist/spinbutton/utils/deselectNode.js +17 -0
- package/dist/spinbutton/utils/deselectNode.js.map +1 -0
- package/dist/spinbutton/utils/resolveInputEvent.d.ts +30 -0
- package/dist/spinbutton/utils/resolveInputEvent.js +53 -0
- package/dist/spinbutton/utils/resolveInputEvent.js.map +1 -0
- package/dist/spinbutton/utils/selectNode.d.ts +5 -0
- package/dist/spinbutton/utils/selectNode.js +15 -0
- package/dist/spinbutton/utils/selectNode.js.map +1 -0
- package/dist/table/StickyTableSection.js.map +1 -1
- package/dist/table/Table.js.map +1 -1
- package/dist/table/TableBody.js.map +1 -1
- package/dist/table/TableCellContent.js.map +1 -1
- package/dist/table/TableCheckbox.js.map +1 -1
- package/dist/table/TableFooter.js.map +1 -1
- package/dist/table/TableHeader.js.map +1 -1
- package/dist/table/TableRadio.js.map +1 -1
- package/dist/table/TableRow.js.map +1 -1
- package/dist/table/useStickyTableSection.js.map +1 -1
- package/dist/tabs/SimpleTabPanel.js.map +1 -1
- package/dist/tabs/SimpleTabPanels.js.map +1 -1
- package/dist/tabs/Tab.js.map +1 -1
- package/dist/tabs/TabList.js.map +1 -1
- package/dist/tabs/TabListScrollButton.js.map +1 -1
- package/dist/tabs/useMaxTabPanelHeight.js.map +1 -1
- package/dist/test-utils/data-testid.js.map +1 -1
- package/dist/test-utils/mocks/match-media.js +5 -5
- package/dist/test-utils/mocks/match-media.js.map +1 -1
- package/dist/test-utils/vitest/timers.d.ts +1 -1
- package/dist/test-utils/vitest/timers.js +1 -1
- package/dist/test-utils/vitest/timers.js.map +1 -1
- package/dist/tooltip/Tooltip.js.map +1 -1
- package/dist/tooltip/TooltipHoverModeProvider.js.map +1 -1
- package/dist/tooltip/useTooltip.js.map +1 -1
- package/dist/transition/CSSTransition.js.map +1 -1
- package/dist/transition/Collapse.js.map +1 -1
- package/dist/transition/CrossFade.js.map +1 -1
- package/dist/transition/ScaleTransition.js.map +1 -1
- package/dist/transition/SkeletonPlaceholder.js.map +1 -1
- package/dist/transition/Slide.js.map +1 -1
- package/dist/transition/SlideContainer.js.map +1 -1
- package/dist/transition/types.js.map +1 -1
- package/dist/transition/useCollapseTransition.js.map +1 -1
- package/dist/transition/useCrossFadeTransition.js.map +1 -1
- package/dist/transition/useMaxWidthTransition.js.map +1 -1
- package/dist/transition/useScaleTransition.js.map +1 -1
- package/dist/transition/useSkeletonPlaceholder.js.map +1 -1
- package/dist/tree/Tree.js.map +1 -1
- package/dist/tree/TreeItem.js.map +1 -1
- package/dist/tree/TreeProvider.js.map +1 -1
- package/dist/tree/styles.js.map +1 -1
- package/dist/tree/types.js.map +1 -1
- package/dist/tree/useTreeMovement.js.map +1 -1
- package/dist/typography/HighlightTextMark.js.map +1 -1
- package/dist/typography/Mark.js.map +1 -1
- package/dist/typography/TextContainer.js.map +1 -1
- package/dist/typography/Typography.js.map +1 -1
- package/dist/typography/_typography.scss +0 -1
- package/dist/useElementSize.js.map +1 -1
- package/dist/useIntersectionObserver.js.map +1 -1
- package/dist/useMutationObserver.js.map +1 -1
- package/dist/useWindowSize.js.map +1 -1
- package/dist/utils/getNumberOfDigits.d.ts +7 -0
- package/dist/utils/getNumberOfDigits.js +11 -0
- package/dist/utils/getNumberOfDigits.js.map +1 -0
- package/dist/utils/nearest.js +2 -1
- package/dist/utils/nearest.js.map +1 -1
- package/dist/utils/useDevEffect.d.ts +7 -0
- package/dist/utils/useDevEffect.js +8 -0
- package/dist/utils/useDevEffect.js.map +1 -0
- package/dist/window-splitter/WindowSplitter.js +3 -2
- package/dist/window-splitter/WindowSplitter.js.map +1 -1
- package/dist/window-splitter/_window-splitter.scss +60 -12
- package/dist/window-splitter/styles.d.ts +9 -0
- package/dist/window-splitter/styles.js +3 -2
- package/dist/window-splitter/styles.js.map +1 -1
- package/dist/window-splitter/useWindowSplitter.js.map +1 -1
- package/package.json +38 -30
- package/src/CoreProviders.tsx +1 -0
- package/src/app-bar/AppBar.tsx +1 -2
- package/src/app-bar/AppBarTitle.tsx +1 -2
- package/src/autocomplete/AutocompleteListboxChildren.tsx +3 -1
- package/src/autocomplete/types.ts +24 -19
- package/src/autocomplete/utils.ts +9 -6
- package/src/avatar/Avatar.tsx +2 -1
- package/src/box/styles.ts +39 -0
- package/src/button/Button.tsx +2 -1
- package/src/button/FloatingActionButton.tsx +2 -1
- package/src/card/Card.tsx +2 -1
- package/src/card/CardContent.tsx +1 -2
- package/src/card/ClickableCard.tsx +1 -2
- package/src/chip/Chip.tsx +2 -1
- package/src/datetime/NativeDateField.tsx +2 -1
- package/src/datetime/NativeTimeField.tsx +2 -1
- package/src/datetime/useDateField.ts +13 -8
- package/src/datetime/useTimeField.ts +13 -8
- package/src/dialog/Dialog.tsx +2 -1
- package/src/dialog/DialogContainer.tsx +1 -2
- package/src/dialog/DialogContent.tsx +1 -2
- package/src/dialog/DialogFooter.tsx +1 -2
- package/src/divider/Divider.tsx +1 -2
- package/src/draggable/useDraggable.ts +4 -4
- package/src/draggable/utils.ts +4 -2
- package/src/expansion-panel/ExpansionPanelHeader.tsx +1 -2
- package/src/files/FileInput.tsx +2 -1
- package/src/files/useFileUpload.ts +6 -6
- package/src/files/validation.ts +1 -2
- package/src/focus/useFocusContainer.ts +4 -4
- package/src/form/Fieldset.tsx +25 -3
- package/src/form/FormMessageContainer.tsx +1 -2
- package/src/form/FormMessageCounter.tsx +1 -2
- package/src/form/InputToggle.tsx +3 -3
- package/src/form/Legend.tsx +55 -10
- package/src/form/Listbox.tsx +1 -2
- package/src/form/ListboxProvider.ts +3 -2
- package/src/form/NativeSelect.tsx +2 -1
- package/src/form/Password.tsx +4 -2
- package/src/form/ResizingTextAreaWrapper.tsx +1 -2
- package/src/form/Select.tsx +2 -1
- package/src/form/Slider.tsx +2 -1
- package/src/form/SliderContainer.tsx +1 -2
- package/src/form/SliderThumb.tsx +6 -3
- package/src/form/SliderTrack.tsx +2 -1
- package/src/form/SliderValueMarks.tsx +1 -2
- package/src/form/Switch.tsx +2 -1
- package/src/form/TextArea.tsx +1 -2
- package/src/form/TextField.tsx +2 -1
- package/src/form/TextFieldContainer.tsx +1 -2
- package/src/form/fieldsetStyles.ts +18 -3
- package/src/form/inputToggleStyles.ts +4 -2
- package/src/form/labelStyles.ts +1 -1
- package/src/form/legendStyles.ts +132 -0
- package/src/form/selectUtils.ts +3 -2
- package/src/form/textFieldContainerStyles.ts +1 -2
- package/src/form/types.ts +35 -17
- package/src/form/useCheckboxGroup.ts +3 -2
- package/src/form/useCombobox.ts +8 -3
- package/src/form/useNumberField.ts +36 -35
- package/src/form/useRangeSlider.ts +1 -2
- package/src/form/useSlider.ts +1 -2
- package/src/form/useTextField.ts +9 -4
- package/src/hoverMode/useHoverMode.ts +4 -8
- package/src/icon/FontIcon.tsx +1 -2
- package/src/icon/IconRotator.tsx +1 -2
- package/src/icon/MaterialIcon.tsx +2 -1
- package/src/icon/MaterialSymbol.tsx +2 -1
- package/src/icon/SVGIcon.tsx +1 -2
- package/src/icon/config.tsx +10 -7
- package/src/icon/materialConfig.ts +1 -2
- package/src/icon/styles.ts +1 -2
- package/src/interaction/UserInteractionModeProvider.tsx +9 -4
- package/src/interaction/types.ts +1 -2
- package/src/interaction/useElementInteraction.tsx +3 -2
- package/src/layout/LayoutAppBar.tsx +6 -6
- package/src/layout/LayoutNav.tsx +2 -1
- package/src/layout/LayoutWindowSplitter.tsx +2 -1
- package/src/layout/Main.tsx +1 -2
- package/src/layout/useExpandableLayout.ts +63 -5
- package/src/layout/useHorizontalLayoutTransition.ts +1 -2
- package/src/layout/useLayoutTree.ts +2 -2
- package/src/layout/useLayoutWindowSplitter.ts +6 -6
- package/src/layout/useResizableLayout.ts +3 -6
- package/src/link/Link.tsx +1 -2
- package/src/link/SkipToMainContent.tsx +20 -23
- package/src/list/List.tsx +1 -2
- package/src/list/ListItem.tsx +2 -1
- package/src/list/ListItemAddon.tsx +2 -1
- package/src/list/ListItemLink.tsx +2 -1
- package/src/list/ListSubheader.tsx +1 -2
- package/src/list/getListItemHeight.ts +8 -9
- package/src/list/listItemStyles.ts +1 -2
- package/src/list/types.ts +1 -2
- package/src/media-queries/AppSizeProvider.tsx +8 -10
- package/src/media-queries/appSize.ts +3 -0
- package/src/media-queries/config.ts +41 -0
- package/src/menu/DropdownMenu.tsx +4 -5
- package/src/menu/Menu.tsx +2 -1
- package/src/menu/MenuItemButton.tsx +1 -2
- package/src/menu/MenuItemFileInput.tsx +2 -1
- package/src/menu/MenuItemInputToggle.tsx +3 -3
- package/src/menu/MenuItemSeparator.tsx +2 -1
- package/src/menu/MenuVisibilityProvider.tsx +4 -2
- package/src/menu/MenuWidget.tsx +1 -2
- package/src/menu/useContextMenu.ts +4 -2
- package/src/movement/types.ts +52 -13
- package/src/movement/useKeyboardMovementProvider.ts +77 -38
- package/src/navigation/CollapsibleNavGroup.tsx +1 -2
- package/src/navigation/NavItem.tsx +1 -2
- package/src/navigation/NavItemButton.tsx +2 -1
- package/src/navigation/NavItemLink.tsx +2 -1
- package/src/navigation/getTableOfContentsHeadings.ts +1 -2
- package/src/navigation/types.ts +1 -2
- package/src/overlay/Overlay.tsx +2 -1
- package/src/positioning/createHorizontalPosition.ts +10 -12
- package/src/positioning/createVerticalPosition.ts +10 -11
- package/src/positioning/useFixedPositioning.ts +6 -3
- package/src/progress/CircularProgress.tsx +2 -1
- package/src/progress/LinearProgress.tsx +2 -1
- package/src/progress/linearProgressStyles.ts +1 -2
- package/src/responsive-item/ResponsiveItem.tsx +1 -2
- package/src/responsive-item/ResponsiveItemOverlay.tsx +2 -1
- package/src/searching/caseInsensitive.ts +2 -4
- package/src/segmented-button/SegmentedButton.tsx +2 -1
- package/src/segmented-button/SegmentedButtonContainer.tsx +2 -1
- package/src/segmented-button/segmentedButtonStyles.ts +1 -2
- package/src/sheet/Sheet.tsx +1 -2
- package/src/snackbar/Toast.tsx +2 -1
- package/src/spinbutton/SpinButton.tsx +98 -0
- package/src/spinbutton/SpinButtonGroupProvider.tsx +32 -0
- package/src/spinbutton/defaults.ts +45 -0
- package/src/spinbutton/types.ts +413 -0
- package/src/spinbutton/useSpinButton.ts +311 -0
- package/src/spinbutton/useSpinButtonGroupProvider.ts +104 -0
- package/src/spinbutton/utils/deselectNode.ts +17 -0
- package/src/spinbutton/utils/resolveInputEvent.ts +112 -0
- package/src/spinbutton/utils/selectNode.ts +15 -0
- package/src/table/StickyTableSection.tsx +2 -1
- package/src/table/Table.tsx +1 -2
- package/src/table/TableBody.tsx +2 -1
- package/src/table/TableCellContent.tsx +1 -2
- package/src/table/TableCheckbox.tsx +1 -2
- package/src/table/TableFooter.tsx +1 -2
- package/src/table/TableHeader.tsx +1 -2
- package/src/table/TableRadio.tsx +1 -2
- package/src/table/TableRow.tsx +1 -2
- package/src/table/useStickyTableSection.tsx +1 -2
- package/src/tabs/SimpleTabPanel.tsx +2 -1
- package/src/tabs/SimpleTabPanels.tsx +2 -1
- package/src/tabs/Tab.tsx +3 -6
- package/src/tabs/TabList.tsx +2 -1
- package/src/tabs/TabListScrollButton.tsx +1 -2
- package/src/tabs/useMaxTabPanelHeight.ts +7 -4
- package/src/test-utils/data-testid.ts +1 -2
- package/src/test-utils/mocks/match-media.ts +5 -10
- package/src/test-utils/vitest/timers.ts +1 -1
- package/src/tooltip/Tooltip.tsx +2 -1
- package/src/tooltip/TooltipHoverModeProvider.tsx +1 -2
- package/src/tooltip/useTooltip.ts +9 -5
- package/src/transition/CSSTransition.tsx +2 -1
- package/src/transition/Collapse.tsx +4 -2
- package/src/transition/CrossFade.tsx +2 -1
- package/src/transition/ScaleTransition.tsx +2 -1
- package/src/transition/SkeletonPlaceholder.tsx +1 -2
- package/src/transition/Slide.tsx +2 -1
- package/src/transition/SlideContainer.tsx +1 -2
- package/src/transition/types.ts +15 -16
- package/src/transition/useCollapseTransition.ts +6 -5
- package/src/transition/useCrossFadeTransition.ts +3 -2
- package/src/transition/useMaxWidthTransition.ts +1 -2
- package/src/transition/useScaleTransition.ts +3 -2
- package/src/transition/useSkeletonPlaceholder.ts +1 -2
- package/src/tree/Tree.tsx +2 -1
- package/src/tree/TreeItem.tsx +2 -1
- package/src/tree/TreeProvider.tsx +4 -4
- package/src/tree/styles.ts +1 -2
- package/src/tree/types.ts +1 -2
- package/src/tree/useTreeMovement.ts +1 -2
- package/src/typography/HighlightTextMark.tsx +1 -2
- package/src/typography/Mark.tsx +1 -2
- package/src/typography/TextContainer.tsx +1 -2
- package/src/typography/Typography.tsx +1 -2
- package/src/useElementSize.ts +7 -4
- package/src/useIntersectionObserver.ts +3 -2
- package/src/useMutationObserver.ts +3 -2
- package/src/useWindowSize.ts +4 -2
- package/src/utils/getNumberOfDigits.ts +18 -0
- package/src/utils/nearest.ts +2 -1
- package/src/utils/useDevEffect.ts +9 -0
- package/src/window-splitter/WindowSplitter.tsx +5 -2
- package/src/window-splitter/styles.ts +13 -2
- package/src/window-splitter/useWindowSplitter.ts +3 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/menu/MenuItemSeparator.tsx"],"sourcesContent":["\"use client\";\n\nimport { type HTMLAttributes, forwardRef } from \"react\";\n\nimport { type DividerProps } from \"../divider/Divider.js\";\nimport { divider } from \"../divider/styles.js\";\nimport { useMenuConfiguration } from \"./MenuConfigurationProvider.js\";\n\n/** @since 5.0.0 */\nexport interface MenuItemSeparatorProps\n extends
|
|
1
|
+
{"version":3,"sources":["../../src/menu/MenuItemSeparator.tsx"],"sourcesContent":["\"use client\";\n\nimport { type HTMLAttributes, forwardRef } from \"react\";\n\nimport { type DividerProps } from \"../divider/Divider.js\";\nimport { divider } from \"../divider/styles.js\";\nimport { useMenuConfiguration } from \"./MenuConfigurationProvider.js\";\n\n/** @since 5.0.0 */\nexport interface MenuItemSeparatorProps\n extends\n HTMLAttributes<HTMLLIElement>,\n Pick<DividerProps, \"inset\" | \"vertical\"> {}\n\n/**\n * **Client Component**\n *\n * This component renders a `<li role=\"separator\">` with the divider styles. It\n * will also automatically render itself vertically instead of horizontally if\n * the menu is rendering horizontally.\n *\n * @see {@link https://react-md.dev/components/menu | Menu Demos}\n * @since 5.0.0 Renders as an `<li>` instead of a `<div>` or `<hr />`.\n */\nexport const MenuItemSeparator = forwardRef<\n HTMLLIElement,\n MenuItemSeparatorProps\n>(function MenuItemSeparator(props, ref) {\n const {\n className,\n inset,\n vertical: propVertical,\n children,\n ...remaining\n } = props;\n\n const horizontal = useMenuConfiguration().horizontal;\n const vertical = propVertical ?? horizontal;\n\n return (\n <li\n {...remaining}\n aria-orientation={vertical ? \"vertical\" : undefined}\n ref={ref}\n role=\"separator\"\n className={divider({ inset: inset && !vertical, vertical, className })}\n >\n {children}\n </li>\n );\n});\n"],"names":["forwardRef","divider","useMenuConfiguration","MenuItemSeparator","props","ref","className","inset","vertical","propVertical","children","remaining","horizontal","li","aria-orientation","undefined","role"],"mappings":"AAAA;;AAEA,SAA8BA,UAAU,QAAQ,QAAQ;AAGxD,SAASC,OAAO,QAAQ,uBAAuB;AAC/C,SAASC,oBAAoB,QAAQ,iCAAiC;AAQtE;;;;;;;;;CASC,GACD,OAAO,MAAMC,kCAAoBH,WAG/B,SAASG,kBAAkBC,KAAK,EAAEC,GAAG;IACrC,MAAM,EACJC,SAAS,EACTC,KAAK,EACLC,UAAUC,YAAY,EACtBC,QAAQ,EACR,GAAGC,WACJ,GAAGP;IAEJ,MAAMQ,aAAaV,uBAAuBU,UAAU;IACpD,MAAMJ,WAAWC,gBAAgBG;IAEjC,qBACE,KAACC;QACE,GAAGF,SAAS;QACbG,oBAAkBN,WAAW,aAAaO;QAC1CV,KAAKA;QACLW,MAAK;QACLV,WAAWL,QAAQ;YAAEM,OAAOA,SAAS,CAACC;YAAUA;YAAUF;QAAU;kBAEnEI;;AAGP,GAAG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/menu/MenuVisibilityProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ReactElement,\n type ReactNode,\n createContext,\n useContext,\n useMemo,\n} from \"react\";\n\nimport { type NonNullMutableRef, type UseStateObject } from \"../types.js\";\n\n/**\n * @since 5.0.0\n * @since 6.0.0 Added the `defaultFocusIndex` ref.\n */\nexport interface MenuVisibilityContext
|
|
1
|
+
{"version":3,"sources":["../../src/menu/MenuVisibilityProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ReactElement,\n type ReactNode,\n createContext,\n useContext,\n useMemo,\n} from \"react\";\n\nimport { type NonNullMutableRef, type UseStateObject } from \"../types.js\";\n\n/**\n * @since 5.0.0\n * @since 6.0.0 Added the `defaultFocusIndex` ref.\n */\nexport interface MenuVisibilityContext extends UseStateObject<\n \"visible\",\n boolean\n> {\n defaultFocusIndex: NonNullMutableRef<number>;\n}\n\n/**\n * @internal\n * @since 5.0.0\n */\nconst context = createContext<MenuVisibilityContext>({\n visible: false,\n setVisible() {\n throw new Error('\"MenuVisibilityProvider\" must be a parent component');\n },\n defaultFocusIndex: { current: 0 },\n});\ncontext.displayName = \"MenuVisibility\";\n\n/**\n * @internal\n * @since 5.0.0\n */\nconst { Provider } = context;\n\n/**\n * This hook allows you control the visibility of a parent menu. The main\n * use-case for this hook is adding a custom sheet header/footer.\n *\n * @example Simple Example\n * ```tsx\n * function SheetFooter(): ReactElement {\n * const { setVisible } = useMenuVisibility();\n *\n * return (\n * <DialogFooter>\n * <Button onClick={() => setVisible(false)}>Cancel</Button>\n * </DialogFooter>\n * );\n * }\n * ```\n *\n * @returns the {@link MenuVisibilityContext}\n * @since 5.0.0\n */\nexport function useMenuVisibility(): Readonly<MenuVisibilityContext> {\n return useContext(context);\n}\n\n/**\n * @internal\n * @since 5.0.0\n */\nexport interface MenuVisibilityProviderProps extends MenuVisibilityContext {\n children: ReactNode;\n}\n\n/**\n * **Client Component**\n *\n * @internal\n * @since 5.0.0\n */\nexport function MenuVisibilityProvider({\n visible,\n setVisible,\n defaultFocusIndex,\n children,\n}: MenuVisibilityProviderProps): ReactElement {\n const value = useMemo<MenuVisibilityContext>(\n () => ({\n visible,\n setVisible,\n defaultFocusIndex,\n }),\n [visible, setVisible, defaultFocusIndex]\n );\n\n return <Provider value={value}>{children}</Provider>;\n}\n"],"names":["createContext","useContext","useMemo","context","visible","setVisible","Error","defaultFocusIndex","current","displayName","Provider","useMenuVisibility","MenuVisibilityProvider","children","value"],"mappings":"AAAA;;AAEA,SAGEA,aAAa,EACbC,UAAU,EACVC,OAAO,QACF,QAAQ;AAef;;;CAGC,GACD,MAAMC,wBAAUH,cAAqC;IACnDI,SAAS;IACTC;QACE,MAAM,IAAIC,MAAM;IAClB;IACAC,mBAAmB;QAAEC,SAAS;IAAE;AAClC;AACAL,QAAQM,WAAW,GAAG;AAEtB;;;CAGC,GACD,MAAM,EAAEC,QAAQ,EAAE,GAAGP;AAErB;;;;;;;;;;;;;;;;;;;CAmBC,GACD,OAAO,SAASQ;IACd,OAAOV,WAAWE;AACpB;AAUA;;;;;CAKC,GACD,OAAO,SAASS,uBAAuB,EACrCR,OAAO,EACPC,UAAU,EACVE,iBAAiB,EACjBM,QAAQ,EACoB;IAC5B,MAAMC,QAAQZ,QACZ,IAAO,CAAA;YACLE;YACAC;YACAE;QACF,CAAA,GACA;QAACH;QAASC;QAAYE;KAAkB;IAG1C,qBAAO,KAACG;QAASI,OAAOA;kBAAQD;;AAClC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/menu/MenuWidget.tsx"],"sourcesContent":["\"use client\";\n\nimport { type HTMLAttributes, forwardRef, useRef, useState } from \"react\";\n\nimport { List } from \"../list/List.js\";\nimport { type GetDefaultFocusedIndex } from \"../movement/types.js\";\nimport { useKeyboardMovementProvider } from \"../movement/useKeyboardMovementProvider.js\";\nimport { type NonNullMutableRef } from \"../types.js\";\nimport { type MenuListConvenienceProps } from \"./Menu.js\";\nimport { MenuWidgetKeyboardProvider } from \"./MenuWidgetKeyboardProvider.js\";\nimport { menu } from \"./styles.js\";\nimport {\n MenuBarProvider,\n useMenuBarContext,\n useMenuBarProvider,\n} from \"./useMenuBarProvider.js\";\n\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * @internal\n */\nexport interface MenuWidgetProps\n extends HTMLAttributes<HTMLDivElement
|
|
1
|
+
{"version":3,"sources":["../../src/menu/MenuWidget.tsx"],"sourcesContent":["\"use client\";\n\nimport { type HTMLAttributes, forwardRef, useRef, useState } from \"react\";\n\nimport { List } from \"../list/List.js\";\nimport { type GetDefaultFocusedIndex } from \"../movement/types.js\";\nimport { useKeyboardMovementProvider } from \"../movement/useKeyboardMovementProvider.js\";\nimport { type NonNullMutableRef } from \"../types.js\";\nimport { type MenuListConvenienceProps } from \"./Menu.js\";\nimport { MenuWidgetKeyboardProvider } from \"./MenuWidgetKeyboardProvider.js\";\nimport { menu } from \"./styles.js\";\nimport {\n MenuBarProvider,\n useMenuBarContext,\n useMenuBarProvider,\n} from \"./useMenuBarProvider.js\";\n\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * @internal\n */\nexport interface MenuWidgetProps\n extends HTMLAttributes<HTMLDivElement>, MenuListConvenienceProps {\n isSheet: boolean;\n horizontal: boolean;\n disableElevation?: boolean;\n cancelUnmountFocus: NonNullMutableRef<boolean>;\n getDefaultFocusedIndex?: GetDefaultFocusedIndex;\n}\n\n/**\n * **Client Component**\n *\n * This component was added to support the listbox role and the `useId()` hook.\n * If the `temporary` prop is set, the `MenuItem`'s ids will not be the same the\n * next time the menu opens, so the aria-activedescendant will point to a\n * non-existing id\n *\n * @internal\n */\nexport const MenuWidget = forwardRef<HTMLDivElement, MenuWidgetProps>(\n function MenuWidget(props, ref) {\n const {\n id,\n role = \"menu\",\n className,\n listStyle,\n listClassName,\n listProps,\n children,\n onClick,\n onBlur = noop,\n onFocus = noop,\n onKeyDown = noop,\n tabIndex = -1,\n isSheet,\n horizontal,\n disableElevation,\n cancelUnmountFocus,\n getDefaultFocusedIndex,\n ...remaining\n } = props;\n const isListbox = role === \"listbox\";\n const { menubar } = useMenuBarContext();\n\n // Since there is the possibility of other tab focusable elements within the\n // sheet and the menu items are programmatically focused, the menu's\n // tabIndex needs to be set to `-1` while one of the child menu items are\n // focused. This allows Shift+Tab correctly focuses the previous focusable\n // element within the sheet. Since `onFocus` and `onBlur` will be bubbled up\n // to the menu widget each time a new MenuItem is focused, only disable the\n // focused state if the blur event is fired without another focus event\n // within an animation frame.\n const [sheetMenuFocused, setSheetMenuFocused] = useState(false);\n const sheetBlurredFame = useRef(0);\n const menuBarContext = useMenuBarProvider({\n root: false,\n menubar,\n hoverTimeout: menubar ? 0 : undefined,\n defaultActiveId: id,\n });\n const { movementProps, movementContext } = useKeyboardMovementProvider({\n ref,\n onClick,\n onFocus(event) {\n onFocus(event);\n\n if (!isSheet) {\n return;\n }\n\n window.cancelAnimationFrame(sheetBlurredFame.current);\n setSheetMenuFocused(true);\n },\n onKeyDown,\n horizontal,\n loopable: true,\n searchable: true,\n programmatic: true,\n includeDisabled: true,\n getDefaultFocusedIndex,\n });\n\n return (\n <MenuWidgetKeyboardProvider disabled={isListbox} value={movementContext}>\n <MenuBarProvider value={menuBarContext}>\n <div\n aria-orientation={horizontal ? \"horizontal\" : undefined}\n {...remaining}\n {...(isListbox\n ? { onClick, onFocus, onKeyDown, ref }\n : movementProps)}\n id={id}\n role={role}\n className={menu({\n className,\n elevated: !disableElevation && !isSheet,\n horizontal,\n })}\n tabIndex={isSheet && !sheetMenuFocused ? 0 : tabIndex}\n onBlur={(event) => {\n onBlur(event);\n if (!isSheet) {\n return;\n }\n\n sheetBlurredFame.current = window.requestAnimationFrame(() => {\n setSheetMenuFocused(false);\n });\n }}\n >\n <List\n {...listProps}\n style={listStyle ?? listProps?.style}\n className={listClassName || listProps?.className}\n horizontal={horizontal}\n onClick={(event) => {\n listProps?.onClick?.(event);\n\n // this makes it so you can click on the menu/list without\n // closing the menu\n if (event.target === event.currentTarget) {\n event.stopPropagation();\n }\n\n // This might be a test only workaround since clicking links move focus\n // somewhere else\n if (event.target instanceof HTMLElement) {\n cancelUnmountFocus.current = event.currentTarget.contains(\n event.target.closest(\"a\")\n );\n }\n }}\n >\n {children}\n </List>\n </div>\n </MenuBarProvider>\n </MenuWidgetKeyboardProvider>\n );\n }\n);\n"],"names":["forwardRef","useRef","useState","List","useKeyboardMovementProvider","MenuWidgetKeyboardProvider","menu","MenuBarProvider","useMenuBarContext","useMenuBarProvider","noop","MenuWidget","props","ref","id","role","className","listStyle","listClassName","listProps","children","onClick","onBlur","onFocus","onKeyDown","tabIndex","isSheet","horizontal","disableElevation","cancelUnmountFocus","getDefaultFocusedIndex","remaining","isListbox","menubar","sheetMenuFocused","setSheetMenuFocused","sheetBlurredFame","menuBarContext","root","hoverTimeout","undefined","defaultActiveId","movementProps","movementContext","event","window","cancelAnimationFrame","current","loopable","searchable","programmatic","includeDisabled","disabled","value","div","aria-orientation","elevated","requestAnimationFrame","style","target","currentTarget","stopPropagation","HTMLElement","contains","closest"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/menu/useContextMenu.ts"],"sourcesContent":["\"use client\";\n\nimport type { MouseEvent, RefObject } from \"react\";\nimport { useCallback, useRef, useState } from \"react\";\n\nimport { BELOW_INNER_LEFT_ANCHOR } from \"../positioning/constants.js\";\nimport type { InitialCoords, PositionAnchor } from \"../positioning/types.js\";\nimport type { UseStateObject } from \"../types.js\";\n\n/** @since 6.0.0 */\nexport interface ContextMenuProps extends InitialCoords {\n \"aria-label\": string;\n anchor: PositionAnchor;\n fixedTo: RefObject<HTMLElement>;\n visible: boolean;\n preventScroll: boolean;\n onRequestClose: () => void;\n}\n\n/**\n * @since 5.0.0\n * @since 6.0.0 Dropped most options since they are no longer required for the\n * context menu to work. Apply any `Menu` props directly to the `Menu` component\n * instead.\n */\nexport interface ContextMenuHookOptions {\n /**\n * @defaultValue `BELOW_INNER_LEFT_ANCHOR`\n * @see {@link BELOW_INNER_LEFT_ANCHOR}\n */\n anchor?: PositionAnchor;\n\n /**\n * @defaultValue `\"Context Menu\"`\n */\n menuLabel?: string;\n\n /**\n * @defaultValue `true`\n */\n preventScroll?: boolean;\n onContextMenu?: <E extends HTMLElement>(event: MouseEvent<E>) => void;\n}\n\n/**\n * @since 5.0.0\n * @since 6.0.0 Renamed from `ContextMenuHookReturnValue` to\n * `ContextMenuImplementation` and dropped the `menuRef` and `menuNodeRef`\n * fields.\n */\nexport interface ContextMenuImplementation
|
|
1
|
+
{"version":3,"sources":["../../src/menu/useContextMenu.ts"],"sourcesContent":["\"use client\";\n\nimport type { MouseEvent, RefObject } from \"react\";\nimport { useCallback, useRef, useState } from \"react\";\n\nimport { BELOW_INNER_LEFT_ANCHOR } from \"../positioning/constants.js\";\nimport type { InitialCoords, PositionAnchor } from \"../positioning/types.js\";\nimport type { UseStateObject } from \"../types.js\";\n\n/** @since 6.0.0 */\nexport interface ContextMenuProps extends InitialCoords {\n \"aria-label\": string;\n anchor: PositionAnchor;\n fixedTo: RefObject<HTMLElement>;\n visible: boolean;\n preventScroll: boolean;\n onRequestClose: () => void;\n}\n\n/**\n * @since 5.0.0\n * @since 6.0.0 Dropped most options since they are no longer required for the\n * context menu to work. Apply any `Menu` props directly to the `Menu` component\n * instead.\n */\nexport interface ContextMenuHookOptions {\n /**\n * @defaultValue `BELOW_INNER_LEFT_ANCHOR`\n * @see {@link BELOW_INNER_LEFT_ANCHOR}\n */\n anchor?: PositionAnchor;\n\n /**\n * @defaultValue `\"Context Menu\"`\n */\n menuLabel?: string;\n\n /**\n * @defaultValue `true`\n */\n preventScroll?: boolean;\n onContextMenu?: <E extends HTMLElement>(event: MouseEvent<E>) => void;\n}\n\n/**\n * @since 5.0.0\n * @since 6.0.0 Renamed from `ContextMenuHookReturnValue` to\n * `ContextMenuImplementation` and dropped the `menuRef` and `menuNodeRef`\n * fields.\n */\nexport interface ContextMenuImplementation extends UseStateObject<\n \"visible\",\n boolean\n> {\n menuProps: ContextMenuProps;\n onContextMenu: <E extends HTMLElement>(event: MouseEvent<E>) => void;\n}\n\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * This hook controls the visibility and positioning for a context menu.\n *\n * @example Simple Example\n * ```tsx\n * import type { ReactElement } from \"react\";\n * import { Menu } from \"@react-md/core/menu/Menu\":\n * import { MenuItem } from \"@react-md/core/menu/MenuItem\":\n * import { useContextMenu } from \"@react-md/core/menu/useContextMenu\":\n *\n * function Example(): ReactElement {\n * const { menuProps, onContextMenu } = useContextMenu();\n *\n * return (\n * <>\n * <textarea onContextMenu={onContextMenu} />\n * <Menu {...menuProps}>\n * <MenuItem>Cut</MenuItem>\n * <MenuItem>Copy</MenuItem>\n * <MenuItem>Paste</MenuItem>\n * <MenuItem>Undo</MenuItem>\n * </Menu>\n * </>\n * );\n * }\n * ```\n *\n * @see {@link https://react-md.dev/components/menu#context-menu | Menu Demos}\n * @since 5.0.0\n * @since 6.0.0 No longer supports overriding most of the `Menu` props. The\n * props must be passed to the `Menu` component manually.\n */\nexport function useContextMenu(\n options: ContextMenuHookOptions = {}\n): ContextMenuImplementation {\n const {\n anchor = BELOW_INNER_LEFT_ANCHOR,\n menuLabel = \"Context Menu\",\n onContextMenu = noop,\n preventScroll = true,\n } = options;\n const [coords, setCoords] = useState<InitialCoords>({});\n const [visible, setVisible] = useState(false);\n const fixedTo = useRef<HTMLElement>(null);\n const onRequestClose = useCallback(() => {\n setVisible(false);\n }, []);\n\n return {\n visible,\n setVisible,\n menuProps: {\n \"aria-label\": menuLabel,\n anchor,\n ...coords,\n fixedTo,\n visible,\n onRequestClose,\n preventScroll,\n },\n onContextMenu(event) {\n onContextMenu(event);\n if (event.isPropagationStopped()) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n setCoords({\n initialX: event.clientX,\n initialY: event.clientY,\n });\n setVisible(true);\n },\n };\n}\n"],"names":["useCallback","useRef","useState","BELOW_INNER_LEFT_ANCHOR","noop","useContextMenu","options","anchor","menuLabel","onContextMenu","preventScroll","coords","setCoords","visible","setVisible","fixedTo","onRequestClose","menuProps","event","isPropagationStopped","preventDefault","stopPropagation","initialX","clientX","initialY","clientY"],"mappings":"AAAA;AAGA,SAASA,WAAW,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAQ;AAEtD,SAASC,uBAAuB,QAAQ,8BAA8B;AAqDtE,MAAMC,OAAO;AACX,aAAa;AACf;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BC,GACD,OAAO,SAASC,eACdC,UAAkC,CAAC,CAAC;IAEpC,MAAM,EACJC,SAASJ,uBAAuB,EAChCK,YAAY,cAAc,EAC1BC,gBAAgBL,IAAI,EACpBM,gBAAgB,IAAI,EACrB,GAAGJ;IACJ,MAAM,CAACK,QAAQC,UAAU,GAAGV,SAAwB,CAAC;IACrD,MAAM,CAACW,SAASC,WAAW,GAAGZ,SAAS;IACvC,MAAMa,UAAUd,OAAoB;IACpC,MAAMe,iBAAiBhB,YAAY;QACjCc,WAAW;IACb,GAAG,EAAE;IAEL,OAAO;QACLD;QACAC;QACAG,WAAW;YACT,cAAcT;YACdD;YACA,GAAGI,MAAM;YACTI;YACAF;YACAG;YACAN;QACF;QACAD,eAAcS,KAAK;YACjBT,cAAcS;YACd,IAAIA,MAAMC,oBAAoB,IAAI;gBAChC;YACF;YAEAD,MAAME,cAAc;YACpBF,MAAMG,eAAe;YACrBT,UAAU;gBACRU,UAAUJ,MAAMK,OAAO;gBACvBC,UAAUN,MAAMO,OAAO;YACzB;YACAX,WAAW;QACb;IACF;AACF"}
|
package/dist/movement/types.d.ts
CHANGED
|
@@ -111,9 +111,15 @@ export interface KeyboardMovementBehavior {
|
|
|
111
111
|
}
|
|
112
112
|
/**
|
|
113
113
|
* @since 6.3.0
|
|
114
|
+
* @since 6.4.0 Added `force` option.
|
|
114
115
|
*/
|
|
115
116
|
export interface KeyboardFocusFromKeyOptions {
|
|
116
117
|
key: string;
|
|
118
|
+
/**
|
|
119
|
+
* @since 6.4.0
|
|
120
|
+
* @defaultValue `false`
|
|
121
|
+
*/
|
|
122
|
+
force?: boolean;
|
|
117
123
|
/** @defaultValue `false` */
|
|
118
124
|
reversed?: boolean;
|
|
119
125
|
/** @defaultValue `getFocusableElementsFromRef()` */
|
|
@@ -122,10 +128,21 @@ export interface KeyboardFocusFromKeyOptions {
|
|
|
122
128
|
/**
|
|
123
129
|
* @since 6.3.0
|
|
124
130
|
*/
|
|
125
|
-
export type KeyboardFocusAction = (focusables?: readonly HTMLElement[]) => void;
|
|
131
|
+
export type KeyboardFocusAction = (focusables?: readonly HTMLElement[], force?: boolean) => void;
|
|
132
|
+
/**
|
|
133
|
+
* @since 6.4.0
|
|
134
|
+
*/
|
|
135
|
+
export interface KeyboardMovementUpdateFocusIndexOptions {
|
|
136
|
+
index: number;
|
|
137
|
+
force?: boolean;
|
|
138
|
+
focusables?: readonly HTMLElement[];
|
|
139
|
+
}
|
|
126
140
|
/**
|
|
127
141
|
* @since 5.0.0
|
|
128
142
|
* @since 6.0.0 Removed `attach`, `detach` and `watching`
|
|
143
|
+
* @since 6.3.0 Added `focusFirst`, `focusLast`, `focusNext`, `focusPrevious`
|
|
144
|
+
* and `focusFromKey`.
|
|
145
|
+
* @since 6.4.0 Added `focusCurrent` and `updateFocusIndex`
|
|
129
146
|
* @internal
|
|
130
147
|
*/
|
|
131
148
|
export interface KeyboardMovementContext extends Required<KeyboardMovementBehavior> {
|
|
@@ -158,6 +175,14 @@ export interface KeyboardMovementContext extends Required<KeyboardMovementBehavi
|
|
|
158
175
|
* @since 6.3.0
|
|
159
176
|
*/
|
|
160
177
|
focusFromKey: (options: KeyboardFocusFromKeyOptions) => void;
|
|
178
|
+
/**
|
|
179
|
+
* @since 6.4.0
|
|
180
|
+
*/
|
|
181
|
+
focusCurrent: (focusables?: readonly HTMLElement[], force?: boolean) => HTMLElement | undefined;
|
|
182
|
+
/**
|
|
183
|
+
* @since 6.4.0
|
|
184
|
+
*/
|
|
185
|
+
updateFocusIndex: (options: KeyboardMovementUpdateFocusIndexOptions) => void;
|
|
161
186
|
}
|
|
162
187
|
/**
|
|
163
188
|
* @since 6.0.0
|
|
@@ -209,6 +234,8 @@ export type KeyboardMovementEventHandlers<E extends HTMLElement> = Pick<HTMLAttr
|
|
|
209
234
|
*/
|
|
210
235
|
export interface SimpleKeyboardMovementWrapperOptions<E extends HTMLElement> extends KeyboardMovementEventHandlers<E> {
|
|
211
236
|
ref?: Ref<E>;
|
|
237
|
+
/** @defaultValue `false` */
|
|
238
|
+
disabled?: boolean;
|
|
212
239
|
}
|
|
213
240
|
/**
|
|
214
241
|
* @since 6.0.0
|
|
@@ -217,8 +244,6 @@ export interface SimpleKeyboardMovementWrapperOptions<E extends HTMLElement> ext
|
|
|
217
244
|
export interface KeyboardMovementProviderOptions<E extends HTMLElement> extends KeyboardMovementBehavior, SimpleKeyboardMovementWrapperOptions<E>, KeyboardMovementConfiguration {
|
|
218
245
|
/** @see {@link TabIndexBehavior} */
|
|
219
246
|
tabIndexBehavior?: TabIndexBehavior;
|
|
220
|
-
/** @defaultValue `false` */
|
|
221
|
-
disabled?: boolean;
|
|
222
247
|
/**
|
|
223
248
|
* This is used to implement custom keyboard movement for the `keydown` event.
|
|
224
249
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/movement/types.ts"],"sourcesContent":["import {\n type HTMLAttributes,\n type KeyboardEvent,\n type Ref,\n type RefCallback,\n type RefObject,\n} from \"react\";\n\nimport {\n type NonNullMutableRef,\n type NonNullRef,\n type UseStateSetter,\n} from \"../types.js\";\n\n/**\n * Set this to `\"roving\"` when:\n * - there are a group of focusable elements that have a `tabIndex={-1}`\n * - the container element defaults to having a `tabIndex={0}`\n * - if the container is focused, it should no longer be included in the normal\n * tab flow. Instead, the current focused element should be included instead\n * by changing its `tabIndex` from `-1` to `0`\n *\n * Set this to `\"virtual\"` when:\n * - the container element should never lose focus\n * - the \"focused\" element only gains focus styles instead of being focused\n * - the container element specifies an `aria-activedescendant` pointing to one\n * of the ids for the child \"focusable\" elements\n *\n * @since 6.0.0\n */\nexport type TabIndexBehavior = \"roving\" | \"virtual\";\n\n/**\n * This should be used for specific widgets that should not include all\n * focusable elements and instead only specific elements.\n *\n * @example\n * ```ts\n * const getExpansionPanelsOnly: GetFocusableElements = (container) =>\n * [...container.querySelectorAll(\".rmd-expansion-panel__button\")];\n *\n * const getTreeItemsOnly: GetFocusableElements = (container) =>\n * [...container.querySelectorAll(\"[role='treeitem']\")];\n * ```\n *\n * @defaultValue `getFocusableElements`\n * @see the default `getFocusableElements` function.\n */\nexport type GetFocusableElements = (\n container: HTMLElement,\n programmatic: boolean\n) => readonly HTMLElement[];\n\n/**\n * @since 5.0.0\n */\nexport interface KeyboardMovementConfiguration {\n /**\n * A list of keys that will attempt to increment the focus index by 1.\n *\n * @defaultValue `[\"ArrowDown\"]`\n */\n incrementKeys?: readonly string[];\n\n /**\n * A list of keys that will attempt to decrement the focus index by 1.\n *\n * @defaultValue `[\"ArrowUp\"]`\n */\n decrementKeys?: readonly string[];\n\n /**\n * A list of keys that will set the focus index to `0`.\n *\n * @defaultValue `[\"Home\"]`\n */\n jumpToFirstKeys?: readonly string[];\n\n /**\n * A list of keys that will set the focus index to the last focusable index.\n *\n * @defaultValue `[\"End\"]`\n */\n jumpToLastKeys?: readonly string[];\n}\n\n/**\n * The defined {@link KeyboardMovementConfiguration} that should be used for\n * custom keyboard focus behavior.\n *\n * @since 5.0.0\n */\nexport type KeyboardMovementConfig = Required<KeyboardMovementConfiguration>;\n\n/**\n * @since 5.0.0\n */\nexport interface KeyboardMovementBehavior {\n /**\n * Boolean if pressing a letter will focus the next item in the\n * {@link KeyboardMovementProvider} that starts with the same letter.\n *\n * @defaultValue `false`\n */\n searchable?: boolean;\n\n /**\n * Boolean if the {@link KeyboardMovementProvider} should allow the focus behavior\n * to loop from the first to last or last to first item instead of preventing\n * any new focus behavior. In other words... if the last item is focused and\n * the user presses a key that should advance the focus to the next focusable\n * element, should the focus stay on the current element or loop back and\n * focus the first focusable item.\n *\n * @defaultValue `false`\n */\n loopable?: boolean;\n\n /**\n * Boolean if elements that are `aria-disabled` or `disabled` should still be\n * able to gain focus.\n *\n * @defaultValue `false`\n */\n includeDisabled?: boolean;\n\n /**\n * Boolean if the keyboard movement is horizontal instead of vertical. This\n * updates the default keyboard config to use `ArrowRight` and `ArrowLeft`\n * instead of `ArrowDown` and `ArrowUp`,\n *\n * @since 5.1.2\n * @defaultValue `false`\n */\n horizontal?: boolean;\n}\n\n/**\n * @since 6.3.0\n */\nexport interface KeyboardFocusFromKeyOptions {\n key: string;\n /** @defaultValue `false` */\n reversed?: boolean;\n\n /** @defaultValue `getFocusableElementsFromRef()` */\n focusables?: readonly HTMLElement[];\n}\n\n/**\n * @since 6.3.0\n */\nexport type KeyboardFocusAction = (focusables?: readonly HTMLElement[]) => void;\n\n/**\n * @since 5.0.0\n * @since 6.0.0 Removed `attach`, `detach` and `watching`\n * @internal\n */\nexport interface KeyboardMovementContext\n extends Required<KeyboardMovementBehavior> {\n /** {@inheritDoc KeyboardMovementConfig} */\n config: NonNullRef<KeyboardMovementConfig>;\n\n /** @see {@link TabIndexBehavior} */\n tabIndexBehavior: TabIndexBehavior | undefined;\n\n /**\n * Note: This will only update if the {@link KeyboardMovementProviderOptions.tabIndexBehavior}\n * has been set to `\"roving\"` or `\"virtual\"`.\n */\n activeDescendantId: string;\n\n /**\n * @since 6.3.0\n */\n focusFirst: KeyboardFocusAction;\n\n /**\n * @since 6.3.0\n */\n focusLast: KeyboardFocusAction;\n\n /**\n * @since 6.3.0\n */\n focusNext: KeyboardFocusAction;\n\n /**\n * @since 6.3.0\n */\n focusPrevious: KeyboardFocusAction;\n\n /**\n * @since 6.3.0\n */\n focusFromKey: (options: KeyboardFocusFromKeyOptions) => void;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface FocusableIndexOptions {\n focusables: readonly HTMLElement[];\n includeDisabled: boolean;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport type GetDefaultFocusedIndex = (options: FocusableIndexOptions) => number;\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport type ExtendKeyDown<E extends HTMLElement> = (\n movementData: KeyboardMovementExtensionData<E>\n) => void;\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface KeyboardMovementFocusChangeEvent {\n index: number;\n element: HTMLElement;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport type KeyboardMovementFocusChangeEventHandler = (\n event: KeyboardMovementFocusChangeEvent\n) => void;\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface KeyboardMovementExtensionData<E extends HTMLElement>\n extends KeyboardMovementContext {\n event: KeyboardEvent<E>;\n currentFocusIndex: NonNullMutableRef<number>;\n setFocusIndex: (index: number, focusables: readonly HTMLElement[]) => void;\n setActiveDescendantId: (id: string) => void;\n}\n\n/**\n * @since 6.3.0\n */\nexport type KeyboardMovementEventHandlers<E extends HTMLElement> = Pick<\n HTMLAttributes<E>,\n \"onClick\" | \"onFocus\" | \"onKeyDown\"\n>;\n\n/**\n * @since 6.3.0\n */\nexport interface SimpleKeyboardMovementWrapperOptions<E extends HTMLElement>\n extends KeyboardMovementEventHandlers<E> {\n ref?: Ref<E>;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface KeyboardMovementProviderOptions<E extends HTMLElement>\n extends KeyboardMovementBehavior,\n SimpleKeyboardMovementWrapperOptions<E>,\n KeyboardMovementConfiguration {\n /** @see {@link TabIndexBehavior} */\n tabIndexBehavior?: TabIndexBehavior;\n\n /** @defaultValue `false` */\n disabled?: boolean;\n\n /**\n * This is used to implement custom keyboard movement for the `keydown` event.\n */\n extendKeyDown?: ExtendKeyDown<E>;\n\n /**\n * Triggered whenever the focus changes.\n */\n onFocusChange?: KeyboardMovementFocusChangeEventHandler;\n\n /**\n * From what I've understood so far, programmatically focusable elements\n * should only be included when disabled elements via `aria-disabled` are\n * allowed.\n *\n * @defaultValue `includeDisabled`\n */\n programmatic?: boolean;\n\n /** @see {@link GetFocusableElements} */\n getFocusableElements?: GetFocusableElements;\n\n /**\n * This can be used to set the initial focus index whenever the container\n * element is first focused or the focus index is `-1` on other focus events.\n */\n getDefaultFocusedIndex?: GetDefaultFocusedIndex;\n\n /**\n * This was added to support editable combobox behavior. As the user types or\n * uses native input keyboard behavior, the focus index should be reset to\n * `-1` so that the next \"ArrowDown\" event focuses the first option again\n * instead of the last selected one.\n *\n * @defaultValue `false`\n */\n isNegativeOneAllowed?: boolean;\n\n /**\n * This was added to support spinbutton groups so the user can either use the\n * ArrowLeft, ArrowRight, or Tab keys to move. Without this, switching\n * between tab and the arrow keys would have the wrong tab index.\n *\n * @since 6.3.0\n * @defaultValue `false`\n */\n trackTabKeys?: boolean;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface KeyboardMovementProps<E extends HTMLElement>\n extends Required<KeyboardMovementEventHandlers<E>> {\n /**\n * This will only be provided if the {@link KeyboardMovementContext.tabIndexBehavior}\n * is set to `\"virtual\"`.\n */\n \"aria-activedescendant\"?: string;\n\n /**\n * This will not be provided if the {@link KeyboardMovementContext.tabIndexBehavior}\n * is `undefined`. Otherwise:\n * - `0` when `\"virtual\"`\n * - `0` when `\"roving\"` and the container element has not been focused at\n * least once\n * - `-1` when `\"roving\"` and the container has been focused at least once\n * - a child element **should** have a `tabIndex={0}` instead\n */\n tabIndex?: number;\n\n ref: RefCallback<E>;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface KeyboardMovementProviderImplementation<E extends HTMLElement> {\n nodeRef: RefObject<E>;\n movementProps: Readonly<KeyboardMovementProps<E>>;\n movementContext: Readonly<KeyboardMovementContext>;\n currentFocusIndex: NonNullMutableRef<number>;\n activeDescendantId: string;\n setActiveDescendantId: UseStateSetter<string>;\n}\n"],"names":[],"mappings":"AAoWA;;;CAGC,GACD,WAOC"}
|
|
1
|
+
{"version":3,"sources":["../../src/movement/types.ts"],"sourcesContent":["import {\n type HTMLAttributes,\n type KeyboardEvent,\n type Ref,\n type RefCallback,\n type RefObject,\n} from \"react\";\n\nimport {\n type NonNullMutableRef,\n type NonNullRef,\n type UseStateSetter,\n} from \"../types.js\";\n\n/**\n * Set this to `\"roving\"` when:\n * - there are a group of focusable elements that have a `tabIndex={-1}`\n * - the container element defaults to having a `tabIndex={0}`\n * - if the container is focused, it should no longer be included in the normal\n * tab flow. Instead, the current focused element should be included instead\n * by changing its `tabIndex` from `-1` to `0`\n *\n * Set this to `\"virtual\"` when:\n * - the container element should never lose focus\n * - the \"focused\" element only gains focus styles instead of being focused\n * - the container element specifies an `aria-activedescendant` pointing to one\n * of the ids for the child \"focusable\" elements\n *\n * @since 6.0.0\n */\nexport type TabIndexBehavior = \"roving\" | \"virtual\";\n\n/**\n * This should be used for specific widgets that should not include all\n * focusable elements and instead only specific elements.\n *\n * @example\n * ```ts\n * const getExpansionPanelsOnly: GetFocusableElements = (container) =>\n * [...container.querySelectorAll(\".rmd-expansion-panel__button\")];\n *\n * const getTreeItemsOnly: GetFocusableElements = (container) =>\n * [...container.querySelectorAll(\"[role='treeitem']\")];\n * ```\n *\n * @defaultValue `getFocusableElements`\n * @see the default `getFocusableElements` function.\n */\nexport type GetFocusableElements = (\n container: HTMLElement,\n programmatic: boolean\n) => readonly HTMLElement[];\n\n/**\n * @since 5.0.0\n */\nexport interface KeyboardMovementConfiguration {\n /**\n * A list of keys that will attempt to increment the focus index by 1.\n *\n * @defaultValue `[\"ArrowDown\"]`\n */\n incrementKeys?: readonly string[];\n\n /**\n * A list of keys that will attempt to decrement the focus index by 1.\n *\n * @defaultValue `[\"ArrowUp\"]`\n */\n decrementKeys?: readonly string[];\n\n /**\n * A list of keys that will set the focus index to `0`.\n *\n * @defaultValue `[\"Home\"]`\n */\n jumpToFirstKeys?: readonly string[];\n\n /**\n * A list of keys that will set the focus index to the last focusable index.\n *\n * @defaultValue `[\"End\"]`\n */\n jumpToLastKeys?: readonly string[];\n}\n\n/**\n * The defined {@link KeyboardMovementConfiguration} that should be used for\n * custom keyboard focus behavior.\n *\n * @since 5.0.0\n */\nexport type KeyboardMovementConfig = Required<KeyboardMovementConfiguration>;\n\n/**\n * @since 5.0.0\n */\nexport interface KeyboardMovementBehavior {\n /**\n * Boolean if pressing a letter will focus the next item in the\n * {@link KeyboardMovementProvider} that starts with the same letter.\n *\n * @defaultValue `false`\n */\n searchable?: boolean;\n\n /**\n * Boolean if the {@link KeyboardMovementProvider} should allow the focus behavior\n * to loop from the first to last or last to first item instead of preventing\n * any new focus behavior. In other words... if the last item is focused and\n * the user presses a key that should advance the focus to the next focusable\n * element, should the focus stay on the current element or loop back and\n * focus the first focusable item.\n *\n * @defaultValue `false`\n */\n loopable?: boolean;\n\n /**\n * Boolean if elements that are `aria-disabled` or `disabled` should still be\n * able to gain focus.\n *\n * @defaultValue `false`\n */\n includeDisabled?: boolean;\n\n /**\n * Boolean if the keyboard movement is horizontal instead of vertical. This\n * updates the default keyboard config to use `ArrowRight` and `ArrowLeft`\n * instead of `ArrowDown` and `ArrowUp`,\n *\n * @since 5.1.2\n * @defaultValue `false`\n */\n horizontal?: boolean;\n}\n\n/**\n * @since 6.3.0\n * @since 6.4.0 Added `force` option.\n */\nexport interface KeyboardFocusFromKeyOptions {\n key: string;\n\n /**\n * @since 6.4.0\n * @defaultValue `false`\n */\n force?: boolean;\n\n /** @defaultValue `false` */\n reversed?: boolean;\n\n /** @defaultValue `getFocusableElementsFromRef()` */\n focusables?: readonly HTMLElement[];\n}\n\n/**\n * @since 6.3.0\n */\nexport type KeyboardFocusAction = (\n focusables?: readonly HTMLElement[],\n force?: boolean\n) => void;\n\n/**\n * @since 6.4.0\n */\nexport interface KeyboardMovementUpdateFocusIndexOptions {\n index: number;\n force?: boolean;\n focusables?: readonly HTMLElement[];\n}\n\n/**\n * @since 5.0.0\n * @since 6.0.0 Removed `attach`, `detach` and `watching`\n * @since 6.3.0 Added `focusFirst`, `focusLast`, `focusNext`, `focusPrevious`\n * and `focusFromKey`.\n * @since 6.4.0 Added `focusCurrent` and `updateFocusIndex`\n * @internal\n */\nexport interface KeyboardMovementContext extends Required<KeyboardMovementBehavior> {\n /** {@inheritDoc KeyboardMovementConfig} */\n config: NonNullRef<KeyboardMovementConfig>;\n\n /** @see {@link TabIndexBehavior} */\n tabIndexBehavior: TabIndexBehavior | undefined;\n\n /**\n * Note: This will only update if the {@link KeyboardMovementProviderOptions.tabIndexBehavior}\n * has been set to `\"roving\"` or `\"virtual\"`.\n */\n activeDescendantId: string;\n\n /**\n * @since 6.3.0\n */\n focusFirst: KeyboardFocusAction;\n\n /**\n * @since 6.3.0\n */\n focusLast: KeyboardFocusAction;\n\n /**\n * @since 6.3.0\n */\n focusNext: KeyboardFocusAction;\n\n /**\n * @since 6.3.0\n */\n focusPrevious: KeyboardFocusAction;\n\n /**\n * @since 6.3.0\n */\n focusFromKey: (options: KeyboardFocusFromKeyOptions) => void;\n\n /**\n * @since 6.4.0\n */\n focusCurrent: (\n focusables?: readonly HTMLElement[],\n force?: boolean\n ) => HTMLElement | undefined;\n\n /**\n * @since 6.4.0\n */\n updateFocusIndex: (options: KeyboardMovementUpdateFocusIndexOptions) => void;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface FocusableIndexOptions {\n focusables: readonly HTMLElement[];\n includeDisabled: boolean;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport type GetDefaultFocusedIndex = (options: FocusableIndexOptions) => number;\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport type ExtendKeyDown<E extends HTMLElement> = (\n movementData: KeyboardMovementExtensionData<E>\n) => void;\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface KeyboardMovementFocusChangeEvent {\n index: number;\n element: HTMLElement;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport type KeyboardMovementFocusChangeEventHandler = (\n event: KeyboardMovementFocusChangeEvent\n) => void;\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface KeyboardMovementExtensionData<\n E extends HTMLElement,\n> extends KeyboardMovementContext {\n event: KeyboardEvent<E>;\n currentFocusIndex: NonNullMutableRef<number>;\n setFocusIndex: (index: number, focusables: readonly HTMLElement[]) => void;\n setActiveDescendantId: (id: string) => void;\n}\n\n/**\n * @since 6.3.0\n */\nexport type KeyboardMovementEventHandlers<E extends HTMLElement> = Pick<\n HTMLAttributes<E>,\n \"onClick\" | \"onFocus\" | \"onKeyDown\"\n>;\n\n/**\n * @since 6.3.0\n */\nexport interface SimpleKeyboardMovementWrapperOptions<\n E extends HTMLElement,\n> extends KeyboardMovementEventHandlers<E> {\n ref?: Ref<E>;\n\n /** @defaultValue `false` */\n disabled?: boolean;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface KeyboardMovementProviderOptions<E extends HTMLElement>\n extends\n KeyboardMovementBehavior,\n SimpleKeyboardMovementWrapperOptions<E>,\n KeyboardMovementConfiguration {\n /** @see {@link TabIndexBehavior} */\n tabIndexBehavior?: TabIndexBehavior;\n\n /**\n * This is used to implement custom keyboard movement for the `keydown` event.\n */\n extendKeyDown?: ExtendKeyDown<E>;\n\n /**\n * Triggered whenever the focus changes.\n */\n onFocusChange?: KeyboardMovementFocusChangeEventHandler;\n\n /**\n * From what I've understood so far, programmatically focusable elements\n * should only be included when disabled elements via `aria-disabled` are\n * allowed.\n *\n * @defaultValue `includeDisabled`\n */\n programmatic?: boolean;\n\n /** @see {@link GetFocusableElements} */\n getFocusableElements?: GetFocusableElements;\n\n /**\n * This can be used to set the initial focus index whenever the container\n * element is first focused or the focus index is `-1` on other focus events.\n */\n getDefaultFocusedIndex?: GetDefaultFocusedIndex;\n\n /**\n * This was added to support editable combobox behavior. As the user types or\n * uses native input keyboard behavior, the focus index should be reset to\n * `-1` so that the next \"ArrowDown\" event focuses the first option again\n * instead of the last selected one.\n *\n * @defaultValue `false`\n */\n isNegativeOneAllowed?: boolean;\n\n /**\n * This was added to support spinbutton groups so the user can either use the\n * ArrowLeft, ArrowRight, or Tab keys to move. Without this, switching\n * between tab and the arrow keys would have the wrong tab index.\n *\n * @since 6.3.0\n * @defaultValue `false`\n */\n trackTabKeys?: boolean;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface KeyboardMovementProps<E extends HTMLElement> extends Required<\n KeyboardMovementEventHandlers<E>\n> {\n /**\n * This will only be provided if the {@link KeyboardMovementContext.tabIndexBehavior}\n * is set to `\"virtual\"`.\n */\n \"aria-activedescendant\"?: string;\n\n /**\n * This will not be provided if the {@link KeyboardMovementContext.tabIndexBehavior}\n * is `undefined`. Otherwise:\n * - `0` when `\"virtual\"`\n * - `0` when `\"roving\"` and the container element has not been focused at\n * least once\n * - `-1` when `\"roving\"` and the container has been focused at least once\n * - a child element **should** have a `tabIndex={0}` instead\n */\n tabIndex?: number;\n\n ref: RefCallback<E>;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface KeyboardMovementProviderImplementation<E extends HTMLElement> {\n nodeRef: RefObject<E>;\n movementProps: Readonly<KeyboardMovementProps<E>>;\n movementContext: Readonly<KeyboardMovementContext>;\n currentFocusIndex: NonNullMutableRef<number>;\n activeDescendantId: string;\n setActiveDescendantId: UseStateSetter<string>;\n}\n"],"names":[],"mappings":"AA2YA;;;CAGC,GACD,WAOC"}
|
|
@@ -27,7 +27,9 @@ const noop = ()=>{
|
|
|
27
27
|
focusLast: noop,
|
|
28
28
|
focusNext: noop,
|
|
29
29
|
focusPrevious: noop,
|
|
30
|
-
focusFromKey: noop
|
|
30
|
+
focusFromKey: noop,
|
|
31
|
+
focusCurrent: ()=>{},
|
|
32
|
+
updateFocusIndex: noop
|
|
31
33
|
};
|
|
32
34
|
/**
|
|
33
35
|
* @since 5.0.0
|
|
@@ -214,12 +216,15 @@ const returnNegative1 = ()=>-1;
|
|
|
214
216
|
nodeRef,
|
|
215
217
|
programmatic
|
|
216
218
|
]);
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
+
const focusCurrent = useCallback((focusables = getFocusableElementsFromRef())=>{
|
|
220
|
+
const index = currentFocusIndex.current;
|
|
221
|
+
if (index === -1) {
|
|
219
222
|
return;
|
|
220
223
|
}
|
|
221
|
-
currentFocusIndex.current = index;
|
|
222
224
|
const focused = focusables[index];
|
|
225
|
+
if (!focused) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
223
228
|
if (tabIndexBehavior) {
|
|
224
229
|
focused.scrollIntoView({
|
|
225
230
|
block: "nearest",
|
|
@@ -230,63 +235,94 @@ const returnNegative1 = ()=>-1;
|
|
|
230
235
|
if (tabIndexBehavior !== "virtual") {
|
|
231
236
|
focused.focus();
|
|
232
237
|
}
|
|
233
|
-
|
|
234
|
-
index,
|
|
235
|
-
element: focused
|
|
236
|
-
});
|
|
238
|
+
return focused;
|
|
237
239
|
}, [
|
|
238
240
|
getFocusableElementsFromRef,
|
|
239
|
-
onFocusChange,
|
|
240
241
|
tabIndexBehavior
|
|
241
242
|
]);
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
243
|
+
const updateFocusIndex = useCallback((options)=>{
|
|
244
|
+
const { index, force, focusables = getFocusableElementsFromRef() } = options;
|
|
245
|
+
const isSameIndex = currentFocusIndex.current === index;
|
|
246
|
+
if (!force && isSameIndex || index === -1) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
currentFocusIndex.current = index;
|
|
250
|
+
const focused = focusCurrent(focusables);
|
|
251
|
+
if (focused && !isSameIndex) {
|
|
252
|
+
onFocusChange({
|
|
253
|
+
index,
|
|
254
|
+
element: focused
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
}, [
|
|
258
|
+
focusCurrent,
|
|
259
|
+
getFocusableElementsFromRef,
|
|
260
|
+
onFocusChange
|
|
261
|
+
]);
|
|
262
|
+
const focusNext = useCallback((focusables = getFocusableElementsFromRef(), force = false)=>{
|
|
263
|
+
updateFocusIndex({
|
|
264
|
+
index: getNextFocusableIndex({
|
|
265
|
+
loopable,
|
|
266
|
+
increment: true,
|
|
267
|
+
focusables,
|
|
268
|
+
includeDisabled: true,
|
|
269
|
+
currentFocusIndex: currentFocusIndex.current
|
|
270
|
+
}),
|
|
271
|
+
force,
|
|
272
|
+
focusables
|
|
273
|
+
});
|
|
250
274
|
}, [
|
|
251
275
|
getFocusableElementsFromRef,
|
|
252
276
|
loopable,
|
|
253
277
|
updateFocusIndex
|
|
254
278
|
]);
|
|
255
|
-
const focusPrevious = useCallback((focusables = getFocusableElementsFromRef())=>{
|
|
256
|
-
updateFocusIndex(
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
279
|
+
const focusPrevious = useCallback((focusables = getFocusableElementsFromRef(), force = false)=>{
|
|
280
|
+
updateFocusIndex({
|
|
281
|
+
index: getNextFocusableIndex({
|
|
282
|
+
loopable,
|
|
283
|
+
increment: false,
|
|
284
|
+
focusables,
|
|
285
|
+
includeDisabled: true,
|
|
286
|
+
currentFocusIndex: currentFocusIndex.current
|
|
287
|
+
}),
|
|
288
|
+
force,
|
|
289
|
+
focusables
|
|
290
|
+
});
|
|
263
291
|
}, [
|
|
264
292
|
getFocusableElementsFromRef,
|
|
265
293
|
loopable,
|
|
266
294
|
updateFocusIndex
|
|
267
295
|
]);
|
|
268
|
-
const focusFirst = useCallback((focusables = getFocusableElementsFromRef())=>{
|
|
269
|
-
updateFocusIndex(
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
296
|
+
const focusFirst = useCallback((focusables = getFocusableElementsFromRef(), force = false)=>{
|
|
297
|
+
updateFocusIndex({
|
|
298
|
+
index: getFirstFocusableIndex({
|
|
299
|
+
focusables,
|
|
300
|
+
includeDisabled
|
|
301
|
+
}),
|
|
302
|
+
force,
|
|
303
|
+
focusables
|
|
304
|
+
});
|
|
273
305
|
}, [
|
|
274
306
|
getFocusableElementsFromRef,
|
|
275
307
|
includeDisabled,
|
|
276
308
|
updateFocusIndex
|
|
277
309
|
]);
|
|
278
|
-
const focusLast = useCallback((focusables = getFocusableElementsFromRef())=>{
|
|
279
|
-
updateFocusIndex(
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
310
|
+
const focusLast = useCallback((focusables = getFocusableElementsFromRef(), force = false)=>{
|
|
311
|
+
updateFocusIndex({
|
|
312
|
+
index: getLastFocusableIndex({
|
|
313
|
+
focusables,
|
|
314
|
+
includeDisabled
|
|
315
|
+
}),
|
|
316
|
+
force,
|
|
317
|
+
focusables
|
|
318
|
+
});
|
|
283
319
|
}, [
|
|
284
320
|
getFocusableElementsFromRef,
|
|
285
321
|
includeDisabled,
|
|
286
322
|
updateFocusIndex
|
|
287
323
|
]);
|
|
288
324
|
const focusFromKey = useCallback((options)=>{
|
|
289
|
-
const { key, reversed, focusables = getFocusableElementsFromRef() } = options;
|
|
325
|
+
const { key, force, reversed, focusables = getFocusableElementsFromRef() } = options;
|
|
290
326
|
if (!searchable) {
|
|
291
327
|
return;
|
|
292
328
|
}
|
|
@@ -295,7 +331,11 @@ const returnNegative1 = ()=>-1;
|
|
|
295
331
|
values: focusables.map((element)=>getSearchText(element, !isNotFocusable(element, includeDisabled))),
|
|
296
332
|
startIndex: reversed ? -1 : currentFocusIndex.current
|
|
297
333
|
});
|
|
298
|
-
updateFocusIndex(
|
|
334
|
+
updateFocusIndex({
|
|
335
|
+
index,
|
|
336
|
+
force,
|
|
337
|
+
focusables
|
|
338
|
+
});
|
|
299
339
|
}, [
|
|
300
340
|
getFocusableElementsFromRef,
|
|
301
341
|
includeDisabled,
|
|
@@ -312,11 +352,14 @@ const returnNegative1 = ()=>-1;
|
|
|
312
352
|
focusNext,
|
|
313
353
|
focusPrevious,
|
|
314
354
|
focusFromKey,
|
|
355
|
+
focusCurrent,
|
|
356
|
+
updateFocusIndex,
|
|
315
357
|
includeDisabled,
|
|
316
358
|
tabIndexBehavior,
|
|
317
359
|
activeDescendantId
|
|
318
360
|
}), [
|
|
319
361
|
activeDescendantId,
|
|
362
|
+
focusCurrent,
|
|
320
363
|
focusFirst,
|
|
321
364
|
focusFromKey,
|
|
322
365
|
focusLast,
|
|
@@ -326,7 +369,8 @@ const returnNegative1 = ()=>-1;
|
|
|
326
369
|
includeDisabled,
|
|
327
370
|
loopable,
|
|
328
371
|
searchable,
|
|
329
|
-
tabIndexBehavior
|
|
372
|
+
tabIndexBehavior,
|
|
373
|
+
updateFocusIndex
|
|
330
374
|
]);
|
|
331
375
|
return {
|
|
332
376
|
nodeRef,
|
|
@@ -433,7 +477,10 @@ const returnNegative1 = ()=>-1;
|
|
|
433
477
|
const setFocusIndex = (index, focusables)=>{
|
|
434
478
|
event.preventDefault();
|
|
435
479
|
event.stopPropagation();
|
|
436
|
-
updateFocusIndex(
|
|
480
|
+
updateFocusIndex({
|
|
481
|
+
index,
|
|
482
|
+
focusables
|
|
483
|
+
});
|
|
437
484
|
};
|
|
438
485
|
extendKeyDown({
|
|
439
486
|
event,
|
|
@@ -480,28 +527,30 @@ const returnNegative1 = ()=>-1;
|
|
|
480
527
|
return;
|
|
481
528
|
}
|
|
482
529
|
if (trackTabKeys && key === "Tab") {
|
|
483
|
-
currentFocusIndex.current
|
|
530
|
+
currentFocusIndex.current = getNextFocusableIndex({
|
|
531
|
+
loopable,
|
|
532
|
+
increment: !event.shiftKey,
|
|
533
|
+
focusables: getFocusableElements(currentTarget, programmatic),
|
|
534
|
+
includeDisabled,
|
|
535
|
+
currentFocusIndex: currentFocusIndex.current
|
|
536
|
+
});
|
|
484
537
|
return;
|
|
485
538
|
}
|
|
486
539
|
const jumpToFirst = jumpToFirstKeys.includes(key);
|
|
487
540
|
const jumpToLast = !jumpToFirst && jumpToLastKeys.includes(key);
|
|
488
541
|
const increment = !jumpToFirst && !jumpToLast && incrementKeys.includes(key);
|
|
489
542
|
const decrement = !jumpToFirst && !jumpToLast && !increment && decrementKeys.includes(key);
|
|
490
|
-
if (jumpToFirst) {
|
|
543
|
+
if (jumpToFirst || jumpToLast || increment || decrement) {
|
|
491
544
|
event.preventDefault();
|
|
492
545
|
event.stopPropagation();
|
|
546
|
+
}
|
|
547
|
+
if (jumpToFirst) {
|
|
493
548
|
focusFirst();
|
|
494
549
|
} else if (jumpToLast) {
|
|
495
|
-
event.preventDefault();
|
|
496
|
-
event.stopPropagation();
|
|
497
550
|
focusLast();
|
|
498
551
|
} else if (increment) {
|
|
499
|
-
event.preventDefault();
|
|
500
|
-
event.stopPropagation();
|
|
501
552
|
focusNext();
|
|
502
553
|
} else if (decrement) {
|
|
503
|
-
event.preventDefault();
|
|
504
|
-
event.stopPropagation();
|
|
505
554
|
focusPrevious();
|
|
506
555
|
}
|
|
507
556
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/movement/useKeyboardMovementProvider.ts"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { getFocusableElements as defaultGetFocusableElements } from \"../focus/utils.js\";\nimport { useUserInteractionMode } from \"../interaction/UserInteractionModeProvider.js\";\nimport { useDir } from \"../typography/WritingDirectionProvider.js\";\nimport { useEnsuredRef } from \"../useEnsuredRef.js\";\nimport { useIsomorphicLayoutEffect } from \"../useIsomorphicLayoutEffect.js\";\nimport {\n DEFAULT_KEYBOARD_MOVEMENT,\n DEFAULT_LTR_KEYBOARD_MOVEMENT,\n DEFAULT_RTL_KEYBOARD_MOVEMENT,\n} from \"./constants.js\";\nimport { findMatchIndex } from \"./findMatchIndex.js\";\nimport {\n type KeyboardFocusFromKeyOptions,\n type KeyboardMovementConfig,\n type KeyboardMovementConfiguration,\n type KeyboardMovementContext,\n type KeyboardMovementProviderImplementation,\n type KeyboardMovementProviderOptions,\n} from \"./types.js\";\nimport {\n getFirstFocusableIndex,\n getLastFocusableIndex,\n getNextFocusableIndex,\n getSearchText,\n getVirtualFocusDefaultIndex,\n isElementDisabled,\n isNotFocusable,\n isSearchableEvent,\n recalculateFocusIndex,\n} from \"./utils.js\";\n\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * @since 6.3.0\n */\nexport const DEFAULT_KEYBOARD_MOVEMENT_CONTEXT: Readonly<KeyboardMovementContext> =\n {\n config: { current: DEFAULT_KEYBOARD_MOVEMENT },\n loopable: false,\n searchable: false,\n horizontal: false,\n includeDisabled: false,\n tabIndexBehavior: undefined,\n activeDescendantId: \"\",\n focusFirst: noop,\n focusLast: noop,\n focusNext: noop,\n focusPrevious: noop,\n focusFromKey: noop,\n };\n\n/**\n * @since 5.0.0\n * @internal\n */\nconst context = createContext<KeyboardMovementContext>(\n DEFAULT_KEYBOARD_MOVEMENT_CONTEXT\n);\ncontext.displayName = \"KeyboardMovement\";\nexport const { Provider: KeyboardMovementProvider } = context;\n\n/**\n * @since 5.0.0\n * @internal\n */\nexport function useKeyboardMovementContext(): Readonly<KeyboardMovementContext> {\n return useContext(context);\n}\n\nconst returnNegative1 = (): number => -1;\n\n/**\n * Implements the custom keyboard movement behavior throughout react-md. Using\n * the \"Find References\" will be the best way to see example usage.\n *\n * @example Default Keyboard Movement for any Focusable Element\n * ```tsx\n * import {\n * KeyboardMovementProvider,\n * useKeyboardMovementProvider,\n * } from \"@react-md/core/movement/useKeyboardMovementProvider\";\n * import type { ReactElement, ReactNode } from \"react\";\n *\n * function Example({ children }: { children: ReactNode }): ReactElement {\n * const { movementContext, movementProps } = useKeyboardMovementProvider();\n *\n * // any focusable element child can be focused with the arrow , home, and\n * // end keys\n * return (\n * <KeyboardMovementProvider value={movementContext}>\n * <div {...movementProps}>\n * {children}\n * </div>\n * </KeyboardMovementProvider>\n * );\n * }\n * ```\n *\n * @example Active Descendant Movement\n * ```tsx\n * import {\n * KeyboardMovementProvider,\n * useKeyboardMovementContext,\n * useKeyboardMovementProvider,\n * } from \"@react-md/core/movement/useKeyboardMovementProvider\";\n * import type { ReactElement, ReactNode } from \"react\";\n * import { useId } from \"react\";\n *\n * function Child(): ReactElement {\n * const id = useId()\n * const { activeDescendantId } = useKeyboardMovementContext();\n *\n * return (\n * <div\n * {...props}\n * id={id}\n * className={cnb(id === activeDescendantId && \"focused-class-name\")}\n * >\n * Some Content\n * </div>\n * );\n * }\n *\n * function Example({ children }: { children: ReactNode }): ReactElement {\n * const { movementContext, movementProps } = useKeyboardMovementProvider({\n * loopable: true,\n * searchable: true,\n * tabIndexBehavior: \"virtual\",\n * });\n *\n * // any focusable element child can be focused with the arrow , home, and\n * // end keys\n * return (\n * <KeyboardMovementProvider value={movementContext}>\n * <div {...movementProps}>\n * <Child />\n * <Child />\n * <Child />\n * </div>\n * </KeyboardMovementProvider>\n * );\n * }\n * ```\n *\n * @example Roving Tab Index\n * ```tsx\n * import {\n * KeyboardMovementProvider,\n * useKeyboardMovementContext,\n * useKeyboardMovementProvider,\n * } from \"@react-md/core/movement/useKeyboardMovementProvider\";\n * import type { ReactElement, ReactNode } from \"react\";\n * import { useId } from \"react\";\n *\n * function Child(): ReactElement {\n * const id = useId()\n * const { activeDescendantId } = useKeyboardMovementContext();\n *\n * return (\n * <div\n * {...props}\n * id={id}\n * tabIndex={id === activeDescendantId ? 0 : -1}\n * >\n * Some Content\n * </div>\n * );\n * }\n *\n * function Example({ children }: { children: ReactNode }): ReactElement {\n * const { movementContext, movementProps } = useKeyboardMovementProvider({\n * loopable: true,\n * searchable: true,\n * tabIndexBehavior: \"roving\",\n * });\n *\n * // any focusable element child can be focused with the arrow , home, and\n * // end keys\n * return (\n * <KeyboardMovementProvider value={movementContext}>\n * <div {...movementProps}>\n * <Child />\n * <Child />\n * <Child />\n * </div>\n * </KeyboardMovementProvider>\n * );\n * }\n * ```\n * @since 6.0.0\n * @internal\n */\nexport function useKeyboardMovementProvider<E extends HTMLElement>(\n options: KeyboardMovementProviderOptions<E> = {}\n): KeyboardMovementProviderImplementation<E> {\n const {\n ref: propRef,\n onClick = noop,\n onFocus = noop,\n onKeyDown = noop,\n loopable = false,\n disabled,\n searchable = false,\n horizontal = false,\n trackTabKeys = false,\n includeDisabled = false,\n tabIndexBehavior,\n extendKeyDown = noop,\n onFocusChange = noop,\n programmatic = includeDisabled,\n incrementKeys: propIncrementKeys,\n decrementKeys: propDecrementKeys,\n jumpToFirstKeys: propJumpToFirstKeys,\n jumpToLastKeys: propJumpToLastKeys,\n getFocusableElements = defaultGetFocusableElements,\n getDefaultFocusedIndex = returnNegative1,\n isNegativeOneAllowed = false,\n } = options;\n\n const [nodeRef, nodeRefCallback] = useEnsuredRef(propRef);\n\n const isRTL = useDir().dir === \"rtl\";\n let defaults: Readonly<Required<KeyboardMovementConfiguration>>;\n if (horizontal) {\n defaults = isRTL\n ? DEFAULT_RTL_KEYBOARD_MOVEMENT\n : DEFAULT_LTR_KEYBOARD_MOVEMENT;\n } else {\n defaults = DEFAULT_KEYBOARD_MOVEMENT;\n }\n\n const incrementKeys = propIncrementKeys || defaults.incrementKeys;\n const decrementKeys = propDecrementKeys || defaults.decrementKeys;\n const jumpToFirstKeys = propJumpToFirstKeys || defaults.jumpToFirstKeys;\n const jumpToLastKeys = propJumpToLastKeys || defaults.jumpToLastKeys;\n\n const configuration: KeyboardMovementConfig = {\n incrementKeys,\n decrementKeys,\n jumpToFirstKeys,\n jumpToLastKeys,\n };\n const config = useRef(configuration);\n useIsomorphicLayoutEffect(() => {\n config.current = configuration;\n });\n\n const mode = useUserInteractionMode();\n const refocus = useRef(false);\n const currentFocusIndex = useRef(-1);\n const [activeDescendantId, setActiveDescendantId] = useState(\"\");\n\n if (process.env.NODE_ENV !== \"production\") {\n // this fixes issues during hot reloading and using the `useId()` hook\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useEffect(() => {\n return () => {\n setActiveDescendantId(\"\");\n };\n }, []);\n }\n\n let tabIndex: number | undefined;\n if (tabIndexBehavior) {\n tabIndex =\n disabled || (tabIndexBehavior === \"roving\" && activeDescendantId)\n ? -1\n : 0;\n }\n\n const getFocusableElementsFromRef = useCallback(() => {\n const container = nodeRef.current;\n if (!container) {\n return [];\n }\n\n return getFocusableElements(container, programmatic);\n }, [getFocusableElements, nodeRef, programmatic]);\n const updateFocusIndex = useCallback(\n (index: number, focusables = getFocusableElementsFromRef()) => {\n if (currentFocusIndex.current === index || index === -1) {\n return;\n }\n\n currentFocusIndex.current = index;\n const focused = focusables[index];\n if (tabIndexBehavior) {\n focused.scrollIntoView({\n block: \"nearest\",\n inline: \"nearest\",\n });\n setActiveDescendantId(focused.id);\n }\n\n if (tabIndexBehavior !== \"virtual\") {\n focused.focus();\n }\n\n onFocusChange({\n index,\n element: focused,\n });\n },\n [getFocusableElementsFromRef, onFocusChange, tabIndexBehavior]\n );\n\n const focusNext = useCallback(\n (focusables = getFocusableElementsFromRef()) => {\n updateFocusIndex(\n getNextFocusableIndex({\n loopable,\n increment: true,\n focusables,\n includeDisabled: true,\n currentFocusIndex: currentFocusIndex.current,\n }),\n focusables\n );\n },\n [getFocusableElementsFromRef, loopable, updateFocusIndex]\n );\n const focusPrevious = useCallback(\n (focusables = getFocusableElementsFromRef()) => {\n updateFocusIndex(\n getNextFocusableIndex({\n loopable,\n increment: false,\n focusables,\n includeDisabled: true,\n currentFocusIndex: currentFocusIndex.current,\n }),\n focusables\n );\n },\n [getFocusableElementsFromRef, loopable, updateFocusIndex]\n );\n const focusFirst = useCallback(\n (focusables = getFocusableElementsFromRef()) => {\n updateFocusIndex(\n getFirstFocusableIndex({\n focusables,\n includeDisabled,\n }),\n focusables\n );\n },\n [getFocusableElementsFromRef, includeDisabled, updateFocusIndex]\n );\n const focusLast = useCallback(\n (focusables = getFocusableElementsFromRef()) => {\n updateFocusIndex(\n getLastFocusableIndex({\n focusables,\n includeDisabled,\n }),\n focusables\n );\n },\n [getFocusableElementsFromRef, includeDisabled, updateFocusIndex]\n );\n const focusFromKey = useCallback(\n (options: KeyboardFocusFromKeyOptions) => {\n const {\n key,\n reversed,\n focusables = getFocusableElementsFromRef(),\n } = options;\n if (!searchable) {\n return;\n }\n\n const index = findMatchIndex({\n value: key,\n values: focusables.map((element) =>\n getSearchText(element, !isNotFocusable(element, includeDisabled))\n ),\n startIndex: reversed ? -1 : currentFocusIndex.current,\n });\n updateFocusIndex(index, focusables);\n },\n [getFocusableElementsFromRef, includeDisabled, searchable, updateFocusIndex]\n );\n\n const movementContext = useMemo<KeyboardMovementContext>(\n () => ({\n config,\n loopable,\n searchable,\n horizontal,\n focusFirst,\n focusLast,\n focusNext,\n focusPrevious,\n focusFromKey,\n includeDisabled,\n tabIndexBehavior,\n activeDescendantId,\n }),\n [\n activeDescendantId,\n focusFirst,\n focusFromKey,\n focusLast,\n focusNext,\n focusPrevious,\n horizontal,\n includeDisabled,\n loopable,\n searchable,\n tabIndexBehavior,\n ]\n );\n\n return {\n nodeRef,\n movementProps: {\n \"aria-activedescendant\":\n tabIndexBehavior === \"virtual\" ? activeDescendantId : undefined,\n ref: nodeRefCallback,\n tabIndex,\n\n // Note: This used to be on the `onFocus` event, but this causes issues in\n // Chromium browsers for drag and drop behavior\n onClick(event) {\n onClick(event);\n if (disabled) {\n return;\n }\n\n // This makes it so you can click an element with a mouse and then\n // keyboard navigate from that element instead of the last keyboard focus\n // element\n const { currentTarget, target } = event;\n if (target === currentTarget || !(target instanceof HTMLElement)) {\n return;\n }\n\n const focusables = getFocusableElements(currentTarget, programmatic);\n const focusedIndex = focusables.findIndex(\n (element) => element === target || element.contains(target)\n );\n if (focusedIndex === -1 || !focusables.length) {\n return;\n }\n\n currentFocusIndex.current = focusedIndex;\n const focused = focusables[focusedIndex];\n if (tabIndexBehavior) {\n setActiveDescendantId(focused.id);\n }\n\n // need to force focus back to the container element when using\n // aria activedescendant\n if (tabIndexBehavior === \"virtual\") {\n refocus.current = true;\n currentTarget.focus();\n }\n\n onFocusChange({\n index: focusedIndex,\n element: focused,\n });\n },\n onFocus(event) {\n onFocus(event);\n if (event.isPropagationStopped() || refocus.current) {\n refocus.current = false;\n return;\n }\n\n if (\n (mode !== \"keyboard\" && tabIndexBehavior !== \"virtual\") ||\n event.target !== event.currentTarget\n ) {\n return;\n }\n\n const focusables = getFocusableElements(\n event.currentTarget,\n programmatic\n );\n if (!focusables.length) {\n return;\n }\n\n let defaultFocusIndex = getDefaultFocusedIndex({\n focusables,\n includeDisabled,\n });\n\n // This allows my custom `getDefaultFocusedIndex` implementations to\n // have a nice fallback without having to re-implement the \"focus\n // first\" behavior\n if (!isNegativeOneAllowed && defaultFocusIndex === -1) {\n if (tabIndexBehavior === \"virtual\") {\n // virtual keyboard navigation **must** always focus at least one element\n defaultFocusIndex = getVirtualFocusDefaultIndex({\n focusables,\n includeDisabled,\n activeDescendantId,\n });\n } else {\n defaultFocusIndex = getFirstFocusableIndex({\n focusables,\n includeDisabled,\n });\n }\n }\n\n if (defaultFocusIndex === -1) {\n return;\n }\n\n currentFocusIndex.current = defaultFocusIndex;\n const focused = focusables[defaultFocusIndex];\n if (tabIndexBehavior) {\n setActiveDescendantId(focused.id);\n }\n\n if (tabIndexBehavior !== \"virtual\") {\n focused.focus();\n } else {\n focused.scrollIntoView({ block: \"nearest\" });\n }\n\n onFocusChange({\n index: defaultFocusIndex,\n element: focused,\n });\n },\n onKeyDown(event) {\n onKeyDown(event);\n if (disabled) {\n return;\n }\n\n const { currentTarget } = event;\n\n const setFocusIndex = (\n index: number,\n focusables: readonly HTMLElement[]\n ): void => {\n event.preventDefault();\n event.stopPropagation();\n updateFocusIndex(index, focusables);\n };\n\n extendKeyDown({\n event,\n setFocusIndex,\n currentFocusIndex,\n setActiveDescendantId,\n ...movementContext,\n });\n\n if (event.isPropagationStopped()) {\n return;\n }\n\n // TODO: Figure this part out. This is currently required for the tree\n // movement when the asterisk key is pressed. There might be other cases\n // as well.\n if (!isNegativeOneAllowed && currentFocusIndex.current === -1) {\n currentFocusIndex.current = recalculateFocusIndex({\n focusables: getFocusableElements(currentTarget, programmatic),\n includeDisabled,\n tabIndexBehavior,\n activeDescendantId,\n });\n }\n\n const { key, shiftKey } = event;\n if (\n tabIndexBehavior === \"virtual\" &&\n activeDescendantId &&\n (key === \" \" || key === \"Enter\")\n ) {\n if (key === \" \") {\n event.preventDefault();\n }\n\n const focusables = getFocusableElements(currentTarget, programmatic);\n const activeElement = focusables[currentFocusIndex.current];\n if (!activeElement || isElementDisabled(activeElement)) {\n return;\n }\n\n activeElement.click();\n return;\n }\n\n const {\n incrementKeys,\n decrementKeys,\n jumpToFirstKeys,\n jumpToLastKeys,\n } = config.current;\n\n if (searchable && isSearchableEvent(event)) {\n event.preventDefault();\n event.stopPropagation();\n focusFromKey({ key, reversed: shiftKey });\n return;\n }\n\n if (trackTabKeys && key === \"Tab\") {\n currentFocusIndex.current += event.shiftKey ? -1 : 1;\n return;\n }\n\n const jumpToFirst = jumpToFirstKeys.includes(key);\n const jumpToLast = !jumpToFirst && jumpToLastKeys.includes(key);\n const increment =\n !jumpToFirst && !jumpToLast && incrementKeys.includes(key);\n const decrement =\n !jumpToFirst &&\n !jumpToLast &&\n !increment &&\n decrementKeys.includes(key);\n\n if (jumpToFirst) {\n event.preventDefault();\n event.stopPropagation();\n focusFirst();\n } else if (jumpToLast) {\n event.preventDefault();\n event.stopPropagation();\n focusLast();\n } else if (increment) {\n event.preventDefault();\n event.stopPropagation();\n focusNext();\n } else if (decrement) {\n event.preventDefault();\n event.stopPropagation();\n focusPrevious();\n }\n },\n },\n movementContext,\n currentFocusIndex,\n activeDescendantId,\n setActiveDescendantId,\n };\n}\n"],"names":["createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","getFocusableElements","defaultGetFocusableElements","useUserInteractionMode","useDir","useEnsuredRef","useIsomorphicLayoutEffect","DEFAULT_KEYBOARD_MOVEMENT","DEFAULT_LTR_KEYBOARD_MOVEMENT","DEFAULT_RTL_KEYBOARD_MOVEMENT","findMatchIndex","getFirstFocusableIndex","getLastFocusableIndex","getNextFocusableIndex","getSearchText","getVirtualFocusDefaultIndex","isElementDisabled","isNotFocusable","isSearchableEvent","recalculateFocusIndex","noop","DEFAULT_KEYBOARD_MOVEMENT_CONTEXT","config","current","loopable","searchable","horizontal","includeDisabled","tabIndexBehavior","undefined","activeDescendantId","focusFirst","focusLast","focusNext","focusPrevious","focusFromKey","context","displayName","Provider","KeyboardMovementProvider","useKeyboardMovementContext","returnNegative1","useKeyboardMovementProvider","options","ref","propRef","onClick","onFocus","onKeyDown","disabled","trackTabKeys","extendKeyDown","onFocusChange","programmatic","incrementKeys","propIncrementKeys","decrementKeys","propDecrementKeys","jumpToFirstKeys","propJumpToFirstKeys","jumpToLastKeys","propJumpToLastKeys","getDefaultFocusedIndex","isNegativeOneAllowed","nodeRef","nodeRefCallback","isRTL","dir","defaults","configuration","mode","refocus","currentFocusIndex","setActiveDescendantId","process","env","NODE_ENV","tabIndex","getFocusableElementsFromRef","container","updateFocusIndex","index","focusables","focused","scrollIntoView","block","inline","id","focus","element","increment","key","reversed","value","values","map","startIndex","movementContext","movementProps","event","currentTarget","target","HTMLElement","focusedIndex","findIndex","contains","length","isPropagationStopped","defaultFocusIndex","setFocusIndex","preventDefault","stopPropagation","shiftKey","activeElement","click","jumpToFirst","includes","jumpToLast","decrement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/movement/useKeyboardMovementProvider.ts"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { getFocusableElements as defaultGetFocusableElements } from \"../focus/utils.js\";\nimport { useUserInteractionMode } from \"../interaction/UserInteractionModeProvider.js\";\nimport { useDir } from \"../typography/WritingDirectionProvider.js\";\nimport { useEnsuredRef } from \"../useEnsuredRef.js\";\nimport { useIsomorphicLayoutEffect } from \"../useIsomorphicLayoutEffect.js\";\nimport {\n DEFAULT_KEYBOARD_MOVEMENT,\n DEFAULT_LTR_KEYBOARD_MOVEMENT,\n DEFAULT_RTL_KEYBOARD_MOVEMENT,\n} from \"./constants.js\";\nimport { findMatchIndex } from \"./findMatchIndex.js\";\nimport {\n type KeyboardFocusFromKeyOptions,\n type KeyboardMovementConfig,\n type KeyboardMovementConfiguration,\n type KeyboardMovementContext,\n type KeyboardMovementProviderImplementation,\n type KeyboardMovementProviderOptions,\n type KeyboardMovementUpdateFocusIndexOptions,\n} from \"./types.js\";\nimport {\n getFirstFocusableIndex,\n getLastFocusableIndex,\n getNextFocusableIndex,\n getSearchText,\n getVirtualFocusDefaultIndex,\n isElementDisabled,\n isNotFocusable,\n isSearchableEvent,\n recalculateFocusIndex,\n} from \"./utils.js\";\n\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * @since 6.3.0\n */\nexport const DEFAULT_KEYBOARD_MOVEMENT_CONTEXT: Readonly<KeyboardMovementContext> =\n {\n config: { current: DEFAULT_KEYBOARD_MOVEMENT },\n loopable: false,\n searchable: false,\n horizontal: false,\n includeDisabled: false,\n tabIndexBehavior: undefined,\n activeDescendantId: \"\",\n focusFirst: noop,\n focusLast: noop,\n focusNext: noop,\n focusPrevious: noop,\n focusFromKey: noop,\n focusCurrent: (): undefined => {},\n updateFocusIndex: noop,\n };\n\n/**\n * @since 5.0.0\n * @internal\n */\nconst context = createContext<KeyboardMovementContext>(\n DEFAULT_KEYBOARD_MOVEMENT_CONTEXT\n);\ncontext.displayName = \"KeyboardMovement\";\nexport const { Provider: KeyboardMovementProvider } = context;\n\n/**\n * @since 5.0.0\n * @internal\n */\nexport function useKeyboardMovementContext(): Readonly<KeyboardMovementContext> {\n return useContext(context);\n}\n\nconst returnNegative1 = (): number => -1;\n\n/**\n * Implements the custom keyboard movement behavior throughout react-md. Using\n * the \"Find References\" will be the best way to see example usage.\n *\n * @example Default Keyboard Movement for any Focusable Element\n * ```tsx\n * import {\n * KeyboardMovementProvider,\n * useKeyboardMovementProvider,\n * } from \"@react-md/core/movement/useKeyboardMovementProvider\";\n * import type { ReactElement, ReactNode } from \"react\";\n *\n * function Example({ children }: { children: ReactNode }): ReactElement {\n * const { movementContext, movementProps } = useKeyboardMovementProvider();\n *\n * // any focusable element child can be focused with the arrow , home, and\n * // end keys\n * return (\n * <KeyboardMovementProvider value={movementContext}>\n * <div {...movementProps}>\n * {children}\n * </div>\n * </KeyboardMovementProvider>\n * );\n * }\n * ```\n *\n * @example Active Descendant Movement\n * ```tsx\n * import {\n * KeyboardMovementProvider,\n * useKeyboardMovementContext,\n * useKeyboardMovementProvider,\n * } from \"@react-md/core/movement/useKeyboardMovementProvider\";\n * import type { ReactElement, ReactNode } from \"react\";\n * import { useId } from \"react\";\n *\n * function Child(): ReactElement {\n * const id = useId()\n * const { activeDescendantId } = useKeyboardMovementContext();\n *\n * return (\n * <div\n * {...props}\n * id={id}\n * className={cnb(id === activeDescendantId && \"focused-class-name\")}\n * >\n * Some Content\n * </div>\n * );\n * }\n *\n * function Example({ children }: { children: ReactNode }): ReactElement {\n * const { movementContext, movementProps } = useKeyboardMovementProvider({\n * loopable: true,\n * searchable: true,\n * tabIndexBehavior: \"virtual\",\n * });\n *\n * // any focusable element child can be focused with the arrow , home, and\n * // end keys\n * return (\n * <KeyboardMovementProvider value={movementContext}>\n * <div {...movementProps}>\n * <Child />\n * <Child />\n * <Child />\n * </div>\n * </KeyboardMovementProvider>\n * );\n * }\n * ```\n *\n * @example Roving Tab Index\n * ```tsx\n * import {\n * KeyboardMovementProvider,\n * useKeyboardMovementContext,\n * useKeyboardMovementProvider,\n * } from \"@react-md/core/movement/useKeyboardMovementProvider\";\n * import type { ReactElement, ReactNode } from \"react\";\n * import { useId } from \"react\";\n *\n * function Child(): ReactElement {\n * const id = useId()\n * const { activeDescendantId } = useKeyboardMovementContext();\n *\n * return (\n * <div\n * {...props}\n * id={id}\n * tabIndex={id === activeDescendantId ? 0 : -1}\n * >\n * Some Content\n * </div>\n * );\n * }\n *\n * function Example({ children }: { children: ReactNode }): ReactElement {\n * const { movementContext, movementProps } = useKeyboardMovementProvider({\n * loopable: true,\n * searchable: true,\n * tabIndexBehavior: \"roving\",\n * });\n *\n * // any focusable element child can be focused with the arrow , home, and\n * // end keys\n * return (\n * <KeyboardMovementProvider value={movementContext}>\n * <div {...movementProps}>\n * <Child />\n * <Child />\n * <Child />\n * </div>\n * </KeyboardMovementProvider>\n * );\n * }\n * ```\n * @since 6.0.0\n * @internal\n */\nexport function useKeyboardMovementProvider<E extends HTMLElement>(\n options: KeyboardMovementProviderOptions<E> = {}\n): KeyboardMovementProviderImplementation<E> {\n const {\n ref: propRef,\n onClick = noop,\n onFocus = noop,\n onKeyDown = noop,\n loopable = false,\n disabled,\n searchable = false,\n horizontal = false,\n trackTabKeys = false,\n includeDisabled = false,\n tabIndexBehavior,\n extendKeyDown = noop,\n onFocusChange = noop,\n programmatic = includeDisabled,\n incrementKeys: propIncrementKeys,\n decrementKeys: propDecrementKeys,\n jumpToFirstKeys: propJumpToFirstKeys,\n jumpToLastKeys: propJumpToLastKeys,\n getFocusableElements = defaultGetFocusableElements,\n getDefaultFocusedIndex = returnNegative1,\n isNegativeOneAllowed = false,\n } = options;\n\n const [nodeRef, nodeRefCallback] = useEnsuredRef(propRef);\n\n const isRTL = useDir().dir === \"rtl\";\n let defaults: Readonly<Required<KeyboardMovementConfiguration>>;\n if (horizontal) {\n defaults = isRTL\n ? DEFAULT_RTL_KEYBOARD_MOVEMENT\n : DEFAULT_LTR_KEYBOARD_MOVEMENT;\n } else {\n defaults = DEFAULT_KEYBOARD_MOVEMENT;\n }\n\n const incrementKeys = propIncrementKeys || defaults.incrementKeys;\n const decrementKeys = propDecrementKeys || defaults.decrementKeys;\n const jumpToFirstKeys = propJumpToFirstKeys || defaults.jumpToFirstKeys;\n const jumpToLastKeys = propJumpToLastKeys || defaults.jumpToLastKeys;\n\n const configuration: KeyboardMovementConfig = {\n incrementKeys,\n decrementKeys,\n jumpToFirstKeys,\n jumpToLastKeys,\n };\n const config = useRef(configuration);\n useIsomorphicLayoutEffect(() => {\n config.current = configuration;\n });\n\n const mode = useUserInteractionMode();\n const refocus = useRef(false);\n const currentFocusIndex = useRef(-1);\n const [activeDescendantId, setActiveDescendantId] = useState(\"\");\n\n if (process.env.NODE_ENV !== \"production\") {\n // this fixes issues during hot reloading and using the `useId()` hook\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useEffect(() => {\n return () => {\n setActiveDescendantId(\"\");\n };\n }, []);\n }\n\n let tabIndex: number | undefined;\n if (tabIndexBehavior) {\n tabIndex =\n disabled || (tabIndexBehavior === \"roving\" && activeDescendantId)\n ? -1\n : 0;\n }\n\n const getFocusableElementsFromRef = useCallback(() => {\n const container = nodeRef.current;\n if (!container) {\n return [];\n }\n\n return getFocusableElements(container, programmatic);\n }, [getFocusableElements, nodeRef, programmatic]);\n const focusCurrent = useCallback(\n (focusables = getFocusableElementsFromRef()): HTMLElement | undefined => {\n const index = currentFocusIndex.current;\n if (index === -1) {\n return;\n }\n\n const focused = focusables[index];\n if (!focused) {\n return;\n }\n\n if (tabIndexBehavior) {\n focused.scrollIntoView({\n block: \"nearest\",\n inline: \"nearest\",\n });\n setActiveDescendantId(focused.id);\n }\n\n if (tabIndexBehavior !== \"virtual\") {\n focused.focus();\n }\n\n return focused;\n },\n [getFocusableElementsFromRef, tabIndexBehavior]\n );\n const updateFocusIndex = useCallback(\n (options: KeyboardMovementUpdateFocusIndexOptions) => {\n const {\n index,\n force,\n focusables = getFocusableElementsFromRef(),\n } = options;\n const isSameIndex = currentFocusIndex.current === index;\n if ((!force && isSameIndex) || index === -1) {\n return;\n }\n\n currentFocusIndex.current = index;\n const focused = focusCurrent(focusables);\n if (focused && !isSameIndex) {\n onFocusChange({\n index,\n element: focused,\n });\n }\n },\n [focusCurrent, getFocusableElementsFromRef, onFocusChange]\n );\n\n const focusNext = useCallback(\n (focusables = getFocusableElementsFromRef(), force = false) => {\n updateFocusIndex({\n index: getNextFocusableIndex({\n loopable,\n increment: true,\n focusables,\n includeDisabled: true,\n currentFocusIndex: currentFocusIndex.current,\n }),\n force,\n focusables,\n });\n },\n [getFocusableElementsFromRef, loopable, updateFocusIndex]\n );\n const focusPrevious = useCallback(\n (focusables = getFocusableElementsFromRef(), force = false) => {\n updateFocusIndex({\n index: getNextFocusableIndex({\n loopable,\n increment: false,\n focusables,\n includeDisabled: true,\n currentFocusIndex: currentFocusIndex.current,\n }),\n force,\n focusables,\n });\n },\n [getFocusableElementsFromRef, loopable, updateFocusIndex]\n );\n const focusFirst = useCallback(\n (focusables = getFocusableElementsFromRef(), force = false) => {\n updateFocusIndex({\n index: getFirstFocusableIndex({\n focusables,\n includeDisabled,\n }),\n force,\n focusables,\n });\n },\n [getFocusableElementsFromRef, includeDisabled, updateFocusIndex]\n );\n const focusLast = useCallback(\n (focusables = getFocusableElementsFromRef(), force = false) => {\n updateFocusIndex({\n index: getLastFocusableIndex({\n focusables,\n includeDisabled,\n }),\n force,\n focusables,\n });\n },\n [getFocusableElementsFromRef, includeDisabled, updateFocusIndex]\n );\n const focusFromKey = useCallback(\n (options: KeyboardFocusFromKeyOptions) => {\n const {\n key,\n force,\n reversed,\n focusables = getFocusableElementsFromRef(),\n } = options;\n if (!searchable) {\n return;\n }\n\n const index = findMatchIndex({\n value: key,\n values: focusables.map((element) =>\n getSearchText(element, !isNotFocusable(element, includeDisabled))\n ),\n startIndex: reversed ? -1 : currentFocusIndex.current,\n });\n updateFocusIndex({ index, force, focusables });\n },\n [getFocusableElementsFromRef, includeDisabled, searchable, updateFocusIndex]\n );\n\n const movementContext = useMemo<KeyboardMovementContext>(\n () => ({\n config,\n loopable,\n searchable,\n horizontal,\n focusFirst,\n focusLast,\n focusNext,\n focusPrevious,\n focusFromKey,\n focusCurrent,\n updateFocusIndex,\n includeDisabled,\n tabIndexBehavior,\n activeDescendantId,\n }),\n [\n activeDescendantId,\n focusCurrent,\n focusFirst,\n focusFromKey,\n focusLast,\n focusNext,\n focusPrevious,\n horizontal,\n includeDisabled,\n loopable,\n searchable,\n tabIndexBehavior,\n updateFocusIndex,\n ]\n );\n\n return {\n nodeRef,\n movementProps: {\n \"aria-activedescendant\":\n tabIndexBehavior === \"virtual\" ? activeDescendantId : undefined,\n ref: nodeRefCallback,\n tabIndex,\n\n // Note: This used to be on the `onFocus` event, but this causes issues in\n // Chromium browsers for drag and drop behavior\n onClick(event) {\n onClick(event);\n if (disabled) {\n return;\n }\n\n // This makes it so you can click an element with a mouse and then\n // keyboard navigate from that element instead of the last keyboard focus\n // element\n const { currentTarget, target } = event;\n if (target === currentTarget || !(target instanceof HTMLElement)) {\n return;\n }\n\n const focusables = getFocusableElements(currentTarget, programmatic);\n const focusedIndex = focusables.findIndex(\n (element) => element === target || element.contains(target)\n );\n if (focusedIndex === -1 || !focusables.length) {\n return;\n }\n\n currentFocusIndex.current = focusedIndex;\n const focused = focusables[focusedIndex];\n if (tabIndexBehavior) {\n setActiveDescendantId(focused.id);\n }\n\n // need to force focus back to the container element when using\n // aria activedescendant\n if (tabIndexBehavior === \"virtual\") {\n refocus.current = true;\n currentTarget.focus();\n }\n\n onFocusChange({\n index: focusedIndex,\n element: focused,\n });\n },\n onFocus(event) {\n onFocus(event);\n if (event.isPropagationStopped() || refocus.current) {\n refocus.current = false;\n return;\n }\n\n if (\n (mode !== \"keyboard\" && tabIndexBehavior !== \"virtual\") ||\n event.target !== event.currentTarget\n ) {\n return;\n }\n\n const focusables = getFocusableElements(\n event.currentTarget,\n programmatic\n );\n if (!focusables.length) {\n return;\n }\n\n let defaultFocusIndex = getDefaultFocusedIndex({\n focusables,\n includeDisabled,\n });\n\n // This allows my custom `getDefaultFocusedIndex` implementations to\n // have a nice fallback without having to re-implement the \"focus\n // first\" behavior\n if (!isNegativeOneAllowed && defaultFocusIndex === -1) {\n if (tabIndexBehavior === \"virtual\") {\n // virtual keyboard navigation **must** always focus at least one element\n defaultFocusIndex = getVirtualFocusDefaultIndex({\n focusables,\n includeDisabled,\n activeDescendantId,\n });\n } else {\n defaultFocusIndex = getFirstFocusableIndex({\n focusables,\n includeDisabled,\n });\n }\n }\n\n if (defaultFocusIndex === -1) {\n return;\n }\n\n currentFocusIndex.current = defaultFocusIndex;\n const focused = focusables[defaultFocusIndex];\n if (tabIndexBehavior) {\n setActiveDescendantId(focused.id);\n }\n\n if (tabIndexBehavior !== \"virtual\") {\n focused.focus();\n } else {\n focused.scrollIntoView({ block: \"nearest\" });\n }\n\n onFocusChange({\n index: defaultFocusIndex,\n element: focused,\n });\n },\n onKeyDown(event) {\n onKeyDown(event);\n if (disabled) {\n return;\n }\n\n const { currentTarget } = event;\n\n const setFocusIndex = (\n index: number,\n focusables: readonly HTMLElement[]\n ): void => {\n event.preventDefault();\n event.stopPropagation();\n updateFocusIndex({ index, focusables });\n };\n\n extendKeyDown({\n event,\n setFocusIndex,\n currentFocusIndex,\n setActiveDescendantId,\n ...movementContext,\n });\n\n if (event.isPropagationStopped()) {\n return;\n }\n\n // TODO: Figure this part out. This is currently required for the tree\n // movement when the asterisk key is pressed. There might be other cases\n // as well.\n if (!isNegativeOneAllowed && currentFocusIndex.current === -1) {\n currentFocusIndex.current = recalculateFocusIndex({\n focusables: getFocusableElements(currentTarget, programmatic),\n includeDisabled,\n tabIndexBehavior,\n activeDescendantId,\n });\n }\n\n const { key, shiftKey } = event;\n if (\n tabIndexBehavior === \"virtual\" &&\n activeDescendantId &&\n (key === \" \" || key === \"Enter\")\n ) {\n if (key === \" \") {\n event.preventDefault();\n }\n\n const focusables = getFocusableElements(currentTarget, programmatic);\n const activeElement = focusables[currentFocusIndex.current];\n if (!activeElement || isElementDisabled(activeElement)) {\n return;\n }\n\n activeElement.click();\n return;\n }\n\n const {\n incrementKeys,\n decrementKeys,\n jumpToFirstKeys,\n jumpToLastKeys,\n } = config.current;\n\n if (searchable && isSearchableEvent(event)) {\n event.preventDefault();\n event.stopPropagation();\n focusFromKey({ key, reversed: shiftKey });\n return;\n }\n\n if (trackTabKeys && key === \"Tab\") {\n currentFocusIndex.current = getNextFocusableIndex({\n loopable,\n increment: !event.shiftKey,\n focusables: getFocusableElements(currentTarget, programmatic),\n includeDisabled,\n currentFocusIndex: currentFocusIndex.current,\n });\n return;\n }\n\n const jumpToFirst = jumpToFirstKeys.includes(key);\n const jumpToLast = !jumpToFirst && jumpToLastKeys.includes(key);\n const increment =\n !jumpToFirst && !jumpToLast && incrementKeys.includes(key);\n const decrement =\n !jumpToFirst &&\n !jumpToLast &&\n !increment &&\n decrementKeys.includes(key);\n\n if (jumpToFirst || jumpToLast || increment || decrement) {\n event.preventDefault();\n event.stopPropagation();\n }\n\n if (jumpToFirst) {\n focusFirst();\n } else if (jumpToLast) {\n focusLast();\n } else if (increment) {\n focusNext();\n } else if (decrement) {\n focusPrevious();\n }\n },\n },\n movementContext,\n currentFocusIndex,\n activeDescendantId,\n setActiveDescendantId,\n };\n}\n"],"names":["createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","getFocusableElements","defaultGetFocusableElements","useUserInteractionMode","useDir","useEnsuredRef","useIsomorphicLayoutEffect","DEFAULT_KEYBOARD_MOVEMENT","DEFAULT_LTR_KEYBOARD_MOVEMENT","DEFAULT_RTL_KEYBOARD_MOVEMENT","findMatchIndex","getFirstFocusableIndex","getLastFocusableIndex","getNextFocusableIndex","getSearchText","getVirtualFocusDefaultIndex","isElementDisabled","isNotFocusable","isSearchableEvent","recalculateFocusIndex","noop","DEFAULT_KEYBOARD_MOVEMENT_CONTEXT","config","current","loopable","searchable","horizontal","includeDisabled","tabIndexBehavior","undefined","activeDescendantId","focusFirst","focusLast","focusNext","focusPrevious","focusFromKey","focusCurrent","updateFocusIndex","context","displayName","Provider","KeyboardMovementProvider","useKeyboardMovementContext","returnNegative1","useKeyboardMovementProvider","options","ref","propRef","onClick","onFocus","onKeyDown","disabled","trackTabKeys","extendKeyDown","onFocusChange","programmatic","incrementKeys","propIncrementKeys","decrementKeys","propDecrementKeys","jumpToFirstKeys","propJumpToFirstKeys","jumpToLastKeys","propJumpToLastKeys","getDefaultFocusedIndex","isNegativeOneAllowed","nodeRef","nodeRefCallback","isRTL","dir","defaults","configuration","mode","refocus","currentFocusIndex","setActiveDescendantId","process","env","NODE_ENV","tabIndex","getFocusableElementsFromRef","container","focusables","index","focused","scrollIntoView","block","inline","id","focus","force","isSameIndex","element","increment","key","reversed","value","values","map","startIndex","movementContext","movementProps","event","currentTarget","target","HTMLElement","focusedIndex","findIndex","contains","length","isPropagationStopped","defaultFocusIndex","setFocusIndex","preventDefault","stopPropagation","shiftKey","activeElement","click","jumpToFirst","includes","jumpToLast","decrement"],"mappings":"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"}
|