@lar-works/design-system 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/actions/Button.d.ts +39 -1
- package/dist/actions/Button.js +39 -9
- package/dist/actions/Button.js.map +1 -1
- package/dist/actions/ButtonLink.d.ts +5 -1
- package/dist/actions/ButtonLink.js +28 -2
- package/dist/actions/ButtonLink.js.map +1 -1
- package/dist/actions/ButtonRecipes.js +7 -0
- package/dist/actions/ButtonRecipes.js.map +1 -0
- package/dist/actions/IconButton.d.ts +2 -2
- package/dist/actions/IconButton.js +1 -1
- package/dist/actions/IconButton.js.map +1 -1
- package/dist/actions/ThemeSwitch.js +1 -1
- package/dist/board/ActivityLine.d.ts +36 -0
- package/dist/board/ActivityLine.js +144 -0
- package/dist/board/ActivityLine.js.map +1 -0
- package/dist/board/ActivityTrack.d.ts +11 -0
- package/dist/board/ActivityTrack.js +25 -0
- package/dist/board/ActivityTrack.js.map +1 -0
- package/dist/board/AddItem.d.ts +82 -0
- package/dist/board/AddItem.js +185 -0
- package/dist/board/AddItem.js.map +1 -0
- package/dist/board/Archive.d.ts +21 -0
- package/dist/board/Archive.js +63 -0
- package/dist/board/Archive.js.map +1 -0
- package/dist/board/Attention.d.ts +66 -0
- package/dist/board/Attention.js +122 -0
- package/dist/board/Attention.js.map +1 -0
- package/dist/board/BoardShell.d.ts +16 -0
- package/dist/board/BoardShell.js +35 -0
- package/dist/board/BoardShell.js.map +1 -0
- package/dist/board/BoardTitleBar.d.ts +50 -0
- package/dist/board/BoardTitleBar.js +125 -0
- package/dist/board/BoardTitleBar.js.map +1 -0
- package/dist/board/ButtonKinds.d.ts +24 -0
- package/dist/board/ButtonKinds.js +19 -0
- package/dist/board/ButtonKinds.js.map +1 -0
- package/dist/board/Cleanup.d.ts +8 -0
- package/dist/board/Cleanup.js +15 -0
- package/dist/board/Cleanup.js.map +1 -0
- package/dist/board/Counters.d.ts +101 -0
- package/dist/board/Counters.js +202 -0
- package/dist/board/Counters.js.map +1 -0
- package/dist/board/DataAttributes.d.ts +6 -0
- package/dist/board/Dependencies.d.ts +17 -0
- package/dist/board/Dependencies.js +44 -0
- package/dist/board/Dependencies.js.map +1 -0
- package/dist/board/Desk.d.ts +52 -0
- package/dist/board/Desk.js +130 -0
- package/dist/board/Desk.js.map +1 -0
- package/dist/board/Dossier.d.ts +100 -0
- package/dist/board/Dossier.js +194 -0
- package/dist/board/Dossier.js.map +1 -0
- package/dist/board/Filters.d.ts +33 -0
- package/dist/board/Filters.js +64 -0
- package/dist/board/Filters.js.map +1 -0
- package/dist/board/ItemDetails.d.ts +167 -0
- package/dist/board/ItemDetails.js +339 -0
- package/dist/board/ItemDetails.js.map +1 -0
- package/dist/board/ItemDialog.d.ts +73 -0
- package/dist/board/ItemDialog.js +140 -0
- package/dist/board/ItemDialog.js.map +1 -0
- package/dist/board/ItemParts.d.ts +42 -0
- package/dist/board/ItemParts.js +82 -0
- package/dist/board/ItemParts.js.map +1 -0
- package/dist/board/ItemProgress.d.ts +56 -0
- package/dist/board/ItemProgress.js +138 -0
- package/dist/board/ItemProgress.js.map +1 -0
- package/dist/board/List.d.ts +65 -0
- package/dist/board/List.js +118 -0
- package/dist/board/List.js.map +1 -0
- package/dist/board/LoadingScreen.d.ts +38 -0
- package/dist/board/LoadingScreen.js +74 -0
- package/dist/board/LoadingScreen.js.map +1 -0
- package/dist/board/NeedsYou.d.ts +13 -0
- package/dist/board/NeedsYou.js +31 -0
- package/dist/board/NeedsYou.js.map +1 -0
- package/dist/board/Onboarding.d.ts +53 -0
- package/dist/board/Onboarding.js +122 -0
- package/dist/board/Onboarding.js.map +1 -0
- package/dist/board/PartsList.d.ts +60 -0
- package/dist/board/PartsList.js +115 -0
- package/dist/board/PartsList.js.map +1 -0
- package/dist/board/ProjectIcon.d.ts +51 -0
- package/dist/board/ProjectIcon.js +120 -0
- package/dist/board/ProjectIcon.js.map +1 -0
- package/dist/board/PullRequests.d.ts +43 -0
- package/dist/board/PullRequests.js +83 -0
- package/dist/board/PullRequests.js.map +1 -0
- package/dist/board/RowStyles.js +14 -0
- package/dist/board/RowStyles.js.map +1 -0
- package/dist/board/Settings.d.ts +54 -0
- package/dist/board/Settings.js +112 -0
- package/dist/board/Settings.js.map +1 -0
- package/dist/board/Slices.d.ts +32 -0
- package/dist/board/Slices.js +88 -0
- package/dist/board/Slices.js.map +1 -0
- package/dist/board/SourceIcon.d.ts +12 -0
- package/dist/board/SourceIcon.js +24 -0
- package/dist/board/SourceIcon.js.map +1 -0
- package/dist/board/StagePane.d.ts +43 -0
- package/dist/board/StagePane.js +97 -0
- package/dist/board/StagePane.js.map +1 -0
- package/dist/board/StageRow.d.ts +141 -0
- package/dist/board/StageRow.js +287 -0
- package/dist/board/StageRow.js.map +1 -0
- package/dist/board/StageTrack.d.ts +18 -0
- package/dist/board/StageTrack.js +38 -0
- package/dist/board/StageTrack.js.map +1 -0
- package/dist/board/StartControls.d.ts +30 -0
- package/dist/board/StartControls.js +51 -0
- package/dist/board/StartControls.js.map +1 -0
- package/dist/board/StatusColors.d.ts +5 -0
- package/dist/board/StatusColors.js +17 -0
- package/dist/board/StatusColors.js.map +1 -0
- package/dist/board/StatusGlyph.d.ts +18 -0
- package/dist/board/StatusGlyph.js +51 -0
- package/dist/board/StatusGlyph.js.map +1 -0
- package/dist/board/Threads.d.ts +13 -0
- package/dist/board/Threads.js +35 -0
- package/dist/board/Threads.js.map +1 -0
- package/dist/board/TrackerLabels.d.ts +27 -0
- package/dist/board/TrackerLabels.js +56 -0
- package/dist/board/TrackerLabels.js.map +1 -0
- package/dist/board/UpdatePill.d.ts +52 -0
- package/dist/board/UpdatePill.js +188 -0
- package/dist/board/UpdatePill.js.map +1 -0
- package/dist/board/Vocabulary.d.ts +56 -0
- package/dist/board/Vocabulary.js +104 -0
- package/dist/board/Vocabulary.js.map +1 -0
- package/dist/board/Warnings.d.ts +35 -0
- package/dist/board/Warnings.js +85 -0
- package/dist/board/Warnings.js.map +1 -0
- package/dist/board/WorkMap.d.ts +136 -0
- package/dist/board/WorkMap.js +274 -0
- package/dist/board/WorkMap.js.map +1 -0
- package/dist/board/index.d.ts +42 -0
- package/dist/collections/CollectionState.d.ts +10 -1
- package/dist/collections/CollectionState.js +12 -5
- package/dist/collections/CollectionState.js.map +1 -1
- package/dist/collections/ResultList.js +1 -1
- package/dist/collections/ScrollRow.js +1 -1
- package/dist/collections/VirtualList.js +1 -1
- package/dist/display/Avatar.d.ts +5 -2
- package/dist/display/Avatar.js +2 -2
- package/dist/display/Avatar.js.map +1 -1
- package/dist/display/Badge.d.ts +6 -1
- package/dist/display/Badge.js +9 -4
- package/dist/display/Badge.js.map +1 -1
- package/dist/display/CheckList.js +1 -1
- package/dist/display/Comment.d.ts +12 -0
- package/dist/display/Comment.js +39 -0
- package/dist/display/Comment.js.map +1 -0
- package/dist/display/CopyButton.d.ts +10 -2
- package/dist/display/CopyButton.js +29 -16
- package/dist/display/CopyButton.js.map +1 -1
- package/dist/display/Diagram.d.ts +17 -0
- package/dist/display/Diagram.js +49 -0
- package/dist/display/Diagram.js.map +1 -0
- package/dist/display/ImagePicker.js +1 -1
- package/dist/display/InfoBox.js +2 -2
- package/dist/display/InsetPanel.d.ts +3 -1
- package/dist/display/InsetPanel.js +7 -4
- package/dist/display/InsetPanel.js.map +1 -1
- package/dist/display/ItemAction.js +2 -2
- package/dist/display/LabelChip.d.ts +26 -0
- package/dist/display/LabelChip.js +41 -0
- package/dist/display/LabelChip.js.map +1 -0
- package/dist/display/LabelTint.js +60 -0
- package/dist/display/LabelTint.js.map +1 -0
- package/dist/display/Person.d.ts +5 -0
- package/dist/display/Person.js +19 -0
- package/dist/display/Person.js.map +1 -0
- package/dist/display/PropertySheet.js +1 -1
- package/dist/display/RadioChoice.d.ts +9 -2
- package/dist/display/RadioChoice.js +5 -1
- package/dist/display/RadioChoice.js.map +1 -1
- package/dist/display/RatingLink.js +1 -1
- package/dist/display/RichText.d.ts +12 -0
- package/dist/display/RichText.js +94 -0
- package/dist/display/RichText.js.map +1 -0
- package/dist/display/RowList.js +1 -1
- package/dist/display/index.d.ts +6 -1
- package/dist/feedback/Alert.js +1 -1
- package/dist/feedback/AsyncState.js +1 -1
- package/dist/feedback/DismissButton.d.ts +12 -0
- package/dist/feedback/DismissButton.js +20 -0
- package/dist/feedback/DismissButton.js.map +1 -0
- package/dist/feedback/ErrorNotification.js +2 -0
- package/dist/feedback/ErrorNotification.js.map +1 -1
- package/dist/feedback/FormResult.d.ts +16 -0
- package/dist/feedback/FormResult.js +30 -0
- package/dist/feedback/FormResult.js.map +1 -0
- package/dist/feedback/LiveRegion.d.ts +7 -0
- package/dist/feedback/LiveRegion.js +15 -0
- package/dist/feedback/LiveRegion.js.map +1 -0
- package/dist/feedback/Loading.d.ts +19 -0
- package/dist/feedback/Loading.js +63 -0
- package/dist/feedback/Loading.js.map +1 -0
- package/dist/feedback/Notifications.d.ts +35 -1
- package/dist/feedback/Notifications.js +196 -4
- package/dist/feedback/Notifications.js.map +1 -1
- package/dist/feedback/Progress.d.ts +15 -0
- package/dist/feedback/Progress.js +38 -0
- package/dist/feedback/Progress.js.map +1 -0
- package/dist/feedback/ProgressStatusRow.js +1 -1
- package/dist/feedback/StatusIndicator.d.ts +6 -1
- package/dist/feedback/StatusIndicator.js +19 -5
- package/dist/feedback/StatusIndicator.js.map +1 -1
- package/dist/feedback/index.d.ts +8 -4
- package/dist/forms/Checkbox.js +1 -1
- package/dist/forms/ColorSwatches.d.ts +21 -0
- package/dist/forms/ColorSwatches.js +26 -0
- package/dist/forms/ColorSwatches.js.map +1 -0
- package/dist/forms/FormSection.d.ts +68 -6
- package/dist/forms/FormSection.js +139 -8
- package/dist/forms/FormSection.js.map +1 -1
- package/dist/forms/HiddenField.d.ts +6 -0
- package/dist/forms/HiddenField.js +13 -0
- package/dist/forms/HiddenField.js.map +1 -0
- package/dist/forms/Input.d.ts +12 -2
- package/dist/forms/Input.js +10 -3
- package/dist/forms/Input.js.map +1 -1
- package/dist/forms/LabelPicker.d.ts +43 -0
- package/dist/forms/LabelPicker.js +107 -0
- package/dist/forms/LabelPicker.js.map +1 -0
- package/dist/forms/MarkdownEditor.d.ts +21 -0
- package/dist/forms/MarkdownEditor.js +175 -0
- package/dist/forms/MarkdownEditor.js.map +1 -0
- package/dist/forms/MarkdownToolbar.js +204 -0
- package/dist/forms/MarkdownToolbar.js.map +1 -0
- package/dist/forms/OptionSelect.d.ts +30 -9
- package/dist/forms/OptionSelect.js +53 -13
- package/dist/forms/OptionSelect.js.map +1 -1
- package/dist/forms/Select.d.ts +4 -1
- package/dist/forms/Select.js +3 -1
- package/dist/forms/Select.js.map +1 -1
- package/dist/forms/Switch.d.ts +4 -1
- package/dist/forms/Switch.js +5 -2
- package/dist/forms/Switch.js.map +1 -1
- package/dist/forms/TagInput.js +1 -1
- package/dist/forms/index.d.ts +7 -3
- package/dist/foundations/AmbientMotion.d.ts +2 -0
- package/dist/foundations/AmbientMotion.js +39 -0
- package/dist/foundations/AmbientMotion.js.map +1 -0
- package/dist/foundations/DesignSystemProvider.d.ts +34 -0
- package/dist/foundations/DesignSystemProvider.js +26 -1
- package/dist/foundations/DesignSystemProvider.js.map +1 -1
- package/dist/foundations/index.d.ts +2 -1
- package/dist/icons/BrandIcons.d.ts +8 -2
- package/dist/icons/BrandIcons.js +14 -3
- package/dist/icons/BrandIcons.js.map +1 -1
- package/dist/icons/dynamic.d.ts +2 -0
- package/dist/icons/dynamic.js +1 -0
- package/dist/icons/index.d.ts +2 -2
- package/dist/icons/index.js +1 -1
- package/dist/icons.d.ts +2 -2
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +71 -10
- package/dist/index.js +78 -21
- package/dist/layout/Site.js +1 -1
- package/dist/layout/TitleBar.js +1 -1
- package/dist/layout/index.d.ts +2 -2
- package/dist/layout/index.js +3 -3
- package/dist/layout/toolbar/CommandPaletteTrigger.d.ts +17 -2
- package/dist/layout/toolbar/CommandPaletteTrigger.js +89 -6
- package/dist/layout/toolbar/CommandPaletteTrigger.js.map +1 -1
- package/dist/layout/toolbar/TriggerFit.js +56 -0
- package/dist/layout/toolbar/TriggerFit.js.map +1 -0
- package/dist/navigation/CollectionBrowseSelector.js +1 -1
- package/dist/navigation/CollectionViewToggle.d.ts +26 -0
- package/dist/navigation/CollectionViewToggle.js +54 -23
- package/dist/navigation/CollectionViewToggle.js.map +1 -1
- package/dist/navigation/DrilldownBrowseSelector.js +1 -1
- package/dist/navigation/FolderSelector.js +2 -2
- package/dist/navigation/SortMenu.d.ts +10 -0
- package/dist/navigation/SortMenu.js +33 -0
- package/dist/navigation/SortMenu.js.map +1 -0
- package/dist/navigation/index.d.ts +3 -2
- package/dist/overlays/CommandPalette.d.ts +38 -4
- package/dist/overlays/CommandPalette.js +140 -54
- package/dist/overlays/CommandPalette.js.map +1 -1
- package/dist/overlays/Drawer.js +1 -1
- package/dist/overlays/DropdownMenu.d.ts +7 -1
- package/dist/overlays/DropdownMenu.js +13 -2
- package/dist/overlays/DropdownMenu.js.map +1 -1
- package/dist/overlays/HelpTip.d.ts +8 -0
- package/dist/overlays/HelpTip.js +29 -0
- package/dist/overlays/HelpTip.js.map +1 -0
- package/dist/overlays/ImageViewer.js +2 -2
- package/dist/overlays/Modal.d.ts +5 -0
- package/dist/overlays/Modal.js +17 -2
- package/dist/overlays/Modal.js.map +1 -1
- package/dist/overlays/ModalExpandButton.d.ts +18 -0
- package/dist/overlays/ModalExpandButton.js +43 -0
- package/dist/overlays/ModalExpandButton.js.map +1 -0
- package/dist/overlays/Popover.d.ts +2 -1
- package/dist/overlays/Popover.js +1 -0
- package/dist/overlays/Popover.js.map +1 -1
- package/dist/overlays/index.d.ts +4 -2
- package/dist/showcase/Cards.js +1 -1
- package/dist/showcase/FeatureRow.js +1 -1
- package/dist/showcase/PhotoSearchConcept.js +1 -1
- package/dist/showcase/ProductBand.js +1 -1
- package/dist/showcase/Status.js +1 -1
- package/dist/typography/Code.d.ts +18 -0
- package/dist/typography/Code.js +24 -0
- package/dist/typography/Code.js.map +1 -0
- package/dist/typography/Link.d.ts +7 -2
- package/dist/typography/Link.js +15 -5
- package/dist/typography/Link.js.map +1 -1
- package/dist/typography/Typography.d.ts +19 -1
- package/dist/typography/Typography.js +11 -3
- package/dist/typography/Typography.js.map +1 -1
- package/dist/typography/index.d.ts +3 -3
- package/package.json +26 -3
- package/src/actions/Button.tsx +78 -11
- package/src/actions/ButtonLink.tsx +34 -0
- package/src/actions/ButtonRecipes.ts +10 -0
- package/src/actions/IconButton.tsx +7 -4
- package/src/board/ActivityLine.tsx +176 -0
- package/src/board/ActivityTrack.tsx +23 -0
- package/src/board/AddItem.tsx +259 -0
- package/src/board/Archive.tsx +75 -0
- package/src/board/Attention.tsx +135 -0
- package/src/board/BoardShell.tsx +30 -0
- package/src/board/BoardTitleBar.tsx +167 -0
- package/src/board/ButtonKinds.ts +32 -0
- package/src/board/Cleanup.tsx +19 -0
- package/src/board/Counters.tsx +224 -0
- package/src/board/DataAttributes.ts +3 -0
- package/src/board/Dependencies.tsx +49 -0
- package/src/board/Desk.tsx +155 -0
- package/src/board/Dossier.tsx +262 -0
- package/src/board/Filters.tsx +85 -0
- package/src/board/ItemDetails.tsx +435 -0
- package/src/board/ItemDialog.tsx +179 -0
- package/src/board/ItemParts.tsx +128 -0
- package/src/board/ItemProgress.tsx +164 -0
- package/src/board/List.tsx +154 -0
- package/src/board/LoadingScreen.tsx +78 -0
- package/src/board/NeedsYou.tsx +30 -0
- package/src/board/Onboarding.tsx +124 -0
- package/src/board/PartsList.tsx +160 -0
- package/src/board/ProjectIcon.tsx +172 -0
- package/src/board/PullRequests.tsx +106 -0
- package/src/board/RowStyles.ts +17 -0
- package/src/board/Settings.tsx +124 -0
- package/src/board/Slices.tsx +103 -0
- package/src/board/SourceIcon.tsx +33 -0
- package/src/board/StagePane.tsx +128 -0
- package/src/board/StageRow.tsx +320 -0
- package/src/board/StageTrack.tsx +61 -0
- package/src/board/StartControls.tsx +77 -0
- package/src/board/StatusColors.ts +28 -0
- package/src/board/StatusGlyph.tsx +70 -0
- package/src/board/Threads.tsx +38 -0
- package/src/board/TrackerLabels.tsx +75 -0
- package/src/board/UpdatePill.tsx +222 -0
- package/src/board/Vocabulary.tsx +155 -0
- package/src/board/Warnings.tsx +83 -0
- package/src/board/WorkMap.tsx +436 -0
- package/src/board/base.css +121 -0
- package/src/board/button-kinds.css +8 -0
- package/src/board/index.ts +224 -0
- package/src/board/items.css +75 -0
- package/src/board/loading-screen.css +171 -0
- package/src/board/rows.css +180 -0
- package/src/board/title-bar.css +56 -0
- package/src/board/tokens.css +52 -0
- package/src/board.css +19 -0
- package/src/collections/CollectionState.tsx +20 -7
- package/src/display/Avatar.tsx +6 -3
- package/src/display/Badge.tsx +25 -3
- package/src/display/Comment.tsx +26 -0
- package/src/display/CopyButton.tsx +48 -18
- package/src/display/Diagram.tsx +59 -0
- package/src/display/InsetPanel.tsx +4 -1
- package/src/display/LabelChip.tsx +73 -0
- package/src/display/LabelTint.ts +72 -0
- package/src/display/Person.tsx +11 -0
- package/src/display/RadioChoice.tsx +11 -2
- package/src/display/RichText.tsx +114 -0
- package/src/display/index.ts +5 -0
- package/src/feedback/DismissButton.tsx +28 -0
- package/src/feedback/ErrorNotification.ts +3 -0
- package/src/feedback/FormResult.tsx +50 -0
- package/src/feedback/LiveRegion.tsx +10 -0
- package/src/feedback/Loading.tsx +75 -0
- package/src/feedback/Notifications.tsx +267 -2
- package/src/feedback/Progress.tsx +44 -0
- package/src/feedback/StatusIndicator.tsx +34 -3
- package/src/feedback/index.ts +12 -2
- package/src/forms/ColorSwatches.tsx +50 -0
- package/src/forms/FormSection.tsx +245 -10
- package/src/forms/HiddenField.tsx +4 -0
- package/src/forms/Input.tsx +26 -4
- package/src/forms/LabelPicker.tsx +140 -0
- package/src/forms/MarkdownEditor.tsx +283 -0
- package/src/forms/MarkdownToolbar.tsx +267 -0
- package/src/forms/OptionSelect.tsx +110 -25
- package/src/forms/Select.tsx +20 -13
- package/src/forms/Switch.tsx +16 -2
- package/src/forms/index.ts +16 -2
- package/src/foundations/AmbientMotion.ts +51 -0
- package/src/foundations/DesignSystemProvider.tsx +19 -0
- package/src/foundations/index.ts +1 -0
- package/src/foundations/theme.css +64 -0
- package/src/icons/BrandIcons.tsx +12 -3
- package/src/icons/dynamic.ts +4 -0
- package/src/icons/index.ts +1 -1
- package/src/index.ts +2 -1
- package/src/layout/index.ts +1 -1
- package/src/layout/toolbar/CommandPaletteTrigger.tsx +187 -31
- package/src/layout/toolbar/TriggerFit.ts +84 -0
- package/src/navigation/CollectionViewToggle.tsx +94 -24
- package/src/navigation/SortMenu.tsx +41 -0
- package/src/navigation/index.ts +2 -1
- package/src/overlays/CommandPalette.tsx +190 -60
- package/src/overlays/DropdownMenu.tsx +12 -1
- package/src/overlays/HelpTip.tsx +29 -0
- package/src/overlays/Modal.tsx +23 -0
- package/src/overlays/ModalExpandButton.tsx +48 -0
- package/src/overlays/Popover.tsx +3 -1
- package/src/overlays/index.ts +9 -1
- package/src/showcase.css +6 -0
- package/src/styles.css +9 -1
- package/src/typography/Code.tsx +24 -0
- package/src/typography/Link.tsx +19 -10
- package/src/typography/Typography.tsx +25 -2
- package/src/typography/index.ts +1 -1
- package/dist/feedback/index.js +0 -11
- package/dist/typography/index.js +0 -4
|
@@ -1,36 +1,67 @@
|
|
|
1
1
|
import { IconButton } from "../actions/IconButton.js";
|
|
2
|
-
import {
|
|
2
|
+
import { tabbable } from "../foundations/KeyboardFocus.js";
|
|
3
3
|
import { LayoutGridIcon, TableIcon } from "lucide-react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
5
|
// src/navigation/CollectionViewToggle.tsx
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* A group of icon buttons that picks one way of drawing a view, the picked one raised. `compact` draws 24px buttons with
|
|
8
|
+
* 14px icons, for a row's line. As `text`, each button is its label in small type, such as a dialog's panes in its
|
|
9
|
+
* header.
|
|
10
|
+
*/
|
|
11
|
+
function ViewToggle({ label, options, value, onChange, compact = false, presentation = "icons" }) {
|
|
12
|
+
if (presentation === "text") return /* @__PURE__ */ jsx("div", {
|
|
13
|
+
role: "group",
|
|
14
|
+
"aria-label": label,
|
|
15
|
+
className: "bg-base-200 flex gap-0.5 rounded-lg p-0.5",
|
|
16
|
+
children: options.map((option) => /* @__PURE__ */ jsx("button", {
|
|
17
|
+
...tabbable,
|
|
18
|
+
...option.attributes,
|
|
19
|
+
type: "button",
|
|
20
|
+
"aria-pressed": value === option.value,
|
|
21
|
+
disabled: option.disabled,
|
|
22
|
+
onClick: () => onChange(option.value),
|
|
23
|
+
className: `focus-visible:ring-primary h-7 rounded-md px-2.5 text-xs font-medium outline-none focus-visible:ring-2 ${value === option.value ? "bg-base-100 text-base-content shadow-sm" : "hover:text-base-content text-(--muted-foreground)"}`,
|
|
24
|
+
children: option.label
|
|
25
|
+
}, option.value))
|
|
26
|
+
});
|
|
27
|
+
return /* @__PURE__ */ jsx("div", {
|
|
7
28
|
role: "group",
|
|
8
29
|
"aria-label": label,
|
|
9
30
|
className: "bg-base-200/70 flex gap-0.5 rounded-lg p-0.5",
|
|
10
|
-
children:
|
|
11
|
-
|
|
12
|
-
"aria-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
31
|
+
children: options.map((option) => /* @__PURE__ */ jsx(IconButton, {
|
|
32
|
+
...option.attributes,
|
|
33
|
+
"aria-label": option.label,
|
|
34
|
+
"aria-pressed": value === option.value,
|
|
35
|
+
disabled: option.disabled,
|
|
36
|
+
icon: option.icon,
|
|
37
|
+
title: option.label,
|
|
38
|
+
className: buttonClasses(value === option.value, compact),
|
|
39
|
+
onClick: () => onChange(option.value),
|
|
18
40
|
tone: "neutral"
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
41
|
+
}, option.value))
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function CollectionViewToggle({ disabledViews = [], gridLabel, label, onChange, tableLabel, value }) {
|
|
45
|
+
return /* @__PURE__ */ jsx(ViewToggle, {
|
|
46
|
+
label,
|
|
47
|
+
value,
|
|
48
|
+
onChange,
|
|
49
|
+
options: [{
|
|
50
|
+
value: "grid",
|
|
51
|
+
label: gridLabel,
|
|
52
|
+
icon: /* @__PURE__ */ jsx(LayoutGridIcon, {}),
|
|
53
|
+
disabled: disabledViews.includes("grid")
|
|
54
|
+
}, {
|
|
55
|
+
value: "table",
|
|
56
|
+
label: tableLabel,
|
|
23
57
|
icon: /* @__PURE__ */ jsx(TableIcon, {}),
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
onClick: () => onChange("table"),
|
|
27
|
-
tone: "neutral"
|
|
28
|
-
})]
|
|
58
|
+
disabled: disabledViews.includes("table")
|
|
59
|
+
}]
|
|
29
60
|
});
|
|
30
61
|
}
|
|
31
|
-
function buttonClasses(active) {
|
|
32
|
-
return
|
|
62
|
+
function buttonClasses(active, compact) {
|
|
63
|
+
return `${compact ? "size-6 **:data-[slot=icon]:size-3.5" : "size-8"} p-0 ${active ? "bg-base-100 text-base-content shadow-sm" : "text-base-600"}`;
|
|
33
64
|
}
|
|
34
|
-
export { CollectionViewToggle };
|
|
65
|
+
export { CollectionViewToggle, ViewToggle };
|
|
35
66
|
|
|
36
67
|
//# sourceMappingURL=CollectionViewToggle.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollectionViewToggle.js","names":[],"sources":["../../src/navigation/CollectionViewToggle.tsx"],"sourcesContent":["import { LayoutGridIcon, TableIcon } from 'lucide-react';\n\nimport { IconButton } from '../actions/IconButton';\n\nexport type CollectionView = 'grid' | 'table';\n\
|
|
1
|
+
{"version":3,"file":"CollectionViewToggle.js","names":[],"sources":["../../src/navigation/CollectionViewToggle.tsx"],"sourcesContent":["import { LayoutGridIcon, TableIcon } from 'lucide-react';\nimport type { ReactNode } from 'react';\n\nimport { IconButton } from '../actions/IconButton';\nimport { tabbable } from '../foundations/KeyboardFocus';\n\nexport type CollectionView = 'grid' | 'table';\n\n/** One way of drawing a view, as ViewToggle offers it: its icon, named by its label (or, as `text`, its label alone).\n * `attributes` are `data-*` markers for its button, such as the pane it shows. */\nexport interface ViewToggleOption<V extends string> {\n value: V;\n label: string;\n icon?: ReactNode;\n disabled?: boolean;\n attributes?: { [name: `data-${string}`]: string };\n}\n\n/**\n * A group of icon buttons that picks one way of drawing a view, the picked one raised. `compact` draws 24px buttons with\n * 14px icons, for a row's line. As `text`, each button is its label in small type, such as a dialog's panes in its\n * header.\n */\nexport function ViewToggle<V extends string>({\n label,\n options,\n value,\n onChange,\n compact = false,\n presentation = 'icons',\n}: {\n /** Names the group; with none, the group is named by its options alone. */\n label?: string;\n options: readonly ViewToggleOption<V>[];\n value: V;\n onChange: (view: V) => void;\n compact?: boolean;\n presentation?: 'icons' | 'text';\n}) {\n if (presentation === 'text')\n return (\n <div role=\"group\" aria-label={label} className=\"bg-base-200 flex gap-0.5 rounded-lg p-0.5\">\n {options.map((option) => (\n <button\n key={option.value}\n {...tabbable}\n {...option.attributes}\n type=\"button\"\n aria-pressed={value === option.value}\n disabled={option.disabled}\n onClick={() => onChange(option.value)}\n className={`focus-visible:ring-primary h-7 rounded-md px-2.5 text-xs font-medium outline-none focus-visible:ring-2 ${value === option.value ? 'bg-base-100 text-base-content shadow-sm' : 'hover:text-base-content text-(--muted-foreground)'}`}\n >\n {option.label}\n </button>\n ))}\n </div>\n );\n\n return (\n <div role=\"group\" aria-label={label} className=\"bg-base-200/70 flex gap-0.5 rounded-lg p-0.5\">\n {options.map((option) => (\n <IconButton\n key={option.value}\n {...option.attributes}\n aria-label={option.label}\n aria-pressed={value === option.value}\n disabled={option.disabled}\n icon={option.icon}\n title={option.label}\n className={buttonClasses(value === option.value, compact)}\n onClick={() => onChange(option.value)}\n tone=\"neutral\"\n />\n ))}\n </div>\n );\n}\n\ninterface CollectionViewToggleProps {\n disabledViews?: readonly CollectionView[];\n gridLabel: string;\n label: string;\n onChange: (view: CollectionView) => void;\n tableLabel: string;\n value: CollectionView;\n}\n\nexport function CollectionViewToggle({\n disabledViews = [],\n gridLabel,\n label,\n onChange,\n tableLabel,\n value,\n}: CollectionViewToggleProps) {\n return (\n <ViewToggle\n label={label}\n value={value}\n onChange={onChange}\n options={[\n {\n value: 'grid',\n label: gridLabel,\n icon: <LayoutGridIcon />,\n disabled: disabledViews.includes('grid'),\n },\n {\n value: 'table',\n label: tableLabel,\n icon: <TableIcon />,\n disabled: disabledViews.includes('table'),\n },\n ]}\n />\n );\n}\n\nfunction buttonClasses(active: boolean, compact: boolean): string {\n return `${compact ? 'size-6 **:data-[slot=icon]:size-3.5' : 'size-8'} p-0 ${active ? 'bg-base-100 text-base-content shadow-sm' : 'text-base-600'}`;\n}\n"],"mappings":";;;;;;;;;;AAuBA,SAAgB,WAA6B,EACzC,OACA,SACA,OACA,UACA,UAAU,OACV,eAAe,WAShB;CACC,IAAI,iBAAiB,QACjB,OACI,oBAAC,OAAD;EAAK,MAAK;EAAQ,cAAY;EAAO,WAAU;EAC1C,UAAA,QAAQ,KAAK,WACV,oBAAC,UAAD;GAEI,GAAI;GACJ,GAAI,OAAO;GACX,MAAK;GACL,gBAAc,UAAU,OAAO;GAC/B,UAAU,OAAO;GACjB,eAAe,SAAS,OAAO,KAAK;GACpC,WAAW,0GAA0G,UAAU,OAAO,QAAQ,4CAA4C;GAEzL,UAAA,OAAO;EACJ,GAVC,OAAO,KAUR,CACX;CACA,CAAA;CAGb,OACI,oBAAC,OAAD;EAAK,MAAK;EAAQ,cAAY;EAAO,WAAU;EAC1C,UAAA,QAAQ,KAAK,WACV,oBAAC,YAAD;GAEI,GAAI,OAAO;GACX,cAAY,OAAO;GACnB,gBAAc,UAAU,OAAO;GAC/B,UAAU,OAAO;GACjB,MAAM,OAAO;GACb,OAAO,OAAO;GACd,WAAW,cAAc,UAAU,OAAO,OAAO,OAAO;GACxD,eAAe,SAAS,OAAO,KAAK;GACpC,MAAK;EACR,GAVQ,OAAO,KAUf,CACJ;CACA,CAAA;AAEb;AAWA,SAAgB,qBAAqB,EACjC,gBAAgB,CAAC,GACjB,WACA,OACA,UACA,YACA,SAC0B;CAC1B,OACI,oBAAC,YAAD;EACW;EACA;EACG;EACV,SAAS,CACL;GACI,OAAO;GACP,OAAO;GACP,MAAM,oBAAC,gBAAD,CAAiB,CAAA;GACvB,UAAU,cAAc,SAAS,MAAM;EAC3C,GACA;GACI,OAAO;GACP,OAAO;GACP,MAAM,oBAAC,WAAD,CAAY,CAAA;GAClB,UAAU,cAAc,SAAS,OAAO;EAC5C,CACJ;CACH,CAAA;AAET;AAEA,SAAS,cAAc,QAAiB,SAA0B;CAC9D,OAAO,GAAG,UAAU,wCAAwC,SAAS,OAAO,SAAS,4CAA4C;AACrI"}
|
|
@@ -4,8 +4,8 @@ import { ScrollArea } from "../layout/ScrollArea.js";
|
|
|
4
4
|
import { Popover } from "../overlays/Popover.js";
|
|
5
5
|
import { CollectionBrowseTrigger } from "./CollectionBrowseSelector.js";
|
|
6
6
|
import { useMemo, useState } from "react";
|
|
7
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
7
|
import { ChevronDownIcon, SearchIcon } from "lucide-react";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
// src/navigation/DrilldownBrowseSelector.tsx
|
|
10
10
|
function DrilldownBrowseSelector({ icon, allLabel, backLabel, disabledOptionLabel, groups, label, onClear }) {
|
|
11
11
|
const [open, setOpen] = useState(false);
|
|
@@ -6,9 +6,9 @@ import { Inline, Stack } from "../layout/Flow.js";
|
|
|
6
6
|
import { ScrollArea } from "../layout/ScrollArea.js";
|
|
7
7
|
import { Popover } from "../overlays/Popover.js";
|
|
8
8
|
import { Text } from "../typography/Typography.js";
|
|
9
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
-
import { ChevronDownIcon, FolderIcon, FolderUpIcon, HouseIcon } from "lucide-react";
|
|
11
9
|
import { Alert, Loading } from "@ninna-ui/feedback";
|
|
10
|
+
import { ChevronDownIcon, FolderIcon, FolderUpIcon, HouseIcon } from "lucide-react";
|
|
11
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
12
|
// src/navigation/FolderSelector.tsx
|
|
13
13
|
function FolderSelector({ id, title, "aria-describedby": describedBy, "aria-invalid": invalid, "aria-required": required, browsePath, disabled, error, hasMore, loading, loadingMore, onBrowsePathChange, onChange, onLoadMore, onOpenChange, onRetry, open, options, parentPath, value }) {
|
|
14
14
|
const labels = useDesignSystemLabels();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** A menu of the ways a list sorts, its button naming the current one. */
|
|
2
|
+
export declare function SortMenu<Value extends string>({ value, options, onChange }: {
|
|
3
|
+
value: Value;
|
|
4
|
+
options: readonly {
|
|
5
|
+
value: Value;
|
|
6
|
+
label: string;
|
|
7
|
+
}[];
|
|
8
|
+
onChange: (value: Value) => void;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=SortMenu.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Button } from "../actions/Button.js";
|
|
2
|
+
import { DropdownMenu } from "../overlays/DropdownMenu.js";
|
|
3
|
+
import { ChevronDownIcon } from "lucide-react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
// src/navigation/SortMenu.tsx
|
|
6
|
+
/** A menu of the ways a list sorts, its button naming the current one. */
|
|
7
|
+
function SortMenu({ value, options, onChange }) {
|
|
8
|
+
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenu.Trigger, {
|
|
9
|
+
asChild: true,
|
|
10
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
11
|
+
variant: "secondary",
|
|
12
|
+
compact: true,
|
|
13
|
+
rightIcon: /* @__PURE__ */ jsx(ChevronDownIcon, {}),
|
|
14
|
+
children: options.find((option) => option.value === value)?.label
|
|
15
|
+
})
|
|
16
|
+
}), /* @__PURE__ */ jsx(DropdownMenu.Content, {
|
|
17
|
+
align: "end",
|
|
18
|
+
children: /* @__PURE__ */ jsx(DropdownMenu.RadioGroup, {
|
|
19
|
+
value,
|
|
20
|
+
onValueChange: (next) => {
|
|
21
|
+
const picked = options.find((option) => option.value === next);
|
|
22
|
+
if (picked) onChange(picked.value);
|
|
23
|
+
},
|
|
24
|
+
children: options.map((option) => /* @__PURE__ */ jsx(DropdownMenu.RadioItem, {
|
|
25
|
+
value: option.value,
|
|
26
|
+
children: option.label
|
|
27
|
+
}, option.value))
|
|
28
|
+
})
|
|
29
|
+
})] });
|
|
30
|
+
}
|
|
31
|
+
export { SortMenu };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=SortMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SortMenu.js","names":[],"sources":["../../src/navigation/SortMenu.tsx"],"sourcesContent":["import { ChevronDownIcon } from 'lucide-react';\n\nimport { Button } from '../actions/Button';\nimport { DropdownMenu } from '../overlays/DropdownMenu';\n\n/** A menu of the ways a list sorts, its button naming the current one. */\nexport function SortMenu<Value extends string>({\n value,\n options,\n onChange,\n}: {\n value: Value;\n options: readonly { value: Value; label: string }[];\n onChange: (value: Value) => void;\n}) {\n return (\n <DropdownMenu>\n <DropdownMenu.Trigger asChild>\n <Button variant=\"secondary\" compact rightIcon={<ChevronDownIcon />}>\n {options.find((option) => option.value === value)?.label}\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.RadioGroup\n value={value}\n onValueChange={(next) => {\n const picked = options.find((option) => option.value === next);\n\n if (picked) onChange(picked.value);\n }}\n >\n {options.map((option) => (\n <DropdownMenu.RadioItem key={option.value} value={option.value}>\n {option.label}\n </DropdownMenu.RadioItem>\n ))}\n </DropdownMenu.RadioGroup>\n </DropdownMenu.Content>\n </DropdownMenu>\n );\n}\n"],"mappings":";;;;;;AAMA,SAAgB,SAA+B,EAC3C,OACA,SACA,YAKD;CACC,OACI,qBAAC,cAAD,EAAA,UAAA,CACI,oBAAC,aAAa,SAAd;EAAsB,SAAA;EAClB,UAAA,oBAAC,QAAD;GAAQ,SAAQ;GAAY,SAAA;GAAQ,WAAW,oBAAC,iBAAD,CAAkB,CAAA;GAC5D,UAAA,QAAQ,MAAM,WAAW,OAAO,UAAU,KAAK,CAAC,EAAE;EAC/C,CAAA;CACU,CAAA,GACtB,oBAAC,aAAa,SAAd;EAAsB,OAAM;EACxB,UAAA,oBAAC,aAAa,YAAd;GACW;GACP,gBAAgB,SAAS;IACrB,MAAM,SAAS,QAAQ,MAAM,WAAW,OAAO,UAAU,IAAI;IAE7D,IAAI,QAAQ,SAAS,OAAO,KAAK;GACrC;GAEC,UAAA,QAAQ,KAAK,WACV,oBAAC,aAAa,WAAd;IAA2C,OAAO,OAAO;IACpD,UAAA,OAAO;GACY,GAFK,OAAO,KAEZ,CAC3B;EACoB,CAAA;CACP,CAAA,CACZ,EAAA,CAAA;AAEtB"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ArtworkTabs, ArtworkTabsItem } from "./ArtworkTabs.js";
|
|
2
2
|
import { Breadcrumbs } from "./Breadcrumbs.js";
|
|
3
3
|
import { CollectionBrowseControls, CollectionBrowseSelector, CollectionBrowseTrigger } from "./CollectionBrowseSelector.js";
|
|
4
|
-
import { CollectionView, CollectionViewToggle } from "./CollectionViewToggle.js";
|
|
4
|
+
import { CollectionView, CollectionViewToggle, ViewToggle, ViewToggleOption } from "./CollectionViewToggle.js";
|
|
5
5
|
import { DrilldownBrowseGroup, DrilldownBrowseItem, DrilldownBrowseSelector } from "./DrilldownBrowseSelector.js";
|
|
6
6
|
import { FolderSelector, FolderSelectorOption, FolderSelectorProps } from "./FolderSelector.js";
|
|
7
|
+
import { SortMenu } from "./SortMenu.js";
|
|
7
8
|
import { ViewTabs, ViewTabsItem } from "./ViewTabs.js";
|
|
8
|
-
export { ArtworkTabs, type ArtworkTabsItem, Breadcrumbs, CollectionBrowseControls, CollectionBrowseSelector, CollectionBrowseTrigger, type CollectionView, CollectionViewToggle, type DrilldownBrowseGroup, type DrilldownBrowseItem, DrilldownBrowseSelector, FolderSelector, type FolderSelectorOption, type FolderSelectorProps, ViewTabs, type ViewTabsItem };
|
|
9
|
+
export { ArtworkTabs, type ArtworkTabsItem, Breadcrumbs, CollectionBrowseControls, CollectionBrowseSelector, CollectionBrowseTrigger, type CollectionView, CollectionViewToggle, type DrilldownBrowseGroup, type DrilldownBrowseItem, DrilldownBrowseSelector, FolderSelector, type FolderSelectorOption, type FolderSelectorProps, SortMenu, ViewTabs, type ViewTabsItem, ViewToggle, type ViewToggleOption };
|
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
|
+
/** A chip before the field for something that narrows the list, such as a filter. */
|
|
3
|
+
export interface CommandPaletteToken {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
/** An icon or colour mark before the label. */
|
|
7
|
+
leading?: ReactNode;
|
|
8
|
+
/** A button on the chip that takes it away; the focus stays in the field. */
|
|
9
|
+
remove?: {
|
|
10
|
+
label: string;
|
|
11
|
+
onRemove: () => void;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
2
14
|
interface CommandPaletteProps {
|
|
3
15
|
/** The dialog's accessible title and description; the field says the rest. */
|
|
4
16
|
label: string;
|
|
@@ -12,26 +24,48 @@ interface CommandPaletteProps {
|
|
|
12
24
|
leaveLabel: string;
|
|
13
25
|
onLeave: () => void;
|
|
14
26
|
};
|
|
27
|
+
/** Chips before the field, such as active filters, which wrap and scroll on their own when there are many. A
|
|
28
|
+
* palette given tokens, even none, is a filtering search, as wide as its chips need. */
|
|
29
|
+
tokens?: readonly CommandPaletteToken[];
|
|
30
|
+
/** Backspace in an empty field, such as to take the last token away. */
|
|
31
|
+
onBackspaceEmpty?: () => void;
|
|
32
|
+
/** A control after the field, such as Clear. A press on it leaves the focus in the field. */
|
|
33
|
+
trailing?: ReactNode;
|
|
15
34
|
/** The options' values in list order, for the arrow keys and Enter. */
|
|
16
35
|
options: readonly string[];
|
|
17
|
-
|
|
36
|
+
/** May return the option the highlight moves to, when choosing changes the list. */
|
|
37
|
+
onSelect: (value: string) => string | void;
|
|
18
38
|
onClose: () => void;
|
|
19
39
|
listLabel: string;
|
|
40
|
+
/** Marks the list busy while more may arrive; `busyLabel` shows under it meanwhile. */
|
|
20
41
|
busy?: boolean;
|
|
21
|
-
|
|
42
|
+
busyLabel?: ReactNode;
|
|
43
|
+
/** Shown when nothing is listed and nothing is pending. */
|
|
22
44
|
empty?: ReactNode;
|
|
23
45
|
/** Quiet key hints under the list, on screens with a keyboard. */
|
|
24
46
|
footer?: ReactNode;
|
|
25
47
|
children: ReactNode;
|
|
26
48
|
}
|
|
27
49
|
/** T3 Code's command palette: a field over one keyboard list of grouped options, as a dialog over the page
|
|
28
|
-
* or, on phones, the whole screen. The arrow keys move through `options`, Enter selects, Escape closes.
|
|
29
|
-
|
|
50
|
+
* or, on phones, the whole screen. The arrow keys move through `options`, Enter selects, Escape closes. Tokens
|
|
51
|
+
* before the field say what narrows the list. */
|
|
52
|
+
export declare function CommandPalette({ label, description, placeholder, query, onQueryChange, scope, tokens: givenTokens, onBackspaceEmpty, trailing, options, onSelect, onClose, listLabel, busy, busyLabel, empty, footer, children }: CommandPaletteProps): import("react").JSX.Element;
|
|
30
53
|
/** A labelled run of options in the palette's list. */
|
|
31
54
|
export declare function CommandPaletteGroup({ label, children }: {
|
|
32
55
|
label: string;
|
|
33
56
|
children: ReactNode;
|
|
34
57
|
}): import("react").JSX.Element;
|
|
58
|
+
/** One line of the palette's list: an icon, the name, an optional hint (searched with the name) and meta (on wider
|
|
59
|
+
* screens), and a tick while `checked`, as a filter that is on. Choosing it keeps the focus in the field. */
|
|
60
|
+
export declare function CommandPaletteOption({ value, icon, name, hint, meta, checked }: {
|
|
61
|
+
value: string;
|
|
62
|
+
icon: ReactNode;
|
|
63
|
+
name: string;
|
|
64
|
+
hint?: string;
|
|
65
|
+
meta?: string;
|
|
66
|
+
/** Whether a filter's option is on; other options leave it out. */
|
|
67
|
+
checked?: boolean;
|
|
68
|
+
}): import("react").JSX.Element;
|
|
35
69
|
/** Props for a palette option, such as a `ResultRow`: its id, highlight and pointer tracking. */
|
|
36
70
|
export declare function useCommandPaletteOption(value: string): {
|
|
37
71
|
id: string;
|
|
@@ -5,14 +5,15 @@ import { Text } from "../typography/Typography.js";
|
|
|
5
5
|
import { useModalAutoFocus } from "./useModalAutoFocus.js";
|
|
6
6
|
import { useScrollFade } from "./useScrollFade.js";
|
|
7
7
|
import { createContext, useContext, useEffect, useId, useRef, useState } from "react";
|
|
8
|
+
import { CheckIcon, SearchIcon, XIcon } from "lucide-react";
|
|
8
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
-
import { SearchIcon, XIcon } from "lucide-react";
|
|
10
10
|
import { Modal } from "@ninna-ui/overlays";
|
|
11
11
|
// src/overlays/CommandPalette.tsx
|
|
12
12
|
const OptionContext = createContext(null);
|
|
13
13
|
/** T3 Code's command palette: a field over one keyboard list of grouped options, as a dialog over the page
|
|
14
|
-
* or, on phones, the whole screen. The arrow keys move through `options`, Enter selects, Escape closes.
|
|
15
|
-
|
|
14
|
+
* or, on phones, the whole screen. The arrow keys move through `options`, Enter selects, Escape closes. Tokens
|
|
15
|
+
* before the field say what narrows the list. */
|
|
16
|
+
function CommandPalette({ label, description, placeholder, query, onQueryChange, scope, tokens: givenTokens, onBackspaceEmpty, trailing, options, onSelect, onClose, listLabel, busy = false, busyLabel, empty, footer, children }) {
|
|
16
17
|
const labels = useDesignSystemLabels();
|
|
17
18
|
const focusProps = useModalAutoFocus();
|
|
18
19
|
const { setViewport, setContent, className } = useScrollFade();
|
|
@@ -20,6 +21,20 @@ function CommandPalette({ label, description, placeholder, query, onQueryChange,
|
|
|
20
21
|
const input = useRef(null);
|
|
21
22
|
const [chosen, setActiveValue] = useState();
|
|
22
23
|
const activeValue = chosen !== void 0 && options.includes(chosen) ? chosen : options[0];
|
|
24
|
+
const select = (value) => {
|
|
25
|
+
const next = onSelect(value);
|
|
26
|
+
if (next) setActiveValue(next);
|
|
27
|
+
};
|
|
28
|
+
const tokens = scope ? [{
|
|
29
|
+
id: "scope",
|
|
30
|
+
label: scope.label,
|
|
31
|
+
remove: {
|
|
32
|
+
label: scope.leaveLabel,
|
|
33
|
+
onRemove: scope.onLeave
|
|
34
|
+
}
|
|
35
|
+
}] : givenTokens ?? [];
|
|
36
|
+
const leaveLast = scope ? scope.onLeave : onBackspaceEmpty;
|
|
37
|
+
const rows = givenTokens !== void 0 || Boolean(trailing);
|
|
23
38
|
useEffect(() => {
|
|
24
39
|
if (activeValue) document.getElementById(optionId(listId, activeValue))?.scrollIntoView({ block: "nearest" });
|
|
25
40
|
}, [activeValue, listId]);
|
|
@@ -31,55 +46,79 @@ function CommandPalette({ label, description, placeholder, query, onQueryChange,
|
|
|
31
46
|
description,
|
|
32
47
|
centered: false,
|
|
33
48
|
...focusProps,
|
|
34
|
-
|
|
49
|
+
"data-command-palette": true,
|
|
50
|
+
onEscapeKeyDown: (event) => {
|
|
51
|
+
if (event.isComposing) event.preventDefault();
|
|
52
|
+
},
|
|
53
|
+
className: `flex max-h-[min(36rem,calc(100dvh-6rem))] w-[calc(100vw-2rem)] max-w-2xl flex-col overflow-hidden p-0 shadow-(--lar-shadow-dialog) max-sm:top-0 max-sm:left-0 max-sm:h-dvh max-sm:max-h-none max-sm:w-full max-sm:max-w-none max-sm:translate-x-0 max-sm:rounded-none! max-sm:border-0 max-sm:pt-[env(safe-area-inset-top)] ${rows ? "max-sm:pb-[env(safe-area-inset-bottom)] sm:w-[calc(100vw-2rem)] sm:max-w-2xl" : ""}`,
|
|
35
54
|
children: [
|
|
36
55
|
/* @__PURE__ */ jsxs("div", {
|
|
37
|
-
className:
|
|
56
|
+
className: `border-base-300 [&>svg]:text-base-600 flex shrink-0 gap-2 border-b px-4 [&>svg]:size-4 [&>svg]:shrink-0 ${rows ? "items-start py-2 [&>svg]:mt-2" : "items-center py-3"}`,
|
|
38
57
|
children: [
|
|
39
58
|
/* @__PURE__ */ jsx(SearchIcon, {}),
|
|
40
|
-
|
|
41
|
-
className:
|
|
42
|
-
children: [
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
59
|
+
/* @__PURE__ */ jsxs("div", {
|
|
60
|
+
className: `flex min-w-0 flex-1 items-center gap-x-2 ${rows ? "flex-wrap gap-y-1" : ""}`,
|
|
61
|
+
children: [tokens.length > 0 ? /* @__PURE__ */ jsx("ul", {
|
|
62
|
+
className: `flex max-w-full min-w-0 shrink-0 items-center gap-1 ${rows ? "max-h-19 flex-wrap overflow-y-auto overscroll-contain py-1 pointer-coarse:max-h-22 pointer-coarse:gap-y-3 pointer-coarse:py-1.5" : ""}`,
|
|
63
|
+
children: tokens.map((token) => /* @__PURE__ */ jsxs("li", {
|
|
64
|
+
className: `bg-primary/12 text-primary flex max-w-full min-w-0 shrink-0 items-center gap-1 rounded-md py-0.5 pr-1 pl-2 text-xs font-medium ${rows ? "dark:text-base-content pointer-coarse:min-h-8 pointer-coarse:py-0 pointer-coarse:pr-0" : ""}`,
|
|
65
|
+
children: [
|
|
66
|
+
token.leading ? /* @__PURE__ */ jsx("span", {
|
|
67
|
+
className: "flex shrink-0 items-center [&>svg]:size-3.5",
|
|
68
|
+
children: token.leading
|
|
69
|
+
}) : null,
|
|
70
|
+
/* @__PURE__ */ jsx("span", {
|
|
71
|
+
className: "min-w-0 truncate",
|
|
72
|
+
children: token.label
|
|
73
|
+
}),
|
|
74
|
+
token.remove ? /* @__PURE__ */ jsx("button", {
|
|
75
|
+
type: "button",
|
|
76
|
+
tabIndex: scope ? -1 : void 0,
|
|
77
|
+
"aria-label": token.remove.label,
|
|
78
|
+
className: `hover:bg-primary/15 grid shrink-0 place-items-center rounded-sm p-0.5 [&>svg]:size-3 ${rows ? "pointer-coarse:-my-1.5 pointer-coarse:size-11 pointer-coarse:p-0" : ""}`,
|
|
79
|
+
onClick: () => {
|
|
80
|
+
token.remove?.onRemove();
|
|
81
|
+
input.current?.focus();
|
|
82
|
+
},
|
|
83
|
+
children: /* @__PURE__ */ jsx(XIcon, {})
|
|
84
|
+
}) : null
|
|
85
|
+
]
|
|
86
|
+
}, token.id))
|
|
87
|
+
}) : null, /* @__PURE__ */ jsx("input", {
|
|
88
|
+
ref: input,
|
|
89
|
+
role: "combobox",
|
|
90
|
+
"aria-label": label,
|
|
91
|
+
"aria-expanded": true,
|
|
92
|
+
"aria-controls": listId,
|
|
93
|
+
"aria-autocomplete": "list",
|
|
94
|
+
"aria-activedescendant": activeValue ? optionId(listId, activeValue) : void 0,
|
|
95
|
+
"aria-busy": busy,
|
|
96
|
+
placeholder,
|
|
97
|
+
value: query,
|
|
98
|
+
className: `text-base-content placeholder:text-base-600 min-w-0 flex-1 bg-transparent text-base outline-none sm:text-sm ${rows ? "h-8 min-w-32" : ""}`,
|
|
99
|
+
onChange: (event) => onQueryChange(event.target.value),
|
|
100
|
+
onKeyDown: (event) => {
|
|
101
|
+
if (event.nativeEvent.isComposing) return;
|
|
102
|
+
if (event.key === "Backspace" && !query && leaveLast) {
|
|
103
|
+
event.preventDefault();
|
|
104
|
+
leaveLast();
|
|
105
|
+
} else if ((event.key === "ArrowDown" || event.key === "ArrowUp") && options.length) {
|
|
106
|
+
event.preventDefault();
|
|
107
|
+
const index = activeValue ? options.indexOf(activeValue) : -1;
|
|
108
|
+
const step = event.key === "ArrowDown" ? 1 : -1;
|
|
109
|
+
setActiveValue(options[(index + step + options.length) % options.length]);
|
|
110
|
+
} else if (event.key === "Enter" && activeValue) {
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
select(activeValue);
|
|
113
|
+
}
|
|
80
114
|
}
|
|
81
|
-
}
|
|
115
|
+
})]
|
|
82
116
|
}),
|
|
117
|
+
trailing ? /* @__PURE__ */ jsx("div", {
|
|
118
|
+
className: "flex min-h-8 shrink-0 items-center pointer-coarse:[&_[data-slot=button]]:h-11!",
|
|
119
|
+
onClick: () => input.current?.focus(),
|
|
120
|
+
children: trailing
|
|
121
|
+
}) : null,
|
|
83
122
|
/* @__PURE__ */ jsx("span", {
|
|
84
123
|
className: "flex sm:hidden",
|
|
85
124
|
children: /* @__PURE__ */ jsx(IconButton, {
|
|
@@ -101,7 +140,8 @@ function CommandPalette({ label, description, placeholder, query, onQueryChange,
|
|
|
101
140
|
value: {
|
|
102
141
|
listId,
|
|
103
142
|
activeValue,
|
|
104
|
-
setActiveValue
|
|
143
|
+
setActiveValue,
|
|
144
|
+
select
|
|
105
145
|
},
|
|
106
146
|
children: /* @__PURE__ */ jsx(ResultList, {
|
|
107
147
|
id: listId,
|
|
@@ -110,11 +150,15 @@ function CommandPalette({ label, description, placeholder, query, onQueryChange,
|
|
|
110
150
|
"aria-busy": busy,
|
|
111
151
|
children
|
|
112
152
|
})
|
|
113
|
-
}),
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
153
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
154
|
+
role: "status",
|
|
155
|
+
children: busy && busyLabel || options.length === 0 && empty ? /* @__PURE__ */ jsx(Text, {
|
|
156
|
+
as: "div",
|
|
157
|
+
tone: "muted",
|
|
158
|
+
className: "px-3 py-8 text-center",
|
|
159
|
+
children: busy && busyLabel ? busyLabel : empty
|
|
160
|
+
}) : null
|
|
161
|
+
})]
|
|
118
162
|
})
|
|
119
163
|
}),
|
|
120
164
|
footer ? /* @__PURE__ */ jsx("div", {
|
|
@@ -142,6 +186,48 @@ function CommandPaletteGroup({ label, children }) {
|
|
|
142
186
|
}), children]
|
|
143
187
|
});
|
|
144
188
|
}
|
|
189
|
+
/** One line of the palette's list: an icon, the name, an optional hint (searched with the name) and meta (on wider
|
|
190
|
+
* screens), and a tick while `checked`, as a filter that is on. Choosing it keeps the focus in the field. */
|
|
191
|
+
function CommandPaletteOption({ value, icon, name, hint, meta, checked }) {
|
|
192
|
+
const context = useContext(OptionContext);
|
|
193
|
+
if (!context) throw new Error("CommandPaletteOption must be used inside CommandPalette");
|
|
194
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
195
|
+
id: optionId(context.listId, value),
|
|
196
|
+
role: "option",
|
|
197
|
+
"aria-selected": context.activeValue === value,
|
|
198
|
+
"aria-checked": checked,
|
|
199
|
+
tabIndex: -1,
|
|
200
|
+
onPointerMove: () => {
|
|
201
|
+
if (context.activeValue !== value) context.setActiveValue(value);
|
|
202
|
+
},
|
|
203
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
204
|
+
onClick: () => context.select(value),
|
|
205
|
+
className: "text-base-800 aria-selected:bg-primary/10 aria-selected:ring-primary/30 dark:text-base-content flex h-8 cursor-pointer items-center gap-2 rounded-md px-2 text-sm aria-selected:ring-1 aria-selected:ring-inset pointer-coarse:h-11",
|
|
206
|
+
children: [
|
|
207
|
+
/* @__PURE__ */ jsx("span", {
|
|
208
|
+
className: "text-base-700 grid size-4 shrink-0 place-items-center [&>svg]:size-3.5",
|
|
209
|
+
children: icon
|
|
210
|
+
}),
|
|
211
|
+
/* @__PURE__ */ jsx("span", {
|
|
212
|
+
title: name,
|
|
213
|
+
className: "min-w-0 flex-1 truncate",
|
|
214
|
+
children: name
|
|
215
|
+
}),
|
|
216
|
+
hint ? /* @__PURE__ */ jsx("span", {
|
|
217
|
+
className: "text-base-700 max-w-40 shrink-0 truncate text-xs tabular-nums",
|
|
218
|
+
children: hint
|
|
219
|
+
}) : null,
|
|
220
|
+
meta ? /* @__PURE__ */ jsx("span", {
|
|
221
|
+
className: "text-base-700 max-w-56 shrink-0 truncate text-xs max-sm:hidden",
|
|
222
|
+
children: meta
|
|
223
|
+
}) : null,
|
|
224
|
+
checked ? /* @__PURE__ */ jsx(CheckIcon, {
|
|
225
|
+
"aria-hidden": "true",
|
|
226
|
+
className: "text-primary size-3.5 shrink-0"
|
|
227
|
+
}) : null
|
|
228
|
+
]
|
|
229
|
+
});
|
|
230
|
+
}
|
|
145
231
|
/** Props for a palette option, such as a `ResultRow`: its id, highlight and pointer tracking. */
|
|
146
232
|
function useCommandPaletteOption(value) {
|
|
147
233
|
const context = useContext(OptionContext);
|
|
@@ -156,8 +242,8 @@ function useCommandPaletteOption(value) {
|
|
|
156
242
|
};
|
|
157
243
|
}
|
|
158
244
|
function optionId(listId, value) {
|
|
159
|
-
return `${listId}-${value
|
|
245
|
+
return `${listId}-${encodeURIComponent(value)}`;
|
|
160
246
|
}
|
|
161
|
-
export { CommandPalette, CommandPaletteGroup, useCommandPaletteOption };
|
|
247
|
+
export { CommandPalette, CommandPaletteGroup, CommandPaletteOption, useCommandPaletteOption };
|
|
162
248
|
|
|
163
249
|
//# sourceMappingURL=CommandPalette.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommandPalette.js","names":["NinnaModal"],"sources":["../../src/overlays/CommandPalette.tsx"],"sourcesContent":["/* oxlint-disable react/only-export-components -- The option hook belongs to the palette. */\n\nimport { Modal as NinnaModal } from '@ninna-ui/overlays';\nimport { SearchIcon, XIcon } from 'lucide-react';\nimport { createContext, type ReactNode, useContext, useEffect, useId, useRef, useState } from 'react';\n\nimport { IconButton } from '../actions/IconButton';\nimport { ResultList } from '../collections/ResultList';\nimport { useDesignSystemLabels } from '../foundations/DesignSystemProvider';\nimport { Text } from '../typography/Typography';\nimport { useModalAutoFocus } from './useModalAutoFocus';\nimport { useScrollFade } from './useScrollFade';\n\ninterface CommandPaletteProps {\n /** The dialog's accessible title and description; the field says the rest. */\n label: string;\n description: string;\n placeholder: string;\n query: string;\n onQueryChange: (query: string) => void;\n /** Narrows the list to one level, shown as a chip before the field; Backspace in an empty field leaves it. */\n scope?: { label: string; leaveLabel: string; onLeave: () => void };\n /** The options' values in list order, for the arrow keys and Enter. */\n options: readonly string[];\n onSelect: (value: string) => void;\n onClose: () => void;\n listLabel: string;\n busy?: boolean;\n /** Shown when nothing is listed. */\n empty?: ReactNode;\n /** Quiet key hints under the list, on screens with a keyboard. */\n footer?: ReactNode;\n children: ReactNode;\n}\n\nconst OptionContext = createContext<{\n listId: string;\n activeValue: string | undefined;\n setActiveValue: (value: string) => void;\n} | null>(null);\n\n/** T3 Code's command palette: a field over one keyboard list of grouped options, as a dialog over the page\n * or, on phones, the whole screen. The arrow keys move through `options`, Enter selects, Escape closes. */\nexport function CommandPalette({\n label,\n description,\n placeholder,\n query,\n onQueryChange,\n scope,\n options,\n onSelect,\n onClose,\n listLabel,\n busy = false,\n empty,\n footer,\n children,\n}: CommandPaletteProps) {\n const labels = useDesignSystemLabels();\n const focusProps = useModalAutoFocus();\n const { setViewport, setContent, className } = useScrollFade();\n const listId = useId();\n const input = useRef<HTMLInputElement>(null);\n const [chosen, setActiveValue] = useState<string>();\n // The highlight follows the list: when the chosen option leaves it, the first option takes over.\n const activeValue = chosen !== undefined && options.includes(chosen) ? chosen : options[0];\n\n useEffect(() => {\n if (activeValue) document.getElementById(optionId(listId, activeValue))?.scrollIntoView({ block: 'nearest' });\n }, [activeValue, listId]);\n\n return (\n <NinnaModal open onOpenChange={(open) => !open && onClose()}>\n <NinnaModal.Content\n title={label}\n description={description}\n centered={false}\n {...focusProps}\n className=\"flex max-h-[min(36rem,calc(100dvh-6rem))] w-[calc(100vw-2rem)] max-w-2xl flex-col overflow-hidden p-0 shadow-(--lar-shadow-dialog) max-sm:top-0 max-sm:left-0 max-sm:h-dvh max-sm:max-h-none max-sm:w-full max-sm:max-w-none max-sm:translate-x-0 max-sm:rounded-none! max-sm:border-0 max-sm:pt-[env(safe-area-inset-top)]\"\n >\n <div className=\"border-base-300 [&>svg]:text-base-600 flex shrink-0 items-center gap-2 border-b px-4 py-3 [&>svg]:size-4 [&>svg]:shrink-0\">\n <SearchIcon />\n {scope ? (\n <span className=\"bg-primary/12 text-primary flex shrink-0 items-center gap-1 rounded-md py-0.5 pr-1 pl-2 text-xs font-medium\">\n {scope.label}\n <button\n type=\"button\"\n tabIndex={-1}\n aria-label={scope.leaveLabel}\n className=\"hover:bg-primary/15 rounded-sm p-0.5 [&>svg]:size-3\"\n onClick={() => {\n scope.onLeave();\n input.current?.focus();\n }}\n >\n <XIcon />\n </button>\n </span>\n ) : null}\n <input\n ref={input}\n role=\"combobox\"\n aria-label={label}\n aria-expanded\n aria-controls={listId}\n aria-autocomplete=\"list\"\n aria-activedescendant={activeValue ? optionId(listId, activeValue) : undefined}\n aria-busy={busy}\n placeholder={placeholder}\n value={query}\n className=\"text-base-content placeholder:text-base-600 min-w-0 flex-1 bg-transparent text-base outline-none sm:text-sm\"\n onChange={(event) => onQueryChange(event.target.value)}\n onKeyDown={(event) => {\n if (event.nativeEvent.isComposing) return;\n\n if (event.key === 'Backspace' && !query && scope) {\n event.preventDefault();\n scope.onLeave();\n } else if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && options.length) {\n event.preventDefault();\n\n const index = activeValue ? options.indexOf(activeValue) : -1;\n const step = event.key === 'ArrowDown' ? 1 : -1;\n\n setActiveValue(options[(index + step + options.length) % options.length]!);\n } else if (event.key === 'Enter' && activeValue) {\n event.preventDefault();\n onSelect(activeValue);\n }\n }}\n />\n <span className=\"flex sm:hidden\">\n <IconButton aria-label={labels.close} icon={<XIcon />} onClick={onClose} variant=\"header\" />\n </span>\n </div>\n <div ref={setViewport} className={`min-h-0 flex-1 overflow-y-auto overscroll-contain p-2 ${className}`}>\n <div ref={setContent} className=\"flow-root\">\n <OptionContext.Provider value={{ listId, activeValue, setActiveValue }}>\n <ResultList id={listId} label={listLabel} density=\"compact\" aria-busy={busy}>\n {children}\n </ResultList>\n </OptionContext.Provider>\n {options.length === 0 && empty ? (\n <Text tone=\"muted\" className=\"px-3 py-8 text-center\">\n {empty}\n </Text>\n ) : null}\n </div>\n </div>\n {footer ? (\n <div className=\"border-base-300 text-2xs text-base-700 hidden shrink-0 items-center gap-4 border-t px-4 py-2 pointer-fine:flex\">\n {footer}\n </div>\n ) : null}\n </NinnaModal.Content>\n </NinnaModal>\n );\n}\n\n/** A labelled run of options in the palette's list. */\nexport function CommandPaletteGroup({ label, children }: { label: string; children: ReactNode }) {\n const labelId = useId();\n\n return (\n <div role=\"group\" aria-labelledby={labelId} className=\"flex flex-col gap-1 not-first:pt-2\">\n <Text\n as=\"span\"\n id={labelId}\n variant=\"caption\"\n tone=\"muted\"\n className=\"px-2 pt-1 font-medium tracking-wide uppercase\"\n >\n {label}\n </Text>\n {children}\n </div>\n );\n}\n\n/** Props for a palette option, such as a `ResultRow`: its id, highlight and pointer tracking. */\nexport function useCommandPaletteOption(value: string) {\n const context = useContext(OptionContext);\n\n if (!context) throw new Error('useCommandPaletteOption must be used inside CommandPalette');\n\n return {\n id: optionId(context.listId, value),\n selected: context.activeValue === value,\n tabIndex: -1,\n onPointerMove: () => {\n if (context.activeValue !== value) context.setActiveValue(value);\n },\n };\n}\n\nfunction optionId(listId: string, value: string) {\n return `${listId}-${value.replace(/[^\\w-]/g, '_')}`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CommandPalette.js","names":["NinnaModal"],"sources":["../../src/overlays/CommandPalette.tsx"],"sourcesContent":["/* oxlint-disable react/only-export-components -- The option hook belongs to the palette. */\n\nimport { Modal as NinnaModal } from '@ninna-ui/overlays';\nimport { CheckIcon, SearchIcon, XIcon } from 'lucide-react';\nimport { createContext, type ReactNode, useContext, useEffect, useId, useRef, useState } from 'react';\n\nimport { IconButton } from '../actions/IconButton';\nimport { ResultList } from '../collections/ResultList';\nimport { useDesignSystemLabels } from '../foundations/DesignSystemProvider';\nimport { Text } from '../typography/Typography';\nimport { useModalAutoFocus } from './useModalAutoFocus';\nimport { useScrollFade } from './useScrollFade';\n\n/** A chip before the field for something that narrows the list, such as a filter. */\nexport interface CommandPaletteToken {\n id: string;\n label: string;\n /** An icon or colour mark before the label. */\n leading?: ReactNode;\n /** A button on the chip that takes it away; the focus stays in the field. */\n remove?: { label: string; onRemove: () => void };\n}\n\ninterface CommandPaletteProps {\n /** The dialog's accessible title and description; the field says the rest. */\n label: string;\n description: string;\n placeholder: string;\n query: string;\n onQueryChange: (query: string) => void;\n /** Narrows the list to one level, shown as a chip before the field; Backspace in an empty field leaves it. */\n scope?: { label: string; leaveLabel: string; onLeave: () => void };\n /** Chips before the field, such as active filters, which wrap and scroll on their own when there are many. A\n * palette given tokens, even none, is a filtering search, as wide as its chips need. */\n tokens?: readonly CommandPaletteToken[];\n /** Backspace in an empty field, such as to take the last token away. */\n onBackspaceEmpty?: () => void;\n /** A control after the field, such as Clear. A press on it leaves the focus in the field. */\n trailing?: ReactNode;\n /** The options' values in list order, for the arrow keys and Enter. */\n options: readonly string[];\n /** May return the option the highlight moves to, when choosing changes the list. */\n onSelect: (value: string) => string | void;\n onClose: () => void;\n listLabel: string;\n /** Marks the list busy while more may arrive; `busyLabel` shows under it meanwhile. */\n busy?: boolean;\n busyLabel?: ReactNode;\n /** Shown when nothing is listed and nothing is pending. */\n empty?: ReactNode;\n /** Quiet key hints under the list, on screens with a keyboard. */\n footer?: ReactNode;\n children: ReactNode;\n}\n\nconst OptionContext = createContext<{\n listId: string;\n activeValue: string | undefined;\n setActiveValue: (value: string) => void;\n select: (value: string) => void;\n} | null>(null);\n\n/** T3 Code's command palette: a field over one keyboard list of grouped options, as a dialog over the page\n * or, on phones, the whole screen. The arrow keys move through `options`, Enter selects, Escape closes. Tokens\n * before the field say what narrows the list. */\nexport function CommandPalette({\n label,\n description,\n placeholder,\n query,\n onQueryChange,\n scope,\n tokens: givenTokens,\n onBackspaceEmpty,\n trailing,\n options,\n onSelect,\n onClose,\n listLabel,\n busy = false,\n busyLabel,\n empty,\n footer,\n children,\n}: CommandPaletteProps) {\n const labels = useDesignSystemLabels();\n const focusProps = useModalAutoFocus();\n const { setViewport, setContent, className } = useScrollFade();\n const listId = useId();\n const input = useRef<HTMLInputElement>(null);\n const [chosen, setActiveValue] = useState<string>();\n // The highlight follows the list: when the chosen option leaves it, the first option takes over.\n const activeValue = chosen !== undefined && options.includes(chosen) ? chosen : options[0];\n const select = (value: string) => {\n const next = onSelect(value);\n\n if (next) setActiveValue(next);\n };\n // A scope is the one token of a palette that narrows by levels.\n const tokens: readonly CommandPaletteToken[] = scope\n ? [{ id: 'scope', label: scope.label, remove: { label: scope.leaveLabel, onRemove: scope.onLeave } }]\n : (givenTokens ?? []);\n const leaveLast = scope ? scope.onLeave : onBackspaceEmpty;\n // A palette that takes tokens, or a trailing control, is a filtering search: wide, with its field wrapping onto\n // rows under the tokens, from the top.\n const rows = givenTokens !== undefined || Boolean(trailing);\n\n useEffect(() => {\n if (activeValue) document.getElementById(optionId(listId, activeValue))?.scrollIntoView({ block: 'nearest' });\n }, [activeValue, listId]);\n\n return (\n <NinnaModal open onOpenChange={(open) => !open && onClose()}>\n <NinnaModal.Content\n title={label}\n description={description}\n centered={false}\n {...focusProps}\n data-command-palette\n // The dialog listens for Escape on the document, past the field's own keys; an input method's Escape\n // only ends its composition.\n onEscapeKeyDown={(event) => {\n if (event.isComposing) event.preventDefault();\n }}\n className={`flex max-h-[min(36rem,calc(100dvh-6rem))] w-[calc(100vw-2rem)] max-w-2xl flex-col overflow-hidden p-0 shadow-(--lar-shadow-dialog) max-sm:top-0 max-sm:left-0 max-sm:h-dvh max-sm:max-h-none max-sm:w-full max-sm:max-w-none max-sm:translate-x-0 max-sm:rounded-none! max-sm:border-0 max-sm:pt-[env(safe-area-inset-top)] ${rows ? 'max-sm:pb-[env(safe-area-inset-bottom)] sm:w-[calc(100vw-2rem)] sm:max-w-2xl' : ''}`}\n >\n <div\n className={`border-base-300 [&>svg]:text-base-600 flex shrink-0 gap-2 border-b px-4 [&>svg]:size-4 [&>svg]:shrink-0 ${rows ? 'items-start py-2 [&>svg]:mt-2' : 'items-center py-3'}`}\n >\n <SearchIcon />\n <div className={`flex min-w-0 flex-1 items-center gap-x-2 ${rows ? 'flex-wrap gap-y-1' : ''}`}>\n {tokens.length > 0 ? (\n // Many tokens scroll on their own, so the field stays in view however many there are. Under\n // a coarse pointer each remove button is 44 px, reaching into the gap between rows.\n <ul\n className={`flex max-w-full min-w-0 shrink-0 items-center gap-1 ${rows ? 'max-h-19 flex-wrap overflow-y-auto overscroll-contain py-1 pointer-coarse:max-h-22 pointer-coarse:gap-y-3 pointer-coarse:py-1.5' : ''}`}\n >\n {tokens.map((token) => (\n <li\n key={token.id}\n className={`bg-primary/12 text-primary flex max-w-full min-w-0 shrink-0 items-center gap-1 rounded-md py-0.5 pr-1 pl-2 text-xs font-medium ${rows ? 'dark:text-base-content pointer-coarse:min-h-8 pointer-coarse:py-0 pointer-coarse:pr-0' : ''}`}\n >\n {token.leading ? (\n <span className=\"flex shrink-0 items-center [&>svg]:size-3.5\">\n {token.leading}\n </span>\n ) : null}\n <span className=\"min-w-0 truncate\">{token.label}</span>\n {token.remove ? (\n <button\n type=\"button\"\n // A scope's chip leaves with Backspace alone; several tokens' buttons are tab stops.\n tabIndex={scope ? -1 : undefined}\n aria-label={token.remove.label}\n className={`hover:bg-primary/15 grid shrink-0 place-items-center rounded-sm p-0.5 [&>svg]:size-3 ${rows ? 'pointer-coarse:-my-1.5 pointer-coarse:size-11 pointer-coarse:p-0' : ''}`}\n onClick={() => {\n token.remove?.onRemove();\n input.current?.focus();\n }}\n >\n <XIcon />\n </button>\n ) : null}\n </li>\n ))}\n </ul>\n ) : null}\n <input\n ref={input}\n role=\"combobox\"\n aria-label={label}\n aria-expanded\n aria-controls={listId}\n aria-autocomplete=\"list\"\n aria-activedescendant={activeValue ? optionId(listId, activeValue) : undefined}\n aria-busy={busy}\n placeholder={placeholder}\n value={query}\n className={`text-base-content placeholder:text-base-600 min-w-0 flex-1 bg-transparent text-base outline-none sm:text-sm ${rows ? 'h-8 min-w-32' : ''}`}\n onChange={(event) => onQueryChange(event.target.value)}\n onKeyDown={(event) => {\n if (event.nativeEvent.isComposing) return;\n\n if (event.key === 'Backspace' && !query && leaveLast) {\n event.preventDefault();\n leaveLast();\n } else if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && options.length) {\n event.preventDefault();\n\n const index = activeValue ? options.indexOf(activeValue) : -1;\n const step = event.key === 'ArrowDown' ? 1 : -1;\n\n setActiveValue(options[(index + step + options.length) % options.length]!);\n } else if (event.key === 'Enter' && activeValue) {\n event.preventDefault();\n select(activeValue);\n }\n }}\n />\n </div>\n {trailing ? (\n // Under a coarse pointer the control is 44 px, as a token's remove button is.\n <div\n className=\"flex min-h-8 shrink-0 items-center pointer-coarse:[&_[data-slot=button]]:h-11!\"\n onClick={() => input.current?.focus()}\n >\n {trailing}\n </div>\n ) : null}\n <span className=\"flex sm:hidden\">\n <IconButton aria-label={labels.close} icon={<XIcon />} onClick={onClose} variant=\"header\" />\n </span>\n </div>\n <div ref={setViewport} className={`min-h-0 flex-1 overflow-y-auto overscroll-contain p-2 ${className}`}>\n <div ref={setContent} className=\"flow-root\">\n <OptionContext.Provider value={{ listId, activeValue, setActiveValue, select }}>\n <ResultList id={listId} label={listLabel} density=\"compact\" aria-busy={busy}>\n {children}\n </ResultList>\n </OptionContext.Provider>\n <div role=\"status\">\n {(busy && busyLabel) || (options.length === 0 && empty) ? (\n <Text as=\"div\" tone=\"muted\" className=\"px-3 py-8 text-center\">\n {busy && busyLabel ? busyLabel : empty}\n </Text>\n ) : null}\n </div>\n </div>\n </div>\n {footer ? (\n <div className=\"border-base-300 text-2xs text-base-700 hidden shrink-0 items-center gap-4 border-t px-4 py-2 pointer-fine:flex\">\n {footer}\n </div>\n ) : null}\n </NinnaModal.Content>\n </NinnaModal>\n );\n}\n\n/** A labelled run of options in the palette's list. */\nexport function CommandPaletteGroup({ label, children }: { label: string; children: ReactNode }) {\n const labelId = useId();\n\n return (\n <div role=\"group\" aria-labelledby={labelId} className=\"flex flex-col gap-1 not-first:pt-2\">\n <Text\n as=\"span\"\n id={labelId}\n variant=\"caption\"\n tone=\"muted\"\n className=\"px-2 pt-1 font-medium tracking-wide uppercase\"\n >\n {label}\n </Text>\n {children}\n </div>\n );\n}\n\n/** One line of the palette's list: an icon, the name, an optional hint (searched with the name) and meta (on wider\n * screens), and a tick while `checked`, as a filter that is on. Choosing it keeps the focus in the field. */\nexport function CommandPaletteOption({\n value,\n icon,\n name,\n hint,\n meta,\n checked,\n}: {\n value: string;\n icon: ReactNode;\n name: string;\n hint?: string;\n meta?: string;\n /** Whether a filter's option is on; other options leave it out. */\n checked?: boolean;\n}) {\n const context = useContext(OptionContext);\n\n if (!context) throw new Error('CommandPaletteOption must be used inside CommandPalette');\n\n return (\n <div\n id={optionId(context.listId, value)}\n role=\"option\"\n aria-selected={context.activeValue === value}\n aria-checked={checked}\n tabIndex={-1}\n onPointerMove={() => {\n if (context.activeValue !== value) context.setActiveValue(value);\n }}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => context.select(value)}\n className=\"text-base-800 aria-selected:bg-primary/10 aria-selected:ring-primary/30 dark:text-base-content flex h-8 cursor-pointer items-center gap-2 rounded-md px-2 text-sm aria-selected:ring-1 aria-selected:ring-inset pointer-coarse:h-11\"\n >\n <span className=\"text-base-700 grid size-4 shrink-0 place-items-center [&>svg]:size-3.5\">{icon}</span>\n <span title={name} className=\"min-w-0 flex-1 truncate\">\n {name}\n </span>\n {hint ? (\n <span className=\"text-base-700 max-w-40 shrink-0 truncate text-xs tabular-nums\">{hint}</span>\n ) : null}\n {meta ? (\n <span className=\"text-base-700 max-w-56 shrink-0 truncate text-xs max-sm:hidden\">{meta}</span>\n ) : null}\n {checked ? <CheckIcon aria-hidden=\"true\" className=\"text-primary size-3.5 shrink-0\" /> : null}\n </div>\n );\n}\n\n/** Props for a palette option, such as a `ResultRow`: its id, highlight and pointer tracking. */\nexport function useCommandPaletteOption(value: string) {\n const context = useContext(OptionContext);\n\n if (!context) throw new Error('useCommandPaletteOption must be used inside CommandPalette');\n\n return {\n id: optionId(context.listId, value),\n selected: context.activeValue === value,\n tabIndex: -1,\n onPointerMove: () => {\n if (context.activeValue !== value) context.setActiveValue(value);\n },\n };\n}\n\nfunction optionId(listId: string, value: string) {\n return `${listId}-${encodeURIComponent(value)}`;\n}\n"],"mappings":"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"}
|