@astryxdesign/core 0.5.0 → 0.5.1-canary.f64186a
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 +222 -0
- package/dist/AlertDialog/AlertDialog.d.ts +1 -1
- package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
- package/dist/AlertDialog/AlertDialog.js +45 -20
- package/dist/AspectRatio/AspectRatio.d.ts +6 -6
- package/dist/Avatar/Avatar.d.ts +25 -1
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +43 -9
- package/dist/Avatar/index.d.ts +2 -2
- package/dist/Avatar/index.d.ts.map +1 -1
- package/dist/Avatar/index.js +1 -1
- package/dist/AvatarGroup/AvatarGroup.d.ts +9 -2
- package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroup.js +5 -2
- package/dist/AvatarGroup/AvatarGroupContext.d.ts +2 -1
- package/dist/AvatarGroup/AvatarGroupContext.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +11 -7
- package/dist/Badge/Badge.d.ts.map +1 -1
- package/dist/Badge/Badge.js +26 -2
- package/dist/Banner/Banner.d.ts +10 -1
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +11 -2
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +8 -7
- package/dist/Calendar/Calendar.d.ts +4 -2
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +15 -21
- package/dist/Calendar/hooks/useCalendarDays.js +4 -6
- package/dist/Calendar/hooks/useCalendarNavigation.js +4 -6
- package/dist/Calendar/styles.d.ts +5 -20
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +15 -17
- package/dist/Card/Card.d.ts +12 -12
- package/dist/Card/Card.d.ts.map +1 -1
- package/dist/Card/Card.js +17 -9
- package/dist/Card/index.d.ts +35 -1
- package/dist/Card/index.d.ts.map +1 -1
- package/dist/Card/index.js +21 -1
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +108 -7
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +7 -1
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +15 -4
- package/dist/CodeBlock/highlightRanges.js +1 -1
- package/dist/CodeBlock/highlightStyles.js +13 -13
- package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteItem.js +2 -7
- package/dist/ComplexSelector/ComplexSelector.d.ts +10 -2
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +14 -7
- package/dist/DateInput/DateInput.d.ts +43 -0
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +22 -5
- package/dist/DateInput/MonthScroller.d.ts.map +1 -1
- package/dist/DateInput/MonthScroller.js +5 -3
- package/dist/DateInput/MonthYearWheels.d.ts.map +1 -1
- package/dist/DateInput/MonthYearWheels.js +6 -4
- package/dist/DateInput/NativeDateField.d.ts +10 -0
- package/dist/DateInput/NativeDateField.d.ts.map +1 -0
- package/dist/DateInput/NativeDateField.js +494 -0
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +52 -25
- package/dist/DateInput/Wheel.d.ts.map +1 -1
- package/dist/DateInput/Wheel.js +1 -0
- package/dist/DateInput/index.d.ts +1 -1
- package/dist/DateInput/index.d.ts.map +1 -1
- package/dist/DateInput/nativeDateSegments.d.ts +22 -0
- package/dist/DateInput/nativeDateSegments.d.ts.map +1 -0
- package/dist/DateInput/nativeDateSegments.js +111 -0
- package/dist/DateRangeInput/DateRangeInput.d.ts +4 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +3 -5
- package/dist/DateTimeInput/DateTimeInput.d.ts +23 -24
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +35 -10
- package/dist/DateTimeInput/TouchDateTimeField.d.ts +6 -0
- package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -0
- package/dist/DateTimeInput/TouchDateTimeField.js +1021 -0
- package/dist/Dialog/Dialog.d.ts +16 -2
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +28 -7
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +4 -13
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +9 -1
- package/dist/Field/InputClearButton.d.ts +9 -3
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +14 -3
- package/dist/Heading/Heading.d.ts.map +1 -1
- package/dist/Heading/Heading.js +0 -1
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +104 -3
- package/dist/HoverCard/useHoverCard.d.ts +14 -2
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +7 -1
- package/dist/Icon/Icon.d.ts +4 -2
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/defaultIcons.d.ts +3 -2
- package/dist/Icon/defaultIcons.d.ts.map +1 -1
- package/dist/Icon/defaultIcons.js +7 -0
- package/dist/Icon/globalIconRegistry.d.ts +13 -0
- package/dist/Icon/globalIconRegistry.d.ts.map +1 -1
- package/dist/Icon/globalIconRegistry.js +34 -6
- package/dist/Icon/index.d.ts +1 -1
- package/dist/Icon/index.d.ts.map +1 -1
- package/dist/Icon/useIcon.d.ts +5 -2
- package/dist/Icon/useIcon.d.ts.map +1 -1
- package/dist/Icon/useIcon.js +3 -0
- package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
- package/dist/Indicator/CheckboxIndicator.js +6 -2
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +2 -2
- package/dist/Kbd/Kbd.d.ts.map +1 -1
- package/dist/Kbd/Kbd.js +2 -26
- package/dist/Layer/gestureCounter.d.ts +8 -0
- package/dist/Layer/gestureCounter.d.ts.map +1 -0
- package/dist/Layer/gestureCounter.js +53 -0
- package/dist/Layer/useLayer.d.ts +23 -13
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +146 -24
- package/dist/List/List.d.ts +1 -1
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +15 -4
- package/dist/Markdown/Markdown.d.ts +1 -1
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +20 -7
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +5 -3
- package/dist/MetadataList/MetadataListItem.d.ts +1 -1
- package/dist/MetadataList/MetadataListItem.d.ts.map +1 -1
- package/dist/MetadataList/MetadataListItem.js +4 -1
- package/dist/MultiSelector/MultiSelector.d.ts +18 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +58 -11
- package/dist/MultiSelector/hooks.d.ts +7 -1
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +3 -2
- package/dist/NavIcon/NavIcon.d.ts.map +1 -1
- package/dist/NavIcon/NavIcon.js +5 -1
- package/dist/NavItem/navItemStyles.stylex.d.ts +0 -8
- package/dist/NavItem/navItemStyles.stylex.d.ts.map +1 -1
- package/dist/NavItem/navItemStyles.stylex.js +0 -2
- package/dist/NavMenu/NavHeadingMenu.d.ts +1 -1
- package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenu.js +7 -4
- package/dist/NumberInput/NumberInput.d.ts +6 -1
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +95 -126
- package/dist/NumberInput/numberInputCommit.d.ts +34 -0
- package/dist/NumberInput/numberInputCommit.d.ts.map +1 -0
- package/dist/NumberInput/numberInputCommit.js +71 -0
- package/dist/NumberInput/numberParser.d.ts +64 -0
- package/dist/NumberInput/numberParser.d.ts.map +1 -0
- package/dist/NumberInput/numberParser.js +350 -0
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +2 -3
- package/dist/OverflowList/OverflowList.d.ts +41 -1
- package/dist/OverflowList/OverflowList.d.ts.map +1 -1
- package/dist/OverflowList/OverflowList.js +43 -2
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +8 -14
- package/dist/Popover/usePopover.d.ts +15 -41
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +26 -7
- package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchValueEditor.js +91 -18
- package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
- package/dist/PowerSearch/formatFilterValue.js +4 -2
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +18 -5
- package/dist/Resizable/useResizable.d.ts +19 -1
- package/dist/Resizable/useResizable.d.ts.map +1 -1
- package/dist/Resizable/useResizable.js +104 -38
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +9 -0
- package/dist/Selector/Selector.d.ts +18 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +92 -21
- package/dist/Selector/hooks.d.ts +7 -1
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +3 -2
- package/dist/SideNav/SideNav.d.ts +6 -1
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +57 -27
- package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +5 -4
- package/dist/SideNav/SideNavItem.d.ts +29 -4
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +75 -20
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +34 -2
- package/dist/Spinner/Spinner.d.ts +3 -1
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +199 -20
- package/dist/StatusDot/StatusDot.d.ts.map +1 -1
- package/dist/StatusDot/StatusDot.js +6 -1
- package/dist/Stepper/Step.d.ts.map +1 -1
- package/dist/Stepper/Step.js +7 -6
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +5 -1
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +6 -1
- package/dist/Table/Table.d.ts.map +1 -1
- package/dist/Table/Table.js +3 -6
- package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
- package/dist/Table/plugins/filtering/useTableFiltering.js +73 -4
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +26 -0
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +34 -3
- package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
- package/dist/Table/plugins/selection/useTableSelection.js +25 -1
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +3 -4
- package/dist/Text/Text.d.ts.map +1 -1
- package/dist/Text/Text.js +0 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +13 -8
- package/dist/Timestamp/Timestamp.d.ts +1 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +10 -18
- package/dist/Timestamp/formatInstant.d.ts.map +1 -1
- package/dist/Timestamp/formatInstant.js +10 -5
- package/dist/Toast/Toast.d.ts +17 -2
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +77 -11
- package/dist/Toast/ToastViewport.d.ts +1 -0
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +76 -21
- package/dist/Toast/index.d.ts +1 -1
- package/dist/Toast/index.d.ts.map +1 -1
- package/dist/Toast/types.d.ts +38 -0
- package/dist/Toast/types.d.ts.map +1 -1
- package/dist/Toast/useToastGesture.d.ts +26 -0
- package/dist/Toast/useToastGesture.d.ts.map +1 -0
- package/dist/Toast/useToastGesture.js +223 -0
- package/dist/Token/Token.d.ts +1 -1
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +23 -12
- package/dist/Token/TokenLink.d.ts +1 -1
- package/dist/Token/TokenLink.d.ts.map +1 -1
- package/dist/Token/TokenLink.js +5 -2
- package/dist/Tokenizer/Tokenizer.d.ts +12 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +31 -21
- package/dist/TopNav/TopNavHeading.js +2 -2
- package/dist/TopNav/TopNavItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavItem.js +3 -3
- package/dist/TopNav/TopNavMegaMenu.d.ts +1 -1
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +30 -9
- package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenuItem.js +3 -3
- package/dist/TopNav/TopNavMenu.d.ts +1 -1
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +21 -6
- package/dist/TreeList/TreeList.d.ts +1 -1
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +7 -2
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +2 -2
- package/dist/Typeahead/BaseTypeahead.d.ts +33 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +51 -8
- package/dist/Typeahead/Typeahead.d.ts +8 -1
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +2 -0
- package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
- package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
- package/dist/Typeahead/TypeaheadItem.js +7 -2
- package/dist/astryx.css +87 -22
- package/dist/hooks/useHotkeys.d.ts.map +1 -1
- package/dist/hooks/useHotkeys.js +3 -25
- package/dist/hooks/useOverflow.d.ts.map +1 -1
- package/dist/hooks/useOverflow.js +14 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/theme/Theme.d.ts.map +1 -1
- package/dist/theme/Theme.js +46 -10
- package/dist/theme/defineTheme.d.ts +9 -3
- 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 +24 -4
- package/dist/theme/generateThemeRules.d.ts +21 -0
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +26 -0
- package/dist/theme/syntax/tokens.d.ts +1 -1
- package/dist/theme/syntax/tokens.d.ts.map +1 -1
- package/dist/theme/syntax/tokens.js +5 -2
- package/dist/theme/useTheme.d.ts.map +1 -1
- package/dist/theme/useTheme.js +6 -7
- package/dist/utils/dateParser.d.ts +5 -8
- package/dist/utils/dateParser.d.ts.map +1 -1
- package/dist/utils/dateParser.js +10 -11
- package/dist/utils/focusOutline.stylex.d.ts +25 -0
- package/dist/utils/focusOutline.stylex.d.ts.map +1 -1
- package/dist/utils/focusOutline.stylex.js +15 -0
- package/dist/utils/interactionOverlay.stylex.d.ts +26 -0
- package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -0
- package/dist/utils/interactionOverlay.stylex.js +42 -0
- package/dist/utils/isApplePlatform.d.ts +18 -0
- package/dist/utils/isApplePlatform.d.ts.map +1 -0
- package/dist/utils/isApplePlatform.js +37 -0
- package/dist/utils/plainDate.d.ts +11 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +20 -4
- package/locales/af-ZA.json +7 -7
- package/locales/ar-SA.json +7 -7
- package/locales/ca-ES.json +6 -6
- package/locales/cs-CZ.json +7 -7
- package/locales/da-DK.json +7 -7
- package/locales/de-DE.json +7 -7
- package/locales/el-GR.json +7 -7
- package/locales/en.json +178 -6
- package/locales/es-ES.json +6 -6
- package/locales/fi-FI.json +7 -7
- package/locales/fr-FR.json +7 -7
- package/locales/he-IL.json +7 -7
- package/locales/hu-HU.json +7 -7
- package/locales/it-IT.json +7 -7
- package/locales/ja-JP.json +7 -7
- package/locales/ko-KR.json +7 -7
- package/locales/nl-NL.json +7 -7
- package/locales/no-NO.json +7 -7
- package/locales/pl-PL.json +7 -7
- package/locales/pseudo.json +130 -1
- package/locales/pt-BR.json +7 -7
- package/locales/pt-PT.json +7 -7
- package/locales/ro-RO.json +7 -7
- package/locales/ru-RU.json +7 -7
- package/locales/sr-SP.json +7 -7
- package/locales/sv-SE.json +7 -7
- package/locales/tr-TR.json +7 -7
- package/locales/uk-UA.json +7 -7
- package/locales/vi-VN.json +7 -7
- package/locales/zh-CN.json +7 -7
- package/locales/zh-TW.json +7 -7
- package/package.json +4 -5
- package/src/AlertDialog/AlertDialog.doc.mjs +114 -30
- package/src/AlertDialog/AlertDialog.test.tsx +211 -2
- package/src/AlertDialog/AlertDialog.tsx +62 -20
- package/src/AspectRatio/AspectRatio.doc.mjs +3 -3
- package/src/AspectRatio/AspectRatio.tsx +6 -6
- package/src/Avatar/Avatar.doc.mjs +12 -2
- package/src/Avatar/Avatar.test.tsx +80 -0
- package/src/Avatar/Avatar.tsx +64 -14
- package/src/Avatar/index.ts +2 -2
- package/src/AvatarGroup/AvatarGroup.doc.mjs +8 -2
- package/src/AvatarGroup/AvatarGroup.test.tsx +24 -0
- package/src/AvatarGroup/AvatarGroup.tsx +12 -4
- package/src/AvatarGroup/AvatarGroupContext.ts +5 -3
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +12 -12
- package/src/Badge/Badge.doc.mjs +3 -2
- package/src/Badge/Badge.test.tsx +32 -3
- package/src/Badge/Badge.tsx +42 -1
- package/src/Banner/Banner.doc.mjs +9 -0
- package/src/Banner/Banner.test.tsx +76 -11
- package/src/Banner/Banner.tsx +21 -2
- package/src/Button/Button.doc.mjs +2 -1
- package/src/Button/Button.test.tsx +19 -4
- package/src/Button/Button.tsx +9 -29
- package/src/ButtonGroup/ButtonGroup.doc.mjs +2 -2
- package/src/ButtonGroup/ButtonGroup.test.tsx +13 -0
- package/src/Calendar/Calendar.doc.mjs +3 -3
- package/src/Calendar/Calendar.test.tsx +112 -0
- package/src/Calendar/Calendar.tsx +18 -16
- package/src/Calendar/hooks/useCalendarDays.ts +4 -4
- package/src/Calendar/hooks/useCalendarNavigation.ts +4 -4
- package/src/Calendar/styles.ts +48 -42
- package/src/Card/Card.doc.mjs +10 -7
- package/src/Card/Card.test.tsx +113 -19
- package/src/Card/Card.tsx +67 -89
- package/src/Card/index.ts +36 -1
- package/src/Carousel/Carousel.doc.mjs +3 -0
- package/src/Carousel/Carousel.test.tsx +360 -0
- package/src/Carousel/Carousel.tsx +116 -15
- package/src/CheckboxInput/CheckboxInput.doc.mjs +2 -0
- package/src/CheckboxInput/CheckboxInput.test.tsx +15 -0
- package/src/CheckboxInput/CheckboxInput.tsx +5 -0
- package/src/CodeBlock/CodeBlock.doc.mjs +10 -4
- package/src/CodeBlock/CodeBlock.test.tsx +37 -0
- package/src/CodeBlock/CodeBlock.tsx +20 -4
- package/src/CodeBlock/highlightRanges.ts +1 -1
- package/src/CodeBlock/highlightStyles.ts +13 -13
- package/src/CommandPalette/CommandPaletteItem.tsx +2 -12
- package/src/ComplexSelector/ComplexSelector.doc.mjs +7 -0
- package/src/ComplexSelector/ComplexSelector.test.tsx +183 -0
- package/src/ComplexSelector/ComplexSelector.tsx +22 -12
- package/src/DateInput/DateInput.doc.mjs +16 -0
- package/src/DateInput/DateInput.test.tsx +9 -4
- package/src/DateInput/DateInput.tsx +54 -3
- package/src/DateInput/DateInputTouch.test.tsx +146 -32
- package/src/DateInput/MonthScroller.tsx +5 -1
- package/src/DateInput/MonthYearWheels.tsx +7 -4
- package/src/DateInput/NativeDateField.test.tsx +635 -0
- package/src/DateInput/NativeDateField.tsx +641 -0
- package/src/DateInput/TouchDateField.tsx +83 -33
- package/src/DateInput/Wheel.tsx +1 -0
- package/src/DateInput/index.ts +1 -0
- package/src/DateInput/nativeDateSegments.ts +127 -0
- package/src/DateRangeInput/DateRangeInput.doc.mjs +2 -2
- package/src/DateRangeInput/DateRangeInput.test.tsx +46 -0
- package/src/DateRangeInput/DateRangeInput.tsx +8 -13
- package/src/DateTimeInput/DateTimeInput.doc.mjs +38 -21
- package/src/DateTimeInput/DateTimeInput.test.tsx +76 -0
- package/src/DateTimeInput/DateTimeInput.tsx +54 -20
- package/src/DateTimeInput/DateTimeInputTouch.test.tsx +980 -0
- package/src/DateTimeInput/TouchDateTimeField.tsx +1437 -0
- package/src/Dialog/Dialog.test.tsx +185 -18
- package/src/Dialog/Dialog.tsx +35 -11
- package/src/DropdownMenu/DropdownMenu.test.tsx +44 -10
- package/src/DropdownMenu/DropdownMenu.tsx +4 -13
- package/src/Field/FieldLabel.test.tsx +29 -0
- package/src/Field/FieldLabel.tsx +7 -0
- package/src/Field/InputClearButton.test.tsx +15 -1
- package/src/Field/InputClearButton.tsx +28 -4
- package/src/Heading/Heading.tsx +0 -1
- package/src/HoverCard/HoverCard.doc.mjs +8 -2
- package/src/HoverCard/HoverCard.test.tsx +154 -4
- package/src/HoverCard/HoverCard.tsx +137 -3
- package/src/HoverCard/useHoverCard.tsx +23 -3
- package/src/Icon/Icon.test.tsx +55 -1
- package/src/Icon/Icon.tsx +5 -3
- package/src/Icon/defaultIcons.tsx +11 -2
- package/src/Icon/globalIconRegistry.test.tsx +16 -3
- package/src/Icon/globalIconRegistry.tsx +37 -6
- package/src/Icon/index.ts +1 -0
- package/src/Icon/useIcon.ts +9 -2
- package/src/Indicator/CheckboxIndicator.tsx +14 -8
- package/src/Indicator/Indicator.doc.mjs +2 -0
- package/src/Item/Item.tsx +2 -7
- package/src/Kbd/Kbd.test.tsx +0 -17
- package/src/Kbd/Kbd.tsx +2 -26
- package/src/Layer/gestureCounter.ts +57 -0
- package/src/Layer/useLayer.test.tsx +368 -16
- package/src/Layer/useLayer.tsx +208 -35
- package/src/Layout/__tests__/edgeCompensation.test.tsx +1 -1
- package/src/List/List.test.tsx +38 -0
- package/src/List/List.tsx +8 -1
- package/src/Markdown/Markdown.test.tsx +37 -0
- package/src/Markdown/Markdown.tsx +16 -5
- package/src/Markdown/parser.test.ts +33 -0
- package/src/Markdown/parser.ts +9 -3
- package/src/MetadataList/MetadataList.test.tsx +75 -2
- package/src/MetadataList/MetadataListItem.tsx +5 -2
- package/src/MultiSelector/MultiSelector.doc.mjs +22 -1
- package/src/MultiSelector/MultiSelector.test.tsx +205 -0
- package/src/MultiSelector/MultiSelector.tsx +103 -16
- package/src/MultiSelector/hooks.ts +9 -2
- package/src/NavIcon/NavIcon.doc.mjs +8 -2
- package/src/NavIcon/NavIcon.test.tsx +9 -0
- package/src/NavIcon/NavIcon.tsx +5 -1
- package/src/NavItem/navItemStyles.stylex.ts +0 -8
- package/src/NavMenu/NavHeadingMenu.test.tsx +30 -0
- package/src/NavMenu/NavHeadingMenu.tsx +7 -4
- package/src/NumberInput/NumberInput.doc.mjs +26 -7
- package/src/NumberInput/NumberInput.test.tsx +563 -8
- package/src/NumberInput/NumberInput.tsx +77 -131
- package/src/NumberInput/numberInputCommit.test.ts +72 -0
- package/src/NumberInput/numberInputCommit.ts +103 -0
- package/src/NumberInput/numberParser.docblock.test.ts +234 -0
- package/src/NumberInput/numberParser.test.ts +222 -0
- package/src/NumberInput/numberParser.ts +403 -0
- package/src/Outline/Outline.tsx +2 -4
- package/src/OverflowList/OverflowList.doc.mjs +102 -21
- package/src/OverflowList/OverflowList.test.tsx +550 -4
- package/src/OverflowList/OverflowList.tsx +100 -2
- package/src/Pagination/Pagination.test.tsx +3 -2
- package/src/Popover/Popover.doc.mjs +2 -2
- package/src/Popover/Popover.test.tsx +38 -0
- package/src/Popover/Popover.tsx +28 -66
- package/src/Popover/usePopover.tsx +44 -5
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +87 -0
- package/src/PowerSearch/PowerSearchValueEditor.test.tsx +64 -0
- package/src/PowerSearch/PowerSearchValueEditor.tsx +109 -10
- package/src/PowerSearch/formatFilterValue.test.ts +16 -1
- package/src/PowerSearch/formatFilterValue.ts +2 -0
- package/src/ProgressBar/ProgressBar.doc.mjs +42 -6
- package/src/ProgressBar/ProgressBar.test.tsx +24 -0
- package/src/ProgressBar/ProgressBar.tsx +28 -8
- package/src/Resizable/Resizable.doc.mjs +2 -2
- package/src/Resizable/useResizable.doc.mjs +21 -2
- package/src/Resizable/useResizable.test.ts +421 -0
- package/src/Resizable/useResizable.ts +133 -48
- package/src/SelectableCard/SelectableCard.doc.mjs +3 -0
- package/src/SelectableCard/SelectableCard.tsx +16 -0
- package/src/Selector/Selector.doc.mjs +14 -0
- package/src/Selector/Selector.source-build.test.mjs +65 -0
- package/src/Selector/Selector.test.tsx +301 -0
- package/src/Selector/Selector.tsx +145 -32
- package/src/Selector/hooks.ts +17 -2
- package/src/SideNav/SideNav.doc.mjs +2 -2
- package/src/SideNav/SideNav.test.tsx +1069 -6
- package/src/SideNav/SideNav.tsx +109 -38
- package/src/SideNav/SideNavHeading.tsx +5 -2
- package/src/SideNav/SideNavItem.doc.mjs +24 -3
- package/src/SideNav/SideNavItem.tsx +134 -44
- package/src/Slider/Slider.test.tsx +106 -1
- package/src/Slider/Slider.tsx +52 -1
- package/src/Spinner/Spinner.doc.mjs +17 -5
- package/src/Spinner/Spinner.test.tsx +164 -0
- package/src/Spinner/Spinner.tsx +252 -22
- package/src/StatusDot/StatusDot.doc.mjs +8 -2
- package/src/StatusDot/StatusDot.test.tsx +9 -0
- package/src/StatusDot/StatusDot.tsx +7 -1
- package/src/Stepper/Step.doc.mjs +1 -1
- package/src/Stepper/Step.tsx +7 -14
- package/src/Switch/Switch.doc.mjs +2 -0
- package/src/Switch/Switch.test.tsx +10 -0
- package/src/Switch/Switch.tsx +3 -0
- package/src/Table/BaseTable.tsx +6 -1
- package/src/Table/Table.doc.mjs +5 -3
- package/src/Table/Table.tsx +3 -8
- package/src/Table/TableBody.doc.mjs +2 -2
- package/src/Table/TableFooter.doc.mjs +1 -1
- package/src/Table/TableHeader.doc.mjs +1 -1
- package/src/Table/plugins/filtering/useTableFiltering.test.tsx +44 -6
- package/src/Table/plugins/filtering/useTableFiltering.tsx +100 -4
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +50 -4
- package/src/Table/plugins/selection/useTableSelection.test.tsx +62 -0
- package/src/Table/plugins/selection/useTableSelection.tsx +25 -2
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -2
- package/src/Table/useTableGroupedRows.doc.mjs +3 -3
- package/src/Table/useTablePagination.doc.mjs +1 -1
- package/src/Table/useTableSelection.doc.mjs +1 -1
- package/src/Text/Text.test.tsx +44 -0
- package/src/Text/Text.tsx +0 -1
- package/src/TextArea/TextArea.doc.mjs +12 -2
- package/src/TextArea/TextArea.test.tsx +11 -0
- package/src/TextArea/TextArea.tsx +34 -22
- package/src/Timestamp/Timestamp.test.tsx +89 -0
- package/src/Timestamp/Timestamp.tsx +8 -8
- package/src/Timestamp/formatInstant.ts +5 -0
- package/src/Toast/Toast.doc.mjs +213 -44
- package/src/Toast/Toast.tsx +118 -23
- package/src/Toast/ToastViewport.test.tsx +1434 -8
- package/src/Toast/ToastViewport.tsx +85 -14
- package/src/Toast/index.ts +2 -0
- package/src/Toast/types.ts +43 -5
- package/src/Toast/useToastGesture.ts +361 -0
- package/src/Token/Token.test.tsx +95 -0
- package/src/Token/Token.tsx +19 -17
- package/src/Token/TokenLink.tsx +12 -3
- package/src/Tokenizer/Tokenizer.doc.mjs +16 -3
- package/src/Tokenizer/Tokenizer.test.tsx +161 -0
- package/src/Tokenizer/Tokenizer.tsx +49 -24
- package/src/TopNav/TopNavHeading.tsx +2 -2
- package/src/TopNav/TopNavItem.tsx +3 -7
- package/src/TopNav/TopNavMegaMenu.test.tsx +104 -0
- package/src/TopNav/TopNavMegaMenu.tsx +47 -4
- package/src/TopNav/TopNavMegaMenuItem.tsx +10 -9
- package/src/TopNav/TopNavMenu.test.tsx +133 -1
- package/src/TopNav/TopNavMenu.tsx +38 -5
- package/src/TreeList/TreeList.test.tsx +49 -0
- package/src/TreeList/TreeList.tsx +7 -2
- package/src/TreeList/TreeListItem.tsx +2 -7
- package/src/Typeahead/BaseTypeahead.doc.mjs +13 -0
- package/src/Typeahead/BaseTypeahead.tsx +96 -6
- package/src/Typeahead/Typeahead.doc.mjs +6 -0
- package/src/Typeahead/Typeahead.test.tsx +154 -0
- package/src/Typeahead/Typeahead.tsx +9 -0
- package/src/Typeahead/TypeaheadItem.test.tsx +43 -0
- package/src/Typeahead/TypeaheadItem.tsx +8 -1
- package/src/hooks/useAnnounce.doc.mjs +96 -0
- package/src/hooks/useDevWarning.doc.mjs +96 -0
- package/src/hooks/useHotkeys.test.ts +0 -18
- package/src/hooks/useHotkeys.ts +3 -25
- package/src/hooks/useIndicatorFocusRing.doc.mjs +104 -0
- package/src/hooks/useInputStatusIcon.doc.mjs +142 -0
- package/src/hooks/useInteractiveRole.doc.mjs +119 -0
- package/src/hooks/useLongPress.doc.mjs +123 -0
- package/src/hooks/useOverflow.doc.mjs +58 -17
- package/src/hooks/useOverflow.ts +16 -4
- package/src/hooks/useTypeahead.doc.mjs +153 -0
- package/src/index.ts +2 -0
- package/src/raw-import.d.ts +14 -0
- package/src/theme/Theme.test.tsx +104 -2
- package/src/theme/Theme.tsx +49 -14
- package/src/theme/defineTheme.test.ts +23 -0
- package/src/theme/defineTheme.ts +12 -3
- package/src/theme/derivedVarRegistry.test.ts +87 -3
- package/src/theme/derivedVarRegistry.ts +23 -4
- package/src/theme/generateThemeRules.test.ts +99 -1
- package/src/theme/generateThemeRules.ts +28 -0
- package/src/theme/syntax/tokens.ts +5 -2
- package/src/theme/useTheme.test.tsx +10 -0
- package/src/theme/useTheme.ts +16 -10
- package/src/utils/dateParser.test.ts +34 -2
- package/src/utils/dateParser.ts +11 -14
- package/src/utils/focusOutline.stylex.ts +50 -0
- package/src/utils/interactionOverlay.stylex.ts +74 -0
- package/src/utils/isApplePlatform.test.ts +61 -0
- package/src/utils/isApplePlatform.ts +37 -0
- package/src/utils/plainDate.test.ts +46 -0
- package/src/utils/plainDate.ts +18 -3
package/src/Layer/useLayer.tsx
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @file useLayer.tsx
|
|
7
7
|
* @input Uses React hooks, Popover API, CSS anchor positioning, typography tokens
|
|
8
|
-
* @output Exports useLayer hook
|
|
8
|
+
* @output Exports the public useLayer hook plus internal trigger helpers.
|
|
9
9
|
* @position Core layer utility; used by useHoverCard, useTooltip, etc.
|
|
10
10
|
*
|
|
11
11
|
* SYNC: When modified, update:
|
|
@@ -18,6 +18,7 @@ import React, {
|
|
|
18
18
|
useCallback,
|
|
19
19
|
useEffect,
|
|
20
20
|
useId,
|
|
21
|
+
useMemo,
|
|
21
22
|
useRef,
|
|
22
23
|
useState,
|
|
23
24
|
type ReactNode,
|
|
@@ -27,6 +28,7 @@ import * as stylex from '@stylexjs/stylex';
|
|
|
27
28
|
import type {StyleXStyles} from '@stylexjs/stylex';
|
|
28
29
|
import {createPortal} from 'react-dom';
|
|
29
30
|
import {addAnchorName, removeAnchorName} from './anchorName';
|
|
31
|
+
import {currentGesture, currentGestureHasClicked} from './gestureCounter';
|
|
30
32
|
import {resolveLayerPortalTarget} from './layerHost';
|
|
31
33
|
import {typeScaleVars, typographyVars} from '../theme/tokens.stylex';
|
|
32
34
|
import {overlayPaddingReset} from '../Layout/padding.stylex';
|
|
@@ -72,6 +74,18 @@ const styles = stylex.create({
|
|
|
72
74
|
}),
|
|
73
75
|
});
|
|
74
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Props for a control that sits on the trigger but must not dismiss the layer.
|
|
79
|
+
*/
|
|
80
|
+
interface KeepLayerOpenProps {
|
|
81
|
+
onPointerDown: React.PointerEventHandler<HTMLElement>;
|
|
82
|
+
/**
|
|
83
|
+
* Capture phase, so spreading these props never collides with the control's
|
|
84
|
+
* own `onClick`.
|
|
85
|
+
*/
|
|
86
|
+
onClickCapture: React.MouseEventHandler<HTMLElement>;
|
|
87
|
+
}
|
|
88
|
+
|
|
75
89
|
/**
|
|
76
90
|
* Position placement relative to anchor.
|
|
77
91
|
* Logical: start/end resolve against the popover's own inherited direction
|
|
@@ -326,6 +340,13 @@ export interface FixedLayerReturn {
|
|
|
326
340
|
render: (children: ReactNode, props: FixedRenderProps) => ReactNode;
|
|
327
341
|
}
|
|
328
342
|
|
|
343
|
+
interface InternalLayerFields {
|
|
344
|
+
wasJustDismissed: () => boolean;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
type InternalContextLayerReturn = ContextLayerReturn & InternalLayerFields;
|
|
348
|
+
type InternalFixedLayerReturn = FixedLayerReturn & InternalLayerFields;
|
|
349
|
+
|
|
329
350
|
function toCssLength(value: number | string): string {
|
|
330
351
|
return typeof value === 'number' ? `${value}px` : value;
|
|
331
352
|
}
|
|
@@ -437,6 +458,51 @@ export function getPositionTryFallbacks(
|
|
|
437
458
|
return `${flips}, ${same} span-top, ${same} span-bottom, ${opposite} span-top, ${opposite} span-bottom`;
|
|
438
459
|
}
|
|
439
460
|
|
|
461
|
+
/**
|
|
462
|
+
* Internal props for controls that sit beside an open layer. This stays out of
|
|
463
|
+
* the public useLayer/usePopover return types until the input family adopts it.
|
|
464
|
+
*/
|
|
465
|
+
export function useKeepLayerOpenProps(
|
|
466
|
+
id: string,
|
|
467
|
+
isOpen: boolean,
|
|
468
|
+
): KeepLayerOpenProps {
|
|
469
|
+
const isOpenRef = useRef(isOpen);
|
|
470
|
+
isOpenRef.current = isOpen;
|
|
471
|
+
|
|
472
|
+
return useMemo(
|
|
473
|
+
() => ({
|
|
474
|
+
onPointerDown: (event: React.PointerEvent<HTMLElement>) => {
|
|
475
|
+
if (!isOpenRef.current) {
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
// The browser reads the invoker relationship at both ends of the press.
|
|
479
|
+
const control = event.currentTarget;
|
|
480
|
+
const doc = control.ownerDocument;
|
|
481
|
+
control.setAttribute('popovertarget', id);
|
|
482
|
+
const onPressEnd = () => {
|
|
483
|
+
doc.removeEventListener('pointerup', onPressEnd);
|
|
484
|
+
doc.removeEventListener('pointercancel', onPressEnd);
|
|
485
|
+
// Light dismiss runs as the pointerup default action after listeners.
|
|
486
|
+
doc.defaultView?.setTimeout(() => {
|
|
487
|
+
control.removeAttribute('popovertarget');
|
|
488
|
+
}, 0);
|
|
489
|
+
};
|
|
490
|
+
doc.addEventListener('pointerup', onPressEnd);
|
|
491
|
+
doc.addEventListener('pointercancel', onPressEnd);
|
|
492
|
+
},
|
|
493
|
+
onClickCapture: (event: React.MouseEvent<HTMLElement>) => {
|
|
494
|
+
const control = event.currentTarget;
|
|
495
|
+
if (control.hasAttribute('popovertarget')) {
|
|
496
|
+
// Being an invoker would otherwise toggle the layer shut.
|
|
497
|
+
event.preventDefault();
|
|
498
|
+
control.removeAttribute('popovertarget');
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
}),
|
|
502
|
+
[id],
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
|
|
440
506
|
/**
|
|
441
507
|
* Core layer hook that handles popover behavior and positioning.
|
|
442
508
|
*
|
|
@@ -451,11 +517,9 @@ export function getPositionTryFallbacks(
|
|
|
451
517
|
* {layer.render(<Content />, { placement: 'above', alignment: 'center' })}
|
|
452
518
|
* ```
|
|
453
519
|
*/
|
|
454
|
-
|
|
455
|
-
export function useLayer(options: FixedLayerOptions): FixedLayerReturn;
|
|
456
|
-
export function useLayer(
|
|
520
|
+
function useLayerImplementation(
|
|
457
521
|
options: ContextLayerOptions | FixedLayerOptions,
|
|
458
|
-
):
|
|
522
|
+
): InternalContextLayerReturn | InternalFixedLayerReturn {
|
|
459
523
|
const {mode, onShow, onHide, lightDismiss = false} = options;
|
|
460
524
|
const lazyMount = mode === 'context' ? (options.lazyMount ?? false) : false;
|
|
461
525
|
const id = useId();
|
|
@@ -485,6 +549,17 @@ export function useLayer(
|
|
|
485
549
|
// stale-closure reads of the previous isOpen value.
|
|
486
550
|
const isOpenRef = useRef(false);
|
|
487
551
|
|
|
552
|
+
// The gesture during which the browser last closed this layer on its own.
|
|
553
|
+
// Read through wasJustDismissed by triggers deciding whether a click is
|
|
554
|
+
// theirs to act on.
|
|
555
|
+
const dismissedByGestureRef = useRef<number | null>(null);
|
|
556
|
+
const forgetDismissalRef = useRef<(() => void) | null>(null);
|
|
557
|
+
|
|
558
|
+
const wasJustDismissed = useCallback(() => {
|
|
559
|
+
const gesture = currentGesture();
|
|
560
|
+
return dismissedByGestureRef.current === gesture;
|
|
561
|
+
}, []);
|
|
562
|
+
|
|
488
563
|
const showPopoverElement = useCallback((popover: HTMLElement) => {
|
|
489
564
|
// Finding infra-4: the Popover API is unsupported on Safari <17 and
|
|
490
565
|
// Firefox <125. On those browsers `showPopover` does not exist, so fall
|
|
@@ -548,6 +623,11 @@ export function useLayer(
|
|
|
548
623
|
}, [mode, lazyMount]);
|
|
549
624
|
|
|
550
625
|
const show = useCallback(() => {
|
|
626
|
+
// Every caller lands here, so this is where the dismissing press is
|
|
627
|
+
// absorbed: opening now would reopen the popup that same press closed.
|
|
628
|
+
if (wasJustDismissed()) {
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
551
631
|
// A context popover left over until React commits a previous hide must not
|
|
552
632
|
// be reopened. The synchronous mount ref is the source of truth.
|
|
553
633
|
const candidate = popoverRef.current;
|
|
@@ -569,12 +649,18 @@ export function useLayer(
|
|
|
569
649
|
requestContextMount,
|
|
570
650
|
showPopoverElement,
|
|
571
651
|
isCurrentContextPopover,
|
|
652
|
+
wasJustDismissed,
|
|
572
653
|
]);
|
|
573
654
|
|
|
574
655
|
const hide = useCallback(() => {
|
|
575
656
|
pendingShowRef.current = false;
|
|
576
657
|
if (isOpenRef.current) {
|
|
577
658
|
const el = popoverRef.current;
|
|
659
|
+
// Clear the open state BEFORE hiding: hidePopover fires `toggle`, and
|
|
660
|
+
// the reconciler below reads this ref to tell the browser's own
|
|
661
|
+
// dismissals from ours.
|
|
662
|
+
openedPopoverRef.current = null;
|
|
663
|
+
isOpenRef.current = false;
|
|
578
664
|
// See finding infra-4 note in `show`: mirror the same guard on hide so
|
|
579
665
|
// unsupported browsers degrade gracefully instead of throwing.
|
|
580
666
|
if (el) {
|
|
@@ -584,31 +670,74 @@ export function useLayer(
|
|
|
584
670
|
el.style.display = 'none';
|
|
585
671
|
}
|
|
586
672
|
}
|
|
587
|
-
openedPopoverRef.current = null;
|
|
588
|
-
isOpenRef.current = false;
|
|
589
673
|
setIsOpen(false);
|
|
590
674
|
onHide?.();
|
|
591
675
|
}
|
|
592
676
|
clearContextMount();
|
|
593
677
|
}, [onHide, clearContextMount]);
|
|
594
678
|
|
|
595
|
-
//
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
679
|
+
// Stable ref for the trigger element (context mode only).
|
|
680
|
+
const contextRef = useCallback(
|
|
681
|
+
(el: HTMLElement | null) => {
|
|
682
|
+
// Remove only THIS layer's anchor name from the previous element so
|
|
683
|
+
// other layers sharing the same trigger keep their anchors.
|
|
684
|
+
if (triggerRef.current && triggerRef.current !== el) {
|
|
685
|
+
removeAnchorName(triggerRef.current, anchorId);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if (el) {
|
|
689
|
+
addAnchorName(el, anchorId);
|
|
690
|
+
}
|
|
604
691
|
|
|
605
|
-
|
|
606
|
-
|
|
692
|
+
triggerRef.current = el;
|
|
693
|
+
},
|
|
694
|
+
[anchorId],
|
|
695
|
+
);
|
|
696
|
+
|
|
697
|
+
// Arm only when the dismissing gesture's click is still ahead of us. Some
|
|
698
|
+
// engines deliver click first; in that order there is nothing left to absorb.
|
|
699
|
+
const rememberDismissal = useCallback((doc: Document) => {
|
|
700
|
+
forgetDismissalRef.current?.();
|
|
701
|
+
if (currentGestureHasClicked()) {
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
dismissedByGestureRef.current = currentGesture();
|
|
705
|
+
const view = doc.defaultView;
|
|
706
|
+
let forgetTimer: number | null = null;
|
|
707
|
+
const forget = () => {
|
|
708
|
+
dismissedByGestureRef.current = null;
|
|
709
|
+
doc.removeEventListener('click', scheduleForget, true);
|
|
710
|
+
if (forgetTimer !== null) {
|
|
711
|
+
view?.clearTimeout(forgetTimer);
|
|
712
|
+
forgetTimer = null;
|
|
713
|
+
}
|
|
714
|
+
if (forgetDismissalRef.current === forget) {
|
|
715
|
+
forgetDismissalRef.current = null;
|
|
716
|
+
}
|
|
717
|
+
};
|
|
718
|
+
const scheduleForget = () => {
|
|
719
|
+
doc.removeEventListener('click', scheduleForget, true);
|
|
720
|
+
// The next task keeps the dismissal armed through React's click handler.
|
|
721
|
+
if (view) {
|
|
722
|
+
forgetTimer = view.setTimeout(() => {
|
|
723
|
+
forgetTimer = null;
|
|
724
|
+
if (forgetDismissalRef.current === forget) {
|
|
725
|
+
forget();
|
|
607
726
|
}
|
|
727
|
+
}, 0);
|
|
728
|
+
} else {
|
|
729
|
+
forget();
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
doc.addEventListener('click', scheduleForget, true);
|
|
733
|
+
forgetDismissalRef.current = forget;
|
|
734
|
+
}, []);
|
|
608
735
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
736
|
+
useEffect(() => {
|
|
737
|
+
// Install capture-phase gesture tracking before the first interaction.
|
|
738
|
+
currentGesture();
|
|
739
|
+
return () => forgetDismissalRef.current?.();
|
|
740
|
+
}, []);
|
|
612
741
|
|
|
613
742
|
// Reconcile browser-initiated closes (light-dismiss, popover="auto" stack
|
|
614
743
|
// eviction). These are the only cases where the DOM mutates without going
|
|
@@ -626,12 +755,15 @@ export function useLayer(
|
|
|
626
755
|
if (toggleEvent.newState === 'closed' && isOpenRef.current) {
|
|
627
756
|
openedPopoverRef.current = null;
|
|
628
757
|
isOpenRef.current = false;
|
|
758
|
+
rememberDismissal(
|
|
759
|
+
(e.currentTarget as HTMLElement | null)?.ownerDocument ?? document,
|
|
760
|
+
);
|
|
629
761
|
setIsOpen(false);
|
|
630
762
|
onHide?.();
|
|
631
763
|
clearContextMount();
|
|
632
764
|
}
|
|
633
765
|
},
|
|
634
|
-
[onHide, clearContextMount],
|
|
766
|
+
[onHide, clearContextMount, rememberDismissal],
|
|
635
767
|
);
|
|
636
768
|
|
|
637
769
|
// Ref callback for popover element — sets up the `toggle` listener.
|
|
@@ -865,24 +997,65 @@ export function useLayer(
|
|
|
865
997
|
[popoverRefCallback, id, lightDismiss],
|
|
866
998
|
);
|
|
867
999
|
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
ref:
|
|
1000
|
+
const contextResult = useMemo<InternalContextLayerReturn>(
|
|
1001
|
+
() => ({
|
|
1002
|
+
ref: contextRef,
|
|
871
1003
|
anchorId,
|
|
872
1004
|
show,
|
|
873
1005
|
hide,
|
|
874
1006
|
isOpen,
|
|
1007
|
+
wasJustDismissed,
|
|
875
1008
|
id,
|
|
876
1009
|
render: renderContext,
|
|
877
|
-
}
|
|
878
|
-
|
|
1010
|
+
}),
|
|
1011
|
+
[
|
|
1012
|
+
contextRef,
|
|
1013
|
+
anchorId,
|
|
1014
|
+
show,
|
|
1015
|
+
hide,
|
|
1016
|
+
isOpen,
|
|
1017
|
+
wasJustDismissed,
|
|
1018
|
+
id,
|
|
1019
|
+
renderContext,
|
|
1020
|
+
],
|
|
1021
|
+
);
|
|
1022
|
+
const fixedResult = useMemo<InternalFixedLayerReturn>(
|
|
1023
|
+
() => ({
|
|
1024
|
+
ref: undefined,
|
|
1025
|
+
show,
|
|
1026
|
+
hide,
|
|
1027
|
+
isOpen,
|
|
1028
|
+
wasJustDismissed,
|
|
1029
|
+
id,
|
|
1030
|
+
render: renderFixed,
|
|
1031
|
+
}),
|
|
1032
|
+
[show, hide, isOpen, wasJustDismissed, id, renderFixed],
|
|
1033
|
+
);
|
|
879
1034
|
|
|
880
|
-
return
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
1035
|
+
return mode === 'context' ? contextResult : fixedResult;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
export function useLayer(options: ContextLayerOptions): ContextLayerReturn;
|
|
1039
|
+
export function useLayer(options: FixedLayerOptions): FixedLayerReturn;
|
|
1040
|
+
export function useLayer(
|
|
1041
|
+
options: ContextLayerOptions | FixedLayerOptions,
|
|
1042
|
+
): ContextLayerReturn | FixedLayerReturn {
|
|
1043
|
+
const internalLayer = useLayerImplementation(options);
|
|
1044
|
+
return useMemo(() => {
|
|
1045
|
+
const {wasJustDismissed: _, ...layer} = internalLayer;
|
|
1046
|
+
return layer;
|
|
1047
|
+
}, [internalLayer]);
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/** @internal Shared with usePopover; not exported from the package barrel. */
|
|
1051
|
+
export function useLayerInternal(
|
|
1052
|
+
options: ContextLayerOptions,
|
|
1053
|
+
): InternalContextLayerReturn;
|
|
1054
|
+
export function useLayerInternal(
|
|
1055
|
+
options: FixedLayerOptions,
|
|
1056
|
+
): InternalFixedLayerReturn;
|
|
1057
|
+
export function useLayerInternal(
|
|
1058
|
+
options: ContextLayerOptions | FixedLayerOptions,
|
|
1059
|
+
): InternalContextLayerReturn | InternalFixedLayerReturn {
|
|
1060
|
+
return useLayerImplementation(options);
|
|
888
1061
|
}
|
|
@@ -112,7 +112,7 @@ describe('Edge Compensation', () => {
|
|
|
112
112
|
describe('Banner container compensation', () => {
|
|
113
113
|
it('renders dismissable banner with ghost dismiss button', () => {
|
|
114
114
|
render(<Banner status="info" title="Test" isDismissable />);
|
|
115
|
-
const dismissButton = screen.getByRole('button', {name: 'Dismiss'});
|
|
115
|
+
const dismissButton = screen.getByRole('button', {name: 'Dismiss Test'});
|
|
116
116
|
expect(dismissButton).toHaveAttribute(EDGE_COMP_ATTR);
|
|
117
117
|
});
|
|
118
118
|
});
|
package/src/List/List.test.tsx
CHANGED
|
@@ -681,6 +681,44 @@ describe('List', () => {
|
|
|
681
681
|
expect(screen.getByText('Simple text')).toBeInTheDocument();
|
|
682
682
|
});
|
|
683
683
|
|
|
684
|
+
it('forwards data and aria attributes onto the list element', () => {
|
|
685
|
+
// BaseProps keeps data-*/aria-*; the list element dropped them.
|
|
686
|
+
const {container} = render(
|
|
687
|
+
<List listStyle="decimal" data-delimiter=")" aria-label="Steps">
|
|
688
|
+
<ListItem label="First" />
|
|
689
|
+
</List>,
|
|
690
|
+
);
|
|
691
|
+
const list = container.querySelector('ol')!;
|
|
692
|
+
expect(list.getAttribute('data-delimiter')).toBe(')');
|
|
693
|
+
expect(list.getAttribute('aria-label')).toBe('Steps');
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
it('keeps an aria-labelledby pointing outside the component', () => {
|
|
697
|
+
// With no header of its own there is nothing to associate, so the
|
|
698
|
+
// consumer's label must survive.
|
|
699
|
+
const {container} = render(
|
|
700
|
+
<List aria-labelledby="external-heading">
|
|
701
|
+
<ListItem label="First" />
|
|
702
|
+
</List>,
|
|
703
|
+
);
|
|
704
|
+
expect(container.querySelector('ul')!.getAttribute('aria-labelledby')).toBe(
|
|
705
|
+
'external-heading',
|
|
706
|
+
);
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
it('keeps its own list role and header association', () => {
|
|
710
|
+
// The rest spread comes first so a consumer prop cannot drop the
|
|
711
|
+
// Safari/VoiceOver role workaround or the generated header association.
|
|
712
|
+
const {container} = render(
|
|
713
|
+
<List header="Steps" role="presentation" aria-labelledby="elsewhere">
|
|
714
|
+
<ListItem label="First" />
|
|
715
|
+
</List>,
|
|
716
|
+
);
|
|
717
|
+
const list = container.querySelector('ul')!;
|
|
718
|
+
expect(list.getAttribute('role')).toBe('list');
|
|
719
|
+
expect(list.getAttribute('aria-labelledby')).not.toBe('elsewhere');
|
|
720
|
+
});
|
|
721
|
+
|
|
684
722
|
it('accepts number as description (ReactNode)', () => {
|
|
685
723
|
render(
|
|
686
724
|
<List>
|
package/src/List/List.tsx
CHANGED
|
@@ -152,6 +152,7 @@ export function List({
|
|
|
152
152
|
style,
|
|
153
153
|
'data-testid': testId,
|
|
154
154
|
ref,
|
|
155
|
+
...props
|
|
155
156
|
}: ListProps) {
|
|
156
157
|
const headerId = useId();
|
|
157
158
|
const isOrdered = listStyle === 'decimal';
|
|
@@ -165,8 +166,14 @@ export function List({
|
|
|
165
166
|
const listElement = (
|
|
166
167
|
<Tag
|
|
167
168
|
ref={ref as React.Ref<HTMLUListElement & HTMLOListElement>}
|
|
169
|
+
// Consumer props first: everything the component sets for itself below
|
|
170
|
+
// is part of its contract and wins on conflict.
|
|
171
|
+
{...props}
|
|
168
172
|
data-testid={testId}
|
|
169
|
-
|
|
173
|
+
// Only when this component renders the header — writing `undefined`
|
|
174
|
+
// unconditionally would erase a label a consumer pointed at their own
|
|
175
|
+
// heading.
|
|
176
|
+
{...(header != null ? {'aria-labelledby': headerId} : null)}
|
|
170
177
|
{...(isOrdered && start != null && start !== 1 ? {start} : {})}
|
|
171
178
|
// The base list style always sets list-style-type: none (markers are
|
|
172
179
|
// custom-rendered by ListItem), and Safari/VoiceOver drops implicit
|
|
@@ -124,6 +124,43 @@ describe('Markdown', () => {
|
|
|
124
124
|
expect(second.className).toContain('astryx-markdown-paragraph');
|
|
125
125
|
});
|
|
126
126
|
|
|
127
|
+
describe('base props', () => {
|
|
128
|
+
// BaseProps documents that data-*, aria-* and role are kept; the root
|
|
129
|
+
// dropped everything but data-testid.
|
|
130
|
+
it('forwards data and aria attributes to the block root', () => {
|
|
131
|
+
const {container} = render(
|
|
132
|
+
<Markdown data-source="turn-7" aria-label="Answer">
|
|
133
|
+
Hello
|
|
134
|
+
</Markdown>,
|
|
135
|
+
);
|
|
136
|
+
const root = container.firstElementChild!;
|
|
137
|
+
expect(root.getAttribute('data-source')).toBe('turn-7');
|
|
138
|
+
expect(root.getAttribute('aria-label')).toBe('Answer');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('keeps its own role when a consumer passes one', () => {
|
|
142
|
+
// The rest spread comes first precisely so the component's own
|
|
143
|
+
// semantics survive a consumer prop.
|
|
144
|
+
const {container} = render(
|
|
145
|
+
<Markdown role="presentation">Hello</Markdown>,
|
|
146
|
+
);
|
|
147
|
+
expect(container.firstElementChild!.getAttribute('role')).toBe(
|
|
148
|
+
'document',
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('forwards them on the inline root too', () => {
|
|
153
|
+
const {container} = render(
|
|
154
|
+
<Markdown display="inline" data-source="turn-7">
|
|
155
|
+
Hello
|
|
156
|
+
</Markdown>,
|
|
157
|
+
);
|
|
158
|
+
expect(container.firstElementChild!.getAttribute('data-source')).toBe(
|
|
159
|
+
'turn-7',
|
|
160
|
+
);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
127
164
|
describe('block spacing theme targets', () => {
|
|
128
165
|
// Every block type renders a stable astryx-markdown-<block> class so a
|
|
129
166
|
// theme can tune the gap around it (marginBlockStart/marginBlockEnd) via
|
|
@@ -561,14 +561,19 @@ const headingStyles = {
|
|
|
561
561
|
const DANGEROUS_URL_PATTERN = /^(javascript|data|vbscript):/i;
|
|
562
562
|
|
|
563
563
|
function sanitizeUrl(url: string): string | null {
|
|
564
|
-
|
|
565
|
-
|
|
564
|
+
// Strip control characters before testing, the same normalization the
|
|
565
|
+
// parser's isSafeUrl applies — the anchored pattern must see the URL the
|
|
566
|
+
// way a browser will. Return the normalized value so the stripped
|
|
567
|
+
// characters don't ride along into an attribute or component override.
|
|
568
|
+
// eslint-disable-next-line no-control-regex -- control chars are the bypass
|
|
569
|
+
const normalized = url.replace(/[\x00-\x1f\x7f]/g, '').trim();
|
|
570
|
+
if (normalized.length === 0) {
|
|
566
571
|
return null;
|
|
567
572
|
}
|
|
568
|
-
if (DANGEROUS_URL_PATTERN.test(
|
|
573
|
+
if (DANGEROUS_URL_PATTERN.test(normalized)) {
|
|
569
574
|
return null;
|
|
570
575
|
}
|
|
571
|
-
return
|
|
576
|
+
return normalized;
|
|
572
577
|
}
|
|
573
578
|
|
|
574
579
|
// ---------------------------------------------------------------------------
|
|
@@ -1622,6 +1627,7 @@ export function Markdown({
|
|
|
1622
1627
|
className,
|
|
1623
1628
|
style,
|
|
1624
1629
|
'data-testid': testId,
|
|
1630
|
+
...props
|
|
1625
1631
|
}: MarkdownProps): React.ReactElement {
|
|
1626
1632
|
const t = useTranslator();
|
|
1627
1633
|
const LinkComponent = useLinkComponent();
|
|
@@ -1744,6 +1750,8 @@ export function Markdown({
|
|
|
1744
1750
|
const renderedInline = (
|
|
1745
1751
|
<span
|
|
1746
1752
|
ref={ref}
|
|
1753
|
+
// Consumer props first: what the component sets for itself wins.
|
|
1754
|
+
{...props}
|
|
1747
1755
|
data-testid={testId}
|
|
1748
1756
|
{...mergeProps(
|
|
1749
1757
|
themeProps('markdown', {density}),
|
|
@@ -1775,8 +1783,11 @@ export function Markdown({
|
|
|
1775
1783
|
|
|
1776
1784
|
const rendered = (
|
|
1777
1785
|
<div
|
|
1778
|
-
role="document"
|
|
1779
1786
|
ref={ref as React.Ref<HTMLDivElement>}
|
|
1787
|
+
// Consumer props first: what the component sets for itself — the
|
|
1788
|
+
// document role included — wins.
|
|
1789
|
+
{...props}
|
|
1790
|
+
role="document"
|
|
1780
1791
|
data-testid={testId}
|
|
1781
1792
|
{...mergeProps(
|
|
1782
1793
|
themeProps('markdown', {density}),
|
|
@@ -454,6 +454,14 @@ describe('parseMarkdown', () => {
|
|
|
454
454
|
}
|
|
455
455
|
});
|
|
456
456
|
|
|
457
|
+
it('rejects a standalone image with an unsafe scheme as literal text (XSS prevention)', () => {
|
|
458
|
+
// Same rule as inline images: the line falls through to the paragraph
|
|
459
|
+
// path and stays literal text instead of becoming an image node.
|
|
460
|
+
const result = parseMarkdown('');
|
|
461
|
+
expect(result[0].type).toBe('paragraph');
|
|
462
|
+
expect(JSON.stringify(result)).not.toContain('"type":"image"');
|
|
463
|
+
});
|
|
464
|
+
|
|
457
465
|
it('parses complex AI response', () => {
|
|
458
466
|
const input = [
|
|
459
467
|
'# Analysis',
|
|
@@ -1150,6 +1158,31 @@ describe('link reference definitions', () => {
|
|
|
1150
1158
|
expect(links).toEqual([{type: 'image', src: '/logo.png', text: 'logo'}]);
|
|
1151
1159
|
});
|
|
1152
1160
|
|
|
1161
|
+
it('rejects a reference image whose definition has an unsafe scheme (XSS prevention)', () => {
|
|
1162
|
+
const {links} = paragraphLinks('![logo][l]\n\n[l]: <javascript:alert(1)>');
|
|
1163
|
+
expect(links).toEqual([]);
|
|
1164
|
+
});
|
|
1165
|
+
|
|
1166
|
+
it('rejects a shortcut reference image with an unsafe definition (XSS prevention)', () => {
|
|
1167
|
+
const {links} = paragraphLinks('![logo]\n\n[logo]: <javascript:alert(1)>');
|
|
1168
|
+
expect(links).toEqual([]);
|
|
1169
|
+
});
|
|
1170
|
+
|
|
1171
|
+
it('rejects definitions that hide the scheme behind control chars (XSS prevention)', () => {
|
|
1172
|
+
// isSafeUrl strips control characters before testing; the angle-bracket
|
|
1173
|
+
// destination form is the only definition shape that can contain them.
|
|
1174
|
+
// Both consumers of a definition — reference images and reference links —
|
|
1175
|
+
// must apply it.
|
|
1176
|
+
const {links: imageLinks} = paragraphLinks(
|
|
1177
|
+
'![logo][l]\n\n[l]: <java\tscript:alert(1)>',
|
|
1178
|
+
);
|
|
1179
|
+
expect(imageLinks).toEqual([]);
|
|
1180
|
+
const {links: refLinks} = paragraphLinks(
|
|
1181
|
+
'[click][l]\n\n[l]: <java\tscript:alert(1)>',
|
|
1182
|
+
);
|
|
1183
|
+
expect(refLinks).toEqual([]);
|
|
1184
|
+
});
|
|
1185
|
+
|
|
1153
1186
|
it('does not treat a whitespace-only second label as collapsed', () => {
|
|
1154
1187
|
// `[foo][ ]` is a full reference to the empty (normalized) label and matches
|
|
1155
1188
|
// nothing; `[foo]` still resolves as a shortcut and `[ ]` stays literal.
|
package/src/Markdown/parser.ts
CHANGED
|
@@ -369,7 +369,7 @@ function matchReferenceImage(
|
|
|
369
369
|
const rawLabel = text.slice(altClose + 2, labelClose);
|
|
370
370
|
const label = rawLabel === '' ? alt : rawLabel;
|
|
371
371
|
const src = linkDefs.get(normalizeLinkLabel(label));
|
|
372
|
-
if (src != null) {
|
|
372
|
+
if (src != null && isSafeUrl(src)) {
|
|
373
373
|
return {node: {type: 'image', src, alt}, end: labelClose + 1};
|
|
374
374
|
}
|
|
375
375
|
// No match — fall back to a shortcut `![alt]`.
|
|
@@ -379,7 +379,7 @@ function matchReferenceImage(
|
|
|
379
379
|
return null;
|
|
380
380
|
}
|
|
381
381
|
const src = linkDefs.get(normalizeLinkLabel(alt));
|
|
382
|
-
if (src == null) {
|
|
382
|
+
if (src == null || !isSafeUrl(src)) {
|
|
383
383
|
return null;
|
|
384
384
|
}
|
|
385
385
|
return {node: {type: 'image', src, alt}, end: altClose + 1};
|
|
@@ -1416,8 +1416,14 @@ function parseMarkdownImpl(
|
|
|
1416
1416
|
}
|
|
1417
1417
|
|
|
1418
1418
|
// --- Standalone image ---
|
|
1419
|
+
// An unsafe src falls through to the paragraph path and renders as
|
|
1420
|
+
// literal text, the same rule the inline image path applies.
|
|
1419
1421
|
const imageMatch = line.match(/^!\[([^\]]*)\]\(([^)]+)\)/);
|
|
1420
|
-
if (
|
|
1422
|
+
if (
|
|
1423
|
+
imageMatch &&
|
|
1424
|
+
line.trim() === imageMatch[0] &&
|
|
1425
|
+
isSafeUrl(imageMatch[2])
|
|
1426
|
+
) {
|
|
1421
1427
|
pushBlock({type: 'image', alt: imageMatch[1], src: imageMatch[2]});
|
|
1422
1428
|
index++;
|
|
1423
1429
|
continue;
|