@react-md/core 1.0.0-next.16 → 1.0.0-next.17
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/_box-shadows.scss +76 -0
- package/dist/_colors.scss +279 -277
- package/dist/_core.scss +107 -16
- package/dist/_object-fit.scss +86 -0
- package/dist/_utils.scss +246 -72
- package/dist/app-bar/AppBar.d.ts +1 -90
- package/dist/app-bar/AppBar.js +1 -40
- package/dist/app-bar/AppBar.js.map +1 -1
- package/dist/app-bar/AppBarTitle.d.ts +1 -27
- package/dist/app-bar/AppBarTitle.js +1 -15
- package/dist/app-bar/AppBarTitle.js.map +1 -1
- package/dist/app-bar/_app-bar.scss +156 -25
- package/dist/app-bar/styles.d.ts +117 -0
- package/dist/app-bar/styles.js +55 -0
- package/dist/app-bar/styles.js.map +1 -0
- package/dist/autocomplete/Autocomplete.d.ts +8 -79
- package/dist/autocomplete/Autocomplete.js +112 -83
- package/dist/autocomplete/Autocomplete.js.map +1 -1
- package/dist/autocomplete/AutocompleteChip.d.ts +8 -0
- package/dist/autocomplete/AutocompleteChip.js +34 -0
- package/dist/autocomplete/AutocompleteChip.js.map +1 -0
- package/dist/autocomplete/AutocompleteCircularProgress.d.ts +5 -11
- package/dist/autocomplete/AutocompleteCircularProgress.js +4 -0
- package/dist/autocomplete/AutocompleteCircularProgress.js.map +1 -1
- package/dist/autocomplete/AutocompleteClearButton.d.ts +9 -0
- package/dist/autocomplete/AutocompleteClearButton.js +29 -0
- package/dist/autocomplete/AutocompleteClearButton.js.map +1 -0
- package/dist/autocomplete/AutocompleteDropdownButton.d.ts +4 -26
- package/dist/autocomplete/AutocompleteDropdownButton.js +5 -1
- package/dist/autocomplete/AutocompleteDropdownButton.js.map +1 -1
- package/dist/autocomplete/AutocompleteListboxChildren.d.ts +22 -0
- package/dist/autocomplete/AutocompleteListboxChildren.js +37 -0
- package/dist/autocomplete/AutocompleteListboxChildren.js.map +1 -0
- package/dist/autocomplete/_autocomplete.scss +362 -34
- package/dist/autocomplete/autocompleteStyles.d.ts +22 -0
- package/dist/autocomplete/autocompleteStyles.js +17 -8
- package/dist/autocomplete/autocompleteStyles.js.map +1 -1
- package/dist/autocomplete/defaults.d.ts +9 -9
- package/dist/autocomplete/defaults.js +13 -13
- package/dist/autocomplete/defaults.js.map +1 -1
- package/dist/autocomplete/types.d.ts +554 -56
- package/dist/autocomplete/types.js.map +1 -1
- package/dist/autocomplete/useAutocomplete.d.ts +22 -0
- package/dist/autocomplete/useAutocomplete.js +281 -0
- package/dist/autocomplete/useAutocomplete.js.map +1 -0
- package/dist/autocomplete/utils.d.ts +81 -0
- package/dist/autocomplete/utils.js +108 -0
- package/dist/autocomplete/utils.js.map +1 -0
- package/dist/avatar/_avatar.scss +93 -2
- package/dist/badge/Badge.d.ts +1 -20
- package/dist/badge/Badge.js +1 -14
- package/dist/badge/Badge.js.map +1 -1
- package/dist/badge/_badge.scss +90 -3
- package/dist/badge/styles.d.ts +26 -0
- package/dist/badge/styles.js +18 -0
- package/dist/badge/styles.js.map +1 -0
- package/dist/box/Box.js +2 -1
- package/dist/box/Box.js.map +1 -1
- package/dist/box/_box.scss +130 -17
- package/dist/box/styles.d.ts +6 -0
- package/dist/box/styles.js +2 -1
- package/dist/box/styles.js.map +1 -1
- package/dist/button/AsyncButton.d.ts +1 -1
- package/dist/button/AsyncButton.js.map +1 -1
- package/dist/button/Button.d.ts +2 -1
- package/dist/button/Button.js +2 -1
- package/dist/button/Button.js.map +1 -1
- package/dist/button/_button.scss +157 -25
- package/dist/card/Card.d.ts +16 -0
- package/dist/card/Card.js +11 -3
- package/dist/card/Card.js.map +1 -1
- package/dist/card/ClickableCard.d.ts +2 -1
- package/dist/card/ClickableCard.js +5 -2
- package/dist/card/ClickableCard.js.map +1 -1
- package/dist/card/_card.scss +90 -19
- package/dist/card/styles.d.ts +0 -7
- package/dist/card/styles.js +2 -3
- package/dist/card/styles.js.map +1 -1
- package/dist/chip/Chip.d.ts +2 -1
- package/dist/chip/Chip.js +2 -1
- package/dist/chip/Chip.js.map +1 -1
- package/dist/chip/_chip.scss +42 -20
- package/dist/chip/styles.d.ts +12 -10
- package/dist/chip/styles.js.map +1 -1
- package/dist/cssUtils.js.map +1 -1
- package/dist/delegateEvent.d.ts +2 -2
- package/dist/delegateEvent.js.map +1 -1
- package/dist/dialog/Dialog.d.ts +8 -21
- package/dist/dialog/Dialog.js +27 -27
- package/dist/dialog/Dialog.js.map +1 -1
- package/dist/dialog/FixedDialog.d.ts +1 -3
- package/dist/dialog/FixedDialog.js +0 -8
- package/dist/dialog/FixedDialog.js.map +1 -1
- package/dist/dialog/_dialog.scss +67 -13
- package/dist/dialog/styles.d.ts +56 -0
- package/dist/dialog/styles.js +29 -2
- package/dist/dialog/styles.js.map +1 -1
- package/dist/divider/Divider.d.ts +0 -11
- package/dist/divider/Divider.js.map +1 -1
- package/dist/divider/_divider.scss +7 -1
- package/dist/divider/styles.d.ts +11 -0
- package/dist/divider/styles.js.map +1 -1
- package/dist/draggable/useDraggable.d.ts +6 -6
- package/dist/draggable/useDraggable.js.map +1 -1
- package/dist/draggable/utils.d.ts +3 -3
- package/dist/draggable/utils.js.map +1 -1
- package/dist/expansion-panel/ExpansionPanel.d.ts +1 -1
- package/dist/expansion-panel/ExpansionPanel.js.map +1 -1
- package/dist/expansion-panel/_expansion-panel.scss +5 -1
- package/dist/expansion-panel/useExpansionPanels.js +12 -24
- package/dist/expansion-panel/useExpansionPanels.js.map +1 -1
- package/dist/{form → files}/FileInput.d.ts +3 -6
- package/dist/{form → files}/FileInput.js +3 -6
- package/dist/files/FileInput.js.map +1 -0
- package/dist/files/_files.scss +22 -0
- package/dist/files/styles.d.ts +5 -0
- package/dist/files/styles.js +7 -0
- package/dist/files/styles.js.map +1 -0
- package/dist/{form → files}/useFileUpload.d.ts +7 -9
- package/dist/{form → files}/useFileUpload.js +5 -7
- package/dist/files/useFileUpload.js.map +1 -0
- package/dist/files/utils.d.ts +169 -0
- package/dist/files/utils.js +114 -0
- package/dist/files/utils.js.map +1 -0
- package/dist/{form/fileUtils.d.ts → files/validation.d.ts} +9 -174
- package/dist/{form/fileUtils.js → files/validation.js} +9 -134
- package/dist/files/validation.js.map +1 -0
- package/dist/focus/useFocusContainer.d.ts +2 -2
- package/dist/focus/useFocusContainer.js.map +1 -1
- package/dist/focus/utils.js.map +1 -1
- package/dist/form/FormMessage.js.map +1 -1
- package/dist/form/FormMessageContainer.js +4 -2
- package/dist/form/FormMessageContainer.js.map +1 -1
- package/dist/form/InputToggle.d.ts +2 -1
- package/dist/form/InputToggle.js +2 -1
- package/dist/form/InputToggle.js.map +1 -1
- package/dist/form/InputToggleIcon.js.map +1 -1
- package/dist/form/Label.js +2 -2
- package/dist/form/Label.js.map +1 -1
- package/dist/form/Listbox.d.ts +24 -0
- package/dist/form/Listbox.js +46 -0
- package/dist/form/Listbox.js.map +1 -0
- package/dist/form/ListboxProvider.d.ts +21 -0
- package/dist/form/{useListboxProvider.js → ListboxProvider.js} +1 -1
- package/dist/form/ListboxProvider.js.map +1 -0
- package/dist/form/MenuItemTextField.js +1 -2
- package/dist/form/MenuItemTextField.js.map +1 -1
- package/dist/form/NativeSelect.js +7 -4
- package/dist/form/NativeSelect.js.map +1 -1
- package/dist/form/Option.d.ts +49 -10
- package/dist/form/Option.js +11 -9
- package/dist/form/Option.js.map +1 -1
- package/dist/form/Password.js.map +1 -1
- package/dist/form/Select.d.ts +2 -2
- package/dist/form/Select.js +81 -85
- package/dist/form/Select.js.map +1 -1
- package/dist/form/Slider.d.ts +4 -4
- package/dist/form/Slider.js +6 -2
- package/dist/form/Slider.js.map +1 -1
- package/dist/form/SliderThumb.d.ts +3 -3
- package/dist/form/SliderThumb.js.map +1 -1
- package/dist/form/SliderValueMarks.d.ts +2 -2
- package/dist/form/SliderValueMarks.js.map +1 -1
- package/dist/form/SliderValueTooltip.js.map +1 -1
- package/dist/form/TextArea.js +1 -2
- package/dist/form/TextArea.js.map +1 -1
- package/dist/form/TextField.js +1 -2
- package/dist/form/TextField.js.map +1 -1
- package/dist/form/TextFieldContainer.js +1 -2
- package/dist/form/TextFieldContainer.js.map +1 -1
- package/dist/form/_form.scss +186 -121
- package/dist/form/formMessageContainerStyles.d.ts +10 -0
- package/dist/form/formMessageContainerStyles.js +11 -0
- package/dist/form/formMessageContainerStyles.js.map +1 -0
- package/dist/form/inputToggleStyles.js.map +1 -1
- package/dist/form/optionStyles.d.ts +1 -0
- package/dist/form/optionStyles.js +2 -2
- package/dist/form/optionStyles.js.map +1 -1
- package/dist/form/selectUtils.js.map +1 -1
- package/dist/form/sliderUtils.d.ts +1 -1
- package/dist/form/sliderUtils.js.map +1 -1
- package/dist/form/textFieldContainerStyles.d.ts +0 -2
- package/dist/form/textFieldContainerStyles.js +1 -2
- package/dist/form/textFieldContainerStyles.js.map +1 -1
- package/dist/form/types.d.ts +3 -10
- package/dist/form/types.js.map +1 -1
- package/dist/form/useCheckboxGroup.d.ts +17 -17
- package/dist/form/useCheckboxGroup.js +9 -17
- package/dist/form/useCheckboxGroup.js.map +1 -1
- package/dist/form/useCombobox.d.ts +56 -21
- package/dist/form/useCombobox.js +19 -4
- package/dist/form/useCombobox.js.map +1 -1
- package/dist/form/useEditableCombobox.d.ts +24 -4
- package/dist/form/useEditableCombobox.js +5 -0
- package/dist/form/useEditableCombobox.js.map +1 -1
- package/dist/form/useNumberField.js.map +1 -1
- package/dist/form/useRadioGroup.d.ts +6 -6
- package/dist/form/useRadioGroup.js.map +1 -1
- package/dist/form/useResizingTextArea.js.map +1 -1
- package/dist/form/useSelectCombobox.d.ts +3 -4
- package/dist/form/useSelectCombobox.js.map +1 -1
- package/dist/form/useTextField.d.ts +1 -1
- package/dist/form/useTextField.js.map +1 -1
- package/dist/form/useTextFieldContainerAddons.js.map +1 -1
- package/dist/hoverMode/useHoverMode.d.ts +3 -3
- package/dist/hoverMode/useHoverMode.js.map +1 -1
- package/dist/hoverMode/useHoverModeProvider.d.ts +4 -4
- package/dist/hoverMode/useHoverModeProvider.js.map +1 -1
- package/dist/icon/_icon.scss +151 -2
- package/dist/icon/iconConfig.d.ts +10 -0
- package/dist/icon/iconConfig.js +7 -0
- package/dist/icon/iconConfig.js.map +1 -1
- package/dist/icon/materialConfig.js.map +1 -1
- package/dist/icon/styles.js.map +1 -1
- package/dist/interaction/UserInteractionModeProvider.d.ts +5 -5
- package/dist/interaction/UserInteractionModeProvider.js +12 -8
- package/dist/interaction/UserInteractionModeProvider.js.map +1 -1
- package/dist/interaction/types.d.ts +20 -2
- package/dist/interaction/types.js.map +1 -1
- package/dist/interaction/useElementInteraction.d.ts +7 -1
- package/dist/interaction/useElementInteraction.js +1 -2
- package/dist/interaction/useElementInteraction.js.map +1 -1
- package/dist/interaction/utils.d.ts +2 -2
- package/dist/interaction/utils.js +2 -2
- package/dist/interaction/utils.js.map +1 -1
- package/dist/layout/LayoutWindowSplitter.js.map +1 -1
- package/dist/layout/_layout.scss +23 -10
- package/dist/layout/useExpandableLayout.d.ts +3 -3
- package/dist/layout/useExpandableLayout.js.map +1 -1
- package/dist/layout/useLayoutAppBarHeight.d.ts +2 -3
- package/dist/layout/useLayoutAppBarHeight.js.map +1 -1
- package/dist/layout/useTemporaryLayout.d.ts +2 -2
- package/dist/layout/useTemporaryLayout.js.map +1 -1
- package/dist/link/SkipToMainContent.js.map +1 -1
- package/dist/list/ListItem.d.ts +2 -1
- package/dist/list/ListItem.js +2 -1
- package/dist/list/ListItem.js.map +1 -1
- package/dist/list/ListItemChildren.js.map +1 -1
- package/dist/list/ListItemLink.d.ts +2 -1
- package/dist/list/ListItemLink.js +2 -1
- package/dist/list/ListItemLink.js.map +1 -1
- package/dist/list/_list.scss +6 -5
- package/dist/media-queries/_media-queries.scss +12 -0
- package/dist/media-queries/appSize.js.map +1 -1
- package/dist/media-queries/useMediaQuery.js +3 -1
- package/dist/media-queries/useMediaQuery.js.map +1 -1
- package/dist/menu/DropdownMenu.js.map +1 -1
- package/dist/menu/Menu.d.ts +8 -3
- package/dist/menu/Menu.js +2 -1
- package/dist/menu/Menu.js.map +1 -1
- package/dist/menu/MenuItemButton.js +6 -2
- package/dist/menu/MenuItemButton.js.map +1 -1
- package/dist/menu/useContextMenu.d.ts +3 -3
- package/dist/menu/useContextMenu.js.map +1 -1
- package/dist/movement/types.d.ts +5 -5
- package/dist/movement/types.js.map +1 -1
- package/dist/navigation/CollapsibleNavGroup.d.ts +5 -3
- package/dist/navigation/CollapsibleNavGroup.js +3 -4
- package/dist/navigation/CollapsibleNavGroup.js.map +1 -1
- package/dist/navigation/DefaultNavigationRenderer.d.ts +1 -2
- package/dist/navigation/DefaultNavigationRenderer.js +6 -2
- package/dist/navigation/DefaultNavigationRenderer.js.map +1 -1
- package/dist/navigation/NavItemButton.d.ts +1 -1
- package/dist/navigation/NavItemButton.js +1 -0
- package/dist/navigation/NavItemButton.js.map +1 -1
- package/dist/navigation/NavItemLink.d.ts +3 -2
- package/dist/navigation/NavItemLink.js +6 -2
- package/dist/navigation/NavItemLink.js.map +1 -1
- package/dist/navigation/NavSubheader.d.ts +2 -3
- package/dist/navigation/NavSubheader.js.map +1 -1
- package/dist/navigation/Navigation.d.ts +1 -1
- package/dist/navigation/Navigation.js.map +1 -1
- package/dist/navigation/_navigation.scss +6 -5
- package/dist/navigation/types.d.ts +54 -6
- package/dist/navigation/types.js.map +1 -1
- package/dist/navigation/useActiveHeadingId.d.ts +1 -1
- package/dist/navigation/useActiveHeadingId.js.map +1 -1
- package/dist/navigation/useNavigationExpansion.d.ts +104 -0
- package/dist/navigation/useNavigationExpansion.js +77 -0
- package/dist/navigation/useNavigationExpansion.js.map +1 -0
- package/dist/navigation/utils.d.ts +13 -0
- package/dist/navigation/utils.js +36 -0
- package/dist/navigation/utils.js.map +1 -0
- package/dist/objectFit.d.ts +69 -0
- package/dist/objectFit.js +52 -0
- package/dist/objectFit.js.map +1 -0
- package/dist/overlay/_overlay.scss +2 -1
- package/dist/positioning/useFixedPositioning.d.ts +17 -4
- package/dist/positioning/useFixedPositioning.js +10 -5
- package/dist/positioning/useFixedPositioning.js.map +1 -1
- package/dist/positioning/utils.js.map +1 -1
- package/dist/progress/LinearProgress.js.map +1 -1
- package/dist/progress/_progress.scss +20 -14
- package/dist/responsive-item/ResponsiveItem.d.ts +64 -0
- package/dist/responsive-item/ResponsiveItem.js +68 -0
- package/dist/responsive-item/ResponsiveItem.js.map +1 -0
- package/dist/responsive-item/ResponsiveItemOverlay.d.ts +1 -19
- package/dist/responsive-item/ResponsiveItemOverlay.js +1 -12
- package/dist/responsive-item/ResponsiveItemOverlay.js.map +1 -1
- package/dist/responsive-item/_responsive-item.scss +110 -133
- package/dist/responsive-item/responsiveItemOverlayStyles.d.ts +19 -0
- package/dist/responsive-item/responsiveItemOverlayStyles.js +14 -0
- package/dist/responsive-item/responsiveItemOverlayStyles.js.map +1 -0
- package/dist/responsive-item/responsiveItemStyles.d.ts +52 -0
- package/dist/responsive-item/responsiveItemStyles.js +15 -0
- package/dist/responsive-item/responsiveItemStyles.js.map +1 -0
- package/dist/scroll/useScrollLock.d.ts +5 -0
- package/dist/scroll/useScrollLock.js.map +1 -1
- package/dist/searching/utils.d.ts +2 -2
- package/dist/searching/utils.js.map +1 -1
- package/dist/segmented-button/SegmentedButton.d.ts +2 -1
- package/dist/segmented-button/SegmentedButton.js +2 -1
- package/dist/segmented-button/SegmentedButton.js.map +1 -1
- package/dist/segmented-button/_segmented-button.scss +6 -6
- package/dist/sheet/_sheet.scss +18 -6
- package/dist/snackbar/ToastManager.js +15 -5
- package/dist/snackbar/ToastManager.js.map +1 -1
- package/dist/snackbar/_snackbar.scss +30 -17
- package/dist/snackbar/useCurrentToastActions.d.ts +5 -5
- package/dist/snackbar/useCurrentToastActions.js.map +1 -1
- package/dist/table/_table.scss +15 -3
- package/dist/table/tableCellStyles.d.ts +7 -3
- package/dist/table/tableCellStyles.js +2 -2
- package/dist/table/tableCellStyles.js.map +1 -1
- package/dist/tabs/Tab.d.ts +2 -1
- package/dist/tabs/Tab.js +2 -1
- package/dist/tabs/Tab.js.map +1 -1
- package/dist/tabs/TabList.d.ts +2 -2
- package/dist/tabs/TabList.js.map +1 -1
- package/dist/tabs/TabListScrollButton.d.ts +1 -1
- package/dist/tabs/TabListScrollButton.js +1 -1
- package/dist/tabs/TabListScrollButton.js.map +1 -1
- package/dist/tabs/_tabs.scss +30 -9
- package/dist/tabs/getTabListScrollToOptions.d.ts +18 -0
- package/dist/tabs/getTabListScrollToOptions.js +19 -0
- package/dist/tabs/getTabListScrollToOptions.js.map +1 -0
- package/dist/tabs/tabStyles.d.ts +3 -0
- package/dist/tabs/tabStyles.js.map +1 -1
- package/dist/tabs/useTabList.d.ts +1 -8
- package/dist/tabs/useTabList.js +1 -0
- package/dist/tabs/useTabList.js.map +1 -1
- package/dist/tabs/useTabs.d.ts +6 -6
- package/dist/tabs/useTabs.js.map +1 -1
- package/dist/tabs/utils.d.ts +0 -18
- package/dist/tabs/utils.js +0 -15
- package/dist/tabs/utils.js.map +1 -1
- package/dist/test-utils/matchMedia.d.ts +1 -1
- package/dist/test-utils/matchMedia.js +4 -4
- package/dist/test-utils/matchMedia.js.map +1 -1
- package/dist/test-utils/polyfills/TextDecoder.js +0 -1
- package/dist/test-utils/polyfills/TextDecoder.js.map +1 -1
- package/dist/test-utils/timers.d.ts +9 -5
- package/dist/test-utils/timers.js +5 -5
- package/dist/test-utils/timers.js.map +1 -1
- package/dist/theme/LocalStorageColorSchemeProvider.d.ts +1 -1
- package/dist/theme/LocalStorageColorSchemeProvider.js +2 -1
- package/dist/theme/LocalStorageColorSchemeProvider.js.map +1 -1
- package/dist/theme/ThemeProvider.js +3 -1
- package/dist/theme/ThemeProvider.js.map +1 -1
- package/dist/theme/_a11y.scss +77 -13
- package/dist/theme/_colors.scss +279 -277
- package/dist/theme/_theme.scss +308 -37
- package/dist/theme/isColorScheme.d.ts +16 -0
- package/dist/theme/isColorScheme.js +19 -0
- package/dist/theme/isColorScheme.js.map +1 -0
- package/dist/theme/types.d.ts +53 -1
- package/dist/theme/types.js +1 -23
- package/dist/theme/types.js.map +1 -1
- package/dist/theme/useCSSVariables.d.ts +2 -19
- package/dist/theme/useCSSVariables.js.map +1 -1
- package/dist/theme/useColorScheme.d.ts +1 -35
- package/dist/theme/useColorScheme.js.map +1 -1
- package/dist/theme/useColorSchemeMetaTag.d.ts +1 -1
- package/dist/theme/useColorSchemeMetaTag.js.map +1 -1
- package/dist/theme/useColorSchemeProvider.d.ts +1 -1
- package/dist/theme/useColorSchemeProvider.js +1 -1
- package/dist/theme/useColorSchemeProvider.js.map +1 -1
- package/dist/theme/{usePrefersColorScheme.js → usePrefersDarkScheme.js} +1 -1
- package/dist/theme/usePrefersDarkScheme.js.map +1 -0
- package/dist/theme/utils.js.map +1 -1
- package/dist/tooltip/useTooltip.d.ts +14 -9
- package/dist/tooltip/useTooltip.js +2 -1
- package/dist/tooltip/useTooltip.js.map +1 -1
- package/dist/transition/_transition.scss +16 -9
- package/dist/transition/skeletonPlaceholderUtils.js.map +1 -1
- package/dist/transition/types.d.ts +1 -1
- package/dist/transition/types.js.map +1 -1
- package/dist/transition/useCarousel.d.ts +3 -3
- package/dist/transition/useCarousel.js.map +1 -1
- package/dist/transition/useCollapseTransition.js.map +1 -1
- package/dist/transition/useTransition.js +1 -0
- package/dist/transition/useTransition.js.map +1 -1
- package/dist/transition/utils.js.map +1 -1
- package/dist/tree/TreeItem.d.ts +2 -1
- package/dist/tree/TreeItem.js +4 -3
- package/dist/tree/TreeItem.js.map +1 -1
- package/dist/tree/TreeItemExpander.js.map +1 -1
- package/dist/tree/_tree.scss +8 -6
- package/dist/tree/useTreeExpansion.d.ts +1 -1
- package/dist/tree/useTreeExpansion.js +6 -18
- package/dist/tree/useTreeExpansion.js.map +1 -1
- package/dist/tree/useTreeSelection.d.ts +1 -1
- package/dist/tree/useTreeSelection.js +7 -25
- package/dist/tree/useTreeSelection.js.map +1 -1
- package/dist/tree/utils.d.ts +1 -1
- package/dist/tree/utils.js.map +1 -1
- package/dist/types.d.ts +12 -4
- package/dist/types.js.map +1 -1
- package/dist/typography/WritingDirectionProvider.d.ts +1 -1
- package/dist/typography/WritingDirectionProvider.js.map +1 -1
- package/dist/typography/_typography.scss +94 -37
- package/dist/typography/typographyStyles.js.map +1 -1
- package/dist/useDebouncedFunction.d.ts +1 -5
- package/dist/useDebouncedFunction.js +3 -1
- package/dist/useDebouncedFunction.js.map +1 -1
- package/dist/useDropzone.d.ts +4 -4
- package/dist/useDropzone.js.map +1 -1
- package/dist/useEnsuredId.js.map +1 -1
- package/dist/useIntersectionObserver.d.ts +5 -5
- package/dist/useIntersectionObserver.js.map +1 -1
- package/dist/useLocalStorage.d.ts +3 -3
- package/dist/useLocalStorage.js +1 -1
- package/dist/useLocalStorage.js.map +1 -1
- package/dist/useMutationObserver.d.ts +1 -1
- package/dist/useMutationObserver.js.map +1 -1
- package/dist/useOrientation.js +3 -1
- package/dist/useOrientation.js.map +1 -1
- package/dist/usePageInactive.d.ts +2 -2
- package/dist/usePageInactive.js.map +1 -1
- package/dist/useReadonlySet.d.ts +76 -0
- package/dist/useReadonlySet.js +72 -0
- package/dist/useReadonlySet.js.map +1 -0
- package/dist/useResizeListener.d.ts +1 -1
- package/dist/useResizeListener.js.map +1 -1
- package/dist/useThrottledFunction.d.ts +1 -5
- package/dist/useThrottledFunction.js +3 -1
- package/dist/useThrottledFunction.js.map +1 -1
- package/dist/useToggle.d.ts +3 -3
- package/dist/useToggle.js.map +1 -1
- package/dist/utils/RenderRecursively.d.ts +1 -1
- package/dist/utils/RenderRecursively.js.map +1 -1
- package/dist/utils/alphaNumericSort.d.ts +1 -1
- package/dist/utils/alphaNumericSort.js.map +1 -1
- package/dist/utils/bem.js.map +1 -1
- package/dist/utils/debounce.d.ts +5 -0
- package/dist/utils/debounce.js +17 -0
- package/dist/utils/debounce.js.map +1 -0
- package/dist/utils/nearest.js.map +1 -1
- package/dist/utils/parseCssLengthUnit.js.map +1 -1
- package/dist/utils/throttle.d.ts +5 -0
- package/dist/utils/throttle.js +30 -0
- package/dist/utils/throttle.js.map +1 -0
- package/dist/utils/wait.js +3 -1
- package/dist/utils/wait.js.map +1 -1
- package/dist/window-splitter/WindowSplitter.d.ts +37 -15
- package/dist/window-splitter/WindowSplitter.js +38 -17
- package/dist/window-splitter/WindowSplitter.js.map +1 -1
- package/dist/window-splitter/_window-splitter.scss +32 -14
- package/dist/window-splitter/styles.d.ts +14 -0
- package/dist/window-splitter/styles.js +18 -0
- package/dist/window-splitter/styles.js.map +1 -0
- package/package.json +24 -23
- package/src/app-bar/AppBar.tsx +1 -170
- package/src/app-bar/AppBarTitle.tsx +1 -44
- package/src/app-bar/styles.ts +206 -0
- package/src/autocomplete/Autocomplete.tsx +194 -211
- package/src/autocomplete/AutocompleteChip.tsx +48 -0
- package/src/autocomplete/AutocompleteCircularProgress.tsx +6 -17
- package/src/autocomplete/AutocompleteClearButton.tsx +44 -0
- package/src/autocomplete/AutocompleteDropdownButton.tsx +16 -37
- package/src/autocomplete/AutocompleteListboxChildren.tsx +68 -0
- package/src/autocomplete/autocompleteStyles.ts +48 -9
- package/src/autocomplete/defaults.ts +26 -17
- package/src/autocomplete/types.ts +744 -61
- package/src/autocomplete/useAutocomplete.ts +428 -0
- package/src/autocomplete/utils.ts +211 -0
- package/src/badge/Badge.tsx +1 -39
- package/src/badge/styles.ts +45 -0
- package/src/box/Box.tsx +11 -9
- package/src/box/styles.ts +14 -5
- package/src/button/AsyncButton.tsx +1 -1
- package/src/button/Button.tsx +5 -1
- package/src/card/Card.tsx +35 -4
- package/src/card/ClickableCard.tsx +9 -2
- package/src/card/styles.ts +1 -10
- package/src/chip/Chip.tsx +6 -1
- package/src/chip/styles.ts +12 -10
- package/src/delegateEvent.ts +5 -5
- package/src/dialog/Dialog.tsx +48 -61
- package/src/dialog/FixedDialog.tsx +1 -11
- package/src/dialog/styles.ts +97 -0
- package/src/divider/Divider.tsx +0 -12
- package/src/divider/styles.ts +12 -0
- package/src/draggable/useDraggable.ts +17 -10
- package/src/draggable/utils.ts +3 -3
- package/src/expansion-panel/ExpansionPanel.tsx +1 -1
- package/src/expansion-panel/useExpansionPanels.ts +18 -27
- package/src/{form → files}/FileInput.tsx +7 -15
- package/src/files/styles.ts +10 -0
- package/src/{form → files}/useFileUpload.ts +30 -34
- package/src/files/utils.ts +234 -0
- package/src/{form/fileUtils.ts → files/validation.ts} +13 -242
- package/src/focus/useFocusContainer.ts +16 -8
- package/src/form/FormMessageContainer.tsx +2 -2
- package/src/form/InputToggle.tsx +5 -1
- package/src/form/Label.tsx +18 -18
- package/src/form/Listbox.tsx +87 -0
- package/src/form/ListboxProvider.ts +37 -0
- package/src/form/MenuItemTextField.tsx +1 -2
- package/src/form/NativeSelect.tsx +14 -10
- package/src/form/Option.tsx +74 -22
- package/src/form/Select.tsx +89 -85
- package/src/form/Slider.tsx +14 -11
- package/src/form/SliderThumb.tsx +4 -4
- package/src/form/SliderValueMarks.tsx +4 -4
- package/src/form/TextArea.tsx +6 -8
- package/src/form/TextField.tsx +0 -2
- package/src/form/TextFieldContainer.tsx +9 -11
- package/src/form/formMessageContainerStyles.ts +22 -0
- package/src/form/optionStyles.ts +7 -2
- package/src/form/sliderUtils.ts +1 -1
- package/src/form/textFieldContainerStyles.ts +9 -14
- package/src/form/types.ts +3 -11
- package/src/form/useCheckboxGroup.ts +28 -36
- package/src/form/useCombobox.ts +86 -38
- package/src/form/useEditableCombobox.ts +43 -8
- package/src/form/useRadioGroup.ts +6 -6
- package/src/form/useSelectCombobox.ts +4 -4
- package/src/form/useTextField.ts +1 -1
- package/src/hoverMode/useHoverMode.ts +3 -3
- package/src/hoverMode/useHoverModeProvider.ts +4 -4
- package/src/icon/iconConfig.tsx +12 -0
- package/src/interaction/UserInteractionModeProvider.tsx +12 -8
- package/src/interaction/types.ts +21 -2
- package/src/interaction/useElementInteraction.tsx +9 -2
- package/src/interaction/utils.ts +7 -7
- package/src/layout/useExpandableLayout.ts +3 -3
- package/src/layout/useLayoutAppBarHeight.ts +3 -4
- package/src/layout/useTemporaryLayout.ts +2 -2
- package/src/list/ListItem.tsx +5 -1
- package/src/list/ListItemLink.tsx +5 -1
- package/src/media-queries/useMediaQuery.ts +2 -1
- package/src/menu/Menu.tsx +11 -3
- package/src/menu/MenuItemButton.tsx +7 -1
- package/src/menu/useContextMenu.ts +3 -3
- package/src/movement/types.ts +5 -5
- package/src/navigation/CollapsibleNavGroup.tsx +16 -8
- package/src/navigation/DefaultNavigationRenderer.tsx +8 -6
- package/src/navigation/NavItemButton.tsx +2 -1
- package/src/navigation/NavItemLink.tsx +11 -3
- package/src/navigation/NavSubheader.tsx +1 -1
- package/src/navigation/Navigation.tsx +1 -1
- package/src/navigation/types.ts +60 -10
- package/src/navigation/useActiveHeadingId.ts +1 -1
- package/src/navigation/useNavigationExpansion.ts +170 -0
- package/src/navigation/utils.ts +47 -0
- package/src/objectFit.ts +88 -0
- package/src/positioning/useFixedPositioning.ts +34 -11
- package/src/responsive-item/ResponsiveItem.tsx +96 -0
- package/src/responsive-item/ResponsiveItemOverlay.tsx +6 -46
- package/src/responsive-item/responsiveItemOverlayStyles.ts +46 -0
- package/src/responsive-item/responsiveItemStyles.ts +81 -0
- package/src/scroll/useScrollLock.ts +6 -0
- package/src/searching/utils.ts +3 -3
- package/src/segmented-button/SegmentedButton.tsx +5 -1
- package/src/snackbar/ToastManager.tsx +16 -5
- package/src/snackbar/useCurrentToastActions.ts +5 -5
- package/src/table/tableCellStyles.ts +10 -6
- package/src/tabs/Tab.tsx +4 -1
- package/src/tabs/TabList.tsx +2 -2
- package/src/tabs/TabListScrollButton.tsx +4 -4
- package/src/tabs/getTabListScrollToOptions.ts +37 -0
- package/src/tabs/tabStyles.ts +4 -0
- package/src/tabs/useTabList.ts +2 -9
- package/src/tabs/useTabs.ts +6 -6
- package/src/tabs/utils.ts +0 -38
- package/src/test-utils/matchMedia.ts +5 -5
- package/src/test-utils/polyfills/TextDecoder.ts +0 -1
- package/src/test-utils/timers.ts +10 -7
- package/src/theme/LocalStorageColorSchemeProvider.tsx +4 -4
- package/src/theme/ThemeProvider.tsx +3 -3
- package/src/theme/isColorScheme.ts +22 -0
- package/src/theme/types.ts +67 -1
- package/src/theme/useCSSVariables.ts +7 -30
- package/src/theme/useColorScheme.ts +1 -40
- package/src/theme/useColorSchemeMetaTag.ts +1 -1
- package/src/theme/useColorSchemeProvider.ts +2 -2
- package/src/tooltip/useTooltip.ts +17 -9
- package/src/transition/types.ts +1 -1
- package/src/transition/useCarousel.ts +3 -3
- package/src/transition/useTransition.ts +1 -0
- package/src/tree/TreeItem.tsx +7 -1
- package/src/tree/TreeItemExpander.tsx +1 -1
- package/src/tree/useTreeExpansion.ts +7 -25
- package/src/tree/useTreeSelection.ts +8 -32
- package/src/tree/utils.ts +6 -2
- package/src/types.ts +20 -4
- package/src/typography/WritingDirectionProvider.tsx +1 -1
- package/src/useDebouncedFunction.ts +4 -9
- package/src/useDropzone.ts +4 -4
- package/src/useIntersectionObserver.ts +5 -5
- package/src/useLocalStorage.ts +6 -6
- package/src/useMutationObserver.ts +1 -1
- package/src/useOrientation.ts +3 -1
- package/src/usePageInactive.ts +2 -2
- package/src/useReadonlySet.ts +122 -0
- package/src/useResizeListener.ts +1 -1
- package/src/useThrottledFunction.ts +6 -9
- package/src/useToggle.ts +3 -3
- package/src/utils/RenderRecursively.tsx +1 -1
- package/src/utils/alphaNumericSort.ts +1 -1
- package/src/utils/debounce.ts +22 -0
- package/src/utils/throttle.ts +38 -0
- package/src/utils/wait.ts +5 -1
- package/src/window-splitter/WindowSplitter.tsx +38 -43
- package/src/window-splitter/styles.ts +42 -0
- package/dist/autocomplete/FilterAutocompleteOptions.d.ts +0 -8
- package/dist/autocomplete/FilterAutocompleteOptions.js +0 -57
- package/dist/autocomplete/FilterAutocompleteOptions.js.map +0 -1
- package/dist/dialog/DialogContainer.d.ts +0 -14
- package/dist/dialog/DialogContainer.js +0 -20
- package/dist/dialog/DialogContainer.js.map +0 -1
- package/dist/form/FileInput.js.map +0 -1
- package/dist/form/fileUtils.js.map +0 -1
- package/dist/form/useFileUpload.js.map +0 -1
- package/dist/form/useListboxProvider.d.ts +0 -31
- package/dist/form/useListboxProvider.js.map +0 -1
- package/dist/navigation/getHrefFromParents.d.ts +0 -5
- package/dist/navigation/getHrefFromParents.js +0 -13
- package/dist/navigation/getHrefFromParents.js.map +0 -1
- package/dist/responsive-item/ResponsiveItemContainer.d.ts +0 -115
- package/dist/responsive-item/ResponsiveItemContainer.js +0 -80
- package/dist/responsive-item/ResponsiveItemContainer.js.map +0 -1
- package/dist/responsive-item/styles.d.ts +0 -34
- package/dist/responsive-item/styles.js +0 -17
- package/dist/responsive-item/styles.js.map +0 -1
- package/dist/theme/usePrefersColorScheme.js.map +0 -1
- package/src/autocomplete/FilterAutocompleteOptions.tsx +0 -86
- package/src/dialog/DialogContainer.tsx +0 -28
- package/src/form/useListboxProvider.ts +0 -45
- package/src/navigation/getHrefFromParents.ts +0 -15
- package/src/responsive-item/ResponsiveItemContainer.tsx +0 -174
- package/src/responsive-item/styles.ts +0 -58
- /package/dist/theme/{usePrefersColorScheme.d.ts → usePrefersDarkScheme.d.ts} +0 -0
- /package/src/theme/{usePrefersColorScheme.ts → usePrefersDarkScheme.ts} +0 -0
|
@@ -78,7 +78,7 @@ export interface BaseIntersectionObserverHookOptions {
|
|
|
78
78
|
* // pretend some expensive computation
|
|
79
79
|
* return [0, 0.25, 0.5, 0.75, 1];
|
|
80
80
|
* }, []),
|
|
81
|
-
*
|
|
81
|
+
* onUpdate: useCallback(() => {
|
|
82
82
|
* // do something
|
|
83
83
|
* }, []),
|
|
84
84
|
* });
|
|
@@ -86,7 +86,7 @@ export interface BaseIntersectionObserverHookOptions {
|
|
|
86
86
|
*
|
|
87
87
|
* If this option is provided, {@link threshold}'s value will be ignored.
|
|
88
88
|
*/
|
|
89
|
-
getThreshold
|
|
89
|
+
getThreshold?: () => IntersectionObserverThreshold;
|
|
90
90
|
/**
|
|
91
91
|
* **Must be wrapped in `useCallback` to prevent re-creating the
|
|
92
92
|
* IntersectionObserver each render.**
|
|
@@ -109,7 +109,7 @@ export interface BaseIntersectionObserverHookOptions {
|
|
|
109
109
|
*
|
|
110
110
|
* Note: If this option is provided, {@link rootMargin} will be ignored.
|
|
111
111
|
*/
|
|
112
|
-
getRootMargin
|
|
112
|
+
getRootMargin?: () => IntersectionObserverRootMargin;
|
|
113
113
|
}
|
|
114
114
|
/**
|
|
115
115
|
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#intersection_observer_options}
|
|
@@ -141,7 +141,7 @@ export interface IntersectionObserverHookOptions<E extends HTMLElement> extends
|
|
|
141
141
|
* }
|
|
142
142
|
* ```
|
|
143
143
|
*/
|
|
144
|
-
onUpdate(entries: readonly IntersectionObserverEntry[])
|
|
144
|
+
onUpdate: (entries: readonly IntersectionObserverEntry[]) => void;
|
|
145
145
|
/**
|
|
146
146
|
* **Must be wrapped in `useCallback` to prevent re-creating the
|
|
147
147
|
* IntersectionObserver each render.**
|
|
@@ -169,7 +169,7 @@ export interface IntersectionObserverHookOptions<E extends HTMLElement> extends
|
|
|
169
169
|
* }
|
|
170
170
|
* ```
|
|
171
171
|
*/
|
|
172
|
-
getTargets
|
|
172
|
+
getTargets?: () => readonly Element[];
|
|
173
173
|
}
|
|
174
174
|
/**
|
|
175
175
|
* @example Simple Example
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useIntersectionObserver.ts"],"sourcesContent":["\"use client\";\nimport type { Ref, RefCallback, RefObject } from \"react\";\nimport { useEffect } from \"react\";\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<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\";\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;AAEA,SAASA,SAAS,QAAQ,QAAQ;AAClC,SAASC,aAAa,QAAQ,qBAAqB;AA2LnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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\";\nimport type { Ref, RefCallback, RefObject } from \"react\";\nimport { useEffect } from \"react\";\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<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\";\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;AAEA,SAASA,SAAS,QAAQ,QAAQ;AAClC,SAASC,aAAa,QAAQ,qBAAqB;AA2LnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
|
|
@@ -56,7 +56,7 @@ export interface LocalStorageHookOptions<T> {
|
|
|
56
56
|
/**
|
|
57
57
|
* @since 6.0.0
|
|
58
58
|
*/
|
|
59
|
-
export declare const defaultLocalStorageSerializer:
|
|
59
|
+
export declare const defaultLocalStorageSerializer: (value: unknown) => string;
|
|
60
60
|
/** @since 6.0.0 */
|
|
61
61
|
export interface GetItemFromStorageOptions<T> {
|
|
62
62
|
/**
|
|
@@ -177,7 +177,7 @@ export interface LocalStorageHookReturnValue<T> {
|
|
|
177
177
|
/**
|
|
178
178
|
* Remove the item from local storage.
|
|
179
179
|
*/
|
|
180
|
-
remove()
|
|
180
|
+
remove: () => void;
|
|
181
181
|
/**
|
|
182
182
|
* Manually persist the current {@link value} into local storage. This is only
|
|
183
183
|
* useful if the {@link LocalStorageHookOptions.manual} option is `true`.
|
|
@@ -212,7 +212,7 @@ export interface LocalStorageHookReturnValue<T> {
|
|
|
212
212
|
* }
|
|
213
213
|
* ```
|
|
214
214
|
*/
|
|
215
|
-
persist()
|
|
215
|
+
persist: () => void;
|
|
216
216
|
}
|
|
217
217
|
/**
|
|
218
218
|
* @example Simple Example
|
package/dist/useLocalStorage.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useLocalStorage.ts"],"sourcesContent":["\"use client\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useSsr } from \"./SsrProvider.js\";\nimport type { UseStateInitializer, UseStateSetter } from \"./types.js\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect.js\";\nimport { identity } from \"./utils/identity.js\";\n\n/** @since 6.0.0 */\nexport type LocalStorageSerializer<T> = (value: T) => string;\n/** @since 6.0.0 */\nexport type LocalStorageDeserializer<T> = (item: string) => T;\n\n/** @since 6.0.0 */\nexport interface LocalStorageHookOptions<T> {\n /**\n * The local storage key name to use.\n *\n * This can be set to an empty string for internal usage of conditionally\n * saving items to local storage.\n */\n key: string;\n\n /**\n * The default value to use if an item does not exist in local storage.\n */\n defaultValue: UseStateInitializer<T>;\n\n /**\n * Set this to `true` if the `value` should not persist to local storage\n * immediately whenever it changes. You will manually need to call\n * {@link LocalStorageHookReturnValue.persist} instead.\n *\n * @see {@link LocalStorageHookReturnValue.persist} for an example.\n * @defaultValue `false`\n */\n manual?: boolean;\n\n /**\n * Set this to `true` to update:\n *\n * - the default {@link serializer} to be:\n * ```\n * typeof value === \"string\" ? value : `${value}`\n * ```\n * - the default {@link deserializer} to not call `JSON.parse` if the\n * {@link defaultValue} is a string.\n *\n * @defaultValue `typeof defaultValue === 'string'`\n */\n raw?: boolean;\n\n /**\n * An optional function to serialize the `value` before storing it in local\n * storage.\n *\n * @defaultValue `JSON.stringify`\n */\n serializer?: LocalStorageSerializer<T>;\n\n /**\n * An optional function to deserialize the `value` if the item existed in\n * local storage.\n *\n * @defaultValue `JSON.parse`\n */\n deserializer?: LocalStorageDeserializer<T>;\n}\n\n/**\n * @since 6.0.0\n */\nexport const defaultLocalStorageSerializer = <T>(value: T): string =>\n typeof value === \"string\" ? value : `${value}`;\n\n/** @since 6.0.0 */\nexport interface GetItemFromStorageOptions<T> {\n /**\n * The storage key to use\n */\n key: string;\n\n /**\n * A value to use when the {@link key} does not exist in storage or there is\n * an error deserializing the value.\n */\n fallback: T;\n\n /** @see {@link LocalStorageHookOptions.deserializer} */\n deserializer?: LocalStorageDeserializer<T>;\n\n /** @defaultValue `localStorage` */\n storage?: Storage;\n}\n\n/**\n * You'll most likely want to use {@link useLocalStorage} instead, but this is a\n * low-level util to \"safely\" get an item from local storage.\n *\n * @example\n * ```ts\n * import { getItemFromStorage } from \"@react-md/core\";\n *\n * const values = [\"a\", \"b\", \"c\", \"d\"] as const;\n *\n * const item1 = getItemFromStorage({\n * key: \"testKey\",\n * fallback: values[0],\n * deserializer(item) {\n * if (!values.includes(item)) {\n * return values[0]\n * }\n *\n * return item;\n * },\n * });\n *\n * const item2 = getItemFromStorage({\n * key: \"anotherKey\",\n * fallback: -1,\n * });\n *\n * const item3 = getItemFromStorage({\n * key: \"anotherKey\",\n * fallback: -1,\n * storage: sessionStorage,\n * });\n * ```\n *\n * @since 6.0.0\n */\nexport const getItemFromStorage = <T>(\n options: GetItemFromStorageOptions<T>\n): T => {\n const {\n key,\n fallback,\n storage = localStorage,\n deserializer = JSON.parse,\n } = options;\n if (!key) {\n return fallback;\n }\n\n try {\n const value = storage.getItem(key);\n return !value ? fallback : deserializer(value);\n } catch (e) {\n return fallback;\n }\n};\n\n/** @since 6.0.0 */\nexport interface SetItemInStorageOptions<T> {\n key: string;\n value: T;\n /** @defaultValue `localStorage` */\n storage?: Storage;\n\n /** @see {@link LocalStorageHookOptions.serializer} */\n serializer?: LocalStorageSerializer<T>;\n}\n\n/**\n * You'll most likely want to use {@link useLocalStorage} instead, but this is a\n * low-level util to \"safely\" get an item from local storage.\n *\n * @example\n * ```ts\n * import { identity, getItemFromStorage } from \"@react-md/core\";\n *\n * const values = [\"a\", \"b\", \"c\", \"d\"] as const;\n *\n * setItemInStorage({\n * key: \"testKey\",\n * value: values[0],\n * // store string value as-is\n * serializer: identity,\n * });\n *\n * setItemInStorage({\n * key: \"anotherKey\",\n * value: 100,\n * });\n *\n * setItemInStorage({\n * key: \"anotherKey\",\n * value: 100,\n * storage: sessionStorage,\n * });\n * ```\n *\n * @since 6.0.0\n */\nexport const setItemInStorage = <T>(\n options: SetItemInStorageOptions<T>\n): void => {\n const {\n key,\n value,\n storage = localStorage,\n serializer = JSON.stringify,\n } = options;\n if (!key) {\n return;\n }\n\n try {\n storage.setItem(key, serializer(value));\n } catch {\n //\n }\n};\n\n/**\n * @since 6.0.0\n * @internal\n */\ninterface RemoveItemFromStorageOptions {\n key: string;\n\n /** @defaultValue `localStorage` */\n storage?: Storage;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport const removeItemFromStorage = (\n options: RemoveItemFromStorageOptions\n): void => {\n const { key, storage = localStorage } = options;\n if (!key) {\n return;\n }\n\n try {\n storage.removeItem(key);\n } catch {\n // do nothing\n }\n};\n\n/** @since 6.0.0 */\nexport interface LocalStorageHookReturnValue<T> {\n value: T;\n\n /**\n * Updates the {@link value} in state. When the\n * {@link LocalStorageHookOptions.manual} option is `false`, the value will\n * also be updated in local storage immediately.\n */\n setValue: UseStateSetter<T>;\n\n /**\n * Remove the item from local storage.\n */\n remove(): void;\n\n /**\n * Manually persist the current {@link value} into local storage. This is only\n * useful if the {@link LocalStorageHookOptions.manual} option is `true`.\n *\n * @example Manual Persisting\n * ```tsx\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { value, setValue, persist } = useLocalStorage({\n * key: \"someKey\",\n * manual: true,\n * defaultValue: \"\",\n * });\n *\n * return (\n * <>\n * <Button onClick={closeDialog}>\n * Cancel\n * </Button>\n * <Button\n * onClick={async () => {\n * await saveToDatabase(value);\n * persist();\n * closeDialog();\n * }}\n * >\n * Confirm\n * </Button>\n * </>\n * );\n * }\n * ```\n */\n persist(): void;\n}\n\n/**\n * @example Simple Example\n * ```tsx\n * import type { ReactElement } from \"react\";\n * import { TextField, useLocalStorage } from \"@react-md/core\";\n *\n * function Example(): ReactElement {\n * const { value, setValue } = useLocalStorage({\n * key: \"savedSearch\",\n * defaultValue: \"\",\n * });\n *\n * return (\n * <TextField\n * label=\"Search\"\n * placeholder=\"Search...\"\n * type=\"search\"\n * value={value}\n * onChange={(event) => {\n * setValue(event.currentTarget.value)\n * }}\n * />\n * );\n * }\n * ```\n *\n * @example Type-safe Objects\n * ```tsx\n * import type { ReactElement } from \"react\";\n * import { useLocalStorage } from \"@react-md/core\";\n *\n * interface ExpectedSchema {\n * label: string;\n * value: string;\n * // others\n * }\n *\n * function Example(): ReactElement {\n * const { value, setValue } = useLocalStorage<ExpectedSchema | null>({\n * key: \"someKey\",\n * defaultValue: null,\n *\n * // this is optional: you can create a custom deserializer to validate\n * // the stored value to prevent people manually updating local storage in\n * // the dev tools\n * deserializer(item) {\n * const parsed = JSON.parse(item):\n * const { label, value } = parsed;\n * if (typeof label !== 'string' || typeof value !== 'string') {\n * return null;\n * }\n *\n * return { label, value };\n * }\n * });\n *\n * // do something\n * // value will be `ExpectedSchema | null`\n * }\n * ```\n *\n * @example Manual Persistence\n * ```tsx\n * import type { ReactElement } from \"react\";\n * import { Button, Checkbox, Form, useLocalStorage } from \"@react-md/core\";\n *\n * function Example(): ReactElement {\n * const { value, setValue, remove, persist } = useLocalStorage({\n * key: \"someKey\",\n * manual: true,\n * defaultValue: false,\n * });\n *\n * return (\n * <Form\n * onSubmit={() => {\n * // current value will be saved into local storage\n * persist();\n * }}\n * onReset={() => {\n * // \"someKey\" will be removed from local storage\n * remove();\n * }}\n * >\n * <Checkbox\n * label=\"Allow cookies\"\n * checked={value}\n * onChange={(event) =>\n * setValue(event.currentTarget.checked);\n * }\n * />\n * <Button type=\"reset\">Decline</Button>\n * <Button type=\"submit\">Save</Button>\n * </Form>\n * );\n * }\n * ```\n *\n * Note: Using the same local storage key in multiple parts in your app will not\n * update all instances with that value. The value will only be updated if it\n * was updated in a separate tab with the `\"storage\"` event. You must setup your\n * own context to share values or another state manager solution.\n *\n * @example Shared Value\n * ```tsx\n * const context = createContext(null);\n * const { Provider } = context;\n *\n * export function useSomeValue(): string {\n * const value = useContext(context);\n * if (!value) {\n * throw new Error()\n * }\n *\n * return value;\n * }\n *\n * function Example({ children }: { children: ReactNode }) {\n * const { value, setValue, remove, persist } = useLocalStorage({\n * key: \"someKey\",\n * defaultValue: \"\",\n *\n * // optional\n * manual: true,\n * });\n *\n * return (\n * <Provider\n * value={useMemo(() => ({\n * value,\n * setValue,\n *\n * // remove and persist are optional\n * remove,\n * persist,\n * }), [value, setValue, remove, persist])}\n * >\n * {children}\n * </Provider>\n * );\n * }\n *\n * function SomeChildComponent() {\n * const { value, setValue } = useSomeValue();\n * // do stuff\n * }\n * ```\n *\n * @since 6.0.0\n */\nexport function useLocalStorage<T>(\n options: LocalStorageHookOptions<T>\n): LocalStorageHookReturnValue<T> {\n const { key, defaultValue, manual = false } = options;\n\n const [initialValue] = useState(defaultValue);\n // this allows for strings to automatically be stored as-is instead of adding\n // additional quotes around then with JSON.stringify\n const raw = options.raw ?? typeof initialValue === \"string\";\n const serializer =\n options.serializer ??\n (raw ? defaultLocalStorageSerializer : JSON.stringify);\n const deserializer =\n options.deserializer ??\n (raw && typeof initialValue === \"string\" ? identity : JSON.parse);\n\n const ssr = useSsr();\n const [value, setStoredValue] = useState<T>(() => {\n if (ssr) {\n return initialValue;\n }\n\n const value = getItemFromStorage({\n key,\n fallback: initialValue,\n deserializer,\n });\n if (!manual) {\n setItemInStorage({\n key,\n value,\n serializer,\n });\n }\n\n return value;\n });\n const config = useRef({\n key,\n value,\n manual,\n serializer,\n deserializer,\n defaultValue: initialValue,\n } as const);\n useIsomorphicLayoutEffect(() => {\n config.current = {\n key,\n value,\n manual,\n serializer,\n deserializer,\n defaultValue: initialValue,\n };\n });\n\n const setValue = useCallback<UseStateSetter<T>>((valueOrDispatcher) => {\n const { key, manual, serializer } = config.current;\n setStoredValue((prevValue) => {\n const nextValue =\n valueOrDispatcher instanceof Function\n ? valueOrDispatcher(prevValue)\n : valueOrDispatcher;\n\n if (!manual) {\n setItemInStorage({\n key,\n value: nextValue,\n serializer,\n });\n }\n\n return nextValue;\n });\n }, []);\n\n const remove = useCallback(() => {\n removeItemFromStorage({\n key: config.current.key,\n });\n }, []);\n\n const persist = useCallback(() => {\n const { key, value, serializer } = config.current;\n setItemInStorage({\n key,\n value,\n serializer,\n });\n }, []);\n\n useEffect(() => {\n const { defaultValue, deserializer, manual } = config.current;\n if (manual || !ssr) {\n return;\n }\n\n setValue(\n getItemFromStorage({\n key,\n fallback: defaultValue,\n deserializer,\n })\n );\n }, [key, ssr, setValue]);\n\n // update the value if another tab changed the local storage value\n useEffect(() => {\n if (!key) {\n return;\n }\n\n const callback = (event: StorageEvent): void => {\n const { defaultValue, deserializer } = config.current;\n if (event.key === key) {\n setStoredValue(\n getItemFromStorage({\n key,\n fallback: defaultValue,\n deserializer,\n })\n );\n }\n };\n\n window.addEventListener(\"storage\", callback);\n return () => {\n window.removeEventListener(\"storage\", callback);\n };\n }, [key]);\n\n return {\n value,\n setValue,\n remove,\n persist,\n };\n}\n"],"names":["useCallback","useEffect","useRef","useState","useSsr","useIsomorphicLayoutEffect","identity","defaultLocalStorageSerializer","value","getItemFromStorage","options","key","fallback","storage","localStorage","deserializer","JSON","parse","getItem","e","setItemInStorage","serializer","stringify","setItem","removeItemFromStorage","removeItem","useLocalStorage","defaultValue","manual","initialValue","raw","ssr","setStoredValue","config","current","setValue","valueOrDispatcher","prevValue","nextValue","Function","remove","persist","callback","event","window","addEventListener","removeEventListener"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/useLocalStorage.ts"],"sourcesContent":["\"use client\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useSsr } from \"./SsrProvider.js\";\nimport type { UseStateInitializer, UseStateSetter } from \"./types.js\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect.js\";\nimport { identity } from \"./utils/identity.js\";\n\n/** @since 6.0.0 */\nexport type LocalStorageSerializer<T> = (value: T) => string;\n/** @since 6.0.0 */\nexport type LocalStorageDeserializer<T> = (item: string) => T;\n\n/** @since 6.0.0 */\nexport interface LocalStorageHookOptions<T> {\n /**\n * The local storage key name to use.\n *\n * This can be set to an empty string for internal usage of conditionally\n * saving items to local storage.\n */\n key: string;\n\n /**\n * The default value to use if an item does not exist in local storage.\n */\n defaultValue: UseStateInitializer<T>;\n\n /**\n * Set this to `true` if the `value` should not persist to local storage\n * immediately whenever it changes. You will manually need to call\n * {@link LocalStorageHookReturnValue.persist} instead.\n *\n * @see {@link LocalStorageHookReturnValue.persist} for an example.\n * @defaultValue `false`\n */\n manual?: boolean;\n\n /**\n * Set this to `true` to update:\n *\n * - the default {@link serializer} to be:\n * ```\n * typeof value === \"string\" ? value : `${value}`\n * ```\n * - the default {@link deserializer} to not call `JSON.parse` if the\n * {@link defaultValue} is a string.\n *\n * @defaultValue `typeof defaultValue === 'string'`\n */\n raw?: boolean;\n\n /**\n * An optional function to serialize the `value` before storing it in local\n * storage.\n *\n * @defaultValue `JSON.stringify`\n */\n serializer?: LocalStorageSerializer<T>;\n\n /**\n * An optional function to deserialize the `value` if the item existed in\n * local storage.\n *\n * @defaultValue `JSON.parse`\n */\n deserializer?: LocalStorageDeserializer<T>;\n}\n\n/**\n * @since 6.0.0\n */\nexport const defaultLocalStorageSerializer = (value: unknown): string =>\n typeof value === \"string\" ? value : `${value}`;\n\n/** @since 6.0.0 */\nexport interface GetItemFromStorageOptions<T> {\n /**\n * The storage key to use\n */\n key: string;\n\n /**\n * A value to use when the {@link key} does not exist in storage or there is\n * an error deserializing the value.\n */\n fallback: T;\n\n /** @see {@link LocalStorageHookOptions.deserializer} */\n deserializer?: LocalStorageDeserializer<T>;\n\n /** @defaultValue `localStorage` */\n storage?: Storage;\n}\n\n/**\n * You'll most likely want to use {@link useLocalStorage} instead, but this is a\n * low-level util to \"safely\" get an item from local storage.\n *\n * @example\n * ```ts\n * import { getItemFromStorage } from \"@react-md/core\";\n *\n * const values = [\"a\", \"b\", \"c\", \"d\"] as const;\n *\n * const item1 = getItemFromStorage({\n * key: \"testKey\",\n * fallback: values[0],\n * deserializer(item) {\n * if (!values.includes(item)) {\n * return values[0]\n * }\n *\n * return item;\n * },\n * });\n *\n * const item2 = getItemFromStorage({\n * key: \"anotherKey\",\n * fallback: -1,\n * });\n *\n * const item3 = getItemFromStorage({\n * key: \"anotherKey\",\n * fallback: -1,\n * storage: sessionStorage,\n * });\n * ```\n *\n * @since 6.0.0\n */\nexport const getItemFromStorage = <T>(\n options: GetItemFromStorageOptions<T>\n): T => {\n const {\n key,\n fallback,\n storage = localStorage,\n deserializer = JSON.parse as LocalStorageDeserializer<T>,\n } = options;\n if (!key) {\n return fallback;\n }\n\n try {\n const value = storage.getItem(key);\n return !value ? fallback : deserializer(value);\n } catch {\n return fallback;\n }\n};\n\n/** @since 6.0.0 */\nexport interface SetItemInStorageOptions<T> {\n key: string;\n value: T;\n /** @defaultValue `localStorage` */\n storage?: Storage;\n\n /** @see {@link LocalStorageHookOptions.serializer} */\n serializer?: LocalStorageSerializer<T>;\n}\n\n/**\n * You'll most likely want to use {@link useLocalStorage} instead, but this is a\n * low-level util to \"safely\" get an item from local storage.\n *\n * @example\n * ```ts\n * import { identity, getItemFromStorage } from \"@react-md/core\";\n *\n * const values = [\"a\", \"b\", \"c\", \"d\"] as const;\n *\n * setItemInStorage({\n * key: \"testKey\",\n * value: values[0],\n * // store string value as-is\n * serializer: identity,\n * });\n *\n * setItemInStorage({\n * key: \"anotherKey\",\n * value: 100,\n * });\n *\n * setItemInStorage({\n * key: \"anotherKey\",\n * value: 100,\n * storage: sessionStorage,\n * });\n * ```\n *\n * @since 6.0.0\n */\nexport const setItemInStorage = <T>(\n options: SetItemInStorageOptions<T>\n): void => {\n const {\n key,\n value,\n storage = localStorage,\n serializer = JSON.stringify,\n } = options;\n if (!key) {\n return;\n }\n\n try {\n storage.setItem(key, serializer(value));\n } catch {\n //\n }\n};\n\n/**\n * @since 6.0.0\n * @internal\n */\ninterface RemoveItemFromStorageOptions {\n key: string;\n\n /** @defaultValue `localStorage` */\n storage?: Storage;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport const removeItemFromStorage = (\n options: RemoveItemFromStorageOptions\n): void => {\n const { key, storage = localStorage } = options;\n if (!key) {\n return;\n }\n\n try {\n storage.removeItem(key);\n } catch {\n // do nothing\n }\n};\n\n/** @since 6.0.0 */\nexport interface LocalStorageHookReturnValue<T> {\n value: T;\n\n /**\n * Updates the {@link value} in state. When the\n * {@link LocalStorageHookOptions.manual} option is `false`, the value will\n * also be updated in local storage immediately.\n */\n setValue: UseStateSetter<T>;\n\n /**\n * Remove the item from local storage.\n */\n remove: () => void;\n\n /**\n * Manually persist the current {@link value} into local storage. This is only\n * useful if the {@link LocalStorageHookOptions.manual} option is `true`.\n *\n * @example Manual Persisting\n * ```tsx\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { value, setValue, persist } = useLocalStorage({\n * key: \"someKey\",\n * manual: true,\n * defaultValue: \"\",\n * });\n *\n * return (\n * <>\n * <Button onClick={closeDialog}>\n * Cancel\n * </Button>\n * <Button\n * onClick={async () => {\n * await saveToDatabase(value);\n * persist();\n * closeDialog();\n * }}\n * >\n * Confirm\n * </Button>\n * </>\n * );\n * }\n * ```\n */\n persist: () => void;\n}\n\n/**\n * @example Simple Example\n * ```tsx\n * import type { ReactElement } from \"react\";\n * import { TextField, useLocalStorage } from \"@react-md/core\";\n *\n * function Example(): ReactElement {\n * const { value, setValue } = useLocalStorage({\n * key: \"savedSearch\",\n * defaultValue: \"\",\n * });\n *\n * return (\n * <TextField\n * label=\"Search\"\n * placeholder=\"Search...\"\n * type=\"search\"\n * value={value}\n * onChange={(event) => {\n * setValue(event.currentTarget.value)\n * }}\n * />\n * );\n * }\n * ```\n *\n * @example Type-safe Objects\n * ```tsx\n * import type { ReactElement } from \"react\";\n * import { useLocalStorage } from \"@react-md/core\";\n *\n * interface ExpectedSchema {\n * label: string;\n * value: string;\n * // others\n * }\n *\n * function Example(): ReactElement {\n * const { value, setValue } = useLocalStorage<ExpectedSchema | null>({\n * key: \"someKey\",\n * defaultValue: null,\n *\n * // this is optional: you can create a custom deserializer to validate\n * // the stored value to prevent people manually updating local storage in\n * // the dev tools\n * deserializer(item) {\n * const parsed = JSON.parse(item):\n * const { label, value } = parsed;\n * if (typeof label !== 'string' || typeof value !== 'string') {\n * return null;\n * }\n *\n * return { label, value };\n * }\n * });\n *\n * // do something\n * // value will be `ExpectedSchema | null`\n * }\n * ```\n *\n * @example Manual Persistence\n * ```tsx\n * import type { ReactElement } from \"react\";\n * import { Button, Checkbox, Form, useLocalStorage } from \"@react-md/core\";\n *\n * function Example(): ReactElement {\n * const { value, setValue, remove, persist } = useLocalStorage({\n * key: \"someKey\",\n * manual: true,\n * defaultValue: false,\n * });\n *\n * return (\n * <Form\n * onSubmit={() => {\n * // current value will be saved into local storage\n * persist();\n * }}\n * onReset={() => {\n * // \"someKey\" will be removed from local storage\n * remove();\n * }}\n * >\n * <Checkbox\n * label=\"Allow cookies\"\n * checked={value}\n * onChange={(event) =>\n * setValue(event.currentTarget.checked);\n * }\n * />\n * <Button type=\"reset\">Decline</Button>\n * <Button type=\"submit\">Save</Button>\n * </Form>\n * );\n * }\n * ```\n *\n * Note: Using the same local storage key in multiple parts in your app will not\n * update all instances with that value. The value will only be updated if it\n * was updated in a separate tab with the `\"storage\"` event. You must setup your\n * own context to share values or another state manager solution.\n *\n * @example Shared Value\n * ```tsx\n * const context = createContext(null);\n * const { Provider } = context;\n *\n * export function useSomeValue(): string {\n * const value = useContext(context);\n * if (!value) {\n * throw new Error()\n * }\n *\n * return value;\n * }\n *\n * function Example({ children }: { children: ReactNode }) {\n * const { value, setValue, remove, persist } = useLocalStorage({\n * key: \"someKey\",\n * defaultValue: \"\",\n *\n * // optional\n * manual: true,\n * });\n *\n * return (\n * <Provider\n * value={useMemo(() => ({\n * value,\n * setValue,\n *\n * // remove and persist are optional\n * remove,\n * persist,\n * }), [value, setValue, remove, persist])}\n * >\n * {children}\n * </Provider>\n * );\n * }\n *\n * function SomeChildComponent() {\n * const { value, setValue } = useSomeValue();\n * // do stuff\n * }\n * ```\n *\n * @since 6.0.0\n */\nexport function useLocalStorage<T>(\n options: LocalStorageHookOptions<T>\n): LocalStorageHookReturnValue<T> {\n const { key, defaultValue, manual = false } = options;\n\n const [initialValue] = useState(defaultValue);\n // this allows for strings to automatically be stored as-is instead of adding\n // additional quotes around then with JSON.stringify\n const raw = options.raw ?? typeof initialValue === \"string\";\n const serializer =\n options.serializer ??\n (raw ? defaultLocalStorageSerializer : JSON.stringify);\n const deserializer: LocalStorageDeserializer<T> =\n options.deserializer ??\n (raw && typeof initialValue === \"string\" ? identity : JSON.parse);\n\n const ssr = useSsr();\n const [value, setStoredValue] = useState<T>(() => {\n if (ssr) {\n return initialValue;\n }\n\n const value = getItemFromStorage({\n key,\n fallback: initialValue,\n deserializer,\n });\n if (!manual) {\n setItemInStorage({\n key,\n value,\n serializer,\n });\n }\n\n return value;\n });\n const config = useRef({\n key,\n value,\n manual,\n serializer,\n deserializer,\n defaultValue: initialValue,\n } as const);\n useIsomorphicLayoutEffect(() => {\n config.current = {\n key,\n value,\n manual,\n serializer,\n deserializer,\n defaultValue: initialValue,\n };\n });\n\n const setValue = useCallback<UseStateSetter<T>>((valueOrDispatcher) => {\n const { key, manual, serializer } = config.current;\n setStoredValue((prevValue) => {\n const nextValue =\n valueOrDispatcher instanceof Function\n ? valueOrDispatcher(prevValue)\n : valueOrDispatcher;\n\n if (!manual) {\n setItemInStorage({\n key,\n value: nextValue,\n serializer,\n });\n }\n\n return nextValue;\n });\n }, []);\n\n const remove = useCallback(() => {\n removeItemFromStorage({\n key: config.current.key,\n });\n }, []);\n\n const persist = useCallback(() => {\n const { key, value, serializer } = config.current;\n setItemInStorage({\n key,\n value,\n serializer,\n });\n }, []);\n\n useEffect(() => {\n const { defaultValue, deserializer, manual } = config.current;\n if (manual || !ssr) {\n return;\n }\n\n setValue(\n getItemFromStorage({\n key,\n fallback: defaultValue,\n deserializer,\n })\n );\n }, [key, ssr, setValue]);\n\n // update the value if another tab changed the local storage value\n useEffect(() => {\n if (!key) {\n return;\n }\n\n const callback = (event: StorageEvent): void => {\n const { defaultValue, deserializer } = config.current;\n if (event.key === key) {\n setStoredValue(\n getItemFromStorage({\n key,\n fallback: defaultValue,\n deserializer,\n })\n );\n }\n };\n\n window.addEventListener(\"storage\", callback);\n return () => {\n window.removeEventListener(\"storage\", callback);\n };\n }, [key]);\n\n return {\n value,\n setValue,\n remove,\n persist,\n };\n}\n"],"names":["useCallback","useEffect","useRef","useState","useSsr","useIsomorphicLayoutEffect","identity","defaultLocalStorageSerializer","value","getItemFromStorage","options","key","fallback","storage","localStorage","deserializer","JSON","parse","getItem","setItemInStorage","serializer","stringify","setItem","removeItemFromStorage","removeItem","useLocalStorage","defaultValue","manual","initialValue","raw","ssr","setStoredValue","config","current","setValue","valueOrDispatcher","prevValue","nextValue","Function","remove","persist","callback","event","window","addEventListener","removeEventListener"],"mappings":"AAAA;AACA,SAASA,WAAW,EAAEC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAQ;AACjE,SAASC,MAAM,QAAQ,mBAAmB;AAE1C,SAASC,yBAAyB,QAAQ,iCAAiC;AAC3E,SAASC,QAAQ,QAAQ,sBAAsB;AA+D/C;;CAEC,GACD,OAAO,MAAMC,gCAAgC,CAACC,QAC5C,OAAOA,UAAU,WAAWA,QAAQ,GAAGA,OAAO,CAAC;AAsBjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCC,GACD,OAAO,MAAMC,qBAAqB,CAChCC;IAEA,MAAM,EACJC,GAAG,EACHC,QAAQ,EACRC,UAAUC,YAAY,EACtBC,eAAeC,KAAKC,KAAK,AAA+B,EACzD,GAAGP;IACJ,IAAI,CAACC,KAAK;QACR,OAAOC;IACT;IAEA,IAAI;QACF,MAAMJ,QAAQK,QAAQK,OAAO,CAACP;QAC9B,OAAO,CAACH,QAAQI,WAAWG,aAAaP;IAC1C,EAAE,OAAM;QACN,OAAOI;IACT;AACF,EAAE;AAaF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BC,GACD,OAAO,MAAMO,mBAAmB,CAC9BT;IAEA,MAAM,EACJC,GAAG,EACHH,KAAK,EACLK,UAAUC,YAAY,EACtBM,aAAaJ,KAAKK,SAAS,EAC5B,GAAGX;IACJ,IAAI,CAACC,KAAK;QACR;IACF;IAEA,IAAI;QACFE,QAAQS,OAAO,CAACX,KAAKS,WAAWZ;IAClC,EAAE,OAAM;IACN,EAAE;IACJ;AACF,EAAE;AAaF;;;CAGC,GACD,OAAO,MAAMe,wBAAwB,CACnCb;IAEA,MAAM,EAAEC,GAAG,EAAEE,UAAUC,YAAY,EAAE,GAAGJ;IACxC,IAAI,CAACC,KAAK;QACR;IACF;IAEA,IAAI;QACFE,QAAQW,UAAU,CAACb;IACrB,EAAE,OAAM;IACN,aAAa;IACf;AACF,EAAE;AAuDF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqJC,GACD,OAAO,SAASc,gBACdf,OAAmC;IAEnC,MAAM,EAAEC,GAAG,EAAEe,YAAY,EAAEC,SAAS,KAAK,EAAE,GAAGjB;IAE9C,MAAM,CAACkB,aAAa,GAAGzB,SAASuB;IAChC,6EAA6E;IAC7E,oDAAoD;IACpD,MAAMG,MAAMnB,QAAQmB,GAAG,IAAI,OAAOD,iBAAiB;IACnD,MAAMR,aACJV,QAAQU,UAAU,IACjBS,CAAAA,MAAMtB,gCAAgCS,KAAKK,SAAS,AAAD;IACtD,MAAMN,eACJL,QAAQK,YAAY,IACnBc,CAAAA,OAAO,OAAOD,iBAAiB,WAAWtB,WAAWU,KAAKC,KAAK,AAAD;IAEjE,MAAMa,MAAM1B;IACZ,MAAM,CAACI,OAAOuB,eAAe,GAAG5B,SAAY;QAC1C,IAAI2B,KAAK;YACP,OAAOF;QACT;QAEA,MAAMpB,QAAQC,mBAAmB;YAC/BE;YACAC,UAAUgB;YACVb;QACF;QACA,IAAI,CAACY,QAAQ;YACXR,iBAAiB;gBACfR;gBACAH;gBACAY;YACF;QACF;QAEA,OAAOZ;IACT;IACA,MAAMwB,SAAS9B,OAAO;QACpBS;QACAH;QACAmB;QACAP;QACAL;QACAW,cAAcE;IAChB;IACAvB,0BAA0B;QACxB2B,OAAOC,OAAO,GAAG;YACftB;YACAH;YACAmB;YACAP;YACAL;YACAW,cAAcE;QAChB;IACF;IAEA,MAAMM,WAAWlC,YAA+B,CAACmC;QAC/C,MAAM,EAAExB,GAAG,EAAEgB,MAAM,EAAEP,UAAU,EAAE,GAAGY,OAAOC,OAAO;QAClDF,eAAe,CAACK;YACd,MAAMC,YACJF,6BAA6BG,WACzBH,kBAAkBC,aAClBD;YAEN,IAAI,CAACR,QAAQ;gBACXR,iBAAiB;oBACfR;oBACAH,OAAO6B;oBACPjB;gBACF;YACF;YAEA,OAAOiB;QACT;IACF,GAAG,EAAE;IAEL,MAAME,SAASvC,YAAY;QACzBuB,sBAAsB;YACpBZ,KAAKqB,OAAOC,OAAO,CAACtB,GAAG;QACzB;IACF,GAAG,EAAE;IAEL,MAAM6B,UAAUxC,YAAY;QAC1B,MAAM,EAAEW,GAAG,EAAEH,KAAK,EAAEY,UAAU,EAAE,GAAGY,OAAOC,OAAO;QACjDd,iBAAiB;YACfR;YACAH;YACAY;QACF;IACF,GAAG,EAAE;IAELnB,UAAU;QACR,MAAM,EAAEyB,YAAY,EAAEX,YAAY,EAAEY,MAAM,EAAE,GAAGK,OAAOC,OAAO;QAC7D,IAAIN,UAAU,CAACG,KAAK;YAClB;QACF;QAEAI,SACEzB,mBAAmB;YACjBE;YACAC,UAAUc;YACVX;QACF;IAEJ,GAAG;QAACJ;QAAKmB;QAAKI;KAAS;IAEvB,kEAAkE;IAClEjC,UAAU;QACR,IAAI,CAACU,KAAK;YACR;QACF;QAEA,MAAM8B,WAAW,CAACC;YAChB,MAAM,EAAEhB,YAAY,EAAEX,YAAY,EAAE,GAAGiB,OAAOC,OAAO;YACrD,IAAIS,MAAM/B,GAAG,KAAKA,KAAK;gBACrBoB,eACEtB,mBAAmB;oBACjBE;oBACAC,UAAUc;oBACVX;gBACF;YAEJ;QACF;QAEA4B,OAAOC,gBAAgB,CAAC,WAAWH;QACnC,OAAO;YACLE,OAAOE,mBAAmB,CAAC,WAAWJ;QACxC;IACF,GAAG;QAAC9B;KAAI;IAER,OAAO;QACLH;QACA0B;QACAK;QACAC;IACF;AACF"}
|
|
@@ -9,7 +9,7 @@ export interface MutationObserverHookOptions<E extends HTMLElement> extends Muta
|
|
|
9
9
|
* @defaultValue `!childList && !attributes && !characterData`
|
|
10
10
|
*/
|
|
11
11
|
disabled?: boolean;
|
|
12
|
-
onObserved(mutation: MutationRecord)
|
|
12
|
+
onObserved: (mutation: MutationRecord) => void;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
15
|
* The mutation observer is used to track the changes made to the DOM tree.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useMutationObserver.ts"],"sourcesContent":["import { useEffect, type RefCallback, type Ref } from \"react\";\nimport { useEnsuredRef } from \"./useEnsuredRef.js\";\n\n/**\n * @since 6.0.0\n */\nexport interface MutationObserverHookOptions<E extends HTMLElement>\n extends MutationObserverInit {\n ref?: Ref<E>;\n\n /**\n * @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe#options\n * @defaultValue `!childList && !attributes && !characterData`\n */\n disabled?: boolean;\n\n onObserved(mutation: MutationRecord)
|
|
1
|
+
{"version":3,"sources":["../src/useMutationObserver.ts"],"sourcesContent":["import { useEffect, type RefCallback, type Ref } from \"react\";\nimport { useEnsuredRef } from \"./useEnsuredRef.js\";\n\n/**\n * @since 6.0.0\n */\nexport interface MutationObserverHookOptions<E extends HTMLElement>\n extends MutationObserverInit {\n ref?: Ref<E>;\n\n /**\n * @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe#options\n * @defaultValue `!childList && !attributes && !characterData`\n */\n disabled?: boolean;\n\n onObserved: (mutation: MutationRecord) => void;\n}\n\n/**\n * The mutation observer is used to track the changes made to the DOM tree.\n *\n * @example Simple Example\n * ```tsx\n * import { useMutationObserver } from \"@react-md/core\";\n * import { useCallback, type HTMLAttributes, type ReactElement } from \"react\";\n *\n * function Example(props: HTMLAttributes<HTMLDivElement>): ReactElement {\n * const { children, ...remaining } = props;\n *\n * const targetRef = useMutationObserver({\n * subtree: true,\n * attributes: true,\n * childList: true,\n * onUpdate: useCallback((mutation) => {\n * switch (mutation.type) {\n * case \"childList\":\n * console.log(\"A child node has been added or removed\");\n * break;\n * case \"attributes\":\n * console.log(`The ${mutation.attributeName} attribute was modified`);\n * break\n * }\n *\n * }, []),\n * });\n *\n * return (\n * <div {...remaining} ref={targetRef}>\n * {children}\n * </div>\n * );\n * }\n * ```\n *\n * @since 6.0.0\n */\nexport function useMutationObserver<E extends HTMLElement>(\n options: MutationObserverHookOptions<E>\n): RefCallback<E> {\n const {\n ref,\n onObserved,\n attributes,\n attributeFilter,\n attributeOldValue,\n subtree,\n childList,\n characterData,\n characterDataOldValue,\n disabled = !childList && !attributes && !characterData,\n } = options;\n\n const [targetNodeRef, refCallback] = useEnsuredRef(ref);\n useEffect(() => {\n if (disabled) {\n return;\n }\n\n const observerTarget = targetNodeRef.current;\n if (!observerTarget) {\n return;\n }\n\n const observer = new MutationObserver((records) => {\n const [entry] = records;\n if (entry) {\n onObserved(entry);\n }\n });\n\n observer.observe(observerTarget, {\n attributes,\n attributeFilter,\n attributeOldValue,\n subtree,\n childList,\n characterData,\n characterDataOldValue,\n });\n return () => {\n observer.disconnect();\n };\n }, [\n attributeFilter,\n attributeOldValue,\n attributes,\n characterData,\n characterDataOldValue,\n childList,\n disabled,\n onObserved,\n subtree,\n targetNodeRef,\n ]);\n\n return refCallback;\n}\n"],"names":["useEffect","useEnsuredRef","useMutationObserver","options","ref","onObserved","attributes","attributeFilter","attributeOldValue","subtree","childList","characterData","characterDataOldValue","disabled","targetNodeRef","refCallback","observerTarget","current","observer","MutationObserver","records","entry","observe","disconnect"],"mappings":"AAAA,SAASA,SAAS,QAAoC,QAAQ;AAC9D,SAASC,aAAa,QAAQ,qBAAqB;AAkBnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCC,GACD,OAAO,SAASC,oBACdC,OAAuC;IAEvC,MAAM,EACJC,GAAG,EACHC,UAAU,EACVC,UAAU,EACVC,eAAe,EACfC,iBAAiB,EACjBC,OAAO,EACPC,SAAS,EACTC,aAAa,EACbC,qBAAqB,EACrBC,WAAW,CAACH,aAAa,CAACJ,cAAc,CAACK,aAAa,EACvD,GAAGR;IAEJ,MAAM,CAACW,eAAeC,YAAY,GAAGd,cAAcG;IACnDJ,UAAU;QACR,IAAIa,UAAU;YACZ;QACF;QAEA,MAAMG,iBAAiBF,cAAcG,OAAO;QAC5C,IAAI,CAACD,gBAAgB;YACnB;QACF;QAEA,MAAME,WAAW,IAAIC,iBAAiB,CAACC;YACrC,MAAM,CAACC,MAAM,GAAGD;YAChB,IAAIC,OAAO;gBACThB,WAAWgB;YACb;QACF;QAEAH,SAASI,OAAO,CAACN,gBAAgB;YAC/BV;YACAC;YACAC;YACAC;YACAC;YACAC;YACAC;QACF;QACA,OAAO;YACLM,SAASK,UAAU;QACrB;IACF,GAAG;QACDhB;QACAC;QACAF;QACAK;QACAC;QACAF;QACAG;QACAR;QACAI;QACAK;KACD;IAED,OAAOC;AACT"}
|
package/dist/useOrientation.js
CHANGED
|
@@ -33,7 +33,9 @@ import { useEffect, useState } from "react";
|
|
|
33
33
|
*/ export function useOrientation() {
|
|
34
34
|
const [orientation, setOrientation] = useState(getOrientationType);
|
|
35
35
|
useEffect(()=>{
|
|
36
|
-
const handler = ()=>
|
|
36
|
+
const handler = ()=>{
|
|
37
|
+
setOrientation(getOrientationType());
|
|
38
|
+
};
|
|
37
39
|
const { orientation } = window.screen;
|
|
38
40
|
if (orientation) {
|
|
39
41
|
orientation.addEventListener("change", handler);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useOrientation.ts"],"sourcesContent":["\"use client\";\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 (typeof 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 * @internal\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 => setOrientation(getOrientationType());\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","window","screenOrientation","screen","orientation","type","availHeight","availWidth","useOrientation","setOrientation","handler","addEventListener","removeEventListener"],"mappings":"AAAA;AACA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,QAAQ;AAE5C;;;;;;;;CAQC,GACD,OAAO,MAAMC,qBAAqB;IAChC,IAAI,OAAOC,WAAW,aAAa;QACjC,OAAO;IACT;IAEA,wEAAwE;IACxE,sCAAsC;IACtC,MAAMC,oBAAoBD,OAAOE,MAAM,CAACC,WAAW,EAAEC;IACrD,IAAI,OAAOH,sBAAsB,UAAU;QACzC,OAAOA;IACT;IAEA,MAAM,EAAEI,WAAW,EAAEC,UAAU,EAAE,GAAGN,OAAOE,MAAM;IAEjD,OAAOG,cAAcC,aAAa,qBAAqB;AACzD,EAAE;AAEF;;;;;;;;;CASC,GACD,OAAO,SAASC;IACd,MAAM,CAACJ,aAAaK,eAAe,GAAGV,SAASC;IAC/CF,UAAU;QACR,MAAMY,UAAU,
|
|
1
|
+
{"version":3,"sources":["../src/useOrientation.ts"],"sourcesContent":["\"use client\";\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 (typeof 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 * @internal\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","window","screenOrientation","screen","orientation","type","availHeight","availWidth","useOrientation","setOrientation","handler","addEventListener","removeEventListener"],"mappings":"AAAA;AACA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,QAAQ;AAE5C;;;;;;;;CAQC,GACD,OAAO,MAAMC,qBAAqB;IAChC,IAAI,OAAOC,WAAW,aAAa;QACjC,OAAO;IACT;IAEA,wEAAwE;IACxE,sCAAsC;IACtC,MAAMC,oBAAoBD,OAAOE,MAAM,CAACC,WAAW,EAAEC;IACrD,IAAI,OAAOH,sBAAsB,UAAU;QACzC,OAAOA;IACT;IAEA,MAAM,EAAEI,WAAW,EAAEC,UAAU,EAAE,GAAGN,OAAOE,MAAM;IAEjD,OAAOG,cAAcC,aAAa,qBAAqB;AACzD,EAAE;AAEF;;;;;;;;;CASC,GACD,OAAO,SAASC;IACd,MAAM,CAACJ,aAAaK,eAAe,GAAGV,SAASC;IAC/CF,UAAU;QACR,MAAMY,UAAU;YACdD,eAAeT;QACjB;QAEA,MAAM,EAAEI,WAAW,EAAE,GAAGH,OAAOE,MAAM;QACrC,IAAIC,aAAa;YACfA,YAAYO,gBAAgB,CAAC,UAAUD;QACzC,OAAO;YACLT,OAAOU,gBAAgB,CAAC,UAAUD;QACpC;QAEA,OAAO;YACL,IAAIN,aAAa;gBACfA,YAAYQ,mBAAmB,CAAC,UAAUF;YAC5C,OAAO;gBACLT,OAAOW,mBAAmB,CAAC,UAAUF;YACvC;QACF;IACF,GAAG,EAAE;IAEL,OAAON;AACT"}
|
|
@@ -26,7 +26,7 @@ export interface PageInactiveOptions {
|
|
|
26
26
|
* This will be called whenever the page activity changes based on the
|
|
27
27
|
* {@link PageInactiveType}.
|
|
28
28
|
*/
|
|
29
|
-
onChange(active: boolean)
|
|
29
|
+
onChange: (active: boolean) => void;
|
|
30
30
|
/**
|
|
31
31
|
* This will be fired whenever the {@link disabled} state is `true` which can
|
|
32
32
|
* be useful for clearing pending timers or resetting state.
|
|
@@ -36,7 +36,7 @@ export interface PageInactiveOptions {
|
|
|
36
36
|
*
|
|
37
37
|
* @defaultValue `() => {}`
|
|
38
38
|
*/
|
|
39
|
-
onDisabledCleanup
|
|
39
|
+
onDisabledCleanup?: () => void;
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
42
|
* @example
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/usePageInactive.ts"],"sourcesContent":["\"use client\";\nimport { useEffect } from \"react\";\n\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * When this is set to `\"focus\"`, the change handler will be fired whenever the\n * window gains or loses focus.\n *\n * When this is set to `visibility`, the change handler will be fired when the\n * browser is no longer partially visible or becomes partially visible.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState\n * @since 6.0.0\n */\nexport type PageInactiveType = \"focus\" | \"visibility\";\n\n/**\n * @since 6.0.0\n */\nexport interface PageInactiveOptions {\n /**\n * @see {@link PageInactiveType}\n * @defaultValue `\"focus\"`\n */\n type?: PageInactiveType;\n\n /**\n * @defaultValue `false`\n */\n disabled?: boolean;\n\n /**\n * This will be called whenever the page activity changes based on the\n * {@link PageInactiveType}.\n */\n onChange(active: boolean)
|
|
1
|
+
{"version":3,"sources":["../src/usePageInactive.ts"],"sourcesContent":["\"use client\";\nimport { useEffect } from \"react\";\n\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * When this is set to `\"focus\"`, the change handler will be fired whenever the\n * window gains or loses focus.\n *\n * When this is set to `visibility`, the change handler will be fired when the\n * browser is no longer partially visible or becomes partially visible.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState\n * @since 6.0.0\n */\nexport type PageInactiveType = \"focus\" | \"visibility\";\n\n/**\n * @since 6.0.0\n */\nexport interface PageInactiveOptions {\n /**\n * @see {@link PageInactiveType}\n * @defaultValue `\"focus\"`\n */\n type?: PageInactiveType;\n\n /**\n * @defaultValue `false`\n */\n disabled?: boolean;\n\n /**\n * This will be called whenever the page activity changes based on the\n * {@link PageInactiveType}.\n */\n onChange: (active: boolean) => void;\n\n /**\n * This will be fired whenever the {@link disabled} state is `true` which can\n * be useful for clearing pending timers or resetting state.\n *\n * Since this is passed to a `useEffect` as a dependency, you might have to\n * wrap this in a `useCallback` if unexpected re-rendering or errors occurs.\n *\n * @defaultValue `() => {}`\n */\n onDisabledCleanup?: () => void;\n}\n\n/**\n * @example\n * ```ts\n * import { usePageInactive } from \"@react-md/core\";\n * import { useCallback, useEffect, useRef, useState } from \"react\";\n *\n * function Example(): null {\n * const [visible, setVisible] = useState(false);\n * const timeout = useRef<number | undefined>();\n * const startTimeout = useCallback(() => {\n * timeout.current = window.setTimeout(() => {\n * setVisible(false);\n * }, 10000);\n * }, []);\n *\n * usePageInactive({\n * onChange(active) {\n * if (!active) {\n * window.clearTimeout(timeout.current);\n * setVisible(false);\n * } else {\n * startTimeout();\n * }\n * }\n * });\n *\n * // pretend implementation\n * return null;\n * }\n * ```\n * @since 6.0.0\n */\nexport function usePageInactive(options: PageInactiveOptions): void {\n const {\n type = \"focus\",\n disabled,\n onChange,\n onDisabledCleanup = noop,\n } = options;\n useEffect(() => {\n if (disabled) {\n onDisabledCleanup();\n return;\n }\n\n const callback = (event: Event): void => {\n let active = document.visibilityState === \"visible\";\n if (event.type === \"blur\") {\n active = false;\n } else if (event.type === \"focus\") {\n active = true;\n }\n\n onChange(active);\n };\n\n document.addEventListener(\"visibilitychange\", callback);\n if (type === \"focus\") {\n window.addEventListener(\"blur\", callback);\n window.addEventListener(\"focus\", callback);\n }\n\n return () => {\n document.removeEventListener(\"visibilitychange\", callback);\n window.removeEventListener(\"blur\", callback);\n window.removeEventListener(\"focus\", callback);\n };\n }, [disabled, onChange, onDisabledCleanup, type]);\n}\n"],"names":["useEffect","noop","usePageInactive","options","type","disabled","onChange","onDisabledCleanup","callback","event","active","document","visibilityState","addEventListener","window","removeEventListener"],"mappings":"AAAA;AACA,SAASA,SAAS,QAAQ,QAAQ;AAElC,MAAMC,OAAO;AACX,aAAa;AACf;AA+CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BC,GACD,OAAO,SAASC,gBAAgBC,OAA4B;IAC1D,MAAM,EACJC,OAAO,OAAO,EACdC,QAAQ,EACRC,QAAQ,EACRC,oBAAoBN,IAAI,EACzB,GAAGE;IACJH,UAAU;QACR,IAAIK,UAAU;YACZE;YACA;QACF;QAEA,MAAMC,WAAW,CAACC;YAChB,IAAIC,SAASC,SAASC,eAAe,KAAK;YAC1C,IAAIH,MAAML,IAAI,KAAK,QAAQ;gBACzBM,SAAS;YACX,OAAO,IAAID,MAAML,IAAI,KAAK,SAAS;gBACjCM,SAAS;YACX;YAEAJ,SAASI;QACX;QAEAC,SAASE,gBAAgB,CAAC,oBAAoBL;QAC9C,IAAIJ,SAAS,SAAS;YACpBU,OAAOD,gBAAgB,CAAC,QAAQL;YAChCM,OAAOD,gBAAgB,CAAC,SAASL;QACnC;QAEA,OAAO;YACLG,SAASI,mBAAmB,CAAC,oBAAoBP;YACjDM,OAAOC,mBAAmB,CAAC,QAAQP;YACnCM,OAAOC,mBAAmB,CAAC,SAASP;QACtC;IACF,GAAG;QAACH;QAAUC;QAAUC;QAAmBH;KAAK;AAClD"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type UseStateSetter, type UseStateInitializer } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* @since 6.0.0
|
|
4
|
+
*/
|
|
5
|
+
export interface ReadonlySetOptions<T> {
|
|
6
|
+
/**
|
|
7
|
+
* Sets the behavior for when the
|
|
8
|
+
* {@link ReadonlySetImplementation.toggleValue} is triggered and mostly for
|
|
9
|
+
* internal usage. The default behavior (`"multiple"`) is to work how most
|
|
10
|
+
* would expect:
|
|
11
|
+
* - If the item does not exist in the set, add it.
|
|
12
|
+
* - If the item exists in the set, remove it.
|
|
13
|
+
*
|
|
14
|
+
* Setting this to `"single"` makes it so that only a single item can be in
|
|
15
|
+
* the set at once and will toggle like normal:
|
|
16
|
+
* - If the item does not exist in the set, return a new set only including
|
|
17
|
+
* the item.
|
|
18
|
+
* - If the item exists in the set, return an empty set.
|
|
19
|
+
* An example usage is the `useExpansionPanels` to allow only a single panel
|
|
20
|
+
* to be expanded at a time.
|
|
21
|
+
*
|
|
22
|
+
* Setting this to `"single-select"` makes it so that only a single item can
|
|
23
|
+
* be in the set at once but will not toggle:
|
|
24
|
+
* - If the item does not exist in the set, return a new set only including
|
|
25
|
+
* the item.
|
|
26
|
+
* - If the item exists in the set, do nothing
|
|
27
|
+
* An example usage is the `useTreeSelection` to always require at least one
|
|
28
|
+
* tree item to be selected. It is impossible to deselect an item.
|
|
29
|
+
*
|
|
30
|
+
* @defaultValue `"multiple"`
|
|
31
|
+
*/
|
|
32
|
+
toggleType?: "single" | "multiple" | "single-select";
|
|
33
|
+
defaultValue?: UseStateInitializer<ReadonlySet<T> | readonly T[]>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* @since 6.0.0
|
|
37
|
+
*/
|
|
38
|
+
export interface ReadonlySetImplementation<T> {
|
|
39
|
+
value: ReadonlySet<T>;
|
|
40
|
+
setValue: UseStateSetter<ReadonlySet<T>>;
|
|
41
|
+
toggleValue: (item: T) => void;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* This is most likely an internal only hook to manage state for a
|
|
45
|
+
* `ReadonlySet`. You most likely want to use one of the other hooks that
|
|
46
|
+
* leverage this instead:
|
|
47
|
+
*
|
|
48
|
+
* - `useCheckboxGroup`
|
|
49
|
+
* - `useExpansionPanels`
|
|
50
|
+
* - `useTreeSelection`
|
|
51
|
+
* - `useTreeExpansion`
|
|
52
|
+
* - etc
|
|
53
|
+
*
|
|
54
|
+
* @example Simple Example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* import { cnb } from "cnbuilder";
|
|
57
|
+
* import { useReadonlySet } from "@react-md/core/useReadonlySet";
|
|
58
|
+
*
|
|
59
|
+
* function Example() {
|
|
60
|
+
* const { value, toggleValue } = useReadonlySet();
|
|
61
|
+
*
|
|
62
|
+
* return (
|
|
63
|
+
* <>
|
|
64
|
+
* {someList.map((item) => (
|
|
65
|
+
* <div key={item.id} className={cnb(value.has(item.id) && styles.selected)}>
|
|
66
|
+
* {item.name}
|
|
67
|
+
* <Button onClick={() => toggleValue(item.id)}>Button</Button>
|
|
68
|
+
* </div>
|
|
69
|
+
* ))}
|
|
70
|
+
* </>
|
|
71
|
+
* );
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
* @since 6.0.0
|
|
75
|
+
*/
|
|
76
|
+
export declare function useReadonlySet<T>(options?: ReadonlySetOptions<T>): ReadonlySetImplementation<T>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useCallback, useState } from "react";
|
|
3
|
+
/**
|
|
4
|
+
* This is most likely an internal only hook to manage state for a
|
|
5
|
+
* `ReadonlySet`. You most likely want to use one of the other hooks that
|
|
6
|
+
* leverage this instead:
|
|
7
|
+
*
|
|
8
|
+
* - `useCheckboxGroup`
|
|
9
|
+
* - `useExpansionPanels`
|
|
10
|
+
* - `useTreeSelection`
|
|
11
|
+
* - `useTreeExpansion`
|
|
12
|
+
* - etc
|
|
13
|
+
*
|
|
14
|
+
* @example Simple Example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* import { cnb } from "cnbuilder";
|
|
17
|
+
* import { useReadonlySet } from "@react-md/core/useReadonlySet";
|
|
18
|
+
*
|
|
19
|
+
* function Example() {
|
|
20
|
+
* const { value, toggleValue } = useReadonlySet();
|
|
21
|
+
*
|
|
22
|
+
* return (
|
|
23
|
+
* <>
|
|
24
|
+
* {someList.map((item) => (
|
|
25
|
+
* <div key={item.id} className={cnb(value.has(item.id) && styles.selected)}>
|
|
26
|
+
* {item.name}
|
|
27
|
+
* <Button onClick={() => toggleValue(item.id)}>Button</Button>
|
|
28
|
+
* </div>
|
|
29
|
+
* ))}
|
|
30
|
+
* </>
|
|
31
|
+
* );
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
* @since 6.0.0
|
|
35
|
+
*/ export function useReadonlySet(options = {}) {
|
|
36
|
+
const { defaultValue, toggleType = "multiple" } = options;
|
|
37
|
+
const [value, setValue] = useState(()=>{
|
|
38
|
+
const initial = defaultValue instanceof Function ? defaultValue() : defaultValue ?? [];
|
|
39
|
+
return new Set(initial);
|
|
40
|
+
});
|
|
41
|
+
const toggleValue = useCallback((item)=>{
|
|
42
|
+
setValue((prevValue)=>{
|
|
43
|
+
const exists = prevValue.has(item);
|
|
44
|
+
if (toggleType === "single") {
|
|
45
|
+
return new Set(exists ? [] : [
|
|
46
|
+
item
|
|
47
|
+
]);
|
|
48
|
+
}
|
|
49
|
+
if (toggleType === "single-select") {
|
|
50
|
+
return exists ? prevValue : new Set([
|
|
51
|
+
item
|
|
52
|
+
]);
|
|
53
|
+
}
|
|
54
|
+
const nextValue = new Set(prevValue);
|
|
55
|
+
if (exists) {
|
|
56
|
+
nextValue.delete(item);
|
|
57
|
+
} else {
|
|
58
|
+
nextValue.add(item);
|
|
59
|
+
}
|
|
60
|
+
return nextValue;
|
|
61
|
+
});
|
|
62
|
+
}, [
|
|
63
|
+
toggleType
|
|
64
|
+
]);
|
|
65
|
+
return {
|
|
66
|
+
value,
|
|
67
|
+
setValue,
|
|
68
|
+
toggleValue
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
//# sourceMappingURL=useReadonlySet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/useReadonlySet.ts"],"sourcesContent":["\"use client\";\nimport { useCallback, useState } from \"react\";\nimport { type UseStateSetter, type UseStateInitializer } 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 * This is most likely an internal only hook to manage state for a\n * `ReadonlySet`. You most likely want to use one of the other hooks that\n * 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 instanceof Function ? defaultValue() : (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","Function","Set","toggleValue","item","prevValue","exists","has","nextValue","delete","add"],"mappings":"AAAA;AACA,SAASA,WAAW,EAAEC,QAAQ,QAAQ,QAAQ;AA8C9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCC,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,UACJJ,wBAAwBK,WAAWL,iBAAkBA,gBAAgB,EAAE;QAEzE,OAAO,IAAIM,IAAIF;IACjB;IAEA,MAAMG,cAAcX,YAClB,CAACY;QACCL,SAAS,CAACM;YACR,MAAMC,SAASD,UAAUE,GAAG,CAACH;YAC7B,IAAIP,eAAe,UAAU;gBAC3B,OAAO,IAAIK,IAAII,SAAS,EAAE,GAAG;oBAACF;iBAAK;YACrC;YAEA,IAAIP,eAAe,iBAAiB;gBAClC,OAAOS,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;QAACX;KAAW;IAGd,OAAO;QACLC;QACAC;QACAI;IACF;AACF"}
|
|
@@ -25,7 +25,7 @@ export interface ResizeListenerOptions extends AddEventListenerOptions {
|
|
|
25
25
|
* This function will be called whenever the resize event is fired on the
|
|
26
26
|
* `window`. This should be wrapped in `useCallback`.
|
|
27
27
|
*/
|
|
28
|
-
onUpdate(event: Event)
|
|
28
|
+
onUpdate: (event: Event) => void;
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
31
|
* This hook can be used to listen to the entire window resizing. If you need to
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useResizeListener.ts"],"sourcesContent":["\"use client\";\nimport { useEffect } from \"react\";\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)
|
|
1
|
+
{"version":3,"sources":["../src/useResizeListener.ts"],"sourcesContent":["\"use client\";\nimport { useEffect } from \"react\";\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\";\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><code>{JSON.stringify(size, null, 2)}</code></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 window.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","window","add","dispatchEvent","Event","remove"],"mappings":"AAAA;AACA,SAASA,SAAS,QAAQ,QAAQ;AAClC,SAASC,aAAa,QAAQ,qBAAqB;AAoCnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCC,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,QAAQJ,UAAU;YAC7DJ;YACAC;YACAC;YACAC;QACF;QACAI,aAAaE,GAAG,CAACH;QAEjBE,OAAOE,aAAa,CAAC,IAAIC,MAAM;QAC/B,OAAO;YACLJ,aAAaK,MAAM,CAACN;QACtB;IACF,GAAG;QAACJ;QAASG;QAAUC;QAAUN;QAAMG;QAASF;QAAQG;KAAS;AACnE"}
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import { type AnyFunction, type
|
|
2
|
-
/**
|
|
3
|
-
* @since 6.0.0
|
|
4
|
-
*/
|
|
5
|
-
export type ThrottledFunction<F extends AnyFunction> = CancelableFunction<(...args: Parameters<F>) => ReturnType<F>>;
|
|
1
|
+
import { type AnyFunction, type ThrottledFunction } from "./types.js";
|
|
6
2
|
/**
|
|
7
3
|
* Creates a function that will only be called once every X milliseconds.
|
|
8
4
|
*
|
|
@@ -107,7 +107,9 @@ import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect.js";
|
|
|
107
107
|
}
|
|
108
108
|
return result.current;
|
|
109
109
|
};
|
|
110
|
-
throttled.cancel = ()=>
|
|
110
|
+
throttled.cancel = ()=>{
|
|
111
|
+
window.clearTimeout(timeout.current);
|
|
112
|
+
};
|
|
111
113
|
return throttled;
|
|
112
114
|
}, [
|
|
113
115
|
wait
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useThrottledFunction.ts"],"sourcesContent":["\"use client\";\nimport { useEffect, useMemo, useRef } from \"react\";\nimport { type AnyFunction, type
|
|
1
|
+
{"version":3,"sources":["../src/useThrottledFunction.ts"],"sourcesContent":["\"use client\";\nimport { useEffect, useMemo, useRef } from \"react\";\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, useThrottledFunction, useUnmounted } from \"@react-md/core\";\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<number | undefined>();\n const funcRef = useRef(func);\n const lastCalledTime = useRef(0);\n\n useIsomorphicLayoutEffect(() => {\n funcRef.current = func;\n });\n\n useEffect(() => {\n return () => {\n window.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 = window.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 window.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","window","clearTimeout","throttled","nextArgs","now","Date","remaining","setTimeout","undefined","cancel"],"mappings":"AAAA;AACA,SAASA,SAAS,EAAEC,OAAO,EAAEC,MAAM,QAAQ,QAAQ;AAEnD,SAASC,yBAAyB,QAAQ,iCAAiC;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0EC,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,OAAOC,YAAY,CAACL,QAAQG,OAAO;QACrC;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,OAAOO,UAAU,CAAC;oBAClCT,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,OAAOC,YAAY,CAACL,QAAQG,OAAO;QACrC;QAEA,OAAOG;IACT,GAAG;QAACT;KAAK;AACX"}
|
package/dist/useToggle.d.ts
CHANGED
|
@@ -5,9 +5,9 @@ import { type UseStateInitializer, type UseStateSetter } from "./types.js";
|
|
|
5
5
|
export interface ToggleImplementation {
|
|
6
6
|
toggled: boolean;
|
|
7
7
|
setToggled: UseStateSetter<boolean>;
|
|
8
|
-
toggle()
|
|
9
|
-
enable()
|
|
10
|
-
disable()
|
|
8
|
+
toggle: () => void;
|
|
9
|
+
enable: () => void;
|
|
10
|
+
disable: () => void;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
*
|
package/dist/useToggle.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useToggle.ts"],"sourcesContent":["\"use client\";\nimport { useCallback, useState } from \"react\";\nimport { type UseStateInitializer, type UseStateSetter } from \"./types.js\";\n\n/**\n * @since 6.0.0\n */\nexport interface ToggleImplementation {\n toggled: boolean;\n setToggled: UseStateSetter<boolean>;\n toggle()
|
|
1
|
+
{"version":3,"sources":["../src/useToggle.ts"],"sourcesContent":["\"use client\";\nimport { useCallback, useState } from \"react\";\nimport { type UseStateInitializer, type UseStateSetter } from \"./types.js\";\n\n/**\n * @since 6.0.0\n */\nexport interface ToggleImplementation {\n toggled: boolean;\n setToggled: UseStateSetter<boolean>;\n toggle: () => void;\n enable: () => void;\n disable: () => void;\n}\n\n/**\n *\n * @example Simple Example\n * ```tsx\n * import { Button, useToggle } from \"@react-md/core\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { toggled, toggle } = useToggle();\n *\n * return (\n * <>\n * <Button onClick={toggle}>Toggle</Button>\n * {`Toggled: ${toggled}`}\n * </>\n * );\n * }\n * ```\n *\n * @param defaultValue - `false`\n */\nexport function useToggle(\n defaultValue: UseStateInitializer<boolean> = false\n): ToggleImplementation {\n const [toggled, setToggled] = useState(defaultValue);\n\n return {\n toggled,\n setToggled,\n toggle: useCallback(() => {\n setToggled((prevToggled) => !prevToggled);\n }, []),\n enable: useCallback(() => {\n setToggled(true);\n }, []),\n disable: useCallback(() => {\n setToggled(false);\n }, []),\n };\n}\n"],"names":["useCallback","useState","useToggle","defaultValue","toggled","setToggled","toggle","prevToggled","enable","disable"],"mappings":"AAAA;AACA,SAASA,WAAW,EAAEC,QAAQ,QAAQ,QAAQ;AAc9C;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,OAAO,SAASC,UACdC,eAA6C,KAAK;IAElD,MAAM,CAACC,SAASC,WAAW,GAAGJ,SAASE;IAEvC,OAAO;QACLC;QACAC;QACAC,QAAQN,YAAY;YAClBK,WAAW,CAACE,cAAgB,CAACA;QAC/B,GAAG,EAAE;QACLC,QAAQR,YAAY;YAClBK,WAAW;QACb,GAAG,EAAE;QACLI,SAAST,YAAY;YACnBK,WAAW;QACb,GAAG,EAAE;IACP;AACF"}
|