@react-md/core 6.4.0 → 6.5.1
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/_a11y.scss +3 -1
- package/dist/_box-shadows.scss +20 -12
- package/dist/_core.scss +1 -1
- package/dist/_utils.scss +26 -11
- package/dist/app-bar/_app-bar.scss +3 -3
- package/dist/autocomplete/AutocompleteChip.js +2 -2
- package/dist/autocomplete/AutocompleteChip.js.map +1 -1
- package/dist/autocomplete/AutocompleteListboxChildren.js +1 -1
- package/dist/autocomplete/AutocompleteListboxChildren.js.map +1 -1
- package/dist/autocomplete/_autocomplete.scss +20 -16
- package/dist/autocomplete/useAutocomplete.js +4 -4
- package/dist/autocomplete/useAutocomplete.js.map +1 -1
- package/dist/autocomplete/utils.js +3 -3
- package/dist/autocomplete/utils.js.map +1 -1
- package/dist/avatar/_avatar.scss +2 -1
- package/dist/box/styles.js +2 -2
- package/dist/box/styles.js.map +1 -1
- package/dist/button/AsyncButton.js +1 -1
- package/dist/button/AsyncButton.js.map +1 -1
- package/dist/button/_button.scss +9 -5
- package/dist/card/_card.scss +6 -6
- package/dist/chip/Chip.js +1 -1
- package/dist/chip/Chip.js.map +1 -1
- package/dist/chip/_chip.scss +6 -6
- package/dist/cssUtils.d.ts +11 -6
- package/dist/cssUtils.js.map +1 -1
- package/dist/datetime/useTimeField.js +1 -1
- package/dist/datetime/useTimeField.js.map +1 -1
- package/dist/delegateEvent.js +9 -9
- package/dist/delegateEvent.js.map +1 -1
- package/dist/dialog/_dialog.scss +6 -6
- package/dist/divider/_divider.scss +6 -2
- package/dist/draggable/useDraggable.js +4 -4
- package/dist/draggable/useDraggable.js.map +1 -1
- package/dist/draggable/utils.js +1 -1
- package/dist/draggable/utils.js.map +1 -1
- package/dist/expansion-panel/ExpansionPanel.js +1 -1
- package/dist/expansion-panel/ExpansionPanel.js.map +1 -1
- package/dist/expansion-panel/useExpansionPanels.js +1 -1
- package/dist/expansion-panel/useExpansionPanels.js.map +1 -1
- package/dist/files/FileInput.js +1 -1
- package/dist/files/FileInput.js.map +1 -1
- package/dist/files/createAcceptFromExtensions.d.ts +5 -0
- package/dist/files/createAcceptFromExtensions.js +15 -0
- package/dist/files/createAcceptFromExtensions.js.map +1 -0
- package/dist/files/useFileUpload.js +45 -41
- package/dist/files/useFileUpload.js.map +1 -1
- package/dist/files/utils.js +14 -10
- package/dist/files/utils.js.map +1 -1
- package/dist/files/validation.js +7 -8
- package/dist/files/validation.js.map +1 -1
- package/dist/focus/useFocusContainer.js +1 -1
- package/dist/focus/useFocusContainer.js.map +1 -1
- package/dist/focus/utils.js +12 -7
- package/dist/focus/utils.js.map +1 -1
- package/dist/form/InputToggleIcon.js +5 -1
- package/dist/form/InputToggleIcon.js.map +1 -1
- package/dist/form/NativeSelect.js +1 -1
- package/dist/form/NativeSelect.js.map +1 -1
- package/dist/form/Select.d.ts +24 -0
- package/dist/form/Select.js +19 -8
- package/dist/form/Select.js.map +1 -1
- package/dist/form/SelectedOption.d.ts +1 -2
- package/dist/form/SelectedOption.js +2 -2
- package/dist/form/SelectedOption.js.map +1 -1
- package/dist/form/_input-toggle.scss +6 -5
- package/dist/form/_label.scss +2 -2
- package/dist/form/_legend.scss +22 -13
- package/dist/form/_slider.scss +7 -5
- package/dist/form/_switch.scss +7 -5
- package/dist/form/_text-field.scss +13 -11
- package/dist/form/formConfig.js +1 -1
- package/dist/form/formConfig.js.map +1 -1
- package/dist/form/inputToggleStyles.js +7 -1
- package/dist/form/inputToggleStyles.js.map +1 -1
- package/dist/form/legendStyles.d.ts +1 -1
- package/dist/form/legendStyles.js.map +1 -1
- package/dist/form/selectUtils.js +2 -2
- package/dist/form/selectUtils.js.map +1 -1
- package/dist/form/useCombobox.js +1 -0
- package/dist/form/useCombobox.js.map +1 -1
- package/dist/form/useFormReset.js +2 -2
- package/dist/form/useFormReset.js.map +1 -1
- package/dist/form/useNumberField.js +1 -1
- package/dist/form/useNumberField.js.map +1 -1
- package/dist/form/useResizingTextArea.js +4 -4
- package/dist/form/useResizingTextArea.js.map +1 -1
- package/dist/form/useSelectCombobox.js +1 -1
- package/dist/form/useSelectCombobox.js.map +1 -1
- package/dist/form/validation.js +1 -1
- package/dist/form/validation.js.map +1 -1
- package/dist/hoverMode/useHoverMode.js +8 -8
- package/dist/hoverMode/useHoverMode.js.map +1 -1
- package/dist/hoverMode/useHoverModeProvider.js +3 -3
- package/dist/hoverMode/useHoverModeProvider.js.map +1 -1
- package/dist/icon/config.js +3 -3
- package/dist/icon/config.js.map +1 -1
- package/dist/icon/materialConfig.js +1 -1
- package/dist/icon/materialConfig.js.map +1 -1
- package/dist/interaction/UserInteractionModeProvider.js +11 -10
- package/dist/interaction/UserInteractionModeProvider.js.map +1 -1
- package/dist/interaction/_interaction.scss +5 -3
- package/dist/interaction/utils.js +7 -3
- package/dist/interaction/utils.js.map +1 -1
- package/dist/layout/useExpandableLayout.js +3 -4
- package/dist/layout/useExpandableLayout.js.map +1 -1
- package/dist/layout/useMainTabIndex.js +1 -1
- package/dist/layout/useMainTabIndex.js.map +1 -1
- package/dist/list/ListItem.js +1 -1
- package/dist/list/ListItem.js.map +1 -1
- package/dist/media-queries/AppSizeProvider.js +1 -1
- package/dist/media-queries/AppSizeProvider.js.map +1 -1
- package/dist/media-queries/config.js +2 -2
- package/dist/media-queries/config.js.map +1 -1
- package/dist/media-queries/useMediaQuery.js +3 -3
- package/dist/media-queries/useMediaQuery.js.map +1 -1
- package/dist/menu/Menu.js +4 -4
- package/dist/menu/Menu.js.map +1 -1
- package/dist/menu/MenuItemButton.js +1 -1
- package/dist/menu/MenuItemButton.js.map +1 -1
- package/dist/menu/MenuItemFileInput.js +1 -1
- package/dist/menu/MenuItemFileInput.js.map +1 -1
- package/dist/menu/MenuWidget.js +2 -2
- package/dist/menu/MenuWidget.js.map +1 -1
- package/dist/movement/findMatchIndex.js +2 -2
- package/dist/movement/findMatchIndex.js.map +1 -1
- package/dist/movement/useKeyboardMovementProvider.js +2 -2
- package/dist/movement/useKeyboardMovementProvider.js.map +1 -1
- package/dist/movement/utils.js +12 -10
- package/dist/movement/utils.js.map +1 -1
- package/dist/navigation/getTableOfContentsHeadings.js +4 -3
- package/dist/navigation/getTableOfContentsHeadings.js.map +1 -1
- package/dist/navigation/useActiveHeadingId.js +9 -9
- package/dist/navigation/useActiveHeadingId.js.map +1 -1
- package/dist/navigation/useTableOfContentsHeadings.js +1 -1
- package/dist/navigation/useTableOfContentsHeadings.js.map +1 -1
- package/dist/navigation/utils.js +6 -5
- package/dist/navigation/utils.js.map +1 -1
- package/dist/portal/PortalContainerProvider.js +5 -3
- package/dist/portal/PortalContainerProvider.js.map +1 -1
- package/dist/positioning/getFixedPosition.js +2 -4
- package/dist/positioning/getFixedPosition.js.map +1 -1
- package/dist/positioning/useFixedPositioning.js +2 -2
- package/dist/positioning/useFixedPositioning.js.map +1 -1
- package/dist/positioning/utils.js +3 -3
- package/dist/positioning/utils.js.map +1 -1
- package/dist/scroll/getScrollbarWidth.js +4 -4
- package/dist/scroll/getScrollbarWidth.js.map +1 -1
- package/dist/searching/fuzzy.js +3 -2
- package/dist/searching/fuzzy.js.map +1 -1
- package/dist/searching/toSearchQuery.js +1 -1
- package/dist/searching/toSearchQuery.js.map +1 -1
- package/dist/searching/utils.js +1 -1
- package/dist/searching/utils.js.map +1 -1
- package/dist/snackbar/Toast.js +1 -1
- package/dist/snackbar/Toast.js.map +1 -1
- package/dist/snackbar/ToastContent.js +2 -2
- package/dist/snackbar/ToastContent.js.map +1 -1
- package/dist/snackbar/ToastManager.d.ts +1 -1
- package/dist/snackbar/ToastManager.js +11 -11
- package/dist/snackbar/ToastManager.js.map +1 -1
- package/dist/snackbar/_snackbar.scss +3 -3
- package/dist/spinbutton/useSpinButton.js +1 -1
- package/dist/spinbutton/useSpinButton.js.map +1 -1
- package/dist/spinbutton/utils/deselectNode.js +1 -1
- package/dist/spinbutton/utils/deselectNode.js.map +1 -1
- package/dist/spinbutton/utils/resolveInputEvent.js +1 -1
- package/dist/spinbutton/utils/resolveInputEvent.js.map +1 -1
- package/dist/spinbutton/utils/selectNode.js +1 -1
- package/dist/spinbutton/utils/selectNode.js.map +1 -1
- package/dist/storage/useStorage.js +8 -3
- package/dist/storage/useStorage.js.map +1 -1
- package/dist/table/useStickyTableSection.js +1 -1
- package/dist/table/useStickyTableSection.js.map +1 -1
- package/dist/tabs/TabList.js +2 -2
- package/dist/tabs/TabList.js.map +1 -1
- package/dist/tabs/_tabs.scss +5 -6
- package/dist/tabs/useMaxTabPanelHeight.js +4 -3
- package/dist/tabs/useMaxTabPanelHeight.js.map +1 -1
- package/dist/tabs/useTabList.js +1 -1
- package/dist/tabs/useTabList.js.map +1 -1
- package/dist/test-utils/jest-globals/match-media.d.ts +1 -1
- package/dist/test-utils/jest-globals/match-media.js +1 -1
- package/dist/test-utils/jest-globals/match-media.js.map +1 -1
- package/dist/test-utils/jest-globals/timers.js +1 -1
- package/dist/test-utils/jest-globals/timers.js.map +1 -1
- package/dist/test-utils/jest-globals/uploadMenuItemFileInput.js +1 -1
- package/dist/test-utils/jest-globals/uploadMenuItemFileInput.js.map +1 -1
- package/dist/test-utils/mocks/ResizeObserver.js +2 -2
- package/dist/test-utils/mocks/ResizeObserver.js.map +1 -1
- package/dist/test-utils/polyfills/IntersectionObserver.js +2 -2
- package/dist/test-utils/polyfills/IntersectionObserver.js.map +1 -1
- package/dist/test-utils/polyfills/ResizeObserver.js +2 -2
- package/dist/test-utils/polyfills/ResizeObserver.js.map +1 -1
- package/dist/test-utils/polyfills/TextDecoder.js +2 -2
- package/dist/test-utils/polyfills/TextDecoder.js.map +1 -1
- package/dist/test-utils/polyfills/TextEncoder.js +2 -2
- package/dist/test-utils/polyfills/TextEncoder.js.map +1 -1
- package/dist/test-utils/polyfills/matchMedia.js +2 -2
- package/dist/test-utils/polyfills/matchMedia.js.map +1 -1
- package/dist/test-utils/polyfills/offsetParent.js +2 -2
- package/dist/test-utils/polyfills/offsetParent.js.map +1 -1
- package/dist/test-utils/polyfills/scrollIntoView.js +1 -1
- package/dist/test-utils/polyfills/scrollIntoView.js.map +1 -1
- package/dist/test-utils/queries/select.js +2 -2
- package/dist/test-utils/queries/select.js.map +1 -1
- package/dist/test-utils/queries/slider.js +1 -1
- package/dist/test-utils/queries/slider.js.map +1 -1
- package/dist/test-utils/utils/createFileList.js +2 -0
- package/dist/test-utils/utils/createFileList.js.map +1 -1
- package/dist/test-utils/utils/createMatchMediaSpy.d.ts +1 -1
- package/dist/test-utils/utils/createMatchMediaSpy.js +3 -3
- package/dist/test-utils/utils/createMatchMediaSpy.js.map +1 -1
- package/dist/test-utils/vitest/match-media.d.ts +1 -1
- package/dist/test-utils/vitest/match-media.js +1 -1
- package/dist/test-utils/vitest/match-media.js.map +1 -1
- package/dist/test-utils/vitest/timers.js +1 -1
- package/dist/test-utils/vitest/timers.js.map +1 -1
- package/dist/test-utils/vitest/uploadMenuItemFileInput.js +1 -1
- package/dist/test-utils/vitest/uploadMenuItemFileInput.js.map +1 -1
- package/dist/theme/ThemeProvider.js +2 -2
- package/dist/theme/ThemeProvider.js.map +1 -1
- package/dist/theme/_a11y.scss +3 -1
- package/dist/theme/_theme.scss +16 -12
- package/dist/theme/getDerivedTheme.js +1 -1
- package/dist/theme/getDerivedTheme.js.map +1 -1
- package/dist/theme/useCSSVariables.js +5 -5
- package/dist/theme/useCSSVariables.js.map +1 -1
- package/dist/theme/useColorSchemeMetaTag.js +2 -2
- package/dist/theme/useColorSchemeMetaTag.js.map +1 -1
- package/dist/theme/useInlineCSSVariables.js +4 -3
- package/dist/theme/useInlineCSSVariables.js.map +1 -1
- package/dist/theme/utils.js +8 -8
- package/dist/theme/utils.js.map +1 -1
- package/dist/tooltip/useTooltip.js +7 -7
- package/dist/tooltip/useTooltip.js.map +1 -1
- package/dist/tooltip/useTooltipPosition.js +1 -1
- package/dist/tooltip/useTooltipPosition.js.map +1 -1
- package/dist/transition/useCarousel.js +2 -2
- package/dist/transition/useCarousel.js.map +1 -1
- package/dist/transition/useCollapseTransition.js +1 -1
- package/dist/transition/useCollapseTransition.js.map +1 -1
- package/dist/transition/useSkeletonPlaceholder.js +4 -4
- package/dist/transition/useSkeletonPlaceholder.js.map +1 -1
- package/dist/transition/useTransition.js +2 -2
- package/dist/transition/useTransition.js.map +1 -1
- package/dist/transition/utils.js +5 -5
- package/dist/transition/utils.js.map +1 -1
- package/dist/tree/TreeItem.js +1 -1
- package/dist/tree/TreeItem.js.map +1 -1
- package/dist/tree/useTreeItems.js +7 -5
- package/dist/tree/useTreeItems.js.map +1 -1
- package/dist/tree/useTreeMovement.js +1 -1
- package/dist/tree/useTreeMovement.js.map +1 -1
- package/dist/tree/utils.js +6 -9
- package/dist/tree/utils.js.map +1 -1
- package/dist/typography/HighlightText.js +2 -1
- package/dist/typography/HighlightText.js.map +1 -1
- package/dist/typography/SrOnly.js +7 -1
- package/dist/typography/SrOnly.js.map +1 -1
- package/dist/useDebouncedFunction.js +4 -4
- package/dist/useDebouncedFunction.js.map +1 -1
- package/dist/useDropzone.js +9 -9
- package/dist/useDropzone.js.map +1 -1
- package/dist/useEnsuredState.js +5 -5
- package/dist/useEnsuredState.js.map +1 -1
- package/dist/useIntersectionObserver.js +3 -3
- package/dist/useIntersectionObserver.js.map +1 -1
- package/dist/useIsomorphicLayoutEffect.js +1 -1
- package/dist/useIsomorphicLayoutEffect.js.map +1 -1
- package/dist/useOrientation.js +1 -1
- package/dist/useOrientation.js.map +1 -1
- package/dist/useReadonlySet.js +1 -1
- package/dist/useReadonlySet.js.map +1 -1
- package/dist/useResizeListener.js +2 -2
- package/dist/useResizeListener.js.map +1 -1
- package/dist/useResizeObserver.js +3 -4
- package/dist/useResizeObserver.js.map +1 -1
- package/dist/useThrottledFunction.js +3 -3
- package/dist/useThrottledFunction.js.map +1 -1
- package/dist/useWindowSize.js +1 -1
- package/dist/useWindowSize.js.map +1 -1
- package/dist/utils/alphaNumericSort.js +3 -1
- package/dist/utils/alphaNumericSort.js.map +1 -1
- package/dist/utils/bem.js +9 -12
- package/dist/utils/bem.js.map +1 -1
- package/dist/utils/getNumberOfDigits.js +1 -0
- package/dist/utils/getNumberOfDigits.js.map +1 -1
- package/dist/utils/getRangeDefaultValue.js +1 -1
- package/dist/utils/getRangeDefaultValue.js.map +1 -1
- package/dist/utils/nearest.js +2 -2
- package/dist/utils/nearest.js.map +1 -1
- package/dist/utils/parseCssLengthUnit.js +3 -3
- package/dist/utils/parseCssLengthUnit.js.map +1 -1
- package/dist/utils/trigonometry.js +1 -1
- package/dist/utils/trigonometry.js.map +1 -1
- package/dist/window-splitter/_window-splitter.scss +15 -17
- package/package.json +9 -7
- package/src/autocomplete/AutocompleteChip.tsx +2 -2
- package/src/autocomplete/AutocompleteListboxChildren.tsx +1 -1
- package/src/autocomplete/useAutocomplete.ts +4 -4
- package/src/autocomplete/utils.ts +3 -3
- package/src/box/styles.ts +2 -2
- package/src/button/AsyncButton.tsx +1 -3
- package/src/chip/Chip.tsx +1 -2
- package/src/cssUtils.ts +12 -6
- package/src/datetime/useTimeField.ts +1 -1
- package/src/delegateEvent.ts +9 -9
- package/src/draggable/useDraggable.ts +4 -4
- package/src/draggable/utils.ts +1 -1
- package/src/expansion-panel/ExpansionPanel.tsx +1 -1
- package/src/expansion-panel/useExpansionPanels.ts +1 -1
- package/src/files/FileInput.tsx +1 -1
- package/src/files/createAcceptFromExtensions.ts +18 -0
- package/src/files/useFileUpload.ts +36 -37
- package/src/files/utils.ts +15 -11
- package/src/files/validation.ts +7 -9
- package/src/focus/useFocusContainer.ts +1 -1
- package/src/focus/utils.ts +11 -6
- package/src/form/InputToggleIcon.tsx +5 -5
- package/src/form/NativeSelect.tsx +1 -1
- package/src/form/Select.tsx +58 -7
- package/src/form/SelectedOption.tsx +2 -4
- package/src/form/formConfig.ts +1 -1
- package/src/form/inputToggleStyles.ts +9 -4
- package/src/form/legendStyles.ts +1 -1
- package/src/form/selectUtils.ts +2 -2
- package/src/form/useCombobox.ts +1 -0
- package/src/form/useFormReset.ts +2 -2
- package/src/form/useNumberField.ts +1 -1
- package/src/form/useResizingTextArea.ts +5 -5
- package/src/form/useSelectCombobox.ts +1 -4
- package/src/form/validation.ts +1 -1
- package/src/hoverMode/useHoverMode.ts +9 -9
- package/src/hoverMode/useHoverModeProvider.ts +4 -4
- package/src/icon/config.tsx +3 -3
- package/src/icon/materialConfig.ts +1 -1
- package/src/interaction/UserInteractionModeProvider.tsx +11 -10
- package/src/interaction/utils.ts +3 -3
- package/src/layout/useExpandableLayout.ts +3 -4
- package/src/layout/useMainTabIndex.ts +1 -1
- package/src/list/ListItem.tsx +1 -1
- package/src/media-queries/AppSizeProvider.tsx +1 -1
- package/src/media-queries/config.ts +2 -2
- package/src/media-queries/useMediaQuery.ts +3 -3
- package/src/menu/Menu.tsx +4 -4
- package/src/menu/MenuItemButton.tsx +1 -1
- package/src/menu/MenuItemFileInput.tsx +1 -1
- package/src/menu/MenuWidget.tsx +6 -4
- package/src/movement/findMatchIndex.ts +2 -2
- package/src/movement/useKeyboardMovementProvider.ts +2 -2
- package/src/movement/utils.ts +15 -14
- package/src/navigation/getTableOfContentsHeadings.ts +4 -3
- package/src/navigation/useActiveHeadingId.ts +8 -8
- package/src/navigation/useTableOfContentsHeadings.ts +1 -1
- package/src/navigation/utils.ts +6 -5
- package/src/portal/PortalContainerProvider.tsx +5 -3
- package/src/positioning/getFixedPosition.ts +9 -6
- package/src/positioning/useFixedPositioning.ts +2 -2
- package/src/positioning/utils.ts +3 -3
- package/src/scroll/getScrollbarWidth.ts +4 -4
- package/src/searching/fuzzy.ts +7 -3
- package/src/searching/toSearchQuery.ts +1 -1
- package/src/searching/utils.ts +1 -1
- package/src/snackbar/Toast.tsx +1 -1
- package/src/snackbar/ToastContent.tsx +2 -2
- package/src/snackbar/ToastManager.ts +11 -12
- package/src/spinbutton/useSpinButton.ts +1 -1
- package/src/spinbutton/utils/deselectNode.ts +1 -1
- package/src/spinbutton/utils/resolveInputEvent.ts +1 -1
- package/src/spinbutton/utils/selectNode.ts +1 -1
- package/src/storage/useStorage.ts +7 -2
- package/src/table/useStickyTableSection.tsx +1 -1
- package/src/tabs/TabList.tsx +2 -2
- package/src/tabs/useMaxTabPanelHeight.ts +6 -3
- package/src/tabs/useTabList.ts +2 -2
- package/src/test-utils/jest-globals/match-media.ts +5 -2
- package/src/test-utils/jest-globals/timers.ts +1 -1
- package/src/test-utils/jest-globals/uploadMenuItemFileInput.ts +1 -1
- package/src/test-utils/mocks/ResizeObserver.ts +2 -2
- package/src/test-utils/polyfills/IntersectionObserver.ts +2 -2
- package/src/test-utils/polyfills/ResizeObserver.ts +2 -2
- package/src/test-utils/polyfills/TextDecoder.ts +2 -2
- package/src/test-utils/polyfills/TextEncoder.ts +2 -2
- package/src/test-utils/polyfills/matchMedia.ts +5 -2
- package/src/test-utils/polyfills/offsetParent.ts +2 -2
- package/src/test-utils/polyfills/scrollIntoView.ts +1 -1
- package/src/test-utils/queries/select.ts +2 -2
- package/src/test-utils/queries/slider.ts +1 -1
- package/src/test-utils/utils/createFileList.ts +2 -0
- package/src/test-utils/utils/createMatchMediaSpy.ts +4 -4
- package/src/test-utils/vitest/match-media.ts +2 -2
- package/src/test-utils/vitest/timers.ts +1 -1
- package/src/test-utils/vitest/uploadMenuItemFileInput.ts +1 -1
- package/src/theme/ThemeProvider.tsx +2 -2
- package/src/theme/getDerivedTheme.ts +1 -1
- package/src/theme/useCSSVariables.ts +5 -5
- package/src/theme/useColorSchemeMetaTag.ts +2 -2
- package/src/theme/useInlineCSSVariables.ts +6 -7
- package/src/theme/utils.ts +8 -8
- package/src/tooltip/useTooltip.ts +7 -7
- package/src/tooltip/useTooltipPosition.ts +1 -1
- package/src/transition/useCarousel.ts +2 -2
- package/src/transition/useCollapseTransition.ts +1 -1
- package/src/transition/useSkeletonPlaceholder.ts +4 -4
- package/src/transition/useTransition.ts +2 -2
- package/src/transition/utils.ts +5 -5
- package/src/tree/TreeItem.tsx +1 -1
- package/src/tree/useTreeItems.ts +5 -5
- package/src/tree/useTreeMovement.ts +1 -1
- package/src/tree/utils.ts +9 -9
- package/src/typography/HighlightText.tsx +4 -3
- package/src/typography/SrOnly.tsx +9 -2
- package/src/useDebouncedFunction.ts +5 -5
- package/src/useDropzone.ts +10 -10
- package/src/useEnsuredState.ts +5 -5
- package/src/useIntersectionObserver.ts +3 -3
- package/src/useIsomorphicLayoutEffect.ts +3 -3
- package/src/useOrientation.ts +1 -1
- package/src/useReadonlySet.ts +3 -1
- package/src/useResizeListener.ts +2 -2
- package/src/useResizeObserver.ts +3 -4
- package/src/useThrottledFunction.ts +4 -4
- package/src/useWindowSize.ts +1 -1
- package/src/utils/alphaNumericSort.ts +1 -1
- package/src/utils/bem.ts +15 -16
- package/src/utils/getNumberOfDigits.ts +1 -0
- package/src/utils/getRangeDefaultValue.ts +1 -1
- package/src/utils/nearest.ts +5 -2
- package/src/utils/parseCssLengthUnit.ts +5 -4
- package/src/utils/trigonometry.ts +1 -1
|
@@ -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 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":"AAAA;AAEA,SACEA,aAAa,EACbC,WAAW,EACXC,UAAU,EACVC,SAAS,EACTC,OAAO,EACPC,MAAM,EACNC,QAAQ,QACH,QAAQ;AAEf,SAASC,wBAAwBC,2BAA2B,QAAQ,oBAAoB;AACxF,SAASC,sBAAsB,QAAQ,gDAAgD;AACvF,SAASC,MAAM,QAAQ,4CAA4C;AACnE,SAASC,aAAa,QAAQ,sBAAsB;AACpD,SAASC,yBAAyB,QAAQ,kCAAkC;AAC5E,SACEC,yBAAyB,EACzBC,6BAA6B,EAC7BC,6BAA6B,QACxB,iBAAiB;AACxB,SAASC,cAAc,QAAQ,sBAAsB;AAUrD,SACEC,sBAAsB,EACtBC,qBAAqB,EACrBC,qBAAqB,EACrBC,aAAa,EACbC,2BAA2B,EAC3BC,iBAAiB,EACjBC,cAAc,EACdC,iBAAiB,EACjBC,qBAAqB,QAChB,aAAa;AAEpB,MAAMC,OAAO;AACX,aAAa;AACf;AAEA;;CAEC,GACD,OAAO,MAAMC,oCACX;IACEC,QAAQ;QAAEC,SAAShB;IAA0B;IAC7CiB,UAAU;IACVC,YAAY;IACZC,YAAY;IACZC,iBAAiB;IACjBC,kBAAkBC;IAClBC,oBAAoB;IACpBC,YAAYX;IACZY,WAAWZ;IACXa,WAAWb;IACXc,eAAed;IACfe,cAAcf;IACdgB,cAAc,KAAkB;IAChCC,kBAAkBjB;AACpB,EAAE;AAEJ;;;CAGC,GACD,MAAMkB,UAAU5C,cACd2B;AAEFiB,QAAQC,WAAW,GAAG;AACtB,OAAO,MAAM,EAAEC,UAAUC,wBAAwB,EAAE,GAAGH,QAAQ;AAE9D;;;CAGC,GACD,OAAO,SAASI;IACd,OAAO9C,WAAW0C;AACpB;AAEA,MAAMK,kBAAkB,IAAc,CAAC;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwHC,GACD,OAAO,SAASC,4BACdC,UAA8C,CAAC,CAAC;IAEhD,MAAM,EACJC,KAAKC,OAAO,EACZC,UAAU5B,IAAI,EACd6B,UAAU7B,IAAI,EACd8B,YAAY9B,IAAI,EAChBI,WAAW,KAAK,EAChB2B,QAAQ,EACR1B,aAAa,KAAK,EAClBC,aAAa,KAAK,EAClB0B,eAAe,KAAK,EACpBzB,kBAAkB,KAAK,EACvBC,gBAAgB,EAChByB,gBAAgBjC,IAAI,EACpBkC,gBAAgBlC,IAAI,EACpBmC,eAAe5B,eAAe,EAC9B6B,eAAeC,iBAAiB,EAChCC,eAAeC,iBAAiB,EAChCC,iBAAiBC,mBAAmB,EACpCC,gBAAgBC,kBAAkB,EAClC9D,uBAAuBC,2BAA2B,EAClD8D,yBAAyBrB,eAAe,EACxCsB,uBAAuB,KAAK,EAC7B,GAAGpB;IAEJ,MAAM,CAACqB,SAASC,gBAAgB,GAAG9D,cAAc0C;IAEjD,MAAMqB,QAAQhE,SAASiE,GAAG,KAAK;IAC/B,IAAIC;IACJ,IAAI5C,YAAY;QACd4C,WAAWF,QACP3D,gCACAD;IACN,OAAO;QACL8D,WAAW/D;IACb;IAEA,MAAMiD,gBAAgBC,qBAAqBa,SAASd,aAAa;IACjE,MAAME,gBAAgBC,qBAAqBW,SAASZ,aAAa;IACjE,MAAME,kBAAkBC,uBAAuBS,SAASV,eAAe;IACvE,MAAME,iBAAiBC,sBAAsBO,SAASR,cAAc;IAEpE,MAAMS,gBAAwC;QAC5Cf;QACAE;QACAE;QACAE;IACF;IACA,MAAMxC,SAASvB,OAAOwE;IACtBjE,0BAA0B;QACxBgB,OAAOC,OAAO,GAAGgD;IACnB;IAEA,MAAMC,OAAOrE;IACb,MAAMsE,UAAU1E,OAAO;IACvB,MAAM2E,oBAAoB3E,OAAO,CAAC;IAClC,MAAM,CAAC+B,oBAAoB6C,sBAAsB,GAAG3E,SAAS;IAE7D,IAAI4E,QAAQC,GAAG,CAACC,QAAQ,KAAK,cAAc;QACzC,sEAAsE;QACtE,sDAAsD;QACtDjF,UAAU;YACR,OAAO;gBACL8E,sBAAsB;YACxB;QACF,GAAG,EAAE;IACP;IAEA,IAAII;IACJ,IAAInD,kBAAkB;QACpBmD,WACE5B,YAAavB,qBAAqB,YAAYE,qBAC1C,CAAC,IACD;IACR;IAEA,MAAMkD,8BAA8BrF,YAAY;QAC9C,MAAMsF,YAAYf,QAAQ3C,OAAO;QACjC,IAAI,CAAC0D,WAAW;YACd,OAAO,EAAE;QACX;QAEA,OAAOhF,qBAAqBgF,WAAW1B;IACzC,GAAG;QAACtD;QAAsBiE;QAASX;KAAa;IAChD,MAAMnB,eAAezC,YACnB,CAACuF,aAAaF,6BAA6B;QACzC,MAAMG,QAAQT,kBAAkBnD,OAAO;QACvC,IAAI4D,UAAU,CAAC,GAAG;YAChB;QACF;QAEA,MAAMC,UAAUF,UAAU,CAACC,MAAM;QACjC,IAAI,CAACC,SAAS;YACZ;QACF;QAEA,IAAIxD,kBAAkB;YACpBwD,QAAQC,cAAc,CAAC;gBACrBC,OAAO;gBACPC,QAAQ;YACV;YACAZ,sBAAsBS,QAAQI,EAAE;QAClC;QAEA,IAAI5D,qBAAqB,WAAW;YAClCwD,QAAQK,KAAK;QACf;QAEA,OAAOL;IACT,GACA;QAACJ;QAA6BpD;KAAiB;IAEjD,MAAMS,mBAAmB1C,YACvB,CAACkD;QACC,MAAM,EACJsC,KAAK,EACLO,KAAK,EACLR,aAAaF,6BAA6B,EAC3C,GAAGnC;QACJ,MAAM8C,cAAcjB,kBAAkBnD,OAAO,KAAK4D;QAClD,IAAI,AAAC,CAACO,SAASC,eAAgBR,UAAU,CAAC,GAAG;YAC3C;QACF;QAEAT,kBAAkBnD,OAAO,GAAG4D;QAC5B,MAAMC,UAAUhD,aAAa8C;QAC7B,IAAIE,WAAW,CAACO,aAAa;YAC3BrC,cAAc;gBACZ6B;gBACAS,SAASR;YACX;QACF;IACF,GACA;QAAChD;QAAc4C;QAA6B1B;KAAc;IAG5D,MAAMrB,YAAYtC,YAChB,CAACuF,aAAaF,6BAA6B,EAAEU,QAAQ,KAAK;QACxDrD,iBAAiB;YACf8C,OAAOtE,sBAAsB;gBAC3BW;gBACAqE,WAAW;gBACXX;gBACAvD,iBAAiB;gBACjB+C,mBAAmBA,kBAAkBnD,OAAO;YAC9C;YACAmE;YACAR;QACF;IACF,GACA;QAACF;QAA6BxD;QAAUa;KAAiB;IAE3D,MAAMH,gBAAgBvC,YACpB,CAACuF,aAAaF,6BAA6B,EAAEU,QAAQ,KAAK;QACxDrD,iBAAiB;YACf8C,OAAOtE,sBAAsB;gBAC3BW;gBACAqE,WAAW;gBACXX;gBACAvD,iBAAiB;gBACjB+C,mBAAmBA,kBAAkBnD,OAAO;YAC9C;YACAmE;YACAR;QACF;IACF,GACA;QAACF;QAA6BxD;QAAUa;KAAiB;IAE3D,MAAMN,aAAapC,YACjB,CAACuF,aAAaF,6BAA6B,EAAEU,QAAQ,KAAK;QACxDrD,iBAAiB;YACf8C,OAAOxE,uBAAuB;gBAC5BuE;gBACAvD;YACF;YACA+D;YACAR;QACF;IACF,GACA;QAACF;QAA6BrD;QAAiBU;KAAiB;IAElE,MAAML,YAAYrC,YAChB,CAACuF,aAAaF,6BAA6B,EAAEU,QAAQ,KAAK;QACxDrD,iBAAiB;YACf8C,OAAOvE,sBAAsB;gBAC3BsE;gBACAvD;YACF;YACA+D;YACAR;QACF;IACF,GACA;QAACF;QAA6BrD;QAAiBU;KAAiB;IAElE,MAAMF,eAAexC,YACnB,CAACkD;QACC,MAAM,EACJiD,GAAG,EACHJ,KAAK,EACLK,QAAQ,EACRb,aAAaF,6BAA6B,EAC3C,GAAGnC;QACJ,IAAI,CAACpB,YAAY;YACf;QACF;QAEA,MAAM0D,QAAQzE,eAAe;YAC3BsF,OAAOF;YACPG,QAAQf,WAAWgB,GAAG,CAAC,CAACN,UACtB9E,cAAc8E,SAAS,CAAC3E,eAAe2E,SAASjE;YAElDwE,YAAYJ,WAAW,CAAC,IAAIrB,kBAAkBnD,OAAO;QACvD;QACAc,iBAAiB;YAAE8C;YAAOO;YAAOR;QAAW;IAC9C,GACA;QAACF;QAA6BrD;QAAiBF;QAAYY;KAAiB;IAG9E,MAAM+D,kBAAkBtG,QACtB,IAAO,CAAA;YACLwB;YACAE;YACAC;YACAC;YACAK;YACAC;YACAC;YACAC;YACAC;YACAC;YACAC;YACAV;YACAC;YACAE;QACF,CAAA,GACA;QACEA;QACAM;QACAL;QACAI;QACAH;QACAC;QACAC;QACAR;QACAC;QACAH;QACAC;QACAG;QACAS;KACD;IAGH,OAAO;QACL6B;QACAmC,eAAe;YACb,yBACEzE,qBAAqB,YAAYE,qBAAqBD;YACxDiB,KAAKqB;YACLY;YAEA,0EAA0E;YAC1E,+CAA+C;YAC/C/B,SAAQsD,KAAK;gBACXtD,QAAQsD;gBACR,IAAInD,UAAU;oBACZ;gBACF;gBAEA,kEAAkE;gBAClE,yEAAyE;gBACzE,UAAU;gBACV,MAAM,EAAEoD,aAAa,EAAEC,MAAM,EAAE,GAAGF;gBAClC,IAAIE,WAAWD,iBAAiB,CAAEC,CAAAA,kBAAkBC,WAAU,GAAI;oBAChE;gBACF;gBAEA,MAAMvB,aAAajF,qBAAqBsG,eAAehD;gBACvD,MAAMmD,eAAexB,WAAWyB,SAAS,CACvC,CAACf,UAAYA,YAAYY,UAAUZ,QAAQgB,QAAQ,CAACJ;gBAEtD,IAAIE,iBAAiB,CAAC,KAAK,CAACxB,WAAW2B,MAAM,EAAE;oBAC7C;gBACF;gBAEAnC,kBAAkBnD,OAAO,GAAGmF;gBAC5B,MAAMtB,UAAUF,UAAU,CAACwB,aAAa;gBACxC,IAAI9E,kBAAkB;oBACpB+C,sBAAsBS,QAAQI,EAAE;gBAClC;gBAEA,+DAA+D;gBAC/D,wBAAwB;gBACxB,IAAI5D,qBAAqB,WAAW;oBAClC6C,QAAQlD,OAAO,GAAG;oBAClBgF,cAAcd,KAAK;gBACrB;gBAEAnC,cAAc;oBACZ6B,OAAOuB;oBACPd,SAASR;gBACX;YACF;YACAnC,SAAQqD,KAAK;gBACXrD,QAAQqD;gBACR,IAAIA,MAAMQ,oBAAoB,MAAMrC,QAAQlD,OAAO,EAAE;oBACnDkD,QAAQlD,OAAO,GAAG;oBAClB;gBACF;gBAEA,IACE,AAACiD,SAAS,cAAc5C,qBAAqB,aAC7C0E,MAAME,MAAM,KAAKF,MAAMC,aAAa,EACpC;oBACA;gBACF;gBAEA,MAAMrB,aAAajF,qBACjBqG,MAAMC,aAAa,EACnBhD;gBAEF,IAAI,CAAC2B,WAAW2B,MAAM,EAAE;oBACtB;gBACF;gBAEA,IAAIE,oBAAoB/C,uBAAuB;oBAC7CkB;oBACAvD;gBACF;gBAEA,oEAAoE;gBACpE,iEAAiE;gBACjE,kBAAkB;gBAClB,IAAI,CAACsC,wBAAwB8C,sBAAsB,CAAC,GAAG;oBACrD,IAAInF,qBAAqB,WAAW;wBAClC,yEAAyE;wBACzEmF,oBAAoBhG,4BAA4B;4BAC9CmE;4BACAvD;4BACAG;wBACF;oBACF,OAAO;wBACLiF,oBAAoBpG,uBAAuB;4BACzCuE;4BACAvD;wBACF;oBACF;gBACF;gBAEA,IAAIoF,sBAAsB,CAAC,GAAG;oBAC5B;gBACF;gBAEArC,kBAAkBnD,OAAO,GAAGwF;gBAC5B,MAAM3B,UAAUF,UAAU,CAAC6B,kBAAkB;gBAC7C,IAAInF,kBAAkB;oBACpB+C,sBAAsBS,QAAQI,EAAE;gBAClC;gBAEA,IAAI5D,qBAAqB,WAAW;oBAClCwD,QAAQK,KAAK;gBACf,OAAO;oBACLL,QAAQC,cAAc,CAAC;wBAAEC,OAAO;oBAAU;gBAC5C;gBAEAhC,cAAc;oBACZ6B,OAAO4B;oBACPnB,SAASR;gBACX;YACF;YACAlC,WAAUoD,KAAK;gBACbpD,UAAUoD;gBACV,IAAInD,UAAU;oBACZ;gBACF;gBAEA,MAAM,EAAEoD,aAAa,EAAE,GAAGD;gBAE1B,MAAMU,gBAAgB,CACpB7B,OACAD;oBAEAoB,MAAMW,cAAc;oBACpBX,MAAMY,eAAe;oBACrB7E,iBAAiB;wBAAE8C;wBAAOD;oBAAW;gBACvC;gBAEA7B,cAAc;oBACZiD;oBACAU;oBACAtC;oBACAC;oBACA,GAAGyB,eAAe;gBACpB;gBAEA,IAAIE,MAAMQ,oBAAoB,IAAI;oBAChC;gBACF;gBAEA,sEAAsE;gBACtE,wEAAwE;gBACxE,WAAW;gBACX,IAAI,CAAC7C,wBAAwBS,kBAAkBnD,OAAO,KAAK,CAAC,GAAG;oBAC7DmD,kBAAkBnD,OAAO,GAAGJ,sBAAsB;wBAChD+D,YAAYjF,qBAAqBsG,eAAehD;wBAChD5B;wBACAC;wBACAE;oBACF;gBACF;gBAEA,MAAM,EAAEgE,GAAG,EAAEqB,QAAQ,EAAE,GAAGb;gBAC1B,IACE1E,qBAAqB,aACrBE,sBACCgE,CAAAA,QAAQ,OAAOA,QAAQ,OAAM,GAC9B;oBACA,IAAIA,QAAQ,KAAK;wBACfQ,MAAMW,cAAc;oBACtB;oBAEA,MAAM/B,aAAajF,qBAAqBsG,eAAehD;oBACvD,MAAM6D,gBAAgBlC,UAAU,CAACR,kBAAkBnD,OAAO,CAAC;oBAC3D,IAAI,CAAC6F,iBAAiBpG,kBAAkBoG,gBAAgB;wBACtD;oBACF;oBAEAA,cAAcC,KAAK;oBACnB;gBACF;gBAEA,MAAM,EACJ7D,aAAa,EACbE,aAAa,EACbE,eAAe,EACfE,cAAc,EACf,GAAGxC,OAAOC,OAAO;gBAElB,IAAIE,cAAcP,kBAAkBoF,QAAQ;oBAC1CA,MAAMW,cAAc;oBACpBX,MAAMY,eAAe;oBACrB/E,aAAa;wBAAE2D;wBAAKC,UAAUoB;oBAAS;oBACvC;gBACF;gBAEA,IAAI/D,gBAAgB0C,QAAQ,OAAO;oBACjCpB,kBAAkBnD,OAAO,GAAGV,sBAAsB;wBAChDW;wBACAqE,WAAW,CAACS,MAAMa,QAAQ;wBAC1BjC,YAAYjF,qBAAqBsG,eAAehD;wBAChD5B;wBACA+C,mBAAmBA,kBAAkBnD,OAAO;oBAC9C;oBACA;gBACF;gBAEA,MAAM+F,cAAc1D,gBAAgB2D,QAAQ,CAACzB;gBAC7C,MAAM0B,aAAa,CAACF,eAAexD,eAAeyD,QAAQ,CAACzB;gBAC3D,MAAMD,YACJ,CAACyB,eAAe,CAACE,cAAchE,cAAc+D,QAAQ,CAACzB;gBACxD,MAAM2B,YACJ,CAACH,eACD,CAACE,cACD,CAAC3B,aACDnC,cAAc6D,QAAQ,CAACzB;gBAEzB,IAAIwB,eAAeE,cAAc3B,aAAa4B,WAAW;oBACvDnB,MAAMW,cAAc;oBACpBX,MAAMY,eAAe;gBACvB;gBAEA,IAAII,aAAa;oBACfvF;gBACF,OAAO,IAAIyF,YAAY;oBACrBxF;gBACF,OAAO,IAAI6D,WAAW;oBACpB5D;gBACF,OAAO,IAAIwF,WAAW;oBACpBvF;gBACF;YACF;QACF;QACAkE;QACA1B;QACA5C;QACA6C;IACF;AACF"}
|
|
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 === 0) {\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 === 0) {\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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"}
|
package/dist/movement/utils.js
CHANGED
|
@@ -20,7 +20,7 @@ import { loop } from "../utils/loop.js";
|
|
|
20
20
|
* @internal
|
|
21
21
|
*/ export const getVirtualFocusDefaultIndex = (options)=>{
|
|
22
22
|
const { focusables, includeDisabled, activeDescendantId } = options;
|
|
23
|
-
if (
|
|
23
|
+
if (focusables.length === 0 || !activeDescendantId && includeDisabled) {
|
|
24
24
|
return 0;
|
|
25
25
|
}
|
|
26
26
|
const activeIndex = focusables.findIndex((element)=>{
|
|
@@ -36,7 +36,7 @@ import { loop } from "../utils/loop.js";
|
|
|
36
36
|
* @internal
|
|
37
37
|
*/ export const getFirstFocusableIndex = (options)=>{
|
|
38
38
|
const { focusables, includeDisabled } = options;
|
|
39
|
-
if (
|
|
39
|
+
if (focusables.length === 0) {
|
|
40
40
|
return -1;
|
|
41
41
|
}
|
|
42
42
|
let firstIndex = 0;
|
|
@@ -53,7 +53,7 @@ import { loop } from "../utils/loop.js";
|
|
|
53
53
|
* @internal
|
|
54
54
|
*/ export const getLastFocusableIndex = (options)=>{
|
|
55
55
|
const { focusables, includeDisabled } = options;
|
|
56
|
-
if (
|
|
56
|
+
if (focusables.length === 0) {
|
|
57
57
|
return -1;
|
|
58
58
|
}
|
|
59
59
|
let lastIndex = focusables.length - 1;
|
|
@@ -70,7 +70,7 @@ import { loop } from "../utils/loop.js";
|
|
|
70
70
|
* @internal
|
|
71
71
|
*/ export const getNextFocusableIndex = (options)=>{
|
|
72
72
|
const { loopable, increment, focusables, includeDisabled, currentFocusIndex } = options;
|
|
73
|
-
if (
|
|
73
|
+
if (focusables.length === 0) {
|
|
74
74
|
return currentFocusIndex;
|
|
75
75
|
}
|
|
76
76
|
const min = getFirstFocusableIndex({
|
|
@@ -109,10 +109,11 @@ import { loop } from "../utils/loop.js";
|
|
|
109
109
|
return "";
|
|
110
110
|
}
|
|
111
111
|
const cloned = element.cloneNode(true);
|
|
112
|
-
cloned.querySelectorAll(// Note: do not include DISPLAY_NONE_CLASS since it is presentational only
|
|
113
|
-
".rmd-icon--font,[aria-hidden=true],[hidden],[role=presentation]")
|
|
114
|
-
|
|
115
|
-
|
|
112
|
+
const invisibleElements = cloned.querySelectorAll(// Note: do not include DISPLAY_NONE_CLASS since it is presentational only
|
|
113
|
+
".rmd-icon--font,[aria-hidden=true],[hidden],[role=presentation]");
|
|
114
|
+
for (const element of invisibleElements){
|
|
115
|
+
element.remove();
|
|
116
|
+
}
|
|
116
117
|
// Note: It would be good to use `cloned.innerText` (maybe?) at some point,
|
|
117
118
|
// but it returns `undefined` in jsdom. It also does cause a reflow, so maybe
|
|
118
119
|
// this is fine?
|
|
@@ -135,8 +136,9 @@ import { loop } from "../utils/loop.js";
|
|
|
135
136
|
activeDescendantId
|
|
136
137
|
});
|
|
137
138
|
}
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
// do type-casting since the types don't matter much here
|
|
140
|
+
const activeElement = document.activeElement;
|
|
141
|
+
return focusables.indexOf(activeElement);
|
|
140
142
|
}
|
|
141
143
|
/**
|
|
142
144
|
* Checks if a keyboard event can trigger a search through focusable elements
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/movement/utils.ts"],"sourcesContent":["import { type KeyboardEvent } from \"react\";\n\nimport { loop } from \"../utils/loop.js\";\nimport { type FocusableIndexOptions, type TabIndexBehavior } from \"./types.js\";\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport const isElementDisabled = (element: HTMLElement): boolean =>\n element.getAttribute(\"disabled\") !== null ||\n element.getAttribute(\"aria-disabled\") === \"true\";\n\n/**\n * @since 5.0.0\n * @internal\n */\nexport const isNotFocusable = (\n element: HTMLElement | undefined,\n includeDisabled: boolean\n): boolean => {\n if (!element) {\n return true;\n }\n\n if (includeDisabled) {\n return false;\n }\n\n return isElementDisabled(element);\n};\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface VirtualFocusableIndexOptions {\n focusables: readonly HTMLElement[];\n includeDisabled: boolean;\n activeDescendantId: string;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport const getVirtualFocusDefaultIndex = (\n options: VirtualFocusableIndexOptions\n): number => {\n const { focusables, includeDisabled, activeDescendantId } = options;\n if (!focusables.length || (!activeDescendantId && includeDisabled)) {\n return 0;\n }\n\n const activeIndex = focusables.findIndex((element) => {\n if (activeDescendantId) {\n return element.id === activeDescendantId;\n }\n\n return !isElementDisabled(element);\n });\n return Math.max(0, activeIndex);\n};\n\n/**\n * @since 5.0.0\n * @internal\n */\nexport const getFirstFocusableIndex = (\n options: FocusableIndexOptions\n): number => {\n const { focusables, includeDisabled } = options;\n\n if (!focusables.length) {\n return -1;\n }\n\n let firstIndex = 0;\n while (\n firstIndex < focusables.length - 1 &&\n isNotFocusable(focusables[firstIndex], includeDisabled)\n ) {\n firstIndex += 1;\n }\n\n if (isNotFocusable(focusables[firstIndex], includeDisabled)) {\n return -1;\n }\n\n return firstIndex;\n};\n\n/**\n * @since 5.0.0\n * @internal\n */\nexport const getLastFocusableIndex = (\n options: FocusableIndexOptions\n): number => {\n const { focusables, includeDisabled } = options;\n\n if (!focusables.length) {\n return -1;\n }\n\n let lastIndex = focusables.length - 1;\n while (\n lastIndex > 0 &&\n isNotFocusable(focusables[lastIndex], includeDisabled)\n ) {\n lastIndex -= 1;\n }\n\n if (isNotFocusable(focusables[lastIndex], includeDisabled)) {\n return -1;\n }\n\n return lastIndex;\n};\n\n/**\n * @since 5.0.0\n * @internal\n */\ninterface NextFocusableIndexOptions extends FocusableIndexOptions {\n loopable: boolean;\n increment: boolean;\n currentFocusIndex: number;\n}\n\n/**\n * @since 5.0.0\n * @internal\n */\nexport const getNextFocusableIndex = (\n options: NextFocusableIndexOptions\n): number => {\n const {\n loopable,\n increment,\n focusables,\n includeDisabled,\n currentFocusIndex,\n } = options;\n if (!focusables.length) {\n return currentFocusIndex;\n }\n\n const min = getFirstFocusableIndex({ focusables, includeDisabled });\n const max = getLastFocusableIndex({ focusables, includeDisabled });\n let nextIndex = loop({\n min,\n max,\n value: currentFocusIndex,\n minmax: !loopable,\n increment,\n });\n while (\n isNotFocusable(focusables[nextIndex], includeDisabled) &&\n (loopable || nextIndex !== (increment ? max : min))\n ) {\n nextIndex = loop({\n min,\n max,\n value: nextIndex,\n minmax: !loopable,\n increment,\n });\n }\n\n // Since the `min` and `max` values are \"safely\" set, I don't need to verify\n // the nextIndex is still focusable\n return nextIndex;\n};\n\n/**\n * @since 5.0.0\n * @internal\n */\nexport function getSearchText(\n element: HTMLElement,\n searchable: boolean\n): string {\n if (!searchable) {\n return \"\";\n }\n\n const cloned = element.cloneNode(true) as HTMLElement;\n cloned\n .querySelectorAll(\n // Note: do not include DISPLAY_NONE_CLASS since it is presentational only\n \".rmd-icon--font,[aria-hidden=true],[hidden],[role=presentation]\"\n )\n .forEach((element) => {\n element.parentNode?.removeChild(element);\n });\n\n // Note: It would be good to use `cloned.innerText` (maybe?) at some point,\n // but it returns `undefined` in jsdom. It also does cause a reflow, so maybe\n // this is fine?\n // https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent#differences_from_innertext\n return (cloned.textContent || \"\")[0].toUpperCase();\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface RecalculateOptions {\n focusables: readonly HTMLElement[];\n includeDisabled: boolean;\n tabIndexBehavior: TabIndexBehavior | undefined;\n activeDescendantId: string;\n}\n\n/**\n * This was added to help with specific widgets that cause focus index to change\n * between renders (i.e. expanding all tree items on the same level with `*`).\n * There might be a better way to handle this in the future.\n *\n * @since 6.0.0\n * @internal\n */\nexport function recalculateFocusIndex(options: RecalculateOptions): number {\n const { focusables, includeDisabled, tabIndexBehavior, activeDescendantId } =\n options;\n if (tabIndexBehavior === \"virtual\") {\n return getVirtualFocusDefaultIndex({\n focusables,\n includeDisabled,\n activeDescendantId,\n });\n }\n\n const { activeElement } = document;\n return focusables.findIndex((element) => element === activeElement);\n}\n\n/**\n * Checks if a keyboard event can trigger a search through focusable elements\n * by:\n *\n * - checking if the key is a single letter that is not the space key\n * - checking that the alt, ctrl, and meta keys are not being held\n *\n * The shift key **is allowed** because holding shift means \"search from the\n * beginning\" instead of \"search from current location\".\n *\n * @since 6.0.0\n * @internal\n */\nexport function isSearchableEvent(event: KeyboardEvent): boolean {\n const { key, altKey, ctrlKey, metaKey } = event;\n\n return (\n key.length === 1 &&\n // can't search with space since it is generally a click event\n key !== \" \" &&\n !altKey &&\n !ctrlKey &&\n !metaKey\n );\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport function isTypeEvent(event: KeyboardEvent): boolean {\n return (\n isSearchableEvent(event) || [\"Backspace\", \"Delete\", \" \"].includes(event.key)\n );\n}\n"],"names":["loop","isElementDisabled","element","getAttribute","isNotFocusable","includeDisabled","getVirtualFocusDefaultIndex","options","focusables","activeDescendantId","length","activeIndex","findIndex","id","Math","max","getFirstFocusableIndex","firstIndex","getLastFocusableIndex","lastIndex","getNextFocusableIndex","loopable","increment","currentFocusIndex","min","nextIndex","value","minmax","getSearchText","searchable","cloned","cloneNode","querySelectorAll","forEach","parentNode","removeChild","textContent","toUpperCase","recalculateFocusIndex","tabIndexBehavior","activeElement","document","isSearchableEvent","event","key","altKey","ctrlKey","metaKey","isTypeEvent","includes"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/movement/utils.ts"],"sourcesContent":["import { type KeyboardEvent } from \"react\";\n\nimport { loop } from \"../utils/loop.js\";\nimport { type FocusableIndexOptions, type TabIndexBehavior } from \"./types.js\";\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport const isElementDisabled = (element: HTMLElement): boolean =>\n element.getAttribute(\"disabled\") !== null ||\n element.getAttribute(\"aria-disabled\") === \"true\";\n\n/**\n * @since 5.0.0\n * @internal\n */\nexport const isNotFocusable = (\n element: HTMLElement | undefined,\n includeDisabled: boolean\n): boolean => {\n if (!element) {\n return true;\n }\n\n if (includeDisabled) {\n return false;\n }\n\n return isElementDisabled(element);\n};\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface VirtualFocusableIndexOptions {\n focusables: readonly HTMLElement[];\n includeDisabled: boolean;\n activeDescendantId: string;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport const getVirtualFocusDefaultIndex = (\n options: VirtualFocusableIndexOptions\n): number => {\n const { focusables, includeDisabled, activeDescendantId } = options;\n if (focusables.length === 0 || (!activeDescendantId && includeDisabled)) {\n return 0;\n }\n\n const activeIndex = focusables.findIndex((element) => {\n if (activeDescendantId) {\n return element.id === activeDescendantId;\n }\n\n return !isElementDisabled(element);\n });\n return Math.max(0, activeIndex);\n};\n\n/**\n * @since 5.0.0\n * @internal\n */\nexport const getFirstFocusableIndex = (\n options: FocusableIndexOptions\n): number => {\n const { focusables, includeDisabled } = options;\n\n if (focusables.length === 0) {\n return -1;\n }\n\n let firstIndex = 0;\n while (\n firstIndex < focusables.length - 1 &&\n isNotFocusable(focusables[firstIndex], includeDisabled)\n ) {\n firstIndex += 1;\n }\n\n if (isNotFocusable(focusables[firstIndex], includeDisabled)) {\n return -1;\n }\n\n return firstIndex;\n};\n\n/**\n * @since 5.0.0\n * @internal\n */\nexport const getLastFocusableIndex = (\n options: FocusableIndexOptions\n): number => {\n const { focusables, includeDisabled } = options;\n\n if (focusables.length === 0) {\n return -1;\n }\n\n let lastIndex = focusables.length - 1;\n while (\n lastIndex > 0 &&\n isNotFocusable(focusables[lastIndex], includeDisabled)\n ) {\n lastIndex -= 1;\n }\n\n if (isNotFocusable(focusables[lastIndex], includeDisabled)) {\n return -1;\n }\n\n return lastIndex;\n};\n\n/**\n * @since 5.0.0\n * @internal\n */\ninterface NextFocusableIndexOptions extends FocusableIndexOptions {\n loopable: boolean;\n increment: boolean;\n currentFocusIndex: number;\n}\n\n/**\n * @since 5.0.0\n * @internal\n */\nexport const getNextFocusableIndex = (\n options: NextFocusableIndexOptions\n): number => {\n const {\n loopable,\n increment,\n focusables,\n includeDisabled,\n currentFocusIndex,\n } = options;\n if (focusables.length === 0) {\n return currentFocusIndex;\n }\n\n const min = getFirstFocusableIndex({ focusables, includeDisabled });\n const max = getLastFocusableIndex({ focusables, includeDisabled });\n let nextIndex = loop({\n min,\n max,\n value: currentFocusIndex,\n minmax: !loopable,\n increment,\n });\n while (\n isNotFocusable(focusables[nextIndex], includeDisabled) &&\n (loopable || nextIndex !== (increment ? max : min))\n ) {\n nextIndex = loop({\n min,\n max,\n value: nextIndex,\n minmax: !loopable,\n increment,\n });\n }\n\n // Since the `min` and `max` values are \"safely\" set, I don't need to verify\n // the nextIndex is still focusable\n return nextIndex;\n};\n\n/**\n * @since 5.0.0\n * @internal\n */\nexport function getSearchText(\n element: HTMLElement,\n searchable: boolean\n): string {\n if (!searchable) {\n return \"\";\n }\n\n const cloned = element.cloneNode(true) as HTMLElement;\n\n const invisibleElements = cloned.querySelectorAll(\n // Note: do not include DISPLAY_NONE_CLASS since it is presentational only\n \".rmd-icon--font,[aria-hidden=true],[hidden],[role=presentation]\"\n );\n for (const element of invisibleElements) {\n element.remove();\n }\n\n // Note: It would be good to use `cloned.innerText` (maybe?) at some point,\n // but it returns `undefined` in jsdom. It also does cause a reflow, so maybe\n // this is fine?\n // https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent#differences_from_innertext\n return (cloned.textContent || \"\")[0].toUpperCase();\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface RecalculateOptions {\n focusables: readonly HTMLElement[];\n includeDisabled: boolean;\n tabIndexBehavior: TabIndexBehavior | undefined;\n activeDescendantId: string;\n}\n\n/**\n * This was added to help with specific widgets that cause focus index to change\n * between renders (i.e. expanding all tree items on the same level with `*`).\n * There might be a better way to handle this in the future.\n *\n * @since 6.0.0\n * @internal\n */\nexport function recalculateFocusIndex(options: RecalculateOptions): number {\n const { focusables, includeDisabled, tabIndexBehavior, activeDescendantId } =\n options;\n if (tabIndexBehavior === \"virtual\") {\n return getVirtualFocusDefaultIndex({\n focusables,\n includeDisabled,\n activeDescendantId,\n });\n }\n\n // do type-casting since the types don't matter much here\n const activeElement = document.activeElement as HTMLElement;\n return focusables.indexOf(activeElement);\n}\n\n/**\n * Checks if a keyboard event can trigger a search through focusable elements\n * by:\n *\n * - checking if the key is a single letter that is not the space key\n * - checking that the alt, ctrl, and meta keys are not being held\n *\n * The shift key **is allowed** because holding shift means \"search from the\n * beginning\" instead of \"search from current location\".\n *\n * @since 6.0.0\n * @internal\n */\nexport function isSearchableEvent(event: KeyboardEvent): boolean {\n const { key, altKey, ctrlKey, metaKey } = event;\n\n return (\n key.length === 1 &&\n // can't search with space since it is generally a click event\n key !== \" \" &&\n !altKey &&\n !ctrlKey &&\n !metaKey\n );\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport function isTypeEvent(event: KeyboardEvent): boolean {\n return (\n isSearchableEvent(event) || [\"Backspace\", \"Delete\", \" \"].includes(event.key)\n );\n}\n"],"names":["loop","isElementDisabled","element","getAttribute","isNotFocusable","includeDisabled","getVirtualFocusDefaultIndex","options","focusables","activeDescendantId","length","activeIndex","findIndex","id","Math","max","getFirstFocusableIndex","firstIndex","getLastFocusableIndex","lastIndex","getNextFocusableIndex","loopable","increment","currentFocusIndex","min","nextIndex","value","minmax","getSearchText","searchable","cloned","cloneNode","invisibleElements","querySelectorAll","remove","textContent","toUpperCase","recalculateFocusIndex","tabIndexBehavior","activeElement","document","indexOf","isSearchableEvent","event","key","altKey","ctrlKey","metaKey","isTypeEvent","includes"],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* @since 6.0.0
|
|
11
11
|
*/ export function getTableOfContentsHeadings(options) {
|
|
12
12
|
const { ssr, selector, getDepth, getHeadingText } = options;
|
|
13
|
-
if (ssr ||
|
|
13
|
+
if (ssr || globalThis.window === undefined) {
|
|
14
14
|
return [];
|
|
15
15
|
}
|
|
16
16
|
const root = {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
let previous = root;
|
|
23
23
|
const parents = [];
|
|
24
24
|
const headings = document.querySelectorAll(selector);
|
|
25
|
-
|
|
25
|
+
for (const heading of headings){
|
|
26
26
|
const depth = getDepth(heading);
|
|
27
27
|
const item = {
|
|
28
28
|
id: heading.id,
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
}
|
|
37
37
|
parents.push(previous);
|
|
38
38
|
} else if (depth < previous.depth) {
|
|
39
|
+
// eslint-disable-next-line unicorn/prefer-at
|
|
39
40
|
while(parents[parents.length - 1].depth >= depth){
|
|
40
41
|
parents.pop();
|
|
41
42
|
}
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
item
|
|
47
48
|
];
|
|
48
49
|
previous = item;
|
|
49
|
-
}
|
|
50
|
+
}
|
|
50
51
|
return root.items;
|
|
51
52
|
}
|
|
52
53
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/navigation/getTableOfContentsHeadings.ts"],"sourcesContent":["import {\n type TableOfContentsHeadingItem,\n type TableOfContentsHeadings,\n type TableOfContentsHeadingsOptions,\n} from \"./types.js\";\n\n/**\n * @internal\n * @since 6.0.0\n */\nexport interface GetTableOfContentsHeadingsOptions extends Required<TableOfContentsHeadingsOptions> {\n ssr: boolean;\n}\n\n/**\n * This is used by the `useTableOfContentsHeadings` hook to find\n * the active heading element which is why it is marked as\n * internal.\n *\n * This will always return an empty list if `ssr` is `true` or\n * `typeof window === \"undefined\"`.\n *\n * @internal\n * @since 6.0.0\n */\nexport function getTableOfContentsHeadings(\n options: GetTableOfContentsHeadingsOptions\n): TableOfContentsHeadings {\n const { ssr, selector, getDepth, getHeadingText } = options;\n\n if (ssr ||
|
|
1
|
+
{"version":3,"sources":["../../src/navigation/getTableOfContentsHeadings.ts"],"sourcesContent":["import {\n type TableOfContentsHeadingItem,\n type TableOfContentsHeadings,\n type TableOfContentsHeadingsOptions,\n} from \"./types.js\";\n\n/**\n * @internal\n * @since 6.0.0\n */\nexport interface GetTableOfContentsHeadingsOptions extends Required<TableOfContentsHeadingsOptions> {\n ssr: boolean;\n}\n\n/**\n * This is used by the `useTableOfContentsHeadings` hook to find\n * the active heading element which is why it is marked as\n * internal.\n *\n * This will always return an empty list if `ssr` is `true` or\n * `typeof window === \"undefined\"`.\n *\n * @internal\n * @since 6.0.0\n */\nexport function getTableOfContentsHeadings(\n options: GetTableOfContentsHeadingsOptions\n): TableOfContentsHeadings {\n const { ssr, selector, getDepth, getHeadingText } = options;\n\n if (ssr || globalThis.window === undefined) {\n return [];\n }\n\n const root = {\n id: \"\",\n depth: 0,\n items: [],\n children: \"\",\n } satisfies TableOfContentsHeadingItem;\n let previous: TableOfContentsHeadingItem = root;\n const parents: TableOfContentsHeadingItem[] = [];\n const headings = document.querySelectorAll(selector);\n for (const heading of headings) {\n const depth = getDepth(heading);\n const item: TableOfContentsHeadingItem = {\n id: heading.id,\n depth,\n items: [],\n children: getHeadingText(heading),\n };\n if (depth > previous.depth) {\n if (!previous.items) {\n previous.items = [];\n }\n\n parents.push(previous);\n } else if (depth < previous.depth) {\n // eslint-disable-next-line unicorn/prefer-at\n while (parents[parents.length - 1].depth >= depth) {\n parents.pop();\n }\n }\n const i = parents.length - 1;\n parents[i].items = [...(parents[i].items ?? []), item];\n previous = item;\n }\n\n return root.items;\n}\n"],"names":["getTableOfContentsHeadings","options","ssr","selector","getDepth","getHeadingText","globalThis","window","undefined","root","id","depth","items","children","previous","parents","headings","document","querySelectorAll","heading","item","push","length","pop","i"],"mappings":"AAcA;;;;;;;;;;CAUC,GACD,OAAO,SAASA,2BACdC,OAA0C;IAE1C,MAAM,EAAEC,GAAG,EAAEC,QAAQ,EAAEC,QAAQ,EAAEC,cAAc,EAAE,GAAGJ;IAEpD,IAAIC,OAAOI,WAAWC,MAAM,KAAKC,WAAW;QAC1C,OAAO,EAAE;IACX;IAEA,MAAMC,OAAO;QACXC,IAAI;QACJC,OAAO;QACPC,OAAO,EAAE;QACTC,UAAU;IACZ;IACA,IAAIC,WAAuCL;IAC3C,MAAMM,UAAwC,EAAE;IAChD,MAAMC,WAAWC,SAASC,gBAAgB,CAACf;IAC3C,KAAK,MAAMgB,WAAWH,SAAU;QAC9B,MAAML,QAAQP,SAASe;QACvB,MAAMC,OAAmC;YACvCV,IAAIS,QAAQT,EAAE;YACdC;YACAC,OAAO,EAAE;YACTC,UAAUR,eAAec;QAC3B;QACA,IAAIR,QAAQG,SAASH,KAAK,EAAE;YAC1B,IAAI,CAACG,SAASF,KAAK,EAAE;gBACnBE,SAASF,KAAK,GAAG,EAAE;YACrB;YAEAG,QAAQM,IAAI,CAACP;QACf,OAAO,IAAIH,QAAQG,SAASH,KAAK,EAAE;YACjC,6CAA6C;YAC7C,MAAOI,OAAO,CAACA,QAAQO,MAAM,GAAG,EAAE,CAACX,KAAK,IAAIA,MAAO;gBACjDI,QAAQQ,GAAG;YACb;QACF;QACA,MAAMC,IAAIT,QAAQO,MAAM,GAAG;QAC3BP,OAAO,CAACS,EAAE,CAACZ,KAAK,GAAG;eAAKG,OAAO,CAACS,EAAE,CAACZ,KAAK,IAAI,EAAE;YAAGQ;SAAK;QACtDN,WAAWM;IACb;IAEA,OAAOX,KAAKG,KAAK;AACnB"}
|
|
@@ -6,8 +6,8 @@ import { parseCssLengthUnit } from "../utils/parseCssLengthUnit.js";
|
|
|
6
6
|
* @defaultValue `[0.0, 1.0]`
|
|
7
7
|
* @since 6.0.0
|
|
8
8
|
*/ export const DEFAULT_ACTIVE_HEADING_THRESHOLD = [
|
|
9
|
-
0
|
|
10
|
-
1
|
|
9
|
+
0,
|
|
10
|
+
1
|
|
11
11
|
];
|
|
12
12
|
/**
|
|
13
13
|
* ```tsx
|
|
@@ -22,7 +22,7 @@ import { parseCssLengthUnit } from "../utils/parseCssLengthUnit.js";
|
|
|
22
22
|
* ```
|
|
23
23
|
* @since 6.0.0
|
|
24
24
|
*/ export const DEFAULT_ACTIVE_HEADING_GET_ROOT_MARGIN = ()=>{
|
|
25
|
-
const headerHeightVar =
|
|
25
|
+
const headerHeightVar = globalThis.getComputedStyle(document.documentElement).getPropertyValue("--rmd-layout-header-height");
|
|
26
26
|
const headerHeight = parseCssLengthUnit({
|
|
27
27
|
value: headerHeightVar || "3.5rem"
|
|
28
28
|
});
|
|
@@ -33,7 +33,7 @@ import { parseCssLengthUnit } from "../utils/parseCssLengthUnit.js";
|
|
|
33
33
|
* @since 6.0.0
|
|
34
34
|
*/ function getHeadingElements(items) {
|
|
35
35
|
const headings = [];
|
|
36
|
-
|
|
36
|
+
for (const item of items){
|
|
37
37
|
const heading = document.getElementById(item.id);
|
|
38
38
|
if (heading) {
|
|
39
39
|
headings.push(heading);
|
|
@@ -41,7 +41,7 @@ import { parseCssLengthUnit } from "../utils/parseCssLengthUnit.js";
|
|
|
41
41
|
if (item.items) {
|
|
42
42
|
headings.push(...getHeadingElements(item.items));
|
|
43
43
|
}
|
|
44
|
-
}
|
|
44
|
+
}
|
|
45
45
|
return headings;
|
|
46
46
|
}
|
|
47
47
|
/**
|
|
@@ -78,9 +78,9 @@ import { parseCssLengthUnit } from "../utils/parseCssLengthUnit.js";
|
|
|
78
78
|
getTargets: useCallback(()=>{
|
|
79
79
|
const headingElements = getHeadingElements(headings);
|
|
80
80
|
const lookup = new Map();
|
|
81
|
-
|
|
81
|
+
for (const heading of headingElements){
|
|
82
82
|
lookup.set(heading.id, false);
|
|
83
|
-
}
|
|
83
|
+
}
|
|
84
84
|
elements.current = lookup;
|
|
85
85
|
return headingElements;
|
|
86
86
|
}, [
|
|
@@ -91,9 +91,9 @@ import { parseCssLengthUnit } from "../utils/parseCssLengthUnit.js";
|
|
|
91
91
|
if (!lookup) {
|
|
92
92
|
return;
|
|
93
93
|
}
|
|
94
|
-
|
|
94
|
+
for (const entry of entries){
|
|
95
95
|
lookup.set(entry.target.id, entry.isIntersecting);
|
|
96
|
-
}
|
|
96
|
+
}
|
|
97
97
|
// get the first visible/intersecting item and set it
|
|
98
98
|
let foundId = [
|
|
99
99
|
...lookup.entries()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/navigation/useActiveHeadingId.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useRef, useState } from \"react\";\n\nimport { type UseStateInitializer } from \"../types.js\";\nimport {\n type IntersectionObserverRootMargin,\n type IntersectionObserverThreshold,\n useIntersectionObserver,\n} from \"../useIntersectionObserver.js\";\nimport { parseCssLengthUnit } from \"../utils/parseCssLengthUnit.js\";\nimport { type HeadingReferenceWithChildren } from \"./types.js\";\n\n/**\n * @defaultValue `[0.0, 1.0]`\n * @since 6.0.0\n */\nexport const DEFAULT_ACTIVE_HEADING_THRESHOLD: IntersectionObserverThreshold = [\n 0
|
|
1
|
+
{"version":3,"sources":["../../src/navigation/useActiveHeadingId.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useRef, useState } from \"react\";\n\nimport { type UseStateInitializer } from \"../types.js\";\nimport {\n type IntersectionObserverRootMargin,\n type IntersectionObserverThreshold,\n useIntersectionObserver,\n} from \"../useIntersectionObserver.js\";\nimport { parseCssLengthUnit } from \"../utils/parseCssLengthUnit.js\";\nimport { type HeadingReferenceWithChildren } from \"./types.js\";\n\n/**\n * @defaultValue `[0.0, 1.0]`\n * @since 6.0.0\n */\nexport const DEFAULT_ACTIVE_HEADING_THRESHOLD: IntersectionObserverThreshold = [\n 0, 1,\n];\n\n/**\n * ```tsx\n * const headerHeightVar = window\n * .getComputedStyle(document.documentElement)\n * .getPropertyValue(\"--rmd-layout-header-height\");\n * const headerHeight = parseCssLengthUnit({\n * value: headerHeightVar || \"3.5rem\",\n * });\n\n * return `-${headerHeight}px 0px 0px 0px`;\n * ```\n * @since 6.0.0\n */\nexport const DEFAULT_ACTIVE_HEADING_GET_ROOT_MARGIN = (): string => {\n const headerHeightVar = globalThis\n .getComputedStyle(document.documentElement)\n .getPropertyValue(\"--rmd-layout-header-height\");\n const headerHeight = parseCssLengthUnit({\n value: headerHeightVar || \"3.5rem\",\n });\n\n return `-${headerHeight}px 0px 0px 0px`;\n};\n\n/**\n * @internal\n * @since 6.0.0\n */\nfunction getHeadingElements(\n items: readonly HeadingReferenceWithChildren[]\n): readonly HTMLElement[] {\n const headings: HTMLElement[] = [];\n for (const item of items) {\n const heading = document.getElementById(item.id);\n if (heading) {\n headings.push(heading);\n }\n\n if (item.items) {\n headings.push(...getHeadingElements(item.items));\n }\n }\n\n return headings;\n}\n\n/**\n * @internal\n * @since 6.0.0\n */\nfunction getLastHeadingId(\n items: readonly HeadingReferenceWithChildren[]\n): string {\n const last = items.at(-1);\n if (!last) {\n return \"\";\n }\n\n if (last.items) {\n return getLastHeadingId(last.items);\n }\n\n return last.id;\n}\n\n/**\n * @internal\n * @since 6.0.0\n */\nconst isScrolledNearPageBottom = (threshold: number): boolean =>\n window.scrollY >= document.documentElement.scrollHeight * threshold;\n\n/**\n * @since 6.0.0\n */\nexport interface ActiveHeadingIdOptions {\n headings: readonly HeadingReferenceWithChildren[];\n\n /** @see {@link DEFAULT_ACTIVE_HEADING_THRESHOLD} */\n threshold?: IntersectionObserverThreshold;\n\n /** @see {@link DEFAULT_ACTIVE_HEADING_GET_ROOT_MARGIN} */\n getRootMargin?: () => IntersectionObserverRootMargin;\n\n /** @defaultValue `headings[0]?.id ?? \"\"` */\n defaultActiveId?: UseStateInitializer<string>;\n\n /** @defaultValue `0.8` */\n scrollBottomThreshold?: number;\n}\n\n/**\n * This is heavily inspired by:\n * @see https://github.com/mdn/yari/blob/231d6aab8f1c8efe159d268c261446c5b7ae12d9/client/src/document/hooks.ts#L171\n *\n * @see {@link https://react-md.dev/hooks/use-active-heading-id | useActiveHeadingId Demos}\n * @since 6.0.0\n */\nexport function useActiveHeadingId(options: ActiveHeadingIdOptions): string {\n const {\n headings,\n threshold = DEFAULT_ACTIVE_HEADING_THRESHOLD,\n getRootMargin = DEFAULT_ACTIVE_HEADING_GET_ROOT_MARGIN,\n defaultActiveId = headings[0]?.id ?? \"\",\n scrollBottomThreshold = 0.8,\n } = options;\n const elements = useRef<Map<string, boolean>>();\n const isFirstRender = useRef(true);\n const [activeHeadingId, setActiveHeadingId] = useState(defaultActiveId);\n useIntersectionObserver({\n threshold,\n getRootMargin,\n getTargets: useCallback(() => {\n const headingElements = getHeadingElements(headings);\n const lookup = new Map<string, boolean>();\n for (const heading of headingElements) {\n lookup.set(heading.id, false);\n }\n elements.current = lookup;\n\n return headingElements;\n }, [headings]),\n onUpdate: useCallback(\n (entries) => {\n const lookup = elements.current;\n if (!lookup) {\n return;\n }\n\n for (const entry of entries) {\n lookup.set(entry.target.id, entry.isIntersecting);\n }\n\n // get the first visible/intersecting item and set it\n let foundId = [...lookup.entries()].find(\n ([_id, isIntersecting]) => isIntersecting\n )?.[0];\n if (\n !foundId &&\n isFirstRender.current &&\n isScrolledNearPageBottom(scrollBottomThreshold)\n ) {\n foundId = getLastHeadingId(headings);\n }\n\n isFirstRender.current = false;\n\n // if there isn't a found id, it might be a really large section where\n // another heading isn't visible, so maintain the previous one\n if (foundId) {\n setActiveHeadingId(foundId);\n }\n },\n [headings, scrollBottomThreshold]\n ),\n });\n\n return activeHeadingId;\n}\n"],"names":["useCallback","useRef","useState","useIntersectionObserver","parseCssLengthUnit","DEFAULT_ACTIVE_HEADING_THRESHOLD","DEFAULT_ACTIVE_HEADING_GET_ROOT_MARGIN","headerHeightVar","globalThis","getComputedStyle","document","documentElement","getPropertyValue","headerHeight","value","getHeadingElements","items","headings","item","heading","getElementById","id","push","getLastHeadingId","last","at","isScrolledNearPageBottom","threshold","window","scrollY","scrollHeight","useActiveHeadingId","options","getRootMargin","defaultActiveId","scrollBottomThreshold","elements","isFirstRender","activeHeadingId","setActiveHeadingId","getTargets","headingElements","lookup","Map","set","current","onUpdate","entries","entry","target","isIntersecting","foundId","find","_id"],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@ import { getTableOfContentsHeadings } from "./getTableOfContentsHeadings.js";
|
|
|
14
14
|
*
|
|
15
15
|
* @since 6.0.0
|
|
16
16
|
*/ export const DEFAULT_GET_HEADING_DEPTH = (element)=>{
|
|
17
|
-
const depth = parseInt(element.tagName.
|
|
17
|
+
const depth = Number.parseInt(element.tagName.slice(1));
|
|
18
18
|
return Number.isNaN(depth) ? 0 : depth;
|
|
19
19
|
};
|
|
20
20
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/navigation/useTableOfContentsHeadings.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\nimport { useSsr } from \"../SsrProvider.js\";\nimport { getTableOfContentsHeadings } from \"./getTableOfContentsHeadings.js\";\nimport {\n type TableOfContentsHeadings,\n type TableOfContentsHeadingsOptions,\n} from \"./types.js\";\n\n/**\n * This will find all headings that have an `id` that are not part of a `<nav>`\n * element since that should normally be a table of contents component.\n *\n * @since 6.0.0\n */\nexport const DEFAULT_HEADING_SELECTOR =\n \"main :where(:not(nav *)):where(h1[id],h2[id],h3[id],h4[id],h5[id],h6[id])\";\n\n/**\n * This only works for heading elements since it is pretty much:\n * `return parseInt(element.tagName.substring(1))`\n *\n * @since 6.0.0\n */\nexport const DEFAULT_GET_HEADING_DEPTH = (element: Element): number => {\n const depth = parseInt(element.tagName.
|
|
1
|
+
{"version":3,"sources":["../../src/navigation/useTableOfContentsHeadings.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\nimport { useSsr } from \"../SsrProvider.js\";\nimport { getTableOfContentsHeadings } from \"./getTableOfContentsHeadings.js\";\nimport {\n type TableOfContentsHeadings,\n type TableOfContentsHeadingsOptions,\n} from \"./types.js\";\n\n/**\n * This will find all headings that have an `id` that are not part of a `<nav>`\n * element since that should normally be a table of contents component.\n *\n * @since 6.0.0\n */\nexport const DEFAULT_HEADING_SELECTOR =\n \"main :where(:not(nav *)):where(h1[id],h2[id],h3[id],h4[id],h5[id],h6[id])\";\n\n/**\n * This only works for heading elements since it is pretty much:\n * `return parseInt(element.tagName.substring(1))`\n *\n * @since 6.0.0\n */\nexport const DEFAULT_GET_HEADING_DEPTH = (element: Element): number => {\n const depth = Number.parseInt(element.tagName.slice(1));\n return Number.isNaN(depth) ? 0 : depth;\n};\n\n/**\n * @since 6.0.0\n */\nexport const DEFAULT_GET_HEADING_TEXT = (element: Element): string =>\n element.textContent || \"\";\n\n/**\n * The `useTableOfContentsHeadings` should normally be used with the\n * `useActiveHeadingId` hook to generate a table of contents for the current\n * page.\n *\n * @example Example Usage\n * ```tsx\n * import { useActiveHeadingId } from \"@react-md/core/navigation/useActiveHeadingId\";\n * import { useTableOfContentsHeadings } from \"@react-md/core/navigation/useTableOfContentsHeadings\";\n *\n * function Example() {\n * const headings = useTableOfContentsHeadings();\n * const activeHeadingId = useActiveHeadingId({ headings });\n *\n * return <TableOfContents headings={headings} activeHeadingId={activeHeadingId} />;\n * }\n * ```\n *\n * @see {@link https://react-md.dev/hooks/use-table-of-contents-headings | useTableOfContentsHeadings Demos}\n * @since 6.0.0\n */\nexport function useTableOfContentsHeadings(\n options: TableOfContentsHeadingsOptions = {}\n): TableOfContentsHeadings {\n const {\n selector = DEFAULT_HEADING_SELECTOR,\n getDepth = DEFAULT_GET_HEADING_DEPTH,\n getHeadingText = DEFAULT_GET_HEADING_TEXT,\n } = options;\n const ssr = useSsr();\n const [headings, setHeadings] = useState(() =>\n getTableOfContentsHeadings({\n ssr,\n selector,\n getDepth,\n getHeadingText,\n })\n );\n useEffect(() => {\n setHeadings(\n getTableOfContentsHeadings({ ssr, selector, getDepth, getHeadingText })\n );\n }, [getDepth, getHeadingText, selector, ssr]);\n\n return headings;\n}\n"],"names":["useEffect","useState","useSsr","getTableOfContentsHeadings","DEFAULT_HEADING_SELECTOR","DEFAULT_GET_HEADING_DEPTH","element","depth","Number","parseInt","tagName","slice","isNaN","DEFAULT_GET_HEADING_TEXT","textContent","useTableOfContentsHeadings","options","selector","getDepth","getHeadingText","ssr","headings","setHeadings"],"mappings":"AAAA;AAEA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,QAAQ;AAE5C,SAASC,MAAM,QAAQ,oBAAoB;AAC3C,SAASC,0BAA0B,QAAQ,kCAAkC;AAM7E;;;;;CAKC,GACD,OAAO,MAAMC,2BACX,4EAA4E;AAE9E;;;;;CAKC,GACD,OAAO,MAAMC,4BAA4B,CAACC;IACxC,MAAMC,QAAQC,OAAOC,QAAQ,CAACH,QAAQI,OAAO,CAACC,KAAK,CAAC;IACpD,OAAOH,OAAOI,KAAK,CAACL,SAAS,IAAIA;AACnC,EAAE;AAEF;;CAEC,GACD,OAAO,MAAMM,2BAA2B,CAACP,UACvCA,QAAQQ,WAAW,IAAI,GAAG;AAE5B;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,OAAO,SAASC,2BACdC,UAA0C,CAAC,CAAC;IAE5C,MAAM,EACJC,WAAWb,wBAAwB,EACnCc,WAAWb,yBAAyB,EACpCc,iBAAiBN,wBAAwB,EAC1C,GAAGG;IACJ,MAAMI,MAAMlB;IACZ,MAAM,CAACmB,UAAUC,YAAY,GAAGrB,SAAS,IACvCE,2BAA2B;YACzBiB;YACAH;YACAC;YACAC;QACF;IAEFnB,UAAU;QACRsB,YACEnB,2BAA2B;YAAEiB;YAAKH;YAAUC;YAAUC;QAAe;IAEzE,GAAG;QAACD;QAAUC;QAAgBF;QAAUG;KAAI;IAE5C,OAAOC;AACT"}
|
package/dist/navigation/utils.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 6.0.0
|
|
3
3
|
*/ export function getHrefFromParents(parents) {
|
|
4
|
-
|
|
4
|
+
let result = "";
|
|
5
|
+
for (const parent of parents){
|
|
5
6
|
if ("href" in parent && parent.href) {
|
|
6
7
|
const { href } = parent;
|
|
7
|
-
|
|
8
|
+
result += href;
|
|
8
9
|
}
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
}
|
|
11
|
+
return result;
|
|
11
12
|
}
|
|
12
13
|
/**
|
|
13
14
|
* @since 6.0.0
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
* @since 6.0.0
|
|
22
23
|
*/ export function getPartsFromPathname(pathname) {
|
|
23
24
|
// remove trailing slashes just in case there aren't rewrites in place
|
|
24
|
-
const href = pathname.
|
|
25
|
+
const href = pathname.replaceAll(/\/{2,}/g, "/").replace(/\/+$/, "");
|
|
25
26
|
const parts = href.split("/");
|
|
26
27
|
const set = new Set();
|
|
27
28
|
let prefix = "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/navigation/utils.ts"],"sourcesContent":["import { type NavigationItem } from \"./types.js\";\n\n/**\n * @since 6.0.0\n */\nexport function getHrefFromParents(parents: readonly NavigationItem[]): string {\n
|
|
1
|
+
{"version":3,"sources":["../../src/navigation/utils.ts"],"sourcesContent":["import { type NavigationItem } from \"./types.js\";\n\n/**\n * @since 6.0.0\n */\nexport function getHrefFromParents(parents: readonly NavigationItem[]): string {\n let result = \"\";\n for (const parent of parents) {\n if (\"href\" in parent && parent.href) {\n const { href } = parent;\n result += href;\n }\n }\n\n return result;\n}\n\n/**\n * @since 6.0.0\n */\nexport function getNavigationGroupId(\n group: NavigationItem,\n parents: readonly NavigationItem[]\n): string {\n if (\"id\" in group && typeof group.id === \"string\" && group.id) {\n return group.id;\n }\n\n return getHrefFromParents(parents);\n}\n\n/**\n * @since 6.0.0\n */\nexport function getPartsFromPathname(pathname: string): ReadonlySet<string> {\n // remove trailing slashes just in case there aren't rewrites in place\n const href = pathname.replaceAll(/\\/{2,}/g, \"/\").replace(/\\/+$/, \"\");\n const parts = href.split(\"/\");\n const set = new Set<string>();\n let prefix = \"\";\n for (const part of parts) {\n const slashed = `/${part}`;\n prefix = prefix === \"/\" ? slashed : prefix + slashed;\n set.add(prefix);\n }\n\n return set;\n}\n"],"names":["getHrefFromParents","parents","result","parent","href","getNavigationGroupId","group","id","getPartsFromPathname","pathname","replaceAll","replace","parts","split","set","Set","prefix","part","slashed","add"],"mappings":"AAEA;;CAEC,GACD,OAAO,SAASA,mBAAmBC,OAAkC;IACnE,IAAIC,SAAS;IACb,KAAK,MAAMC,UAAUF,QAAS;QAC5B,IAAI,UAAUE,UAAUA,OAAOC,IAAI,EAAE;YACnC,MAAM,EAAEA,IAAI,EAAE,GAAGD;YACjBD,UAAUE;QACZ;IACF;IAEA,OAAOF;AACT;AAEA;;CAEC,GACD,OAAO,SAASG,qBACdC,KAAqB,EACrBL,OAAkC;IAElC,IAAI,QAAQK,SAAS,OAAOA,MAAMC,EAAE,KAAK,YAAYD,MAAMC,EAAE,EAAE;QAC7D,OAAOD,MAAMC,EAAE;IACjB;IAEA,OAAOP,mBAAmBC;AAC5B;AAEA;;CAEC,GACD,OAAO,SAASO,qBAAqBC,QAAgB;IACnD,sEAAsE;IACtE,MAAML,OAAOK,SAASC,UAAU,CAAC,WAAW,KAAKC,OAAO,CAAC,QAAQ;IACjE,MAAMC,QAAQR,KAAKS,KAAK,CAAC;IACzB,MAAMC,MAAM,IAAIC;IAChB,IAAIC,SAAS;IACb,KAAK,MAAMC,QAAQL,MAAO;QACxB,MAAMM,UAAU,CAAC,CAAC,EAAED,MAAM;QAC1BD,SAASA,WAAW,MAAME,UAAUF,SAASE;QAC7CJ,IAAIK,GAAG,CAACH;IACV;IAEA,OAAOF;AACT"}
|
|
@@ -3,7 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { createContext, useContext, useEffect, useState } from "react";
|
|
4
4
|
export const PORTAL_CONTAINER_ID = "rmd-portal-container";
|
|
5
5
|
let portalContainer = null;
|
|
6
|
-
const getPortalContainer = ()=>
|
|
6
|
+
const getPortalContainer = ()=>globalThis.window === undefined ? null : document.body;
|
|
7
7
|
const context = /*#__PURE__*/ createContext(getPortalContainer());
|
|
8
8
|
context.displayName = "PortalContainer";
|
|
9
9
|
const { Provider } = context;
|
|
@@ -32,7 +32,7 @@ const { Provider } = context;
|
|
|
32
32
|
setValue(container.current);
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
|
-
if (
|
|
35
|
+
if (container !== undefined) {
|
|
36
36
|
setValue(container);
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
@@ -41,11 +41,13 @@ const { Provider } = context;
|
|
|
41
41
|
portalContainer.id = PORTAL_CONTAINER_ID;
|
|
42
42
|
}
|
|
43
43
|
if (!document.body.contains(portalContainer)) {
|
|
44
|
-
document.body.
|
|
44
|
+
document.body.append(portalContainer);
|
|
45
45
|
}
|
|
46
46
|
setValue(portalContainer);
|
|
47
47
|
return ()=>{
|
|
48
48
|
if (portalContainer && document.body.contains(portalContainer)) {
|
|
49
|
+
// can't use `portalContainer.remove()` since `DocumentFragment` does not have `.remove()`
|
|
50
|
+
// eslint-disable-next-line unicorn/prefer-dom-node-remove
|
|
49
51
|
document.body.removeChild(portalContainer);
|
|
50
52
|
}
|
|
51
53
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/portal/PortalContainerProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ReactElement,\n type ReactNode,\n type RefObject,\n createContext,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\n/**\n * @internal\n * @since 6.0.0\n */\nexport type PortalContainerNode = Element | DocumentFragment | null;\n\n/**\n * @internal\n * @since 6.0.0\n */\nexport type PortalContainer =\n | PortalContainerNode\n | RefObject<PortalContainerNode>;\n\nexport const PORTAL_CONTAINER_ID = \"rmd-portal-container\";\n\nlet portalContainer: PortalContainerNode = null;\n\nconst getPortalContainer = (): PortalContainerNode =>\n
|
|
1
|
+
{"version":3,"sources":["../../src/portal/PortalContainerProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ReactElement,\n type ReactNode,\n type RefObject,\n createContext,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\n/**\n * @internal\n * @since 6.0.0\n */\nexport type PortalContainerNode = Element | DocumentFragment | null;\n\n/**\n * @internal\n * @since 6.0.0\n */\nexport type PortalContainer =\n | PortalContainerNode\n | RefObject<PortalContainerNode>;\n\nexport const PORTAL_CONTAINER_ID = \"rmd-portal-container\";\n\nlet portalContainer: PortalContainerNode = null;\n\nconst getPortalContainer = (): PortalContainerNode =>\n globalThis.window === undefined ? null : document.body;\n\nconst context = createContext<PortalContainerNode>(getPortalContainer());\ncontext.displayName = \"PortalContainer\";\nconst { Provider } = context;\n\n/**\n * @internal\n * @since 6.0.0\n */\nexport function usePortalContainer(): PortalContainerNode {\n return useContext(context);\n}\n\n/** @since 6.0.0 */\nexport interface PortalContainerProviderProps {\n /**\n * An optional container element to use. When this is `undefined`, a\n * `<div id=\"rmd-portal-container\"></div>` will be added as the last child to\n * the `document.body` and be used as the container element.\n */\n container?: PortalContainer;\n children: ReactNode;\n}\n\n/**\n * **Client Component**\n *\n * This component allows for all child `Portal` components to render within the\n * same container element. If a custom `container` element is not provided, a\n * `<div id=\"rmd-portal-container\"></div>` will be added as the last child to\n * the `document.body` and be used as the container element.\n *\n * @see {@link https://react-md.dev/components/portal | Portal Demos}\n * @see {@link Portal}\n * @since 6.0.0\n */\nexport function PortalContainerProvider(\n props: PortalContainerProviderProps\n): ReactElement {\n const { container, children } = props;\n const [value, setValue] = useState<PortalContainerNode>(portalContainer);\n useEffect(() => {\n if (container && \"current\" in container) {\n setValue(container.current);\n return;\n }\n\n if (container !== undefined) {\n setValue(container);\n return;\n }\n\n if (!portalContainer) {\n portalContainer = document.createElement(\"div\");\n portalContainer.id = PORTAL_CONTAINER_ID;\n }\n if (!document.body.contains(portalContainer)) {\n document.body.append(portalContainer);\n }\n\n setValue(portalContainer);\n\n return () => {\n if (portalContainer && document.body.contains(portalContainer)) {\n // can't use `portalContainer.remove()` since `DocumentFragment` does not have `.remove()`\n // eslint-disable-next-line unicorn/prefer-dom-node-remove\n document.body.removeChild(portalContainer);\n }\n };\n }, [container]);\n\n const containerValue =\n (container && \"current\" in container) || !container ? value : container;\n return <Provider value={containerValue}>{children}</Provider>;\n}\n"],"names":["createContext","useContext","useEffect","useState","PORTAL_CONTAINER_ID","portalContainer","getPortalContainer","globalThis","window","undefined","document","body","context","displayName","Provider","usePortalContainer","PortalContainerProvider","props","container","children","value","setValue","current","createElement","id","contains","append","removeChild","containerValue"],"mappings":"AAAA;;AAEA,SAIEA,aAAa,EACbC,UAAU,EACVC,SAAS,EACTC,QAAQ,QACH,QAAQ;AAgBf,OAAO,MAAMC,sBAAsB,uBAAuB;AAE1D,IAAIC,kBAAuC;AAE3C,MAAMC,qBAAqB,IACzBC,WAAWC,MAAM,KAAKC,YAAY,OAAOC,SAASC,IAAI;AAExD,MAAMC,wBAAUZ,cAAmCM;AACnDM,QAAQC,WAAW,GAAG;AACtB,MAAM,EAAEC,QAAQ,EAAE,GAAGF;AAErB;;;CAGC,GACD,OAAO,SAASG;IACd,OAAOd,WAAWW;AACpB;AAaA;;;;;;;;;;;CAWC,GACD,OAAO,SAASI,wBACdC,KAAmC;IAEnC,MAAM,EAAEC,SAAS,EAAEC,QAAQ,EAAE,GAAGF;IAChC,MAAM,CAACG,OAAOC,SAAS,GAAGlB,SAA8BE;IACxDH,UAAU;QACR,IAAIgB,aAAa,aAAaA,WAAW;YACvCG,SAASH,UAAUI,OAAO;YAC1B;QACF;QAEA,IAAIJ,cAAcT,WAAW;YAC3BY,SAASH;YACT;QACF;QAEA,IAAI,CAACb,iBAAiB;YACpBA,kBAAkBK,SAASa,aAAa,CAAC;YACzClB,gBAAgBmB,EAAE,GAAGpB;QACvB;QACA,IAAI,CAACM,SAASC,IAAI,CAACc,QAAQ,CAACpB,kBAAkB;YAC5CK,SAASC,IAAI,CAACe,MAAM,CAACrB;QACvB;QAEAgB,SAAShB;QAET,OAAO;YACL,IAAIA,mBAAmBK,SAASC,IAAI,CAACc,QAAQ,CAACpB,kBAAkB;gBAC9D,0FAA0F;gBAC1F,0DAA0D;gBAC1DK,SAASC,IAAI,CAACgB,WAAW,CAACtB;YAC5B;QACF;IACF,GAAG;QAACa;KAAU;IAEd,MAAMU,iBACJ,AAACV,aAAa,aAAaA,aAAc,CAACA,YAAYE,QAAQF;IAChE,qBAAO,KAACJ;QAASM,OAAOQ;kBAAiBT;;AAC3C"}
|
|
@@ -57,10 +57,8 @@ import { findSizingContainer, getElementRect, getTransformOrigin } from "./utils
|
|
|
57
57
|
const { element, anchor = BELOW_CENTER_ANCHOR, initialX, vwMargin = 16, vhMargin = 16, xMargin = 0, yMargin = 0, width: widthType = "auto", preventOverlap = false, transformOrigin = false, disableSwapping = false, disableVHBounds = false } = options;
|
|
58
58
|
let { initialY } = options;
|
|
59
59
|
const container = findSizingContainer(options.container);
|
|
60
|
-
if (process.env.NODE_ENV !== "production") {
|
|
61
|
-
|
|
62
|
-
throw new Error('Unable to prevent overlap when the vertical anchor is not `"above"` or `"below"`');
|
|
63
|
-
}
|
|
60
|
+
if (process.env.NODE_ENV !== "production" && preventOverlap && anchor.y !== "above" && anchor.y !== "below") {
|
|
61
|
+
throw new Error('Unable to prevent overlap when the vertical anchor is not `"above"` or `"below"`');
|
|
64
62
|
}
|
|
65
63
|
if (!element) {
|
|
66
64
|
return {
|