@lar-works/design-system 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +54 -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 +71 -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,68 @@
|
|
|
1
|
+
import { Button as NinnaButton, type ButtonProps as NinnaButtonProps } from '@ninna-ui/primitives';
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
|
|
4
|
+
import { tabbable } from '../foundations/KeyboardFocus';
|
|
5
|
+
|
|
6
|
+
/** T3 Code's button (coss ui): an 8px-radius control, 36px on touch and 32px with a pointer, that dips to
|
|
7
|
+
* 97% while pressed. Every recipe sets its own colours, so ninna-ui only supplies behaviour. */
|
|
8
|
+
const base =
|
|
9
|
+
'h-9 gap-2 rounded-md border px-[11px] text-sm font-medium whitespace-nowrap transition-[background-color,box-shadow,scale,color] duration-150 active:scale-[0.97] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary focus-visible:ring-offset-0 disabled:opacity-64 sm:h-8 [&_[data-slot=icon]>svg]:size-4';
|
|
10
|
+
|
|
11
|
+
const outline =
|
|
12
|
+
'border-base-400/90 bg-base-100 text-base-content shadow-xs/5 hover:bg-base-200/70 dark:border-base-400 dark:bg-base-400/30 dark:hover:bg-base-400/60 [&_[data-slot=icon]]:text-base-700';
|
|
13
|
+
const ghost =
|
|
14
|
+
'border-transparent text-base-content hover:bg-base-200 data-[state=open]:bg-base-200 [&_[data-slot=icon]]:text-base-700';
|
|
15
|
+
|
|
16
|
+
const recipes = {
|
|
17
|
+
primary:
|
|
18
|
+
'border-primary bg-primary text-primary-content shadow-xs shadow-primary/24 inset-shadow-[0_1px_rgb(255_255_255/16%)] hover:bg-primary/90 active:shadow-none active:inset-shadow-[0_1px_rgb(0_0_0/8%)]',
|
|
19
|
+
secondary: outline,
|
|
20
|
+
quiet: ghost,
|
|
21
|
+
row: `${ghost} h-auto min-h-8 min-w-0 max-w-full justify-start whitespace-normal px-0 py-1 text-left text-xs font-normal text-base-700 hover:bg-transparent hover:text-base-content sm:h-auto active:scale-100`,
|
|
22
|
+
subtle: 'border-transparent bg-base-200 text-base-content hover:bg-base-300/70 dark:bg-base-300 dark:hover:bg-base-400',
|
|
23
|
+
destructive:
|
|
24
|
+
'border-danger bg-danger text-white shadow-xs shadow-danger/24 inset-shadow-[0_1px_rgb(255_255_255/16%)] hover:bg-danger/90 active:shadow-none',
|
|
25
|
+
'destructive-quiet':
|
|
26
|
+
'border-transparent text-(--lar-danger-text) hover:bg-danger/8 dark:hover:bg-danger/16 [&_[data-slot=icon]]:text-current',
|
|
27
|
+
choice: outline,
|
|
28
|
+
context: `${ghost} h-11 min-w-0 gap-1.5 px-2 lg:max-w-48 lg:pointer-fine:h-8`,
|
|
29
|
+
summary: `${ghost} h-7 min-w-0 px-1.5 sm:h-7`,
|
|
30
|
+
avatar: 'size-7 rounded-full border-transparent p-0 hover:bg-transparent sm:h-7 [&>*]:size-7',
|
|
31
|
+
status: 'h-4 min-w-0 max-w-full justify-start gap-1.5 rounded-sm border-transparent px-0 text-xs font-normal text-base-700 hover:bg-transparent hover:text-base-content sm:h-4 active:scale-100 [&>svg]:size-3 [&>svg]:shrink-0',
|
|
32
|
+
} as const;
|
|
33
|
+
|
|
34
|
+
const selectedChoice =
|
|
35
|
+
'border-primary/60 bg-primary/8 text-base-content ring-1 ring-inset ring-primary/40 hover:bg-primary/12 dark:border-primary/60 dark:bg-primary/16 dark:hover:bg-primary/20';
|
|
36
|
+
|
|
37
|
+
export type ButtonProps = Omit<NinnaButtonProps, 'color' | 'radius' | 'size' | 'variant'> & {
|
|
38
|
+
variant?: keyof typeof recipes;
|
|
39
|
+
selected?: boolean;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
43
|
+
({ variant = 'primary', selected, className = '', children, leftIcon, rightIcon, ...props }, ref) => {
|
|
44
|
+
const context = variant === 'context';
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<NinnaButton
|
|
48
|
+
ref={ref}
|
|
49
|
+
{...tabbable}
|
|
50
|
+
{...props}
|
|
51
|
+
size="sm"
|
|
52
|
+
radius="lg"
|
|
53
|
+
variant="ghost"
|
|
54
|
+
color="neutral"
|
|
55
|
+
aria-pressed={selected ?? props['aria-pressed']}
|
|
56
|
+
className={`${base} ${variant === 'choice' && selected ? selectedChoice : recipes[variant]} ${selected && variant !== 'choice' ? 'bg-base-200' : ''} ${className}`}
|
|
57
|
+
leftIcon={
|
|
58
|
+
context ? <span className="text-(--color-header-icon) [&>svg]:size-4">{leftIcon}</span> : leftIcon
|
|
59
|
+
}
|
|
60
|
+
rightIcon={context ? <span className="text-base-700 [&>svg]:size-3.5">{rightIcon}</span> : rightIcon}
|
|
61
|
+
>
|
|
62
|
+
{context ? <span className="truncate">{children}</span> : children}
|
|
63
|
+
</NinnaButton>
|
|
64
|
+
);
|
|
65
|
+
},
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
Button.displayName = 'Button';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ArrowRightIcon } from 'lucide-react';
|
|
2
|
+
import type { AnchorHTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
import { tabbable } from '../foundations/KeyboardFocus';
|
|
5
|
+
|
|
6
|
+
/** The marketing pages' calls to action: the Button recipes at a roomier 44px, as links. */
|
|
7
|
+
const recipes = {
|
|
8
|
+
primary:
|
|
9
|
+
'border-primary bg-primary text-primary-content shadow-sm shadow-primary/30 inset-shadow-[0_1px_rgb(255_255_255/18%)] hover:bg-[color-mix(in_srgb,var(--color-primary)_88%,white)] active:shadow-none',
|
|
10
|
+
secondary:
|
|
11
|
+
'border-base-400/90 bg-base-100 text-base-content shadow-xs/5 hover:bg-base-200/70 dark:border-base-400 dark:bg-base-300/40 dark:hover:bg-base-400/50',
|
|
12
|
+
inverse:
|
|
13
|
+
'border-transparent bg-base-content text-base-50 shadow-sm hover:bg-[color-mix(in_srgb,var(--color-base-content)_86%,transparent)]',
|
|
14
|
+
quiet: 'border-transparent text-base-content hover:text-primary dark:hover:text-[color-mix(in_srgb,var(--color-primary)_45%,white)]',
|
|
15
|
+
} as const;
|
|
16
|
+
|
|
17
|
+
export interface ButtonLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'className' | 'style'> {
|
|
18
|
+
href: string;
|
|
19
|
+
variant?: keyof typeof recipes;
|
|
20
|
+
size?: 'md' | 'lg';
|
|
21
|
+
icon?: ReactNode;
|
|
22
|
+
/** Shows an arrow that nudges forward on hover. */
|
|
23
|
+
arrow?: boolean;
|
|
24
|
+
external?: boolean;
|
|
25
|
+
onNavigate?: (href: string) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function ButtonLink({
|
|
29
|
+
variant = 'primary',
|
|
30
|
+
size = 'lg',
|
|
31
|
+
icon,
|
|
32
|
+
arrow,
|
|
33
|
+
external,
|
|
34
|
+
onNavigate,
|
|
35
|
+
onClick,
|
|
36
|
+
children,
|
|
37
|
+
href,
|
|
38
|
+
...props
|
|
39
|
+
}: ButtonLinkProps) {
|
|
40
|
+
return (
|
|
41
|
+
<a
|
|
42
|
+
{...tabbable}
|
|
43
|
+
{...props}
|
|
44
|
+
href={href}
|
|
45
|
+
{...(external ? { target: '_blank', rel: 'noreferrer' } : {})}
|
|
46
|
+
onClick={(event) => {
|
|
47
|
+
onClick?.(event);
|
|
48
|
+
|
|
49
|
+
if (
|
|
50
|
+
!onNavigate ||
|
|
51
|
+
external ||
|
|
52
|
+
event.defaultPrevented ||
|
|
53
|
+
event.button !== 0 ||
|
|
54
|
+
event.metaKey ||
|
|
55
|
+
event.ctrlKey ||
|
|
56
|
+
event.shiftKey ||
|
|
57
|
+
event.altKey
|
|
58
|
+
)
|
|
59
|
+
return;
|
|
60
|
+
|
|
61
|
+
event.preventDefault();
|
|
62
|
+
onNavigate(href);
|
|
63
|
+
}}
|
|
64
|
+
className={`group/button focus-visible:outline-primary inline-flex shrink-0 items-center justify-center gap-2 rounded-[0.625rem] border font-medium whitespace-nowrap transition-[background-color,box-shadow,scale,color] duration-150 select-none focus-visible:outline-2 focus-visible:outline-offset-2 active:scale-[0.97] [&_svg]:size-4 [&_svg]:shrink-0 ${size === 'lg' ? 'h-11 text-[15px]' : 'h-9 text-sm'} ${variant === 'quiet' ? 'px-0' : size === 'lg' ? 'px-[1.125rem]' : 'px-3.5'} ${recipes[variant]}`}
|
|
65
|
+
>
|
|
66
|
+
{icon}
|
|
67
|
+
{children}
|
|
68
|
+
{arrow ? (
|
|
69
|
+
<span className="-mr-0.5 inline-flex transition-transform duration-200 group-hover/button:translate-x-0.5">
|
|
70
|
+
<ArrowRightIcon />
|
|
71
|
+
</span>
|
|
72
|
+
) : null}
|
|
73
|
+
</a>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { IconButton as NinnaIconButton, type IconButtonProps as NinnaIconButtonProps } from '@ninna-ui/primitives';
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
|
|
4
|
+
import { StatusIndicator, type StatusTone } from '../feedback/StatusIndicator';
|
|
5
|
+
import { tabbable } from '../foundations/KeyboardFocus';
|
|
6
|
+
|
|
7
|
+
export type IconButtonProps = Omit<NinnaIconButtonProps, 'color' | 'radius' | 'size' | 'variant'> & {
|
|
8
|
+
variant?: 'header' | 'quiet' | 'title-bar';
|
|
9
|
+
tone?: StatusTone | 'accent';
|
|
10
|
+
notification?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|
14
|
+
({ variant = 'quiet', tone = 'neutral', className = '', notification, icon, ...props }, ref) => (
|
|
15
|
+
<NinnaIconButton
|
|
16
|
+
ref={ref}
|
|
17
|
+
{...tabbable}
|
|
18
|
+
aria-description={notification}
|
|
19
|
+
{...props}
|
|
20
|
+
icon={
|
|
21
|
+
notification ? (
|
|
22
|
+
<span className="relative block size-full">
|
|
23
|
+
{icon}
|
|
24
|
+
<StatusIndicator
|
|
25
|
+
tone="warning"
|
|
26
|
+
size="sm"
|
|
27
|
+
className="ring-base-100 absolute -top-0.5 -right-0.5 ring-2"
|
|
28
|
+
/>
|
|
29
|
+
</span>
|
|
30
|
+
) : (
|
|
31
|
+
icon
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
variant="ghost"
|
|
35
|
+
color={tone === 'accent' ? 'primary' : tone}
|
|
36
|
+
size="sm"
|
|
37
|
+
radius="lg"
|
|
38
|
+
className={
|
|
39
|
+
// T3 Code's ghost icon button: muted until hovered, on an accent fill.
|
|
40
|
+
(variant === 'header'
|
|
41
|
+
? 'text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 data-[state=open]:text-base-content size-8 rounded-md p-0 before:-inset-1 **:data-[slot=icon]:size-[18px] '
|
|
42
|
+
: variant === 'title-bar'
|
|
43
|
+
? // The title bar's 28px row of controls, with 16px icons.
|
|
44
|
+
'text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 data-[state=open]:text-base-content size-7 rounded-md p-0 before:-inset-1.5 **:data-[slot=icon]:size-4 '
|
|
45
|
+
: tone === 'neutral'
|
|
46
|
+
? 'text-base-700 hover:bg-base-200 hover:text-base-content data-[state=open]:bg-base-200 rounded-md '
|
|
47
|
+
: 'rounded-md ') +
|
|
48
|
+
'transition-[background-color,color,scale] active:scale-[0.94] [&_svg]:size-full ' +
|
|
49
|
+
className
|
|
50
|
+
}
|
|
51
|
+
/>
|
|
52
|
+
),
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
IconButton.displayName = 'IconButton';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { MonitorIcon, MoonIcon, SunIcon } from 'lucide-react';
|
|
2
|
+
|
|
3
|
+
import { useDesignSystemLabels } from '../foundations/DesignSystemProvider';
|
|
4
|
+
import { tabbable } from '../foundations/KeyboardFocus';
|
|
5
|
+
import type { ThemePreference } from '../foundations/Theme';
|
|
6
|
+
|
|
7
|
+
const choices = [
|
|
8
|
+
{ value: 'system', Icon: MonitorIcon },
|
|
9
|
+
{ value: 'light', Icon: SunIcon },
|
|
10
|
+
{ value: 'dark', Icon: MoonIcon },
|
|
11
|
+
] as const;
|
|
12
|
+
|
|
13
|
+
/** Three small segments for the colour scheme: follow the system, light or dark. */
|
|
14
|
+
export function ThemeSwitch({
|
|
15
|
+
value,
|
|
16
|
+
onChange,
|
|
17
|
+
}: {
|
|
18
|
+
value: ThemePreference;
|
|
19
|
+
onChange: (value: ThemePreference) => void;
|
|
20
|
+
}) {
|
|
21
|
+
const labels = useDesignSystemLabels().theme;
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div
|
|
25
|
+
role="radiogroup"
|
|
26
|
+
aria-label={labels.label}
|
|
27
|
+
className="border-base-300 bg-base-100/70 dark:bg-base-200/60 inline-flex h-8 items-center gap-0.5 rounded-full border p-0.5"
|
|
28
|
+
>
|
|
29
|
+
{choices.map(({ value: choice, Icon }) => (
|
|
30
|
+
<button
|
|
31
|
+
key={choice}
|
|
32
|
+
{...tabbable}
|
|
33
|
+
type="button"
|
|
34
|
+
role="radio"
|
|
35
|
+
aria-checked={value === choice}
|
|
36
|
+
aria-label={labels[choice]}
|
|
37
|
+
title={labels[choice]}
|
|
38
|
+
onClick={() => onChange(choice)}
|
|
39
|
+
className="text-base-600 hover:text-base-content aria-checked:bg-base-200 aria-checked:text-base-content focus-visible:outline-primary dark:aria-checked:bg-base-400/70 inline-flex size-7 items-center justify-center rounded-full transition-colors focus-visible:outline-2 aria-checked:shadow-xs/10 [&_svg]:size-[15px]"
|
|
40
|
+
>
|
|
41
|
+
<Icon />
|
|
42
|
+
</button>
|
|
43
|
+
))}
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Text } from '../typography/Typography';
|
|
4
|
+
|
|
5
|
+
export function CollectionSectionHeader({ children }: { children: ReactNode }) {
|
|
6
|
+
return (
|
|
7
|
+
<div className="border-base-300 bg-base-100/65 flex h-10 items-center border-b px-3" role="presentation">
|
|
8
|
+
<Text as="span" className="shrink-0 tracking-[0.12em]" variant="overline">
|
|
9
|
+
{children}
|
|
10
|
+
</Text>
|
|
11
|
+
</div>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Button } from '../actions/Button';
|
|
4
|
+
import { Stack } from '../layout/Flow';
|
|
5
|
+
import { Heading, Text } from '../typography/Typography';
|
|
6
|
+
|
|
7
|
+
const page = { layout: 'max-w-lg px-6 py-16', icon: '[&>svg]:size-8', space: 'group' } as const;
|
|
8
|
+
const variants = {
|
|
9
|
+
page,
|
|
10
|
+
/** A placeholder outlining the content that will fill the region. */
|
|
11
|
+
framed: page,
|
|
12
|
+
/** Fits inside a panel or popover instead of owning a page region. */
|
|
13
|
+
compact: { layout: 'max-w-64 px-3 py-6', icon: '[&>svg]:size-6', space: 'related' },
|
|
14
|
+
/** A quiet empty state with the same surface as dashboard content. */
|
|
15
|
+
panel: { layout: 'max-w-md px-4 py-5', icon: '[&>svg]:size-6', space: 'related' },
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
interface CollectionStateProps {
|
|
19
|
+
actionLabel?: string;
|
|
20
|
+
description: string;
|
|
21
|
+
icon?: ReactNode;
|
|
22
|
+
onAction?: () => void;
|
|
23
|
+
title: string;
|
|
24
|
+
variant?: keyof typeof variants;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function CollectionState({
|
|
28
|
+
actionLabel,
|
|
29
|
+
description,
|
|
30
|
+
icon,
|
|
31
|
+
onAction,
|
|
32
|
+
title,
|
|
33
|
+
variant = 'page',
|
|
34
|
+
}: CollectionStateProps) {
|
|
35
|
+
const compact = variant === 'compact' || variant === 'panel';
|
|
36
|
+
const state = (
|
|
37
|
+
<Stack
|
|
38
|
+
align="center"
|
|
39
|
+
space={variants[variant].space}
|
|
40
|
+
className={`mx-auto text-center ${variants[variant].layout}`}
|
|
41
|
+
>
|
|
42
|
+
{icon ? <span className={`text-base-500 ${variants[variant].icon}`}>{icon}</span> : null}
|
|
43
|
+
<Stack space="tight">
|
|
44
|
+
{compact ? (
|
|
45
|
+
<Text variant="label">{title}</Text>
|
|
46
|
+
) : (
|
|
47
|
+
<Heading as="h2" variant="subsection">
|
|
48
|
+
{title}
|
|
49
|
+
</Heading>
|
|
50
|
+
)}
|
|
51
|
+
<Text variant={compact ? 'caption' : 'description'} tone="muted">
|
|
52
|
+
{description}
|
|
53
|
+
</Text>
|
|
54
|
+
</Stack>
|
|
55
|
+
{actionLabel && onAction ? (
|
|
56
|
+
<Button type="button" onClick={onAction} variant="secondary">
|
|
57
|
+
{actionLabel}
|
|
58
|
+
</Button>
|
|
59
|
+
) : null}
|
|
60
|
+
</Stack>
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return variant === 'framed' || variant === 'panel' ? (
|
|
64
|
+
<div
|
|
65
|
+
className={
|
|
66
|
+
variant === 'panel'
|
|
67
|
+
? 'border-base-300 bg-base-100 rounded-xl border'
|
|
68
|
+
: 'border-base-300 rounded-xl border border-dashed'
|
|
69
|
+
}
|
|
70
|
+
>
|
|
71
|
+
{state}
|
|
72
|
+
</div>
|
|
73
|
+
) : (
|
|
74
|
+
state
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const columnWidths = {
|
|
2
|
+
primary: 'minmax(0, 2.5fr)',
|
|
3
|
+
secondary: 'minmax(0, 1.5fr)',
|
|
4
|
+
value: 'minmax(0, 1fr)',
|
|
5
|
+
compact: '4rem',
|
|
6
|
+
numeric: '5rem',
|
|
7
|
+
index: '2.5rem',
|
|
8
|
+
action: '1.5rem',
|
|
9
|
+
wide: '14rem',
|
|
10
|
+
} as const;
|
|
11
|
+
|
|
12
|
+
export const columnBreakpoints = { primary: 0, secondary: 640, tertiary: 900 } as const;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useLayoutEffect, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
export function useCollectionViewport() {
|
|
4
|
+
const [collectionElement, setCollectionElement] = useState<HTMLDivElement | null>(null);
|
|
5
|
+
const [geometry, setGeometry] = useState({ scrollMargin: 0, width: 0 });
|
|
6
|
+
|
|
7
|
+
useLayoutEffect(() => {
|
|
8
|
+
if (!collectionElement) return;
|
|
9
|
+
|
|
10
|
+
const measure = () => {
|
|
11
|
+
const collection = collectionElement.getBoundingClientRect();
|
|
12
|
+
const next = {
|
|
13
|
+
scrollMargin: collection.top + window.scrollY,
|
|
14
|
+
width: collection.width,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
setGeometry((current) =>
|
|
18
|
+
current.width === next.width && current.scrollMargin === next.scrollMargin ? current : next,
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
const observer = new ResizeObserver(measure);
|
|
22
|
+
|
|
23
|
+
observer.observe(collectionElement);
|
|
24
|
+
|
|
25
|
+
// Ancestor sizes can move the collection without changing its own size.
|
|
26
|
+
for (let ancestor = collectionElement.parentElement; ancestor; ancestor = ancestor.parentElement) {
|
|
27
|
+
observer.observe(ancestor);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
window.addEventListener('resize', measure);
|
|
31
|
+
measure();
|
|
32
|
+
|
|
33
|
+
return () => {
|
|
34
|
+
observer.disconnect();
|
|
35
|
+
window.removeEventListener('resize', measure);
|
|
36
|
+
};
|
|
37
|
+
}, [collectionElement]);
|
|
38
|
+
|
|
39
|
+
return { ...geometry, setCollectionElement };
|
|
40
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/* oxlint-disable react/only-export-components -- Compound members are exported through DataRow. */
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
import { SkeletonLoader } from '../feedback/SkeletonLoader';
|
|
5
|
+
import { LinkBox } from '../typography/Link';
|
|
6
|
+
import { Text } from '../typography/Typography';
|
|
7
|
+
|
|
8
|
+
function DataRowRoot({
|
|
9
|
+
children,
|
|
10
|
+
interactive,
|
|
11
|
+
rowIndex,
|
|
12
|
+
}: {
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
interactive?: boolean;
|
|
15
|
+
rowIndex: number;
|
|
16
|
+
}) {
|
|
17
|
+
return (
|
|
18
|
+
<LinkBox
|
|
19
|
+
role="row"
|
|
20
|
+
aria-rowindex={rowIndex}
|
|
21
|
+
className={`group group/media-item border-base-300/60 grid h-full min-w-0 grid-cols-(--lar-list-columns) items-center gap-4 border-b px-3 transition-colors motion-reduce:transition-none ${interactive ? 'hover:bg-base-100 focus-within:bg-base-100' : ''}`}
|
|
22
|
+
>
|
|
23
|
+
{children}
|
|
24
|
+
</LinkBox>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
type DataRowPrimaryProps =
|
|
29
|
+
| {
|
|
30
|
+
artwork?: ReactNode;
|
|
31
|
+
detail?: ReactNode;
|
|
32
|
+
loading?: false;
|
|
33
|
+
subtitle?: ReactNode;
|
|
34
|
+
title: string;
|
|
35
|
+
}
|
|
36
|
+
| {
|
|
37
|
+
artwork?: boolean;
|
|
38
|
+
loading: true;
|
|
39
|
+
subtitle?: boolean;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function DataRowPrimary(props: DataRowPrimaryProps) {
|
|
43
|
+
const artwork = props.loading
|
|
44
|
+
? props.artwork !== false && <SkeletonLoader.Shape presentation="artwork" />
|
|
45
|
+
: props.artwork;
|
|
46
|
+
const subtitle = props.loading ? props.subtitle !== false : Boolean(props.subtitle);
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<span className="flex min-w-0 items-center gap-3">
|
|
50
|
+
{artwork ? <span className="size-10 shrink-0">{artwork}</span> : null}
|
|
51
|
+
<span className="min-w-0 flex-1">
|
|
52
|
+
<Text
|
|
53
|
+
as="span"
|
|
54
|
+
className="block"
|
|
55
|
+
truncate
|
|
56
|
+
variant="label"
|
|
57
|
+
loading={props.loading}
|
|
58
|
+
title={props.loading ? undefined : props.title}
|
|
59
|
+
>
|
|
60
|
+
{!props.loading && props.title}
|
|
61
|
+
</Text>
|
|
62
|
+
{subtitle ? (
|
|
63
|
+
<Text as="span" className="block" truncate variant="caption" tone="muted" loading={props.loading}>
|
|
64
|
+
{!props.loading && props.subtitle}
|
|
65
|
+
</Text>
|
|
66
|
+
) : null}
|
|
67
|
+
</span>
|
|
68
|
+
{!props.loading && props.detail ? (
|
|
69
|
+
<Text as="span" className="ml-auto shrink-0" variant="caption" tone="muted">
|
|
70
|
+
{props.detail}
|
|
71
|
+
</Text>
|
|
72
|
+
) : null}
|
|
73
|
+
</span>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const DataRow = Object.assign(DataRowRoot, {
|
|
78
|
+
Primary: DataRowPrimary,
|
|
79
|
+
});
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { ChevronRightIcon } from 'lucide-react';
|
|
2
|
+
import { type ComponentPropsWithoutRef, createContext, type ReactNode, useContext } from 'react';
|
|
3
|
+
|
|
4
|
+
import { SkeletonLoader } from '../feedback/SkeletonLoader';
|
|
5
|
+
import { tabbable } from '../foundations/KeyboardFocus';
|
|
6
|
+
import { Stack } from '../layout/Flow';
|
|
7
|
+
import { LinkBox, LinkOverlay } from '../typography/Link';
|
|
8
|
+
import { Text } from '../typography/Typography';
|
|
9
|
+
|
|
10
|
+
const ResultListContext = createContext({ compact: false, listbox: true });
|
|
11
|
+
|
|
12
|
+
interface ResultListProps extends Omit<ComponentPropsWithoutRef<'div'>, 'className' | 'style'> {
|
|
13
|
+
label: string;
|
|
14
|
+
loading?: boolean;
|
|
15
|
+
loadingLabel?: string;
|
|
16
|
+
density?: 'compact' | 'comfortable';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function ResultList({
|
|
20
|
+
children,
|
|
21
|
+
label,
|
|
22
|
+
loading = false,
|
|
23
|
+
loadingLabel = label,
|
|
24
|
+
density = 'comfortable',
|
|
25
|
+
role = 'listbox',
|
|
26
|
+
...props
|
|
27
|
+
}: ResultListProps) {
|
|
28
|
+
return (
|
|
29
|
+
<ResultListContext.Provider value={{ compact: density === 'compact', listbox: role === 'listbox' }}>
|
|
30
|
+
<SkeletonLoader loading={loading} label={loadingLabel}>
|
|
31
|
+
<div
|
|
32
|
+
{...props}
|
|
33
|
+
role={role}
|
|
34
|
+
aria-label={label}
|
|
35
|
+
aria-busy={loading || props['aria-busy']}
|
|
36
|
+
className="flex flex-col gap-1"
|
|
37
|
+
>
|
|
38
|
+
{loading ? Array.from({ length: 8 }, (_, index) => <ResultRow key={index} loading />) : children}
|
|
39
|
+
</div>
|
|
40
|
+
</SkeletonLoader>
|
|
41
|
+
</ResultListContext.Provider>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ResultRowProps extends Pick<
|
|
46
|
+
ComponentPropsWithoutRef<'button'>,
|
|
47
|
+
'disabled' | 'id' | 'onPointerMove' | 'tabIndex'
|
|
48
|
+
> {
|
|
49
|
+
artwork: ReactNode;
|
|
50
|
+
kind: string;
|
|
51
|
+
onSelect: () => void;
|
|
52
|
+
href?: string;
|
|
53
|
+
selected?: boolean;
|
|
54
|
+
/** `icon` sets a small glyph in a narrow column; `default` shows artwork. */
|
|
55
|
+
presentation?: 'default' | 'icon' | 'poster' | 'video';
|
|
56
|
+
current?: boolean;
|
|
57
|
+
subtitle?: string;
|
|
58
|
+
detail?: string;
|
|
59
|
+
title: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function ResultRow(props: ResultRowProps | { loading: true }) {
|
|
63
|
+
const { compact, listbox } = useContext(ResultListContext);
|
|
64
|
+
const loading = 'loading' in props;
|
|
65
|
+
const presentation = loading ? 'default' : props.presentation;
|
|
66
|
+
const classes = `grid w-full items-center rounded-md px-2 text-left ${presentation === 'poster' ? 'grid-cols-[4rem_minmax(0,1fr)_auto] gap-4 py-3' : presentation === 'video' ? 'grid-cols-[5rem_minmax(0,1fr)_auto] gap-4 py-3 sm:grid-cols-[10rem_minmax(0,1fr)_auto]' : presentation === 'icon' ? 'grid-cols-[1rem_minmax(0,1fr)] gap-3 py-2' : compact ? 'grid-cols-[2rem_minmax(0,1fr)] gap-2 py-1' : 'grid-cols-[2.75rem_minmax(0,1fr)] gap-3 py-2'}`;
|
|
67
|
+
const content = (
|
|
68
|
+
<>
|
|
69
|
+
{loading ? (
|
|
70
|
+
<SkeletonLoader.Shape presentation="artwork" />
|
|
71
|
+
) : presentation === 'icon' ? (
|
|
72
|
+
<span aria-hidden="true" className="text-base-600 flex size-4 [&_svg]:size-4">
|
|
73
|
+
{props.artwork}
|
|
74
|
+
</span>
|
|
75
|
+
) : (
|
|
76
|
+
props.artwork
|
|
77
|
+
)}
|
|
78
|
+
<Stack space="none" className="min-w-0">
|
|
79
|
+
<Text as="span" variant="label" truncate loading={loading}>
|
|
80
|
+
{!loading &&
|
|
81
|
+
(props.href && !listbox ? (
|
|
82
|
+
<LinkOverlay
|
|
83
|
+
href={props.href}
|
|
84
|
+
onNavigate={props.onSelect}
|
|
85
|
+
aria-label={resultLabel(props)}
|
|
86
|
+
aria-current={props.current ? 'page' : undefined}
|
|
87
|
+
>
|
|
88
|
+
{props.title}
|
|
89
|
+
</LinkOverlay>
|
|
90
|
+
) : (
|
|
91
|
+
props.title
|
|
92
|
+
))}
|
|
93
|
+
</Text>
|
|
94
|
+
<Text as="span" variant="caption" tone="muted" truncate loading={loading}>
|
|
95
|
+
{!loading && (props.subtitle ?? props.kind)}
|
|
96
|
+
</Text>
|
|
97
|
+
{!loading && props.detail ? (
|
|
98
|
+
<Text as="span" variant="caption" tone="muted" className="line-clamp-2 wrap-break-word">
|
|
99
|
+
{props.detail}
|
|
100
|
+
</Text>
|
|
101
|
+
) : null}
|
|
102
|
+
</Stack>
|
|
103
|
+
{presentation === 'poster' || presentation === 'video' ? (
|
|
104
|
+
<span aria-hidden="true" className="text-base-500 flex [&>svg]:size-4">
|
|
105
|
+
<ChevronRightIcon />
|
|
106
|
+
</span>
|
|
107
|
+
) : null}
|
|
108
|
+
</>
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
if (loading) return <div className={classes}>{content}</div>;
|
|
112
|
+
|
|
113
|
+
const {
|
|
114
|
+
artwork: _artwork,
|
|
115
|
+
href,
|
|
116
|
+
kind: _kind,
|
|
117
|
+
onSelect,
|
|
118
|
+
selected = false,
|
|
119
|
+
presentation: _presentation,
|
|
120
|
+
current = false,
|
|
121
|
+
subtitle: _subtitle,
|
|
122
|
+
detail: _detail,
|
|
123
|
+
title: _title,
|
|
124
|
+
...buttonProps
|
|
125
|
+
} = props;
|
|
126
|
+
|
|
127
|
+
const row =
|
|
128
|
+
href && !listbox ? (
|
|
129
|
+
<LinkBox
|
|
130
|
+
className={`${classes} hover:bg-base-100 focus-within:bg-base-100 has-[[aria-current=page]]:bg-base-100 has-[[aria-current=page]]:ring-base-300 has-[[aria-current=page]]:ring-1`}
|
|
131
|
+
>
|
|
132
|
+
{content}
|
|
133
|
+
</LinkBox>
|
|
134
|
+
) : (
|
|
135
|
+
<button
|
|
136
|
+
{...tabbable}
|
|
137
|
+
{...buttonProps}
|
|
138
|
+
type="button"
|
|
139
|
+
role={listbox ? 'option' : undefined}
|
|
140
|
+
aria-label={resultLabel(props)}
|
|
141
|
+
aria-selected={listbox ? selected : undefined}
|
|
142
|
+
aria-current={current ? 'page' : undefined}
|
|
143
|
+
className={`${classes} hover:bg-base-100 aria-selected:bg-primary/10 aria-selected:ring-primary/30 focus-visible:outline-primary focus-visible:outline-2 disabled:pointer-events-none disabled:opacity-60 aria-selected:ring-1 aria-selected:ring-inset`}
|
|
144
|
+
onClick={onSelect}
|
|
145
|
+
>
|
|
146
|
+
{content}
|
|
147
|
+
</button>
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
return listbox ? row : <div role="listitem">{row}</div>;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** The row's accessible name: what it shows, then its kind, so two rows with one title still differ. */
|
|
154
|
+
function resultLabel({ title, subtitle, kind }: ResultRowProps): string {
|
|
155
|
+
return [title, subtitle, kind].filter(Boolean).join(', ');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function ResultEmpty({ children }: { children: ReactNode }) {
|
|
159
|
+
return (
|
|
160
|
+
<Text as="span" tone="muted" className="px-3 py-4 text-center">
|
|
161
|
+
{children}
|
|
162
|
+
</Text>
|
|
163
|
+
);
|
|
164
|
+
}
|