@react-md/core 6.5.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/_utils.scss +2 -1
- 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/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/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/chip/Chip.js +1 -1
- package/dist/chip/Chip.js.map +1 -1
- 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/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.js +5 -5
- package/dist/form/Select.js.map +1 -1
- 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/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/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/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/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/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/package.json +3 -1
- 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 +5 -5
- package/src/form/formConfig.ts +1 -1
- package/src/form/inputToggleStyles.ts +9 -4
- 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
- package/dist/form/defaultGetSelectedOptionChildren.d.ts +0 -1
- package/dist/form/getSelectedOptionChildren.d.ts +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/typography/SrOnly.tsx"],"sourcesContent":["import { type ElementType, type HTMLAttributes, forwardRef } from \"react\";\n\nimport { cssUtils } from \"../cssUtils.js\";\nimport {\n type CustomTypographyComponent,\n type TypographyHTMLElement,\n} from \"./Typography.js\";\n\nexport interface SrOnlyProps extends HTMLAttributes<TypographyHTMLElement> {\n /** @defaultValue `\"span\"` */\n as?: CustomTypographyComponent;\n\n /**\n * Set this to `true` if the content should only be screen reader only text on\n * phones. This is useful for only displaying an icon on phones when there is\n * limited space and then displaying an icon and text on larger devices.\n *\n * @defaultValue `false`\n */\n phoneOnly?: boolean;\n\n /**\n * Set this to `true` if the element should be keyboard focusable.\n *\n * @defaultValue `false`\n */\n focusable?: boolean;\n}\n\n/**\n * The `SrOnly` component is used to render content that is only visible to\n * screen readers.\n *\n * @example Simple Example\n * ```tsx\n * import { SrOnly } from \"@react-md/core/typography/SrOnly\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * return (\n * <>\n * <SrOnly>\n * I am only visible to screen readers.\n * </SrOnly>\n * <SrOnly focusable>\n * I am only visible to screen readers but can be focused.\n * </SrOnly>\n * </>\n * );\n * }\n * ```\n *\n * @see {@link https://react-md.dev/components/sr-only | SrOnly Demos}\n */\nexport const SrOnly = forwardRef<TypographyHTMLElement, SrOnlyProps>(\n function SrOnly(props, ref) {\n const {\n as: AsComponent = \"span\",\n className,\n phoneOnly,\n focusable,\n children,\n tabIndex,\n ...remaining\n } = props;\n\n // do some type-casting so ref works\n const Component = AsComponent as ElementType;\n\n return (\n <Component\n {...remaining}\n ref={ref}\n tabIndex={tabIndex ?? (focusable ? 0 : undefined)}\n className={cssUtils({\n srOnly
|
|
1
|
+
{"version":3,"sources":["../../src/typography/SrOnly.tsx"],"sourcesContent":["import { type ElementType, type HTMLAttributes, forwardRef } from \"react\";\n\nimport { type SrOnlyBehavior, cssUtils } from \"../cssUtils.js\";\nimport {\n type CustomTypographyComponent,\n type TypographyHTMLElement,\n} from \"./Typography.js\";\n\nexport interface SrOnlyProps extends HTMLAttributes<TypographyHTMLElement> {\n /** @defaultValue `\"span\"` */\n as?: CustomTypographyComponent;\n\n /**\n * Set this to `true` if the content should only be screen reader only text on\n * phones. This is useful for only displaying an icon on phones when there is\n * limited space and then displaying an icon and text on larger devices.\n *\n * @defaultValue `false`\n */\n phoneOnly?: boolean;\n\n /**\n * Set this to `true` if the element should be keyboard focusable.\n *\n * @defaultValue `false`\n */\n focusable?: boolean;\n}\n\n/**\n * The `SrOnly` component is used to render content that is only visible to\n * screen readers.\n *\n * @example Simple Example\n * ```tsx\n * import { SrOnly } from \"@react-md/core/typography/SrOnly\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * return (\n * <>\n * <SrOnly>\n * I am only visible to screen readers.\n * </SrOnly>\n * <SrOnly focusable>\n * I am only visible to screen readers but can be focused.\n * </SrOnly>\n * </>\n * );\n * }\n * ```\n *\n * @see {@link https://react-md.dev/components/sr-only | SrOnly Demos}\n */\nexport const SrOnly = forwardRef<TypographyHTMLElement, SrOnlyProps>(\n function SrOnly(props, ref) {\n const {\n as: AsComponent = \"span\",\n className,\n phoneOnly,\n focusable,\n children,\n tabIndex,\n ...remaining\n } = props;\n\n // do some type-casting so ref works\n const Component = AsComponent as ElementType;\n\n let srOnly: SrOnlyBehavior = true;\n if (focusable) {\n srOnly = \"focusable\";\n } else if (phoneOnly) {\n srOnly = \"phone\";\n }\n\n return (\n <Component\n {...remaining}\n ref={ref}\n tabIndex={tabIndex ?? (focusable ? 0 : undefined)}\n className={cssUtils({\n srOnly,\n className,\n })}\n >\n {children}\n </Component>\n );\n }\n);\n"],"names":["forwardRef","cssUtils","SrOnly","props","ref","as","AsComponent","className","phoneOnly","focusable","children","tabIndex","remaining","Component","srOnly","undefined"],"mappings":";AAAA,SAAgDA,UAAU,QAAQ,QAAQ;AAE1E,SAA8BC,QAAQ,QAAQ,iBAAiB;AA2B/D;;;;;;;;;;;;;;;;;;;;;;;;CAwBC,GACD,OAAO,MAAMC,uBAASF,WACpB,SAASE,OAAOC,KAAK,EAAEC,GAAG;IACxB,MAAM,EACJC,IAAIC,cAAc,MAAM,EACxBC,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,QAAQ,EACRC,QAAQ,EACR,GAAGC,WACJ,GAAGT;IAEJ,oCAAoC;IACpC,MAAMU,YAAYP;IAElB,IAAIQ,SAAyB;IAC7B,IAAIL,WAAW;QACbK,SAAS;IACX,OAAO,IAAIN,WAAW;QACpBM,SAAS;IACX;IAEA,qBACE,KAACD;QACE,GAAGD,SAAS;QACbR,KAAKA;QACLO,UAAUA,YAAaF,CAAAA,YAAY,IAAIM,SAAQ;QAC/CR,WAAWN,SAAS;YAClBa;YACAP;QACF;kBAECG;;AAGP,GACA"}
|
|
@@ -86,18 +86,18 @@ import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect.js";
|
|
|
86
86
|
});
|
|
87
87
|
useEffect(()=>{
|
|
88
88
|
return ()=>{
|
|
89
|
-
|
|
89
|
+
globalThis.clearTimeout(timeout.current);
|
|
90
90
|
};
|
|
91
91
|
}, []);
|
|
92
92
|
return useMemo(()=>{
|
|
93
93
|
const debounced = (...args)=>{
|
|
94
|
-
|
|
95
|
-
timeout.current =
|
|
94
|
+
globalThis.clearTimeout(timeout.current);
|
|
95
|
+
timeout.current = globalThis.setTimeout(()=>{
|
|
96
96
|
funcRef.current(...args);
|
|
97
97
|
}, wait);
|
|
98
98
|
};
|
|
99
99
|
debounced.cancel = ()=>{
|
|
100
|
-
|
|
100
|
+
globalThis.clearTimeout(timeout.current);
|
|
101
101
|
};
|
|
102
102
|
return debounced;
|
|
103
103
|
}, [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useDebouncedFunction.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef } from \"react\";\n\nimport { type AnyFunction, type DebouncedFunction } from \"./types.js\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect.js\";\n\n/**\n * Creates a function that will only be called if it has not been called again\n * for X milliseconds.\n *\n * @example Debounced Search API Requests\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useDebouncedFunction } from \"@react-md/core/useDebouncedFunction\";\n * import { useUnmounted } from \"@react-md/core/useUnmounted\";\n * import { useState } from \"react\";\n * import type { ReactElement } from \"react\";\n *\n * interface State {\n * error?: unknown\n * loading: boolean;\n * results?: {\n * // pretend some search results\n * id: string;\n * name: string;\n * }[];\n * }\n *\n * function Example(): ReactElement {\n * const [state, setState] = useState<State>({\n * loading: false,\n * });\n * // this is only required for async actions\n * const unmounted = useUnmounted();\n *\n * // A new search request will be fired once every 500ms as the user types.\n * // can't use the event here since React uses synthetic events\n * const search = useDebouncedFunction(async (q: string) => {\n * setState({\n * loading: true,\n * error: undefined,\n * results: undefined,\n * });\n *\n * try {\n * const response = await fetch('/search', {\n * method: 'POST',\n * headers: {\n * 'Content-Type': 'application/json',\n * },\n * body: JSON.stringify({ q }),\n * });\n * const json = await response.json();\n *\n * if (!unmounted.current) {\n * setState({\n * loading: false,\n * results: json,\n * });\n * }\n * } catch (error) {\n * if (!unmounted.current) {\n * setState({\n * error,\n * loading: false,\n * });\n * }\n * }\n * }, 500);\n *\n * return (\n * <TextField\n * type=\"search\"\n * label=\"Search\"\n * onChange={(event) => search(event.currentTarget.value)}\n * />\n * );\n * }\n * ```\n *\n * @see `useThrottledFunction` for throttle behavior instead. (Call a\n * function at most once every X milliseconds).\n * @since 6.0.0\n */\nexport function useDebouncedFunction<F extends AnyFunction>(\n func: F,\n wait: number\n): DebouncedFunction<F> {\n const timeout = useRef<
|
|
1
|
+
{"version":3,"sources":["../src/useDebouncedFunction.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef } from \"react\";\n\nimport { type AnyFunction, type DebouncedFunction } from \"./types.js\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect.js\";\n\n/**\n * Creates a function that will only be called if it has not been called again\n * for X milliseconds.\n *\n * @example Debounced Search API Requests\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useDebouncedFunction } from \"@react-md/core/useDebouncedFunction\";\n * import { useUnmounted } from \"@react-md/core/useUnmounted\";\n * import { useState } from \"react\";\n * import type { ReactElement } from \"react\";\n *\n * interface State {\n * error?: unknown\n * loading: boolean;\n * results?: {\n * // pretend some search results\n * id: string;\n * name: string;\n * }[];\n * }\n *\n * function Example(): ReactElement {\n * const [state, setState] = useState<State>({\n * loading: false,\n * });\n * // this is only required for async actions\n * const unmounted = useUnmounted();\n *\n * // A new search request will be fired once every 500ms as the user types.\n * // can't use the event here since React uses synthetic events\n * const search = useDebouncedFunction(async (q: string) => {\n * setState({\n * loading: true,\n * error: undefined,\n * results: undefined,\n * });\n *\n * try {\n * const response = await fetch('/search', {\n * method: 'POST',\n * headers: {\n * 'Content-Type': 'application/json',\n * },\n * body: JSON.stringify({ q }),\n * });\n * const json = await response.json();\n *\n * if (!unmounted.current) {\n * setState({\n * loading: false,\n * results: json,\n * });\n * }\n * } catch (error) {\n * if (!unmounted.current) {\n * setState({\n * error,\n * loading: false,\n * });\n * }\n * }\n * }, 500);\n *\n * return (\n * <TextField\n * type=\"search\"\n * label=\"Search\"\n * onChange={(event) => search(event.currentTarget.value)}\n * />\n * );\n * }\n * ```\n *\n * @see `useThrottledFunction` for throttle behavior instead. (Call a\n * function at most once every X milliseconds).\n * @since 6.0.0\n */\nexport function useDebouncedFunction<F extends AnyFunction>(\n func: F,\n wait: number\n): DebouncedFunction<F> {\n const timeout = useRef<NodeJS.Timeout>();\n const funcRef = useRef(func);\n useIsomorphicLayoutEffect(() => {\n funcRef.current = func;\n });\n\n useEffect(() => {\n return () => {\n globalThis.clearTimeout(timeout.current);\n };\n }, []);\n\n return useMemo(() => {\n const debounced: DebouncedFunction<F> = (...args) => {\n globalThis.clearTimeout(timeout.current);\n timeout.current = globalThis.setTimeout(() => {\n funcRef.current(...args);\n }, wait);\n };\n debounced.cancel = () => {\n globalThis.clearTimeout(timeout.current);\n };\n\n return debounced;\n }, [wait]);\n}\n"],"names":["useEffect","useMemo","useRef","useIsomorphicLayoutEffect","useDebouncedFunction","func","wait","timeout","funcRef","current","globalThis","clearTimeout","debounced","args","setTimeout","cancel"],"mappings":"AAAA;AAEA,SAASA,SAAS,EAAEC,OAAO,EAAEC,MAAM,QAAQ,QAAQ;AAGnD,SAASC,yBAAyB,QAAQ,iCAAiC;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6EC,GACD,OAAO,SAASC,qBACdC,IAAO,EACPC,IAAY;IAEZ,MAAMC,UAAUL;IAChB,MAAMM,UAAUN,OAAOG;IACvBF,0BAA0B;QACxBK,QAAQC,OAAO,GAAGJ;IACpB;IAEAL,UAAU;QACR,OAAO;YACLU,WAAWC,YAAY,CAACJ,QAAQE,OAAO;QACzC;IACF,GAAG,EAAE;IAEL,OAAOR,QAAQ;QACb,MAAMW,YAAkC,CAAC,GAAGC;YAC1CH,WAAWC,YAAY,CAACJ,QAAQE,OAAO;YACvCF,QAAQE,OAAO,GAAGC,WAAWI,UAAU,CAAC;gBACtCN,QAAQC,OAAO,IAAII;YACrB,GAAGP;QACL;QACAM,UAAUG,MAAM,GAAG;YACjBL,WAAWC,YAAY,CAACJ,QAAQE,OAAO;QACzC;QAEA,OAAOG;IACT,GAAG;QAACN;KAAK;AACX"}
|
package/dist/useDropzone.js
CHANGED
|
@@ -85,8 +85,8 @@ const noop = ()=>{
|
|
|
85
85
|
// instead. The `dragover` event will continually fire within the window
|
|
86
86
|
// until the user drops the file or moves the file outside of the window.
|
|
87
87
|
const delayedStopDragging = useCallback(()=>{
|
|
88
|
-
|
|
89
|
-
draggingTimeout.current =
|
|
88
|
+
globalThis.clearTimeout(draggingTimeout.current);
|
|
89
|
+
draggingTimeout.current = globalThis.setTimeout(()=>{
|
|
90
90
|
stopDragging();
|
|
91
91
|
}, 100);
|
|
92
92
|
}, [
|
|
@@ -96,12 +96,12 @@ const noop = ()=>{
|
|
|
96
96
|
if (disableDragging) {
|
|
97
97
|
return;
|
|
98
98
|
}
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
globalThis.addEventListener("dragenter", startDragging);
|
|
100
|
+
globalThis.addEventListener("dragover", delayedStopDragging);
|
|
101
101
|
return ()=>{
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
globalThis.clearTimeout(draggingTimeout.current);
|
|
103
|
+
globalThis.removeEventListener("dragenter", startDragging);
|
|
104
|
+
globalThis.removeEventListener("dragover", delayedStopDragging);
|
|
105
105
|
};
|
|
106
106
|
}, [
|
|
107
107
|
delayedStopDragging,
|
|
@@ -122,7 +122,7 @@ const noop = ()=>{
|
|
|
122
122
|
onDrop (event) {
|
|
123
123
|
event.preventDefault();
|
|
124
124
|
event.stopPropagation();
|
|
125
|
-
|
|
125
|
+
globalThis.clearTimeout(draggingTimeout.current);
|
|
126
126
|
onDrop(event);
|
|
127
127
|
setOver(false);
|
|
128
128
|
stopDragging();
|
|
@@ -130,7 +130,7 @@ const noop = ()=>{
|
|
|
130
130
|
onDragOver (event) {
|
|
131
131
|
event.preventDefault();
|
|
132
132
|
event.stopPropagation();
|
|
133
|
-
|
|
133
|
+
globalThis.clearTimeout(draggingTimeout.current);
|
|
134
134
|
onDragOver(event);
|
|
135
135
|
setOver(true);
|
|
136
136
|
},
|
package/dist/useDropzone.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useDropzone.ts"],"sourcesContent":["\"use client\";\n\nimport {\n type DragEvent,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\n\nimport { useToggle } from \"./useToggle.js\";\n\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * @since 5.1.3\n * @since 6.0.0 The element type is dynamically inferred on each handler\n * instead of the `DropzoneHandlers` type.\n */\nexport interface DropzoneHandlers {\n onDrop: <E extends HTMLElement>(event: DragEvent<E>) => void;\n onDragEnter?: <E extends HTMLElement>(event: DragEvent<E>) => void;\n onDragOver?: <E extends HTMLElement>(event: DragEvent<E>) => void;\n onDragLeave?: <E extends HTMLElement>(event: DragEvent<E>) => void;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface DropzoneOptions extends DropzoneHandlers {\n /**\n * By default, the `useDropzone` hook will listen to any `dragenter`/`dragover`\n * events on the page and enabling the {@link DragHookReturnValue.isDragging}\n * flag to show that the user is dragging _something_ and they might want to\n * drag that something into the dropzone.\n *\n * So set this option to `true` if that behavior is not required and only\n * drag events on the dropzone element need to be captured.\n *\n * @defaultValue `false`\n * @see {@link DropzoneImplementation.isDragging}\n */\n disableDragging?: boolean;\n}\n\n/**\n * @since 2.9.0\n * @since 6.0.0 Renamed from `DropzoneHookReturnValue` to\n * `DropzoneImplementation` to match other naming conventions. Returns an\n * object instead of an ordered array of `[isOver: boolean, dropzoneHandlers:\n * DropzoneHandlers]`. Also returns a new `isDragging` state.\n */\nexport interface DropzoneImplementation {\n /**\n * This will be `true` when the user is dragging something over the dropzone\n * target.\n */\n isOver: boolean;\n\n /**\n * This will be `true` when the user is dragging anything within the document.\n * The main use case for this is detecting when a user is dragging a file into\n * the document so you can help highlight the dropzone area.\n *\n * This will always be `false` if {@link DropzoneOptions.disableDragging} is\n * `true`.\n */\n isDragging: boolean;\n\n /**\n * The event handlers that should be passed to the dropzone target.\n */\n dropzoneHandlers: Required<DropzoneHandlers>;\n}\n\n/**\n * @example Simple Example\n * ```tsx\n * import { useFileUpload } from \"@react-md/core/files/useFileUpload\";\n * import { useDropzone } from \"@react-md/core/useDropzone\";\n * import { type CSSProperties, type ReactElement } from \"react\";\n *\n * const style: CSSProperties = {\n * border: '1px solid blue',\n * };\n *\n * function Example(): ReactElement {\n * const { onDrop } = useFileUpload()\n * const { isOver, dropzoneHandlers } = useDropzone({\n * onDrop(event) {\n * // normally use the `onDrop` behavior from `useFileUpload` to upload\n * // files:\n * // onDrop(event);\n * },\n * disableDragging: true,\n * });\n *\n * return (\n * <div {...dropzoneHandlers} style={isOver ? style : {}}>\n * Drag and drop some files!\n * {isOver && <UploadSVGIcon />}\n * </div>\n * );\n * }\n * ```\n *\n * @example Dragging Example\n * ```tsx\n * import { useFileUpload } from \"@react-md/core/files/useFileUpload\";\n * import { useDropzone } from \"@react-md/core/useDropzone\";\n * import { type CSSProperties, type ReactElement } from \"react\";\n *\n * const draggingStyle: CSSProperties = {\n * backgroundColor: \"orange\",\n * };\n * const overStyle: CSSProperties = {\n * border: '1px solid blue',\n * };\n *\n * function Example(): ReactElement {\n * const { onDrop } = useFileUpload()\n * const { isOver, isDragging, dropzoneHandlers } = useDropzone({\n * onDrop(event) {\n * // normally use the `onDrop` behavior from `useFileUpload` to upload\n * // files:\n * // onDrop(event);\n * },\n * });\n *\n * return (\n * <div\n * {...dropzoneHandlers}\n * style={{\n * ...(isDragging && draggingStyle),\n * ...(isOver && overStyle),\n * }}\n * >\n * Drag and drop some files!\n * {isOver && <UploadSVGIcon />}\n * </div>\n * );\n * }\n * ```\n *\n * @since 2.9.0\n * @since 6.0.0 Supports document-level dragging flag;\n */\nexport function useDropzone(options: DropzoneOptions): DropzoneImplementation {\n const {\n onDrop,\n onDragOver = noop,\n onDragEnter = noop,\n onDragLeave = noop,\n disableDragging = false,\n } = options;\n\n const [isOver, setOver] = useState(false);\n const {\n toggled: isDragging,\n enable: startDragging,\n disable: stopDragging,\n } = useToggle();\n const draggingTimeout = useRef<
|
|
1
|
+
{"version":3,"sources":["../src/useDropzone.ts"],"sourcesContent":["\"use client\";\n\nimport {\n type DragEvent,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\n\nimport { useToggle } from \"./useToggle.js\";\n\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * @since 5.1.3\n * @since 6.0.0 The element type is dynamically inferred on each handler\n * instead of the `DropzoneHandlers` type.\n */\nexport interface DropzoneHandlers {\n onDrop: <E extends HTMLElement>(event: DragEvent<E>) => void;\n onDragEnter?: <E extends HTMLElement>(event: DragEvent<E>) => void;\n onDragOver?: <E extends HTMLElement>(event: DragEvent<E>) => void;\n onDragLeave?: <E extends HTMLElement>(event: DragEvent<E>) => void;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface DropzoneOptions extends DropzoneHandlers {\n /**\n * By default, the `useDropzone` hook will listen to any `dragenter`/`dragover`\n * events on the page and enabling the {@link DragHookReturnValue.isDragging}\n * flag to show that the user is dragging _something_ and they might want to\n * drag that something into the dropzone.\n *\n * So set this option to `true` if that behavior is not required and only\n * drag events on the dropzone element need to be captured.\n *\n * @defaultValue `false`\n * @see {@link DropzoneImplementation.isDragging}\n */\n disableDragging?: boolean;\n}\n\n/**\n * @since 2.9.0\n * @since 6.0.0 Renamed from `DropzoneHookReturnValue` to\n * `DropzoneImplementation` to match other naming conventions. Returns an\n * object instead of an ordered array of `[isOver: boolean, dropzoneHandlers:\n * DropzoneHandlers]`. Also returns a new `isDragging` state.\n */\nexport interface DropzoneImplementation {\n /**\n * This will be `true` when the user is dragging something over the dropzone\n * target.\n */\n isOver: boolean;\n\n /**\n * This will be `true` when the user is dragging anything within the document.\n * The main use case for this is detecting when a user is dragging a file into\n * the document so you can help highlight the dropzone area.\n *\n * This will always be `false` if {@link DropzoneOptions.disableDragging} is\n * `true`.\n */\n isDragging: boolean;\n\n /**\n * The event handlers that should be passed to the dropzone target.\n */\n dropzoneHandlers: Required<DropzoneHandlers>;\n}\n\n/**\n * @example Simple Example\n * ```tsx\n * import { useFileUpload } from \"@react-md/core/files/useFileUpload\";\n * import { useDropzone } from \"@react-md/core/useDropzone\";\n * import { type CSSProperties, type ReactElement } from \"react\";\n *\n * const style: CSSProperties = {\n * border: '1px solid blue',\n * };\n *\n * function Example(): ReactElement {\n * const { onDrop } = useFileUpload()\n * const { isOver, dropzoneHandlers } = useDropzone({\n * onDrop(event) {\n * // normally use the `onDrop` behavior from `useFileUpload` to upload\n * // files:\n * // onDrop(event);\n * },\n * disableDragging: true,\n * });\n *\n * return (\n * <div {...dropzoneHandlers} style={isOver ? style : {}}>\n * Drag and drop some files!\n * {isOver && <UploadSVGIcon />}\n * </div>\n * );\n * }\n * ```\n *\n * @example Dragging Example\n * ```tsx\n * import { useFileUpload } from \"@react-md/core/files/useFileUpload\";\n * import { useDropzone } from \"@react-md/core/useDropzone\";\n * import { type CSSProperties, type ReactElement } from \"react\";\n *\n * const draggingStyle: CSSProperties = {\n * backgroundColor: \"orange\",\n * };\n * const overStyle: CSSProperties = {\n * border: '1px solid blue',\n * };\n *\n * function Example(): ReactElement {\n * const { onDrop } = useFileUpload()\n * const { isOver, isDragging, dropzoneHandlers } = useDropzone({\n * onDrop(event) {\n * // normally use the `onDrop` behavior from `useFileUpload` to upload\n * // files:\n * // onDrop(event);\n * },\n * });\n *\n * return (\n * <div\n * {...dropzoneHandlers}\n * style={{\n * ...(isDragging && draggingStyle),\n * ...(isOver && overStyle),\n * }}\n * >\n * Drag and drop some files!\n * {isOver && <UploadSVGIcon />}\n * </div>\n * );\n * }\n * ```\n *\n * @since 2.9.0\n * @since 6.0.0 Supports document-level dragging flag;\n */\nexport function useDropzone(options: DropzoneOptions): DropzoneImplementation {\n const {\n onDrop,\n onDragOver = noop,\n onDragEnter = noop,\n onDragLeave = noop,\n disableDragging = false,\n } = options;\n\n const [isOver, setOver] = useState(false);\n const {\n toggled: isDragging,\n enable: startDragging,\n disable: stopDragging,\n } = useToggle();\n const draggingTimeout = useRef<NodeJS.Timeout>();\n\n // Browsers sometimes don't trigger a dragleave event for the entire\n // document, so we have to work around that by using the `dragover` event\n // instead. The `dragover` event will continually fire within the window\n // until the user drops the file or moves the file outside of the window.\n const delayedStopDragging = useCallback(() => {\n globalThis.clearTimeout(draggingTimeout.current);\n draggingTimeout.current = globalThis.setTimeout(() => {\n stopDragging();\n }, 100);\n }, [stopDragging]);\n\n useEffect(() => {\n if (disableDragging) {\n return;\n }\n\n globalThis.addEventListener(\"dragenter\", startDragging);\n globalThis.addEventListener(\"dragover\", delayedStopDragging);\n return () => {\n globalThis.clearTimeout(draggingTimeout.current);\n globalThis.removeEventListener(\"dragenter\", startDragging);\n globalThis.removeEventListener(\"dragover\", delayedStopDragging);\n };\n }, [delayedStopDragging, disableDragging, startDragging]);\n\n return {\n isOver,\n isDragging,\n dropzoneHandlers: {\n // Note: need to call `event.stopPropagation()` and\n // `event.preventDefault())` for each of these handlers to prevent the\n // default browser behavior when dropping. Only calling within `onDrop`\n // does not work.\n //\n // i.e. dropping an image would preview that image in the current\n // window/tab instead of triggering the drop event.\n onDrop(event) {\n event.preventDefault();\n event.stopPropagation();\n\n globalThis.clearTimeout(draggingTimeout.current);\n onDrop(event);\n setOver(false);\n stopDragging();\n },\n onDragOver(event) {\n event.preventDefault();\n event.stopPropagation();\n\n globalThis.clearTimeout(draggingTimeout.current);\n onDragOver(event);\n setOver(true);\n },\n onDragEnter(event) {\n event.preventDefault();\n event.stopPropagation();\n\n onDragEnter(event);\n setOver(true);\n },\n onDragLeave(event) {\n event.preventDefault();\n event.stopPropagation();\n\n onDragLeave(event);\n setOver(false);\n // this stops dragging if the user's File Explorer is somewhat above the dropzone\n // and drags out into the File Explorer\n delayedStopDragging();\n },\n },\n };\n}\n"],"names":["useCallback","useEffect","useRef","useState","useToggle","noop","useDropzone","options","onDrop","onDragOver","onDragEnter","onDragLeave","disableDragging","isOver","setOver","toggled","isDragging","enable","startDragging","disable","stopDragging","draggingTimeout","delayedStopDragging","globalThis","clearTimeout","current","setTimeout","addEventListener","removeEventListener","dropzoneHandlers","event","preventDefault","stopPropagation"],"mappings":"AAAA;AAEA,SAEEA,WAAW,EACXC,SAAS,EACTC,MAAM,EACNC,QAAQ,QACH,QAAQ;AAEf,SAASC,SAAS,QAAQ,iBAAiB;AAE3C,MAAMC,OAAO;AACX,aAAa;AACf;AA+DA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuEC,GACD,OAAO,SAASC,YAAYC,OAAwB;IAClD,MAAM,EACJC,MAAM,EACNC,aAAaJ,IAAI,EACjBK,cAAcL,IAAI,EAClBM,cAAcN,IAAI,EAClBO,kBAAkB,KAAK,EACxB,GAAGL;IAEJ,MAAM,CAACM,QAAQC,QAAQ,GAAGX,SAAS;IACnC,MAAM,EACJY,SAASC,UAAU,EACnBC,QAAQC,aAAa,EACrBC,SAASC,YAAY,EACtB,GAAGhB;IACJ,MAAMiB,kBAAkBnB;IAExB,oEAAoE;IACpE,yEAAyE;IACzE,wEAAwE;IACxE,yEAAyE;IACzE,MAAMoB,sBAAsBtB,YAAY;QACtCuB,WAAWC,YAAY,CAACH,gBAAgBI,OAAO;QAC/CJ,gBAAgBI,OAAO,GAAGF,WAAWG,UAAU,CAAC;YAC9CN;QACF,GAAG;IACL,GAAG;QAACA;KAAa;IAEjBnB,UAAU;QACR,IAAIW,iBAAiB;YACnB;QACF;QAEAW,WAAWI,gBAAgB,CAAC,aAAaT;QACzCK,WAAWI,gBAAgB,CAAC,YAAYL;QACxC,OAAO;YACLC,WAAWC,YAAY,CAACH,gBAAgBI,OAAO;YAC/CF,WAAWK,mBAAmB,CAAC,aAAaV;YAC5CK,WAAWK,mBAAmB,CAAC,YAAYN;QAC7C;IACF,GAAG;QAACA;QAAqBV;QAAiBM;KAAc;IAExD,OAAO;QACLL;QACAG;QACAa,kBAAkB;YAChB,mDAAmD;YACnD,sEAAsE;YACtE,uEAAuE;YACvE,iBAAiB;YACjB,EAAE;YACF,iEAAiE;YACjE,mDAAmD;YACnDrB,QAAOsB,KAAK;gBACVA,MAAMC,cAAc;gBACpBD,MAAME,eAAe;gBAErBT,WAAWC,YAAY,CAACH,gBAAgBI,OAAO;gBAC/CjB,OAAOsB;gBACPhB,QAAQ;gBACRM;YACF;YACAX,YAAWqB,KAAK;gBACdA,MAAMC,cAAc;gBACpBD,MAAME,eAAe;gBAErBT,WAAWC,YAAY,CAACH,gBAAgBI,OAAO;gBAC/ChB,WAAWqB;gBACXhB,QAAQ;YACV;YACAJ,aAAYoB,KAAK;gBACfA,MAAMC,cAAc;gBACpBD,MAAME,eAAe;gBAErBtB,YAAYoB;gBACZhB,QAAQ;YACV;YACAH,aAAYmB,KAAK;gBACfA,MAAMC,cAAc;gBACpBD,MAAME,eAAe;gBAErBrB,YAAYmB;gBACZhB,QAAQ;gBACR,iFAAiF;gBACjF,uCAAuC;gBACvCQ;YACF;QACF;IACF;AACF"}
|
package/dist/useEnsuredState.js
CHANGED
|
@@ -7,18 +7,18 @@
|
|
|
7
7
|
* @since 6.0.0
|
|
8
8
|
*/ export function useEnsuredState(options) {
|
|
9
9
|
const { name = "value", value, setValue, defaultValue } = options;
|
|
10
|
-
if (
|
|
10
|
+
if (value !== undefined && setValue !== undefined) {
|
|
11
11
|
return [
|
|
12
12
|
value,
|
|
13
13
|
setValue
|
|
14
14
|
];
|
|
15
15
|
}
|
|
16
|
-
if (
|
|
17
|
-
const pascalName = name.charAt(0).toUpperCase() + name.
|
|
16
|
+
if (value !== undefined || setValue !== undefined) {
|
|
17
|
+
const pascalName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
18
18
|
throw new Error(`Both a \`${name}\` and \`set${pascalName}\` must be defined for controlled components.`);
|
|
19
19
|
}
|
|
20
|
-
if (
|
|
21
|
-
const pascalName = name.charAt(0).toUpperCase() + name.
|
|
20
|
+
if (defaultValue === undefined) {
|
|
21
|
+
const pascalName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
22
22
|
throw new Error(`A \`default${pascalName}\` must be defined for uncontrolled components.`);
|
|
23
23
|
}
|
|
24
24
|
return useState(defaultValue);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useEnsuredState.ts"],"sourcesContent":["/* eslint-disable react-hooks/rules-of-hooks */\nimport type { Dispatch } from \"react\";\nimport { useState } from \"react\";\n\nimport type { UseStateInitializer, UseStateSetter } from \"./types.js\";\n\n/**\n * @internal\n * @since 6.0.0\n */\nexport interface EnsuredStateOptions<\n V,\n Setter extends Dispatch<V> | UseStateSetter<V> = UseStateSetter<V>,\n> {\n name?: string;\n value?: V;\n setValue?: Setter;\n defaultValue?: UseStateInitializer<V>;\n}\n\n/**\n * This is used to dynamically allow controlling hooks by providing a `value` +\n * `setValue` or defaulting to uncontrolled behavior with local state.\n *\n * @internal\n * @since 6.0.0\n */\nexport function useEnsuredState<\n V,\n Setter extends Dispatch<V> | UseStateSetter<V>,\n>(\n options: EnsuredStateOptions<V, Setter>\n): readonly [value: V, setValue: Setter] {\n const { name = \"value\", value, setValue, defaultValue } = options;\n if (
|
|
1
|
+
{"version":3,"sources":["../src/useEnsuredState.ts"],"sourcesContent":["/* eslint-disable react-hooks/rules-of-hooks */\nimport type { Dispatch } from \"react\";\nimport { useState } from \"react\";\n\nimport type { UseStateInitializer, UseStateSetter } from \"./types.js\";\n\n/**\n * @internal\n * @since 6.0.0\n */\nexport interface EnsuredStateOptions<\n V,\n Setter extends Dispatch<V> | UseStateSetter<V> = UseStateSetter<V>,\n> {\n name?: string;\n value?: V;\n setValue?: Setter;\n defaultValue?: UseStateInitializer<V>;\n}\n\n/**\n * This is used to dynamically allow controlling hooks by providing a `value` +\n * `setValue` or defaulting to uncontrolled behavior with local state.\n *\n * @internal\n * @since 6.0.0\n */\nexport function useEnsuredState<\n V,\n Setter extends Dispatch<V> | UseStateSetter<V>,\n>(\n options: EnsuredStateOptions<V, Setter>\n): readonly [value: V, setValue: Setter] {\n const { name = \"value\", value, setValue, defaultValue } = options;\n if (value !== undefined && setValue !== undefined) {\n return [value, setValue];\n }\n\n if (value !== undefined || setValue !== undefined) {\n const pascalName = name.charAt(0).toUpperCase() + name.slice(1);\n throw new Error(\n `Both a \\`${name}\\` and \\`set${pascalName}\\` must be defined for controlled components.`\n );\n }\n\n if (defaultValue === undefined) {\n const pascalName = name.charAt(0).toUpperCase() + name.slice(1);\n throw new Error(\n `A \\`default${pascalName}\\` must be defined for uncontrolled components.`\n );\n }\n\n return useState(defaultValue) as [value: V, setValue: Setter];\n}\n"],"names":["useState","useEnsuredState","options","name","value","setValue","defaultValue","undefined","pascalName","charAt","toUpperCase","slice","Error"],"mappings":"AAAA,6CAA6C,GAE7C,SAASA,QAAQ,QAAQ,QAAQ;AAkBjC;;;;;;CAMC,GACD,OAAO,SAASC,gBAIdC,OAAuC;IAEvC,MAAM,EAAEC,OAAO,OAAO,EAAEC,KAAK,EAAEC,QAAQ,EAAEC,YAAY,EAAE,GAAGJ;IAC1D,IAAIE,UAAUG,aAAaF,aAAaE,WAAW;QACjD,OAAO;YAACH;YAAOC;SAAS;IAC1B;IAEA,IAAID,UAAUG,aAAaF,aAAaE,WAAW;QACjD,MAAMC,aAAaL,KAAKM,MAAM,CAAC,GAAGC,WAAW,KAAKP,KAAKQ,KAAK,CAAC;QAC7D,MAAM,IAAIC,MACR,CAAC,SAAS,EAAET,KAAK,YAAY,EAAEK,WAAW,6CAA6C,CAAC;IAE5F;IAEA,IAAIF,iBAAiBC,WAAW;QAC9B,MAAMC,aAAaL,KAAKM,MAAM,CAAC,GAAGC,WAAW,KAAKP,KAAKQ,KAAK,CAAC;QAC7D,MAAM,IAAIC,MACR,CAAC,WAAW,EAAEJ,WAAW,+CAA+C,CAAC;IAE7E;IAEA,OAAOR,SAASM;AAClB"}
|
|
@@ -73,7 +73,7 @@ import { useEnsuredRef } from "./useEnsuredRef.js";
|
|
|
73
73
|
element
|
|
74
74
|
];
|
|
75
75
|
}
|
|
76
|
-
if (disabled ||
|
|
76
|
+
if (disabled || targets.length === 0) {
|
|
77
77
|
return;
|
|
78
78
|
}
|
|
79
79
|
let resolvedRoot;
|
|
@@ -96,9 +96,9 @@ import { useEnsuredRef } from "./useEnsuredRef.js";
|
|
|
96
96
|
// - when cleaning up, check if there are any other existing callbacks
|
|
97
97
|
// - disconnect and remove the observer if there are none left
|
|
98
98
|
const observer = new IntersectionObserver(onUpdate, options);
|
|
99
|
-
|
|
99
|
+
for (const target of targets){
|
|
100
100
|
observer.observe(target);
|
|
101
|
-
}
|
|
101
|
+
}
|
|
102
102
|
return ()=>{
|
|
103
103
|
observer.disconnect();
|
|
104
104
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useIntersectionObserver.ts"],"sourcesContent":["\"use client\";\n\nimport { type Ref, type RefCallback, type RefObject } from \"react\";\nimport { useEffect } from \"react\";\n\nimport { useEnsuredRef } from \"./useEnsuredRef.js\";\n\n/** @since 6.0.0 */\nexport type IntersectionObserverRoot = IntersectionObserverInit[\"root\"];\n/** @since 6.0.0 */\nexport type IntersectionObserverThreshold =\n IntersectionObserverInit[\"threshold\"];\n/** @since 6.0.0 */\nexport type IntersectionObserverRootMargin =\n IntersectionObserverInit[\"rootMargin\"];\n\n/**\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#intersection_observer_options}\n * @since 6.0.0\n */\nexport interface BaseIntersectionObserverHookOptions {\n /**\n * This is the same as the normal `root` for an IntersectionObserverInit, but\n * also supports refs.\n */\n root?: RefObject<IntersectionObserverRoot> | IntersectionObserverRoot;\n\n /**\n * Set this to `true` if the intersection observer behavior should be\n * disabled.\n *\n * @defaultValue `false`\n */\n disabled?: boolean;\n\n /**\n * **When using a list of thresholds, they must either be defined outside of\n * the component or wrapped in a `useMemo` to prevent the IntersectionObserver\n * from being re-created each render.**\n *\n * @example Moving Out of Render\n * ```tsx\n * const threshold = [0, 0.25, 0.5, 0.75, 1];\n *\n * function Example() {\n * const targetRef = useIntersectionObserver({\n * threshold,\n * onUpdate: useCallback(([entry]) => {\n * // do something\n * }, []),\n * })\n * }\n * ```\n *\n * @example Wrapping in useMemo\n * ```tsx\n * interface ExampleProps {\n * min: number;\n * max: number;\n * }\n *\n * function Example({ min, max }: ExampleProps): ReactElement {\n * const targetRef = useIntersectionObserver({\n * threshold: useMemo(() => [min, max], [min, max]),\n * onUpdate: useCallback(([entry]) => {\n * // do something\n * }, []),\n * });\n * }\n * ```\n *\n * @see {@link getThreshold}\n */\n threshold?: IntersectionObserverThreshold;\n\n /** @see {@link getRootMargin} */\n rootMargin?: IntersectionObserverRootMargin;\n\n /**\n * **Must be wrapped in `useCallback` to prevent re-creating the\n * IntersectionObserver each render.**\n *\n * This can be used to dynamically generate the {@link threshold} which is\n * generally useful if you need access to the DOM or do some expensive\n * computation.\n *\n * @example Simple Example\n * ```tsx\n * const targetRef = useIntersectionObserver({\n * getThreshold: useCallback(() => {\n * // pretend some expensive computation\n * return [0, 0.25, 0.5, 0.75, 1];\n * }, []),\n * onUpdate: useCallback(() => {\n * // do something\n * }, []),\n * });\n * ```\n *\n * If this option is provided, {@link threshold}'s value will be ignored.\n */\n getThreshold?: () => IntersectionObserverThreshold;\n\n /**\n * **Must be wrapped in `useCallback` to prevent re-creating the\n * IntersectionObserver each render.**\n *\n * This can be used to dynamically generate the {@link rootMargin} which is\n * generally useful if you need access to the DOM.\n *\n * @example Simple Example\n * ```tsx\n * const nodeRef = useRef<HTMLElement>();\n * const targetRef = useIntersectionObserver({\n * getRootMargin: useCallback(() => {\n * return `-${nodeRef.current.offsetHeight - 1}px 0px 0px`;\n * }, []),\n * onUpdate: useCallback(() => {\n * // do something\n * }, []),\n * });\n * ```\n *\n * Note: If this option is provided, {@link rootMargin} will be ignored.\n */\n getRootMargin?: () => IntersectionObserverRootMargin;\n}\n\n/**\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#intersection_observer_options}\n * @since 6.0.0\n */\nexport interface IntersectionObserverHookOptions<\n E extends HTMLElement,\n> extends BaseIntersectionObserverHookOptions {\n /**\n * An optional ref to merge with the ref returned by this hook.\n */\n ref?: Ref<E>;\n\n /**\n * **Must be wrapped in `useCallback` to prevent re-creating the\n * IntersectionObserver each render.**\n *\n * @example Simple Example\n * ```tsx\n * const threshold = [0, 0.25, 0.5, 0.75, 1];\n *\n * function Example(): ReactElement {\n * const [intersecting, setIntersecting] = useState(false);\n * const targetRef = useIntersectionObserver({\n * threshold,\n * onUpdate: useCallback(([entry]) {\n * setIntersecting(entry.isIntersecting);\n * }, []),\n * });\n *\n * // implementation\n * }\n * ```\n */\n onUpdate: (entries: readonly IntersectionObserverEntry[]) => void;\n\n /**\n * **Must be wrapped in `useCallback` to prevent re-creating the\n * IntersectionObserver each render.**\n *\n * If this is defined, the {@link ref} will be ignored along with the returned\n * ref.\n *\n * @example Watching Queried Elements\n * ```tsx\n * function Example(): ReactElement {\n * useIntersectionObserver({\n * onUpdate: useCallback((entries) => {\n * entries.forEach((entry) => {\n * // do stuff\n * });\n *\n * setIntersectingIds(intersecting);\n * }, []),\n * getTargets: useCallback(() => {\n * return document.querySelectorAll('h1, h2, h3, h4, h5, h6');\n * }, []),\n * }),\n *\n * return <div {...props} />;\n * }\n * ```\n */\n getTargets?: () => readonly Element[];\n}\n\n/**\n * @example Simple Example\n * ```tsx\n * // https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#a_simple_example\n *\n * import { useIntersectionObserver } from \"@react-md/core/useIntersectionObserver\";\n * import { type ReactElement } from \"react\";\n * import { useState } from \"react\";\n *\n * import styles from \"./Example.module.scss\";\n *\n * const numSteps = 20;\n * const thresholds = Array.from({ length: numSteps }, (_, i) => i / numSteps);\n * thresholds.push(0);\n *\n * const INCREASING = \"rgba(40, 40, 190, ratio)\";\n * const DECREASING = \"rgba(190, 40, 40, ratio)\";\n *\n * export default function Example(): ReactElement {\n * const [{ ratio, increasing }, setState] = useState({\n * ratio: 0.0,\n * increasing: true,\n * });\n *\n * const targetRef = useIntersectionObserver({\n * threshold: thresholds,\n * rootMargin: \"0px\",\n * onUpdate: useCallback(([entry]) => {\n * const { intersectionRatio } = entry;\n * setState((prevState) => {\n * return {\n * ratio: intersectionRatio,\n * increasing: intersectionRatio > prevState.ratio,\n * };\n * });\n * }, []),\n * });\n *\n * return (\n * <div\n * ref={targetRef}\n * className={styles.box}\n * style={{\n * backgroundColor: (increasing ? INCREASING : DECREASING).replace(\n * \"ratio\",\n * `${ratio}`\n * ),\n * }}\n * >\n * <div className={styles.vertical}>\n * Welcome to <strong>The Box!</strong>\n * </div>\n * </div>\n * );\n * }\n * ```\n *\n * @since 6.0.0\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API\n */\nexport function useIntersectionObserver<E extends HTMLElement>(\n options: IntersectionObserverHookOptions<E>\n): RefCallback<E> {\n const {\n ref,\n root,\n disabled = false,\n onUpdate,\n threshold,\n rootMargin,\n getTargets,\n getThreshold,\n getRootMargin,\n } = options;\n\n const [targetNodeRef, targetRef] = useEnsuredRef(ref);\n\n useEffect(() => {\n const element = targetNodeRef.current;\n let targets: readonly Element[] = [];\n if (getTargets) {\n targets = getTargets();\n } else if (element) {\n targets = [element];\n }\n\n if (disabled || !targets.length) {\n return;\n }\n\n let resolvedRoot: IntersectionObserverRoot;\n if (root && \"current\" in root) {\n resolvedRoot = root.current;\n } else {\n resolvedRoot = root;\n }\n\n const options: IntersectionObserverInit = {\n root: resolvedRoot,\n threshold: (getThreshold || (() => threshold))(),\n rootMargin: (getRootMargin || (() => rootMargin))(),\n };\n\n // Just like the ResizeObserver, you can see performance improvements by\n // sharing a single intersection observer but I don't think it's worth the\n // effort to implement here since I'd need to:\n // - check if there is an observer with the same options\n // - if there is, add the callback to that existing observer\n // - if there isn't, create a new observer\n // - when cleaning up, check if there are any other existing callbacks\n // - disconnect and remove the observer if there are none left\n const observer = new IntersectionObserver(onUpdate, options);\n targets.forEach((target) => {\n observer.observe(target);\n });\n\n return () => {\n observer.disconnect();\n };\n }, [\n disabled,\n getRootMargin,\n getTargets,\n getThreshold,\n onUpdate,\n root,\n rootMargin,\n targetNodeRef,\n threshold,\n ]);\n\n return targetRef;\n}\n"],"names":["useEffect","useEnsuredRef","useIntersectionObserver","options","ref","root","disabled","onUpdate","threshold","rootMargin","getTargets","getThreshold","getRootMargin","targetNodeRef","targetRef","element","current","targets","length","resolvedRoot","observer","IntersectionObserver","forEach","target","observe","disconnect"],"mappings":"AAAA;AAGA,SAASA,SAAS,QAAQ,QAAQ;AAElC,SAASC,aAAa,QAAQ,qBAAqB;AA4LnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2DC,GACD,OAAO,SAASC,wBACdC,OAA2C;IAE3C,MAAM,EACJC,GAAG,EACHC,IAAI,EACJC,WAAW,KAAK,EAChBC,QAAQ,EACRC,SAAS,EACTC,UAAU,EACVC,UAAU,EACVC,YAAY,EACZC,aAAa,EACd,GAAGT;IAEJ,MAAM,CAACU,eAAeC,UAAU,GAAGb,cAAcG;IAEjDJ,UAAU;QACR,MAAMe,UAAUF,cAAcG,OAAO;QACrC,IAAIC,UAA8B,EAAE;QACpC,IAAIP,YAAY;YACdO,UAAUP;QACZ,OAAO,IAAIK,SAAS;YAClBE,UAAU;gBAACF;aAAQ;QACrB;QAEA,IAAIT,YAAY,CAACW,QAAQC,MAAM,EAAE;YAC/B;QACF;QAEA,IAAIC;QACJ,IAAId,QAAQ,aAAaA,MAAM;YAC7Bc,eAAed,KAAKW,OAAO;QAC7B,OAAO;YACLG,eAAed;QACjB;QAEA,MAAMF,UAAoC;YACxCE,MAAMc;YACNX,WAAW,AAACG,CAAAA,gBAAiB,CAAA,IAAMH,SAAQ,CAAC;YAC5CC,YAAY,AAACG,CAAAA,iBAAkB,CAAA,IAAMH,UAAS,CAAC;QACjD;QAEA,wEAAwE;QACxE,0EAA0E;QAC1E,8CAA8C;QAC9C,wDAAwD;QACxD,8DAA8D;QAC9D,4CAA4C;QAC5C,sEAAsE;QACtE,gEAAgE;QAChE,MAAMW,WAAW,IAAIC,qBAAqBd,UAAUJ;QACpDc,QAAQK,OAAO,CAAC,CAACC;YACfH,SAASI,OAAO,CAACD;QACnB;QAEA,OAAO;YACLH,SAASK,UAAU;QACrB;IACF,GAAG;QACDnB;QACAM;QACAF;QACAC;QACAJ;QACAF;QACAI;QACAI;QACAL;KACD;IAED,OAAOM;AACT"}
|
|
1
|
+
{"version":3,"sources":["../src/useIntersectionObserver.ts"],"sourcesContent":["\"use client\";\n\nimport { type Ref, type RefCallback, type RefObject } from \"react\";\nimport { useEffect } from \"react\";\n\nimport { useEnsuredRef } from \"./useEnsuredRef.js\";\n\n/** @since 6.0.0 */\nexport type IntersectionObserverRoot = IntersectionObserverInit[\"root\"];\n/** @since 6.0.0 */\nexport type IntersectionObserverThreshold =\n IntersectionObserverInit[\"threshold\"];\n/** @since 6.0.0 */\nexport type IntersectionObserverRootMargin =\n IntersectionObserverInit[\"rootMargin\"];\n\n/**\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#intersection_observer_options}\n * @since 6.0.0\n */\nexport interface BaseIntersectionObserverHookOptions {\n /**\n * This is the same as the normal `root` for an IntersectionObserverInit, but\n * also supports refs.\n */\n root?: RefObject<IntersectionObserverRoot> | IntersectionObserverRoot;\n\n /**\n * Set this to `true` if the intersection observer behavior should be\n * disabled.\n *\n * @defaultValue `false`\n */\n disabled?: boolean;\n\n /**\n * **When using a list of thresholds, they must either be defined outside of\n * the component or wrapped in a `useMemo` to prevent the IntersectionObserver\n * from being re-created each render.**\n *\n * @example Moving Out of Render\n * ```tsx\n * const threshold = [0, 0.25, 0.5, 0.75, 1];\n *\n * function Example() {\n * const targetRef = useIntersectionObserver({\n * threshold,\n * onUpdate: useCallback(([entry]) => {\n * // do something\n * }, []),\n * })\n * }\n * ```\n *\n * @example Wrapping in useMemo\n * ```tsx\n * interface ExampleProps {\n * min: number;\n * max: number;\n * }\n *\n * function Example({ min, max }: ExampleProps): ReactElement {\n * const targetRef = useIntersectionObserver({\n * threshold: useMemo(() => [min, max], [min, max]),\n * onUpdate: useCallback(([entry]) => {\n * // do something\n * }, []),\n * });\n * }\n * ```\n *\n * @see {@link getThreshold}\n */\n threshold?: IntersectionObserverThreshold;\n\n /** @see {@link getRootMargin} */\n rootMargin?: IntersectionObserverRootMargin;\n\n /**\n * **Must be wrapped in `useCallback` to prevent re-creating the\n * IntersectionObserver each render.**\n *\n * This can be used to dynamically generate the {@link threshold} which is\n * generally useful if you need access to the DOM or do some expensive\n * computation.\n *\n * @example Simple Example\n * ```tsx\n * const targetRef = useIntersectionObserver({\n * getThreshold: useCallback(() => {\n * // pretend some expensive computation\n * return [0, 0.25, 0.5, 0.75, 1];\n * }, []),\n * onUpdate: useCallback(() => {\n * // do something\n * }, []),\n * });\n * ```\n *\n * If this option is provided, {@link threshold}'s value will be ignored.\n */\n getThreshold?: () => IntersectionObserverThreshold;\n\n /**\n * **Must be wrapped in `useCallback` to prevent re-creating the\n * IntersectionObserver each render.**\n *\n * This can be used to dynamically generate the {@link rootMargin} which is\n * generally useful if you need access to the DOM.\n *\n * @example Simple Example\n * ```tsx\n * const nodeRef = useRef<HTMLElement>();\n * const targetRef = useIntersectionObserver({\n * getRootMargin: useCallback(() => {\n * return `-${nodeRef.current.offsetHeight - 1}px 0px 0px`;\n * }, []),\n * onUpdate: useCallback(() => {\n * // do something\n * }, []),\n * });\n * ```\n *\n * Note: If this option is provided, {@link rootMargin} will be ignored.\n */\n getRootMargin?: () => IntersectionObserverRootMargin;\n}\n\n/**\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#intersection_observer_options}\n * @since 6.0.0\n */\nexport interface IntersectionObserverHookOptions<\n E extends HTMLElement,\n> extends BaseIntersectionObserverHookOptions {\n /**\n * An optional ref to merge with the ref returned by this hook.\n */\n ref?: Ref<E>;\n\n /**\n * **Must be wrapped in `useCallback` to prevent re-creating the\n * IntersectionObserver each render.**\n *\n * @example Simple Example\n * ```tsx\n * const threshold = [0, 0.25, 0.5, 0.75, 1];\n *\n * function Example(): ReactElement {\n * const [intersecting, setIntersecting] = useState(false);\n * const targetRef = useIntersectionObserver({\n * threshold,\n * onUpdate: useCallback(([entry]) {\n * setIntersecting(entry.isIntersecting);\n * }, []),\n * });\n *\n * // implementation\n * }\n * ```\n */\n onUpdate: (entries: readonly IntersectionObserverEntry[]) => void;\n\n /**\n * **Must be wrapped in `useCallback` to prevent re-creating the\n * IntersectionObserver each render.**\n *\n * If this is defined, the {@link ref} will be ignored along with the returned\n * ref.\n *\n * @example Watching Queried Elements\n * ```tsx\n * function Example(): ReactElement {\n * useIntersectionObserver({\n * onUpdate: useCallback((entries) => {\n * entries.forEach((entry) => {\n * // do stuff\n * });\n *\n * setIntersectingIds(intersecting);\n * }, []),\n * getTargets: useCallback(() => {\n * return document.querySelectorAll('h1, h2, h3, h4, h5, h6');\n * }, []),\n * }),\n *\n * return <div {...props} />;\n * }\n * ```\n */\n getTargets?: () => readonly Element[];\n}\n\n/**\n * @example Simple Example\n * ```tsx\n * // https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#a_simple_example\n *\n * import { useIntersectionObserver } from \"@react-md/core/useIntersectionObserver\";\n * import { type ReactElement } from \"react\";\n * import { useState } from \"react\";\n *\n * import styles from \"./Example.module.scss\";\n *\n * const numSteps = 20;\n * const thresholds = Array.from({ length: numSteps }, (_, i) => i / numSteps);\n * thresholds.push(0);\n *\n * const INCREASING = \"rgba(40, 40, 190, ratio)\";\n * const DECREASING = \"rgba(190, 40, 40, ratio)\";\n *\n * export default function Example(): ReactElement {\n * const [{ ratio, increasing }, setState] = useState({\n * ratio: 0.0,\n * increasing: true,\n * });\n *\n * const targetRef = useIntersectionObserver({\n * threshold: thresholds,\n * rootMargin: \"0px\",\n * onUpdate: useCallback(([entry]) => {\n * const { intersectionRatio } = entry;\n * setState((prevState) => {\n * return {\n * ratio: intersectionRatio,\n * increasing: intersectionRatio > prevState.ratio,\n * };\n * });\n * }, []),\n * });\n *\n * return (\n * <div\n * ref={targetRef}\n * className={styles.box}\n * style={{\n * backgroundColor: (increasing ? INCREASING : DECREASING).replace(\n * \"ratio\",\n * `${ratio}`\n * ),\n * }}\n * >\n * <div className={styles.vertical}>\n * Welcome to <strong>The Box!</strong>\n * </div>\n * </div>\n * );\n * }\n * ```\n *\n * @since 6.0.0\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API\n */\nexport function useIntersectionObserver<E extends HTMLElement>(\n options: IntersectionObserverHookOptions<E>\n): RefCallback<E> {\n const {\n ref,\n root,\n disabled = false,\n onUpdate,\n threshold,\n rootMargin,\n getTargets,\n getThreshold,\n getRootMargin,\n } = options;\n\n const [targetNodeRef, targetRef] = useEnsuredRef(ref);\n\n useEffect(() => {\n const element = targetNodeRef.current;\n let targets: readonly Element[] = [];\n if (getTargets) {\n targets = getTargets();\n } else if (element) {\n targets = [element];\n }\n\n if (disabled || targets.length === 0) {\n return;\n }\n\n let resolvedRoot: IntersectionObserverRoot;\n if (root && \"current\" in root) {\n resolvedRoot = root.current;\n } else {\n resolvedRoot = root;\n }\n\n const options: IntersectionObserverInit = {\n root: resolvedRoot,\n threshold: (getThreshold || (() => threshold))(),\n rootMargin: (getRootMargin || (() => rootMargin))(),\n };\n\n // Just like the ResizeObserver, you can see performance improvements by\n // sharing a single intersection observer but I don't think it's worth the\n // effort to implement here since I'd need to:\n // - check if there is an observer with the same options\n // - if there is, add the callback to that existing observer\n // - if there isn't, create a new observer\n // - when cleaning up, check if there are any other existing callbacks\n // - disconnect and remove the observer if there are none left\n const observer = new IntersectionObserver(onUpdate, options);\n for (const target of targets) {\n observer.observe(target);\n }\n\n return () => {\n observer.disconnect();\n };\n }, [\n disabled,\n getRootMargin,\n getTargets,\n getThreshold,\n onUpdate,\n root,\n rootMargin,\n targetNodeRef,\n threshold,\n ]);\n\n return targetRef;\n}\n"],"names":["useEffect","useEnsuredRef","useIntersectionObserver","options","ref","root","disabled","onUpdate","threshold","rootMargin","getTargets","getThreshold","getRootMargin","targetNodeRef","targetRef","element","current","targets","length","resolvedRoot","observer","IntersectionObserver","target","observe","disconnect"],"mappings":"AAAA;AAGA,SAASA,SAAS,QAAQ,QAAQ;AAElC,SAASC,aAAa,QAAQ,qBAAqB;AA4LnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2DC,GACD,OAAO,SAASC,wBACdC,OAA2C;IAE3C,MAAM,EACJC,GAAG,EACHC,IAAI,EACJC,WAAW,KAAK,EAChBC,QAAQ,EACRC,SAAS,EACTC,UAAU,EACVC,UAAU,EACVC,YAAY,EACZC,aAAa,EACd,GAAGT;IAEJ,MAAM,CAACU,eAAeC,UAAU,GAAGb,cAAcG;IAEjDJ,UAAU;QACR,MAAMe,UAAUF,cAAcG,OAAO;QACrC,IAAIC,UAA8B,EAAE;QACpC,IAAIP,YAAY;YACdO,UAAUP;QACZ,OAAO,IAAIK,SAAS;YAClBE,UAAU;gBAACF;aAAQ;QACrB;QAEA,IAAIT,YAAYW,QAAQC,MAAM,KAAK,GAAG;YACpC;QACF;QAEA,IAAIC;QACJ,IAAId,QAAQ,aAAaA,MAAM;YAC7Bc,eAAed,KAAKW,OAAO;QAC7B,OAAO;YACLG,eAAed;QACjB;QAEA,MAAMF,UAAoC;YACxCE,MAAMc;YACNX,WAAW,AAACG,CAAAA,gBAAiB,CAAA,IAAMH,SAAQ,CAAC;YAC5CC,YAAY,AAACG,CAAAA,iBAAkB,CAAA,IAAMH,UAAS,CAAC;QACjD;QAEA,wEAAwE;QACxE,0EAA0E;QAC1E,8CAA8C;QAC9C,wDAAwD;QACxD,8DAA8D;QAC9D,4CAA4C;QAC5C,sEAAsE;QACtE,gEAAgE;QAChE,MAAMW,WAAW,IAAIC,qBAAqBd,UAAUJ;QACpD,KAAK,MAAMmB,UAAUL,QAAS;YAC5BG,SAASG,OAAO,CAACD;QACnB;QAEA,OAAO;YACLF,SAASI,UAAU;QACrB;IACF,GAAG;QACDlB;QACAM;QACAF;QACAC;QACAJ;QACAF;QACAI;QACAI;QACAL;KACD;IAED,OAAOM;AACT"}
|
|
@@ -5,6 +5,6 @@ import { useEffect, useLayoutEffect } from "react";
|
|
|
5
5
|
* this and how to fix "invalid" warnings while running tests.
|
|
6
6
|
*
|
|
7
7
|
* @see {@link https://github.com/reduxjs/react-redux/blob/4c907c0870c6b9a136dd69be294c17d1dc63c8f5/src/utils/useIsomorphicLayoutEffect.js}
|
|
8
|
-
*/ export const useIsomorphicLayoutEffect =
|
|
8
|
+
*/ export const useIsomorphicLayoutEffect = globalThis.window !== undefined && globalThis.document !== undefined && globalThis.document.createElement !== undefined ? useLayoutEffect : useEffect;
|
|
9
9
|
|
|
10
10
|
//# sourceMappingURL=useIsomorphicLayoutEffect.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useIsomorphicLayoutEffect.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useLayoutEffect } from \"react\";\n\n/**\n * This is copy/pasted from react-redux which has some more information about\n * this and how to fix \"invalid\" warnings while running tests.\n *\n * @see {@link https://github.com/reduxjs/react-redux/blob/4c907c0870c6b9a136dd69be294c17d1dc63c8f5/src/utils/useIsomorphicLayoutEffect.js}\n */\nexport const useIsomorphicLayoutEffect =\n
|
|
1
|
+
{"version":3,"sources":["../src/useIsomorphicLayoutEffect.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useLayoutEffect } from \"react\";\n\n/**\n * This is copy/pasted from react-redux which has some more information about\n * this and how to fix \"invalid\" warnings while running tests.\n *\n * @see {@link https://github.com/reduxjs/react-redux/blob/4c907c0870c6b9a136dd69be294c17d1dc63c8f5/src/utils/useIsomorphicLayoutEffect.js}\n */\nexport const useIsomorphicLayoutEffect =\n globalThis.window !== undefined &&\n globalThis.document !== undefined &&\n globalThis.document.createElement !== undefined\n ? useLayoutEffect\n : useEffect;\n"],"names":["useEffect","useLayoutEffect","useIsomorphicLayoutEffect","globalThis","window","undefined","document","createElement"],"mappings":"AAAA;AAEA,SAASA,SAAS,EAAEC,eAAe,QAAQ,QAAQ;AAEnD;;;;;CAKC,GACD,OAAO,MAAMC,4BACXC,WAAWC,MAAM,KAAKC,aACtBF,WAAWG,QAAQ,KAAKD,aACxBF,WAAWG,QAAQ,CAACC,aAAa,KAAKF,YAClCJ,kBACAD,UAAU"}
|
package/dist/useOrientation.js
CHANGED
|
@@ -9,7 +9,7 @@ import { useEffect, useState } from "react";
|
|
|
9
9
|
* by comparing the `availHeight` and `availWidth` on the `window.screen`
|
|
10
10
|
* @internal
|
|
11
11
|
*/ export const getOrientationType = ()=>{
|
|
12
|
-
if (
|
|
12
|
+
if (globalThis.window === undefined) {
|
|
13
13
|
return "landscape-primary";
|
|
14
14
|
}
|
|
15
15
|
// Note: at the time of writing this, it looks like only Safari does not
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useOrientation.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\n/**\n * An extremely simple \"polyfill\" for the `window.screen.orientation` just for\n * the `type` value that is required for the `useOrientation` hook.\n *\n * @see {@link https://caniuse.com/screen-orientation}\n * @returns the orientation type either from the `window.screen.orientation` or\n * by comparing the `availHeight` and `availWidth` on the `window.screen`\n * @internal\n */\nexport const getOrientationType = (): OrientationType => {\n if (
|
|
1
|
+
{"version":3,"sources":["../src/useOrientation.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\n/**\n * An extremely simple \"polyfill\" for the `window.screen.orientation` just for\n * the `type` value that is required for the `useOrientation` hook.\n *\n * @see {@link https://caniuse.com/screen-orientation}\n * @returns the orientation type either from the `window.screen.orientation` or\n * by comparing the `availHeight` and `availWidth` on the `window.screen`\n * @internal\n */\nexport const getOrientationType = (): OrientationType => {\n if (globalThis.window === undefined) {\n return \"landscape-primary\";\n }\n\n // Note: at the time of writing this, it looks like only Safari does not\n // support it from my list of browsers\n const screenOrientation = window.screen.orientation?.type;\n if (typeof screenOrientation === \"string\") {\n return screenOrientation;\n }\n\n const { availHeight, availWidth } = window.screen;\n\n return availHeight > availWidth ? \"portrait-primary\" : \"landscape-primary\";\n};\n\n/**\n * This hook uses the {@link https://developer.mozilla.org/en-US/docs/Web/API/ScreenOrientation} API\n * to determine if the screen is landscape or portrait. For browsers that do not\n * support this API yet, it will polyfill that behavior using a resize handler\n * instead.\n *\n * @see {@link https://caniuse.com/screen-orientation}\n * @returns the current orientation type\n */\nexport function useOrientation(): OrientationType {\n const [orientation, setOrientation] = useState(getOrientationType);\n useEffect(() => {\n const handler = (): void => {\n setOrientation(getOrientationType());\n };\n\n const { orientation } = window.screen;\n if (orientation) {\n orientation.addEventListener(\"change\", handler);\n } else {\n window.addEventListener(\"resize\", handler);\n }\n\n return () => {\n if (orientation) {\n orientation.removeEventListener(\"change\", handler);\n } else {\n window.removeEventListener(\"resize\", handler);\n }\n };\n }, []);\n\n return orientation;\n}\n"],"names":["useEffect","useState","getOrientationType","globalThis","window","undefined","screenOrientation","screen","orientation","type","availHeight","availWidth","useOrientation","setOrientation","handler","addEventListener","removeEventListener"],"mappings":"AAAA;AAEA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,QAAQ;AAE5C;;;;;;;;CAQC,GACD,OAAO,MAAMC,qBAAqB;IAChC,IAAIC,WAAWC,MAAM,KAAKC,WAAW;QACnC,OAAO;IACT;IAEA,wEAAwE;IACxE,sCAAsC;IACtC,MAAMC,oBAAoBF,OAAOG,MAAM,CAACC,WAAW,EAAEC;IACrD,IAAI,OAAOH,sBAAsB,UAAU;QACzC,OAAOA;IACT;IAEA,MAAM,EAAEI,WAAW,EAAEC,UAAU,EAAE,GAAGP,OAAOG,MAAM;IAEjD,OAAOG,cAAcC,aAAa,qBAAqB;AACzD,EAAE;AAEF;;;;;;;;CAQC,GACD,OAAO,SAASC;IACd,MAAM,CAACJ,aAAaK,eAAe,GAAGZ,SAASC;IAC/CF,UAAU;QACR,MAAMc,UAAU;YACdD,eAAeX;QACjB;QAEA,MAAM,EAAEM,WAAW,EAAE,GAAGJ,OAAOG,MAAM;QACrC,IAAIC,aAAa;YACfA,YAAYO,gBAAgB,CAAC,UAAUD;QACzC,OAAO;YACLV,OAAOW,gBAAgB,CAAC,UAAUD;QACpC;QAEA,OAAO;YACL,IAAIN,aAAa;gBACfA,YAAYQ,mBAAmB,CAAC,UAAUF;YAC5C,OAAO;gBACLV,OAAOY,mBAAmB,CAAC,UAAUF;YACvC;QACF;IACF,GAAG,EAAE;IAEL,OAAON;AACT"}
|
package/dist/useReadonlySet.js
CHANGED
|
@@ -36,7 +36,7 @@ import { useCallback, useState } from "react";
|
|
|
36
36
|
*/ export function useReadonlySet(options = {}) {
|
|
37
37
|
const { defaultValue, toggleType = "multiple" } = options;
|
|
38
38
|
const [value, setValue] = useState(()=>{
|
|
39
|
-
const initial = defaultValue
|
|
39
|
+
const initial = typeof defaultValue === "function" ? defaultValue() : defaultValue ?? [];
|
|
40
40
|
return new Set(initial);
|
|
41
41
|
});
|
|
42
42
|
const toggleValue = useCallback((item)=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useReadonlySet.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useState } from \"react\";\n\nimport { type UseStateInitializer, type UseStateSetter } from \"./types.js\";\n\n/**\n * @since 6.0.0\n */\nexport interface ReadonlySetOptions<T> {\n /**\n * Sets the behavior for when the\n * {@link ReadonlySetImplementation.toggleValue} is triggered and mostly for\n * internal usage. The default behavior (`\"multiple\"`) is to work how most\n * would expect:\n * - If the item does not exist in the set, add it.\n * - If the item exists in the set, remove it.\n *\n * Setting this to `\"single\"` makes it so that only a single item can be in\n * the set at once and will toggle like normal:\n * - If the item does not exist in the set, return a new set only including\n * the item.\n * - If the item exists in the set, return an empty set.\n * An example usage is the `useExpansionPanels` to allow only a single panel\n * to be expanded at a time.\n *\n * Setting this to `\"single-select\"` makes it so that only a single item can\n * be in the set at once but will not toggle:\n * - If the item does not exist in the set, return a new set only including\n * the item.\n * - If the item exists in the set, do nothing\n * An example usage is the `useTreeSelection` to always require at least one\n * tree item to be selected. It is impossible to deselect an item.\n *\n * @defaultValue `\"multiple\"`\n */\n toggleType?: \"single\" | \"multiple\" | \"single-select\";\n defaultValue?: UseStateInitializer<ReadonlySet<T> | readonly T[]>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ReadonlySetImplementation<T> {\n value: ReadonlySet<T>;\n setValue: UseStateSetter<ReadonlySet<T>>;\n toggleValue: (item: T) => void;\n}\n\n/**\n * The `useReadonlySet` hook is used to create a more performant lookup\n * behavior for lists/arrays. This is most likely an internal only hook to\n * manage state for a `ReadonlySet`. You most likely want to use one of the\n * other hooks that leverage this instead:\n *\n * - `useCheckboxGroup`\n * - `useExpansionPanels`\n * - `useTreeSelection`\n * - `useTreeExpansion`\n * - etc\n *\n * @example Simple Example\n * ```tsx\n * import { cnb } from \"cnbuilder\";\n * import { useReadonlySet } from \"@react-md/core/useReadonlySet\";\n *\n * function Example() {\n * const { value, toggleValue } = useReadonlySet();\n *\n * return (\n * <>\n * {someList.map((item) => (\n * <div key={item.id} className={cnb(value.has(item.id) && styles.selected)}>\n * {item.name}\n * <Button onClick={() => toggleValue(item.id)}>Button</Button>\n * </div>\n * ))}\n * </>\n * );\n * }\n * ```\n * @since 6.0.0\n */\nexport function useReadonlySet<T>(\n options: ReadonlySetOptions<T> = {}\n): ReadonlySetImplementation<T> {\n const { defaultValue, toggleType = \"multiple\" } = options;\n const [value, setValue] = useState<ReadonlySet<T>>(() => {\n const initial =\n defaultValue
|
|
1
|
+
{"version":3,"sources":["../src/useReadonlySet.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useState } from \"react\";\n\nimport { type UseStateInitializer, type UseStateSetter } from \"./types.js\";\n\n/**\n * @since 6.0.0\n */\nexport interface ReadonlySetOptions<T> {\n /**\n * Sets the behavior for when the\n * {@link ReadonlySetImplementation.toggleValue} is triggered and mostly for\n * internal usage. The default behavior (`\"multiple\"`) is to work how most\n * would expect:\n * - If the item does not exist in the set, add it.\n * - If the item exists in the set, remove it.\n *\n * Setting this to `\"single\"` makes it so that only a single item can be in\n * the set at once and will toggle like normal:\n * - If the item does not exist in the set, return a new set only including\n * the item.\n * - If the item exists in the set, return an empty set.\n * An example usage is the `useExpansionPanels` to allow only a single panel\n * to be expanded at a time.\n *\n * Setting this to `\"single-select\"` makes it so that only a single item can\n * be in the set at once but will not toggle:\n * - If the item does not exist in the set, return a new set only including\n * the item.\n * - If the item exists in the set, do nothing\n * An example usage is the `useTreeSelection` to always require at least one\n * tree item to be selected. It is impossible to deselect an item.\n *\n * @defaultValue `\"multiple\"`\n */\n toggleType?: \"single\" | \"multiple\" | \"single-select\";\n defaultValue?: UseStateInitializer<ReadonlySet<T> | readonly T[]>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ReadonlySetImplementation<T> {\n value: ReadonlySet<T>;\n setValue: UseStateSetter<ReadonlySet<T>>;\n toggleValue: (item: T) => void;\n}\n\n/**\n * The `useReadonlySet` hook is used to create a more performant lookup\n * behavior for lists/arrays. This is most likely an internal only hook to\n * manage state for a `ReadonlySet`. You most likely want to use one of the\n * other hooks that leverage this instead:\n *\n * - `useCheckboxGroup`\n * - `useExpansionPanels`\n * - `useTreeSelection`\n * - `useTreeExpansion`\n * - etc\n *\n * @example Simple Example\n * ```tsx\n * import { cnb } from \"cnbuilder\";\n * import { useReadonlySet } from \"@react-md/core/useReadonlySet\";\n *\n * function Example() {\n * const { value, toggleValue } = useReadonlySet();\n *\n * return (\n * <>\n * {someList.map((item) => (\n * <div key={item.id} className={cnb(value.has(item.id) && styles.selected)}>\n * {item.name}\n * <Button onClick={() => toggleValue(item.id)}>Button</Button>\n * </div>\n * ))}\n * </>\n * );\n * }\n * ```\n * @since 6.0.0\n */\nexport function useReadonlySet<T>(\n options: ReadonlySetOptions<T> = {}\n): ReadonlySetImplementation<T> {\n const { defaultValue, toggleType = \"multiple\" } = options;\n const [value, setValue] = useState<ReadonlySet<T>>(() => {\n const initial =\n typeof defaultValue === \"function\"\n ? defaultValue()\n : (defaultValue ?? []);\n\n return new Set(initial);\n });\n\n const toggleValue = useCallback(\n (item: T) => {\n setValue((prevValue) => {\n const exists = prevValue.has(item);\n if (toggleType === \"single\") {\n return new Set(exists ? [] : [item]);\n }\n\n if (toggleType === \"single-select\") {\n return exists ? prevValue : new Set([item]);\n }\n\n const nextValue = new Set(prevValue);\n if (exists) {\n nextValue.delete(item);\n } else {\n nextValue.add(item);\n }\n\n return nextValue;\n });\n },\n [toggleType]\n );\n\n return {\n value,\n setValue,\n toggleValue,\n };\n}\n"],"names":["useCallback","useState","useReadonlySet","options","defaultValue","toggleType","value","setValue","initial","Set","toggleValue","item","prevValue","exists","has","nextValue","delete","add"],"mappings":"AAAA;AAEA,SAASA,WAAW,EAAEC,QAAQ,QAAQ,QAAQ;AA+C9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCC,GACD,OAAO,SAASC,eACdC,UAAiC,CAAC,CAAC;IAEnC,MAAM,EAAEC,YAAY,EAAEC,aAAa,UAAU,EAAE,GAAGF;IAClD,MAAM,CAACG,OAAOC,SAAS,GAAGN,SAAyB;QACjD,MAAMO,UACJ,OAAOJ,iBAAiB,aACpBA,iBACCA,gBAAgB,EAAE;QAEzB,OAAO,IAAIK,IAAID;IACjB;IAEA,MAAME,cAAcV,YAClB,CAACW;QACCJ,SAAS,CAACK;YACR,MAAMC,SAASD,UAAUE,GAAG,CAACH;YAC7B,IAAIN,eAAe,UAAU;gBAC3B,OAAO,IAAII,IAAII,SAAS,EAAE,GAAG;oBAACF;iBAAK;YACrC;YAEA,IAAIN,eAAe,iBAAiB;gBAClC,OAAOQ,SAASD,YAAY,IAAIH,IAAI;oBAACE;iBAAK;YAC5C;YAEA,MAAMI,YAAY,IAAIN,IAAIG;YAC1B,IAAIC,QAAQ;gBACVE,UAAUC,MAAM,CAACL;YACnB,OAAO;gBACLI,UAAUE,GAAG,CAACN;YAChB;YAEA,OAAOI;QACT;IACF,GACA;QAACV;KAAW;IAGd,OAAO;QACLC;QACAC;QACAG;IACF;AACF"}
|
|
@@ -47,14 +47,14 @@ import { delegateEvent } from "./delegateEvent.js";
|
|
|
47
47
|
if (disabled) {
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
|
-
const eventHandler = delegateEvent("resize", window, throttle, {
|
|
50
|
+
const eventHandler = delegateEvent("resize", globalThis.window, throttle, {
|
|
51
51
|
once,
|
|
52
52
|
signal,
|
|
53
53
|
capture,
|
|
54
54
|
passive
|
|
55
55
|
});
|
|
56
56
|
eventHandler.add(onUpdate);
|
|
57
|
-
|
|
57
|
+
globalThis.dispatchEvent(new Event("resize"));
|
|
58
58
|
return ()=>{
|
|
59
59
|
eventHandler.remove(onUpdate);
|
|
60
60
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useResizeListener.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\n\nimport { delegateEvent } from \"./delegateEvent.js\";\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport { type useResizeObserver } from \"./useResizeObserver.js\";\n\n/**\n * @since 6.0.0 Removed the `immediate` option to force the resize handler to be\n * called immediately.\n * @since 6.0.0 Renamed to a new API so that there is no longer an `options`\n * property and instead the `AddEventListenerOptions` are part of the hook\n * options.\n * @since 6.0.0 Renamed `onResize` to `onUpdate` and `enabled` to `disabled`.\n */\nexport interface ResizeListenerOptions extends AddEventListenerOptions {\n /**\n * Set this to `false` to disable throttling with\n * `window.requestAnimationFrame`.\n *\n * @defaultValue `true`\n * @since 6.0.0\n */\n throttle?: boolean;\n\n /**\n * Set this to `true` to disable attaching the resize event handler.\n *\n * @defaultValue `false`\n */\n disabled?: boolean;\n\n /**\n * This function will be called whenever the resize event is fired on the\n * `window`. This should be wrapped in `useCallback`.\n */\n onUpdate: (event: Event) => void;\n}\n\n/**\n * This hook can be used to listen to the entire window resizing. If you need to\n * observe specific elements resizing, check out the {@link useResizeObserver}\n * hook instead.\n *\n * @example Simple Example\n * ```tsx\n * import { useResizeListener } from \"@react-md/core/useResizeListener\";\n * import { type ReactElement } from \"react\";\n * import { useState } from \"react\";\n *\n * function Example(): ReactElement {\n * const [size, setSize] = useState({\n * height: window.innerHeight,\n * width: window.innerWidth,\n * });\n *\n * useResizeListener({\n * onUpdate(event) {\n * setSize({\n * height: window.innerHeight,\n * width: window.innerWidth,\n * });\n * },\n * });\n *\n * return (\n * <>\n * The current window size:\n * <pre>\n * <code>{JSON.stringify(size, null, 2)}</code>\n * </pre>\n * </>\n * );\n * }\n * ```\n *\n * @since 6.0.0 Updated the API to match the `useResizeObserver` and\n * `useIntersectionObserver` hooks by having an `onUpdate` callback and include\n * the `AddEventListenerOptions` as part of the hook options.\n */\nexport function useResizeListener(options: ResizeListenerOptions): void {\n const {\n once,\n signal,\n capture,\n passive,\n throttle = true,\n disabled = false,\n onUpdate,\n } = options;\n\n useEffect(() => {\n if (disabled) {\n return;\n }\n\n const eventHandler = delegateEvent(\"resize\", window, throttle, {\n once,\n signal,\n capture,\n passive,\n });\n eventHandler.add(onUpdate);\n\n
|
|
1
|
+
{"version":3,"sources":["../src/useResizeListener.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\n\nimport { delegateEvent } from \"./delegateEvent.js\";\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport { type useResizeObserver } from \"./useResizeObserver.js\";\n\n/**\n * @since 6.0.0 Removed the `immediate` option to force the resize handler to be\n * called immediately.\n * @since 6.0.0 Renamed to a new API so that there is no longer an `options`\n * property and instead the `AddEventListenerOptions` are part of the hook\n * options.\n * @since 6.0.0 Renamed `onResize` to `onUpdate` and `enabled` to `disabled`.\n */\nexport interface ResizeListenerOptions extends AddEventListenerOptions {\n /**\n * Set this to `false` to disable throttling with\n * `window.requestAnimationFrame`.\n *\n * @defaultValue `true`\n * @since 6.0.0\n */\n throttle?: boolean;\n\n /**\n * Set this to `true` to disable attaching the resize event handler.\n *\n * @defaultValue `false`\n */\n disabled?: boolean;\n\n /**\n * This function will be called whenever the resize event is fired on the\n * `window`. This should be wrapped in `useCallback`.\n */\n onUpdate: (event: Event) => void;\n}\n\n/**\n * This hook can be used to listen to the entire window resizing. If you need to\n * observe specific elements resizing, check out the {@link useResizeObserver}\n * hook instead.\n *\n * @example Simple Example\n * ```tsx\n * import { useResizeListener } from \"@react-md/core/useResizeListener\";\n * import { type ReactElement } from \"react\";\n * import { useState } from \"react\";\n *\n * function Example(): ReactElement {\n * const [size, setSize] = useState({\n * height: window.innerHeight,\n * width: window.innerWidth,\n * });\n *\n * useResizeListener({\n * onUpdate(event) {\n * setSize({\n * height: window.innerHeight,\n * width: window.innerWidth,\n * });\n * },\n * });\n *\n * return (\n * <>\n * The current window size:\n * <pre>\n * <code>{JSON.stringify(size, null, 2)}</code>\n * </pre>\n * </>\n * );\n * }\n * ```\n *\n * @since 6.0.0 Updated the API to match the `useResizeObserver` and\n * `useIntersectionObserver` hooks by having an `onUpdate` callback and include\n * the `AddEventListenerOptions` as part of the hook options.\n */\nexport function useResizeListener(options: ResizeListenerOptions): void {\n const {\n once,\n signal,\n capture,\n passive,\n throttle = true,\n disabled = false,\n onUpdate,\n } = options;\n\n useEffect(() => {\n if (disabled) {\n return;\n }\n\n const eventHandler = delegateEvent(\"resize\", globalThis.window, throttle, {\n once,\n signal,\n capture,\n passive,\n });\n eventHandler.add(onUpdate);\n\n globalThis.dispatchEvent(new Event(\"resize\"));\n return () => {\n eventHandler.remove(onUpdate);\n };\n }, [capture, disabled, onUpdate, once, passive, signal, throttle]);\n}\n"],"names":["useEffect","delegateEvent","useResizeListener","options","once","signal","capture","passive","throttle","disabled","onUpdate","eventHandler","globalThis","window","add","dispatchEvent","Event","remove"],"mappings":"AAAA;AAEA,SAASA,SAAS,QAAQ,QAAQ;AAElC,SAASC,aAAa,QAAQ,qBAAqB;AAoCnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCC,GACD,OAAO,SAASC,kBAAkBC,OAA8B;IAC9D,MAAM,EACJC,IAAI,EACJC,MAAM,EACNC,OAAO,EACPC,OAAO,EACPC,WAAW,IAAI,EACfC,WAAW,KAAK,EAChBC,QAAQ,EACT,GAAGP;IAEJH,UAAU;QACR,IAAIS,UAAU;YACZ;QACF;QAEA,MAAME,eAAeV,cAAc,UAAUW,WAAWC,MAAM,EAAEL,UAAU;YACxEJ;YACAC;YACAC;YACAC;QACF;QACAI,aAAaG,GAAG,CAACJ;QAEjBE,WAAWG,aAAa,CAAC,IAAIC,MAAM;QACnC,OAAO;YACLL,aAAaM,MAAM,CAACP;QACtB;IACF,GAAG;QAACJ;QAASG;QAAUC;QAAUN;QAAMG;QAASF;QAAQG;KAAS;AACnE"}
|
|
@@ -22,7 +22,7 @@ import { useEnsuredRef } from "./useEnsuredRef.js";
|
|
|
22
22
|
* `src/tests-utils/ResizeObserver.ts`
|
|
23
23
|
*/ export class ResizeObserverManager {
|
|
24
24
|
constructor(){
|
|
25
|
-
_define_property(this, "frame",
|
|
25
|
+
_define_property(this, "frame", 0);
|
|
26
26
|
_define_property(this, "subscriptions", void 0);
|
|
27
27
|
/**
|
|
28
28
|
* Why is there a single shared observer instead of multiple and a
|
|
@@ -38,8 +38,8 @@ import { useEnsuredRef } from "./useEnsuredRef.js";
|
|
|
38
38
|
// lazy initialize the observer
|
|
39
39
|
const observer = this.sharedObserver || new ResizeObserver((entries)=>{
|
|
40
40
|
// this prevents the `ResizeObserver loop limit exceeded`
|
|
41
|
-
|
|
42
|
-
this.frame =
|
|
41
|
+
globalThis.cancelAnimationFrame(this.frame);
|
|
42
|
+
this.frame = globalThis.requestAnimationFrame(()=>{
|
|
43
43
|
this.handleResizeEntries(entries);
|
|
44
44
|
});
|
|
45
45
|
});
|
|
@@ -86,7 +86,6 @@ import { useEnsuredRef } from "./useEnsuredRef.js";
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
});
|
|
89
|
-
this.frame = 0;
|
|
90
89
|
this.subscriptions = new Map();
|
|
91
90
|
}
|
|
92
91
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useResizeObserver.ts"],"sourcesContent":["\"use client\";\n\nimport { type Ref, type RefCallback, useEffect } from \"react\";\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport { type useElementSize } from \"./useElementSize.js\";\nimport { useEnsuredRef } from \"./useEnsuredRef.js\";\n\n/**\n * @since 6.0.0\n */\nexport type ResizeObserverEntryCallback = (entry: ResizeObserverEntry) => void;\n\n/** @internal */\ntype Unsubscribe = () => void;\n\n/** @internal */\ninterface TargetSize {\n height: number;\n width: number;\n scrollHeight: number;\n scrollWidth: number;\n}\n\n/** @internal */\ninterface TargetSubscription {\n onUpdate: ResizeObserverEntryCallback;\n disableHeight: boolean;\n disableWidth: boolean;\n\n size?: TargetSize;\n}\n\n/** @internal */\ninterface SubscribeOptions {\n element: Element;\n onUpdate: ResizeObserverEntryCallback;\n disableHeight: boolean;\n disableWidth: boolean;\n}\n\n/**\n * @internal\n * @since 6.0.0 This was added to help with testing. The\n * `subscriptions` and `sharedObserver` used to be module-level variables but\n * moving to a class makes it easier to mock. Checkout the\n * `src/tests-utils/ResizeObserver.ts`\n */\nexport class ResizeObserverManager {\n frame: number;\n subscriptions: Map<Element, Set<TargetSubscription>>;\n\n /**\n * Why is there a single shared observer instead of multiple and a\n * \"subscription\" model?\n *\n * Note: Probably a bit of a premature optimization right now...\n *\n * @see https://github.com/WICG/resize-observer/issues/59\n * @internal\n */\n sharedObserver: ResizeObserver | undefined;\n\n constructor() {\n this.
|
|
1
|
+
{"version":3,"sources":["../src/useResizeObserver.ts"],"sourcesContent":["\"use client\";\n\nimport { type Ref, type RefCallback, useEffect } from \"react\";\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport { type useElementSize } from \"./useElementSize.js\";\nimport { useEnsuredRef } from \"./useEnsuredRef.js\";\n\n/**\n * @since 6.0.0\n */\nexport type ResizeObserverEntryCallback = (entry: ResizeObserverEntry) => void;\n\n/** @internal */\ntype Unsubscribe = () => void;\n\n/** @internal */\ninterface TargetSize {\n height: number;\n width: number;\n scrollHeight: number;\n scrollWidth: number;\n}\n\n/** @internal */\ninterface TargetSubscription {\n onUpdate: ResizeObserverEntryCallback;\n disableHeight: boolean;\n disableWidth: boolean;\n\n size?: TargetSize;\n}\n\n/** @internal */\ninterface SubscribeOptions {\n element: Element;\n onUpdate: ResizeObserverEntryCallback;\n disableHeight: boolean;\n disableWidth: boolean;\n}\n\n/**\n * @internal\n * @since 6.0.0 This was added to help with testing. The\n * `subscriptions` and `sharedObserver` used to be module-level variables but\n * moving to a class makes it easier to mock. Checkout the\n * `src/tests-utils/ResizeObserver.ts`\n */\nexport class ResizeObserverManager {\n frame: number = 0;\n subscriptions: Map<Element, Set<TargetSubscription>>;\n\n /**\n * Why is there a single shared observer instead of multiple and a\n * \"subscription\" model?\n *\n * Note: Probably a bit of a premature optimization right now...\n *\n * @see https://github.com/WICG/resize-observer/issues/59\n * @internal\n */\n sharedObserver: ResizeObserver | undefined;\n\n constructor() {\n this.subscriptions = new Map();\n }\n\n subscribe = (options: SubscribeOptions): Unsubscribe => {\n const { element, onUpdate, disableHeight, disableWidth } = options;\n\n // lazy initialize the observer\n const observer =\n this.sharedObserver ||\n new ResizeObserver((entries) => {\n // this prevents the `ResizeObserver loop limit exceeded`\n globalThis.cancelAnimationFrame(this.frame);\n this.frame = globalThis.requestAnimationFrame(() => {\n this.handleResizeEntries(entries);\n });\n });\n this.sharedObserver = observer;\n\n const updates = this.subscriptions.get(element) || new Set();\n const subscription: TargetSubscription = {\n onUpdate,\n disableHeight,\n disableWidth,\n };\n updates.add(subscription);\n if (!this.subscriptions.has(element)) {\n this.subscriptions.set(element, updates);\n }\n\n observer.observe(element);\n\n return () => {\n observer.unobserve(element);\n updates.delete(subscription);\n };\n };\n\n handleResizeEntries = (entries: ResizeObserverEntry[]): void => {\n for (const entry of entries) {\n const targetSubscriptions = this.subscriptions.get(entry.target);\n // shouldn't really happen\n /* c8 ignore start */\n if (!targetSubscriptions) {\n continue;\n }\n /* c8 ignore stop */\n\n const entries = targetSubscriptions.values();\n for (const subscription of entries) {\n const { height, width } = entry.contentRect;\n const { scrollHeight, scrollWidth } = entry.target;\n const { onUpdate, size, disableHeight, disableWidth } = subscription;\n const isHeightChange =\n !disableHeight &&\n (!size ||\n size.height !== height ||\n size.scrollHeight !== scrollHeight);\n const isWidthChange =\n !disableWidth &&\n (!size || size.width !== width || size.scrollWidth !== scrollWidth);\n\n subscription.size = {\n height,\n width,\n scrollHeight,\n scrollWidth,\n };\n if (isHeightChange || isWidthChange) {\n onUpdate(entry);\n }\n }\n }\n };\n}\n\n/**\n * @internal\n * @since 6.0.0\n */\nexport const resizeObserverManager = new ResizeObserverManager();\n\n/**\n * @since 2.3.0\n * @since 6.0.0 Renamed from `UseResizeObserverOptions` and added\n * `onUpdate`/`disabled` options.\n */\nexport interface ResizeObserverHookOptions<E extends HTMLElement> {\n /**\n * An optional ref to merge with the ref returned by this hook.\n */\n ref?: Ref<E>;\n\n /**\n * **Must be wrapped in `useCallback` to prevent re-creating the\n * ResizeObserver each render.**\n *\n * This function will be called whenever the target element resizes.\n *\n * @see {@link useResizeObserver} for an example.\n */\n onUpdate: ResizeObserverEntryCallback;\n\n /**\n * Set this to `true` to prevent observing the element's size changes. This is\n * equivalent to not attaching the returned ref to any element.\n *\n * @defaultValue `false`\n */\n disabled?: boolean;\n\n /**\n * Set this to `true` if the {@link onUpdate} should not be fired for height\n * changes.\n *\n * @defaultValue `false`\n */\n disableHeight?: boolean;\n\n /**\n * Set this to `true` if the {@link onUpdate} should not be fired for width\n * changes.\n *\n * @defaultValue `false`\n */\n disableWidth?: boolean;\n}\n\n/**\n * The resize observer is used to track the size changes of a specific element.\n * For most cases you can use the {@link useElementSize} instead, but this hook\n * can be used for more complex behavior with the {@link ResizeObserverEntry}.\n *\n * @example Simple Example\n * ```tsx\n * import { useResizeObserver } from \"@react-md/core/useResizeObserver\";\n * import { useCallback, useState, type ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const elementRef = useResizeObserver({\n * onUpdate: useCallback((entry) => {\n * const element = entry.target;\n * const { height, width } = entry.contentRect;\n * const { inlineSize, blockSize } = entry.borderBoxSize[0];\n * // do something\n * }, []),\n * });\n *\n * return <div ref={elementRef}>{...whatever...}</div>\n * }\n * ```\n *\n * @since 2.3.0\n * @since 6.0.0 The API was updated to match the `useIntersectionObserver`\n * implementation -- accepts only a single object parameter and returns a\n * {@link RefCallback} instead of `[nodeRef, refCallback]`\n */\nexport function useResizeObserver<E extends HTMLElement>(\n options: ResizeObserverHookOptions<E>\n): RefCallback<E> {\n const {\n ref,\n onUpdate,\n disabled,\n disableHeight = false,\n disableWidth = false,\n } = options;\n\n const [targetNodeRef, refCallback] = useEnsuredRef(ref);\n useEffect(() => {\n const element = targetNodeRef.current;\n if (disabled || (disableHeight && disableWidth) || !element) {\n return;\n }\n\n const unsubscribe = resizeObserverManager.subscribe({\n element,\n onUpdate,\n disableHeight,\n disableWidth,\n });\n\n return () => {\n unsubscribe();\n };\n }, [disableHeight, disableWidth, disabled, onUpdate, targetNodeRef]);\n\n return refCallback;\n}\n"],"names":["useEffect","useEnsuredRef","ResizeObserverManager","frame","subscriptions","sharedObserver","subscribe","options","element","onUpdate","disableHeight","disableWidth","observer","ResizeObserver","entries","globalThis","cancelAnimationFrame","requestAnimationFrame","handleResizeEntries","updates","get","Set","subscription","add","has","set","observe","unobserve","delete","entry","targetSubscriptions","target","values","height","width","contentRect","scrollHeight","scrollWidth","size","isHeightChange","isWidthChange","Map","resizeObserverManager","useResizeObserver","ref","disabled","targetNodeRef","refCallback","current","unsubscribe"],"mappings":"AAAA;;;;;;;;;;;;;;AAEA,SAAqCA,SAAS,QAAQ,QAAQ;AAI9D,SAASC,aAAa,QAAQ,qBAAqB;AAmCnD;;;;;;CAMC,GACD,OAAO,MAAMC;IAeX,aAAc;QAddC,uBAAAA,SAAgB;QAChBC,uBAAAA,iBAAAA,KAAAA;QAEA;;;;;;;;GAQC,GACDC,uBAAAA,kBAAAA,KAAAA;QAMAC,uBAAAA,aAAY,CAACC;YACX,MAAM,EAAEC,OAAO,EAAEC,QAAQ,EAAEC,aAAa,EAAEC,YAAY,EAAE,GAAGJ;YAE3D,+BAA+B;YAC/B,MAAMK,WACJ,IAAI,CAACP,cAAc,IACnB,IAAIQ,eAAe,CAACC;gBAClB,yDAAyD;gBACzDC,WAAWC,oBAAoB,CAAC,IAAI,CAACb,KAAK;gBAC1C,IAAI,CAACA,KAAK,GAAGY,WAAWE,qBAAqB,CAAC;oBAC5C,IAAI,CAACC,mBAAmB,CAACJ;gBAC3B;YACF;YACF,IAAI,CAACT,cAAc,GAAGO;YAEtB,MAAMO,UAAU,IAAI,CAACf,aAAa,CAACgB,GAAG,CAACZ,YAAY,IAAIa;YACvD,MAAMC,eAAmC;gBACvCb;gBACAC;gBACAC;YACF;YACAQ,QAAQI,GAAG,CAACD;YACZ,IAAI,CAAC,IAAI,CAAClB,aAAa,CAACoB,GAAG,CAAChB,UAAU;gBACpC,IAAI,CAACJ,aAAa,CAACqB,GAAG,CAACjB,SAASW;YAClC;YAEAP,SAASc,OAAO,CAAClB;YAEjB,OAAO;gBACLI,SAASe,SAAS,CAACnB;gBACnBW,QAAQS,MAAM,CAACN;YACjB;QACF;QAEAJ,uBAAAA,uBAAsB,CAACJ;YACrB,KAAK,MAAMe,SAASf,QAAS;gBAC3B,MAAMgB,sBAAsB,IAAI,CAAC1B,aAAa,CAACgB,GAAG,CAACS,MAAME,MAAM;gBAC/D,0BAA0B;gBAC1B,mBAAmB,GACnB,IAAI,CAACD,qBAAqB;oBACxB;gBACF;gBACA,kBAAkB,GAElB,MAAMhB,UAAUgB,oBAAoBE,MAAM;gBAC1C,KAAK,MAAMV,gBAAgBR,QAAS;oBAClC,MAAM,EAAEmB,MAAM,EAAEC,KAAK,EAAE,GAAGL,MAAMM,WAAW;oBAC3C,MAAM,EAAEC,YAAY,EAAEC,WAAW,EAAE,GAAGR,MAAME,MAAM;oBAClD,MAAM,EAAEtB,QAAQ,EAAE6B,IAAI,EAAE5B,aAAa,EAAEC,YAAY,EAAE,GAAGW;oBACxD,MAAMiB,iBACJ,CAAC7B,iBACA,CAAA,CAAC4B,QACAA,KAAKL,MAAM,KAAKA,UAChBK,KAAKF,YAAY,KAAKA,YAAW;oBACrC,MAAMI,gBACJ,CAAC7B,gBACA,CAAA,CAAC2B,QAAQA,KAAKJ,KAAK,KAAKA,SAASI,KAAKD,WAAW,KAAKA,WAAU;oBAEnEf,aAAagB,IAAI,GAAG;wBAClBL;wBACAC;wBACAE;wBACAC;oBACF;oBACA,IAAIE,kBAAkBC,eAAe;wBACnC/B,SAASoB;oBACX;gBACF;YACF;QACF;QAxEE,IAAI,CAACzB,aAAa,GAAG,IAAIqC;IAC3B;AAwEF;AAEA;;;CAGC,GACD,OAAO,MAAMC,wBAAwB,IAAIxC,wBAAwB;AAgDjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BC,GACD,OAAO,SAASyC,kBACdpC,OAAqC;IAErC,MAAM,EACJqC,GAAG,EACHnC,QAAQ,EACRoC,QAAQ,EACRnC,gBAAgB,KAAK,EACrBC,eAAe,KAAK,EACrB,GAAGJ;IAEJ,MAAM,CAACuC,eAAeC,YAAY,GAAG9C,cAAc2C;IACnD5C,UAAU;QACR,MAAMQ,UAAUsC,cAAcE,OAAO;QACrC,IAAIH,YAAanC,iBAAiBC,gBAAiB,CAACH,SAAS;YAC3D;QACF;QAEA,MAAMyC,cAAcP,sBAAsBpC,SAAS,CAAC;YAClDE;YACAC;YACAC;YACAC;QACF;QAEA,OAAO;YACLsC;QACF;IACF,GAAG;QAACvC;QAAeC;QAAckC;QAAUpC;QAAUqC;KAAc;IAEnE,OAAOC;AACT"}
|
|
@@ -88,7 +88,7 @@ import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect.js";
|
|
|
88
88
|
});
|
|
89
89
|
useEffect(()=>{
|
|
90
90
|
return ()=>{
|
|
91
|
-
|
|
91
|
+
globalThis.clearTimeout(timeout.current);
|
|
92
92
|
};
|
|
93
93
|
}, []);
|
|
94
94
|
return useMemo(()=>{
|
|
@@ -100,7 +100,7 @@ import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect.js";
|
|
|
100
100
|
lastCalledTime.current = now;
|
|
101
101
|
result.current = funcRef.current(...args.current);
|
|
102
102
|
} else if (!timeout.current) {
|
|
103
|
-
timeout.current =
|
|
103
|
+
timeout.current = globalThis.setTimeout(()=>{
|
|
104
104
|
lastCalledTime.current = Date.now();
|
|
105
105
|
timeout.current = undefined;
|
|
106
106
|
// should exist by this time
|
|
@@ -110,7 +110,7 @@ import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect.js";
|
|
|
110
110
|
return result.current;
|
|
111
111
|
};
|
|
112
112
|
throttled.cancel = ()=>{
|
|
113
|
-
|
|
113
|
+
globalThis.clearTimeout(timeout.current);
|
|
114
114
|
};
|
|
115
115
|
return throttled;
|
|
116
116
|
}, [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useThrottledFunction.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef } from \"react\";\n\nimport { type AnyFunction, type ThrottledFunction } from \"./types.js\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect.js\";\n\n/**\n * Creates a function that will only be called once every X milliseconds.\n *\n * @example Throttling Search API Requests\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useThrottledFunction } from \"@react-md/core/useThrottledFunction\";\n * import { useUnmounted } from \"@react-md/core/useUnmounted\";\n * import { useState } from \"react\";\n * import type { ReactElement } from \"react\";\n *\n * interface State {\n * error?: unknown\n * loading: boolean;\n * results?: {\n * // pretend some search results\n * id: string;\n * name: string;\n * }[];\n * }\n *\n * function Example(): ReactElement {\n * const [state, setState] = useState<State>({\n * loading: false,\n * });\n * // this is only required for async actions\n * const unmounted = useUnmounted();\n *\n * // A new search request will be fired once every 500ms as the user types.\n * // can't use the event here since React uses synthetic events\n * const search = useThrottledFunction(async (q: string) => {\n * setState({\n * loading: true,\n * error: undefined,\n * results: undefined,\n * });\n *\n * try {\n * const response = await fetch('/search', {\n * method: 'POST',\n * headers: {\n * 'Content-Type': 'application/json',\n * },\n * body: JSON.stringify({ q }),\n * });\n * const json = await response.json();\n *\n * if (!unmounted.current) {\n * setState({\n * loading: false,\n * results: json,\n * });\n * }\n * } catch (error) {\n * if (!unmounted.current) {\n * setState({\n * error,\n * loading: false,\n * });\n * }\n * }\n * }, 500);\n *\n * return (\n * <TextField\n * type=\"search\"\n * label=\"Search\"\n * onChange={(event) => search(event.currentTarget.value)}\n * />\n * );\n * }\n * ```\n *\n * @see `useDebouncedFunction` for debounce behavior instead. (Call a\n * function only if it has not been called again for X milliseconds).\n * @since 6.0.0\n */\nexport function useThrottledFunction<F extends AnyFunction>(\n func: F,\n wait: number\n): ThrottledFunction<F> {\n const args = useRef<Parameters<F>>();\n const result = useRef<ReturnType<F>>();\n const timeout = useRef<
|
|
1
|
+
{"version":3,"sources":["../src/useThrottledFunction.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef } from \"react\";\n\nimport { type AnyFunction, type ThrottledFunction } from \"./types.js\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect.js\";\n\n/**\n * Creates a function that will only be called once every X milliseconds.\n *\n * @example Throttling Search API Requests\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useThrottledFunction } from \"@react-md/core/useThrottledFunction\";\n * import { useUnmounted } from \"@react-md/core/useUnmounted\";\n * import { useState } from \"react\";\n * import type { ReactElement } from \"react\";\n *\n * interface State {\n * error?: unknown\n * loading: boolean;\n * results?: {\n * // pretend some search results\n * id: string;\n * name: string;\n * }[];\n * }\n *\n * function Example(): ReactElement {\n * const [state, setState] = useState<State>({\n * loading: false,\n * });\n * // this is only required for async actions\n * const unmounted = useUnmounted();\n *\n * // A new search request will be fired once every 500ms as the user types.\n * // can't use the event here since React uses synthetic events\n * const search = useThrottledFunction(async (q: string) => {\n * setState({\n * loading: true,\n * error: undefined,\n * results: undefined,\n * });\n *\n * try {\n * const response = await fetch('/search', {\n * method: 'POST',\n * headers: {\n * 'Content-Type': 'application/json',\n * },\n * body: JSON.stringify({ q }),\n * });\n * const json = await response.json();\n *\n * if (!unmounted.current) {\n * setState({\n * loading: false,\n * results: json,\n * });\n * }\n * } catch (error) {\n * if (!unmounted.current) {\n * setState({\n * error,\n * loading: false,\n * });\n * }\n * }\n * }, 500);\n *\n * return (\n * <TextField\n * type=\"search\"\n * label=\"Search\"\n * onChange={(event) => search(event.currentTarget.value)}\n * />\n * );\n * }\n * ```\n *\n * @see `useDebouncedFunction` for debounce behavior instead. (Call a\n * function only if it has not been called again for X milliseconds).\n * @since 6.0.0\n */\nexport function useThrottledFunction<F extends AnyFunction>(\n func: F,\n wait: number\n): ThrottledFunction<F> {\n const args = useRef<Parameters<F>>();\n const result = useRef<ReturnType<F>>();\n const timeout = useRef<NodeJS.Timeout>();\n const funcRef = useRef(func);\n const lastCalledTime = useRef(0);\n\n useIsomorphicLayoutEffect(() => {\n funcRef.current = func;\n });\n\n useEffect(() => {\n return () => {\n globalThis.clearTimeout(timeout.current);\n };\n }, []);\n\n return useMemo(() => {\n const throttled: ThrottledFunction<F> = (...nextArgs) => {\n args.current = nextArgs;\n\n const now = Date.now();\n const remaining = wait - (now - lastCalledTime.current);\n if (remaining <= 0 || remaining > wait) {\n lastCalledTime.current = now;\n\n result.current = funcRef.current(...args.current);\n } else if (!timeout.current) {\n timeout.current = globalThis.setTimeout(() => {\n lastCalledTime.current = Date.now();\n timeout.current = undefined;\n // should exist by this time\n\n result.current = funcRef.current(...(args.current as Parameters<F>));\n }, remaining);\n }\n\n return result.current as ReturnType<F>;\n };\n throttled.cancel = () => {\n globalThis.clearTimeout(timeout.current);\n };\n\n return throttled;\n }, [wait]);\n}\n"],"names":["useEffect","useMemo","useRef","useIsomorphicLayoutEffect","useThrottledFunction","func","wait","args","result","timeout","funcRef","lastCalledTime","current","globalThis","clearTimeout","throttled","nextArgs","now","Date","remaining","setTimeout","undefined","cancel"],"mappings":"AAAA;AAEA,SAASA,SAAS,EAAEC,OAAO,EAAEC,MAAM,QAAQ,QAAQ;AAGnD,SAASC,yBAAyB,QAAQ,iCAAiC;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4EC,GACD,OAAO,SAASC,qBACdC,IAAO,EACPC,IAAY;IAEZ,MAAMC,OAAOL;IACb,MAAMM,SAASN;IACf,MAAMO,UAAUP;IAChB,MAAMQ,UAAUR,OAAOG;IACvB,MAAMM,iBAAiBT,OAAO;IAE9BC,0BAA0B;QACxBO,QAAQE,OAAO,GAAGP;IACpB;IAEAL,UAAU;QACR,OAAO;YACLa,WAAWC,YAAY,CAACL,QAAQG,OAAO;QACzC;IACF,GAAG,EAAE;IAEL,OAAOX,QAAQ;QACb,MAAMc,YAAkC,CAAC,GAAGC;YAC1CT,KAAKK,OAAO,GAAGI;YAEf,MAAMC,MAAMC,KAAKD,GAAG;YACpB,MAAME,YAAYb,OAAQW,CAAAA,MAAMN,eAAeC,OAAO,AAAD;YACrD,IAAIO,aAAa,KAAKA,YAAYb,MAAM;gBACtCK,eAAeC,OAAO,GAAGK;gBAEzBT,OAAOI,OAAO,GAAGF,QAAQE,OAAO,IAAIL,KAAKK,OAAO;YAClD,OAAO,IAAI,CAACH,QAAQG,OAAO,EAAE;gBAC3BH,QAAQG,OAAO,GAAGC,WAAWO,UAAU,CAAC;oBACtCT,eAAeC,OAAO,GAAGM,KAAKD,GAAG;oBACjCR,QAAQG,OAAO,GAAGS;oBAClB,4BAA4B;oBAE5Bb,OAAOI,OAAO,GAAGF,QAAQE,OAAO,IAAKL,KAAKK,OAAO;gBACnD,GAAGO;YACL;YAEA,OAAOX,OAAOI,OAAO;QACvB;QACAG,UAAUO,MAAM,GAAG;YACjBT,WAAWC,YAAY,CAACL,QAAQG,OAAO;QACzC;QAEA,OAAOG;IACT,GAAG;QAACT;KAAK;AACX"}
|
package/dist/useWindowSize.js
CHANGED
|
@@ -28,7 +28,7 @@ import { useResizeListener } from "./useResizeListener.js";
|
|
|
28
28
|
const { once, signal, capture, passive, throttle, ssrHeight = 0, ssrWidth = 0, disableWidth, disableHeight } = options;
|
|
29
29
|
const ssr = useSsr();
|
|
30
30
|
const [size, setSize] = useState(()=>{
|
|
31
|
-
if (
|
|
31
|
+
if (globalThis.window === undefined || ssr) {
|
|
32
32
|
return {
|
|
33
33
|
height: ssrHeight,
|
|
34
34
|
width: ssrWidth
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useWindowSize.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useState } from \"react\";\n\nimport { useSsr } from \"./SsrProvider.js\";\nimport { type ElementSize } from \"./types.js\";\nimport {\n type ResizeListenerOptions,\n useResizeListener,\n} from \"./useResizeListener.js\";\n\n/**\n * @since 6.0.0\n */\nexport interface WindowSizeOptions extends Omit<\n ResizeListenerOptions,\n \"disabled\" | \"onUpdate\"\n> {\n /**\n * The default value to use in SSR environments for the window's height.\n *\n * @defaultValue `0`\n */\n ssrHeight?: number;\n\n /**\n * The default value to use in SSR environments for the window's width.\n *\n * @defaultValue `0`\n */\n ssrWidth?: number;\n\n /**\n * Set this to `true` to ignore resize events that only updated the height.\n * The hook can be disabled by setting this and {@link disableWidth} to\n * `true`.\n *\n * @defaultValue `false`\n */\n disableHeight?: boolean;\n\n /**\n * Set this to `true` to ignore resize events that only updated the width.\n * The hook can be disabled by setting this and {@link disableHeight} to\n * `true`.\n *\n * @defaultValue `false`\n */\n disableWidth?: boolean;\n}\n\n/**\n * This is just a convenience wrapper around the {@link useResizeListener}.\n *\n * @example Simple Example\n * ```tsx\n * import { useWindowSize } from \"@react-md/core/useWindowSize\";\n * import type { ReactElement } from \"react\";\n * import { useState } from \"react\";\n *\n * function Example(): ReactElement {\n * const { height, width } = useWindowSize();\n *\n * return (\n * <>\n * The current window size:\n * <pre><code>{JSON.stringify(size, null, 2)}</code></pre>\n * </>\n * );\n * }\n * ```\n *\n * @since 6.0.0\n */\nexport function useWindowSize(options: WindowSizeOptions = {}): ElementSize {\n const {\n once,\n signal,\n capture,\n passive,\n throttle,\n ssrHeight = 0,\n ssrWidth = 0,\n disableWidth,\n disableHeight,\n } = options;\n\n const ssr = useSsr();\n const [size, setSize] = useState(() => {\n if (
|
|
1
|
+
{"version":3,"sources":["../src/useWindowSize.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useState } from \"react\";\n\nimport { useSsr } from \"./SsrProvider.js\";\nimport { type ElementSize } from \"./types.js\";\nimport {\n type ResizeListenerOptions,\n useResizeListener,\n} from \"./useResizeListener.js\";\n\n/**\n * @since 6.0.0\n */\nexport interface WindowSizeOptions extends Omit<\n ResizeListenerOptions,\n \"disabled\" | \"onUpdate\"\n> {\n /**\n * The default value to use in SSR environments for the window's height.\n *\n * @defaultValue `0`\n */\n ssrHeight?: number;\n\n /**\n * The default value to use in SSR environments for the window's width.\n *\n * @defaultValue `0`\n */\n ssrWidth?: number;\n\n /**\n * Set this to `true` to ignore resize events that only updated the height.\n * The hook can be disabled by setting this and {@link disableWidth} to\n * `true`.\n *\n * @defaultValue `false`\n */\n disableHeight?: boolean;\n\n /**\n * Set this to `true` to ignore resize events that only updated the width.\n * The hook can be disabled by setting this and {@link disableHeight} to\n * `true`.\n *\n * @defaultValue `false`\n */\n disableWidth?: boolean;\n}\n\n/**\n * This is just a convenience wrapper around the {@link useResizeListener}.\n *\n * @example Simple Example\n * ```tsx\n * import { useWindowSize } from \"@react-md/core/useWindowSize\";\n * import type { ReactElement } from \"react\";\n * import { useState } from \"react\";\n *\n * function Example(): ReactElement {\n * const { height, width } = useWindowSize();\n *\n * return (\n * <>\n * The current window size:\n * <pre><code>{JSON.stringify(size, null, 2)}</code></pre>\n * </>\n * );\n * }\n * ```\n *\n * @since 6.0.0\n */\nexport function useWindowSize(options: WindowSizeOptions = {}): ElementSize {\n const {\n once,\n signal,\n capture,\n passive,\n throttle,\n ssrHeight = 0,\n ssrWidth = 0,\n disableWidth,\n disableHeight,\n } = options;\n\n const ssr = useSsr();\n const [size, setSize] = useState(() => {\n if (globalThis.window === undefined || ssr) {\n return {\n height: ssrHeight,\n width: ssrWidth,\n };\n }\n\n return {\n height: window.innerHeight,\n width: window.innerWidth,\n };\n });\n\n useResizeListener({\n once,\n signal,\n capture,\n passive,\n throttle,\n disabled: disableHeight && disableWidth,\n onUpdate: useCallback(() => {\n setSize((prevSize) => {\n const nextSize: ElementSize = {\n height: window.innerHeight,\n width: window.innerWidth,\n };\n\n const isHeightChange =\n !disableHeight && prevSize.height !== nextSize.height;\n const isWidthChange =\n !disableWidth && prevSize.width !== nextSize.width;\n\n return isHeightChange || isWidthChange ? nextSize : prevSize;\n });\n }, [disableHeight, disableWidth]),\n });\n\n return size;\n}\n"],"names":["useCallback","useState","useSsr","useResizeListener","useWindowSize","options","once","signal","capture","passive","throttle","ssrHeight","ssrWidth","disableWidth","disableHeight","ssr","size","setSize","globalThis","window","undefined","height","width","innerHeight","innerWidth","disabled","onUpdate","prevSize","nextSize","isHeightChange","isWidthChange"],"mappings":"AAAA;AAEA,SAASA,WAAW,EAAEC,QAAQ,QAAQ,QAAQ;AAE9C,SAASC,MAAM,QAAQ,mBAAmB;AAE1C,SAEEC,iBAAiB,QACZ,yBAAyB;AA0ChC;;;;;;;;;;;;;;;;;;;;;;CAsBC,GACD,OAAO,SAASC,cAAcC,UAA6B,CAAC,CAAC;IAC3D,MAAM,EACJC,IAAI,EACJC,MAAM,EACNC,OAAO,EACPC,OAAO,EACPC,QAAQ,EACRC,YAAY,CAAC,EACbC,WAAW,CAAC,EACZC,YAAY,EACZC,aAAa,EACd,GAAGT;IAEJ,MAAMU,MAAMb;IACZ,MAAM,CAACc,MAAMC,QAAQ,GAAGhB,SAAS;QAC/B,IAAIiB,WAAWC,MAAM,KAAKC,aAAaL,KAAK;YAC1C,OAAO;gBACLM,QAAQV;gBACRW,OAAOV;YACT;QACF;QAEA,OAAO;YACLS,QAAQF,OAAOI,WAAW;YAC1BD,OAAOH,OAAOK,UAAU;QAC1B;IACF;IAEArB,kBAAkB;QAChBG;QACAC;QACAC;QACAC;QACAC;QACAe,UAAUX,iBAAiBD;QAC3Ba,UAAU1B,YAAY;YACpBiB,QAAQ,CAACU;gBACP,MAAMC,WAAwB;oBAC5BP,QAAQF,OAAOI,WAAW;oBAC1BD,OAAOH,OAAOK,UAAU;gBAC1B;gBAEA,MAAMK,iBACJ,CAACf,iBAAiBa,SAASN,MAAM,KAAKO,SAASP,MAAM;gBACvD,MAAMS,gBACJ,CAACjB,gBAAgBc,SAASL,KAAK,KAAKM,SAASN,KAAK;gBAEpD,OAAOO,kBAAkBC,gBAAgBF,WAAWD;YACtD;QACF,GAAG;YAACb;YAAeD;SAAa;IAClC;IAEA,OAAOG;AACT"}
|