@smwb/ui-react 2.8.0 → 2.9.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/AI_LESS_OVERRIDES.md +84 -21
- package/AI_THEMING.md +72 -28
- package/README.md +654 -0
- package/dist/assets/styles/less/components/appBar/appBar.entry.css +1 -1
- package/dist/assets/styles/less/components/button/button.entry.css +1 -1
- package/dist/assets/styles/less/components/checkbox/checkbox.entry.css +1 -1
- package/dist/assets/styles/less/components/chip/chip.entry.css +1 -1
- package/dist/assets/styles/less/components/commandPalette/commandPalette.entry.css +1 -0
- package/dist/assets/styles/less/components/composer/composer.entry.css +1 -0
- package/dist/assets/styles/less/components/dagView/dagView.entry.css +1 -0
- package/dist/assets/styles/less/components/diffStat/diffStat.entry.css +1 -0
- package/dist/assets/styles/less/components/kbd/kbd.entry.css +1 -0
- package/dist/assets/styles/less/components/list/list.entry.css +1 -1
- package/dist/assets/styles/less/components/qrCode/qrCode.entry.css +1 -0
- package/dist/assets/styles/less/components/radioButton/radioButton.entry.css +1 -1
- package/dist/assets/styles/less/components/selectField/selectField.entry.css +1 -1
- package/dist/assets/styles/less/components/sidebar/sidebar.entry.css +1 -1
- package/dist/assets/styles/less/components/statusDot/statusDot.entry.css +1 -0
- package/dist/assets/styles/less/components/swimlanes/swimlanes.entry.css +1 -0
- package/dist/assets/styles/less/components/tabGroups/tabGroups.entry.css +1 -0
- package/dist/assets/styles/less/components/tabs/tab/tab.entry.css +1 -1
- package/dist/assets/styles/less/components/tabs/tabPanel/tabPanel.entry.css +1 -0
- package/dist/assets/styles/less/components/tabs/tabs.entry.css +1 -1
- package/dist/assets/styles/less/components/textField/textField.entry.css +1 -1
- package/dist/assets/styles/less/components/toggle/toggle.entry.css +1 -1
- package/dist/assets/styles/less/components/treeView/treeView.entry.css +1 -1
- package/dist/assets/styles/less/tokens.entry.css +1 -1
- package/dist/components/dataDisplay/chat/chat.d.ts +43 -1
- package/dist/components/dataDisplay/chat/chat.js +179 -150
- package/dist/components/dataDisplay/chat/chat.js.map +1 -1
- package/dist/components/dataDisplay/chat/chatComposer.d.ts +17 -0
- package/dist/components/dataDisplay/chat/chatComposer.js +31 -29
- package/dist/components/dataDisplay/chat/chatComposer.js.map +1 -1
- package/dist/components/dataDisplay/chat/index.d.ts +1 -1
- package/dist/components/dataDisplay/chat/utils.d.ts +14 -0
- package/dist/components/dataDisplay/chat/utils.js.map +1 -1
- package/dist/components/dataDisplay/dagView/dagLayout.d.ts +74 -0
- package/dist/components/dataDisplay/dagView/dagLayout.js +289 -0
- package/dist/components/dataDisplay/dagView/dagLayout.js.map +1 -0
- package/dist/components/dataDisplay/dagView/dagView.d.ts +157 -0
- package/dist/components/dataDisplay/dagView/dagView.js +543 -0
- package/dist/components/dataDisplay/dagView/dagView.js.map +1 -0
- package/dist/components/dataDisplay/dagView/index.d.ts +4 -0
- package/dist/components/dataDisplay/dagView/panZoom.d.ts +75 -0
- package/dist/components/dataDisplay/dagView/panZoom.js +171 -0
- package/dist/components/dataDisplay/dagView/panZoom.js.map +1 -0
- package/dist/components/dataDisplay/diffStat/diffStat.d.ts +54 -0
- package/dist/components/dataDisplay/diffStat/diffStat.js +63 -0
- package/dist/components/dataDisplay/diffStat/diffStat.js.map +1 -0
- package/dist/components/dataDisplay/diffStat/index.d.ts +2 -0
- package/dist/components/dataDisplay/kbd/index.d.ts +4 -0
- package/dist/components/dataDisplay/kbd/kbd.d.ts +40 -0
- package/dist/components/dataDisplay/kbd/kbd.js +27 -0
- package/dist/components/dataDisplay/kbd/kbd.js.map +1 -0
- package/dist/components/dataDisplay/kbd/kbdKeys.d.ts +18 -0
- package/dist/components/dataDisplay/kbd/kbdKeys.js +72 -0
- package/dist/components/dataDisplay/kbd/kbdKeys.js.map +1 -0
- package/dist/components/dataDisplay/list/listItem.d.ts +34 -0
- package/dist/components/dataDisplay/list/listItem.js +47 -24
- package/dist/components/dataDisplay/list/listItem.js.map +1 -1
- package/dist/components/dataDisplay/qrCode/index.d.ts +2 -0
- package/dist/components/dataDisplay/qrCode/qrCode.d.ts +28 -0
- package/dist/components/dataDisplay/qrCode/qrCode.js +78 -0
- package/dist/components/dataDisplay/qrCode/qrCode.js.map +1 -0
- package/dist/components/dataDisplay/qrCode/qrCodePath.d.ts +7 -0
- package/dist/components/dataDisplay/qrCode/qrCodePath.js +20 -0
- package/dist/components/dataDisplay/qrCode/qrCodePath.js.map +1 -0
- package/dist/components/dataDisplay/statusDot/index.d.ts +2 -0
- package/dist/components/dataDisplay/statusDot/statusDot.d.ts +35 -0
- package/dist/components/dataDisplay/statusDot/statusDot.js +30 -0
- package/dist/components/dataDisplay/statusDot/statusDot.js.map +1 -0
- package/dist/components/dataDisplay/swimlanes/index.d.ts +2 -0
- package/dist/components/dataDisplay/swimlanes/swimlanes.d.ts +53 -0
- package/dist/components/dataDisplay/swimlanes/swimlanes.js +357 -0
- package/dist/components/dataDisplay/swimlanes/swimlanes.js.map +1 -0
- package/dist/components/dataDisplay/treeView/treeView.d.ts +17 -1
- package/dist/components/dataDisplay/treeView/treeView.js +113 -92
- package/dist/components/dataDisplay/treeView/treeView.js.map +1 -1
- package/dist/components/feedBack/modal/modal.js +84 -63
- package/dist/components/feedBack/modal/modal.js.map +1 -1
- package/dist/components/inputs/button/button.d.ts +13 -1
- package/dist/components/inputs/button/button.js +57 -51
- package/dist/components/inputs/button/button.js.map +1 -1
- package/dist/components/inputs/composer/composer.d.ts +149 -0
- package/dist/components/inputs/composer/composer.js +219 -0
- package/dist/components/inputs/composer/composer.js.map +1 -0
- package/dist/components/inputs/composer/composerFiles.d.ts +26 -0
- package/dist/components/inputs/composer/composerFiles.js +19 -0
- package/dist/components/inputs/composer/composerFiles.js.map +1 -0
- package/dist/components/inputs/composer/composerKeys.d.ts +29 -0
- package/dist/components/inputs/composer/composerKeys.js +7 -0
- package/dist/components/inputs/composer/composerKeys.js.map +1 -0
- package/dist/components/inputs/composer/index.d.ts +3 -0
- package/dist/components/layout/sheet/sheet.d.ts +12 -0
- package/dist/components/layout/sheet/sheet.js +152 -137
- package/dist/components/layout/sheet/sheet.js.map +1 -1
- package/dist/components/layout/tabGroups/index.d.ts +4 -0
- package/dist/components/layout/tabGroups/tabGroups.d.ts +94 -0
- package/dist/components/layout/tabGroups/tabGroups.js +783 -0
- package/dist/components/layout/tabGroups/tabGroups.js.map +1 -0
- package/dist/components/layout/tabGroups/tabGroupsFocus.d.ts +55 -0
- package/dist/components/layout/tabGroups/tabGroupsFocus.js +199 -0
- package/dist/components/layout/tabGroups/tabGroupsFocus.js.map +1 -0
- package/dist/components/layout/tabGroups/tabGroupsLayout.d.ts +250 -0
- package/dist/components/layout/tabGroups/tabGroupsLayout.js +497 -0
- package/dist/components/layout/tabGroups/tabGroupsLayout.js.map +1 -0
- package/dist/components/navigation/appBar/appBar.d.ts +22 -0
- package/dist/components/navigation/appBar/appBar.js +31 -26
- package/dist/components/navigation/appBar/appBar.js.map +1 -1
- package/dist/components/navigation/commandPalette/commandPalette.d.ts +111 -0
- package/dist/components/navigation/commandPalette/commandPalette.js +337 -0
- package/dist/components/navigation/commandPalette/commandPalette.js.map +1 -0
- package/dist/components/navigation/commandPalette/commandPaletteFilter.d.ts +11 -0
- package/dist/components/navigation/commandPalette/commandPaletteFilter.js +16 -0
- package/dist/components/navigation/commandPalette/commandPaletteFilter.js.map +1 -0
- package/dist/components/navigation/commandPalette/commandPaletteNavigation.d.ts +13 -0
- package/dist/components/navigation/commandPalette/commandPaletteNavigation.js +38 -0
- package/dist/components/navigation/commandPalette/commandPaletteNavigation.js.map +1 -0
- package/dist/components/navigation/commandPalette/commandPaletteTypes.d.ts +39 -0
- package/dist/components/navigation/commandPalette/index.d.ts +4 -0
- package/dist/components/navigation/sidebar/sidebar.d.ts +10 -0
- package/dist/components/navigation/sidebar/sidebar.js +61 -59
- package/dist/components/navigation/sidebar/sidebar.js.map +1 -1
- package/dist/components/navigation/tabs/index.d.ts +3 -1
- package/dist/components/navigation/tabs/tab/tab.d.ts +88 -1
- package/dist/components/navigation/tabs/tab/tab.js +121 -42
- package/dist/components/navigation/tabs/tab/tab.js.map +1 -1
- package/dist/components/navigation/tabs/tabPanel/tabPanel.d.ts +19 -0
- package/dist/components/navigation/tabs/tabPanel/tabPanel.js +27 -0
- package/dist/components/navigation/tabs/tabPanel/tabPanel.js.map +1 -0
- package/dist/components/navigation/tabs/tabs.d.ts +75 -5
- package/dist/components/navigation/tabs/tabs.js +369 -145
- package/dist/components/navigation/tabs/tabs.js.map +1 -1
- package/dist/components/navigation/tabs/tabs.utils.d.ts +20 -0
- package/dist/components/navigation/tabs/tabs.utils.js +11 -0
- package/dist/components/navigation/tabs/tabs.utils.js.map +1 -0
- package/dist/components/navigation/tabs/tabsContext.d.ts +11 -0
- package/dist/components/navigation/tabs/tabsContext.js +6 -0
- package/dist/components/navigation/tabs/tabsContext.js.map +1 -0
- package/dist/headless/components/dataDisplay/chat/chat.js +179 -150
- package/dist/headless/components/dataDisplay/chat/chat.js.map +1 -1
- package/dist/headless/components/dataDisplay/chat/chatComposer.js +31 -29
- package/dist/headless/components/dataDisplay/chat/chatComposer.js.map +1 -1
- package/dist/headless/components/dataDisplay/chat/utils.js.map +1 -1
- package/dist/headless/components/dataDisplay/dagView/dagLayout.js +289 -0
- package/dist/headless/components/dataDisplay/dagView/dagLayout.js.map +1 -0
- package/dist/headless/components/dataDisplay/dagView/dagView.js +541 -0
- package/dist/headless/components/dataDisplay/dagView/dagView.js.map +1 -0
- package/dist/headless/components/dataDisplay/dagView/panZoom.js +171 -0
- package/dist/headless/components/dataDisplay/dagView/panZoom.js.map +1 -0
- package/dist/headless/components/dataDisplay/diffStat/diffStat.js +61 -0
- package/dist/headless/components/dataDisplay/diffStat/diffStat.js.map +1 -0
- package/dist/headless/components/dataDisplay/kbd/kbd.js +25 -0
- package/dist/headless/components/dataDisplay/kbd/kbd.js.map +1 -0
- package/dist/headless/components/dataDisplay/kbd/kbdKeys.js +72 -0
- package/dist/headless/components/dataDisplay/kbd/kbdKeys.js.map +1 -0
- package/dist/headless/components/dataDisplay/list/listItem.js +47 -24
- package/dist/headless/components/dataDisplay/list/listItem.js.map +1 -1
- package/dist/headless/components/dataDisplay/qrCode/qrCode.js +76 -0
- package/dist/headless/components/dataDisplay/qrCode/qrCode.js.map +1 -0
- package/dist/headless/components/dataDisplay/qrCode/qrCodePath.js +20 -0
- package/dist/headless/components/dataDisplay/qrCode/qrCodePath.js.map +1 -0
- package/dist/headless/components/dataDisplay/statusDot/statusDot.js +28 -0
- package/dist/headless/components/dataDisplay/statusDot/statusDot.js.map +1 -0
- package/dist/headless/components/dataDisplay/swimlanes/swimlanes.js +355 -0
- package/dist/headless/components/dataDisplay/swimlanes/swimlanes.js.map +1 -0
- package/dist/headless/components/dataDisplay/treeView/treeView.js +113 -92
- package/dist/headless/components/dataDisplay/treeView/treeView.js.map +1 -1
- package/dist/headless/components/feedBack/modal/modal.js +85 -64
- package/dist/headless/components/feedBack/modal/modal.js.map +1 -1
- package/dist/headless/components/inputs/button/button.js +56 -50
- package/dist/headless/components/inputs/button/button.js.map +1 -1
- package/dist/headless/components/inputs/composer/composer.js +217 -0
- package/dist/headless/components/inputs/composer/composer.js.map +1 -0
- package/dist/headless/components/inputs/composer/composerFiles.js +19 -0
- package/dist/headless/components/inputs/composer/composerFiles.js.map +1 -0
- package/dist/headless/components/inputs/composer/composerKeys.js +7 -0
- package/dist/headless/components/inputs/composer/composerKeys.js.map +1 -0
- package/dist/headless/components/layout/sheet/sheet.js +160 -145
- package/dist/headless/components/layout/sheet/sheet.js.map +1 -1
- package/dist/headless/components/layout/tabGroups/tabGroups.js +781 -0
- package/dist/headless/components/layout/tabGroups/tabGroups.js.map +1 -0
- package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js +199 -0
- package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js.map +1 -0
- package/dist/headless/components/layout/tabGroups/tabGroupsLayout.js +497 -0
- package/dist/headless/components/layout/tabGroups/tabGroupsLayout.js.map +1 -0
- package/dist/headless/components/navigation/appBar/appBar.js +35 -30
- package/dist/headless/components/navigation/appBar/appBar.js.map +1 -1
- package/dist/headless/components/navigation/commandPalette/commandPalette.js +335 -0
- package/dist/headless/components/navigation/commandPalette/commandPalette.js.map +1 -0
- package/dist/headless/components/navigation/commandPalette/commandPaletteFilter.js +16 -0
- package/dist/headless/components/navigation/commandPalette/commandPaletteFilter.js.map +1 -0
- package/dist/headless/components/navigation/commandPalette/commandPaletteNavigation.js +38 -0
- package/dist/headless/components/navigation/commandPalette/commandPaletteNavigation.js.map +1 -0
- package/dist/headless/components/navigation/sidebar/sidebar.js +56 -54
- package/dist/headless/components/navigation/sidebar/sidebar.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tab/tab.js +121 -42
- package/dist/headless/components/navigation/tabs/tab/tab.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tabPanel/tabPanel.js +25 -0
- package/dist/headless/components/navigation/tabs/tabPanel/tabPanel.js.map +1 -0
- package/dist/headless/components/navigation/tabs/tabs.js +369 -145
- package/dist/headless/components/navigation/tabs/tabs.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tabs.utils.js +11 -0
- package/dist/headless/components/navigation/tabs/tabs.utils.js.map +1 -0
- package/dist/headless/components/navigation/tabs/tabsContext.js +6 -0
- package/dist/headless/components/navigation/tabs/tabsContext.js.map +1 -0
- package/dist/headless/hooks/useFocusTrap.js +24 -21
- package/dist/headless/hooks/useFocusTrap.js.map +1 -1
- package/dist/headless/hooks/useKeyboardShortcut.js +19 -0
- package/dist/headless/hooks/useKeyboardShortcut.js.map +1 -0
- package/dist/headless/index.js +360 -316
- package/dist/headless/index.js.map +1 -1
- package/dist/headless/utils/keyboardShortcut.js +49 -0
- package/dist/headless/utils/keyboardShortcut.js.map +1 -0
- package/dist/headless/utils/linkAttrs.js +13 -0
- package/dist/headless/utils/linkAttrs.js.map +1 -0
- package/dist/headless/utils/restoreFocus.js +10 -0
- package/dist/headless/utils/restoreFocus.js.map +1 -0
- package/dist/hooks/useFocusTrap.d.ts +6 -1
- package/dist/hooks/useFocusTrap.js +24 -21
- package/dist/hooks/useFocusTrap.js.map +1 -1
- package/dist/hooks/useKeyboardShortcut.d.ts +30 -0
- package/dist/hooks/useKeyboardShortcut.js +19 -0
- package/dist/hooks/useKeyboardShortcut.js.map +1 -0
- package/dist/index.cjs +3 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +24 -3
- package/dist/index.js +360 -316
- package/dist/index.js.map +1 -1
- package/dist/utils/keyboardShortcut.d.ts +12 -0
- package/dist/utils/keyboardShortcut.js +49 -0
- package/dist/utils/keyboardShortcut.js.map +1 -0
- package/dist/utils/linkAttrs.d.ts +13 -0
- package/dist/utils/linkAttrs.js +13 -0
- package/dist/utils/linkAttrs.js.map +1 -0
- package/dist/utils/restoreFocus.d.ts +8 -0
- package/dist/utils/restoreFocus.js +10 -0
- package/dist/utils/restoreFocus.js.map +1 -0
- package/package.json +5 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commandPalette.js","sources":["../../../../src/components/navigation/commandPalette/commandPalette.tsx"],"sourcesContent":["import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport cn from \"clsx\";\nimport { Icon } from \"../../base/icon\";\nimport { Kbd } from \"../../dataDisplay/kbd\";\nimport { Modal } from \"../../feedBack/modal\";\nimport { Skeleton } from \"../../feedBack/skeleton\";\nimport { useControllableState } from \"../../../hooks/useControllableState\";\nimport { useEventCallback } from \"../../../hooks/useEventCallback\";\nimport { useId } from \"../../../hooks/useId\";\nimport { useSafeLayoutEffect } from \"../../../hooks/useSafeLayoutEffect\";\nimport { commandPaletteFilter } from \"./commandPaletteFilter\";\nimport { firstOption, keepInView, moveOption } from \"./commandPaletteNavigation\";\nimport type {\n CommandPaletteFilter,\n CommandPaletteGroup,\n CommandPaletteItem,\n CommandPaletteSource,\n} from \"./commandPaletteTypes\";\n\nexport interface CommandPaletteProps {\n /** Controlled open state. The palette is controlled while this is not `undefined`. */\n open?: boolean;\n /** Open state used while `open` is `undefined`; `false` by default. */\n defaultOpen?: boolean;\n /**\n * Called for every request to open or close: Escape, a backdrop click, and choosing an item\n * while `closeOnSelect`. Called in the controlled and in the uncontrolled mode.\n */\n onOpenChange?: (open: boolean) => void;\n /** Static groups, filtered locally by `filter`. A group left with no items is hidden, heading included. */\n groups?: CommandPaletteGroup[];\n /**\n * Recently used items, kept by the app: it owns the list and updates it from `onSelect`. Shown as\n * the first group while the trimmed query is empty, never filtered, and hidden while searching.\n */\n recent?: CommandPaletteItem[];\n /** Heading of the recent group; `\"Recent\"` by default. That group is `{ id: \"recent\", label: recentLabel, items: recent }` in `onSelect`. */\n recentLabel?: string;\n /** Controlled query. The palette is controlled while this is not `undefined`. */\n query?: string;\n /**\n * Query used while `query` is `undefined`; `\"\"` by default. An uncontrolled field goes back to it\n * each time the palette opens.\n */\n defaultQuery?: string;\n /** Called for every edit of the field, in the controlled and in the uncontrolled mode. */\n onQueryChange?: (query: string) => void;\n /**\n * Local matching of `groups`; {@link commandPaletteFilter} by default (every word of the query\n * occurs in the label, the subtitle or a keyword, ignoring case and accents). `false` shows\n * `groups` as given, for an app that filters or ranks them itself. Never applied to `recent` or\n * to the results of `source`.\n */\n filter?: CommandPaletteFilter | false;\n /**\n * Loads results for the trimmed query, appended after the static groups. Called after `debounce`\n * milliseconds of quiet typing and only for a query of at least `minQueryLength` characters;\n * `signal` is aborted when a newer query, a close or an unmount makes the answer useless. While a\n * request is pending its predecessors' groups are not shown, and a rejection that is not an abort\n * shows `errorText`.\n */\n source?: CommandPaletteSource;\n /** Milliseconds of quiet typing before `source` is called; `200` by default. */\n debounce?: number;\n /**\n * `source` is called only when the trimmed query has at least this many characters; `1` by\n * default, so an empty query loads nothing. `0` also loads for the empty query.\n */\n minQueryLength?: number;\n /** App-driven loading: shows the skeleton like a pending `source`; `false` by default. */\n loading?: boolean;\n /**\n * Called for every chosen item, after the item's own `onSelect`. The place for the app to run the\n * command and to update its `recent` list.\n */\n onSelect?: (item: CommandPaletteItem, group: CommandPaletteGroup) => void;\n /** Ask to close (`onOpenChange(false)`) when an item is chosen; `true` by default. */\n closeOnSelect?: boolean;\n /** Placeholder of the field; `\"Type a command or search…\"` by default. It is not the field's name. */\n placeholder?: string;\n /** Accessible name of the field and, through `aria-labelledby`, of the listbox; `\"Search commands\"` by default. */\n searchLabel?: string;\n /** Shown and announced when nothing matches; `\"No results\"` by default. */\n noResultsText?: string;\n /** Shown and announced when `source` rejects; `\"Couldn't load results\"` by default. */\n errorText?: string;\n /**\n * Text of the polite status once a search has settled; `\"1 result\"` / `\"N results\"` by default.\n * Not used for zero results, which announce `noResultsText`.\n */\n resultsAnnouncement?: (count: number) => string;\n /** Slot under the results, e.g. key hints built with `Kbd`. Drawn only when given. */\n footer?: React.ReactNode;\n /** Added to the dialog element, after `smwb-command-palette`. */\n className?: string;\n /** Name of the dialog; `\"Command palette\"` by default. Not set when `aria-labelledby` is given. */\n \"aria-label\"?: string;\n /** Id of the element that names the dialog. Wins over `aria-label`. */\n \"aria-labelledby\"?: string;\n /** Id of the element that describes the dialog. */\n \"aria-describedby\"?: string;\n /** Test id of the dialog element; `\"command-palette\"` unless given. */\n \"data-testid\"?: string;\n}\n\n/** One drawn option: the item, the group it is drawn under, and where it sits in the flat list. */\ninterface Row {\n group: CommandPaletteGroup;\n item: CommandPaletteItem;\n /** Group key and item id: keeps the row active while the results change under it. */\n key: string;\n /** Position among the drawn options; names the option's id. */\n index: number;\n}\n\n/** One drawn group and its rows. */\ninterface Section {\n group: CommandPaletteGroup;\n rows: Row[];\n}\n\nconst RECENT_GROUP_ID = \"recent\";\nconst NO_GROUPS: CommandPaletteGroup[] = [];\n/** PageDown/PageUp move this many options, as the select field's listbox does. */\nconst PAGE_STEP = 10;\n/** Quiet moment before a settled search is announced, so fast typing makes no chatter. */\nconst ANNOUNCE_DELAY = 500;\nconst LOADING_ROWS = 3;\n\nconst defaultResultsAnnouncement = (count: number): string => (count === 1 ? \"1 result\" : `${count} results`);\n\nconst groupKeyOf = (group: CommandPaletteGroup): string => group.id ?? group.label;\n\n/** A rejection caused by the palette's own abort is not an error state. */\nconst isAbortError = (error: unknown): boolean =>\n typeof error === \"object\" && error !== null && (error as { name?: unknown }).name === \"AbortError\";\n\n/**\n * The ⌘K palette: a modal dialog with one search field and grouped results, driven by the keyboard.\n *\n * ArrowUp/ArrowDown (and PageUp/PageDown) move the active option, Enter runs it, Escape closes the\n * palette — all of it on the field, which keeps the focus the whole time (`aria-activedescendant`\n * points at the active option). Results come from `groups`, filtered locally, from `recent` while\n * the query is empty, and from an async `source` that is debounced and aborted on a newer query,\n * with skeleton rows while it loads plus empty and error states.\n *\n * The palette does not bind ⌘K itself: the app does it once, with `useKeyboardShortcut`, and draws\n * the same keys with `Kbd`.\n *\n * ```tsx\n * const [open, setOpen] = useState(false);\n * useKeyboardShortcut({ keys: [\"Mod\", \"K\"], onTrigger: () => setOpen((was) => !was) });\n * <Button label=\"Search\" onClick={() => setOpen(true)} endIcon={<Kbd keys={[\"Mod\", \"K\"]} />} />\n * <CommandPalette open={open} onOpenChange={setOpen} groups={groups} recent={recent} onSelect={run} />\n * ```\n *\n * Filtering and rendering are linear, so an app with a long list should cap its groups (50 items is\n * a good ceiling) or rank on the server and pass `filter={false}`.\n */\nexport const CommandPalette = forwardRef<HTMLDivElement, CommandPaletteProps>(function CommandPalette(props, ref) {\n const {\n open: openProp,\n defaultOpen = false,\n onOpenChange,\n groups = NO_GROUPS,\n recent,\n recentLabel = \"Recent\",\n query: queryProp,\n defaultQuery = \"\",\n onQueryChange,\n filter = commandPaletteFilter,\n source,\n debounce: debounceMs = 200,\n minQueryLength = 1,\n loading = false,\n onSelect,\n closeOnSelect = true,\n placeholder = \"Type a command or search…\",\n searchLabel = \"Search commands\",\n noResultsText = \"No results\",\n errorText = \"Couldn't load results\",\n resultsAnnouncement,\n footer,\n className,\n \"aria-label\": ariaLabel = \"Command palette\",\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n \"data-testid\": dataTestId = \"command-palette\",\n } = props;\n\n const [open, setOpen] = useControllableState<boolean>({\n value: openProp,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n });\n const [query, setQuery] = useControllableState<string>({\n value: queryProp,\n defaultValue: defaultQuery,\n onChange: onQueryChange,\n });\n const trimmed = query.trim();\n\n // The async answer of the current query, whether it is loading, and whether it failed. Cleared on\n // every query change, so groups of another query are never shown.\n const [asyncGroups, setAsyncGroups] = useState<CommandPaletteGroup[]>(NO_GROUPS);\n const [asyncPending, setAsyncPending] = useState(false);\n const [asyncFailed, setAsyncFailed] = useState(false);\n // The key of the option the user is on; the drawn index is derived from it (see `activeIndex`).\n const [activeKey, setActiveKey] = useState<string | null>(null);\n const [status, setStatus] = useState(\"\");\n // Bumped by a keyboard move: the effect keyed on it scrolls the active option into view.\n const [scrollTick, setScrollTick] = useState(0);\n\n // One id call in the palette body, not in the portaled panel, so the server and the client\n // consume ids in the same order.\n const uid = useId(undefined, \"smwb-command-palette\");\n const inputId = `${uid}-input`;\n const listboxId = `${uid}-listbox`;\n const optionIdAt = (index: number): string => `${listboxId}-option-${index}`;\n\n const inputRef = useRef<HTMLInputElement>(null);\n const resultsRef = useRef<HTMLDivElement>(null);\n const optionRefs = useRef<Array<HTMLLIElement | null>>([]);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const controllerRef = useRef<AbortController | null>(null);\n const lastPointerRef = useRef<{ x: number; y: number } | null>(null);\n\n // The panel element as state, used only to focus the field once the portaled panel lands: Modal\n // portals its content a commit after `open`, and jsdom has no layout, so Modal's `autoFocus` would\n // stop at the dialog itself there. In a browser the field is already the dialog's first tab stop.\n const [panelEl, setPanelEl] = useState<HTMLDivElement | null>(null);\n const attachPanel = useCallback((element: HTMLDivElement | null) => {\n setPanelEl(element);\n }, []);\n\n // Read at call time: a new function or number identity on each render must not start a request.\n const sourceRef = useRef({ source, debounce: debounceMs, minQueryLength });\n sourceRef.current = { source, debounce: debounceMs, minQueryLength };\n const announceRef = useRef(resultsAnnouncement);\n announceRef.current = resultsAnnouncement;\n const queryRef = useRef(query);\n queryRef.current = query;\n const querySeedRef = useRef({ defaultQuery, controlled: queryProp !== undefined });\n querySeedRef.current = { defaultQuery, controlled: queryProp !== undefined };\n const activeIndexRef = useRef(-1);\n\n // Rows in the order they are drawn: recent (empty query only), the static groups filtered, then\n // the answer of `source`, which is already for this query. Empty groups are dropped.\n const { sections, rows } = useMemo(() => {\n const builtSections: Section[] = [];\n const builtRows: Row[] = [];\n const add = (group: CommandPaletteGroup, items: CommandPaletteItem[]) => {\n if (items.length === 0) {\n return;\n }\n const sectionRows: Row[] = [];\n for (const item of items) {\n const row: Row = { group, item, key: `${groupKeyOf(group)}\\u0000${item.id}`, index: builtRows.length };\n builtRows.push(row);\n sectionRows.push(row);\n }\n builtSections.push({ group, rows: sectionRows });\n };\n\n if (trimmed === \"\" && recent !== undefined && recent.length > 0) {\n add({ id: RECENT_GROUP_ID, label: recentLabel, items: recent }, recent);\n }\n for (const group of groups) {\n add(group, filter === false ? group.items : group.items.filter((item) => filter(item, query)));\n }\n for (const group of asyncGroups) {\n add(group, group.items);\n }\n return { sections: builtSections, rows: builtRows };\n }, [trimmed, recent, recentLabel, groups, filter, query, asyncGroups]);\n\n const isEnabled = useCallback((index: number) => !rows[index]?.item.disabled, [rows]);\n\n // The active option is kept by key, not by index: it stays while the results change under it, and\n // falls back to the first enabled option. That option is active right away (APG list autocomplete\n // with automatic selection), so Enter runs the top hit.\n const activeIndex = useMemo(() => {\n if (activeKey !== null) {\n const kept = rows.find((row) => row.key === activeKey);\n if (kept !== undefined && !kept.item.disabled) {\n return kept.index;\n }\n }\n return firstOption(rows.length, isEnabled);\n }, [rows, activeKey, isEnabled]);\n activeIndexRef.current = activeIndex;\n\n const pending = loading || asyncPending;\n const hasOptions = rows.length > 0;\n const activeOptionId = activeIndex >= 0 ? optionIdAt(activeIndex) : undefined;\n\n // Modal owns the focus trap and the focus return; the field is focused below rather than by the\n // trap (jsdom has no layout, so the trap's `autoFocus` finds nothing there).\n useEffect(() => {\n if (panelEl !== null) {\n inputRef.current?.focus({ preventScroll: true });\n }\n }, [panelEl]);\n\n const wasOpenRef = useRef(open);\n useEffect(() => {\n const opened = open && !wasOpenRef.current;\n wasOpenRef.current = open;\n if (opened) {\n setActiveKey(null);\n const { defaultQuery: seed, controlled } = querySeedRef.current;\n // An uncontrolled field goes back to its seed each time the palette opens. A controlled one is\n // the parent's, so it is left alone and `onQueryChange` is not told about a reset it did not ask\n // for when nothing changes.\n if (!controlled && queryRef.current !== seed) {\n setQuery(seed);\n }\n } else if (!open) {\n setActiveKey(null);\n }\n }, [open, setQuery]);\n\n const cancelPending = useCallback(() => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n if (controllerRef.current !== null) {\n controllerRef.current.abort();\n controllerRef.current = null;\n }\n }, []);\n\n useEffect(() => {\n // Every new query, a close and an unmount drop what the previous one was loading: no timer may\n // outlive the palette, and an answer to another query is never shown.\n cancelPending();\n setAsyncGroups((previous) => (previous.length === 0 ? previous : NO_GROUPS));\n setAsyncFailed((previous) => (previous ? false : previous));\n setAsyncPending((previous) => (previous ? false : previous));\n if (!open) {\n return cancelPending;\n }\n const { source: load, debounce: wait, minQueryLength: min } = sourceRef.current;\n if (load === undefined || trimmed.length < min) {\n return cancelPending;\n }\n setAsyncPending(true);\n timerRef.current = setTimeout(() => {\n const controller = new AbortController();\n controllerRef.current = controller;\n void load(trimmed, { signal: controller.signal }).then(\n (loaded) => {\n // A source that ignores `signal` is still safe: an answer is applied only while its own\n // controller is the current one.\n if (controllerRef.current !== controller || controller.signal.aborted) {\n return;\n }\n controllerRef.current = null;\n setAsyncPending(false);\n setAsyncFailed(false);\n setAsyncGroups(loaded ?? NO_GROUPS);\n },\n (error: unknown) => {\n if (controllerRef.current !== controller || controller.signal.aborted || isAbortError(error)) {\n return;\n }\n controllerRef.current = null;\n setAsyncPending(false);\n setAsyncFailed(true);\n }\n );\n }, wait);\n return cancelPending;\n }, [open, trimmed, cancelPending]);\n\n const optionCount = rows.length;\n useEffect(() => {\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n if (!open || trimmed === \"\") {\n setStatus(\"\");\n } else if (!pending) {\n // Loading is exposed by `aria-busy`; the count follows once the search settles.\n timer = setTimeout(() => {\n setStatus(\n asyncFailed\n ? errorText\n : optionCount === 0\n ? noResultsText\n : (announceRef.current ?? defaultResultsAnnouncement)(optionCount)\n );\n }, ANNOUNCE_DELAY);\n }\n\n // Always return a cleanup to clear the timer if one was set. This ensures no timer outlives\n // the component on unmount or close.\n return () => {\n if (timer !== null) {\n clearTimeout(timer);\n }\n };\n }, [open, trimmed, pending, asyncFailed, errorText, noResultsText, optionCount]);\n\n // A keyboard move scrolls; a pointer move does not (the option is already where the pointer is).\n useSafeLayoutEffect(() => {\n if (scrollTick === 0) {\n return;\n }\n const option = optionRefs.current[activeIndexRef.current];\n if (option) {\n keepInView(option, resultsRef.current);\n }\n }, [scrollTick]);\n\n const handleClose = useEventCallback(() => {\n setOpen(false);\n });\n\n const handleQueryChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n setQuery(event.currentTarget.value);\n };\n\n const moveTo = (index: number) => {\n const row = rows[index];\n if (row === undefined || index === activeIndex) {\n return;\n }\n setActiveKey(row.key);\n setScrollTick((tick) => tick + 1);\n };\n\n const move = (steps: number) => {\n moveTo(moveOption(rows.length, isEnabled, activeIndex, steps));\n };\n\n const choose = (index: number) => {\n const row = rows[index];\n if (row === undefined || row.item.disabled) {\n return;\n }\n // Close first, then run the handlers, so focus a handler moves wins over the palette's own\n // focus return.\n if (closeOnSelect) {\n setOpen(false);\n }\n row.item.onSelect?.();\n onSelect?.(row.item, row.group);\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.nativeEvent.isComposing || event.keyCode === 229) {\n // The composition owns the keys. Escape is marked handled so that it cancels the composition\n // and Modal leaves the palette open.\n if (event.key === \"Escape\") {\n event.preventDefault();\n }\n return;\n }\n // Modified keys stay with the browser and with the field: Shift+ArrowDown selects text,\n // Alt+ArrowDown and Ctrl+Enter are the app's or the platform's.\n if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) {\n return;\n }\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n move(1);\n return;\n case \"ArrowUp\":\n event.preventDefault();\n move(-1);\n return;\n case \"PageDown\":\n event.preventDefault();\n move(PAGE_STEP);\n return;\n case \"PageUp\":\n event.preventDefault();\n move(-PAGE_STEP);\n return;\n case \"Enter\":\n // Always prevented: the palette is no form, and Enter without an active option does nothing.\n event.preventDefault();\n choose(activeIndex);\n return;\n default:\n // Escape is not the palette's: Modal takes it when this overlay is the top layer and the\n // event is unhandled. Everything else is native text editing. Never `stopPropagation()`\n // here — it would hide Escape from Modal's document listener and Mod+K from the app's\n // shortcut hook.\n return;\n }\n };\n\n // A press anywhere in the panel but on the field keeps the focus in the field: an option, a group\n // label, the footer or the scrollbar must not blur it. The scrollbar still drags.\n const handlePanelMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {\n if (event.target === inputRef.current) {\n return;\n }\n event.preventDefault();\n };\n\n const handleOptionPointerMove = (event: React.PointerEvent<HTMLLIElement>, row: Row) => {\n // Content scrolling under a resting pointer must not steal the active option, so only a move to\n // new coordinates counts.\n const last = lastPointerRef.current;\n if (last !== null && last.x === event.clientX && last.y === event.clientY) {\n return;\n }\n lastPointerRef.current = { x: event.clientX, y: event.clientY };\n if (row.item.disabled) {\n return;\n }\n setActiveKey(row.key);\n };\n\n // Modal spreads the attributes it does not declare onto the dialog element, so the test id travels\n // as a plain attribute bag rather than as a change to Modal's props.\n const dialogTestId = { \"data-testid\": dataTestId } as Record<string, unknown>;\n\n return (\n <Modal\n ref={ref}\n open={open}\n onClose={handleClose}\n size=\"medium\"\n animation=\"fade\"\n backdrop=\"dark\"\n closeOnEsc\n closeOnOutsideClick\n className={cn(\"smwb-command-palette\", className)}\n {...(ariaLabelledBy === undefined ? { \"aria-label\": ariaLabel } : { \"aria-labelledby\": ariaLabelledBy })}\n {...(ariaDescribedBy === undefined ? {} : { \"aria-describedby\": ariaDescribedBy })}\n {...dialogTestId}\n >\n <div className=\"smwb-command-palette__panel\" ref={attachPanel} onMouseDown={handlePanelMouseDown}>\n <div className=\"smwb-command-palette__search\">\n <span className=\"smwb-command-palette__search-icon\" aria-hidden=\"true\">\n <Icon name=\"search\" size={20} />\n </span>\n <input\n ref={inputRef}\n id={inputId}\n className=\"smwb-command-palette__input\"\n type=\"text\"\n role=\"combobox\"\n data-testid=\"command-palette-input\"\n placeholder={placeholder}\n value={query}\n aria-label={searchLabel}\n aria-autocomplete=\"list\"\n aria-expanded={hasOptions}\n aria-controls={hasOptions ? listboxId : undefined}\n aria-activedescendant={activeOptionId}\n autoComplete=\"off\"\n autoCapitalize=\"off\"\n enterKeyHint=\"go\"\n spellCheck={false}\n onChange={handleQueryChange}\n onKeyDown={handleKeyDown}\n />\n </div>\n {/* A scroller with nothing focusable inside would be a tab stop of its own in Chromium. */}\n <div\n className=\"smwb-command-palette__results\"\n ref={resultsRef}\n tabIndex={-1}\n data-testid=\"command-palette-results\"\n >\n {/* An empty listbox is drawn never: axe flags it, and a collapsed combobox may point nowhere. */}\n {hasOptions ? (\n <ul\n id={listboxId}\n className=\"smwb-command-palette__listbox\"\n role=\"listbox\"\n aria-labelledby={inputId}\n aria-busy={pending || undefined}\n data-testid=\"command-palette-listbox\"\n >\n {sections.map((section, sectionIndex) => {\n const labelId = `${listboxId}-group-${sectionIndex}`;\n return (\n <li\n key={`${groupKeyOf(section.group)}-${sectionIndex}`}\n className=\"smwb-command-palette__group\"\n role=\"group\"\n aria-labelledby={labelId}\n >\n <div className=\"smwb-command-palette__group-label\" id={labelId}>\n {section.group.label}\n </div>\n <ul className=\"smwb-command-palette__group-options\" role=\"presentation\">\n {section.rows.map((row) => {\n const optionId = optionIdAt(row.index);\n const isActive = row.index === activeIndex;\n const describedBy = [\n row.item.subtitle === undefined ? \"\" : `${optionId}-subtitle`,\n row.item.shortcut === undefined ? \"\" : `${optionId}-shortcut`,\n ]\n .filter(Boolean)\n .join(\" \");\n return (\n <li\n key={row.key}\n ref={(element) => {\n optionRefs.current[row.index] = element;\n }}\n id={optionId}\n className={cn(\n \"smwb-command-palette__item\",\n isActive && \"smwb-command-palette__item_active\",\n row.item.disabled && \"smwb-command-palette__item_disabled\"\n )}\n role=\"option\"\n // The label alone names the option; the subtitle and the shortcut caps\n // describe it, so a screen reader does not read them as part of the name.\n aria-labelledby={`${optionId}-label`}\n aria-describedby={describedBy === \"\" ? undefined : describedBy}\n aria-selected={isActive || undefined}\n aria-disabled={row.item.disabled || undefined}\n data-item-id={row.item.id}\n data-testid=\"command-palette-option\"\n onClick={() => choose(row.index)}\n onPointerMove={(event) => handleOptionPointerMove(event, row)}\n >\n {row.item.icon === undefined ? null : (\n <span className=\"smwb-command-palette__item-icon\" aria-hidden=\"true\">\n {typeof row.item.icon === \"string\" ? <Icon name={row.item.icon} /> : row.item.icon}\n </span>\n )}\n <span className=\"smwb-command-palette__item-text\">\n <span className=\"smwb-command-palette__item-label\" id={`${optionId}-label`}>\n {row.item.label}\n </span>\n {row.item.subtitle === undefined ? null : (\n <span className=\"smwb-command-palette__item-subtitle\" id={`${optionId}-subtitle`}>\n {row.item.subtitle}\n </span>\n )}\n </span>\n {row.item.shortcut === undefined ? null : (\n <Kbd\n keys={row.item.shortcut}\n id={`${optionId}-shortcut`}\n className=\"smwb-command-palette__item-shortcut\"\n />\n )}\n </li>\n );\n })}\n </ul>\n </li>\n );\n })}\n </ul>\n ) : null}\n {pending ? (\n <div className=\"smwb-command-palette__loading\" aria-hidden=\"true\" data-testid=\"command-palette-loading\">\n {Array.from({ length: LOADING_ROWS }, (_, rowIndex) => (\n <div className=\"smwb-command-palette__loading-row\" key={rowIndex}>\n <Skeleton variant=\"circular\" width={20} height={20} />\n <Skeleton variant=\"text\" width=\"60%\" />\n <Skeleton variant=\"text\" width=\"40%\" />\n </div>\n ))}\n </div>\n ) : null}\n {asyncFailed ? (\n <div\n className={cn(\"smwb-command-palette__message\", \"smwb-command-palette__message_error\")}\n data-testid=\"command-palette-error\"\n >\n {errorText}\n </div>\n ) : null}\n {!pending && !asyncFailed && !hasOptions ? (\n <div className=\"smwb-command-palette__message\" data-testid=\"command-palette-empty\">\n {noResultsText}\n </div>\n ) : null}\n </div>\n {footer === undefined || footer === null ? null : (\n <div className=\"smwb-command-palette__footer\" data-testid=\"command-palette-footer\">\n {footer}\n </div>\n )}\n {/* Inside the dialog: a screen reader ignores a live region outside an aria-modal one. */}\n <div className=\"smwb-command-palette__status\" role=\"status\" data-testid=\"command-palette-status\">\n {status}\n </div>\n </div>\n </Modal>\n );\n});\n\nexport default CommandPalette;\n"],"names":["RECENT_GROUP_ID","NO_GROUPS","PAGE_STEP","ANNOUNCE_DELAY","LOADING_ROWS","defaultResultsAnnouncement","count","groupKeyOf","group","_a","isAbortError","error","CommandPalette","forwardRef","props","ref","openProp","defaultOpen","onOpenChange","groups","recent","recentLabel","queryProp","defaultQuery","onQueryChange","filter","commandPaletteFilter","source","debounceMs","minQueryLength","loading","onSelect","closeOnSelect","placeholder","searchLabel","noResultsText","errorText","resultsAnnouncement","footer","className","ariaLabel","ariaLabelledBy","ariaDescribedBy","dataTestId","open","setOpen","useControllableState","query","setQuery","trimmed","asyncGroups","setAsyncGroups","useState","asyncPending","setAsyncPending","asyncFailed","setAsyncFailed","activeKey","setActiveKey","status","setStatus","scrollTick","setScrollTick","uid","useId","inputId","listboxId","optionIdAt","index","inputRef","useRef","resultsRef","optionRefs","timerRef","controllerRef","lastPointerRef","panelEl","setPanelEl","attachPanel","useCallback","element","sourceRef","announceRef","queryRef","querySeedRef","activeIndexRef","sections","rows","useMemo","builtSections","builtRows","add","items","sectionRows","item","row","isEnabled","activeIndex","kept","firstOption","pending","hasOptions","activeOptionId","useEffect","wasOpenRef","opened","seed","controlled","cancelPending","previous","load","wait","min","controller","loaded","optionCount","timer","useSafeLayoutEffect","option","keepInView","handleClose","useEventCallback","handleQueryChange","event","moveTo","tick","move","steps","moveOption","choose","_b","handleKeyDown","handlePanelMouseDown","handleOptionPointerMove","last","dialogTestId","jsx","Modal","cn","jsxs","Icon","section","sectionIndex","labelId","optionId","isActive","describedBy","Kbd","_","rowIndex","Skeleton"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CommandPaletteFilter } from "./commandPaletteTypes";
|
|
2
|
+
/**
|
|
3
|
+
* Lower case, without combining marks: "Café" → "cafe", "Ёжик" → "ежик". A side effect of dropping the marks
|
|
4
|
+
* is that "й" reads as "и", so a query with "и" also finds words with "й".
|
|
5
|
+
*/
|
|
6
|
+
export declare function normalizeSearchText(text: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* The palette's default filter: every word of the query occurs in the label, the subtitle or a keyword,
|
|
9
|
+
* ignoring case and accents. An empty query matches everything. It never reorders items.
|
|
10
|
+
*/
|
|
11
|
+
export declare const commandPaletteFilter: CommandPaletteFilter;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function o(e) {
|
|
2
|
+
return e.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase();
|
|
3
|
+
}
|
|
4
|
+
const c = (e, l) => {
|
|
5
|
+
var r, n;
|
|
6
|
+
const t = o(l).split(/\s+/).filter(Boolean);
|
|
7
|
+
if (t.length === 0)
|
|
8
|
+
return !0;
|
|
9
|
+
const s = o([e.label, (r = e.subtitle) != null ? r : "", ...(n = e.keywords) != null ? n : []].join(" "));
|
|
10
|
+
return t.every((a) => s.includes(a));
|
|
11
|
+
};
|
|
12
|
+
export {
|
|
13
|
+
c as commandPaletteFilter,
|
|
14
|
+
o as normalizeSearchText
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=commandPaletteFilter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commandPaletteFilter.js","sources":["../../../../src/components/navigation/commandPalette/commandPaletteFilter.ts"],"sourcesContent":["import type { CommandPaletteFilter } from \"./commandPaletteTypes\";\n\n/**\n * Lower case, without combining marks: \"Café\" → \"cafe\", \"Ёжик\" → \"ежик\". A side effect of dropping the marks\n * is that \"й\" reads as \"и\", so a query with \"и\" also finds words with \"й\".\n */\nexport function normalizeSearchText(text: string): string {\n return text.normalize(\"NFD\").replace(/[̀-ͯ]/g, \"\").toLowerCase();\n}\n\n/**\n * The palette's default filter: every word of the query occurs in the label, the subtitle or a keyword,\n * ignoring case and accents. An empty query matches everything. It never reorders items.\n */\nexport const commandPaletteFilter: CommandPaletteFilter = (item, query) => {\n const words = normalizeSearchText(query).split(/\\s+/).filter(Boolean);\n if (words.length === 0) {\n return true;\n }\n const text = normalizeSearchText([item.label, item.subtitle ?? \"\", ...(item.keywords ?? [])].join(\" \"));\n return words.every((word) => text.includes(word));\n};\n"],"names":["normalizeSearchText","text","commandPaletteFilter","item","query","_a","_b","words","word"],"mappings":"AAMO,SAASA,EAAoBC,GAAsB;AACxD,SAAOA,EAAK,UAAU,KAAK,EAAE,QAAQ,UAAU,EAAE,EAAE,YAAA;AACrD;AAMO,MAAMC,IAA6C,CAACC,GAAMC,MAAU;AARpE,MAAAC,GAAAC;AASL,QAAMC,IAAQP,EAAoBI,CAAK,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO;AACpE,MAAIG,EAAM,WAAW;AACnB,WAAO;AAET,QAAMN,IAAOD,EAAoB,CAACG,EAAK,QAAOE,IAAAF,EAAK,aAAL,OAAAE,IAAiB,IAAI,IAAIC,IAAAH,EAAK,aAAL,OAAAG,IAAiB,CAAA,CAAG,EAAE,KAAK,GAAG,CAAC;AACtG,SAAOC,EAAM,MAAM,CAACC,MAASP,EAAK,SAASO,CAAI,CAAC;AAClD;"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type IsOptionEnabled = (index: number) => boolean;
|
|
2
|
+
/** The first enabled option, or -1. */
|
|
3
|
+
export declare function firstOption(count: number, isEnabled: IsOptionEnabled): number;
|
|
4
|
+
/** The last enabled option, or -1. */
|
|
5
|
+
export declare function lastOption(count: number, isEnabled: IsOptionEnabled): number;
|
|
6
|
+
/**
|
|
7
|
+
* The enabled option `steps` options after `from` (before it for a negative
|
|
8
|
+
* count), stopping at the first or the last one. With no active option, a move
|
|
9
|
+
* down starts at the first option and a move up at the last.
|
|
10
|
+
*/
|
|
11
|
+
export declare function moveOption(count: number, isEnabled: IsOptionEnabled, from: number, steps: number): number;
|
|
12
|
+
/** Scrolls each scrolling box from the element up to `root` so the element shows. */
|
|
13
|
+
export declare function keepInView(element: HTMLElement, root: HTMLElement | null): void;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
function c(e, o) {
|
|
2
|
+
for (let t = 0; t < e; t++)
|
|
3
|
+
if (o(t))
|
|
4
|
+
return t;
|
|
5
|
+
return -1;
|
|
6
|
+
}
|
|
7
|
+
function u(e, o) {
|
|
8
|
+
for (let t = e - 1; t >= 0; t--)
|
|
9
|
+
if (o(t))
|
|
10
|
+
return t;
|
|
11
|
+
return -1;
|
|
12
|
+
}
|
|
13
|
+
function p(e, o, t, n) {
|
|
14
|
+
if (t < 0)
|
|
15
|
+
return n > 0 ? c(e, o) : u(e, o);
|
|
16
|
+
const i = n > 0 ? 1 : -1;
|
|
17
|
+
let l = t, f = Math.abs(n);
|
|
18
|
+
for (let r = t + i; r >= 0 && r < e && f > 0; r += i)
|
|
19
|
+
o(r) && (l = r, f--);
|
|
20
|
+
return l;
|
|
21
|
+
}
|
|
22
|
+
function g(e, o) {
|
|
23
|
+
for (let t = e.parentElement; t; t = t.parentElement) {
|
|
24
|
+
if (t.scrollHeight > t.clientHeight) {
|
|
25
|
+
const n = t.getBoundingClientRect(), i = e.getBoundingClientRect();
|
|
26
|
+
i.top < n.top ? t.scrollTop -= n.top - i.top : i.bottom > n.bottom && (t.scrollTop += i.bottom - n.bottom);
|
|
27
|
+
}
|
|
28
|
+
if (t === o)
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export {
|
|
33
|
+
c as firstOption,
|
|
34
|
+
g as keepInView,
|
|
35
|
+
u as lastOption,
|
|
36
|
+
p as moveOption
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=commandPaletteNavigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commandPaletteNavigation.js","sources":["../../../../src/components/navigation/commandPalette/commandPaletteNavigation.ts"],"sourcesContent":["// Moves of the active option over the palette's options, by index in the order they are drawn.\n// A disabled option is passed over. A copy of the helpers of the select field's listbox: importing\n// them from there would make the palette depend on the select field's styles.\n\nexport type IsOptionEnabled = (index: number) => boolean;\n\n/** The first enabled option, or -1. */\nexport function firstOption(count: number, isEnabled: IsOptionEnabled): number {\n for (let index = 0; index < count; index++) {\n if (isEnabled(index)) {\n return index;\n }\n }\n return -1;\n}\n\n/** The last enabled option, or -1. */\nexport function lastOption(count: number, isEnabled: IsOptionEnabled): number {\n for (let index = count - 1; index >= 0; index--) {\n if (isEnabled(index)) {\n return index;\n }\n }\n return -1;\n}\n\n/**\n * The enabled option `steps` options after `from` (before it for a negative\n * count), stopping at the first or the last one. With no active option, a move\n * down starts at the first option and a move up at the last.\n */\nexport function moveOption(count: number, isEnabled: IsOptionEnabled, from: number, steps: number): number {\n if (from < 0) {\n return steps > 0 ? firstOption(count, isEnabled) : lastOption(count, isEnabled);\n }\n const direction = steps > 0 ? 1 : -1;\n let result = from;\n let left = Math.abs(steps);\n for (let index = from + direction; index >= 0 && index < count && left > 0; index += direction) {\n if (isEnabled(index)) {\n result = index;\n left--;\n }\n }\n return result;\n}\n\n/** Scrolls each scrolling box from the element up to `root` so the element shows. */\nexport function keepInView(element: HTMLElement, root: HTMLElement | null) {\n for (let box = element.parentElement; box; box = box.parentElement) {\n if (box.scrollHeight > box.clientHeight) {\n const outer = box.getBoundingClientRect();\n const inner = element.getBoundingClientRect();\n if (inner.top < outer.top) {\n box.scrollTop -= outer.top - inner.top;\n } else if (inner.bottom > outer.bottom) {\n box.scrollTop += inner.bottom - outer.bottom;\n }\n }\n if (box === root) {\n break;\n }\n }\n}\n"],"names":["firstOption","count","isEnabled","index","lastOption","moveOption","from","steps","direction","result","left","keepInView","element","root","box","outer","inner"],"mappings":"AAOO,SAASA,EAAYC,GAAeC,GAAoC;AAC7E,WAASC,IAAQ,GAAGA,IAAQF,GAAOE;AACjC,QAAID,EAAUC,CAAK;AACjB,aAAOA;AAGX,SAAO;AACT;AAGO,SAASC,EAAWH,GAAeC,GAAoC;AAC5E,WAASC,IAAQF,IAAQ,GAAGE,KAAS,GAAGA;AACtC,QAAID,EAAUC,CAAK;AACjB,aAAOA;AAGX,SAAO;AACT;AAOO,SAASE,EAAWJ,GAAeC,GAA4BI,GAAcC,GAAuB;AACzG,MAAID,IAAO;AACT,WAAOC,IAAQ,IAAIP,EAAYC,GAAOC,CAAS,IAAIE,EAAWH,GAAOC,CAAS;AAEhF,QAAMM,IAAYD,IAAQ,IAAI,IAAI;AAClC,MAAIE,IAASH,GACTI,IAAO,KAAK,IAAIH,CAAK;AACzB,WAASJ,IAAQG,IAAOE,GAAWL,KAAS,KAAKA,IAAQF,KAASS,IAAO,GAAGP,KAASK;AACnF,IAAIN,EAAUC,CAAK,MACjBM,IAASN,GACTO;AAGJ,SAAOD;AACT;AAGO,SAASE,EAAWC,GAAsBC,GAA0B;AACzE,WAASC,IAAMF,EAAQ,eAAeE,GAAKA,IAAMA,EAAI,eAAe;AAClE,QAAIA,EAAI,eAAeA,EAAI,cAAc;AACvC,YAAMC,IAAQD,EAAI,sBAAA,GACZE,IAAQJ,EAAQ,sBAAA;AACtB,MAAII,EAAM,MAAMD,EAAM,MACpBD,EAAI,aAAaC,EAAM,MAAMC,EAAM,MAC1BA,EAAM,SAASD,EAAM,WAC9BD,EAAI,aAAaE,EAAM,SAASD,EAAM;AAAA,IAE1C;AACA,QAAID,MAAQD;AACV;AAAA,EAEJ;AACF;"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface CommandPaletteItem {
|
|
3
|
+
/** Identifies the item within its group: keeps it active across result updates; also `data-item-id`. */
|
|
4
|
+
id: string;
|
|
5
|
+
/** The item's text. Names its option and is searched by the default filter. */
|
|
6
|
+
label: string;
|
|
7
|
+
/** A second, quieter line, e.g. a path or the project a run belongs to. Searched; describes the option. */
|
|
8
|
+
subtitle?: string;
|
|
9
|
+
/** Extra words the default filter matches on (synonyms, ids, the group name). Not shown. */
|
|
10
|
+
keywords?: string[];
|
|
11
|
+
/** An icon name from the smwb set, or a node, drawn before the label. Hidden from assistive technology. */
|
|
12
|
+
icon?: string | ReactNode;
|
|
13
|
+
/**
|
|
14
|
+
* The item's own shortcut in `Kbd` key names, e.g. `["Mod", "Shift", "P"]`, drawn with `Kbd` at the end of the row.
|
|
15
|
+
* Display only: the palette does not bind it.
|
|
16
|
+
*/
|
|
17
|
+
shortcut?: string[];
|
|
18
|
+
/** Drawn dimmed, skipped by the arrow keys, and cannot be chosen. */
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
/** Runs when the item is chosen (Enter or a click), after the palette has asked to close. */
|
|
21
|
+
onSelect?: () => void;
|
|
22
|
+
}
|
|
23
|
+
export interface CommandPaletteGroup {
|
|
24
|
+
/** Stable key of the group; its label when not given. Item ids need to be unique only within a group. */
|
|
25
|
+
id?: string;
|
|
26
|
+
/** The group heading; also the accessible name of the group. */
|
|
27
|
+
label: string;
|
|
28
|
+
/** The group's items in the order they are shown. */
|
|
29
|
+
items: CommandPaletteItem[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Loads results for `query` (already trimmed). Called after the debounce; `signal` is aborted when a newer query,
|
|
33
|
+
* a close or an unmount makes the answer useless. Rejecting with anything but an abort shows the error state.
|
|
34
|
+
*/
|
|
35
|
+
export type CommandPaletteSource = (query: string, context: {
|
|
36
|
+
signal: AbortSignal;
|
|
37
|
+
}) => Promise<CommandPaletteGroup[]>;
|
|
38
|
+
/** Decides whether `item` matches `query` (the raw query; may be empty). */
|
|
39
|
+
export type CommandPaletteFilter = (item: CommandPaletteItem, query: string) => boolean;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { CommandPalette, default } from "./commandPalette";
|
|
2
|
+
export type { CommandPaletteProps } from "./commandPalette";
|
|
3
|
+
export { commandPaletteFilter, normalizeSearchText } from "./commandPaletteFilter";
|
|
4
|
+
export type { CommandPaletteFilter, CommandPaletteGroup, CommandPaletteItem, CommandPaletteSource, } from "./commandPaletteTypes";
|
|
@@ -19,6 +19,16 @@ export interface SidebarProps extends React.HTMLAttributes<HTMLElement> {
|
|
|
19
19
|
onCollapsedChange?: (collapsed: boolean) => void;
|
|
20
20
|
/** Accessible label for the built-in collapse toggle. */
|
|
21
21
|
collapseToggleAriaLabel?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Place the rail inside its container instead of pinning it to the window.
|
|
24
|
+
* The sidebar stays in the page flow (`position: relative`), keeps its
|
|
25
|
+
* variant width as a non-shrinking flex item and scrolls a long menu inside
|
|
26
|
+
* itself, so sibling content flows beside it and reflows when it collapses.
|
|
27
|
+
* Give the container a definite height (e.g. a fixed-height flex row) to
|
|
28
|
+
* make the rail fill it; with an auto-height container the rail sizes
|
|
29
|
+
* itself to the menu. Defaults to `false`: the sidebar stays viewport-fixed.
|
|
30
|
+
*/
|
|
31
|
+
contained?: boolean;
|
|
22
32
|
}
|
|
23
33
|
export declare const Sidebar: React.ForwardRefExoticComponent<SidebarProps & React.RefAttributes<HTMLElement>>;
|
|
24
34
|
export default Sidebar;
|
|
@@ -1,41 +1,43 @@
|
|
|
1
|
-
import { jsxs as
|
|
1
|
+
import { jsxs as k, jsx as e } from "react/jsx-runtime";
|
|
2
2
|
import '../../../assets/styles/less/components/sidebar/sidebar.entry.css';import '../../../assets/styles/less/tokens.entry.css';/* empty css */
|
|
3
3
|
/* empty css */
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import { Ripple as
|
|
7
|
-
import { Icon as
|
|
8
|
-
import { useControllableState as
|
|
9
|
-
const
|
|
10
|
-
className:
|
|
11
|
-
variant:
|
|
4
|
+
import g, { forwardRef as x, useState as z } from "react";
|
|
5
|
+
import y from "clsx";
|
|
6
|
+
import { Ripple as $ } from "../../base/ripple/ripple.js";
|
|
7
|
+
import { Icon as q } from "../../base/icon/icon.js";
|
|
8
|
+
import { useControllableState as B } from "../../../hooks/useControllableState.js";
|
|
9
|
+
const U = x(function({
|
|
10
|
+
className: c,
|
|
11
|
+
variant: o = "default",
|
|
12
12
|
menuItems: s,
|
|
13
|
-
activeItem:
|
|
14
|
-
defaultActiveItem:
|
|
15
|
-
onActiveItemChange:
|
|
13
|
+
activeItem: d,
|
|
14
|
+
defaultActiveItem: n = null,
|
|
15
|
+
onActiveItemChange: i,
|
|
16
16
|
collapsible: l = !1,
|
|
17
|
-
collapsed:
|
|
18
|
-
defaultCollapsed:
|
|
17
|
+
collapsed: m,
|
|
18
|
+
defaultCollapsed: p = !1,
|
|
19
19
|
onCollapsedChange: _,
|
|
20
20
|
collapseToggleAriaLabel: v = "Toggle navigation",
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
contained: w = !1,
|
|
22
|
+
...t
|
|
23
|
+
}, b) {
|
|
24
|
+
var R;
|
|
25
|
+
const h = d !== void 0, [C, E] = z(n), T = h ? d : C, [r, j] = B({
|
|
26
|
+
value: m,
|
|
27
|
+
defaultValue: p,
|
|
27
28
|
onChange: _
|
|
28
|
-
}),
|
|
29
|
-
return /* @__PURE__ */
|
|
29
|
+
}), N = l && r ? "compactMini" : o;
|
|
30
|
+
return /* @__PURE__ */ k(
|
|
30
31
|
"aside",
|
|
31
32
|
{
|
|
32
|
-
ref:
|
|
33
|
-
className:
|
|
33
|
+
ref: b,
|
|
34
|
+
className: y("smwb-sidebar", c, `smwb-${N}`, {
|
|
34
35
|
"smwb-sidebar_collapsible": l,
|
|
35
|
-
"smwb-sidebar_collapsed": l &&
|
|
36
|
+
"smwb-sidebar_collapsed": l && r,
|
|
37
|
+
"smwb-sidebar_contained": w
|
|
36
38
|
}),
|
|
37
|
-
...
|
|
38
|
-
role: (
|
|
39
|
+
...t,
|
|
40
|
+
role: (R = t.role) != null ? R : "menubar",
|
|
39
41
|
children: [
|
|
40
42
|
l && /* @__PURE__ */ e("div", { className: "smwb-sidebar__collapse", children: /* @__PURE__ */ e(
|
|
41
43
|
"button",
|
|
@@ -43,66 +45,66 @@ const Q = g(function({
|
|
|
43
45
|
type: "button",
|
|
44
46
|
className: "smwb-sidebar__collapse-btn",
|
|
45
47
|
"aria-label": v,
|
|
46
|
-
"aria-expanded": !
|
|
47
|
-
onClick: () =>
|
|
48
|
-
children: /* @__PURE__ */ e(
|
|
48
|
+
"aria-expanded": !r,
|
|
49
|
+
onClick: () => j(!r),
|
|
50
|
+
children: /* @__PURE__ */ e(q, { name: r ? "chevron_right" : "chevron_left", size: 20 })
|
|
49
51
|
}
|
|
50
52
|
) }),
|
|
51
|
-
/* @__PURE__ */ e("nav", { className: "smwb-sidebar__nav", children: s && (s == null ? void 0 : s.map((a,
|
|
52
|
-
|
|
53
|
+
/* @__PURE__ */ e("nav", { className: "smwb-sidebar__nav", children: s && (s == null ? void 0 : s.map((a, f) => /* @__PURE__ */ e(
|
|
54
|
+
F,
|
|
53
55
|
{
|
|
54
56
|
as: a.as,
|
|
55
|
-
isActive:
|
|
56
|
-
onClick: (
|
|
57
|
-
var
|
|
58
|
-
|
|
57
|
+
isActive: T === f,
|
|
58
|
+
onClick: (V) => {
|
|
59
|
+
var S;
|
|
60
|
+
h || E(f), i == null || i(f), (S = a.onClick) == null || S.call(a, V);
|
|
59
61
|
},
|
|
60
62
|
icon: a.icon,
|
|
61
63
|
title: a.title,
|
|
62
64
|
href: a.href,
|
|
63
|
-
variant:
|
|
65
|
+
variant: N
|
|
64
66
|
},
|
|
65
|
-
|
|
67
|
+
f
|
|
66
68
|
))) })
|
|
67
69
|
]
|
|
68
70
|
}
|
|
69
71
|
);
|
|
70
72
|
});
|
|
71
|
-
function
|
|
72
|
-
isActive:
|
|
73
|
-
icon:
|
|
74
|
-
title:
|
|
73
|
+
function F({
|
|
74
|
+
isActive: u,
|
|
75
|
+
icon: c,
|
|
76
|
+
title: o,
|
|
75
77
|
as: s = "div",
|
|
76
|
-
href:
|
|
77
|
-
onMouseDown:
|
|
78
|
-
variant:
|
|
78
|
+
href: d,
|
|
79
|
+
onMouseDown: n,
|
|
80
|
+
variant: i,
|
|
79
81
|
...l
|
|
80
82
|
}) {
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
}, _ = (
|
|
84
|
-
var
|
|
85
|
-
(
|
|
86
|
-
}, v = /* @__PURE__ */ e(
|
|
87
|
-
return /* @__PURE__ */
|
|
83
|
+
const m = g.useRef(null), p = (t) => {
|
|
84
|
+
n == null || n(t);
|
|
85
|
+
}, _ = (t) => {
|
|
86
|
+
var b;
|
|
87
|
+
(b = m.current) == null || b.onRipple(t);
|
|
88
|
+
}, v = /* @__PURE__ */ e($, { actionRef: m });
|
|
89
|
+
return /* @__PURE__ */ k(
|
|
88
90
|
s,
|
|
89
91
|
{
|
|
90
|
-
href:
|
|
92
|
+
href: d,
|
|
91
93
|
role: "menuitem",
|
|
92
|
-
className:
|
|
93
|
-
onMouseDown:
|
|
94
|
+
className: y("sidebar__nav__item", "smwb-nav-item", i, { active: u }),
|
|
95
|
+
onMouseDown: p,
|
|
94
96
|
onPointerDown: _,
|
|
95
97
|
...l,
|
|
96
98
|
children: [
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
c && /* @__PURE__ */ e("span", { className: "smwb-nav-item__icon", children: c }),
|
|
100
|
+
o && /* @__PURE__ */ e("span", { className: "smwb-nav-item__title", children: o }),
|
|
99
101
|
v
|
|
100
102
|
]
|
|
101
103
|
}
|
|
102
104
|
);
|
|
103
105
|
}
|
|
104
106
|
export {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
U as Sidebar,
|
|
108
|
+
U as default
|
|
107
109
|
};
|
|
108
110
|
//# sourceMappingURL=sidebar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar.js","sources":["../../../../src/components/navigation/sidebar/sidebar.tsx"],"sourcesContent":["import React, { forwardRef, useState } from \"react\";\nimport cn from \"clsx\";\nimport { Ripple, RippleActionsRef } from \"../../base/ripple/ripple\";\nimport Icon from \"../../base/icon/icon\";\nimport { useControllableState } from \"../../../hooks/useControllableState\";\n\nexport interface SidebarProps extends React.HTMLAttributes<HTMLElement> {\n className?: string;\n variant?: \"compact\" | \"default\" | \"compactMini\";\n menuItems?: MenuItemProps[];\n /** Controlled index of the active menu item. */\n activeItem?: number | null;\n /** Default active index (uncontrolled). */\n defaultActiveItem?: number | null;\n /** Called with the index of the activated item. */\n onActiveItemChange?: (index: number) => void;\n /** Render a built-in toggle that collapses the rail to an icon-only mini rail. */\n collapsible?: boolean;\n /** Controlled collapsed state. */\n collapsed?: boolean;\n /** Initial collapsed state (uncontrolled). */\n defaultCollapsed?: boolean;\n /** Called whenever the collapsed state changes. */\n onCollapsedChange?: (collapsed: boolean) => void;\n /** Accessible label for the built-in collapse toggle. */\n collapseToggleAriaLabel?: string;\n}\n\nexport const Sidebar = forwardRef<HTMLElement, SidebarProps>(function Sidebar(\n {\n className,\n variant = \"default\",\n menuItems,\n activeItem: activeItemProp,\n defaultActiveItem = null,\n onActiveItemChange,\n collapsible = false,\n collapsed: collapsedProp,\n defaultCollapsed = false,\n onCollapsedChange,\n collapseToggleAriaLabel = \"Toggle navigation\",\n ...rest\n },\n ref\n) {\n const isControlled = activeItemProp !== undefined;\n const [activeItemState, setActiveItemState] = useState<number | null>(defaultActiveItem);\n const activeItem = isControlled ? activeItemProp : activeItemState;\n\n const [collapsed, setCollapsed] = useControllableState<boolean>({\n value: collapsedProp,\n defaultValue: defaultCollapsed,\n onChange: onCollapsedChange,\n });\n\n // When collapsed the rail always shows the icon-only mini variant,\n // otherwise it honours the requested variant.\n const effectiveVariant = collapsible && collapsed ? \"compactMini\" : variant;\n\n return (\n <aside\n ref={ref}\n className={cn(\"smwb-sidebar\", className, `smwb-${effectiveVariant}`, {\n \"smwb-sidebar_collapsible\": collapsible,\n \"smwb-sidebar_collapsed\": collapsible && collapsed,\n })}\n {...rest}\n // A default: the caller's own wins, and an explicit undefined keeps it.\n role={rest.role ?? \"menubar\"}\n >\n {collapsible && (\n <div className=\"smwb-sidebar__collapse\">\n <button\n type=\"button\"\n className=\"smwb-sidebar__collapse-btn\"\n aria-label={collapseToggleAriaLabel}\n aria-expanded={!collapsed}\n onClick={() => setCollapsed(!collapsed)}\n >\n <Icon name={collapsed ? \"chevron_right\" : \"chevron_left\"} size={20} />\n </button>\n </div>\n )}\n <nav className=\"smwb-sidebar__nav\">\n {menuItems &&\n menuItems?.map((item, idx) => (\n <MenuItem\n key={idx}\n as={item.as}\n isActive={activeItem === idx}\n onClick={(e) => {\n if (!isControlled) {\n setActiveItemState(idx);\n }\n onActiveItemChange?.(idx);\n item.onClick?.(e);\n }}\n icon={item.icon}\n title={item.title}\n href={item.href}\n variant={effectiveVariant}\n />\n ))}\n </nav>\n </aside>\n );\n});\n\nexport default Sidebar;\n\nexport interface MenuItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> {\n icon?: React.ReactNode;\n title: string;\n isActive?: boolean;\n onClick?: React.MouseEventHandler<HTMLDivElement>;\n as?: React.ElementType;\n href?: string;\n variant?: \"compact\" | \"default\" | \"compactMini\";\n}\n\nfunction MenuItem({\n isActive,\n icon,\n title,\n as = \"div\",\n href,\n onMouseDown: onMouseDownProp,\n variant,\n ...rest\n}: MenuItemProps) {\n const rippleRef = React.useRef<RippleActionsRef>(null);\n\n const onMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {\n onMouseDownProp?.(event);\n };\n\n // Ripple on pointerdown so it fires for touch and pen, not just mouse.\n const onPointerDown = (event: React.PointerEvent<HTMLDivElement>) => {\n rippleRef.current?.onRipple(event);\n };\n\n const rippleElement = <Ripple actionRef={rippleRef} />;\n\n const ElementType = as;\n\n return (\n <ElementType\n href={href}\n role=\"menuitem\"\n className={cn(\"sidebar__nav__item\", \"smwb-nav-item\", variant, { active: isActive })}\n onMouseDown={onMouseDown}\n onPointerDown={onPointerDown}\n {...rest}\n >\n {icon && <span className=\"smwb-nav-item__icon\">{icon}</span>}\n {title && <span className=\"smwb-nav-item__title\">{title}</span>}\n {rippleElement}\n </ElementType>\n );\n}\n"],"names":["Sidebar","forwardRef","className","variant","menuItems","activeItemProp","defaultActiveItem","onActiveItemChange","collapsible","collapsedProp","defaultCollapsed","onCollapsedChange","collapseToggleAriaLabel","rest","ref","isControlled","activeItemState","setActiveItemState","useState","activeItem","collapsed","setCollapsed","useControllableState","effectiveVariant","jsxs","cn","_a","jsx","Icon","item","idx","MenuItem","e","isActive","icon","title","as","href","onMouseDownProp","rippleRef","React","onMouseDown","event","onPointerDown","rippleElement","Ripple"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"sidebar.js","sources":["../../../../src/components/navigation/sidebar/sidebar.tsx"],"sourcesContent":["import React, { forwardRef, useState } from \"react\";\nimport cn from \"clsx\";\nimport { Ripple, RippleActionsRef } from \"../../base/ripple/ripple\";\nimport Icon from \"../../base/icon/icon\";\nimport { useControllableState } from \"../../../hooks/useControllableState\";\n\nexport interface SidebarProps extends React.HTMLAttributes<HTMLElement> {\n className?: string;\n variant?: \"compact\" | \"default\" | \"compactMini\";\n menuItems?: MenuItemProps[];\n /** Controlled index of the active menu item. */\n activeItem?: number | null;\n /** Default active index (uncontrolled). */\n defaultActiveItem?: number | null;\n /** Called with the index of the activated item. */\n onActiveItemChange?: (index: number) => void;\n /** Render a built-in toggle that collapses the rail to an icon-only mini rail. */\n collapsible?: boolean;\n /** Controlled collapsed state. */\n collapsed?: boolean;\n /** Initial collapsed state (uncontrolled). */\n defaultCollapsed?: boolean;\n /** Called whenever the collapsed state changes. */\n onCollapsedChange?: (collapsed: boolean) => void;\n /** Accessible label for the built-in collapse toggle. */\n collapseToggleAriaLabel?: string;\n /**\n * Place the rail inside its container instead of pinning it to the window.\n * The sidebar stays in the page flow (`position: relative`), keeps its\n * variant width as a non-shrinking flex item and scrolls a long menu inside\n * itself, so sibling content flows beside it and reflows when it collapses.\n * Give the container a definite height (e.g. a fixed-height flex row) to\n * make the rail fill it; with an auto-height container the rail sizes\n * itself to the menu. Defaults to `false`: the sidebar stays viewport-fixed.\n */\n contained?: boolean;\n}\n\nexport const Sidebar = forwardRef<HTMLElement, SidebarProps>(function Sidebar(\n {\n className,\n variant = \"default\",\n menuItems,\n activeItem: activeItemProp,\n defaultActiveItem = null,\n onActiveItemChange,\n collapsible = false,\n collapsed: collapsedProp,\n defaultCollapsed = false,\n onCollapsedChange,\n collapseToggleAriaLabel = \"Toggle navigation\",\n contained = false,\n ...rest\n },\n ref\n) {\n const isControlled = activeItemProp !== undefined;\n const [activeItemState, setActiveItemState] = useState<number | null>(defaultActiveItem);\n const activeItem = isControlled ? activeItemProp : activeItemState;\n\n const [collapsed, setCollapsed] = useControllableState<boolean>({\n value: collapsedProp,\n defaultValue: defaultCollapsed,\n onChange: onCollapsedChange,\n });\n\n // When collapsed the rail always shows the icon-only mini variant,\n // otherwise it honours the requested variant.\n const effectiveVariant = collapsible && collapsed ? \"compactMini\" : variant;\n\n return (\n <aside\n ref={ref}\n className={cn(\"smwb-sidebar\", className, `smwb-${effectiveVariant}`, {\n \"smwb-sidebar_collapsible\": collapsible,\n \"smwb-sidebar_collapsed\": collapsible && collapsed,\n \"smwb-sidebar_contained\": contained,\n })}\n {...rest}\n // A default: the caller's own wins, and an explicit undefined keeps it.\n role={rest.role ?? \"menubar\"}\n >\n {collapsible && (\n <div className=\"smwb-sidebar__collapse\">\n <button\n type=\"button\"\n className=\"smwb-sidebar__collapse-btn\"\n aria-label={collapseToggleAriaLabel}\n aria-expanded={!collapsed}\n onClick={() => setCollapsed(!collapsed)}\n >\n <Icon name={collapsed ? \"chevron_right\" : \"chevron_left\"} size={20} />\n </button>\n </div>\n )}\n <nav className=\"smwb-sidebar__nav\">\n {menuItems &&\n menuItems?.map((item, idx) => (\n <MenuItem\n key={idx}\n as={item.as}\n isActive={activeItem === idx}\n onClick={(e) => {\n if (!isControlled) {\n setActiveItemState(idx);\n }\n onActiveItemChange?.(idx);\n item.onClick?.(e);\n }}\n icon={item.icon}\n title={item.title}\n href={item.href}\n variant={effectiveVariant}\n />\n ))}\n </nav>\n </aside>\n );\n});\n\nexport default Sidebar;\n\nexport interface MenuItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> {\n icon?: React.ReactNode;\n title: string;\n isActive?: boolean;\n onClick?: React.MouseEventHandler<HTMLDivElement>;\n as?: React.ElementType;\n href?: string;\n variant?: \"compact\" | \"default\" | \"compactMini\";\n}\n\nfunction MenuItem({\n isActive,\n icon,\n title,\n as = \"div\",\n href,\n onMouseDown: onMouseDownProp,\n variant,\n ...rest\n}: MenuItemProps) {\n const rippleRef = React.useRef<RippleActionsRef>(null);\n\n const onMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {\n onMouseDownProp?.(event);\n };\n\n // Ripple on pointerdown so it fires for touch and pen, not just mouse.\n const onPointerDown = (event: React.PointerEvent<HTMLDivElement>) => {\n rippleRef.current?.onRipple(event);\n };\n\n const rippleElement = <Ripple actionRef={rippleRef} />;\n\n const ElementType = as;\n\n return (\n <ElementType\n href={href}\n role=\"menuitem\"\n className={cn(\"sidebar__nav__item\", \"smwb-nav-item\", variant, { active: isActive })}\n onMouseDown={onMouseDown}\n onPointerDown={onPointerDown}\n {...rest}\n >\n {icon && <span className=\"smwb-nav-item__icon\">{icon}</span>}\n {title && <span className=\"smwb-nav-item__title\">{title}</span>}\n {rippleElement}\n </ElementType>\n );\n}\n"],"names":["Sidebar","forwardRef","className","variant","menuItems","activeItemProp","defaultActiveItem","onActiveItemChange","collapsible","collapsedProp","defaultCollapsed","onCollapsedChange","collapseToggleAriaLabel","contained","rest","ref","isControlled","activeItemState","setActiveItemState","useState","activeItem","collapsed","setCollapsed","useControllableState","effectiveVariant","jsxs","cn","_a","jsx","Icon","item","idx","MenuItem","e","isActive","icon","title","as","href","onMouseDownProp","rippleRef","React","onMouseDown","event","onPointerDown","rippleElement","Ripple"],"mappings":"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"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { Tabs } from "./tabs";
|
|
2
2
|
export type { TabsProps } from "./tabs";
|
|
3
3
|
export { Tab } from "./tab/tab";
|
|
4
|
-
export type { TabProps } from "./tab/tab";
|
|
4
|
+
export type { TabActionsApi, TabCloseReason, TabProps } from "./tab/tab";
|
|
5
|
+
export { TabPanel } from "./tabPanel/tabPanel";
|
|
6
|
+
export type { TabPanelProps } from "./tabPanel/tabPanel";
|
|
@@ -1,13 +1,100 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* What asked for a tab to close: its close button, Delete or Backspace or a middle click on it, or
|
|
4
|
+
* its `actions`.
|
|
5
|
+
*/
|
|
6
|
+
export type TabCloseReason = "button" | "key" | "middleClick" | "actions";
|
|
7
|
+
/** What a function given as `actions` receives. */
|
|
8
|
+
export interface TabActionsApi {
|
|
9
|
+
/**
|
|
10
|
+
* Ask for the tab to close, as its close button does: `onClose` is called with this event and the
|
|
11
|
+
* reason "actions", and `Tabs` moves focus on to the neighbour once the tab goes, even though focus
|
|
12
|
+
* is in a menu drawn outside the row. Call it from the item that closes the tab ("Terminate"), with
|
|
13
|
+
* that item's event. It works on a tab that is not `closable`.
|
|
14
|
+
*/
|
|
15
|
+
close: (event: React.SyntheticEvent<HTMLElement>) => void;
|
|
16
|
+
}
|
|
2
17
|
export interface TabProps extends React.HTMLAttributes<HTMLButtonElement | HTMLAnchorElement> {
|
|
3
18
|
label?: string | React.ReactNode;
|
|
4
19
|
isActive?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Whether the tab is the one in the page's Tab order (`tabIndex` 0, the others -1). `Tabs` sets
|
|
22
|
+
* it: the focused tab while focus is in the row, the selected one otherwise. On its own a tab
|
|
23
|
+
* is the stop while `isActive`.
|
|
24
|
+
*/
|
|
25
|
+
tabStop?: boolean;
|
|
5
26
|
contentRef?: React.Ref<unknown>;
|
|
27
|
+
/**
|
|
28
|
+
* Content before the label: a status marker (running, done, failed). The slot is decorative, so
|
|
29
|
+
* the tab's accessible name stays the label alone and nothing is read out twice. An icon that has
|
|
30
|
+
* to be announced belongs in `label`, where you can give it words.
|
|
31
|
+
*/
|
|
6
32
|
icon?: React.ReactNode;
|
|
7
33
|
stacked?: boolean;
|
|
34
|
+
/** The element to render. A tab with an `href` is an `a` unless you say otherwise. */
|
|
8
35
|
tag?: React.ElementType;
|
|
9
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Navigation mode: where the tab goes. The tab is then a real link (`<a href role="tab">`, with
|
|
38
|
+
* no `target`: a tab never opens another window), so it opens in place and middle click, copy
|
|
39
|
+
* link and the like work. A router takes over the plain click in `onClick` with
|
|
40
|
+
* `event.preventDefault()`; `Tabs` still calls `onChange` for it. A modified or non-primary click
|
|
41
|
+
* (Ctrl, Meta, Shift or Alt held, or a button other than the main one) is the browser's, as
|
|
42
|
+
* "open in a new tab": the router must let it through, and `Tabs` does not call `onChange`.
|
|
43
|
+
* The one exception is a middle press on a `closable` tab: it closes the tab instead, as in an
|
|
44
|
+
* editor, and its default is prevented so nothing opens.
|
|
45
|
+
*/
|
|
10
46
|
href?: string;
|
|
11
47
|
disabled?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Draw a close button after the tab, and let Delete or Backspace on the focused tab close it too
|
|
50
|
+
* (Backspace because a Mac has no Delete key); the tab lists them in `aria-keyshortcuts`. A middle
|
|
51
|
+
* press on the tab asks for the same thing (`reason` "middleClick") without selecting it. The tab
|
|
52
|
+
* does not close itself: `onClose` asks for it and the owner removes the `Tab`. The button is a
|
|
53
|
+
* sibling of the tab, not inside its `role="tab"`, so the tab's accessible name is its label alone.
|
|
54
|
+
* It is out of the Tab order (`tabIndex` -1), so the row keeps one tab stop, and a press on it takes
|
|
55
|
+
* no focus and never selects the tab. When the tab that has focus closes, `Tabs` moves focus to the
|
|
56
|
+
* tab that takes its place (the previous one if it was last), skipping disabled tabs. A disabled tab
|
|
57
|
+
* has a disabled button.
|
|
58
|
+
*
|
|
59
|
+
* The button stays in the accessibility tree, named by `closeLabel`: it is how a screen reader user
|
|
60
|
+
* who cannot press Delete, as on a touch screen, closes the tab. It sits in the tab list beside its
|
|
61
|
+
* tab, though, and ARIA 1.2 lets a `tablist` own only `tab`s: a linter that applies that strictly
|
|
62
|
+
* (axe `aria-required-children`) can flag the button, and whatever `actions` holds.
|
|
63
|
+
*
|
|
64
|
+
* To switch it off on a tab, pass `false` rather than leaving it out: a tab given `closable` or
|
|
65
|
+
* `actions` is wrapped in an item with them, a tab given neither is not, and moving between the two
|
|
66
|
+
* recreates the tab and drops its focus.
|
|
67
|
+
*/
|
|
68
|
+
closable?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Asks for the tab to close, and receives what asked for it: the close button's click (`reason`
|
|
71
|
+
* "button"), the key press of Delete or Backspace on the tab (`reason` "key", its default is
|
|
72
|
+
* prevented), the middle press on the tab (`reason` "middleClick", its default is prevented too),
|
|
73
|
+
* or the event passed to `close` by the tab's `actions` (`reason` "actions"). The owner removes
|
|
74
|
+
* the `Tab`.
|
|
75
|
+
*/
|
|
76
|
+
onClose?: (event: React.SyntheticEvent<HTMLElement>, reason: TabCloseReason) => void;
|
|
77
|
+
/** Accessible label of the close button. English by default; set it to localise, or to name the tab ("Close Terminal 1"). */
|
|
78
|
+
closeLabel?: string;
|
|
79
|
+
/**
|
|
80
|
+
* Content after the tab, before the close button: a trigger with a `Menu` ("Rename", "Terminate"),
|
|
81
|
+
* or any control. Give a function to get `{ close }` (see `TabActionsApi`). Like the close button
|
|
82
|
+
* the content is a sibling of the tab, so it is not part of the tab's name; the tab's own `ref`,
|
|
83
|
+
* `className` and handlers stay on the `role="tab"` element. It stays in the accessibility tree as
|
|
84
|
+
* written, inside the tab list (see `closable`).
|
|
85
|
+
*
|
|
86
|
+
* The row has one tab stop, so give the trigger `tabIndex={-1}`. Shift+F10 or the Menu key on the
|
|
87
|
+
* focused tab, which the tab lists in `aria-keyshortcuts`, focuses the first control in `actions`
|
|
88
|
+
* and clicks it, unless that control says `aria-expanded="true"` (it is already open). If the
|
|
89
|
+
* control names its popup in `aria-controls`, the first enabled `menuitem` in that element then
|
|
90
|
+
* takes focus, as the WAI-ARIA menu button pattern asks: ArrowDown moves on, Enter chooses, and
|
|
91
|
+
* Escape hands focus back to the trigger. Without `aria-controls` focus stays on the trigger.
|
|
92
|
+
*
|
|
93
|
+
* The row clips what overflows it: draw the menu in a portal, anchored to the trigger and with the
|
|
94
|
+
* `id` the trigger names. A choice that removes the tab ("Terminate") should call `close` with its
|
|
95
|
+
* event, so that `onClose` removes the tab and `Tabs` moves focus on to the neighbour; a tab removed
|
|
96
|
+
* some other way leaves focus on the page.
|
|
97
|
+
*/
|
|
98
|
+
actions?: React.ReactNode | ((api: TabActionsApi) => React.ReactNode);
|
|
12
99
|
}
|
|
13
100
|
export declare const Tab: React.ForwardRefExoticComponent<TabProps & React.RefAttributes<HTMLButtonElement | HTMLAnchorElement>>;
|