@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,63 @@
|
|
|
1
|
+
import { type ReactNode, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
interface AppShellProps {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
header: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** The page frame: a column whose header sticks to the top as glass. The document itself
|
|
9
|
+
* scrolls, so content passes under the header and Safari tints its toolbar to match. The header's hairline
|
|
10
|
+
* appears once the page has scrolled, as on t3.codes. */
|
|
11
|
+
export function AppShell({ children, header }: AppShellProps) {
|
|
12
|
+
const shell = useRef<HTMLDivElement>(null);
|
|
13
|
+
const headerContainer = useRef<HTMLDivElement>(null);
|
|
14
|
+
const scrolled = useDocumentScrolled();
|
|
15
|
+
|
|
16
|
+
useLayoutEffect(() => {
|
|
17
|
+
const container = headerContainer.current;
|
|
18
|
+
const root = shell.current;
|
|
19
|
+
|
|
20
|
+
if (!container || !root) return;
|
|
21
|
+
|
|
22
|
+
const measure = () => {
|
|
23
|
+
root.style.setProperty('--lar-header-height', `${container.getBoundingClientRect().height}px`);
|
|
24
|
+
};
|
|
25
|
+
const observer = new ResizeObserver(measure);
|
|
26
|
+
|
|
27
|
+
observer.observe(container);
|
|
28
|
+
measure();
|
|
29
|
+
|
|
30
|
+
return () => observer.disconnect();
|
|
31
|
+
}, []);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div
|
|
35
|
+
ref={shell}
|
|
36
|
+
className="flex min-h-dvh min-w-0 flex-col pr-[env(safe-area-inset-right)] pl-[env(safe-area-inset-left)]"
|
|
37
|
+
>
|
|
38
|
+
<div
|
|
39
|
+
ref={headerContainer}
|
|
40
|
+
data-scrolled={scrolled || undefined}
|
|
41
|
+
className="glass-bar data-scrolled:border-base-300 sticky top-0 z-50 shrink-0 border-b border-transparent pt-[env(safe-area-inset-top)] transition-[border-color] duration-300"
|
|
42
|
+
>
|
|
43
|
+
{header}
|
|
44
|
+
</div>
|
|
45
|
+
{children}
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function useDocumentScrolled() {
|
|
51
|
+
const [scrolled, setScrolled] = useState(false);
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const update = () => setScrolled(window.scrollY > 2);
|
|
55
|
+
|
|
56
|
+
update();
|
|
57
|
+
window.addEventListener('scroll', update, { passive: true });
|
|
58
|
+
|
|
59
|
+
return () => window.removeEventListener('scroll', update);
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
return scrolled;
|
|
63
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type ReactNode, useId } from 'react';
|
|
2
|
+
|
|
3
|
+
import { BrandMark } from '../display/BrandMark';
|
|
4
|
+
import { Heading, Text } from '../typography/Typography';
|
|
5
|
+
import { Inline, Stack } from './Flow';
|
|
6
|
+
|
|
7
|
+
interface AuthLayoutProps {
|
|
8
|
+
brandLabel: string;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
description?: string;
|
|
11
|
+
title: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** A page-centered card for signing in or first-run setup, shown before the app shell exists. */
|
|
15
|
+
export function AuthLayout({ brandLabel, children, description, title }: AuthLayoutProps) {
|
|
16
|
+
const titleId = useId();
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<main className="flex min-h-dvh items-center justify-center px-4 py-10">
|
|
20
|
+
<section
|
|
21
|
+
aria-labelledby={titleId}
|
|
22
|
+
className="border-base-300 bg-base-100 w-full max-w-sm rounded-2xl border p-6 shadow-[0_24px_64px_-32px_rgb(0_0_0/35%)] sm:p-8"
|
|
23
|
+
>
|
|
24
|
+
<Stack space="page">
|
|
25
|
+
<Stack space="related" className="items-center text-center">
|
|
26
|
+
<Inline align="baseline" space="tight" className="text-xl leading-none">
|
|
27
|
+
<BrandMark label={brandLabel} />
|
|
28
|
+
<span className="font-medium">Server</span>
|
|
29
|
+
</Inline>
|
|
30
|
+
<Heading id={titleId} as="h1" variant="section">
|
|
31
|
+
{title}
|
|
32
|
+
</Heading>
|
|
33
|
+
{description ? <Text tone="muted">{description}</Text> : null}
|
|
34
|
+
</Stack>
|
|
35
|
+
{children}
|
|
36
|
+
</Stack>
|
|
37
|
+
</section>
|
|
38
|
+
</main>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Container } from '@ninna-ui/layout';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface ContentContainerProps {
|
|
5
|
+
as?: 'div' | 'main';
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function ContentContainer({ as = 'div', children, className }: ContentContainerProps) {
|
|
11
|
+
return (
|
|
12
|
+
<Container as={as} maxWidth="full" padding={false} className={className ? `px-4 ${className}` : 'px-4'}>
|
|
13
|
+
{children}
|
|
14
|
+
</Container>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Flex as NinnaFlex,
|
|
3
|
+
type FlexProps,
|
|
4
|
+
Grid as NinnaResponsiveGrid,
|
|
5
|
+
SimpleGrid as NinnaGrid,
|
|
6
|
+
Stack as NinnaStack,
|
|
7
|
+
type StackProps as NinnaStackProps,
|
|
8
|
+
} from '@ninna-ui/layout';
|
|
9
|
+
import type { ComponentProps, ElementType } from 'react';
|
|
10
|
+
|
|
11
|
+
const spacing = { none: '0', tight: '1', related: '2', group: '3', section: '4', page: '6' } as const;
|
|
12
|
+
|
|
13
|
+
export type FlowSpace = keyof typeof spacing;
|
|
14
|
+
|
|
15
|
+
export type StackProps<C extends ElementType = 'div'> = Omit<NinnaStackProps<C>, 'gap' | 'direction'> & {
|
|
16
|
+
space?: FlowSpace;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function Stack<C extends ElementType = 'div'>({ space = 'group', ...props }: StackProps<C>) {
|
|
20
|
+
return <NinnaStack {...(props as NinnaStackProps<C>)} gap={spacing[space]} />;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type InlineProps<C extends ElementType> = Omit<FlexProps<C>, 'gap' | 'direction' | 'wrap'> & {
|
|
24
|
+
space?: FlowSpace;
|
|
25
|
+
wrap?: boolean;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export function Inline<C extends ElementType = 'div'>({ space = 'related', wrap, ...props }: InlineProps<C>) {
|
|
29
|
+
return <NinnaFlex {...(props as FlexProps<C>)} gap={spacing[space]} wrap={wrap ? 'wrap' : 'nowrap'} />;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type GridProps = Omit<ComponentProps<typeof NinnaGrid>, 'gap' | 'minChildWidth' | 'columns'> & {
|
|
33
|
+
variant?: 'metrics' | 'content' | 'overview' | 'details' | 'pairs' | 'posters';
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export function Grid({ variant = 'content', ...props }: GridProps) {
|
|
37
|
+
if (variant === 'posters')
|
|
38
|
+
return (
|
|
39
|
+
<NinnaGrid
|
|
40
|
+
{...props}
|
|
41
|
+
gap="4"
|
|
42
|
+
style={{ gridTemplateColumns: 'repeat(auto-fill, minmax(min(6.5rem, 100%), 1fr))' }}
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
if (variant === 'details') return <NinnaResponsiveGrid {...props} gap="6" columns={{ base: 1, md: 2 }} />;
|
|
47
|
+
|
|
48
|
+
if (variant === 'pairs') return <NinnaResponsiveGrid {...props} gap="3" columns={{ base: 1, lg: 2 }} />;
|
|
49
|
+
|
|
50
|
+
if (variant === 'overview')
|
|
51
|
+
return <NinnaResponsiveGrid {...props} gap="3" columns={{ base: 1, md: 2, lg: 3, '2xl': 4 }} />;
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<NinnaGrid {...props} gap="3" minChildWidth={variant === 'metrics' ? 'min(11rem, 100%)' : 'min(16rem, 100%)'} />
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Heading, Text } from '../typography/Typography';
|
|
4
|
+
import { ContentContainer } from './ContentContainer';
|
|
5
|
+
import { Stack } from './Flow';
|
|
6
|
+
|
|
7
|
+
interface PageLayoutProps {
|
|
8
|
+
label?: string;
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
header?: ReactNode;
|
|
11
|
+
title?: string;
|
|
12
|
+
description?: ReactNode;
|
|
13
|
+
variant?: 'default' | 'detail';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function PageLayout({ children, header, title, description, label, variant = 'default' }: PageLayoutProps) {
|
|
17
|
+
return (
|
|
18
|
+
<main aria-label={label} className="flex min-w-0 flex-1 flex-col [--lar-page-gutter:--spacing(4)]">
|
|
19
|
+
{header}
|
|
20
|
+
<ContentContainer className="pt-(--lar-page-gutter) pb-10 md:pb-12">
|
|
21
|
+
<Stack space={variant === 'detail' ? 'page' : 'section'}>
|
|
22
|
+
{title ? (
|
|
23
|
+
<Stack space="related">
|
|
24
|
+
<Heading as="h1" variant="page">
|
|
25
|
+
{title}
|
|
26
|
+
</Heading>
|
|
27
|
+
{description ? <Text tone="muted">{description}</Text> : null}
|
|
28
|
+
</Stack>
|
|
29
|
+
) : null}
|
|
30
|
+
{children}
|
|
31
|
+
</Stack>
|
|
32
|
+
</ContentContainer>
|
|
33
|
+
</main>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { type ReactNode, useId } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Heading, Text } from '../typography/Typography';
|
|
4
|
+
|
|
5
|
+
const widths = {
|
|
6
|
+
narrow: 'max-w-[880px]',
|
|
7
|
+
default: 'max-w-[1200px]',
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
const spacing = {
|
|
11
|
+
hero: 'pt-16 pb-20 sm:pt-24 sm:pb-28',
|
|
12
|
+
default: 'py-12 sm:py-20',
|
|
13
|
+
tight: 'py-12 sm:py-20',
|
|
14
|
+
/** The last band before the footer, which follows a full section. */
|
|
15
|
+
closing: 'pt-0 pb-14 sm:pb-20',
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
interface PageSectionProps {
|
|
19
|
+
children: ReactNode;
|
|
20
|
+
id?: string;
|
|
21
|
+
width?: keyof typeof widths;
|
|
22
|
+
space?: keyof typeof spacing;
|
|
23
|
+
/** A raised band separates a section from the ones around it. */
|
|
24
|
+
tone?: 'plain' | 'raised';
|
|
25
|
+
/** Names the section for assistive technology when it has no SectionHeading. */
|
|
26
|
+
label?: string;
|
|
27
|
+
background?: ReactNode;
|
|
28
|
+
/** The section's SectionHeading, set above the content with room to breathe. */
|
|
29
|
+
heading?: ReactNode;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** One band of a marketing page, centred in the page column. */
|
|
33
|
+
export function PageSection({
|
|
34
|
+
children,
|
|
35
|
+
id,
|
|
36
|
+
width = 'default',
|
|
37
|
+
space = 'default',
|
|
38
|
+
tone = 'plain',
|
|
39
|
+
label,
|
|
40
|
+
background,
|
|
41
|
+
heading,
|
|
42
|
+
}: PageSectionProps) {
|
|
43
|
+
return (
|
|
44
|
+
<section
|
|
45
|
+
id={id}
|
|
46
|
+
aria-label={label}
|
|
47
|
+
className={`relative isolate scroll-mt-16 ${tone === 'raised' ? 'border-base-300/80 bg-base-100/70 dark:bg-base-100/50 border-y' : ''}`}
|
|
48
|
+
>
|
|
49
|
+
{background}
|
|
50
|
+
<div className={`mx-auto w-full px-5 sm:px-8 ${widths[width]} ${spacing[space]}`}>
|
|
51
|
+
{heading ? <div className="lar-reveal mb-8 sm:mb-16">{heading}</div> : null}
|
|
52
|
+
{children}
|
|
53
|
+
</div>
|
|
54
|
+
</section>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface SectionHeadingProps {
|
|
59
|
+
eyebrow?: string;
|
|
60
|
+
title: ReactNode;
|
|
61
|
+
lead?: ReactNode;
|
|
62
|
+
align?: 'center' | 'start';
|
|
63
|
+
level?: 'h1' | 'h2';
|
|
64
|
+
size?: 'display' | 'headline';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** The eyebrow, title and lead that open a section. */
|
|
68
|
+
export function SectionHeading({
|
|
69
|
+
eyebrow,
|
|
70
|
+
title,
|
|
71
|
+
lead,
|
|
72
|
+
align = 'center',
|
|
73
|
+
level = 'h2',
|
|
74
|
+
size = 'headline',
|
|
75
|
+
}: SectionHeadingProps) {
|
|
76
|
+
const id = useId();
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<header
|
|
80
|
+
aria-labelledby={id}
|
|
81
|
+
className={`flex flex-col gap-4 ${align === 'center' ? 'mx-auto max-w-[760px] items-center text-center' : 'max-w-[640px]'}`}
|
|
82
|
+
>
|
|
83
|
+
{eyebrow ? <Eyebrow>{eyebrow}</Eyebrow> : null}
|
|
84
|
+
<Heading id={id} as={level} variant={size}>
|
|
85
|
+
{title}
|
|
86
|
+
</Heading>
|
|
87
|
+
{lead ? (
|
|
88
|
+
<Text variant="lead" tone="muted" className={align === 'center' ? 'max-w-[620px]' : ''}>
|
|
89
|
+
{lead}
|
|
90
|
+
</Text>
|
|
91
|
+
) : null}
|
|
92
|
+
</header>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** A short label above a title, in the brand navy. */
|
|
97
|
+
export function Eyebrow({ children }: { children: ReactNode }) {
|
|
98
|
+
return (
|
|
99
|
+
<span className="text-primary text-[13px] font-semibold tracking-[-0.005em] dark:text-[color-mix(in_srgb,var(--color-primary)_50%,white)]">
|
|
100
|
+
{children}
|
|
101
|
+
</span>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef } from 'react';
|
|
2
|
+
|
|
3
|
+
export type ScrollAreaProps = Omit<ComponentPropsWithoutRef<'div'>, 'className' | 'style'>;
|
|
4
|
+
|
|
5
|
+
export function ScrollArea(props: ScrollAreaProps) {
|
|
6
|
+
return <div {...props} className="max-h-64 min-h-0 overflow-y-auto overscroll-contain pr-1" />;
|
|
7
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type ReactNode, useId } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Badge } from '../display/Badge';
|
|
4
|
+
import { Heading, Text } from '../typography/Typography';
|
|
5
|
+
import { Inline, Stack } from './Flow';
|
|
6
|
+
|
|
7
|
+
interface SectionProps {
|
|
8
|
+
title: string;
|
|
9
|
+
description?: ReactNode;
|
|
10
|
+
count?: ReactNode;
|
|
11
|
+
actions?: ReactNode;
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
level?: 'h2' | 'h3' | 'h4';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function Section({ title, description, count, actions, children, level = 'h2' }: SectionProps) {
|
|
17
|
+
const id = useId();
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Stack as="section" space="section" aria-labelledby={id}>
|
|
21
|
+
<Stack space="tight">
|
|
22
|
+
<Inline justify="between" align="center">
|
|
23
|
+
<Inline align="center">
|
|
24
|
+
<Heading id={id} as={level} variant={level === 'h2' ? 'section' : 'subsection'}>
|
|
25
|
+
{title}
|
|
26
|
+
</Heading>
|
|
27
|
+
{count != null ? <Badge>{count}</Badge> : null}
|
|
28
|
+
</Inline>
|
|
29
|
+
{actions}
|
|
30
|
+
</Inline>
|
|
31
|
+
{description ? <Text tone="muted">{description}</Text> : null}
|
|
32
|
+
</Stack>
|
|
33
|
+
{children}
|
|
34
|
+
</Stack>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { MenuIcon, XIcon } from 'lucide-react';
|
|
2
|
+
import { type ReactNode, useEffect, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
import { tabbable } from '../foundations/KeyboardFocus';
|
|
5
|
+
|
|
6
|
+
export interface SiteLink {
|
|
7
|
+
label: string;
|
|
8
|
+
href: string;
|
|
9
|
+
current?: boolean;
|
|
10
|
+
external?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface SiteShellProps {
|
|
14
|
+
skipLabel: string;
|
|
15
|
+
header: ReactNode;
|
|
16
|
+
footer: ReactNode;
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** The website frame: a glass header that stays on top while the document scrolls under it, then the footer. */
|
|
21
|
+
export function SiteShell({ skipLabel, header, footer, children }: SiteShellProps) {
|
|
22
|
+
const scrolled = useScrolled();
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div className="flex min-h-dvh min-w-0 flex-col overflow-x-clip pr-[env(safe-area-inset-right)] pl-[env(safe-area-inset-left)]">
|
|
26
|
+
<a
|
|
27
|
+
href="#content"
|
|
28
|
+
className="bg-base-100 sr-only z-[60] rounded-md px-3 py-2 text-sm font-medium focus:not-sr-only focus:fixed focus:top-3 focus:left-3"
|
|
29
|
+
>
|
|
30
|
+
{skipLabel}
|
|
31
|
+
</a>
|
|
32
|
+
<div
|
|
33
|
+
data-scrolled={scrolled || undefined}
|
|
34
|
+
className="glass-bar data-scrolled:border-base-300 sticky top-0 z-50 shrink-0 border-b border-transparent pt-[env(safe-area-inset-top)] transition-[border-color] duration-300"
|
|
35
|
+
>
|
|
36
|
+
{header}
|
|
37
|
+
</div>
|
|
38
|
+
<main id="content" className="flex-1">
|
|
39
|
+
{children}
|
|
40
|
+
</main>
|
|
41
|
+
{footer}
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface SiteHeaderProps {
|
|
47
|
+
brand: ReactNode;
|
|
48
|
+
links: readonly SiteLink[];
|
|
49
|
+
actions: ReactNode;
|
|
50
|
+
/** Secondary controls, such as the theme switch: in the bar on wide screens and in the menu on narrow ones. */
|
|
51
|
+
utilities?: ReactNode;
|
|
52
|
+
menuLabel: string;
|
|
53
|
+
closeMenuLabel: string;
|
|
54
|
+
navigationLabel: string;
|
|
55
|
+
onNavigate: (href: string) => void;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function SiteHeader({
|
|
59
|
+
brand,
|
|
60
|
+
links,
|
|
61
|
+
actions,
|
|
62
|
+
utilities,
|
|
63
|
+
menuLabel,
|
|
64
|
+
closeMenuLabel,
|
|
65
|
+
navigationLabel,
|
|
66
|
+
onNavigate,
|
|
67
|
+
}: SiteHeaderProps) {
|
|
68
|
+
const [open, setOpen] = useState(false);
|
|
69
|
+
|
|
70
|
+
function follow(href: string) {
|
|
71
|
+
setOpen(false);
|
|
72
|
+
onNavigate(href);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<header className="mx-auto flex h-14 w-full max-w-[1200px] items-center gap-6 px-5 sm:px-8">
|
|
77
|
+
{brand}
|
|
78
|
+
<nav aria-label={navigationLabel} className="hidden items-center gap-1 md:flex">
|
|
79
|
+
{links.map((link) => (
|
|
80
|
+
<NavLink key={link.href} link={link} onNavigate={follow} />
|
|
81
|
+
))}
|
|
82
|
+
</nav>
|
|
83
|
+
<div className="ml-auto flex items-center gap-2 max-sm:[&>a]:hidden">
|
|
84
|
+
{utilities ? <div className="hidden md:contents">{utilities}</div> : null}
|
|
85
|
+
{actions}
|
|
86
|
+
</div>
|
|
87
|
+
<button
|
|
88
|
+
{...tabbable}
|
|
89
|
+
type="button"
|
|
90
|
+
aria-expanded={open}
|
|
91
|
+
aria-controls="site-menu"
|
|
92
|
+
aria-label={open ? closeMenuLabel : menuLabel}
|
|
93
|
+
onClick={() => setOpen((value) => !value)}
|
|
94
|
+
className="text-base-800 hover:bg-base-200 -mr-2 inline-flex size-9 items-center justify-center rounded-md transition-colors md:hidden [&_svg]:size-5"
|
|
95
|
+
>
|
|
96
|
+
{open ? <XIcon /> : <MenuIcon />}
|
|
97
|
+
</button>
|
|
98
|
+
{open ? (
|
|
99
|
+
<nav
|
|
100
|
+
id="site-menu"
|
|
101
|
+
aria-label={navigationLabel}
|
|
102
|
+
className="glass-menu absolute inset-x-3 top-[calc(100%+0.5rem)] flex flex-col gap-1 rounded-2xl p-2 md:hidden"
|
|
103
|
+
>
|
|
104
|
+
{links.map((link) => (
|
|
105
|
+
<NavLink key={link.href} link={link} onNavigate={follow} large />
|
|
106
|
+
))}
|
|
107
|
+
{utilities ? <div className="border-base-300 mt-1 border-t px-3 pt-3 pb-1">{utilities}</div> : null}
|
|
108
|
+
</nav>
|
|
109
|
+
) : null}
|
|
110
|
+
</header>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function NavLink({ link, onNavigate, large }: { link: SiteLink; onNavigate: (href: string) => void; large?: boolean }) {
|
|
115
|
+
return (
|
|
116
|
+
<a
|
|
117
|
+
{...tabbable}
|
|
118
|
+
href={link.href}
|
|
119
|
+
aria-current={link.current ? 'page' : undefined}
|
|
120
|
+
{...(link.external ? { target: '_blank', rel: 'noreferrer' } : {})}
|
|
121
|
+
onClick={(event) => {
|
|
122
|
+
if (link.external || event.metaKey || event.ctrlKey || event.shiftKey || event.button !== 0) return;
|
|
123
|
+
|
|
124
|
+
event.preventDefault();
|
|
125
|
+
onNavigate(link.href);
|
|
126
|
+
}}
|
|
127
|
+
className={`text-base-700 hover:text-base-content aria-[current=page]:text-base-content focus-visible:outline-primary rounded-md font-medium transition-colors focus-visible:outline-2 ${large ? 'hover:bg-base-200 px-3 py-2.5 text-base' : 'px-2.5 py-1.5 text-sm'}`}
|
|
128
|
+
>
|
|
129
|
+
{link.label}
|
|
130
|
+
</a>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
interface SiteFooterProps {
|
|
135
|
+
brand: ReactNode;
|
|
136
|
+
tagline: string;
|
|
137
|
+
columns: readonly { title: string; links: readonly SiteLink[] }[];
|
|
138
|
+
legal: string;
|
|
139
|
+
note: ReactNode;
|
|
140
|
+
onNavigate: (href: string) => void;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function SiteFooter({ brand, tagline, columns, legal, note, onNavigate }: SiteFooterProps) {
|
|
144
|
+
return (
|
|
145
|
+
<footer className="border-base-300 bg-base-50 border-t">
|
|
146
|
+
<div className="mx-auto grid w-full max-w-[1200px] grid-cols-2 gap-x-6 gap-y-10 px-5 pt-14 pb-10 sm:px-8 md:grid-cols-[1.4fr_repeat(4,1fr)]">
|
|
147
|
+
<div className="col-span-2 flex flex-col gap-3 md:col-span-1">
|
|
148
|
+
{brand}
|
|
149
|
+
<p className="text-base-700 max-w-64 text-sm leading-6">{tagline}</p>
|
|
150
|
+
</div>
|
|
151
|
+
{columns.map((column) => (
|
|
152
|
+
<div key={column.title} className="flex flex-col gap-3">
|
|
153
|
+
<h2 className="text-base-800 text-xs font-semibold tracking-[0.06em] uppercase">
|
|
154
|
+
{column.title}
|
|
155
|
+
</h2>
|
|
156
|
+
<ul className="flex flex-col gap-2">
|
|
157
|
+
{column.links.map((link) => (
|
|
158
|
+
<li key={link.href}>
|
|
159
|
+
<a
|
|
160
|
+
{...tabbable}
|
|
161
|
+
href={link.href}
|
|
162
|
+
{...(link.external ? { target: '_blank', rel: 'noreferrer' } : {})}
|
|
163
|
+
onClick={(event) => {
|
|
164
|
+
if (link.external || !link.href.startsWith('/')) return;
|
|
165
|
+
|
|
166
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey || event.button !== 0)
|
|
167
|
+
return;
|
|
168
|
+
|
|
169
|
+
event.preventDefault();
|
|
170
|
+
onNavigate(link.href);
|
|
171
|
+
}}
|
|
172
|
+
className="text-base-700 hover:text-base-content text-sm transition-colors"
|
|
173
|
+
>
|
|
174
|
+
{link.label}
|
|
175
|
+
</a>
|
|
176
|
+
</li>
|
|
177
|
+
))}
|
|
178
|
+
</ul>
|
|
179
|
+
</div>
|
|
180
|
+
))}
|
|
181
|
+
</div>
|
|
182
|
+
<div className="mx-auto w-full max-w-[1200px] px-5 sm:px-8">
|
|
183
|
+
<div className="border-base-300/70 text-base-700 flex flex-col gap-2 border-t py-6 text-xs sm:flex-row sm:items-center sm:justify-between">
|
|
184
|
+
<span>{legal}</span>
|
|
185
|
+
<span>{note}</span>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
</footer>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function useScrolled() {
|
|
193
|
+
const [scrolled, setScrolled] = useState(false);
|
|
194
|
+
|
|
195
|
+
useEffect(() => {
|
|
196
|
+
const update = () => setScrolled(window.scrollY > 4);
|
|
197
|
+
|
|
198
|
+
update();
|
|
199
|
+
window.addEventListener('scroll', update, { passive: true });
|
|
200
|
+
|
|
201
|
+
return () => window.removeEventListener('scroll', update);
|
|
202
|
+
}, []);
|
|
203
|
+
|
|
204
|
+
return scrolled;
|
|
205
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { ChevronDownIcon, ChevronRightIcon } from 'lucide-react';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
import { useDesignSystemLabels } from '../foundations/DesignSystemProvider';
|
|
5
|
+
import { tabbable } from '../foundations/KeyboardFocus';
|
|
6
|
+
|
|
7
|
+
interface TitleBarProps {
|
|
8
|
+
actions?: ReactNode;
|
|
9
|
+
/** The brand, a link home, before a divider and the title. */
|
|
10
|
+
brand: ReactNode;
|
|
11
|
+
search?: ReactNode;
|
|
12
|
+
title: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** T3 Code's 52px title bar: the brand and where you are on the left, tools on the right. Its own width,
|
|
16
|
+
* not the window's, decides when search folds to an icon; narrow screens close the gaps so the title keeps
|
|
17
|
+
* the room left. */
|
|
18
|
+
export function TitleBar({ actions, brand, search, title }: TitleBarProps) {
|
|
19
|
+
const labels = useDesignSystemLabels();
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<header
|
|
23
|
+
aria-label={labels.toolbar}
|
|
24
|
+
className="@container relative flex h-13 min-w-0 items-center gap-1 px-3 sm:gap-2 sm:px-4"
|
|
25
|
+
>
|
|
26
|
+
<div className="[&_a]:focus-visible:ring-primary flex shrink-0 items-center [&_a]:rounded-sm [&_a]:outline-none [&_a]:focus-visible:ring-2">
|
|
27
|
+
{brand}
|
|
28
|
+
</div>
|
|
29
|
+
<span aria-hidden="true" className="bg-base-300 mx-1 h-5 w-px shrink-0 max-sm:hidden" />
|
|
30
|
+
<div className="flex min-w-0 flex-1 items-center gap-1">{title}</div>
|
|
31
|
+
{search ? <div className="flex shrink-0">{search}</div> : null}
|
|
32
|
+
{actions ? <div className="flex shrink-0 items-center gap-1.5">{actions}</div> : null}
|
|
33
|
+
</header>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface TitleBarTrailItem {
|
|
38
|
+
key: string;
|
|
39
|
+
icon?: ReactNode;
|
|
40
|
+
label: string;
|
|
41
|
+
/** Makes the step a button, such as one switching to its siblings; `selectLabel` says where it leads. */
|
|
42
|
+
onSelect?: () => void;
|
|
43
|
+
selectLabel?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The title bar's location, T3's "project / thread": each step muted and chevron-separated, the current one
|
|
47
|
+
* in the foreground. Steps that switch somewhere are buttons with a chevron. Narrow screens show only the
|
|
48
|
+
* current step. */
|
|
49
|
+
export function TitleBarTrail({ items }: { items: readonly TitleBarTrailItem[] }) {
|
|
50
|
+
return (
|
|
51
|
+
<ol className="flex min-w-0 items-center gap-0.5 text-sm">
|
|
52
|
+
{items.map((item, index) => {
|
|
53
|
+
const last = index === items.length - 1;
|
|
54
|
+
const content = (
|
|
55
|
+
<>
|
|
56
|
+
{item.icon ? (
|
|
57
|
+
<span className="text-base-700 flex shrink-0 [&_svg]:size-4">{item.icon}</span>
|
|
58
|
+
) : null}
|
|
59
|
+
<span className="truncate">{item.label}</span>
|
|
60
|
+
</>
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<li
|
|
65
|
+
key={item.key}
|
|
66
|
+
aria-current={last ? 'page' : undefined}
|
|
67
|
+
className={`flex min-w-0 items-center gap-0.5 ${last ? 'text-base-content font-medium' : 'text-base-700 hidden shrink-0 sm:flex'}`}
|
|
68
|
+
>
|
|
69
|
+
{index > 0 ? (
|
|
70
|
+
<span aria-hidden="true" className="text-base-500 flex shrink-0 [&>svg]:size-3.5">
|
|
71
|
+
<ChevronRightIcon />
|
|
72
|
+
</span>
|
|
73
|
+
) : null}
|
|
74
|
+
{item.onSelect ? (
|
|
75
|
+
<button
|
|
76
|
+
{...tabbable}
|
|
77
|
+
type="button"
|
|
78
|
+
aria-haspopup="dialog"
|
|
79
|
+
aria-description={item.selectLabel}
|
|
80
|
+
title={item.selectLabel}
|
|
81
|
+
onClick={item.onSelect}
|
|
82
|
+
className="hover:bg-base-200 hover:text-base-content focus-visible:outline-primary dark:hover:bg-base-300 flex h-7 min-w-0 items-center gap-2 rounded-lg px-2 transition-colors focus-visible:outline-2"
|
|
83
|
+
>
|
|
84
|
+
{content}
|
|
85
|
+
<span aria-hidden="true" className="text-base-500 flex shrink-0 [&>svg]:size-3.5">
|
|
86
|
+
<ChevronDownIcon />
|
|
87
|
+
</span>
|
|
88
|
+
</button>
|
|
89
|
+
) : (
|
|
90
|
+
<span className="flex min-w-0 items-center gap-2 px-2">{content}</span>
|
|
91
|
+
)}
|
|
92
|
+
</li>
|
|
93
|
+
);
|
|
94
|
+
})}
|
|
95
|
+
</ol>
|
|
96
|
+
);
|
|
97
|
+
}
|