@astryxdesign/core 0.4.5 → 0.4.6-canary.cea9ecd
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/CHANGELOG.md +134 -0
- package/dist/Avatar/Avatar.d.ts +10 -5
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +139 -30
- package/dist/Avatar/AvatarStatusDot.d.ts +2 -1
- package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
- package/dist/Avatar/AvatarStatusDot.js +30 -4
- package/dist/Avatar/AvatarStatusLabelContext.d.ts +39 -0
- package/dist/Avatar/AvatarStatusLabelContext.d.ts.map +1 -0
- package/dist/Avatar/AvatarStatusLabelContext.js +41 -0
- package/dist/AvatarGroup/AvatarGroup.d.ts +3 -1
- package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +15 -9
- package/dist/Blockquote/Blockquote.d.ts +4 -3
- package/dist/Blockquote/Blockquote.d.ts.map +1 -1
- package/dist/Blockquote/Blockquote.js +9 -10
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +21 -5
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +47 -34
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +7 -7
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +21 -12
- package/dist/Calendar/hooks/useCalendarNavigation.d.ts.map +1 -1
- package/dist/Calendar/hooks/useCalendarNavigation.js +8 -4
- package/dist/Calendar/styles.d.ts +2 -2
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +5 -5
- package/dist/Center/Center.d.ts +23 -1
- package/dist/Center/Center.d.ts.map +1 -1
- package/dist/Center/Center.js +12 -6
- package/dist/Chat/ChatComposer.d.ts.map +1 -1
- package/dist/Chat/ChatComposer.js +3 -3
- package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
- package/dist/Chat/ChatComposerDrawer.js +2 -2
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +2 -2
- package/dist/Chat/useChatDictation.d.ts +1 -1
- package/dist/Chat/useChatDictation.d.ts.map +1 -1
- package/dist/Chat/useSpeechRecognition.d.ts +1 -1
- package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
- package/dist/Chat/useSpeechRecognition.js +4 -3
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +2 -2
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +2 -2
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +5 -5
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +4 -4
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +1 -1
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +2 -2
- package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteItem.js +3 -3
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +6 -6
- package/dist/DateInput/DateInput.d.ts +31 -2
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +90 -22
- package/dist/DateInput/MonthScroller.d.ts +35 -0
- package/dist/DateInput/MonthScroller.d.ts.map +1 -0
- package/dist/DateInput/MonthScroller.js +658 -0
- package/dist/DateInput/MonthYearWheels.d.ts +24 -0
- package/dist/DateInput/MonthYearWheels.d.ts.map +1 -0
- package/dist/DateInput/MonthYearWheels.js +114 -0
- package/dist/DateInput/TouchDateField.d.ts +10 -0
- package/dist/DateInput/TouchDateField.d.ts.map +1 -0
- package/dist/DateInput/TouchDateField.js +810 -0
- package/dist/DateInput/Wheel.d.ts +41 -0
- package/dist/DateInput/Wheel.d.ts.map +1 -0
- package/dist/DateInput/Wheel.js +315 -0
- package/dist/DateInput/monthGeometry.d.ts +65 -0
- package/dist/DateInput/monthGeometry.d.ts.map +1 -0
- package/dist/DateInput/monthGeometry.js +98 -0
- package/dist/DateInput/tokens.stylex.d.ts +63 -0
- package/dist/DateInput/tokens.stylex.d.ts.map +1 -0
- package/dist/DateInput/tokens.stylex.js +74 -0
- package/dist/DateInput/useOwnScrollGesture.d.ts +41 -0
- package/dist/DateInput/useOwnScrollGesture.d.ts.map +1 -0
- package/dist/DateInput/useOwnScrollGesture.js +202 -0
- package/dist/DateInput/usePointerDragScroll.d.ts +15 -0
- package/dist/DateInput/usePointerDragScroll.d.ts.map +1 -0
- package/dist/DateInput/usePointerDragScroll.js +216 -0
- package/dist/DateInput/useScrollSettle.d.ts +26 -0
- package/dist/DateInput/useScrollSettle.d.ts.map +1 -0
- package/dist/DateInput/useScrollSettle.js +149 -0
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +17 -14
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +17 -14
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +3 -3
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +2 -2
- package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuItem.js +2 -2
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +2 -2
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +2 -2
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +4 -4
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +6 -0
- package/dist/Field/inputStyles.stylex.d.ts +1 -1
- package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
- package/dist/Field/inputStyles.stylex.js +5 -5
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +6 -6
- package/dist/HoverCard/HoverCard.d.ts +13 -3
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +2 -0
- package/dist/HoverCard/index.d.ts +1 -1
- package/dist/HoverCard/index.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.d.ts +17 -2
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +78 -9
- package/dist/InputGroup/InputGroup.js +1 -1
- package/dist/Item/Item.d.ts +9 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +52 -14
- package/dist/Layer/index.d.ts +4 -2
- package/dist/Layer/index.d.ts.map +1 -1
- package/dist/Layer/index.js +2 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +3 -2
- package/dist/Layer/useTouchTrigger.d.ts +113 -0
- package/dist/Layer/useTouchTrigger.d.ts.map +1 -0
- package/dist/Layer/useTouchTrigger.js +241 -0
- package/dist/Layout/container.stylex.d.ts +4 -2
- package/dist/Layout/container.stylex.d.ts.map +1 -1
- package/dist/Layout/container.stylex.js +19 -11
- package/dist/Layout/index.d.ts +1 -0
- package/dist/Layout/index.d.ts.map +1 -1
- package/dist/Layout/index.js +4 -0
- package/dist/Layout/padding.stylex.d.ts +315 -12
- package/dist/Layout/padding.stylex.d.ts.map +1 -1
- package/dist/Layout/padding.stylex.js +389 -12
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +5 -4
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +6 -6
- package/dist/MetadataList/MetadataList.d.ts.map +1 -1
- package/dist/MetadataList/MetadataList.js +1 -1
- package/dist/MobileNav/MobileNav.d.ts +1 -0
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +24 -6
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +8 -8
- package/dist/NavItem/navItemStyles.stylex.d.ts +4 -4
- package/dist/NavItem/navItemStyles.stylex.d.ts.map +1 -1
- package/dist/NavItem/navItemStyles.stylex.js +4 -4
- package/dist/NavMenu/NavHeadingMenuItem.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenuItem.js +3 -3
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +36 -8
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +3 -3
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +2 -2
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +11 -12
- package/dist/PowerSearch/PowerSearchToken.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchToken.js +3 -1
- package/dist/PowerSearch/formatFilterValue.d.ts +11 -2
- package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
- package/dist/PowerSearch/formatFilterValue.js +23 -8
- package/dist/RadioList/RadioListItem.d.ts +2 -2
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +70 -40
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +7 -7
- package/dist/Section/Section.d.ts +36 -1
- package/dist/Section/Section.d.ts.map +1 -1
- package/dist/Section/Section.js +12 -2
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +7 -2
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +3 -3
- package/dist/Selector/Selector.d.ts +26 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +93 -20
- package/dist/Selector/SelectorOption.d.ts +14 -1
- package/dist/Selector/SelectorOption.d.ts.map +1 -1
- package/dist/Selector/SelectorOption.js +6 -0
- package/dist/Selector/SelectorRowLayoutContext.d.ts +8 -0
- package/dist/Selector/SelectorRowLayoutContext.d.ts.map +1 -0
- package/dist/Selector/SelectorRowLayoutContext.js +27 -0
- package/dist/Selector/types.d.ts +1 -0
- package/dist/Selector/types.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +4 -4
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +3 -3
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +7 -7
- package/dist/Stack/Stack.d.ts +23 -1
- package/dist/Stack/Stack.d.ts.map +1 -1
- package/dist/Stack/Stack.js +12 -6
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +2 -2
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +1 -1
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +3 -3
- package/dist/Table/TableRow.js +4 -4
- package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
- package/dist/Table/plugins/columnResize/useTableColumnResize.js +1 -1
- package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
- package/dist/Table/plugins/filtering/useTableFiltering.js +2 -2
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +2 -2
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +2 -2
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +1 -1
- package/dist/Table/plugins/sortable/useTableSortableState.d.ts +5 -3
- package/dist/Table/plugins/sortable/useTableSortableState.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortableState.js +12 -9
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +3 -3
- package/dist/TextArea/TextArea.js +1 -1
- package/dist/TextInput/TextInput.js +1 -1
- package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
- package/dist/Thumbnail/Thumbnail.js +3 -3
- package/dist/TimeInput/TimeInput.js +2 -2
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +6 -4
- package/dist/Timestamp/formatInstant.d.ts +3 -2
- package/dist/Timestamp/formatInstant.d.ts.map +1 -1
- package/dist/Timestamp/formatInstant.js +8 -8
- package/dist/Timestamp/tooltipEntries.d.ts +2 -1
- package/dist/Timestamp/tooltipEntries.d.ts.map +1 -1
- package/dist/Timestamp/tooltipEntries.js +5 -3
- package/dist/Toast/Toast.d.ts +4 -3
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +10 -7
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +6 -6
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +1 -1
- package/dist/Tooltip/Tooltip.d.ts +16 -3
- package/dist/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip/Tooltip.js +2 -0
- package/dist/Tooltip/index.d.ts +1 -1
- package/dist/Tooltip/index.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.d.ts +21 -2
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +71 -13
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +4 -4
- package/dist/TopNav/TopNavItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavItem.js +3 -3
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +2 -2
- package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenuItem.js +2 -2
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +4 -4
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +7 -7
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +2 -2
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +1 -1
- package/dist/astryx.css +124 -62
- package/dist/hooks/containerReveal.stylex.d.ts.map +1 -1
- package/dist/hooks/containerReveal.stylex.js +18 -18
- package/dist/hooks/scrollbarGutter.d.ts +28 -0
- package/dist/hooks/scrollbarGutter.d.ts.map +1 -0
- package/dist/hooks/scrollbarGutter.js +103 -0
- package/dist/hooks/useAutoMediaMode.d.ts +31 -0
- package/dist/hooks/useAutoMediaMode.d.ts.map +1 -0
- package/dist/hooks/useAutoMediaMode.js +201 -0
- package/dist/hooks/useInputStatusIcon.d.ts.map +1 -1
- package/dist/hooks/useInputStatusIcon.js +1 -1
- package/dist/hooks/useListFocus.d.ts +5 -2
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +12 -6
- package/dist/hooks/useScrollLock.d.ts +4 -0
- package/dist/hooks/useScrollLock.d.ts.map +1 -1
- package/dist/hooks/useScrollLock.js +13 -1
- package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
- package/dist/i18n/InternationalizationContext.js +2 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js +6 -0
- package/dist/i18n/useCollator.d.ts +12 -0
- package/dist/i18n/useCollator.d.ts.map +1 -0
- package/dist/i18n/useCollator.js +40 -0
- package/dist/i18n/useLocale.d.ts +3 -0
- package/dist/i18n/useLocale.d.ts.map +1 -0
- package/dist/i18n/useLocale.js +31 -0
- package/dist/theme/MediaTheme.d.ts +25 -5
- package/dist/theme/MediaTheme.d.ts.map +1 -1
- package/dist/theme/MediaTheme.js +31 -6
- package/dist/theme/defineTheme.d.ts +5 -0
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +5 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +7 -0
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +66 -5
- package/dist/theme/index.d.ts +1 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/syntax/index.d.ts +6 -0
- package/dist/theme/syntax/index.d.ts.map +1 -1
- package/dist/theme/syntax/index.js +7 -2
- package/dist/utils/dateParser.d.ts +4 -3
- package/dist/utils/dateParser.d.ts.map +1 -1
- package/dist/utils/dateParser.js +8 -8
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/plainDate.d.ts +5 -2
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +20 -4
- package/locales/en.json +28 -0
- package/locales/pseudo.json +21 -0
- package/package.json +3 -3
- package/src/Avatar/Avatar.doc.mjs +10 -6
- package/src/Avatar/Avatar.test.tsx +219 -1
- package/src/Avatar/Avatar.tsx +179 -37
- package/src/Avatar/AvatarStatusDot.tsx +30 -4
- package/src/Avatar/AvatarStatusLabelContext.ts +47 -0
- package/src/AvatarGroup/AvatarGroup.doc.mjs +10 -6
- package/src/AvatarGroup/AvatarGroup.test.tsx +62 -0
- package/src/AvatarGroup/AvatarGroup.tsx +3 -1
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +31 -8
- package/src/Banner/Banner.doc.mjs +2 -0
- package/src/Blockquote/Blockquote.doc.mjs +30 -7
- package/src/Blockquote/Blockquote.test.tsx +34 -3
- package/src/Blockquote/Blockquote.tsx +11 -9
- package/src/BottomSheet/BottomSheet.doc.mjs +3 -3
- package/src/BottomSheet/BottomSheet.test.tsx +24 -0
- package/src/BottomSheet/BottomSheetPanel.test.tsx +91 -0
- package/src/BottomSheet/BottomSheetPanel.tsx +58 -3
- package/src/Breadcrumbs/BreadcrumbItem.tsx +36 -23
- package/src/Breadcrumbs/Breadcrumbs.doc.mjs +26 -2
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -0
- package/src/Button/Button.tsx +12 -9
- package/src/Calendar/Calendar.tsx +15 -9
- package/src/Calendar/hooks/useCalendarNavigation.ts +6 -4
- package/src/Calendar/styles.ts +8 -5
- package/src/Center/Center.doc.mjs +48 -0
- package/src/Center/Center.test.tsx +158 -0
- package/src/Center/Center.tsx +50 -9
- package/src/Chat/ChatComposer.tsx +11 -5
- package/src/Chat/ChatComposerDrawer.tsx +4 -1
- package/src/Chat/ChatToolCalls.tsx +13 -4
- package/src/Chat/{useChatDictation.test.ts → useChatDictation.test.tsx} +29 -14
- package/src/Chat/useChatDictation.ts +1 -1
- package/src/Chat/useSpeechRecognition.ts +5 -3
- package/src/Chat/useTriggerMenu.tsx +4 -1
- package/src/CheckboxInput/CheckboxInput.tsx +5 -2
- package/src/Citation/Citation.test.tsx +6 -1
- package/src/Citation/Citation.tsx +11 -5
- package/src/ClickableCard/ClickableCard.tsx +7 -4
- package/src/CodeBlock/CodeBlock.tsx +4 -1
- package/src/Collapsible/Collapsible.tsx +5 -2
- package/src/CommandPalette/CommandPaletteItem.tsx +6 -3
- package/src/ComplexSelector/ComplexSelector.doc.mjs +10 -0
- package/src/ComplexSelector/ComplexSelector.tsx +14 -7
- package/src/DateInput/DateInput.test.tsx +17 -1
- package/src/DateInput/DateInput.tsx +93 -21
- package/src/DateInput/DateInputTouch.test.tsx +2582 -0
- package/src/DateInput/MonthScroller.tsx +878 -0
- package/src/DateInput/MonthYearWheels.tsx +147 -0
- package/src/DateInput/TouchDateField.tsx +1223 -0
- package/src/DateInput/Wheel.tsx +473 -0
- package/src/DateInput/monthGeometry.ts +118 -0
- package/src/DateInput/tokens.stylex.ts +99 -0
- package/src/DateInput/useOwnScrollGesture.ts +227 -0
- package/src/DateInput/usePointerDragScroll.ts +220 -0
- package/src/DateInput/useScrollSettle.ts +164 -0
- package/src/DateRangeInput/DateRangeInput.doc.mjs +1 -1
- package/src/DateRangeInput/DateRangeInput.tsx +31 -13
- package/src/DateTimeInput/DateTimeInput.tsx +25 -9
- package/src/Dialog/Dialog.test.tsx +24 -0
- package/src/Dialog/Dialog.tsx +3 -0
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +5 -2
- package/src/DropdownMenu/DropdownMenuItem.tsx +5 -2
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +5 -2
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +5 -2
- package/src/Field/Field.doc.mjs +2 -0
- package/src/Field/FieldLabel.tsx +9 -3
- package/src/Field/InputClearButton.test.tsx +110 -3
- package/src/Field/InputClearButton.tsx +38 -0
- package/src/Field/inputStyles.stylex.ts +17 -13
- package/src/FileInput/FileInput.tsx +15 -8
- package/src/FormLayout/FormLayout.doc.mjs +1 -1
- package/src/HoverCard/HoverCard.doc.mjs +18 -0
- package/src/HoverCard/HoverCard.test.tsx +189 -0
- package/src/HoverCard/HoverCard.tsx +22 -2
- package/src/HoverCard/index.ts +1 -0
- package/src/HoverCard/useHoverCard.doc.mjs +2 -0
- package/src/HoverCard/useHoverCard.tsx +103 -7
- package/src/InputGroup/InputGroup.tsx +1 -1
- package/src/Item/Item.doc.mjs +1 -0
- package/src/Item/Item.test.tsx +50 -0
- package/src/Item/Item.tsx +54 -6
- package/src/Layer/index.ts +10 -0
- package/src/Layer/useLayer.tsx +13 -2
- package/src/Layer/useTouchTrigger.test.ts +70 -0
- package/src/Layer/useTouchTrigger.ts +366 -0
- package/src/Layout/Layout.doc.mjs +18 -0
- package/src/Layout/container.stylex.ts +11 -3
- package/src/Layout/index.ts +4 -0
- package/src/Layout/overlayPaddingReset.test.tsx +222 -0
- package/src/Layout/padding.stylex.ts +192 -12
- package/src/Lightbox/Lightbox.tsx +11 -3
- package/src/Link/Link.tsx +9 -6
- package/src/MetadataList/MetadataList.tsx +4 -1
- package/src/MobileNav/MobileNav.tsx +61 -5
- package/src/MobileNav/MobileNavEntryAnimation.test.tsx +212 -0
- package/src/MobileNav/MobileNavScrollbarGutter.test.tsx +109 -0
- package/src/MultiSelector/MultiSelector.test.tsx +1 -1
- package/src/MultiSelector/MultiSelector.tsx +26 -10
- package/src/NavItem/navItemStyles.stylex.ts +7 -4
- package/src/NavMenu/NavHeadingMenuItem.tsx +6 -3
- package/src/NumberInput/NumberInput.doc.mjs +24 -0
- package/src/NumberInput/NumberInput.test.tsx +138 -0
- package/src/NumberInput/NumberInput.tsx +47 -8
- package/src/Outline/Outline.tsx +5 -2
- package/src/Pagination/Pagination.tsx +5 -2
- package/src/Popover/Popover.test.tsx +27 -1
- package/src/PowerSearch/PowerSearch.tsx +17 -8
- package/src/PowerSearch/PowerSearchToken.tsx +3 -0
- package/src/PowerSearch/formatFilterValue.test.ts +22 -2
- package/src/PowerSearch/formatFilterValue.ts +31 -6
- package/src/RadioList/RadioList.doc.mjs +1 -1
- package/src/RadioList/RadioList.test.tsx +170 -2
- package/src/RadioList/RadioListItem.tsx +88 -53
- package/src/Resizable/ResizeHandle.test.tsx +22 -0
- package/src/Resizable/ResizeHandle.tsx +25 -7
- package/src/Section/Section.doc.mjs +55 -0
- package/src/Section/Section.test.tsx +201 -4
- package/src/Section/Section.tsx +69 -0
- package/src/SegmentedControl/SegmentedControl.test.tsx +31 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +15 -3
- package/src/SelectableCard/SelectableCard.tsx +6 -3
- package/src/Selector/Selector.doc.mjs +16 -2
- package/src/Selector/Selector.test.tsx +525 -1
- package/src/Selector/Selector.tsx +180 -25
- package/src/Selector/SelectorOption.doc.mjs +7 -0
- package/src/Selector/SelectorOption.tsx +21 -0
- package/src/Selector/SelectorRowLayoutContext.ts +32 -0
- package/src/Selector/types.ts +4 -4
- package/src/SideNav/SideNavHeading.tsx +14 -5
- package/src/SideNav/SideNavItem.tsx +9 -3
- package/src/Slider/Slider.tsx +25 -6
- package/src/Stack/Stack.doc.mjs +72 -0
- package/src/Stack/Stack.test.tsx +156 -0
- package/src/Stack/Stack.tsx +50 -8
- package/src/Switch/Switch.tsx +5 -2
- package/src/TabList/Tab.tsx +4 -1
- package/src/TabList/TabMenu.tsx +9 -3
- package/src/Table/TableRow.tsx +4 -4
- package/src/Table/plugins/columnResize/useTableColumnResize.tsx +6 -2
- package/src/Table/plugins/filtering/useTableFiltering.tsx +4 -1
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +10 -3
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +6 -3
- package/src/Table/plugins/sortable/useTableSortable.tsx +4 -1
- package/src/Table/plugins/sortable/useTableSortableState.test.tsx +34 -0
- package/src/Table/plugins/sortable/useTableSortableState.tsx +26 -23
- package/src/Table/plugins/tree/useTableTreeData.tsx +10 -4
- package/src/TextArea/TextArea.doc.mjs +1 -1
- package/src/TextArea/TextArea.tsx +1 -1
- package/src/TextInput/TextInput.tsx +1 -1
- package/src/Thumbnail/Thumbnail.tsx +9 -3
- package/src/TimeInput/TimeInput.tsx +1 -1
- package/src/Timestamp/Timestamp.test.tsx +27 -7
- package/src/Timestamp/Timestamp.tsx +8 -4
- package/src/Timestamp/formatInstant.ts +9 -7
- package/src/Timestamp/tooltipEntries.test.ts +11 -6
- package/src/Timestamp/tooltipEntries.ts +6 -2
- package/src/Toast/Toast.tsx +9 -7
- package/src/Token/Token.tsx +14 -5
- package/src/Tokenizer/Tokenizer.tsx +4 -1
- package/src/Tooltip/Tooltip.doc.mjs +18 -0
- package/src/Tooltip/Tooltip.test.tsx +254 -1
- package/src/Tooltip/Tooltip.tsx +22 -2
- package/src/Tooltip/index.ts +1 -0
- package/src/Tooltip/useTooltip.doc.mjs +2 -0
- package/src/Tooltip/useTooltip.tsx +99 -21
- package/src/TopNav/TopNavHeading.tsx +13 -4
- package/src/TopNav/TopNavItem.tsx +6 -3
- package/src/TopNav/TopNavMegaMenu.tsx +5 -2
- package/src/TopNav/TopNavMegaMenuItem.tsx +5 -2
- package/src/TopNav/TopNavMenu.tsx +10 -4
- package/src/TreeList/TreeListItem.tsx +22 -7
- package/src/Typeahead/BaseTypeahead.tsx +5 -2
- package/src/Typeahead/Typeahead.tsx +4 -1
- package/src/hooks/containerReveal.stylex.ts +54 -18
- package/src/hooks/scrollbarGutter.test.ts +167 -0
- package/src/hooks/scrollbarGutter.ts +121 -0
- package/src/hooks/useAutoMediaMode.test.ts +109 -0
- package/src/hooks/useAutoMediaMode.ts +233 -0
- package/src/hooks/useInputStatusIcon.tsx +4 -1
- package/src/hooks/useListFocus.doc.mjs +2 -2
- package/src/hooks/useListFocus.test.tsx +65 -3
- package/src/hooks/useListFocus.ts +15 -7
- package/src/hooks/useScrollLock.doc.mjs +4 -4
- package/src/hooks/useScrollLock.test.ts +73 -0
- package/src/hooks/useScrollLock.ts +14 -0
- package/src/i18n/InternationalizationContext.ts +2 -0
- package/src/i18n/__tests__/e2e-powersearch.test.tsx +37 -1
- package/src/i18n/__tests__/useCollator.test.tsx +115 -0
- package/src/i18n/__tests__/useLocale.test.tsx +52 -0
- package/src/i18n/index.ts +6 -0
- package/src/i18n/useCollator.doc.mjs +84 -0
- package/src/i18n/useCollator.ts +44 -0
- package/src/i18n/useLocale.doc.mjs +70 -0
- package/src/i18n/useLocale.ts +34 -0
- package/src/i18n/useTranslator.doc.mjs +1 -1
- package/src/reset.css +9 -2
- package/src/reset.test.ts +22 -0
- package/src/theme/MediaTheme.doc.mjs +23 -4
- package/src/theme/MediaTheme.dom.test.tsx +97 -0
- package/src/theme/MediaTheme.tsx +42 -7
- package/src/theme/defineTheme.test.ts +9 -3
- package/src/theme/defineTheme.ts +5 -0
- package/src/theme/derivedVarRegistry.test.ts +19 -5
- package/src/theme/derivedVarRegistry.ts +4 -0
- package/src/theme/generateThemeRules.test.ts +118 -0
- package/src/theme/generateThemeRules.ts +83 -5
- package/src/theme/index.ts +1 -1
- package/src/theme/syntax/index.ts +6 -2
- package/src/theme/syntax/serverSafeSyntax.test.ts +68 -0
- package/src/utils/dateParser.test.ts +20 -0
- package/src/utils/dateParser.ts +14 -7
- package/src/utils/index.ts +2 -0
- package/src/utils/plainDate.test.ts +6 -0
- package/src/utils/plainDate.ts +21 -4
|
@@ -66,6 +66,13 @@ export const docs = {
|
|
|
66
66
|
description: 'Controls when focus events trigger the tooltip.',
|
|
67
67
|
default: "'auto'",
|
|
68
68
|
},
|
|
69
|
+
{
|
|
70
|
+
name: 'touchTrigger',
|
|
71
|
+
type: "'auto' | 'tap' | 'none'",
|
|
72
|
+
description:
|
|
73
|
+
'What a tap does where there is no hover. auto opens on tap unless the trigger performs an action of its own (a button, link, or form control), whose tap belongs to the control. tap always opens; use it for an info icon rendered as a button, whose only job is to reveal the tooltip. none never opens on touch.',
|
|
74
|
+
default: "'auto'",
|
|
75
|
+
},
|
|
69
76
|
{
|
|
70
77
|
name: 'isEnabled',
|
|
71
78
|
type: 'boolean',
|
|
@@ -103,6 +110,7 @@ export const docs = {
|
|
|
103
110
|
bestPractices: [
|
|
104
111
|
{guidance: true, description: 'Keep tooltip content concise: aim for under 140 characters of plain text.'},
|
|
105
112
|
{guidance: true, description: 'Add a tooltip to icon-only buttons and controls that lack a visible label.'},
|
|
113
|
+
{guidance: true, description: 'Set touchTrigger to tap when the trigger is a button whose only job is revealing the tooltip, such as an info icon: touch has no hover, and auto keeps the tap for triggers that perform an action.'},
|
|
106
114
|
{guidance: false, description: 'Place interactive elements like links or buttons inside a tooltip; use HoverCard or Popover instead.'},
|
|
107
115
|
{guidance: false, description: 'Use tooltips for essential information that users must see to complete a task.'},
|
|
108
116
|
],
|
|
@@ -165,6 +173,13 @@ export const docsZh = {
|
|
|
165
173
|
description: '控制聚焦事件何时触发工具提示。',
|
|
166
174
|
default: "'auto'",
|
|
167
175
|
},
|
|
176
|
+
{
|
|
177
|
+
name: 'touchTrigger',
|
|
178
|
+
type: "'auto' | 'tap' | 'none'",
|
|
179
|
+
description:
|
|
180
|
+
'在没有悬停的触摸设备上,轻点的行为。auto:轻点即打开,除非触发元素本身会执行操作(按钮、链接、表单控件),此时轻点归该控件所有。tap:始终轻点打开——适用于以按钮形式呈现、唯一作用就是显示工具提示的信息图标。none:触摸永不打开。',
|
|
181
|
+
default: "'auto'",
|
|
182
|
+
},
|
|
168
183
|
{
|
|
169
184
|
name: 'isEnabled',
|
|
170
185
|
type: 'boolean',
|
|
@@ -202,6 +217,7 @@ export const docsZh = {
|
|
|
202
217
|
bestPractices: [
|
|
203
218
|
{guidance: true, description: 'Keep tooltip content concise: aim for under 140 characters of plain text.'},
|
|
204
219
|
{guidance: true, description: 'Add a tooltip to icon-only buttons and controls that lack a visible label.'},
|
|
220
|
+
{guidance: true, description: 'Set touchTrigger to tap when the trigger is a button whose only job is revealing the tooltip, such as an info icon: touch has no hover, and auto keeps the tap for triggers that perform an action.'},
|
|
205
221
|
{guidance: false, description: 'Place interactive elements like links or buttons inside a tooltip; use HoverCard or Popover instead.'},
|
|
206
222
|
{guidance: false, description: 'Use tooltips for essential information that users must see to complete a task.'},
|
|
207
223
|
],
|
|
@@ -217,6 +233,7 @@ export const docsDense = {
|
|
|
217
233
|
bestPractices: [
|
|
218
234
|
{guidance: true, description: 'Keep tooltip content concise: aim for under 140 characters of plain text.'},
|
|
219
235
|
{guidance: true, description: 'Add a tooltip to icon-only buttons and controls that lack a visible label.'},
|
|
236
|
+
{guidance: true, description: 'Set touchTrigger to tap when the trigger is a button whose only job is revealing the tooltip, such as an info icon: touch has no hover, and auto keeps the tap for triggers that perform an action.'},
|
|
220
237
|
{guidance: false, description: 'Place interactive elements like links or buttons inside a tooltip; use HoverCard or Popover instead.'},
|
|
221
238
|
{guidance: false, description: 'Use tooltips for essential information that users must see to complete a task.'},
|
|
222
239
|
],
|
|
@@ -235,6 +252,7 @@ export const docsDense = {
|
|
|
235
252
|
delay: 'Show delay in ms.',
|
|
236
253
|
hideDelay: 'Hide delay in ms.',
|
|
237
254
|
focusTrigger: 'Controls when focus events trigger tooltip.',
|
|
255
|
+
touchTrigger: 'Tap behavior where there is no hover. auto = tap opens unless the trigger acts (button/link/control); tap = always opens (info icon rendered as a button); none = never on touch.',
|
|
238
256
|
isEnabled: 'Enables/disables tooltip triggers.',
|
|
239
257
|
onOpenChange: 'Callback when visibility changes; true=shown, false=hidden.',
|
|
240
258
|
hasHoverIndication: 'Dashed underline on trigger element.',
|
|
@@ -9,9 +9,18 @@
|
|
|
9
9
|
* SYNC: When Tooltip.tsx changes, update tests to match new behavior
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
describe,
|
|
14
|
+
it,
|
|
15
|
+
expect,
|
|
16
|
+
vi,
|
|
17
|
+
beforeAll,
|
|
18
|
+
beforeEach,
|
|
19
|
+
afterAll,
|
|
20
|
+
} from 'vitest';
|
|
13
21
|
import {render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
14
22
|
import {Tooltip} from './Tooltip';
|
|
23
|
+
import {__resetInteractionModalityForTest} from '../utils/interactionModality';
|
|
15
24
|
|
|
16
25
|
// Store original matches to restore later
|
|
17
26
|
const originalMatches = HTMLElement.prototype.matches;
|
|
@@ -267,4 +276,248 @@ describe('Tooltip', () => {
|
|
|
267
276
|
expect(onOpenChange).not.toHaveBeenCalledWith(false);
|
|
268
277
|
});
|
|
269
278
|
});
|
|
279
|
+
describe('touch', () => {
|
|
280
|
+
// The modality is document-global; a tap in one case must not decide the
|
|
281
|
+
// next one's answer.
|
|
282
|
+
beforeEach(() => {
|
|
283
|
+
__resetInteractionModalityForTest();
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
/** A tap: the pointer sequence a finger produces before hover is faked. */
|
|
287
|
+
const tap = (element: HTMLElement) => {
|
|
288
|
+
// A finger's arrival fires pointerenter too, and that is the path a pen
|
|
289
|
+
// must not take — cover it here rather than starting at pointerdown.
|
|
290
|
+
fireEvent.pointerEnter(element, {pointerType: 'touch'});
|
|
291
|
+
fireEvent.pointerDown(element, {pointerType: 'touch'});
|
|
292
|
+
fireEvent.pointerUp(element, {pointerType: 'touch'});
|
|
293
|
+
// Touch synthesizes hover after the press; the tooltip must not act on it.
|
|
294
|
+
fireEvent.mouseEnter(element);
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
it('opens on a tap when the trigger performs no action', async () => {
|
|
298
|
+
const onOpenChange = vi.fn();
|
|
299
|
+
render(
|
|
300
|
+
<Tooltip content="Tooltip text" onOpenChange={onOpenChange} delay={200}>
|
|
301
|
+
Abbreviation
|
|
302
|
+
</Tooltip>,
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
tap(screen.getByText('Abbreviation'));
|
|
306
|
+
|
|
307
|
+
// Immediately: a tap is a decision, not hover intent, so no delay applies.
|
|
308
|
+
await waitFor(() => {
|
|
309
|
+
expect(onOpenChange).toHaveBeenCalledWith(true);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('stays shut on a tap when the trigger performs an action', async () => {
|
|
314
|
+
const onOpenChange = vi.fn();
|
|
315
|
+
render(
|
|
316
|
+
<Tooltip content="Tooltip text" onOpenChange={onOpenChange} delay={0}>
|
|
317
|
+
<button type="button">Save</button>
|
|
318
|
+
</Tooltip>,
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
tap(screen.getByRole('button', {name: 'Save'}));
|
|
322
|
+
|
|
323
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
324
|
+
expect(onOpenChange).not.toHaveBeenCalledWith(true);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it('opens on a tap of an action trigger when touchTrigger is "tap"', async () => {
|
|
328
|
+
const onOpenChange = vi.fn();
|
|
329
|
+
render(
|
|
330
|
+
<Tooltip
|
|
331
|
+
content="What this metric means"
|
|
332
|
+
onOpenChange={onOpenChange}
|
|
333
|
+
touchTrigger="tap"
|
|
334
|
+
delay={0}>
|
|
335
|
+
<button type="button">Info</button>
|
|
336
|
+
</Tooltip>,
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
tap(screen.getByRole('button', {name: 'Info'}));
|
|
340
|
+
|
|
341
|
+
await waitFor(() => {
|
|
342
|
+
expect(onOpenChange).toHaveBeenCalledWith(true);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('never opens on a tap when touchTrigger is "none"', async () => {
|
|
347
|
+
const onOpenChange = vi.fn();
|
|
348
|
+
render(
|
|
349
|
+
<Tooltip
|
|
350
|
+
content="Tooltip text"
|
|
351
|
+
onOpenChange={onOpenChange}
|
|
352
|
+
touchTrigger="none"
|
|
353
|
+
delay={0}>
|
|
354
|
+
Abbreviation
|
|
355
|
+
</Tooltip>,
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
tap(screen.getByText('Abbreviation'));
|
|
359
|
+
|
|
360
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
361
|
+
expect(onOpenChange).not.toHaveBeenCalledWith(true);
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
it('closes on a second tap of the trigger', async () => {
|
|
365
|
+
const onOpenChange = vi.fn();
|
|
366
|
+
render(
|
|
367
|
+
<Tooltip content="Tooltip text" onOpenChange={onOpenChange} delay={0}>
|
|
368
|
+
Abbreviation
|
|
369
|
+
</Tooltip>,
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
const trigger = screen.getByText('Abbreviation');
|
|
373
|
+
tap(trigger);
|
|
374
|
+
await waitFor(() => {
|
|
375
|
+
expect(onOpenChange).toHaveBeenCalledWith(true);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
tap(trigger);
|
|
379
|
+
await waitFor(() => {
|
|
380
|
+
expect(onOpenChange).toHaveBeenCalledWith(false);
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it('closes on a tap outside — the dismissal a tap-open owes the user', async () => {
|
|
385
|
+
const onOpenChange = vi.fn();
|
|
386
|
+
render(
|
|
387
|
+
<>
|
|
388
|
+
<Tooltip content="Tooltip text" onOpenChange={onOpenChange} delay={0}>
|
|
389
|
+
Abbreviation
|
|
390
|
+
</Tooltip>
|
|
391
|
+
<button type="button">Elsewhere</button>
|
|
392
|
+
</>,
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
tap(screen.getByText('Abbreviation'));
|
|
396
|
+
await waitFor(() => {
|
|
397
|
+
expect(onOpenChange).toHaveBeenCalledWith(true);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
fireEvent.pointerDown(screen.getByRole('button', {name: 'Elsewhere'}), {
|
|
401
|
+
pointerType: 'touch',
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
await waitFor(() => {
|
|
405
|
+
expect(onOpenChange).toHaveBeenCalledWith(false);
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it('still opens on a real mouse hover after a tap', async () => {
|
|
410
|
+
const onOpenChange = vi.fn();
|
|
411
|
+
render(
|
|
412
|
+
<Tooltip content="Tooltip text" onOpenChange={onOpenChange} delay={0}>
|
|
413
|
+
<button type="button">Save</button>
|
|
414
|
+
</Tooltip>,
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
const trigger = screen.getByRole('button', {name: 'Save'});
|
|
418
|
+
tap(trigger);
|
|
419
|
+
await new Promise(resolve => setTimeout(resolve, 20));
|
|
420
|
+
expect(onOpenChange).not.toHaveBeenCalledWith(true);
|
|
421
|
+
|
|
422
|
+
// A hybrid device: the same trigger, now under a mouse.
|
|
423
|
+
fireEvent.pointerEnter(trigger, {pointerType: 'mouse'});
|
|
424
|
+
fireEvent.mouseEnter(trigger);
|
|
425
|
+
|
|
426
|
+
await waitFor(() => {
|
|
427
|
+
expect(onOpenChange).toHaveBeenCalledWith(true);
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it('opens on a hovering pen, which is a hover and not a tap', async () => {
|
|
432
|
+
const onOpenChange = vi.fn();
|
|
433
|
+
render(
|
|
434
|
+
<Tooltip content="Tooltip text" onOpenChange={onOpenChange} delay={0}>
|
|
435
|
+
<button type="button">Save</button>
|
|
436
|
+
</Tooltip>,
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
const trigger = screen.getByRole('button', {name: 'Save'});
|
|
440
|
+
// A stylus in detection range: pointerenter with nothing in contact, on
|
|
441
|
+
// a device where `(hover: hover)` matches. Reading that as touch would
|
|
442
|
+
// bail out of the hover path and leave the user no tooltip at all.
|
|
443
|
+
fireEvent.pointerEnter(trigger, {pointerType: 'pen', buttons: 0});
|
|
444
|
+
fireEvent.mouseEnter(trigger);
|
|
445
|
+
|
|
446
|
+
await waitFor(() => {
|
|
447
|
+
expect(onOpenChange).toHaveBeenCalledWith(true);
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
it('tap-opens when a pen lands on an inert trigger', async () => {
|
|
452
|
+
const onOpenChange = vi.fn();
|
|
453
|
+
render(
|
|
454
|
+
<Tooltip content="Tooltip text" onOpenChange={onOpenChange} delay={200}>
|
|
455
|
+
Abbreviation
|
|
456
|
+
</Tooltip>,
|
|
457
|
+
);
|
|
458
|
+
|
|
459
|
+
const trigger = screen.getByText('Abbreviation');
|
|
460
|
+
// Hovering first, as a real pen does — then contact, which is a tap.
|
|
461
|
+
fireEvent.pointerEnter(trigger, {pointerType: 'pen', buttons: 0});
|
|
462
|
+
fireEvent.pointerDown(trigger, {pointerType: 'pen'});
|
|
463
|
+
fireEvent.pointerUp(trigger, {pointerType: 'pen'});
|
|
464
|
+
|
|
465
|
+
await waitFor(() => {
|
|
466
|
+
expect(onOpenChange).toHaveBeenCalledWith(true);
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
it('does not reopen from the focus a tapped text field takes', async () => {
|
|
471
|
+
const onOpenChange = vi.fn();
|
|
472
|
+
render(
|
|
473
|
+
<Tooltip content="Tooltip text" onOpenChange={onOpenChange} delay={0}>
|
|
474
|
+
<input type="text" aria-label="Amount" />
|
|
475
|
+
</Tooltip>,
|
|
476
|
+
);
|
|
477
|
+
|
|
478
|
+
const trigger = screen.getByLabelText('Amount');
|
|
479
|
+
// A tapped text field matches `:focus-visible` in a real browser —
|
|
480
|
+
// deliberately, per Selectors 4, so typing has a visible home. jsdom
|
|
481
|
+
// does not model that, so stand it up here; without it this case cannot
|
|
482
|
+
// fail, whatever the focus path does.
|
|
483
|
+
const realMatches = trigger.matches.bind(trigger);
|
|
484
|
+
vi.spyOn(trigger, 'matches').mockImplementation((selector: string) =>
|
|
485
|
+
selector === ':focus-visible' ? true : realMatches(selector),
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
// An `<input>` is an action trigger, so `auto` gives it the tap — and
|
|
489
|
+
// the focus it takes must not put the tooltip back over the field the
|
|
490
|
+
// user is about to type into.
|
|
491
|
+
tap(trigger);
|
|
492
|
+
fireEvent.focusIn(trigger);
|
|
493
|
+
|
|
494
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
495
|
+
expect(onOpenChange).not.toHaveBeenCalledWith(true);
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
it('still opens on keyboard focus of a trigger a finger touched', async () => {
|
|
499
|
+
const onOpenChange = vi.fn();
|
|
500
|
+
render(
|
|
501
|
+
<Tooltip content="Tooltip text" onOpenChange={onOpenChange} delay={0}>
|
|
502
|
+
<input type="text" aria-label="Amount" />
|
|
503
|
+
</Tooltip>,
|
|
504
|
+
);
|
|
505
|
+
|
|
506
|
+
const trigger = screen.getByLabelText('Amount');
|
|
507
|
+
const realMatches = trigger.matches.bind(trigger);
|
|
508
|
+
vi.spyOn(trigger, 'matches').mockImplementation((selector: string) =>
|
|
509
|
+
selector === ':focus-visible' ? true : realMatches(selector),
|
|
510
|
+
);
|
|
511
|
+
|
|
512
|
+
tap(trigger);
|
|
513
|
+
// Reaching for the keyboard ends the touch interaction; the guard is on
|
|
514
|
+
// the gesture in flight, not on the device the trigger last saw.
|
|
515
|
+
fireEvent.keyDown(document, {key: 'Tab'});
|
|
516
|
+
fireEvent.focusIn(trigger);
|
|
517
|
+
|
|
518
|
+
await waitFor(() => {
|
|
519
|
+
expect(onOpenChange).toHaveBeenCalledWith(true);
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
});
|
|
270
523
|
});
|
package/src/Tooltip/Tooltip.tsx
CHANGED
|
@@ -22,11 +22,15 @@ import React, {
|
|
|
22
22
|
} from 'react';
|
|
23
23
|
import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
|
|
24
24
|
import * as stylex from '@stylexjs/stylex';
|
|
25
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
useTooltip,
|
|
27
|
+
type TooltipFocusTrigger,
|
|
28
|
+
type TooltipTouchTrigger,
|
|
29
|
+
} from './useTooltip';
|
|
26
30
|
import type {LayerAlignment, LayerPlacement} from '../Layer/useLayer';
|
|
27
31
|
import {colorVars} from '../theme/tokens.stylex';
|
|
28
32
|
|
|
29
|
-
export type {TooltipFocusTrigger} from './useTooltip';
|
|
33
|
+
export type {TooltipFocusTrigger, TooltipTouchTrigger} from './useTooltip';
|
|
30
34
|
|
|
31
35
|
const styles = stylex.create({
|
|
32
36
|
wrapperContents: {
|
|
@@ -99,6 +103,20 @@ export interface TooltipProps {
|
|
|
99
103
|
*/
|
|
100
104
|
focusTrigger?: TooltipFocusTrigger;
|
|
101
105
|
|
|
106
|
+
/**
|
|
107
|
+
* What a tap does on a touch pointer, where there is no hover:
|
|
108
|
+
* - `auto`: tap opens the tooltip, unless the trigger performs an action of
|
|
109
|
+
* its own (a button, a link, a form control) — that tap belongs to the
|
|
110
|
+
* control, and a hint about a control the user just operated is noise
|
|
111
|
+
* - `tap`: tap always opens the tooltip. This is what an info icon rendered
|
|
112
|
+
* as a button wants: it looks like an action to the DOM, but revealing the
|
|
113
|
+
* tooltip is the only thing it does
|
|
114
|
+
* - `none`: touch never opens the tooltip
|
|
115
|
+
*
|
|
116
|
+
* @default 'auto'
|
|
117
|
+
*/
|
|
118
|
+
touchTrigger?: TooltipTouchTrigger;
|
|
119
|
+
|
|
102
120
|
/**
|
|
103
121
|
* Whether the tooltip is enabled.
|
|
104
122
|
* When false, hover/focus triggers are disabled.
|
|
@@ -176,6 +194,7 @@ export function Tooltip({
|
|
|
176
194
|
delay = 200,
|
|
177
195
|
hideDelay = 0,
|
|
178
196
|
focusTrigger = 'auto',
|
|
197
|
+
touchTrigger = 'auto',
|
|
179
198
|
isEnabled = true,
|
|
180
199
|
onOpenChange,
|
|
181
200
|
hasHoverIndication = 'auto',
|
|
@@ -204,6 +223,7 @@ export function Tooltip({
|
|
|
204
223
|
delay,
|
|
205
224
|
hideDelay,
|
|
206
225
|
focusTrigger,
|
|
226
|
+
touchTrigger,
|
|
207
227
|
isEnabled,
|
|
208
228
|
isOpen,
|
|
209
229
|
isDefaultOpen,
|
package/src/Tooltip/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ export const docs = {
|
|
|
12
12
|
{name: 'delay', type: 'number', description: 'Delay before showing on hover, in milliseconds.', default: '200'},
|
|
13
13
|
{name: 'hideDelay', type: 'number', description: 'Delay before hiding after mouse or focus leaves, in milliseconds.', default: '0'},
|
|
14
14
|
{name: 'focusTrigger', type: "'auto' | 'always' | 'never'", description: 'When focus should open the tooltip. auto only attaches focus listeners to naturally focusable elements.', default: "'auto'"},
|
|
15
|
+
{name: 'touchTrigger', type: "'auto' | 'tap' | 'none'", description: 'What a tap does where there is no hover. auto opens on tap unless the trigger performs an action of its own; tap always opens (an info icon rendered as a button); none never opens on touch.', default: "'auto'"},
|
|
15
16
|
{name: 'isEnabled', type: 'boolean', description: 'Whether hover and focus triggers are enabled.', default: 'true'},
|
|
16
17
|
{name: 'isOpen', type: 'boolean', description: 'Controlled open state. true force-shows, false force-hides, undefined lets hover/focus manage visibility.'},
|
|
17
18
|
{name: 'isDefaultOpen', type: 'boolean', description: 'Whether the tooltip should be shown on mount.', default: 'false'},
|
|
@@ -49,6 +50,7 @@ export const docsDense = {
|
|
|
49
50
|
delay: 'show delay in ms.',
|
|
50
51
|
hideDelay: 'hide delay after mouse/focus leave in ms.',
|
|
51
52
|
focusTrigger: 'when focus opens tooltip; auto = naturally focusable elements only.',
|
|
53
|
+
touchTrigger: 'tap behavior with no hover; auto = tap unless trigger acts, tap = always, none = never.',
|
|
52
54
|
isEnabled: 'whether hover/focus triggers are enabled.',
|
|
53
55
|
isOpen: 'controlled open state: true force-show, false force-hide, undefined unmanaged.',
|
|
54
56
|
isDefaultOpen: 'show on mount.',
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file useTooltip.tsx
|
|
7
|
-
* @input Uses useLayer, React hooks
|
|
8
|
-
* @output Exports useTooltip hook for hover/focus triggered tooltips
|
|
7
|
+
* @input Uses useLayer, useTouchTrigger, React hooks
|
|
8
|
+
* @output Exports useTooltip hook for hover/focus/tap triggered tooltips
|
|
9
9
|
* @position Layer hook; builds on useLayer for tooltip behavior
|
|
10
10
|
*
|
|
11
11
|
* SYNC: When modified, update:
|
|
@@ -26,6 +26,10 @@ import {
|
|
|
26
26
|
type LayerAlignment,
|
|
27
27
|
type LayerPlacement,
|
|
28
28
|
} from '../Layer/useLayer';
|
|
29
|
+
import {
|
|
30
|
+
useTouchTrigger,
|
|
31
|
+
type LayerTouchTrigger,
|
|
32
|
+
} from '../Layer/useTouchTrigger';
|
|
29
33
|
import {layerAnimations} from '../Layer/layerAnimations.stylex';
|
|
30
34
|
import {themeProps} from '../utils/themeProps';
|
|
31
35
|
import {isImeKeyEvent} from '../utils/ime';
|
|
@@ -73,6 +77,11 @@ const styles = stylex.create({
|
|
|
73
77
|
*/
|
|
74
78
|
export type TooltipFocusTrigger = 'auto' | 'always' | 'never';
|
|
75
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Touch trigger behavior for tooltips
|
|
82
|
+
*/
|
|
83
|
+
export type TooltipTouchTrigger = LayerTouchTrigger;
|
|
84
|
+
|
|
76
85
|
export interface TooltipOptions {
|
|
77
86
|
/**
|
|
78
87
|
* Position placement relative to anchor
|
|
@@ -108,6 +117,20 @@ export interface TooltipOptions {
|
|
|
108
117
|
*/
|
|
109
118
|
focusTrigger?: TooltipFocusTrigger;
|
|
110
119
|
|
|
120
|
+
/**
|
|
121
|
+
* What a tap does on a touch pointer, where there is no hover:
|
|
122
|
+
* - `auto`: tap opens the tooltip, unless the trigger performs an action of
|
|
123
|
+
* its own (a button, a link, a form control) — that tap belongs to the
|
|
124
|
+
* control, and a hint about a control the user just operated is noise
|
|
125
|
+
* - `tap`: tap always opens the tooltip. This is what an info icon rendered
|
|
126
|
+
* as a button wants: it looks like an action to the DOM, but revealing the
|
|
127
|
+
* tooltip is the only thing it does
|
|
128
|
+
* - `none`: touch never opens the tooltip
|
|
129
|
+
*
|
|
130
|
+
* @default 'auto'
|
|
131
|
+
*/
|
|
132
|
+
touchTrigger?: TooltipTouchTrigger;
|
|
133
|
+
|
|
111
134
|
/**
|
|
112
135
|
* Whether the tooltip is enabled.
|
|
113
136
|
* When false, hover/focus triggers are disabled.
|
|
@@ -218,6 +241,7 @@ function isFocusable(element: HTMLElement): boolean {
|
|
|
218
241
|
* Builds on useLayer to add:
|
|
219
242
|
* - Hover triggers with configurable delay
|
|
220
243
|
* - Focus triggers with auto-detection for focusable elements
|
|
244
|
+
* - Tap triggers on touch, where there is no hover (see useTouchTrigger)
|
|
221
245
|
* - Inverted color palette for high contrast
|
|
222
246
|
*
|
|
223
247
|
* Unlike HoverCard, tooltips:
|
|
@@ -242,6 +266,7 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
|
|
|
242
266
|
delay = 200,
|
|
243
267
|
hideDelay = 0,
|
|
244
268
|
focusTrigger = 'auto',
|
|
269
|
+
touchTrigger = 'auto',
|
|
245
270
|
isEnabled = true,
|
|
246
271
|
isOpen,
|
|
247
272
|
isDefaultOpen = false,
|
|
@@ -273,6 +298,29 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
|
|
|
273
298
|
}
|
|
274
299
|
}, []);
|
|
275
300
|
|
|
301
|
+
// Touch resolves immediately: the hover delays exist to filter out a pointer
|
|
302
|
+
// passing across the trigger, and a tap is never that.
|
|
303
|
+
const showNow = useCallback(() => {
|
|
304
|
+
clearTimeouts();
|
|
305
|
+
layer.show();
|
|
306
|
+
}, [clearTimeouts, layer]);
|
|
307
|
+
|
|
308
|
+
const hideNow = useCallback(() => {
|
|
309
|
+
clearTimeouts();
|
|
310
|
+
layer.hide();
|
|
311
|
+
}, [clearTimeouts, layer]);
|
|
312
|
+
|
|
313
|
+
const touch = useTouchTrigger({
|
|
314
|
+
touchTrigger,
|
|
315
|
+
isEnabled,
|
|
316
|
+
isControlled: isOpen !== undefined,
|
|
317
|
+
isOpen: layer.isOpen,
|
|
318
|
+
layerId: layer.id,
|
|
319
|
+
triggerRef,
|
|
320
|
+
show: showNow,
|
|
321
|
+
hide: hideNow,
|
|
322
|
+
});
|
|
323
|
+
|
|
276
324
|
// Schedule show with delay (suppressed when isOpen is false)
|
|
277
325
|
const scheduleShow = useCallback(() => {
|
|
278
326
|
if (!isEnabled || isOpen === false) {
|
|
@@ -309,26 +357,38 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
|
|
|
309
357
|
|
|
310
358
|
// Event handlers
|
|
311
359
|
const handleMouseEnter = useCallback(() => {
|
|
312
|
-
//
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
window.matchMedia('(hover: none)').matches
|
|
317
|
-
) {
|
|
360
|
+
// A tap synthesizes mouseenter. On touch the tap path owns the decision,
|
|
361
|
+
// so hover must not also fire — including the tap that just opened the
|
|
362
|
+
// tooltip, which would otherwise be double-handled.
|
|
363
|
+
if (touch.isTouchPointerRef.current) {
|
|
318
364
|
return;
|
|
319
365
|
}
|
|
320
366
|
scheduleShow();
|
|
321
|
-
}, [scheduleShow]);
|
|
367
|
+
}, [touch, scheduleShow]);
|
|
322
368
|
|
|
323
369
|
const handleMouseLeave = useCallback(() => {
|
|
370
|
+
// On touch the synthesized mouseleave arrives with the next tap elsewhere,
|
|
371
|
+
// which the outside-tap dismissal already handles — and handling it here
|
|
372
|
+
// too would close the tooltip behind the tap-open bookkeeping's back.
|
|
373
|
+
if (touch.isTouchPointerRef.current) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
324
376
|
scheduleHide();
|
|
325
|
-
}, [scheduleHide]);
|
|
377
|
+
}, [touch, scheduleHide]);
|
|
326
378
|
|
|
327
379
|
const handleFocusIn = useCallback(
|
|
328
380
|
(e: Event) => {
|
|
329
381
|
if (!isEnabled) {
|
|
330
382
|
return;
|
|
331
383
|
}
|
|
384
|
+
// A tap focuses the trigger it activates, and `:focus-visible` does not
|
|
385
|
+
// filter that out on every element: a tapped `<input>` or contenteditable
|
|
386
|
+
// matches it. Those are exactly the action triggers `auto` just decided
|
|
387
|
+
// to keep shut, so without this the focus reopens what the tap
|
|
388
|
+
// suppressed, over the field the user is trying to type into.
|
|
389
|
+
if (touch.isTouchInteraction()) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
332
392
|
// Only show tooltip for keyboard focus (:focus-visible),
|
|
333
393
|
// not programmatic focus (e.g. dialog auto-focus, touch tap)
|
|
334
394
|
const target = e.target as HTMLElement;
|
|
@@ -338,7 +398,7 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
|
|
|
338
398
|
clearTimeouts();
|
|
339
399
|
layer.show();
|
|
340
400
|
},
|
|
341
|
-
[isEnabled, clearTimeouts, layer],
|
|
401
|
+
[isEnabled, touch, clearTimeouts, layer],
|
|
342
402
|
);
|
|
343
403
|
|
|
344
404
|
const handleFocusOut = useCallback(() => {
|
|
@@ -350,15 +410,24 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
|
|
|
350
410
|
// just-pressed control reads as stale. Fires on pointerdown so it feels
|
|
351
411
|
// immediate. Uncontrolled tooltips only — a controlled tooltip's visibility
|
|
352
412
|
// is owned by the consumer. `layer.hide()` self-guards when already closed.
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
413
|
+
// A touch press is a different gesture (it may be the only way to open the
|
|
414
|
+
// tooltip at all), so the touch path answers it first.
|
|
415
|
+
const handlePointerDown = useCallback(
|
|
416
|
+
(event: PointerEvent) => {
|
|
417
|
+
if (touch.handlePointerDown(event)) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
if (isOpen !== undefined) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
clearTimeouts();
|
|
424
|
+
layer.hide();
|
|
425
|
+
},
|
|
426
|
+
[touch, isOpen, clearTimeouts, layer],
|
|
427
|
+
);
|
|
360
428
|
|
|
361
429
|
// Interaction ref that handles event listeners only
|
|
430
|
+
const {handlePointerEnter, clearTapOpen} = touch;
|
|
362
431
|
const interactionRef: RefCallback<HTMLElement> = useCallback(
|
|
363
432
|
(el: HTMLElement | null) => {
|
|
364
433
|
// Cleanup previous element
|
|
@@ -367,6 +436,10 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
|
|
|
367
436
|
triggerRef.current.removeEventListener('mouseleave', handleMouseLeave);
|
|
368
437
|
triggerRef.current.removeEventListener('focusin', handleFocusIn);
|
|
369
438
|
triggerRef.current.removeEventListener('focusout', handleFocusOut);
|
|
439
|
+
triggerRef.current.removeEventListener(
|
|
440
|
+
'pointerenter',
|
|
441
|
+
handlePointerEnter,
|
|
442
|
+
);
|
|
370
443
|
triggerRef.current.removeEventListener(
|
|
371
444
|
'pointerdown',
|
|
372
445
|
handlePointerDown,
|
|
@@ -374,10 +447,13 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
|
|
|
374
447
|
}
|
|
375
448
|
|
|
376
449
|
if (el) {
|
|
377
|
-
// Attach hover listeners
|
|
450
|
+
// Attach hover listeners. `pointerenter` runs before the synthesized
|
|
451
|
+
// `mouseenter` a tap produces, which is what lets the hover path know
|
|
452
|
+
// it is looking at a finger.
|
|
453
|
+
el.addEventListener('pointerenter', handlePointerEnter);
|
|
378
454
|
el.addEventListener('mouseenter', handleMouseEnter);
|
|
379
455
|
el.addEventListener('mouseleave', handleMouseLeave);
|
|
380
|
-
// Press-to-dismiss
|
|
456
|
+
// Press-to-dismiss on a mouse; tap-to-open on a touch pointer.
|
|
381
457
|
el.addEventListener('pointerdown', handlePointerDown);
|
|
382
458
|
|
|
383
459
|
// Attach focus listeners based on focusTrigger option
|
|
@@ -399,6 +475,7 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
|
|
|
399
475
|
handleMouseLeave,
|
|
400
476
|
handleFocusIn,
|
|
401
477
|
handleFocusOut,
|
|
478
|
+
handlePointerEnter,
|
|
402
479
|
handlePointerDown,
|
|
403
480
|
],
|
|
404
481
|
);
|
|
@@ -461,13 +538,14 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
|
|
|
461
538
|
return;
|
|
462
539
|
}
|
|
463
540
|
clearTimeouts();
|
|
541
|
+
clearTapOpen();
|
|
464
542
|
layer.hide();
|
|
465
543
|
};
|
|
466
544
|
document.addEventListener('keydown', handleKeyDown);
|
|
467
545
|
return () => {
|
|
468
546
|
document.removeEventListener('keydown', handleKeyDown);
|
|
469
547
|
};
|
|
470
|
-
}, [isOpen, layer, clearTimeouts]);
|
|
548
|
+
}, [isOpen, layer, clearTimeouts, clearTapOpen]);
|
|
471
549
|
|
|
472
550
|
// Render function that wraps layer.render with tooltip styling
|
|
473
551
|
const renderTooltip = useCallback(
|