@lar-works/design-system 0.0.0-stage → 0.1.0
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/README.md +24 -2
- package/dist/actions/Button.d.ts +25 -0
- package/dist/actions/Button.js +55 -0
- package/dist/actions/Button.js.map +1 -0
- package/dist/actions/ButtonLink.d.ts +21 -0
- package/dist/actions/ButtonLink.js +40 -0
- package/dist/actions/ButtonLink.js.map +1 -0
- package/dist/actions/IconButton.d.ts +14 -0
- package/dist/actions/IconButton.js +29 -0
- package/dist/actions/IconButton.js.map +1 -0
- package/dist/actions/ThemeSwitch.d.ts +7 -0
- package/dist/actions/ThemeSwitch.js +42 -0
- package/dist/actions/ThemeSwitch.js.map +1 -0
- package/dist/actions/index.d.ts +5 -0
- package/dist/collections/CollectionSectionHeader.d.ts +5 -0
- package/dist/collections/CollectionSectionHeader.js +18 -0
- package/dist/collections/CollectionSectionHeader.js.map +1 -0
- package/dist/collections/CollectionState.d.ts +37 -0
- package/dist/collections/CollectionState.js +69 -0
- package/dist/collections/CollectionState.js.map +1 -0
- package/dist/collections/CollectionTokens.d.ts +16 -0
- package/dist/collections/CollectionTokens.js +19 -0
- package/dist/collections/CollectionTokens.js.map +1 -0
- package/dist/collections/CollectionViewport.js +36 -0
- package/dist/collections/CollectionViewport.js.map +1 -0
- package/dist/collections/DataRow.d.ts +23 -0
- package/dist/collections/DataRow.js +57 -0
- package/dist/collections/DataRow.js.map +1 -0
- package/dist/collections/ResultList.d.ts +29 -0
- package/dist/collections/ResultList.js +128 -0
- package/dist/collections/ResultList.js.map +1 -0
- package/dist/collections/ScrollRow.d.ts +23 -0
- package/dist/collections/ScrollRow.js +59 -0
- package/dist/collections/ScrollRow.js.map +1 -0
- package/dist/collections/VirtualGrid.d.ts +14 -0
- package/dist/collections/VirtualGrid.js +71 -0
- package/dist/collections/VirtualGrid.js.map +1 -0
- package/dist/collections/VirtualList.d.ts +34 -0
- package/dist/collections/VirtualList.js +128 -0
- package/dist/collections/VirtualList.js.map +1 -0
- package/dist/collections/index.d.ts +10 -0
- package/dist/collections/useCollectionMotion.d.ts +3 -0
- package/dist/collections/useCollectionMotion.js +34 -0
- package/dist/collections/useCollectionMotion.js.map +1 -0
- package/dist/collections/useScrollRow.d.ts +17 -0
- package/dist/collections/useScrollRow.js +63 -0
- package/dist/collections/useScrollRow.js.map +1 -0
- package/dist/display/ActivityCard.d.ts +17 -0
- package/dist/display/ActivityCard.js +58 -0
- package/dist/display/ActivityCard.js.map +1 -0
- package/dist/display/Artwork.d.ts +25 -0
- package/dist/display/Artwork.js +97 -0
- package/dist/display/Artwork.js.map +1 -0
- package/dist/display/Avatar.d.ts +5 -0
- package/dist/display/Avatar.js +13 -0
- package/dist/display/Avatar.js.map +1 -0
- package/dist/display/Badge.d.ts +10 -0
- package/dist/display/Badge.js +28 -0
- package/dist/display/Badge.js.map +1 -0
- package/dist/display/BadgeList.d.ts +11 -0
- package/dist/display/BadgeList.js +20 -0
- package/dist/display/BadgeList.js.map +1 -0
- package/dist/display/BrandMark.d.ts +21 -0
- package/dist/display/BrandMark.js +60 -0
- package/dist/display/BrandMark.js.map +1 -0
- package/dist/display/ChangeList.d.ts +16 -0
- package/dist/display/ChangeList.js +56 -0
- package/dist/display/ChangeList.js.map +1 -0
- package/dist/display/CheckList.d.ts +10 -0
- package/dist/display/CheckList.js +25 -0
- package/dist/display/CheckList.js.map +1 -0
- package/dist/display/CodeBlock.d.ts +6 -0
- package/dist/display/CodeBlock.js +12 -0
- package/dist/display/CodeBlock.js.map +1 -0
- package/dist/display/CopyButton.d.ts +9 -0
- package/dist/display/CopyButton.js +59 -0
- package/dist/display/CopyButton.js.map +1 -0
- package/dist/display/DataTable.d.ts +35 -0
- package/dist/display/DataTable.js +53 -0
- package/dist/display/DataTable.js.map +1 -0
- package/dist/display/DetailHero.d.ts +39 -0
- package/dist/display/DetailHero.js +146 -0
- package/dist/display/DetailHero.js.map +1 -0
- package/dist/display/DetailList.d.ts +15 -0
- package/dist/display/DetailList.js +53 -0
- package/dist/display/DetailList.js.map +1 -0
- package/dist/display/DeviceCard.d.ts +18 -0
- package/dist/display/DeviceCard.js +48 -0
- package/dist/display/DeviceCard.js.map +1 -0
- package/dist/display/Identity.d.ts +14 -0
- package/dist/display/Identity.js +54 -0
- package/dist/display/Identity.js.map +1 -0
- package/dist/display/ImageCard.d.ts +22 -0
- package/dist/display/ImageCard.js +63 -0
- package/dist/display/ImageCard.js.map +1 -0
- package/dist/display/ImagePicker.d.ts +30 -0
- package/dist/display/ImagePicker.js +108 -0
- package/dist/display/ImagePicker.js.map +1 -0
- package/dist/display/InfoBox.d.ts +15 -0
- package/dist/display/InfoBox.js +41 -0
- package/dist/display/InfoBox.js.map +1 -0
- package/dist/display/InsetPanel.d.ts +13 -0
- package/dist/display/InsetPanel.js +26 -0
- package/dist/display/InsetPanel.js.map +1 -0
- package/dist/display/ItemAction.d.ts +10 -0
- package/dist/display/ItemAction.js +35 -0
- package/dist/display/ItemAction.js.map +1 -0
- package/dist/display/Kbd.d.ts +6 -0
- package/dist/display/Kbd.js +12 -0
- package/dist/display/Kbd.js.map +1 -0
- package/dist/display/KindIcon.d.ts +8 -0
- package/dist/display/KindIcon.js +15 -0
- package/dist/display/KindIcon.js.map +1 -0
- package/dist/display/NoticeCard.d.ts +24 -0
- package/dist/display/NoticeCard.js +59 -0
- package/dist/display/NoticeCard.js.map +1 -0
- package/dist/display/PairingList.d.ts +19 -0
- package/dist/display/PairingList.js +53 -0
- package/dist/display/PairingList.js.map +1 -0
- package/dist/display/PathList.d.ts +9 -0
- package/dist/display/PathList.js +21 -0
- package/dist/display/PathList.js.map +1 -0
- package/dist/display/PeoplePreview.d.ts +16 -0
- package/dist/display/PeoplePreview.js +41 -0
- package/dist/display/PeoplePreview.js.map +1 -0
- package/dist/display/PropertySheet.d.ts +56 -0
- package/dist/display/PropertySheet.js +150 -0
- package/dist/display/PropertySheet.js.map +1 -0
- package/dist/display/QrCode.d.ts +6 -0
- package/dist/display/QrCode.js +47 -0
- package/dist/display/QrCode.js.map +1 -0
- package/dist/display/RadioChoice.d.ts +9 -0
- package/dist/display/RadioChoice.js +28 -0
- package/dist/display/RadioChoice.js.map +1 -0
- package/dist/display/RatingLink.d.ts +10 -0
- package/dist/display/RatingLink.js +80 -0
- package/dist/display/RatingLink.js.map +1 -0
- package/dist/display/ResourceCard.d.ts +20 -0
- package/dist/display/ResourceCard.js +200 -0
- package/dist/display/ResourceCard.js.map +1 -0
- package/dist/display/RowList.d.ts +28 -0
- package/dist/display/RowList.js +76 -0
- package/dist/display/RowList.js.map +1 -0
- package/dist/display/StackedMeter.d.ts +28 -0
- package/dist/display/StackedMeter.js +48 -0
- package/dist/display/StackedMeter.js.map +1 -0
- package/dist/display/StatTile.d.ts +13 -0
- package/dist/display/StatTile.js +35 -0
- package/dist/display/StatTile.js.map +1 -0
- package/dist/display/StepList.d.ts +5 -0
- package/dist/display/StepList.js +12 -0
- package/dist/display/StepList.js.map +1 -0
- package/dist/display/TextPreview.d.ts +14 -0
- package/dist/display/TextPreview.js +46 -0
- package/dist/display/TextPreview.js.map +1 -0
- package/dist/display/TimeSeriesChart.d.ts +19 -0
- package/dist/display/TimeSeriesChart.js +163 -0
- package/dist/display/TimeSeriesChart.js.map +1 -0
- package/dist/display/ToneTile.js +12 -0
- package/dist/display/ToneTile.js.map +1 -0
- package/dist/display/index.d.ts +38 -0
- package/dist/feedback/Alert.d.ts +15 -0
- package/dist/feedback/Alert.js +19 -0
- package/dist/feedback/Alert.js.map +1 -0
- package/dist/feedback/AsyncState.d.ts +16 -0
- package/dist/feedback/AsyncState.js +29 -0
- package/dist/feedback/AsyncState.js.map +1 -0
- package/dist/feedback/ErrorNotification.d.ts +8 -0
- package/dist/feedback/ErrorNotification.js +20 -0
- package/dist/feedback/ErrorNotification.js.map +1 -0
- package/dist/feedback/Notifications.d.ts +2 -0
- package/dist/feedback/Notifications.js +9 -0
- package/dist/feedback/Notifications.js.map +1 -0
- package/dist/feedback/ProgressStatusRow.d.ts +23 -0
- package/dist/feedback/ProgressStatusRow.js +74 -0
- package/dist/feedback/ProgressStatusRow.js.map +1 -0
- package/dist/feedback/SkeletonLoader.d.ts +19 -0
- package/dist/feedback/SkeletonLoader.js +59 -0
- package/dist/feedback/SkeletonLoader.js.map +1 -0
- package/dist/feedback/StatusIndicator.d.ts +9 -0
- package/dist/feedback/StatusIndicator.js +28 -0
- package/dist/feedback/StatusIndicator.js.map +1 -0
- package/dist/feedback/StatusPopoverContent.d.ts +13 -0
- package/dist/feedback/StatusPopoverContent.js +50 -0
- package/dist/feedback/StatusPopoverContent.js.map +1 -0
- package/dist/feedback/StatusRow.d.ts +16 -0
- package/dist/feedback/StatusRow.js +60 -0
- package/dist/feedback/StatusRow.js.map +1 -0
- package/dist/feedback/index.d.ts +11 -0
- package/dist/feedback/index.js +11 -0
- package/dist/forms/Checkbox.d.ts +10 -0
- package/dist/forms/Checkbox.js +48 -0
- package/dist/forms/Checkbox.js.map +1 -0
- package/dist/forms/Field.d.ts +5 -0
- package/dist/forms/Field.js +15 -0
- package/dist/forms/Field.js.map +1 -0
- package/dist/forms/FormControlStyles.js +14 -0
- package/dist/forms/FormControlStyles.js.map +1 -0
- package/dist/forms/FormSection.d.ts +48 -0
- package/dist/forms/FormSection.js +142 -0
- package/dist/forms/FormSection.js.map +1 -0
- package/dist/forms/InlineFields.d.ts +13 -0
- package/dist/forms/InlineFields.js +24 -0
- package/dist/forms/InlineFields.js.map +1 -0
- package/dist/forms/Input.d.ts +5 -0
- package/dist/forms/Input.js +18 -0
- package/dist/forms/Input.js.map +1 -0
- package/dist/forms/OptionSelect.d.ts +21 -0
- package/dist/forms/OptionSelect.js +28 -0
- package/dist/forms/OptionSelect.js.map +1 -0
- package/dist/forms/RadioGroup.d.ts +5 -0
- package/dist/forms/RadioGroup.js +35 -0
- package/dist/forms/RadioGroup.js.map +1 -0
- package/dist/forms/Select.d.ts +6 -0
- package/dist/forms/Select.js +36 -0
- package/dist/forms/Select.js.map +1 -0
- package/dist/forms/Switch.d.ts +4 -0
- package/dist/forms/Switch.js +16 -0
- package/dist/forms/Switch.js.map +1 -0
- package/dist/forms/TagInput.d.ts +19 -0
- package/dist/forms/TagInput.js +60 -0
- package/dist/forms/TagInput.js.map +1 -0
- package/dist/forms/Textarea.d.ts +4 -0
- package/dist/forms/Textarea.js +15 -0
- package/dist/forms/Textarea.js.map +1 -0
- package/dist/forms/index.d.ts +12 -0
- package/dist/foundations/DesignSystemProvider.d.ts +64 -0
- package/dist/foundations/DesignSystemProvider.js +66 -0
- package/dist/foundations/DesignSystemProvider.js.map +1 -0
- package/dist/foundations/KeyboardFocus.d.ts +9 -0
- package/dist/foundations/KeyboardFocus.js +10 -0
- package/dist/foundations/KeyboardFocus.js.map +1 -0
- package/dist/foundations/KeyboardShortcut.d.ts +5 -0
- package/dist/foundations/KeyboardShortcut.js +10 -0
- package/dist/foundations/KeyboardShortcut.js.map +1 -0
- package/dist/foundations/Theme.d.ts +14 -0
- package/dist/foundations/Theme.js +56 -0
- package/dist/foundations/Theme.js.map +1 -0
- package/dist/foundations/index.d.ts +5 -0
- package/dist/icons/BrandIcons.d.ts +3 -0
- package/dist/icons/BrandIcons.js +14 -0
- package/dist/icons/BrandIcons.js.map +1 -0
- package/dist/icons/index.d.ts +3 -0
- package/dist/icons/index.js +2 -0
- package/dist/icons.d.ts +4 -0
- package/dist/icons.js +2 -0
- package/dist/index.d.ts +133 -0
- package/dist/index.js +125 -0
- package/dist/layout/AppShell.d.ts +11 -0
- package/dist/layout/AppShell.js +46 -0
- package/dist/layout/AppShell.js.map +1 -0
- package/dist/layout/AuthLayout.d.ts +11 -0
- package/dist/layout/AuthLayout.js +48 -0
- package/dist/layout/AuthLayout.js.map +1 -0
- package/dist/layout/ContentContainer.d.ts +9 -0
- package/dist/layout/ContentContainer.js +15 -0
- package/dist/layout/ContentContainer.js.map +1 -0
- package/dist/layout/Flow.d.ts +26 -0
- package/dist/layout/Flow.js +65 -0
- package/dist/layout/Flow.js.map +1 -0
- package/dist/layout/PageLayout.d.ts +12 -0
- package/dist/layout/PageLayout.js +31 -0
- package/dist/layout/PageLayout.js.map +1 -0
- package/dist/layout/PageSection.d.ts +43 -0
- package/dist/layout/PageSection.js +63 -0
- package/dist/layout/PageSection.js.map +1 -0
- package/dist/layout/ScrollArea.d.ts +4 -0
- package/dist/layout/ScrollArea.js +11 -0
- package/dist/layout/ScrollArea.js.map +1 -0
- package/dist/layout/Section.d.ts +12 -0
- package/dist/layout/Section.js +36 -0
- package/dist/layout/Section.js.map +1 -0
- package/dist/layout/Site.d.ts +41 -0
- package/dist/layout/Site.js +157 -0
- package/dist/layout/Site.js.map +1 -0
- package/dist/layout/TitleBar.d.ts +28 -0
- package/dist/layout/TitleBar.js +83 -0
- package/dist/layout/TitleBar.js.map +1 -0
- package/dist/layout/WorkspaceActionsHeader.d.ts +8 -0
- package/dist/layout/WorkspaceActionsHeader.js +18 -0
- package/dist/layout/WorkspaceActionsHeader.js.map +1 -0
- package/dist/layout/index.d.ts +19 -0
- package/dist/layout/index.js +19 -0
- package/dist/layout/sidebar/SidebarNavigationItem.d.ts +10 -0
- package/dist/layout/sidebar/SidebarNavigationItem.js +36 -0
- package/dist/layout/sidebar/SidebarNavigationItem.js.map +1 -0
- package/dist/layout/sidebar/SidebarPane.d.ts +13 -0
- package/dist/layout/sidebar/SidebarPane.js +30 -0
- package/dist/layout/sidebar/SidebarPane.js.map +1 -0
- package/dist/layout/toolbar/CommandPaletteTrigger.d.ts +11 -0
- package/dist/layout/toolbar/CommandPaletteTrigger.js +46 -0
- package/dist/layout/toolbar/CommandPaletteTrigger.js.map +1 -0
- package/dist/layout/toolbar/ToolbarStatusGroup.d.ts +5 -0
- package/dist/layout/toolbar/ToolbarStatusGroup.js +14 -0
- package/dist/layout/toolbar/ToolbarStatusGroup.js.map +1 -0
- package/dist/layout/toolbar/ToolbarStatusItem.d.ts +9 -0
- package/dist/layout/toolbar/ToolbarStatusItem.js +18 -0
- package/dist/layout/toolbar/ToolbarStatusItem.js.map +1 -0
- package/dist/navigation/ArtworkTabs.d.ts +18 -0
- package/dist/navigation/ArtworkTabs.js +72 -0
- package/dist/navigation/ArtworkTabs.js.map +1 -0
- package/dist/navigation/Breadcrumbs.d.ts +13 -0
- package/dist/navigation/Breadcrumbs.js +32 -0
- package/dist/navigation/Breadcrumbs.js.map +1 -0
- package/dist/navigation/CollectionBrowseSelector.d.ts +22 -0
- package/dist/navigation/CollectionBrowseSelector.js +70 -0
- package/dist/navigation/CollectionBrowseSelector.js.map +1 -0
- package/dist/navigation/CollectionViewToggle.d.ts +12 -0
- package/dist/navigation/CollectionViewToggle.js +36 -0
- package/dist/navigation/CollectionViewToggle.js.map +1 -0
- package/dist/navigation/DrilldownBrowseSelector.d.ts +31 -0
- package/dist/navigation/DrilldownBrowseSelector.js +174 -0
- package/dist/navigation/DrilldownBrowseSelector.js.map +1 -0
- package/dist/navigation/FolderSelector.d.ts +24 -0
- package/dist/navigation/FolderSelector.js +142 -0
- package/dist/navigation/FolderSelector.js.map +1 -0
- package/dist/navigation/TabKeys.js +13 -0
- package/dist/navigation/TabKeys.js.map +1 -0
- package/dist/navigation/ViewTabs.d.ts +19 -0
- package/dist/navigation/ViewTabs.js +48 -0
- package/dist/navigation/ViewTabs.js.map +1 -0
- package/dist/navigation/index.d.ts +8 -0
- package/dist/overlays/ActionModal.d.ts +21 -0
- package/dist/overlays/ActionModal.js +48 -0
- package/dist/overlays/ActionModal.js.map +1 -0
- package/dist/overlays/CommandPalette.d.ts +43 -0
- package/dist/overlays/CommandPalette.js +163 -0
- package/dist/overlays/CommandPalette.js.map +1 -0
- package/dist/overlays/Drawer.d.ts +19 -0
- package/dist/overlays/Drawer.js +83 -0
- package/dist/overlays/Drawer.js.map +1 -0
- package/dist/overlays/DropdownMenu.d.ts +47 -0
- package/dist/overlays/DropdownMenu.js +58 -0
- package/dist/overlays/DropdownMenu.js.map +1 -0
- package/dist/overlays/ImageViewer.d.ts +21 -0
- package/dist/overlays/ImageViewer.js +82 -0
- package/dist/overlays/ImageViewer.js.map +1 -0
- package/dist/overlays/Modal.d.ts +36 -0
- package/dist/overlays/Modal.js +149 -0
- package/dist/overlays/Modal.js.map +1 -0
- package/dist/overlays/Popover.d.ts +19 -0
- package/dist/overlays/Popover.js +26 -0
- package/dist/overlays/Popover.js.map +1 -0
- package/dist/overlays/Tooltip.d.ts +12 -0
- package/dist/overlays/Tooltip.js +54 -0
- package/dist/overlays/Tooltip.js.map +1 -0
- package/dist/overlays/index.d.ts +9 -0
- package/dist/overlays/useModalAutoFocus.js +84 -0
- package/dist/overlays/useModalAutoFocus.js.map +1 -0
- package/dist/overlays/useScrollFade.js +43 -0
- package/dist/overlays/useScrollFade.js.map +1 -0
- package/dist/showcase/CallToAction.d.ts +11 -0
- package/dist/showcase/CallToAction.js +54 -0
- package/dist/showcase/CallToAction.js.map +1 -0
- package/dist/showcase/Cards.d.ts +34 -0
- package/dist/showcase/Cards.js +122 -0
- package/dist/showcase/Cards.js.map +1 -0
- package/dist/showcase/Devices.d.ts +72 -0
- package/dist/showcase/Devices.js +249 -0
- package/dist/showcase/Devices.js.map +1 -0
- package/dist/showcase/FeatureRow.d.ts +30 -0
- package/dist/showcase/FeatureRow.js +91 -0
- package/dist/showcase/FeatureRow.js.map +1 -0
- package/dist/showcase/Hero.d.ts +15 -0
- package/dist/showcase/Hero.js +73 -0
- package/dist/showcase/Hero.js.map +1 -0
- package/dist/showcase/PhotoSearchConcept.d.ts +14 -0
- package/dist/showcase/PhotoSearchConcept.js +43 -0
- package/dist/showcase/PhotoSearchConcept.js.map +1 -0
- package/dist/showcase/Platforms.d.ts +15 -0
- package/dist/showcase/Platforms.js +48 -0
- package/dist/showcase/Platforms.js.map +1 -0
- package/dist/showcase/ProductBand.d.ts +38 -0
- package/dist/showcase/ProductBand.js +120 -0
- package/dist/showcase/ProductBand.js.map +1 -0
- package/dist/showcase/Roadmap.d.ts +21 -0
- package/dist/showcase/Roadmap.js +111 -0
- package/dist/showcase/Roadmap.js.map +1 -0
- package/dist/showcase/RouteDiagram.d.ts +14 -0
- package/dist/showcase/RouteDiagram.js +57 -0
- package/dist/showcase/RouteDiagram.js.map +1 -0
- package/dist/showcase/ServerUnit.d.ts +50 -0
- package/dist/showcase/ServerUnit.js +175 -0
- package/dist/showcase/ServerUnit.js.map +1 -0
- package/dist/showcase/Stage.d.ts +46 -0
- package/dist/showcase/Stage.js +106 -0
- package/dist/showcase/Stage.js.map +1 -0
- package/dist/showcase/Status.d.ts +30 -0
- package/dist/showcase/Status.js +84 -0
- package/dist/showcase/Status.js.map +1 -0
- package/dist/showcase/StepFlow.d.ts +13 -0
- package/dist/showcase/StepFlow.js +47 -0
- package/dist/showcase/StepFlow.js.map +1 -0
- package/dist/showcase/index.d.ts +15 -0
- package/dist/testing.d.ts +5 -0
- package/dist/testing.js +43 -0
- package/dist/testing.js.map +1 -0
- package/dist/typography/Link.d.ts +21 -0
- package/dist/typography/Link.js +60 -0
- package/dist/typography/Link.js.map +1 -0
- package/dist/typography/Typography.d.ts +53 -0
- package/dist/typography/Typography.js +67 -0
- package/dist/typography/Typography.js.map +1 -0
- package/dist/typography/index.d.ts +4 -0
- package/dist/typography/index.js +4 -0
- package/package.json +80 -3
- package/src/actions/Button.tsx +68 -0
- package/src/actions/ButtonLink.tsx +75 -0
- package/src/actions/IconButton.tsx +55 -0
- package/src/actions/ThemeSwitch.tsx +46 -0
- package/src/actions/index.ts +4 -0
- package/src/collections/CollectionSectionHeader.tsx +13 -0
- package/src/collections/CollectionState.tsx +76 -0
- package/src/collections/CollectionTokens.ts +12 -0
- package/src/collections/CollectionViewport.ts +40 -0
- package/src/collections/DataRow.tsx +79 -0
- package/src/collections/ResultList.tsx +164 -0
- package/src/collections/ScrollRow.tsx +90 -0
- package/src/collections/VirtualGrid.tsx +92 -0
- package/src/collections/VirtualList.tsx +224 -0
- package/src/collections/index.ts +10 -0
- package/src/collections/useCollectionMotion.ts +42 -0
- package/src/collections/useScrollRow.ts +64 -0
- package/src/display/ActivityCard.tsx +76 -0
- package/src/display/Artwork.tsx +140 -0
- package/src/display/Avatar.tsx +7 -0
- package/src/display/Badge.tsx +33 -0
- package/src/display/BadgeList.tsx +25 -0
- package/src/display/BrandMark.tsx +72 -0
- package/src/display/ChangeList.tsx +41 -0
- package/src/display/CheckList.tsx +27 -0
- package/src/display/CodeBlock.tsx +12 -0
- package/src/display/CopyButton.tsx +77 -0
- package/src/display/DataTable.tsx +80 -0
- package/src/display/DetailHero.tsx +191 -0
- package/src/display/DetailList.tsx +74 -0
- package/src/display/DeviceCard.tsx +49 -0
- package/src/display/Identity.tsx +56 -0
- package/src/display/ImageCard.tsx +102 -0
- package/src/display/ImagePicker.tsx +149 -0
- package/src/display/InfoBox.tsx +48 -0
- package/src/display/InsetPanel.tsx +37 -0
- package/src/display/ItemAction.tsx +53 -0
- package/src/display/Kbd.tsx +6 -0
- package/src/display/KindIcon.tsx +15 -0
- package/src/display/NoticeCard.tsx +77 -0
- package/src/display/PairingList.tsx +55 -0
- package/src/display/PathList.tsx +16 -0
- package/src/display/PeoplePreview.tsx +66 -0
- package/src/display/PropertySheet.tsx +180 -0
- package/src/display/QrCode.tsx +47 -0
- package/src/display/RadioChoice.tsx +34 -0
- package/src/display/RatingLink.tsx +76 -0
- package/src/display/ResourceCard.tsx +201 -0
- package/src/display/RowList.tsx +110 -0
- package/src/display/StackedMeter.tsx +72 -0
- package/src/display/StatTile.tsx +39 -0
- package/src/display/StepList.tsx +10 -0
- package/src/display/TextPreview.tsx +66 -0
- package/src/display/TimeSeriesChart.tsx +191 -0
- package/src/display/ToneTile.ts +10 -0
- package/src/display/index.ts +37 -0
- package/src/feedback/Alert.tsx +35 -0
- package/src/feedback/AsyncState.tsx +56 -0
- package/src/feedback/ErrorNotification.ts +24 -0
- package/src/feedback/Notifications.tsx +5 -0
- package/src/feedback/ProgressStatusRow.tsx +104 -0
- package/src/feedback/SkeletonLoader.tsx +88 -0
- package/src/feedback/StatusIndicator.tsx +28 -0
- package/src/feedback/StatusPopoverContent.tsx +54 -0
- package/src/feedback/StatusRow.tsx +70 -0
- package/src/feedback/index.ts +15 -0
- package/src/forms/Checkbox.tsx +61 -0
- package/src/forms/Field.tsx +17 -0
- package/src/forms/FormControlStyles.ts +9 -0
- package/src/forms/FormSection.tsx +175 -0
- package/src/forms/InlineFields.tsx +22 -0
- package/src/forms/Input.tsx +22 -0
- package/src/forms/OptionSelect.tsx +49 -0
- package/src/forms/RadioGroup.tsx +48 -0
- package/src/forms/Select.tsx +46 -0
- package/src/forms/Switch.tsx +10 -0
- package/src/forms/TagInput.tsx +76 -0
- package/src/forms/Textarea.tsx +14 -0
- package/src/forms/index.ts +11 -0
- package/src/foundations/DesignSystemProvider.tsx +79 -0
- package/src/foundations/KeyboardFocus.ts +6 -0
- package/src/foundations/KeyboardShortcut.ts +12 -0
- package/src/foundations/Theme.ts +75 -0
- package/src/foundations/index.ts +10 -0
- package/src/foundations/theme.css +425 -0
- package/src/icons/BrandIcons.tsx +8 -0
- package/src/icons/index.ts +4 -0
- package/src/icons.ts +1 -0
- package/src/index.ts +13 -0
- package/src/layout/AppShell.tsx +63 -0
- package/src/layout/AuthLayout.tsx +40 -0
- package/src/layout/ContentContainer.tsx +16 -0
- package/src/layout/Flow.tsx +56 -0
- package/src/layout/PageLayout.tsx +35 -0
- package/src/layout/PageSection.tsx +103 -0
- package/src/layout/ScrollArea.tsx +7 -0
- package/src/layout/Section.tsx +36 -0
- package/src/layout/Site.tsx +205 -0
- package/src/layout/TitleBar.tsx +97 -0
- package/src/layout/WorkspaceActionsHeader.tsx +17 -0
- package/src/layout/index.ts +18 -0
- package/src/layout/sidebar/SidebarNavigationItem.tsx +45 -0
- package/src/layout/sidebar/SidebarPane.tsx +37 -0
- package/src/layout/toolbar/CommandPaletteTrigger.tsx +53 -0
- package/src/layout/toolbar/ToolbarStatusGroup.tsx +9 -0
- package/src/layout/toolbar/ToolbarStatusItem.tsx +18 -0
- package/src/navigation/ArtworkTabs.tsx +107 -0
- package/src/navigation/Breadcrumbs.tsx +31 -0
- package/src/navigation/CollectionBrowseSelector.tsx +90 -0
- package/src/navigation/CollectionViewToggle.tsx +52 -0
- package/src/navigation/DrilldownBrowseSelector.tsx +229 -0
- package/src/navigation/FolderSelector.tsx +172 -0
- package/src/navigation/TabKeys.ts +21 -0
- package/src/navigation/ViewTabs.tsx +85 -0
- package/src/navigation/index.ts +15 -0
- package/src/overlays/ActionModal.tsx +81 -0
- package/src/overlays/CommandPalette.tsx +199 -0
- package/src/overlays/Drawer.tsx +107 -0
- package/src/overlays/DropdownMenu.tsx +122 -0
- package/src/overlays/ImageViewer.tsx +96 -0
- package/src/overlays/Modal.tsx +234 -0
- package/src/overlays/Popover.tsx +40 -0
- package/src/overlays/Tooltip.tsx +56 -0
- package/src/overlays/index.ts +8 -0
- package/src/overlays/useModalAutoFocus.ts +119 -0
- package/src/overlays/useScrollFade.ts +49 -0
- package/src/showcase/CallToAction.tsx +46 -0
- package/src/showcase/Cards.tsx +133 -0
- package/src/showcase/Devices.tsx +259 -0
- package/src/showcase/FeatureRow.tsx +107 -0
- package/src/showcase/Hero.tsx +70 -0
- package/src/showcase/PhotoSearchConcept.tsx +50 -0
- package/src/showcase/Platforms.tsx +49 -0
- package/src/showcase/ProductBand.tsx +148 -0
- package/src/showcase/Roadmap.tsx +115 -0
- package/src/showcase/RouteDiagram.tsx +56 -0
- package/src/showcase/ServerUnit.tsx +191 -0
- package/src/showcase/Stage.tsx +160 -0
- package/src/showcase/Status.tsx +107 -0
- package/src/showcase/StepFlow.tsx +48 -0
- package/src/showcase/devices.css +441 -0
- package/src/showcase/index.ts +34 -0
- package/src/showcase/server-unit.css +258 -0
- package/src/showcase/stage.css +175 -0
- package/src/styles.css +5 -0
- package/src/testing.ts +34 -0
- package/src/typography/Link.tsx +105 -0
- package/src/typography/Typography.tsx +113 -0
- package/src/typography/index.ts +3 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface ImageViewerProps {
|
|
2
|
+
alt: string;
|
|
3
|
+
caption?: string;
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
open: boolean;
|
|
6
|
+
/** Pixel size to show beside the caption; omit when unknown rather than guessing. */
|
|
7
|
+
resolution?: {
|
|
8
|
+
height: number;
|
|
9
|
+
width: number;
|
|
10
|
+
};
|
|
11
|
+
/** Omit while the image is not ready yet (still loading, authenticating, and so on); shows the
|
|
12
|
+
* same loading indicator as a slow-loading image rather than a broken one. */
|
|
13
|
+
src?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Shows one image at its natural size over the blurred modal backdrop, scaled down only when it would not fit.
|
|
17
|
+
* Clicking anywhere except the image, the close button, or Escape dismisses it.
|
|
18
|
+
*/
|
|
19
|
+
export declare function ImageViewer({ alt, caption, onClose, open, resolution, src }: ImageViewerProps): import("react").JSX.Element;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=ImageViewer.d.ts.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { IconButton } from "../actions/IconButton.js";
|
|
2
|
+
import { useDesignSystemLabels } from "../foundations/DesignSystemProvider.js";
|
|
3
|
+
import { Text } from "../typography/Typography.js";
|
|
4
|
+
import { useModalAutoFocus } from "./useModalAutoFocus.js";
|
|
5
|
+
import { useId, useState } from "react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { XIcon } from "lucide-react";
|
|
8
|
+
import { Loading } from "@ninna-ui/feedback";
|
|
9
|
+
import { Modal } from "@ninna-ui/overlays";
|
|
10
|
+
// src/overlays/ImageViewer.tsx
|
|
11
|
+
/**
|
|
12
|
+
* Shows one image at its natural size over the blurred modal backdrop, scaled down only when it would not fit.
|
|
13
|
+
* Clicking anywhere except the image, the close button, or Escape dismisses it.
|
|
14
|
+
*/
|
|
15
|
+
function ImageViewer({ alt, caption, onClose, open, resolution, src }) {
|
|
16
|
+
const labels = useDesignSystemLabels();
|
|
17
|
+
const focusProps = useModalAutoFocus();
|
|
18
|
+
const captionId = useId();
|
|
19
|
+
const [loadedSource, setLoadedSource] = useState();
|
|
20
|
+
const loaded = Boolean(src) && loadedSource === src;
|
|
21
|
+
const size = resolution ? labels.imageSize(resolution.width, resolution.height) : void 0;
|
|
22
|
+
return /* @__PURE__ */ jsx(Modal, {
|
|
23
|
+
open,
|
|
24
|
+
onOpenChange: (next) => !next && onClose(),
|
|
25
|
+
children: /* @__PURE__ */ jsxs(Modal.Content, {
|
|
26
|
+
...focusProps,
|
|
27
|
+
title: caption ?? alt,
|
|
28
|
+
size: "full",
|
|
29
|
+
className: "top-0 left-0 flex h-dvh max-h-none w-screen translate-x-0 translate-y-0 items-center justify-center overflow-hidden rounded-none border-0 bg-transparent p-4 shadow-none sm:top-0 sm:left-0 sm:h-dvh sm:w-screen sm:translate-x-0 sm:translate-y-0 sm:p-8",
|
|
30
|
+
onClick: (event) => event.target === event.currentTarget && onClose(),
|
|
31
|
+
children: [
|
|
32
|
+
/* @__PURE__ */ jsx("div", {
|
|
33
|
+
className: "absolute top-5 right-5 z-10 [--color-header-icon:#ffffff] sm:top-6 sm:right-6",
|
|
34
|
+
children: /* @__PURE__ */ jsx(Modal.Close, {
|
|
35
|
+
asChild: true,
|
|
36
|
+
children: /* @__PURE__ */ jsx(IconButton, {
|
|
37
|
+
"aria-label": labels.close,
|
|
38
|
+
icon: /* @__PURE__ */ jsx(XIcon, {}),
|
|
39
|
+
variant: "header"
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
}),
|
|
43
|
+
loaded ? null : /* @__PURE__ */ jsx("span", {
|
|
44
|
+
className: "pointer-events-none absolute inset-0 flex items-center justify-center text-white/80",
|
|
45
|
+
children: /* @__PURE__ */ jsx(Loading, { size: "lg" })
|
|
46
|
+
}),
|
|
47
|
+
/* @__PURE__ */ jsxs("figure", {
|
|
48
|
+
"aria-labelledby": caption ? captionId : void 0,
|
|
49
|
+
className: "pointer-events-none m-0 flex max-w-full flex-col items-center gap-3",
|
|
50
|
+
children: [src ? /* @__PURE__ */ jsx("img", {
|
|
51
|
+
alt,
|
|
52
|
+
src,
|
|
53
|
+
decoding: "async",
|
|
54
|
+
ref: (image) => {
|
|
55
|
+
if (image?.complete && image.naturalWidth > 0) setLoadedSource(src);
|
|
56
|
+
},
|
|
57
|
+
onLoad: () => setLoadedSource(src),
|
|
58
|
+
onError: () => setLoadedSource(src),
|
|
59
|
+
className: `pointer-events-auto max-h-[calc(100dvh-7rem)] max-w-full rounded-lg object-contain shadow-2xl transition-opacity duration-200 motion-reduce:transition-none sm:max-h-[calc(100dvh-9rem)] ${loaded ? "opacity-100" : "opacity-0"}`
|
|
60
|
+
}) : null, caption || size ? /* @__PURE__ */ jsxs("figcaption", {
|
|
61
|
+
className: "flex max-w-prose flex-wrap items-baseline justify-center gap-x-3 gap-y-1 text-center",
|
|
62
|
+
children: [caption ? /* @__PURE__ */ jsx(Text, {
|
|
63
|
+
id: captionId,
|
|
64
|
+
as: "span",
|
|
65
|
+
className: "wrap-break-word text-white/90",
|
|
66
|
+
variant: "label",
|
|
67
|
+
children: caption
|
|
68
|
+
}) : null, size ? /* @__PURE__ */ jsx(Text, {
|
|
69
|
+
as: "span",
|
|
70
|
+
className: "text-white/60 tabular-nums",
|
|
71
|
+
variant: "caption",
|
|
72
|
+
children: size
|
|
73
|
+
}) : null]
|
|
74
|
+
}) : null]
|
|
75
|
+
})
|
|
76
|
+
]
|
|
77
|
+
})
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
export { ImageViewer };
|
|
81
|
+
|
|
82
|
+
//# sourceMappingURL=ImageViewer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageViewer.js","names":["NinnaModal"],"sources":["../../src/overlays/ImageViewer.tsx"],"sourcesContent":["import { Loading } from '@ninna-ui/feedback';\nimport { Modal as NinnaModal } from '@ninna-ui/overlays';\nimport { XIcon } from 'lucide-react';\nimport { useId, useState } from 'react';\n\nimport { IconButton } from '../actions/IconButton';\nimport { useDesignSystemLabels } from '../foundations/DesignSystemProvider';\nimport { Text } from '../typography/Typography';\nimport { useModalAutoFocus } from './useModalAutoFocus';\n\ninterface ImageViewerProps {\n alt: string;\n caption?: string;\n onClose: () => void;\n open: boolean;\n /** Pixel size to show beside the caption; omit when unknown rather than guessing. */\n resolution?: { height: number; width: number };\n /** Omit while the image is not ready yet (still loading, authenticating, and so on); shows the\n * same loading indicator as a slow-loading image rather than a broken one. */\n src?: string;\n}\n\n/**\n * Shows one image at its natural size over the blurred modal backdrop, scaled down only when it would not fit.\n * Clicking anywhere except the image, the close button, or Escape dismisses it.\n */\nexport function ImageViewer({ alt, caption, onClose, open, resolution, src }: ImageViewerProps) {\n const labels = useDesignSystemLabels();\n const focusProps = useModalAutoFocus();\n const captionId = useId();\n const [loadedSource, setLoadedSource] = useState<string>();\n const loaded = Boolean(src) && loadedSource === src;\n const size = resolution ? labels.imageSize(resolution.width, resolution.height) : undefined;\n\n return (\n <NinnaModal open={open} onOpenChange={(next) => !next && onClose()}>\n <NinnaModal.Content\n {...focusProps}\n title={caption ?? alt}\n size=\"full\"\n className=\"top-0 left-0 flex h-dvh max-h-none w-screen translate-x-0 translate-y-0 items-center justify-center overflow-hidden rounded-none border-0 bg-transparent p-4 shadow-none sm:top-0 sm:left-0 sm:h-dvh sm:w-screen sm:translate-x-0 sm:translate-y-0 sm:p-8\"\n onClick={(event) => event.target === event.currentTarget && onClose()}\n >\n {/* The standard header close button, lightened because it always sits on the dark backdrop. */}\n <div className=\"absolute top-5 right-5 z-10 [--color-header-icon:#ffffff] sm:top-6 sm:right-6\">\n <NinnaModal.Close asChild>\n <IconButton aria-label={labels.close} icon={<XIcon />} variant=\"header\" />\n </NinnaModal.Close>\n </div>\n {loaded ? null : (\n <span className=\"pointer-events-none absolute inset-0 flex items-center justify-center text-white/80\">\n <Loading size=\"lg\" />\n </span>\n )}\n {/* Only the image itself catches clicks; the space around it and the caption fall through to close. */}\n <figure\n aria-labelledby={caption ? captionId : undefined}\n className=\"pointer-events-none m-0 flex max-w-full flex-col items-center gap-3\"\n >\n {src ? (\n <img\n alt={alt}\n src={src}\n decoding=\"async\"\n ref={(image) => {\n if (image?.complete && image.naturalWidth > 0) setLoadedSource(src);\n }}\n onLoad={() => setLoadedSource(src)}\n onError={() => setLoadedSource(src)}\n className={`pointer-events-auto max-h-[calc(100dvh-7rem)] max-w-full rounded-lg object-contain shadow-2xl transition-opacity duration-200 motion-reduce:transition-none sm:max-h-[calc(100dvh-9rem)] ${loaded ? 'opacity-100' : 'opacity-0'}`}\n />\n ) : null}\n {caption || size ? (\n <figcaption className=\"flex max-w-prose flex-wrap items-baseline justify-center gap-x-3 gap-y-1 text-center\">\n {caption ? (\n <Text\n id={captionId}\n as=\"span\"\n className=\"wrap-break-word text-white/90\"\n variant=\"label\"\n >\n {caption}\n </Text>\n ) : null}\n {size ? (\n <Text as=\"span\" className=\"text-white/60 tabular-nums\" variant=\"caption\">\n {size}\n </Text>\n ) : null}\n </figcaption>\n ) : null}\n </figure>\n </NinnaModal.Content>\n </NinnaModal>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AA0BA,SAAgB,YAAY,EAAE,KAAK,SAAS,SAAS,MAAM,YAAY,OAAyB;CAC5F,MAAM,SAAS,sBAAsB;CACrC,MAAM,aAAa,kBAAkB;CACrC,MAAM,YAAY,MAAM;CACxB,MAAM,CAAC,cAAc,mBAAmB,SAAiB;CACzD,MAAM,SAAS,QAAQ,GAAG,KAAK,iBAAiB;CAChD,MAAM,OAAO,aAAa,OAAO,UAAU,WAAW,OAAO,WAAW,MAAM,IAAI,KAAA;CAElF,OACI,oBAACA,OAAD;EAAkB;EAAM,eAAe,SAAS,CAAC,QAAQ,QAAQ;EAC7D,UAAA,qBAACA,MAAW,SAAZ;GACI,GAAI;GACJ,OAAO,WAAW;GAClB,MAAK;GACL,WAAU;GACV,UAAU,UAAU,MAAM,WAAW,MAAM,iBAAiB,QAAQ;GALxE,UAAA;IAQI,oBAAC,OAAD;KAAK,WAAU;KACX,UAAA,oBAACA,MAAW,OAAZ;MAAkB,SAAA;MACd,UAAA,oBAAC,YAAD;OAAY,cAAY,OAAO;OAAO,MAAM,oBAAC,OAAD,CAAQ,CAAA;OAAG,SAAQ;MAAU,CAAA;KAC3D,CAAA;IACjB,CAAA;IACJ,SAAS,OACN,oBAAC,QAAD;KAAM,WAAU;KACZ,UAAA,oBAAC,SAAD,EAAS,MAAK,KAAM,CAAA;IAClB,CAAA;IAGV,qBAAC,UAAD;KACI,mBAAiB,UAAU,YAAY,KAAA;KACvC,WAAU;KAFd,UAAA,CAIK,MACG,oBAAC,OAAD;MACS;MACA;MACL,UAAS;MACT,MAAM,UAAU;OACZ,IAAI,OAAO,YAAY,MAAM,eAAe,GAAG,gBAAgB,GAAG;MACtE;MACA,cAAc,gBAAgB,GAAG;MACjC,eAAe,gBAAgB,GAAG;MAClC,WAAW,4LAA4L,SAAS,gBAAgB;KACnO,CAAA,IACD,MACH,WAAW,OACR,qBAAC,cAAD;MAAY,WAAU;MAAtB,UAAA,CACK,UACG,oBAAC,MAAD;OACI,IAAI;OACJ,IAAG;OACH,WAAU;OACV,SAAQ;OAEP,UAAA;MACC,CAAA,IACN,MACH,OACG,oBAAC,MAAD;OAAM,IAAG;OAAO,WAAU;OAA6B,SAAQ;OAC1D,UAAA;MACC,CAAA,IACN,IACI;KACZ,CAAA,IAAA,IACA;;GACQ;;CACZ,CAAA;AAEpB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ComponentProps, ReactNode } from "react";
|
|
2
|
+
import { ModalBodyProps, ModalContentProps, ModalFooterProps } from "@ninna-ui/overlays";
|
|
3
|
+
interface ModalContentPolicyProps extends Omit<ModalContentProps, 'className' | 'size' | 'title'> {
|
|
4
|
+
accessibleTitle?: string;
|
|
5
|
+
/** Whether opening focuses the first editable field; off while the caller focuses something else. */
|
|
6
|
+
focusFirstField?: boolean;
|
|
7
|
+
headerActions?: ReactNode;
|
|
8
|
+
sidebar?: ReactNode;
|
|
9
|
+
/** The dialog's size; a dialog with a sidebar is `paned` unless it says otherwise. */
|
|
10
|
+
presentation?: 'default' | 'paned' | 'workspace';
|
|
11
|
+
title: string;
|
|
12
|
+
}
|
|
13
|
+
declare function ModalForm(props: Omit<ComponentProps<'form'>, 'className'>): import("react").JSX.Element;
|
|
14
|
+
declare function ModalPane({ active, children }: {
|
|
15
|
+
active: boolean;
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
}): import("react").JSX.Element;
|
|
18
|
+
interface ModalRootPolicyProps {
|
|
19
|
+
children: ReactNode;
|
|
20
|
+
loading?: boolean;
|
|
21
|
+
onClose: () => void;
|
|
22
|
+
}
|
|
23
|
+
declare function ModalRoot({ children, loading, onClose }: ModalRootPolicyProps): import("react").JSX.Element;
|
|
24
|
+
declare const Modal$1: typeof ModalRoot & {
|
|
25
|
+
Body: import("react").ForwardRefExoticComponent<Omit<ModalBodyProps, "className"> & {
|
|
26
|
+
layout?: 'scroll' | 'fill';
|
|
27
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
28
|
+
Form: typeof ModalForm;
|
|
29
|
+
Pane: typeof ModalPane;
|
|
30
|
+
Content: import("react").ForwardRefExoticComponent<ModalContentPolicyProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
31
|
+
Footer: import("react").ForwardRefExoticComponent<Omit<ModalFooterProps, "className"> & {
|
|
32
|
+
leading?: ReactNode;
|
|
33
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
34
|
+
};
|
|
35
|
+
export { Modal$1 as Modal };
|
|
36
|
+
//# sourceMappingURL=Modal.d.ts.map
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { IconButton } from "../actions/IconButton.js";
|
|
2
|
+
import { useDesignSystemLabels } from "../foundations/DesignSystemProvider.js";
|
|
3
|
+
import { Heading, Text } from "../typography/Typography.js";
|
|
4
|
+
import { useModalAutoFocus } from "./useModalAutoFocus.js";
|
|
5
|
+
import { useScrollFade } from "./useScrollFade.js";
|
|
6
|
+
import { createContext, forwardRef, useCallback, useContext } from "react";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { XIcon } from "lucide-react";
|
|
9
|
+
import { Modal } from "@ninna-ui/overlays";
|
|
10
|
+
// src/overlays/Modal.tsx
|
|
11
|
+
const ModalLoadingContext = createContext(false);
|
|
12
|
+
const ModalContent = forwardRef(({ accessibleTitle, children, closeOnEscape, closeOnOverlayClick, description, focusFirstField, headerActions, onPointerDownOutside, sidebar, presentation = sidebar ? "paned" : "default", title, ...props }, ref) => {
|
|
13
|
+
const loading = useContext(ModalLoadingContext);
|
|
14
|
+
const focusProps = useModalAutoFocus(focusFirstField);
|
|
15
|
+
return /* @__PURE__ */ jsxs(Modal.Content, {
|
|
16
|
+
ref,
|
|
17
|
+
...props,
|
|
18
|
+
...focusProps,
|
|
19
|
+
title: accessibleTitle ?? title,
|
|
20
|
+
description,
|
|
21
|
+
closeOnEscape: loading ? false : closeOnEscape,
|
|
22
|
+
closeOnOverlayClick: loading ? false : closeOnOverlayClick,
|
|
23
|
+
onPointerDownOutside: (event) => {
|
|
24
|
+
if (event.target instanceof Element && event.target.closest("[data-slot=\"toaster\"]")) event.preventDefault();
|
|
25
|
+
onPointerDownOutside?.(event);
|
|
26
|
+
},
|
|
27
|
+
size: presentation === "workspace" ? "full" : void 0,
|
|
28
|
+
className: `flex max-h-[calc(100dvh-1rem)] w-[calc(100vw-1rem)] flex-col overflow-hidden sm:max-h-[calc(100dvh-2rem)] sm:w-[calc(100vw-2rem)] ${sidebar ? "md:grid md:grid-cols-[14rem_minmax(0,1fr)] md:grid-rows-[auto_minmax(0,1fr)]" : ""} ${presentation === "workspace" ? "h-[calc(100dvh-1rem)] max-w-6xl sm:h-[calc(100dvh-2rem)] sm:max-w-6xl" : presentation === "paned" ? "h-[calc(100dvh-1rem)] max-w-4xl sm:h-[min(44rem,calc(100dvh-2rem))] sm:max-w-4xl" : "max-w-160 sm:max-w-160"}`,
|
|
29
|
+
children: [
|
|
30
|
+
/* @__PURE__ */ jsx("header", {
|
|
31
|
+
"data-slot": "modal-header",
|
|
32
|
+
className: `@container min-w-0 shrink-0 px-5 pt-5 sm:px-6 sm:pt-6 ${description ? sidebar ? "pb-4 md:pb-0" : "" : "pb-4"} ${sidebar ? "md:col-start-2 md:row-start-1" : ""}`,
|
|
33
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
34
|
+
className: "flex min-w-0 flex-wrap items-center justify-between gap-x-4 gap-y-3",
|
|
35
|
+
children: [
|
|
36
|
+
/* @__PURE__ */ jsx(Heading, {
|
|
37
|
+
as: "h2",
|
|
38
|
+
className: "min-w-0 flex-1 wrap-break-word",
|
|
39
|
+
variant: "section",
|
|
40
|
+
children: title
|
|
41
|
+
}),
|
|
42
|
+
headerActions ? /* @__PURE__ */ jsx("div", {
|
|
43
|
+
className: "order-3 flex basis-full items-center justify-end gap-2 @min-[32rem]:order-0 @min-[32rem]:ml-auto @min-[32rem]:basis-auto",
|
|
44
|
+
children: headerActions
|
|
45
|
+
}) : null,
|
|
46
|
+
/* @__PURE__ */ jsx("div", {
|
|
47
|
+
className: "shrink-0",
|
|
48
|
+
children: /* @__PURE__ */ jsx(ModalClose, {})
|
|
49
|
+
})
|
|
50
|
+
]
|
|
51
|
+
})
|
|
52
|
+
}),
|
|
53
|
+
sidebar ? /* @__PURE__ */ jsx("div", {
|
|
54
|
+
className: "min-h-0 min-w-0 shrink-0 md:col-start-1 md:row-span-2 md:row-start-1",
|
|
55
|
+
children: sidebar
|
|
56
|
+
}) : null,
|
|
57
|
+
/* @__PURE__ */ jsxs("div", {
|
|
58
|
+
className: `flex min-h-0 min-w-0 flex-1 flex-col ${sidebar ? "md:col-start-2 md:row-start-2" : ""}`,
|
|
59
|
+
children: [description ? /* @__PURE__ */ jsx(Text, {
|
|
60
|
+
className: `shrink-0 px-5 pb-4 sm:px-6 ${sidebar ? "pt-4 md:pt-2" : "pt-2"}`,
|
|
61
|
+
tone: "muted",
|
|
62
|
+
children: description
|
|
63
|
+
}) : null, children]
|
|
64
|
+
})
|
|
65
|
+
]
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
ModalContent.displayName = "Modal.Content";
|
|
69
|
+
const ModalBody = forwardRef(({ layout = "scroll", children, ...props }, ref) => {
|
|
70
|
+
const { setViewport, setContent, className } = useScrollFade();
|
|
71
|
+
const bodyRef = useCallback((element) => {
|
|
72
|
+
setViewport(element);
|
|
73
|
+
const cleanup = typeof ref === "function" ? ref(element) : void 0;
|
|
74
|
+
if (ref && typeof ref !== "function") ref.current = element;
|
|
75
|
+
return () => {
|
|
76
|
+
setViewport(null);
|
|
77
|
+
if (typeof cleanup === "function") cleanup();
|
|
78
|
+
else if (typeof ref === "function") ref(null);
|
|
79
|
+
else if (ref) ref.current = null;
|
|
80
|
+
};
|
|
81
|
+
}, [ref, setViewport]);
|
|
82
|
+
return /* @__PURE__ */ jsx(Modal.Body, {
|
|
83
|
+
ref: bodyRef,
|
|
84
|
+
...props,
|
|
85
|
+
className: `min-h-0 flex-1 overflow-y-auto overscroll-contain px-5 pt-2 pb-6 sm:px-6 ${layout === "fill" ? "flex flex-col" : ""} ${className}`,
|
|
86
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
87
|
+
ref: setContent,
|
|
88
|
+
className: layout === "fill" ? "flex min-h-0 flex-1 flex-col gap-3" : "flow-root",
|
|
89
|
+
children
|
|
90
|
+
})
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
ModalBody.displayName = "Modal.Body";
|
|
94
|
+
function ModalForm(props) {
|
|
95
|
+
return /* @__PURE__ */ jsx("form", {
|
|
96
|
+
...props,
|
|
97
|
+
className: "flex min-h-0 flex-1 flex-col"
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function ModalPane({ active, children }) {
|
|
101
|
+
return /* @__PURE__ */ jsx("div", {
|
|
102
|
+
hidden: !active,
|
|
103
|
+
className: active ? "flex min-h-0 flex-1 flex-col" : "hidden",
|
|
104
|
+
children
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
const ModalFooter = forwardRef(({ leading, children, ...props }, ref) => /* @__PURE__ */ jsxs(Modal.Footer, {
|
|
108
|
+
ref,
|
|
109
|
+
...props,
|
|
110
|
+
className: "border-base-300 bg-base-50/60 shrink-0 border-t px-5 py-4 sm:px-6 sm:pb-4",
|
|
111
|
+
children: [leading ? /* @__PURE__ */ jsx("div", {
|
|
112
|
+
className: "mr-auto min-w-0 basis-full pb-2 sm:basis-auto sm:pb-0",
|
|
113
|
+
children: leading
|
|
114
|
+
}) : null, children]
|
|
115
|
+
}));
|
|
116
|
+
ModalFooter.displayName = "Modal.Footer";
|
|
117
|
+
function ModalClose() {
|
|
118
|
+
const labels = useDesignSystemLabels();
|
|
119
|
+
const loading = useContext(ModalLoadingContext);
|
|
120
|
+
return /* @__PURE__ */ jsx(Modal.Close, {
|
|
121
|
+
asChild: true,
|
|
122
|
+
children: /* @__PURE__ */ jsx(IconButton, {
|
|
123
|
+
"aria-label": labels.close,
|
|
124
|
+
disabled: loading,
|
|
125
|
+
icon: /* @__PURE__ */ jsx(XIcon, {}),
|
|
126
|
+
variant: "header"
|
|
127
|
+
})
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function ModalRoot({ children, loading = false, onClose }) {
|
|
131
|
+
return /* @__PURE__ */ jsx(ModalLoadingContext.Provider, {
|
|
132
|
+
value: loading,
|
|
133
|
+
children: /* @__PURE__ */ jsx(Modal, {
|
|
134
|
+
open: true,
|
|
135
|
+
onOpenChange: (open) => !open && !loading && onClose(),
|
|
136
|
+
children
|
|
137
|
+
})
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const Modal$1 = Object.assign(ModalRoot, {
|
|
141
|
+
Body: ModalBody,
|
|
142
|
+
Form: ModalForm,
|
|
143
|
+
Pane: ModalPane,
|
|
144
|
+
Content: ModalContent,
|
|
145
|
+
Footer: ModalFooter
|
|
146
|
+
});
|
|
147
|
+
export { Modal$1 as Modal };
|
|
148
|
+
|
|
149
|
+
//# sourceMappingURL=Modal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Modal.js","names":["NinnaModal","Modal"],"sources":["../../src/overlays/Modal.tsx"],"sourcesContent":["/* oxlint-disable react/only-export-components -- Compound members are exported through Modal. */\n\nimport {\n Modal as NinnaModal,\n type ModalBodyProps,\n type ModalContentProps,\n type ModalFooterProps,\n} from '@ninna-ui/overlays';\nimport { XIcon } from 'lucide-react';\nimport {\n type ComponentProps,\n createContext,\n forwardRef,\n type ReactNode,\n type Ref,\n useCallback,\n useContext,\n} from 'react';\n\nimport { IconButton } from '../actions/IconButton';\nimport { useDesignSystemLabels } from '../foundations/DesignSystemProvider';\nimport { Heading, Text } from '../typography/Typography';\nimport { useModalAutoFocus } from './useModalAutoFocus';\nimport { useScrollFade } from './useScrollFade';\n\nconst ModalLoadingContext = createContext(false);\n\ninterface ModalContentPolicyProps extends Omit<ModalContentProps, 'className' | 'size' | 'title'> {\n accessibleTitle?: string;\n /** Whether opening focuses the first editable field; off while the caller focuses something else. */\n focusFirstField?: boolean;\n headerActions?: ReactNode;\n sidebar?: ReactNode;\n /** The dialog's size; a dialog with a sidebar is `paned` unless it says otherwise. */\n presentation?: 'default' | 'paned' | 'workspace';\n title: string;\n}\n\nconst ModalContent = forwardRef<HTMLDivElement, ModalContentPolicyProps>(\n (\n {\n accessibleTitle,\n children,\n closeOnEscape,\n closeOnOverlayClick,\n description,\n focusFirstField,\n headerActions,\n onPointerDownOutside,\n sidebar,\n presentation = sidebar ? 'paned' : 'default',\n title,\n ...props\n },\n ref,\n ) => {\n const loading = useContext(ModalLoadingContext);\n const focusProps = useModalAutoFocus(focusFirstField);\n\n return (\n <NinnaModal.Content\n ref={ref}\n {...props}\n {...focusProps}\n title={accessibleTitle ?? title}\n description={description}\n closeOnEscape={loading ? false : closeOnEscape}\n closeOnOverlayClick={loading ? false : closeOnOverlayClick}\n onPointerDownOutside={(event) => {\n if (event.target instanceof Element && event.target.closest('[data-slot=\"toaster\"]')) {\n event.preventDefault();\n }\n\n onPointerDownOutside?.(event);\n }}\n size={presentation === 'workspace' ? 'full' : undefined}\n className={`flex max-h-[calc(100dvh-1rem)] w-[calc(100vw-1rem)] flex-col overflow-hidden sm:max-h-[calc(100dvh-2rem)] sm:w-[calc(100vw-2rem)] ${\n sidebar ? 'md:grid md:grid-cols-[14rem_minmax(0,1fr)] md:grid-rows-[auto_minmax(0,1fr)]' : ''\n } ${\n presentation === 'workspace'\n ? 'h-[calc(100dvh-1rem)] max-w-6xl sm:h-[calc(100dvh-2rem)] sm:max-w-6xl'\n : presentation === 'paned'\n ? // Paned dialogs keep one height across panes; the body scrolls instead of the dialog resizing.\n 'h-[calc(100dvh-1rem)] max-w-4xl sm:h-[min(44rem,calc(100dvh-2rem))] sm:max-w-4xl'\n : 'max-w-160 sm:max-w-160'\n }`}\n >\n <header\n data-slot=\"modal-header\"\n className={`@container min-w-0 shrink-0 px-5 pt-5 sm:px-6 sm:pt-6 ${\n description ? (sidebar ? 'pb-4 md:pb-0' : '') : 'pb-4'\n } ${sidebar ? 'md:col-start-2 md:row-start-1' : ''}`}\n >\n <div className=\"flex min-w-0 flex-wrap items-center justify-between gap-x-4 gap-y-3\">\n <Heading as=\"h2\" className=\"min-w-0 flex-1 wrap-break-word\" variant=\"section\">\n {title}\n </Heading>\n {headerActions ? (\n <div className=\"order-3 flex basis-full items-center justify-end gap-2 @min-[32rem]:order-0 @min-[32rem]:ml-auto @min-[32rem]:basis-auto\">\n {headerActions}\n </div>\n ) : null}\n <div className=\"shrink-0\">\n <ModalClose />\n </div>\n </div>\n </header>\n {sidebar ? (\n <div className=\"min-h-0 min-w-0 shrink-0 md:col-start-1 md:row-span-2 md:row-start-1\">\n {sidebar}\n </div>\n ) : null}\n <div\n className={`flex min-h-0 min-w-0 flex-1 flex-col ${sidebar ? 'md:col-start-2 md:row-start-2' : ''}`}\n >\n {description ? (\n <Text\n className={`shrink-0 px-5 pb-4 sm:px-6 ${sidebar ? 'pt-4 md:pt-2' : 'pt-2'}`}\n tone=\"muted\"\n >\n {description}\n </Text>\n ) : null}\n {children}\n </div>\n </NinnaModal.Content>\n );\n },\n);\n\nModalContent.displayName = 'Modal.Content';\n\nconst ModalBody = forwardRef<HTMLDivElement, Omit<ModalBodyProps, 'className'> & { layout?: 'scroll' | 'fill' }>(\n ({ layout = 'scroll', children, ...props }, ref: Ref<HTMLDivElement>) => {\n const { setViewport, setContent, className } = useScrollFade();\n const bodyRef = useCallback(\n (element: HTMLDivElement) => {\n setViewport(element);\n\n const cleanup = typeof ref === 'function' ? ref(element) : undefined;\n\n if (ref && typeof ref !== 'function') ref.current = element;\n\n return () => {\n setViewport(null);\n\n if (typeof cleanup === 'function') cleanup();\n else if (typeof ref === 'function') ref(null);\n else if (ref) ref.current = null;\n };\n },\n [ref, setViewport],\n );\n\n return (\n <NinnaModal.Body\n ref={bodyRef}\n {...props}\n className={`min-h-0 flex-1 overflow-y-auto overscroll-contain px-5 pt-2 pb-6 sm:px-6 ${layout === 'fill' ? 'flex flex-col' : ''} ${className}`}\n >\n <div\n ref={setContent}\n className={layout === 'fill' ? 'flex min-h-0 flex-1 flex-col gap-3' : 'flow-root'}\n >\n {children}\n </div>\n </NinnaModal.Body>\n );\n },\n);\n\nModalBody.displayName = 'Modal.Body';\n\nfunction ModalForm(props: Omit<ComponentProps<'form'>, 'className'>) {\n return <form {...props} className=\"flex min-h-0 flex-1 flex-col\" />;\n}\n\nfunction ModalPane({ active, children }: { active: boolean; children: ReactNode }) {\n return (\n <div hidden={!active} className={active ? 'flex min-h-0 flex-1 flex-col' : 'hidden'}>\n {children}\n </div>\n );\n}\n\nconst ModalFooter = forwardRef<HTMLDivElement, Omit<ModalFooterProps, 'className'> & { leading?: ReactNode }>(\n ({ leading, children, ...props }, ref) => (\n <NinnaModal.Footer\n ref={ref}\n {...props}\n className=\"border-base-300 bg-base-50/60 shrink-0 border-t px-5 py-4 sm:px-6 sm:pb-4\"\n >\n {leading ? <div className=\"mr-auto min-w-0 basis-full pb-2 sm:basis-auto sm:pb-0\">{leading}</div> : null}\n {children}\n </NinnaModal.Footer>\n ),\n);\n\nModalFooter.displayName = 'Modal.Footer';\n\nfunction ModalClose() {\n const labels = useDesignSystemLabels();\n const loading = useContext(ModalLoadingContext);\n\n return (\n <NinnaModal.Close asChild>\n <IconButton aria-label={labels.close} disabled={loading} icon={<XIcon />} variant=\"header\" />\n </NinnaModal.Close>\n );\n}\n\ninterface ModalRootPolicyProps {\n children: ReactNode;\n loading?: boolean;\n onClose: () => void;\n}\n\nfunction ModalRoot({ children, loading = false, onClose }: ModalRootPolicyProps) {\n return (\n <ModalLoadingContext.Provider value={loading}>\n <NinnaModal open onOpenChange={(open) => !open && !loading && onClose()}>\n {children}\n </NinnaModal>\n </ModalLoadingContext.Provider>\n );\n}\n\nexport const Modal = Object.assign(ModalRoot, {\n Body: ModalBody,\n Form: ModalForm,\n Pane: ModalPane,\n Content: ModalContent,\n Footer: ModalFooter,\n});\n"],"mappings":";;;;;;;;;;AAyBA,MAAM,sBAAsB,cAAc,KAAK;AAa/C,MAAM,eAAe,YAEb,EACI,iBACA,UACA,eACA,qBACA,aACA,iBACA,eACA,sBACA,SACA,eAAe,UAAU,UAAU,WACnC,OACA,GAAG,SAEP,QACC;CACD,MAAM,UAAU,WAAW,mBAAmB;CAC9C,MAAM,aAAa,kBAAkB,eAAe;CAEpD,OACI,qBAACA,MAAW,SAAZ;EACS;EACL,GAAI;EACJ,GAAI;EACJ,OAAO,mBAAmB;EACb;EACb,eAAe,UAAU,QAAQ;EACjC,qBAAqB,UAAU,QAAQ;EACvC,uBAAuB,UAAU;GAC7B,IAAI,MAAM,kBAAkB,WAAW,MAAM,OAAO,QAAQ,yBAAuB,GAC/E,MAAM,eAAe;GAGzB,uBAAuB,KAAK;EAChC;EACA,MAAM,iBAAiB,cAAc,SAAS,KAAA;EAC9C,WAAW,qIACP,UAAU,iFAAiF,GAC9F,GACG,iBAAiB,cACX,0EACA,iBAAiB,UAEf,qFACA;EAxBhB,UAAA;GA2BI,oBAAC,UAAD;IACI,aAAU;IACV,WAAW,yDACP,cAAe,UAAU,iBAAiB,KAAM,OACnD,GAAG,UAAU,kCAAkC;IAEhD,UAAA,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACI,oBAAC,SAAD;OAAS,IAAG;OAAK,WAAU;OAAiC,SAAQ;OAC/D,UAAA;MACI,CAAA;MACR,gBACG,oBAAC,OAAD;OAAK,WAAU;OACV,UAAA;MACA,CAAA,IACL;MACJ,oBAAC,OAAD;OAAK,WAAU;OACX,UAAA,oBAAC,YAAD,CAAa,CAAA;MACZ,CAAA;KACJ;;GACD,CAAA;GACP,UACG,oBAAC,OAAD;IAAK,WAAU;IACV,UAAA;GACA,CAAA,IACL;GACJ,qBAAC,OAAD;IACI,WAAW,wCAAwC,UAAU,kCAAkC;IADnG,UAAA,CAGK,cACG,oBAAC,MAAD;KACI,WAAW,8BAA8B,UAAU,iBAAiB;KACpE,MAAK;KAEJ,UAAA;IACC,CAAA,IACN,MACH,QACA;;EACW;;AAE5B,CACJ;AAEA,aAAa,cAAc;AAE3B,MAAM,YAAY,YACb,EAAE,SAAS,UAAU,UAAU,GAAG,SAAS,QAA6B;CACrE,MAAM,EAAE,aAAa,YAAY,cAAc,cAAc;CAC7D,MAAM,UAAU,aACX,YAA4B;EACzB,YAAY,OAAO;EAEnB,MAAM,UAAU,OAAO,QAAQ,aAAa,IAAI,OAAO,IAAI,KAAA;EAE3D,IAAI,OAAO,OAAO,QAAQ,YAAY,IAAI,UAAU;EAEpD,aAAa;GACT,YAAY,IAAI;GAEhB,IAAI,OAAO,YAAY,YAAY,QAAQ;QACtC,IAAI,OAAO,QAAQ,YAAY,IAAI,IAAI;QACvC,IAAI,KAAK,IAAI,UAAU;EAChC;CACJ,GACA,CAAC,KAAK,WAAW,CACrB;CAEA,OACI,oBAACA,MAAW,MAAZ;EACI,KAAK;EACL,GAAI;EACJ,WAAW,4EAA4E,WAAW,SAAS,kBAAkB,GAAG,GAAG;EAEnI,UAAA,oBAAC,OAAD;GACI,KAAK;GACL,WAAW,WAAW,SAAS,uCAAuC;GAErE;EACA,CAAA;CACQ,CAAA;AAEzB,CACJ;AAEA,UAAU,cAAc;AAExB,SAAS,UAAU,OAAkD;CACjE,OAAO,oBAAC,QAAD;EAAM,GAAI;EAAO,WAAU;CAAgC,CAAA;AACtE;AAEA,SAAS,UAAU,EAAE,QAAQ,YAAsD;CAC/E,OACI,oBAAC,OAAD;EAAK,QAAQ,CAAC;EAAQ,WAAW,SAAS,iCAAiC;EACtE;CACA,CAAA;AAEb;AAEA,MAAM,cAAc,YACf,EAAE,SAAS,UAAU,GAAG,SAAS,QAC9B,qBAACA,MAAW,QAAZ;CACS;CACL,GAAI;CACJ,WAAU;CAHd,UAAA,CAKK,UAAU,oBAAC,OAAD;EAAK,WAAU;EAAyD,UAAA;CAAa,CAAA,IAAI,MACnG,QACc;AAE3B,CAAA,CAAA;AAEA,YAAY,cAAc;AAE1B,SAAS,aAAa;CAClB,MAAM,SAAS,sBAAsB;CACrC,MAAM,UAAU,WAAW,mBAAmB;CAE9C,OACI,oBAACA,MAAW,OAAZ;EAAkB,SAAA;EACd,UAAA,oBAAC,YAAD;GAAY,cAAY,OAAO;GAAO,UAAU;GAAS,MAAM,oBAAC,OAAD,CAAQ,CAAA;GAAG,SAAQ;EAAU,CAAA;CAC9E,CAAA;AAE1B;AAQA,SAAS,UAAU,EAAE,UAAU,UAAU,OAAO,WAAiC;CAC7E,OACI,oBAAC,oBAAoB,UAArB;EAA8B,OAAO;EACjC,UAAA,oBAACA,OAAD;GAAY,MAAA;GAAK,eAAe,SAAS,CAAC,QAAQ,CAAC,WAAW,QAAQ;GACjE;EACO,CAAA;CACc,CAAA;AAEtC;AAEA,MAAaC,UAAQ,OAAO,OAAO,WAAW;CAC1C,MAAM;CACN,MAAM;CACN,MAAM;CACN,SAAS;CACT,QAAQ;AACZ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ComponentProps } from "react";
|
|
2
|
+
import { Popover, PopoverContentProps } from "@ninna-ui/overlays";
|
|
3
|
+
interface PopoverContentPolicyProps extends Omit<PopoverContentProps, 'className'> {
|
|
4
|
+
layout?: 'fill' | 'scroll';
|
|
5
|
+
onOpenAutoFocus?: (event: Event) => void;
|
|
6
|
+
onCloseAutoFocus?: (event: Event) => void;
|
|
7
|
+
presentation?: 'default' | 'menu';
|
|
8
|
+
width?: 'content' | 'sm' | 'trigger';
|
|
9
|
+
}
|
|
10
|
+
declare function PopoverRoot(props: ComponentProps<typeof Popover>): import("react").JSX.Element;
|
|
11
|
+
declare const Popover$1: typeof PopoverRoot & {
|
|
12
|
+
displayName: string;
|
|
13
|
+
Trigger: import("react").ForwardRefExoticComponent<import("@ninna-ui/overlays").PopoverTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
14
|
+
Arrow: import("react").ForwardRefExoticComponent<import("@ninna-ui/overlays").PopoverArrowProps & import("react").RefAttributes<SVGSVGElement>>;
|
|
15
|
+
Close: import("react").ForwardRefExoticComponent<import("@ninna-ui/overlays").PopoverCloseProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
16
|
+
Content: import("react").ForwardRefExoticComponent<PopoverContentPolicyProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
17
|
+
};
|
|
18
|
+
export { Popover$1 as Popover };
|
|
19
|
+
//# sourceMappingURL=Popover.d.ts.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Popover } from "@ninna-ui/overlays";
|
|
4
|
+
// src/overlays/Popover.tsx
|
|
5
|
+
const popoverWidthClasses = {
|
|
6
|
+
content: void 0,
|
|
7
|
+
sm: "w-64",
|
|
8
|
+
trigger: "w-(--radix-popover-trigger-width)"
|
|
9
|
+
};
|
|
10
|
+
const PopoverContent = forwardRef(({ layout = "scroll", presentation = "default", width = "content", ...props }, ref) => /* @__PURE__ */ jsx(Popover.Content, {
|
|
11
|
+
ref,
|
|
12
|
+
...props,
|
|
13
|
+
"data-layout": layout,
|
|
14
|
+
className: `${popoverWidthClasses[width] ?? ""} ${presentation === "menu" ? "p-1" : ""}`
|
|
15
|
+
}));
|
|
16
|
+
PopoverContent.displayName = "Popover.Content";
|
|
17
|
+
function PopoverRoot(props) {
|
|
18
|
+
return /* @__PURE__ */ jsx(Popover, { ...props });
|
|
19
|
+
}
|
|
20
|
+
const Popover$1 = Object.assign(PopoverRoot, {
|
|
21
|
+
...Popover,
|
|
22
|
+
Content: PopoverContent
|
|
23
|
+
});
|
|
24
|
+
export { Popover$1 as Popover };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=Popover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Popover.js","names":["NinnaPopover","Popover"],"sources":["../../src/overlays/Popover.tsx"],"sourcesContent":["/* oxlint-disable react/only-export-components -- Compound members are exported through Popover. */\n\nimport { Popover as NinnaPopover, type PopoverContentProps } from '@ninna-ui/overlays';\nimport { type ComponentProps, forwardRef } from 'react';\n\ninterface PopoverContentPolicyProps extends Omit<PopoverContentProps, 'className'> {\n layout?: 'fill' | 'scroll';\n onOpenAutoFocus?: (event: Event) => void;\n onCloseAutoFocus?: (event: Event) => void;\n presentation?: 'default' | 'menu';\n width?: 'content' | 'sm' | 'trigger';\n}\n\nconst popoverWidthClasses: Record<NonNullable<PopoverContentPolicyProps['width']>, string | undefined> = {\n content: undefined,\n sm: 'w-64',\n trigger: 'w-(--radix-popover-trigger-width)',\n};\n\nconst PopoverContent = forwardRef<HTMLDivElement, PopoverContentPolicyProps>(\n ({ layout = 'scroll', presentation = 'default', width = 'content', ...props }, ref) => (\n <NinnaPopover.Content\n ref={ref}\n {...props}\n data-layout={layout}\n className={`${popoverWidthClasses[width] ?? ''} ${presentation === 'menu' ? 'p-1' : ''}`}\n />\n ),\n);\n\nPopoverContent.displayName = 'Popover.Content';\n\nfunction PopoverRoot(props: ComponentProps<typeof NinnaPopover>) {\n return <NinnaPopover {...props} />;\n}\n\nexport const Popover = Object.assign(PopoverRoot, {\n ...NinnaPopover,\n Content: PopoverContent,\n});\n"],"mappings":";;;;AAaA,MAAM,sBAAmG;CACrG,SAAS,KAAA;CACT,IAAI;CACJ,SAAS;AACb;AAEA,MAAM,iBAAiB,YAClB,EAAE,SAAS,UAAU,eAAe,WAAW,QAAQ,WAAW,GAAG,SAAS,QAC3E,oBAACA,QAAa,SAAd;CACS;CACL,GAAI;CACJ,eAAa;CACb,WAAW,GAAG,oBAAoB,UAAU,GAAG,GAAG,iBAAiB,SAAS,QAAQ;AACvF,CAAA,CAET;AAEA,eAAe,cAAc;AAE7B,SAAS,YAAY,OAA4C;CAC7D,OAAO,oBAACA,SAAD,EAAc,GAAI,MAAQ,CAAA;AACrC;AAEA,MAAaC,YAAU,OAAO,OAAO,aAAa;CAC9C,GAAGD;CACH,SAAS;AACb,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ComponentProps } from "react";
|
|
2
|
+
import { TooltipContentProps, TooltipTriggerProps } from "@ninna-ui/overlays";
|
|
3
|
+
import { TooltipEngine } from "@ninna-ui/react-internal";
|
|
4
|
+
/** Shares one open delay across the tooltips inside it. */
|
|
5
|
+
export declare function TooltipProvider(props: ComponentProps<typeof TooltipEngine.Provider>): import("react").JSX.Element;
|
|
6
|
+
declare function Tooltip$1({ disabled, ...props }: ComponentProps<typeof TooltipEngine.Root> & {
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
9
|
+
export declare const TooltipTrigger: import("react").ForwardRefExoticComponent<TooltipTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
10
|
+
export declare const TooltipPopup: import("react").ForwardRefExoticComponent<Omit<TooltipContentProps, "color" | "hasArrow"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
11
|
+
export { Tooltip$1 as Tooltip };
|
|
12
|
+
//# sourceMappingURL=Tooltip.d.ts.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { forwardRef, isValidElement } from "react";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Tooltip } from "@ninna-ui/overlays";
|
|
4
|
+
import { Slot, TooltipEngine } from "@ninna-ui/react-internal";
|
|
5
|
+
// src/overlays/Tooltip.tsx
|
|
6
|
+
/** Shares one open delay across the tooltips inside it. */
|
|
7
|
+
function TooltipProvider(props) {
|
|
8
|
+
return /* @__PURE__ */ jsx(TooltipEngine.Provider, { ...props });
|
|
9
|
+
}
|
|
10
|
+
function Tooltip$1({ disabled, ...props }) {
|
|
11
|
+
return /* @__PURE__ */ jsx(TooltipEngine.Root, {
|
|
12
|
+
...props,
|
|
13
|
+
open: disabled ? false : props.open
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
const TooltipTrigger = forwardRef(({ asChild, children, ...props }, ref) => {
|
|
17
|
+
const childProps = asChild && isValidElement(children) ? children.props : void 0;
|
|
18
|
+
if (props.disabled || childProps?.disabled) {
|
|
19
|
+
const Trigger = asChild ? Slot : "button";
|
|
20
|
+
return /* @__PURE__ */ jsx(Tooltip.Trigger, {
|
|
21
|
+
asChild: true,
|
|
22
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
23
|
+
tabIndex: 0,
|
|
24
|
+
role: "button",
|
|
25
|
+
"aria-disabled": "true",
|
|
26
|
+
"aria-label": props["aria-label"] ?? childProps?.["aria-label"],
|
|
27
|
+
"aria-labelledby": props["aria-labelledby"] ?? childProps?.["aria-labelledby"],
|
|
28
|
+
className: "inline-flex [&>*]:pointer-events-none",
|
|
29
|
+
children: /* @__PURE__ */ jsx(Trigger, {
|
|
30
|
+
type: "button",
|
|
31
|
+
...props,
|
|
32
|
+
ref,
|
|
33
|
+
children
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return /* @__PURE__ */ jsx(Tooltip.Trigger, {
|
|
39
|
+
...props,
|
|
40
|
+
ref,
|
|
41
|
+
asChild,
|
|
42
|
+
children
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
TooltipTrigger.displayName = "TooltipTrigger";
|
|
46
|
+
const TooltipPopup = forwardRef((props, ref) => /* @__PURE__ */ jsx(Tooltip.Content, {
|
|
47
|
+
...props,
|
|
48
|
+
ref,
|
|
49
|
+
role: void 0
|
|
50
|
+
}));
|
|
51
|
+
TooltipPopup.displayName = "TooltipPopup";
|
|
52
|
+
export { Tooltip$1 as Tooltip, TooltipPopup, TooltipProvider, TooltipTrigger };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=Tooltip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tooltip.js","names":["Tooltip","NinnaTooltip"],"sources":["../../src/overlays/Tooltip.tsx"],"sourcesContent":["import { Tooltip as NinnaTooltip, type TooltipContentProps, type TooltipTriggerProps } from '@ninna-ui/overlays';\nimport { Slot, TooltipEngine } from '@ninna-ui/react-internal';\nimport { type ComponentProps, forwardRef, isValidElement } from 'react';\n\n/** Shares one open delay across the tooltips inside it. */\nexport function TooltipProvider(props: ComponentProps<typeof TooltipEngine.Provider>) {\n return <TooltipEngine.Provider {...props} />;\n}\n\nexport function Tooltip({ disabled, ...props }: ComponentProps<typeof TooltipEngine.Root> & { disabled?: boolean }) {\n return <TooltipEngine.Root {...props} open={disabled ? false : props.open} />;\n}\n\nexport const TooltipTrigger = forwardRef<HTMLButtonElement, TooltipTriggerProps>(\n ({ asChild, children, ...props }, ref) => {\n const childProps = asChild && isValidElement<TooltipTriggerProps>(children) ? children.props : undefined;\n\n if (props.disabled || childProps?.disabled) {\n const Trigger = asChild ? Slot : 'button';\n\n return (\n <NinnaTooltip.Trigger asChild>\n <span\n tabIndex={0}\n role=\"button\"\n aria-disabled=\"true\"\n aria-label={props['aria-label'] ?? childProps?.['aria-label']}\n aria-labelledby={props['aria-labelledby'] ?? childProps?.['aria-labelledby']}\n className=\"inline-flex [&>*]:pointer-events-none\"\n >\n <Trigger type=\"button\" {...props} ref={ref}>\n {children}\n </Trigger>\n </span>\n </NinnaTooltip.Trigger>\n );\n }\n\n return (\n <NinnaTooltip.Trigger {...props} ref={ref} asChild={asChild}>\n {children}\n </NinnaTooltip.Trigger>\n );\n },\n);\n\nTooltipTrigger.displayName = 'TooltipTrigger';\n\nexport const TooltipPopup = forwardRef<HTMLDivElement, Omit<TooltipContentProps, 'color' | 'hasArrow'>>(\n (props, ref) => (\n // Radix supplies the tooltip role on its visually hidden accessible description.\n <NinnaTooltip.Content {...props} ref={ref} role={undefined} />\n ),\n);\n\nTooltipPopup.displayName = 'TooltipPopup';\n"],"mappings":";;;;;;AAKA,SAAgB,gBAAgB,OAAsD;CAClF,OAAO,oBAAC,cAAc,UAAf,EAAwB,GAAI,MAAQ,CAAA;AAC/C;AAEA,SAAgBA,UAAQ,EAAE,UAAU,GAAG,SAA6E;CAChH,OAAO,oBAAC,cAAc,MAAf;EAAoB,GAAI;EAAO,MAAM,WAAW,QAAQ,MAAM;CAAO,CAAA;AAChF;AAEA,MAAa,iBAAiB,YACzB,EAAE,SAAS,UAAU,GAAG,SAAS,QAAQ;CACtC,MAAM,aAAa,WAAW,eAAoC,QAAQ,IAAI,SAAS,QAAQ,KAAA;CAE/F,IAAI,MAAM,YAAY,YAAY,UAAU;EACxC,MAAM,UAAU,UAAU,OAAO;EAEjC,OACI,oBAACC,QAAa,SAAd;GAAsB,SAAA;GAClB,UAAA,oBAAC,QAAD;IACI,UAAU;IACV,MAAK;IACL,iBAAc;IACd,cAAY,MAAM,iBAAiB,aAAa;IAChD,mBAAiB,MAAM,sBAAsB,aAAa;IAC1D,WAAU;IAEV,UAAA,oBAAC,SAAD;KAAS,MAAK;KAAS,GAAI;KAAY;KAClC;IACI,CAAA;GACP,CAAA;EACY,CAAA;CAE9B;CAEA,OACI,oBAACA,QAAa,SAAd;EAAsB,GAAI;EAAY;EAAc;EAC/C;CACiB,CAAA;AAE9B,CACJ;AAEA,eAAe,cAAc;AAE7B,MAAa,eAAe,YACvB,OAAO,QAEJ,oBAACA,QAAa,SAAd;CAAsB,GAAI;CAAY;CAAK,MAAM,KAAA;AAAY,CAAA,CAErE;AAEA,aAAa,cAAc"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ActionModal } from "./ActionModal.js";
|
|
2
|
+
import { CommandPalette, CommandPaletteGroup, useCommandPaletteOption } from "./CommandPalette.js";
|
|
3
|
+
import { Drawer } from "./Drawer.js";
|
|
4
|
+
import { DropdownMenu } from "./DropdownMenu.js";
|
|
5
|
+
import { ImageViewer } from "./ImageViewer.js";
|
|
6
|
+
import { Modal } from "./Modal.js";
|
|
7
|
+
import { Popover } from "./Popover.js";
|
|
8
|
+
import { Tooltip, TooltipPopup, TooltipProvider, TooltipTrigger } from "./Tooltip.js";
|
|
9
|
+
export { ActionModal, CommandPalette, CommandPaletteGroup, Drawer, DropdownMenu, ImageViewer, Modal, Popover, Tooltip, TooltipPopup, TooltipProvider, TooltipTrigger, useCommandPaletteOption };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
// src/overlays/useModalAutoFocus.ts
|
|
3
|
+
/** Focuses a dialog's first editable field when it opens, or once one appears, unless `focusFirstField` is
|
|
4
|
+
* false, such as while the caller focuses something else; turning it off stops a pending wait. */
|
|
5
|
+
function useModalAutoFocus(focusFirstField = true) {
|
|
6
|
+
const cleanup = useRef(void 0);
|
|
7
|
+
const returnFocus = useRef(null);
|
|
8
|
+
useEffect(() => () => cleanup.current?.(), []);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (!focusFirstField) cleanup.current?.();
|
|
11
|
+
}, [focusFirstField]);
|
|
12
|
+
const onOpenAutoFocus = (event) => {
|
|
13
|
+
cleanup.current?.();
|
|
14
|
+
const dialog = event.target;
|
|
15
|
+
if (!(dialog instanceof HTMLElement)) return;
|
|
16
|
+
returnFocus.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
17
|
+
if (!focusFirstField) return;
|
|
18
|
+
if (focusFirstEditable(dialog)) {
|
|
19
|
+
event.preventDefault();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const observer = new MutationObserver(() => {
|
|
23
|
+
if (focusFirstEditable(dialog)) stop();
|
|
24
|
+
});
|
|
25
|
+
const stop = () => {
|
|
26
|
+
observer.disconnect();
|
|
27
|
+
dialog.removeEventListener("pointerdown", stop, true);
|
|
28
|
+
dialog.removeEventListener("keydown", stop, true);
|
|
29
|
+
cleanup.current = void 0;
|
|
30
|
+
};
|
|
31
|
+
cleanup.current = stop;
|
|
32
|
+
observer.observe(dialog, {
|
|
33
|
+
childList: true,
|
|
34
|
+
subtree: true,
|
|
35
|
+
attributes: true,
|
|
36
|
+
attributeFilter: [
|
|
37
|
+
"disabled",
|
|
38
|
+
"readonly",
|
|
39
|
+
"hidden",
|
|
40
|
+
"inert",
|
|
41
|
+
"class",
|
|
42
|
+
"style",
|
|
43
|
+
"aria-disabled",
|
|
44
|
+
"aria-readonly",
|
|
45
|
+
"aria-hidden"
|
|
46
|
+
]
|
|
47
|
+
});
|
|
48
|
+
dialog.addEventListener("pointerdown", stop, true);
|
|
49
|
+
dialog.addEventListener("keydown", stop, true);
|
|
50
|
+
};
|
|
51
|
+
const onCloseAutoFocus = (event) => {
|
|
52
|
+
cleanup.current?.();
|
|
53
|
+
if (returnFocus.current?.isConnected) {
|
|
54
|
+
event.preventDefault();
|
|
55
|
+
returnFocus.current.focus({ preventScroll: true });
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
onOpenAutoFocus,
|
|
60
|
+
onCloseAutoFocus
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function focusFirstEditable(dialog) {
|
|
64
|
+
const candidates = dialog.querySelectorAll("input, textarea, select, [role=\"combobox\"], [role=\"switch\"], [role=\"checkbox\"], [role=\"radio\"], [contenteditable=\"true\"], [data-slot=\"field\"] button[aria-haspopup=\"dialog\"]");
|
|
65
|
+
for (const field of candidates) {
|
|
66
|
+
if (field.tabIndex < 0 || field.matches(":disabled, [readonly], [aria-disabled=\"true\"], [aria-readonly=\"true\"], input[type=\"hidden\"], input[type=\"button\"], input[type=\"submit\"], input[type=\"reset\"], input[type=\"image\"]") || field.closest("[hidden], [inert], [aria-hidden=\"true\"], details:not([open])") || field.closest("[role=\"dialog\"]") !== dialog || !isVisible(field, dialog)) continue;
|
|
67
|
+
field.focus({ preventScroll: true });
|
|
68
|
+
if (document.activeElement !== field) continue;
|
|
69
|
+
if (field instanceof HTMLTextAreaElement || field instanceof HTMLInputElement && field.selectionStart !== null) field.select();
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
function isVisible(field, dialog) {
|
|
75
|
+
if (getComputedStyle(field).visibility !== "visible") return false;
|
|
76
|
+
for (let element = field; element; element = element.parentElement) {
|
|
77
|
+
if (getComputedStyle(element).display === "none") return false;
|
|
78
|
+
if (element === dialog) return true;
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
export { useModalAutoFocus };
|
|
83
|
+
|
|
84
|
+
//# sourceMappingURL=useModalAutoFocus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useModalAutoFocus.js","names":[],"sources":["../../src/overlays/useModalAutoFocus.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\n\n/** Focuses a dialog's first editable field when it opens, or once one appears, unless `focusFirstField` is\n * false, such as while the caller focuses something else; turning it off stops a pending wait. */\nexport function useModalAutoFocus(focusFirstField = true) {\n const cleanup = useRef<(() => void) | undefined>(undefined);\n const returnFocus = useRef<HTMLElement | null>(null);\n\n useEffect(() => () => cleanup.current?.(), []);\n useEffect(() => {\n if (!focusFirstField) cleanup.current?.();\n }, [focusFirstField]);\n\n const onOpenAutoFocus = (event: Event) => {\n cleanup.current?.();\n\n const dialog = event.target;\n\n if (!(dialog instanceof HTMLElement)) return;\n\n returnFocus.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n\n if (!focusFirstField) return;\n\n if (focusFirstEditable(dialog)) {\n event.preventDefault();\n\n return;\n }\n\n const observer = new MutationObserver(() => {\n if (focusFirstEditable(dialog)) stop();\n });\n\n const stop = () => {\n observer.disconnect();\n dialog.removeEventListener('pointerdown', stop, true);\n dialog.removeEventListener('keydown', stop, true);\n cleanup.current = undefined;\n };\n\n cleanup.current = stop;\n observer.observe(dialog, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\n 'disabled',\n 'readonly',\n 'hidden',\n 'inert',\n 'class',\n 'style',\n 'aria-disabled',\n 'aria-readonly',\n 'aria-hidden',\n ],\n });\n dialog.addEventListener('pointerdown', stop, true);\n dialog.addEventListener('keydown', stop, true);\n };\n\n const onCloseAutoFocus = (event: Event) => {\n cleanup.current?.();\n\n if (returnFocus.current?.isConnected) {\n event.preventDefault();\n returnFocus.current.focus({ preventScroll: true });\n }\n };\n\n return { onOpenAutoFocus, onCloseAutoFocus };\n}\n\nfunction focusFirstEditable(dialog: HTMLElement): boolean {\n const candidates = dialog.querySelectorAll<HTMLElement>(\n 'input, textarea, select, [role=\"combobox\"], [role=\"switch\"], [role=\"checkbox\"], [role=\"radio\"], [contenteditable=\"true\"], [data-slot=\"field\"] button[aria-haspopup=\"dialog\"]',\n );\n\n for (const field of candidates) {\n if (\n field.tabIndex < 0 ||\n field.matches(\n ':disabled, [readonly], [aria-disabled=\"true\"], [aria-readonly=\"true\"], input[type=\"hidden\"], input[type=\"button\"], input[type=\"submit\"], input[type=\"reset\"], input[type=\"image\"]',\n ) ||\n field.closest('[hidden], [inert], [aria-hidden=\"true\"], details:not([open])') ||\n field.closest('[role=\"dialog\"]') !== dialog ||\n !isVisible(field, dialog)\n )\n continue;\n\n field.focus({ preventScroll: true });\n\n if (document.activeElement !== field) continue;\n\n if (\n field instanceof HTMLTextAreaElement ||\n (field instanceof HTMLInputElement && field.selectionStart !== null)\n ) {\n field.select();\n }\n\n return true;\n }\n\n return false;\n}\n\nfunction isVisible(field: HTMLElement, dialog: HTMLElement): boolean {\n if (getComputedStyle(field).visibility !== 'visible') return false;\n\n for (let element: HTMLElement | null = field; element; element = element.parentElement) {\n if (getComputedStyle(element).display === 'none') return false;\n\n if (element === dialog) return true;\n }\n\n return false;\n}\n"],"mappings":";;;;AAIA,SAAgB,kBAAkB,kBAAkB,MAAM;CACtD,MAAM,UAAU,OAAiC,KAAA,CAAS;CAC1D,MAAM,cAAc,OAA2B,IAAI;CAEnD,sBAAsB,QAAQ,UAAU,GAAG,CAAC,CAAC;CAC7C,gBAAgB;EACZ,IAAI,CAAC,iBAAiB,QAAQ,UAAU;CAC5C,GAAG,CAAC,eAAe,CAAC;CAEpB,MAAM,mBAAmB,UAAiB;EACtC,QAAQ,UAAU;EAElB,MAAM,SAAS,MAAM;EAErB,IAAI,EAAE,kBAAkB,cAAc;EAEtC,YAAY,UAAU,SAAS,yBAAyB,cAAc,SAAS,gBAAgB;EAE/F,IAAI,CAAC,iBAAiB;EAEtB,IAAI,mBAAmB,MAAM,GAAG;GAC5B,MAAM,eAAe;GAErB;EACJ;EAEA,MAAM,WAAW,IAAI,uBAAuB;GACxC,IAAI,mBAAmB,MAAM,GAAG,KAAK;EACzC,CAAC;EAED,MAAM,aAAa;GACf,SAAS,WAAW;GACpB,OAAO,oBAAoB,eAAe,MAAM,IAAI;GACpD,OAAO,oBAAoB,WAAW,MAAM,IAAI;GAChD,QAAQ,UAAU,KAAA;EACtB;EAEA,QAAQ,UAAU;EAClB,SAAS,QAAQ,QAAQ;GACrB,WAAW;GACX,SAAS;GACT,YAAY;GACZ,iBAAiB;IACb;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;GACJ;EACJ,CAAC;EACD,OAAO,iBAAiB,eAAe,MAAM,IAAI;EACjD,OAAO,iBAAiB,WAAW,MAAM,IAAI;CACjD;CAEA,MAAM,oBAAoB,UAAiB;EACvC,QAAQ,UAAU;EAElB,IAAI,YAAY,SAAS,aAAa;GAClC,MAAM,eAAe;GACrB,YAAY,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;EACrD;CACJ;CAEA,OAAO;EAAE;EAAiB;CAAiB;AAC/C;AAEA,SAAS,mBAAmB,QAA8B;CACtD,MAAM,aAAa,OAAO,iBACtB,4LACJ;CAEA,KAAK,MAAM,SAAS,YAAY;EAC5B,IACI,MAAM,WAAW,KACjB,MAAM,QACF,iMACJ,KACA,MAAM,QAAQ,gEAA8D,KAC5E,MAAM,QAAQ,mBAAiB,MAAM,UACrC,CAAC,UAAU,OAAO,MAAM,GAExB;EAEJ,MAAM,MAAM,EAAE,eAAe,KAAK,CAAC;EAEnC,IAAI,SAAS,kBAAkB,OAAO;EAEtC,IACI,iBAAiB,uBAChB,iBAAiB,oBAAoB,MAAM,mBAAmB,MAE/D,MAAM,OAAO;EAGjB,OAAO;CACX;CAEA,OAAO;AACX;AAEA,SAAS,UAAU,OAAoB,QAA8B;CACjE,IAAI,iBAAiB,KAAK,CAAC,CAAC,eAAe,WAAW,OAAO;CAE7D,KAAK,IAAI,UAA8B,OAAO,SAAS,UAAU,QAAQ,eAAe;EACpF,IAAI,iBAAiB,OAAO,CAAC,CAAC,YAAY,QAAQ,OAAO;EAEzD,IAAI,YAAY,QAAQ,OAAO;CACnC;CAEA,OAAO;AACX"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useLayoutEffect, useState } from "react";
|
|
2
|
+
// src/overlays/useScrollFade.ts
|
|
3
|
+
/** Attach to the scroll owner and its content so async content and viewport changes update the mask. */
|
|
4
|
+
function useScrollFade() {
|
|
5
|
+
const [viewport, setViewport] = useState(null);
|
|
6
|
+
const [content, setContent] = useState(null);
|
|
7
|
+
useLayoutEffect(() => {
|
|
8
|
+
if (!viewport || !content) return;
|
|
9
|
+
const measure = () => {
|
|
10
|
+
const { scrollTop, scrollHeight, clientHeight } = viewport;
|
|
11
|
+
viewport.style.setProperty("--scroll-fade-top", `${Math.max(0, scrollTop)}px`);
|
|
12
|
+
viewport.style.setProperty("--scroll-fade-bottom", `${Math.max(0, scrollHeight - clientHeight - scrollTop)}px`);
|
|
13
|
+
};
|
|
14
|
+
const observer = new ResizeObserver(measure);
|
|
15
|
+
const observeContent = () => {
|
|
16
|
+
observer.disconnect();
|
|
17
|
+
observer.observe(viewport);
|
|
18
|
+
observer.observe(content);
|
|
19
|
+
content.querySelectorAll("*").forEach((element) => observer.observe(element));
|
|
20
|
+
measure();
|
|
21
|
+
};
|
|
22
|
+
const mutations = new MutationObserver(observeContent);
|
|
23
|
+
mutations.observe(content, {
|
|
24
|
+
childList: true,
|
|
25
|
+
subtree: true
|
|
26
|
+
});
|
|
27
|
+
viewport.addEventListener("scroll", measure, { passive: true });
|
|
28
|
+
observeContent();
|
|
29
|
+
return () => {
|
|
30
|
+
mutations.disconnect();
|
|
31
|
+
observer.disconnect();
|
|
32
|
+
viewport.removeEventListener("scroll", measure);
|
|
33
|
+
};
|
|
34
|
+
}, [viewport, content]);
|
|
35
|
+
return {
|
|
36
|
+
setViewport,
|
|
37
|
+
setContent,
|
|
38
|
+
className: "[mask-image:linear-gradient(to_bottom,transparent,black_min(1.5rem,var(--scroll-fade-top,0px)),black_calc(100%_-_min(1.5rem,var(--scroll-fade-bottom,0px))),transparent)] focus-visible:[mask-image:none] has-[:focus-visible]:[mask-image:none]"
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export { useScrollFade };
|
|
42
|
+
|
|
43
|
+
//# sourceMappingURL=useScrollFade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useScrollFade.js","names":[],"sources":["../../src/overlays/useScrollFade.ts"],"sourcesContent":["import { useLayoutEffect, useState } from 'react';\n\n/** Attach to the scroll owner and its content so async content and viewport changes update the mask. */\nexport function useScrollFade() {\n const [viewport, setViewport] = useState<HTMLDivElement | null>(null);\n const [content, setContent] = useState<HTMLDivElement | null>(null);\n\n useLayoutEffect(() => {\n if (!viewport || !content) return;\n\n const measure = () => {\n const { scrollTop, scrollHeight, clientHeight } = viewport;\n\n viewport.style.setProperty('--scroll-fade-top', `${Math.max(0, scrollTop)}px`);\n viewport.style.setProperty(\n '--scroll-fade-bottom',\n `${Math.max(0, scrollHeight - clientHeight - scrollTop)}px`,\n );\n };\n const observer = new ResizeObserver(measure);\n\n const observeContent = () => {\n observer.disconnect();\n observer.observe(viewport);\n observer.observe(content);\n // Fill layouts can keep ancestors fixed while descendants change the scroll extent.\n content.querySelectorAll('*').forEach((element) => observer.observe(element));\n measure();\n };\n const mutations = new MutationObserver(observeContent);\n\n mutations.observe(content, { childList: true, subtree: true });\n viewport.addEventListener('scroll', measure, { passive: true });\n observeContent();\n\n return () => {\n mutations.disconnect();\n observer.disconnect();\n viewport.removeEventListener('scroll', measure);\n };\n }, [viewport, content]);\n\n return {\n setViewport,\n setContent,\n className:\n '[mask-image:linear-gradient(to_bottom,transparent,black_min(1.5rem,var(--scroll-fade-top,0px)),black_calc(100%_-_min(1.5rem,var(--scroll-fade-bottom,0px))),transparent)] focus-visible:[mask-image:none] has-[:focus-visible]:[mask-image:none]',\n };\n}\n"],"mappings":";;;AAGA,SAAgB,gBAAgB;CAC5B,MAAM,CAAC,UAAU,eAAe,SAAgC,IAAI;CACpE,MAAM,CAAC,SAAS,cAAc,SAAgC,IAAI;CAElE,sBAAsB;EAClB,IAAI,CAAC,YAAY,CAAC,SAAS;EAE3B,MAAM,gBAAgB;GAClB,MAAM,EAAE,WAAW,cAAc,iBAAiB;GAElD,SAAS,MAAM,YAAY,qBAAqB,GAAG,KAAK,IAAI,GAAG,SAAS,EAAE,GAAG;GAC7E,SAAS,MAAM,YACX,wBACA,GAAG,KAAK,IAAI,GAAG,eAAe,eAAe,SAAS,EAAE,GAC5D;EACJ;EACA,MAAM,WAAW,IAAI,eAAe,OAAO;EAE3C,MAAM,uBAAuB;GACzB,SAAS,WAAW;GACpB,SAAS,QAAQ,QAAQ;GACzB,SAAS,QAAQ,OAAO;GAExB,QAAQ,iBAAiB,GAAG,CAAC,CAAC,SAAS,YAAY,SAAS,QAAQ,OAAO,CAAC;GAC5E,QAAQ;EACZ;EACA,MAAM,YAAY,IAAI,iBAAiB,cAAc;EAErD,UAAU,QAAQ,SAAS;GAAE,WAAW;GAAM,SAAS;EAAK,CAAC;EAC7D,SAAS,iBAAiB,UAAU,SAAS,EAAE,SAAS,KAAK,CAAC;EAC9D,eAAe;EAEf,aAAa;GACT,UAAU,WAAW;GACrB,SAAS,WAAW;GACpB,SAAS,oBAAoB,UAAU,OAAO;EAClD;CACJ,GAAG,CAAC,UAAU,OAAO,CAAC;CAEtB,OAAO;EACH;EACA;EACA,WACI;CACR;AACJ"}
|