@k2b/ui 0.50.0 → 0.51.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/dist/base.css +32 -1
- package/dist/browser/actions/Button.js.map +1 -1
- package/dist/browser/actions/CommandList.js +861 -0
- package/dist/browser/actions/CommandList.js.map +1 -0
- package/dist/browser/actions/CommandMenu.js +237 -0
- package/dist/browser/actions/CommandMenu.js.map +1 -0
- package/dist/browser/actions/Dropdown.js +43 -10
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/command-dock.js +47 -0
- package/dist/browser/actions/command-dock.js.map +1 -0
- package/dist/browser/actions/command-items.js +84 -0
- package/dist/browser/actions/command-items.js.map +1 -0
- package/dist/browser/actions/command-messages.js +42 -0
- package/dist/browser/actions/command-messages.js.map +1 -0
- package/dist/browser/actions/index.js +1 -0
- package/dist/browser/actions/index.js.map +1 -1
- package/dist/browser/charts/core/area.js +3 -5
- package/dist/browser/charts/core/area.js.map +1 -1
- package/dist/browser/charts/core/calendar.js +1 -1
- package/dist/browser/charts/core/calendar.js.map +1 -1
- package/dist/browser/charts/core/chart-messages.js +17 -0
- package/dist/browser/charts/core/chart-messages.js.map +1 -0
- package/dist/browser/charts/core/hbar-layout.js +118 -0
- package/dist/browser/charts/core/hbar-layout.js.map +1 -0
- package/dist/browser/charts/core/hbar.js +39 -0
- package/dist/browser/charts/core/hbar.js.map +1 -0
- package/dist/browser/charts/core/index.js +7 -2
- package/dist/browser/charts/core/index.js.map +1 -1
- package/dist/browser/charts/core/map.js +116 -0
- package/dist/browser/charts/core/map.js.map +1 -0
- package/dist/browser/charts/core/registry.js +22 -15
- package/dist/browser/charts/core/registry.js.map +1 -1
- package/dist/browser/charts/core/render-size.js +13 -0
- package/dist/browser/charts/core/render-size.js.map +1 -0
- package/dist/browser/charts/core/render.js +20 -10
- package/dist/browser/charts/core/render.js.map +1 -1
- package/dist/browser/charts/core/snapshot.js +3 -3
- package/dist/browser/charts/core/snapshot.js.map +1 -1
- package/dist/browser/charts/core/svg-renderers.js +2406 -0
- package/dist/browser/charts/core/svg-renderers.js.map +1 -0
- package/dist/browser/charts/core/svg.js +4 -2525
- package/dist/browser/charts/core/svg.js.map +1 -1
- package/dist/browser/charts/core/types.js +0 -2
- package/dist/browser/charts/core/types.js.map +1 -1
- package/dist/browser/charts/core/waterfall.js +162 -0
- package/dist/browser/charts/core/waterfall.js.map +1 -0
- package/dist/browser/charts/description.js +2 -0
- package/dist/browser/charts/description.js.map +1 -0
- package/dist/browser/charts.js.map +1 -1
- package/dist/browser/content/Chart.js +14 -628
- package/dist/browser/content/Chart.js.map +1 -1
- package/dist/browser/content/ChartRoot.js +632 -0
- package/dist/browser/content/ChartRoot.js.map +1 -0
- package/dist/browser/content/ChartSparkline.js +24 -0
- package/dist/browser/content/ChartSparkline.js.map +1 -0
- package/dist/browser/content/FileView.js +111 -61
- package/dist/browser/content/FileView.js.map +1 -1
- package/dist/browser/content/Lightbox.js +8 -8
- package/dist/browser/content/Lightbox.js.map +1 -1
- package/dist/browser/content/MapView.js +30 -28
- package/dist/browser/content/MapView.js.map +1 -1
- package/dist/browser/content/PdfPreview.js +84 -52
- package/dist/browser/content/PdfPreview.js.map +1 -1
- package/dist/browser/content/PdfViewer.js +588 -0
- package/dist/browser/content/PdfViewer.js.map +1 -0
- package/dist/browser/content/chart-bar.js +246 -16
- package/dist/browser/content/chart-bar.js.map +1 -1
- package/dist/browser/content/chart-inspection-core.js +22 -21
- package/dist/browser/content/chart-inspection-core.js.map +1 -1
- package/dist/browser/content/chart-line-gaps.js +1 -1
- package/dist/browser/content/chart-line-gaps.js.map +1 -1
- package/dist/browser/content/chart-message-catalog.js +10 -0
- package/dist/browser/content/chart-message-catalog.js.map +1 -1
- package/dist/browser/content/chart-state-timeline.js +1 -1
- package/dist/browser/content/chart-state-timeline.js.map +1 -1
- package/dist/browser/content/chart-svg.js +2 -1
- package/dist/browser/content/chart-svg.js.map +1 -1
- package/dist/browser/content/index.js +1 -0
- package/dist/browser/content/index.js.map +1 -1
- package/dist/browser/content/pdf-document.js +29 -0
- package/dist/browser/content/pdf-document.js.map +1 -0
- package/dist/browser/content/pdf-limits.js +31 -0
- package/dist/browser/content/pdf-limits.js.map +1 -0
- package/dist/browser/content/pdf-messages.js +34 -2
- package/dist/browser/content/pdf-messages.js.map +1 -1
- package/dist/browser/content/pdf-viewer-engine.js +57 -0
- package/dist/browser/content/pdf-viewer-worker.js +28 -0
- package/dist/browser/inputs/ChoiceInputs.js +94 -51
- package/dist/browser/inputs/ChoiceInputs.js.map +1 -1
- package/dist/browser/inputs/ChoiceSlider.js +75 -58
- package/dist/browser/inputs/ChoiceSlider.js.map +1 -1
- package/dist/browser/inputs/DatePicker.js +113 -98
- package/dist/browser/inputs/DatePicker.js.map +1 -1
- package/dist/browser/inputs/PeriodPicker.js +874 -0
- package/dist/browser/inputs/PeriodPicker.js.map +1 -0
- package/dist/browser/inputs/index.js +4 -1
- package/dist/browser/inputs/index.js.map +1 -1
- package/dist/browser/inputs/input-messages.js +8 -2
- package/dist/browser/inputs/input-messages.js.map +1 -1
- package/dist/browser/inputs/markdown/MarkdownEditor.js +14 -10
- package/dist/browser/inputs/markdown/MarkdownEditor.js.map +1 -1
- package/dist/browser/inputs/markdown/SlashCommands.js +402 -0
- package/dist/browser/inputs/markdown/SlashCommands.js.map +1 -0
- package/dist/browser/inputs/period-picker-messages.js +71 -0
- package/dist/browser/inputs/period-picker-messages.js.map +1 -0
- package/dist/browser/inputs/period.js +263 -0
- package/dist/browser/inputs/period.js.map +1 -0
- package/dist/browser/layout/DetailPanel.js +147 -120
- package/dist/browser/layout/DetailPanel.js.map +1 -1
- package/dist/browser/layout/Discussion.js +101 -108
- package/dist/browser/layout/Discussion.js.map +1 -1
- package/dist/browser/layout/index.js.map +1 -1
- package/dist/browser/surfaces/DescriptionList.js +5 -2
- package/dist/browser/surfaces/DescriptionList.js.map +1 -1
- package/dist/browser/surfaces/StatCell.js +19 -14
- package/dist/browser/surfaces/StatCell.js.map +1 -1
- package/dist/browser/surfaces/delta-badge.js +16 -2
- package/dist/browser/surfaces/delta-badge.js.map +1 -1
- package/dist/browser/widgets/DashboardFrame.js +310 -0
- package/dist/browser/widgets/DashboardFrame.js.map +1 -0
- package/dist/browser/widgets/index.js +1 -0
- package/dist/browser/widgets/index.js.map +1 -1
- package/dist/licenses/pdfjs-dist.txt +177 -0
- package/dist/ssr/actions/Button.js.map +1 -1
- package/dist/ssr/actions/CommandList.js +638 -0
- package/dist/ssr/actions/CommandList.js.map +1 -0
- package/dist/ssr/actions/CommandMenu.js +197 -0
- package/dist/ssr/actions/CommandMenu.js.map +1 -0
- package/dist/ssr/actions/Dropdown.js +43 -10
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/command-dock.js +47 -0
- package/dist/ssr/actions/command-dock.js.map +1 -0
- package/dist/ssr/actions/command-items.js +84 -0
- package/dist/ssr/actions/command-items.js.map +1 -0
- package/dist/ssr/actions/command-messages.js +42 -0
- package/dist/ssr/actions/command-messages.js.map +1 -0
- package/dist/ssr/actions/index.js +1 -0
- package/dist/ssr/actions/index.js.map +1 -1
- package/dist/ssr/charts/core/area.js +3 -5
- package/dist/ssr/charts/core/area.js.map +1 -1
- package/dist/ssr/charts/core/calendar.js +1 -1
- package/dist/ssr/charts/core/calendar.js.map +1 -1
- package/dist/ssr/charts/core/chart-messages.js +17 -0
- package/dist/ssr/charts/core/chart-messages.js.map +1 -0
- package/dist/ssr/charts/core/hbar-layout.js +118 -0
- package/dist/ssr/charts/core/hbar-layout.js.map +1 -0
- package/dist/ssr/charts/core/hbar.js +39 -0
- package/dist/ssr/charts/core/hbar.js.map +1 -0
- package/dist/ssr/charts/core/index.js +7 -2
- package/dist/ssr/charts/core/index.js.map +1 -1
- package/dist/ssr/charts/core/map.js +116 -0
- package/dist/ssr/charts/core/map.js.map +1 -0
- package/dist/ssr/charts/core/registry.js +22 -15
- package/dist/ssr/charts/core/registry.js.map +1 -1
- package/dist/ssr/charts/core/render-size.js +13 -0
- package/dist/ssr/charts/core/render-size.js.map +1 -0
- package/dist/ssr/charts/core/render.js +20 -10
- package/dist/ssr/charts/core/render.js.map +1 -1
- package/dist/ssr/charts/core/snapshot.js +3 -3
- package/dist/ssr/charts/core/snapshot.js.map +1 -1
- package/dist/ssr/charts/core/svg-renderers.js +2406 -0
- package/dist/ssr/charts/core/svg-renderers.js.map +1 -0
- package/dist/ssr/charts/core/svg.js +4 -2525
- package/dist/ssr/charts/core/svg.js.map +1 -1
- package/dist/ssr/charts/core/types.js +0 -2
- package/dist/ssr/charts/core/types.js.map +1 -1
- package/dist/ssr/charts/core/waterfall.js +162 -0
- package/dist/ssr/charts/core/waterfall.js.map +1 -0
- package/dist/ssr/charts/description.js +2 -0
- package/dist/ssr/charts/description.js.map +1 -0
- package/dist/ssr/charts.js.map +1 -1
- package/dist/ssr/content/Chart.js +14 -471
- package/dist/ssr/content/Chart.js.map +1 -1
- package/dist/ssr/content/ChartRoot.js +475 -0
- package/dist/ssr/content/ChartRoot.js.map +1 -0
- package/dist/ssr/content/ChartSparkline.js +24 -0
- package/dist/ssr/content/ChartSparkline.js.map +1 -0
- package/dist/ssr/content/FileView.js +56 -7
- package/dist/ssr/content/FileView.js.map +1 -1
- package/dist/ssr/content/Lightbox.js +8 -8
- package/dist/ssr/content/Lightbox.js.map +1 -1
- package/dist/ssr/content/MapView.js +9 -9
- package/dist/ssr/content/MapView.js.map +1 -1
- package/dist/ssr/content/PdfPreview.js +49 -20
- package/dist/ssr/content/PdfPreview.js.map +1 -1
- package/dist/ssr/content/PdfViewer.js +484 -0
- package/dist/ssr/content/PdfViewer.js.map +1 -0
- package/dist/ssr/content/chart-bar.js +246 -16
- package/dist/ssr/content/chart-bar.js.map +1 -1
- package/dist/ssr/content/chart-inspection-core.js +22 -21
- package/dist/ssr/content/chart-inspection-core.js.map +1 -1
- package/dist/ssr/content/chart-line-gaps.js +1 -1
- package/dist/ssr/content/chart-line-gaps.js.map +1 -1
- package/dist/ssr/content/chart-message-catalog.js +10 -0
- package/dist/ssr/content/chart-message-catalog.js.map +1 -1
- package/dist/ssr/content/chart-state-timeline.js +1 -1
- package/dist/ssr/content/chart-state-timeline.js.map +1 -1
- package/dist/ssr/content/chart-svg.js +2 -1
- package/dist/ssr/content/chart-svg.js.map +1 -1
- package/dist/ssr/content/index.js +1 -0
- package/dist/ssr/content/index.js.map +1 -1
- package/dist/ssr/content/pdf-document.js +29 -0
- package/dist/ssr/content/pdf-document.js.map +1 -0
- package/dist/ssr/content/pdf-limits.js +31 -0
- package/dist/ssr/content/pdf-limits.js.map +1 -0
- package/dist/ssr/content/pdf-messages.js +34 -2
- package/dist/ssr/content/pdf-messages.js.map +1 -1
- package/dist/ssr/inputs/ChoiceInputs.js +49 -12
- package/dist/ssr/inputs/ChoiceInputs.js.map +1 -1
- package/dist/ssr/inputs/ChoiceSlider.js +17 -12
- package/dist/ssr/inputs/ChoiceSlider.js.map +1 -1
- package/dist/ssr/inputs/DatePicker.js +14 -9
- package/dist/ssr/inputs/DatePicker.js.map +1 -1
- package/dist/ssr/inputs/PeriodPicker.js +598 -0
- package/dist/ssr/inputs/PeriodPicker.js.map +1 -0
- package/dist/ssr/inputs/index.js +4 -1
- package/dist/ssr/inputs/index.js.map +1 -1
- package/dist/ssr/inputs/input-messages.js +8 -2
- package/dist/ssr/inputs/input-messages.js.map +1 -1
- package/dist/ssr/inputs/markdown/MarkdownEditor.js +3 -2
- package/dist/ssr/inputs/markdown/MarkdownEditor.js.map +1 -1
- package/dist/ssr/inputs/markdown/SlashCommands.js +339 -0
- package/dist/ssr/inputs/markdown/SlashCommands.js.map +1 -0
- package/dist/ssr/inputs/period-picker-messages.js +71 -0
- package/dist/ssr/inputs/period-picker-messages.js.map +1 -0
- package/dist/ssr/inputs/period.js +263 -0
- package/dist/ssr/inputs/period.js.map +1 -0
- package/dist/ssr/layout/DetailPanel.js +27 -4
- package/dist/ssr/layout/DetailPanel.js.map +1 -1
- package/dist/ssr/layout/Discussion.js +16 -2
- package/dist/ssr/layout/Discussion.js.map +1 -1
- package/dist/ssr/layout/index.js.map +1 -1
- package/dist/ssr/surfaces/DescriptionList.js +1 -1
- package/dist/ssr/surfaces/DescriptionList.js.map +1 -1
- package/dist/ssr/surfaces/StatCell.js +4 -5
- package/dist/ssr/surfaces/StatCell.js.map +1 -1
- package/dist/ssr/surfaces/delta-badge.js +16 -2
- package/dist/ssr/surfaces/delta-badge.js.map +1 -1
- package/dist/ssr/widgets/DashboardFrame.js +200 -0
- package/dist/ssr/widgets/DashboardFrame.js.map +1 -0
- package/dist/ssr/widgets/index.js +1 -0
- package/dist/ssr/widgets/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/Button.d.ts +1 -1
- package/dist/types/actions/CommandList.d.ts +120 -0
- package/dist/types/actions/CommandMenu.d.ts +39 -0
- package/dist/types/actions/Dropdown.d.ts +17 -0
- package/dist/types/actions/command-dock.d.ts +8 -0
- package/dist/types/actions/command-items.d.ts +134 -0
- package/dist/types/actions/command-messages.d.ts +19 -0
- package/dist/types/actions/index.d.ts +3 -0
- package/dist/types/charts/core/calendar.d.ts +1 -1
- package/dist/types/charts/core/chart-messages.d.ts +5 -0
- package/dist/types/charts/core/hbar-layout.d.ts +74 -0
- package/dist/types/charts/core/hbar.d.ts +13 -0
- package/dist/types/charts/core/index.d.ts +7 -2
- package/dist/types/charts/core/map.d.ts +3 -0
- package/dist/types/charts/core/registry.d.ts +17 -11
- package/dist/types/charts/core/render-size.d.ts +7 -0
- package/dist/types/charts/core/render.d.ts +1 -4
- package/dist/types/charts/core/snapshot.d.ts +2 -2
- package/dist/types/charts/core/svg-renderers.d.ts +722 -0
- package/dist/types/charts/core/svg.d.ts +4 -698
- package/dist/types/charts/core/types.d.ts +1 -12
- package/dist/types/charts/core/waterfall.d.ts +68 -0
- package/dist/types/charts/description.d.ts +226 -0
- package/dist/types/charts.d.ts +1 -0
- package/dist/types/content/Chart.d.ts +3 -91
- package/dist/types/content/ChartRoot.d.ts +92 -0
- package/dist/types/content/ChartSparkline.d.ts +5 -0
- package/dist/types/content/PdfViewer.d.ts +32 -0
- package/dist/types/content/chart-bar.d.ts +95 -2
- package/dist/types/content/index.d.ts +2 -0
- package/dist/types/content/pdf-document.d.ts +5 -0
- package/dist/types/content/pdf-engine.d.ts +9 -0
- package/dist/types/content/pdf-limits.d.ts +43 -0
- package/dist/types/content/pdf-messages.d.ts +16 -0
- package/dist/types/inputs/ChoiceInputs.d.ts +4 -0
- package/dist/types/inputs/ChoiceSlider.d.ts +12 -0
- package/dist/types/inputs/DatePicker.d.ts +22 -0
- package/dist/types/inputs/PeriodPicker.d.ts +24 -0
- package/dist/types/inputs/index.d.ts +8 -2
- package/dist/types/inputs/input-messages.d.ts +3 -0
- package/dist/types/inputs/markdown/MarkdownEditor.d.ts +5 -0
- package/dist/types/inputs/markdown/SlashCommands.d.ts +20 -0
- package/dist/types/inputs/period-picker-messages.d.ts +34 -0
- package/dist/types/inputs/period.d.ts +134 -0
- package/dist/types/layout/DetailPanel.d.ts +12 -0
- package/dist/types/layout/index.d.ts +1 -1
- package/dist/types/surfaces/DescriptionList.d.ts +5 -0
- package/dist/types/surfaces/StatCell.d.ts +6 -1
- package/dist/types/widgets/DashboardFrame.d.ts +58 -0
- package/dist/types/widgets/index.d.ts +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/CommandList.tsx"],"sourcesContent":["import { type Accessor, createEffect, createMemo, createSignal, For, type JSX, onCleanup, Show, untrack } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport {\n type CommandContext,\n type CommandGroup,\n type CommandItem,\n type CommandSource,\n commandKey,\n filterCommandItems,\n groupCommandItems,\n} from \"./command-items\";\nimport { useCommandMessages } from \"./command-messages\";\n\n/** The state of one open command list: its steps, the shown entries, and the marked one. */\nexport type CommandNavigator = ReturnType<typeof createCommandNavigator>;\n\n/** The context without what the list adds itself: the query, the path, the signal, and the reports. */\nexport type CommandPlace = Omit<CommandContext, \"query\" | \"path\" | \"signal\" | \"success\" | \"error\">;\n\n/** A list whose entries come from a promise: pending, or failed with the message of its rejection. */\nexport type CommandListLoad = { state: \"ready\" } | { state: \"loading\" } | { state: \"failed\"; message?: string };\n\n/** A command that returned a promise, busy while it runs. */\nexport type CommandStatus = { key: string; label: string; state: \"running\" };\n\n/**\n * What a finished command reported, shown in the list's place: a confirmation, an error (with a way to try again when\n * the command threw or rejected), or the command running again after a retry.\n */\nexport type CommandOutcome =\n | { state: \"success\"; message: string }\n | { state: \"error\"; message?: string; retry?: () => void }\n | { state: \"running\"; message: string };\n\n/** A confirmation or an error stays at least this long, even when the person types on at once. */\nexport const COMMAND_OUTCOME_MIN_MS = 1200;\n/** A confirmation goes by itself after this long; an error stays until the person types, retries, or presses Escape. */\nexport const COMMAND_OUTCOME_SUCCESS_MS = 4000;\n\nconst ignoreReport = () => {};\n\n/**\n * Keeps the steps, the marked entry, and the running command of a command list. The host owns the query and the\n * effects: `onText` places an entry's text; for an entry with `onSelect`, `beforeRun` lets the host remove its query,\n * `context` describes the text the command acts on, and `afterRun` closes the list once the command finished.\n * `onStep` runs after a further list opened or closed, with the new depth, so the host clears its query.\n */\nexport const createCommandNavigator = (options: {\n items: Accessor<CommandSource>;\n query: Accessor<string>;\n onText: (item: CommandItem) => void;\n /** The part of the context the host knows: the text and where the list is in it. */\n context: () => CommandPlace;\n /** Whether the list is open; a closed list asks no source. */\n active: () => boolean;\n beforeRun?: () => void;\n /** Runs once a command finished, before its outcome shows; `outcome` tells the host to keep its place for it. */\n afterRun: (outcome: boolean) => void;\n onStep?: (depth: number) => void;\n}) => {\n const [status, setStatus] = createSignal<CommandStatus>();\n const [outcome, setOutcome] = createSignal<CommandOutcome>();\n let shownAt = 0;\n let outcomeTimer: ReturnType<typeof setTimeout> | undefined;\n const clearOutcome = () => {\n clearTimeout(outcomeTimer);\n outcomeTimer = undefined;\n setOutcome(undefined);\n };\n const showOutcome = (next: CommandOutcome) => {\n clearTimeout(outcomeTimer);\n outcomeTimer = undefined;\n setOutcome(next);\n shownAt = Date.now();\n if (next.state === \"success\") outcomeTimer = setTimeout(clearOutcome, COMMAND_OUTCOME_SUCCESS_MS);\n };\n let running: AbortController | undefined;\n // A list that goes away forgets its run, as `reset` does: a late result reports nothing and starts no timer.\n onCleanup(() => {\n clearTimeout(outcomeTimer);\n running = undefined;\n });\n const run = (item: CommandItem, path: readonly CommandItem[], again = false) => {\n const controller = new AbortController();\n running = controller;\n const key = commandKey(item);\n setStatus(undefined);\n if (!again) options.beforeRun?.();\n // What the command reported before it finished; a stopped command's report never shows.\n let report: CommandOutcome | undefined;\n const reporting = () => running === controller && !controller.signal.aborted;\n const settle = (failure?: { error: unknown }) => {\n if (!reporting()) return;\n running = undefined;\n setStatus(undefined);\n const next: CommandOutcome | undefined = failure\n ? {\n state: \"error\",\n message: failure.error instanceof Error && failure.error.message ? failure.error.message : undefined,\n retry: () => runAgain(item, path),\n }\n : report;\n // The outcome takes its place before the host closes the list, so the container and its live regions stay and\n // their text changes, which is what a screen reader announces.\n if (next) showOutcome(next);\n else clearOutcome();\n options.afterRun(next !== undefined);\n };\n let result: unknown;\n try {\n const base = options.context();\n result = item.onSelect?.({\n ...base,\n // A command the person stopped writes nothing more.\n insert: (text: string) => {\n if (!controller.signal.aborted) base.insert(text);\n },\n success: (message: string) => {\n report = { state: \"success\", message };\n },\n error: (message: string) => {\n report = { state: \"error\", message };\n },\n query: options.query(),\n path,\n signal: controller.signal,\n });\n } catch (error) {\n settle({ error });\n return;\n }\n if (!(result instanceof Promise)) return settle();\n // A first run shows on its row; a retry runs where its error was.\n if (again) showOutcome({ state: \"running\", message: item.label });\n else setStatus({ key, label: item.label, state: \"running\" });\n result.then(\n () => settle(),\n (error: unknown) => settle({ error }),\n );\n };\n // The error stays until the retry's own state replaces it, so a host never sees the outcome go in between.\n const runAgain = (item: CommandItem, path: readonly CommandItem[]) => run(item, path, true);\n const [steps, setSteps] = createSignal<readonly CommandItem[]>([]);\n const step = () => steps().at(-1);\n // A source that returns a promise: each request has a token, and only the latest one's result reaches the list. A new\n // request aborts the previous one's signal, so stale results are discarded where they are made.\n const [retries, setRetries] = createSignal(0);\n const [settled, setSettled] = createSignal<{ token: object; items?: readonly CommandItem[]; error?: unknown }>();\n let pending: AbortController | undefined;\n type Request = { items?: readonly CommandItem[]; error?: unknown; token?: object };\n // Where the list is, compared by value: only a new place, query, or path asks a source again, not every selection event.\n const place = createMemo(() => options.context(), undefined, {\n equals: (a, b) =>\n a.text === b.text &&\n a.before === b.before &&\n a.atStart === b.atStart &&\n a.lineStart === b.lineStart &&\n a.selection.start === b.selection.start &&\n a.selection.end === b.selection.end,\n });\n const request = createMemo<Request>(() => {\n retries();\n pending?.abort();\n pending = undefined;\n if (!options.active()) return { items: [] };\n const source = step()?.next?.items ?? options.items();\n if (typeof source !== \"function\") return { items: filterCommandItems(source, options.query()) };\n const controller = new AbortController();\n const context: CommandContext = {\n ...place(),\n query: options.query(),\n path: steps(),\n signal: controller.signal,\n success: ignoreReport,\n error: ignoreReport,\n };\n let result: readonly CommandItem[] | Promise<readonly CommandItem[]>;\n try {\n result = untrack(() => source(context));\n } catch (error) {\n return { error };\n }\n if (!(result instanceof Promise)) return { items: filterCommandItems(result, context.query) };\n pending = controller;\n const token = {};\n result.then(\n (items) => {\n if (pending === controller) setSettled({ token, items: filterCommandItems(items, context.query) });\n },\n (error: unknown) => {\n if (pending === controller && !controller.signal.aborted) setSettled({ token, error });\n },\n );\n return { token };\n });\n /** Pending, failed, or ready; while a new query loads, the step's previous entries stay in place. */\n const load = createMemo<CommandListLoad>(() => {\n const current = request();\n const result = current.token ? (settled()?.token === current.token ? settled() : undefined) : current;\n if (!result) return { state: \"loading\" };\n if (result.error !== undefined) {\n const message = result.error instanceof Error && result.error.message ? result.error.message : undefined;\n return { state: \"failed\", message };\n }\n return { state: \"ready\" };\n });\n // Only entries of the same step stay while a query loads: a further list never shows the list it came from.\n const shown = createMemo<{ step: CommandItem | undefined; items: readonly CommandItem[] }>(\n (previous) => {\n const current = request();\n const at = step();\n if (!current.token) return { step: at, items: current.items ?? [] };\n const result = settled();\n if (result?.token === current.token) return { step: at, items: result.items ?? [] };\n return { step: at, items: previous.step === at ? previous.items : [] };\n },\n { step: undefined, items: [] },\n );\n const entries = () => shown().items;\n const groups = createMemo<CommandGroup[]>(() => groupCommandItems(entries()));\n const ordered = createMemo(() => groups().flatMap((group) => group.entries.map((entry) => entry.item)));\n // The marked entry is remembered for the query and step it was marked in; a new query marks the first entry again.\n const [wanted, setWanted] = createSignal<{ key: string; query: string; step: CommandItem | undefined }>();\n const active = createMemo(() => {\n const list = ordered();\n const mark = wanted();\n if (mark && mark.query === options.query() && mark.step === step()) {\n const index = list.findIndex((item) => commandKey(item) === mark.key);\n if (index >= 0) return index;\n }\n const enabled = list.findIndex((item) => !item.disabled);\n return enabled >= 0 ? enabled : 0;\n });\n const setActive = (index: number) => {\n const list = ordered();\n const item = list[(index + list.length) % Math.max(1, list.length)];\n if (item && !item.disabled) setWanted({ key: commandKey(item), query: options.query(), step: step() });\n };\n /** The next entry that can be chosen from `from` in `direction`, wrapping; unavailable entries are passed over. */\n const nextEnabled = (from: number, direction: 1 | -1) => {\n const list = ordered();\n for (let step = 1; step <= list.length; step++) {\n const index = (((from + direction * step) % list.length) + list.length) % list.length;\n if (!list[index]?.disabled) return index;\n }\n return from;\n };\n /** Chooses the marked entry or the one at `index`. An unavailable entry, or any while a command runs, does nothing. */\n const choose = (index = active()) => {\n const item = ordered()[index];\n if (!item || item.disabled || status()?.state === \"running\") return;\n if (item.next) changeStep([...steps(), item]);\n else if (item.text !== undefined) options.onText(item);\n else run(item, steps());\n };\n const changeStep = (next: readonly CommandItem[]) => {\n setSteps(next);\n setWanted(undefined);\n options.onStep?.(next.length);\n };\n // Enter while entries load waits for that query's entries and takes the first that can be chosen; a new query or no\n // match chooses nothing.\n const [awaiting, setAwaiting] = createSignal<string>();\n createEffect(() => {\n const query = awaiting();\n if (query === undefined) return;\n if (query !== options.query()) return setAwaiting(undefined);\n const state = load().state;\n if (state === \"loading\") return;\n setAwaiting(undefined);\n if (state !== \"ready\") return;\n const index = ordered().findIndex((item) => !item.disabled);\n if (index >= 0) untrack(() => choose(index));\n });\n\n return {\n query: options.query,\n step,\n groups,\n entries: ordered,\n active,\n setActive,\n /** Marks the next or previous entry, wrapping; unavailable entries are passed over, as in a searchable menu. */\n move: (delta: 1 | -1) => setActive(nextEnabled(active(), delta)),\n edge: (which: \"first\" | \"last\") => setActive(which === \"first\" ? nextEnabled(-1, 1) : nextEnabled(ordered().length, -1)),\n status,\n load,\n /** Asks a source whose promise failed again. */\n retry: () => setRetries((value) => value + 1),\n /** Whether a command's promise is pending; the list then waits for it. */\n busy: () => status()?.state === \"running\",\n choose: (index?: number) => choose(index),\n /** Enter while entries load: chooses the first entry of this query once it arrives. */\n chooseWhenLoaded: () => setAwaiting(options.query()),\n /** Whether a choice waits for entries on their way. */\n awaitingChoice: () => awaiting() !== undefined,\n /** Stops a running command: its signal aborts, and its result no longer reaches the list. */\n abort: () => {\n running?.abort();\n running = undefined;\n setStatus(undefined);\n if (outcome()?.state === \"running\") clearOutcome();\n },\n /** What the last command reported, shown in the list's place until it clears. */\n outcome,\n /** The person typed on: the outcome clears, but not before it showed for `COMMAND_OUTCOME_MIN_MS`. */\n typedOn: () => {\n const current = outcome();\n if (!current || current.state === \"running\") return;\n const left = COMMAND_OUTCOME_MIN_MS - (Date.now() - shownAt);\n if (left <= 0) return clearOutcome();\n clearTimeout(outcomeTimer);\n outcomeTimer = setTimeout(clearOutcome, left);\n },\n /** Clears the outcome at once, for Escape or a new list; a retry still running is stopped. */\n clearOutcome: () => {\n if (outcome()?.state === \"running\") {\n running?.abort();\n running = undefined;\n }\n clearOutcome();\n },\n /** Leaves the second list; `false` when the first list shows. */\n back: () => {\n if (steps().length === 0) return false;\n changeStep(steps().slice(0, -1));\n return true;\n },\n /**\n * Forgets steps, mark, and status. A running command goes on, but its result no longer reaches the list, so a\n * retry's running line goes too; a reported outcome stays until it clears.\n */\n reset: () => {\n if (outcome()?.state === \"running\") clearOutcome();\n running = undefined;\n pending?.abort();\n pending = undefined;\n setSteps([]);\n setWanted(undefined);\n setStatus(undefined);\n },\n };\n};\n\nexport const commandOptionId = (listId: string, index: number) => `${listId}-${index}`;\n\n/**\n * The rows of a command list as a list box, with the menu's own rows and headings. The focus stays in the host's\n * field, which points at the marked row as its active descendant; the rows only answer the pointer.\n */\nexport function CommandList(props: {\n navigator: CommandNavigator;\n id: string;\n /** Names the first list; a second list is named by its step. */\n label: string;\n /** Shows the step's label beside the back control, for a host without its own search field. */\n stepHint?: boolean;\n /** Says how many entries match, after the query changed. */\n query: Accessor<string>;\n /** Content between the back control and the list, such as a search field. */\n header?: JSX.Element;\n /** Runs after Retry or Close on an outcome, so the host puts the focus back where the person writes. */\n onOutcomeAction?: () => void;\n}): JSX.Element {\n const messages = useUiMessages();\n const commandMessages = useCommandMessages();\n const nav = props.navigator;\n const matches = () => nav.entries().filter((item) => !item.disabled).length;\n // The focus stays in the field, so the marked row scrolls into view itself.\n createEffect(() => {\n if (nav.entries().length === 0) return;\n document.getElementById(commandOptionId(props.id, nav.active()))?.scrollIntoView?.({ block: \"nearest\" });\n });\n const statusOf = (item: CommandItem) => {\n const current = nav.status();\n return current?.key === commandKey(item) ? current : undefined;\n };\n const runningLabel = () => {\n const current = nav.status();\n return current?.state === \"running\" ? commandMessages().running({ label: current.label }) : \"\";\n };\n const loadFailure = () => {\n const current = nav.load();\n return current.state === \"failed\" ? (current.message ?? commandMessages().loadFailed) : \"\";\n };\n /** The outcome as one line of text: the report, or for an error without one, that it did not work. */\n const outcomeText = (outcome: CommandOutcome) =>\n outcome.state === \"running\"\n ? commandMessages().running({ label: outcome.message })\n : (outcome.message ?? (outcome.state === \"error\" ? commandMessages().failed : commandMessages().done));\n const outcomeError = () => {\n const current = nav.outcome();\n return current?.state === \"error\" ? outcomeText(current) : \"\";\n };\n const status = () => {\n const current = nav.outcome();\n if (current) return current.state === \"error\" ? \"\" : outcomeText(current);\n if (runningLabel()) return runningLabel();\n const step = nav.step()?.next;\n const count = props.query().trim() || step ? messages().searchMatches({ count: matches() }) : \"\";\n return step && count ? `${step.label}, ${count}` : count;\n };\n\n return (\n <>\n {/* After a command reported, a status line of the same width takes the list's place until it clears. */}\n <Show when={!nav.outcome()} fallback={<CommandOutcomeLine navigator={nav} text={outcomeText} onAction={props.onOutcomeAction} />}>\n <Show when={nav.step()}>\n {(item) => (\n <div class=\"k2b-command-list__step\">\n <button\n type=\"button\"\n class=\"k2b-command-list__back\"\n tabIndex={-1}\n aria-label={commandMessages().back({ label: item().label })}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => nav.back()}\n >\n <i class=\"ti ti-chevron-left\" aria-hidden=\"true\" />\n <span>{item().label}</span>\n </button>\n <Show when={props.stepHint}>\n <span class=\"k2b-command-list__step-hint\">{item().next?.label}</span>\n </Show>\n </div>\n )}\n </Show>\n {props.header}\n <div\n id={props.id}\n role=\"listbox\"\n aria-label={nav.step()?.next?.label ?? props.label}\n aria-busy={nav.load().state === \"loading\" ? \"true\" : undefined}\n class=\"k2b-command-list\"\n // A press on a row leaves the focus in the host's field.\n onMouseDown={(event) => event.preventDefault()}\n >\n <For each={nav.groups()}>\n {(group) => {\n const headingId = `${props.id}-group-${group.entries[0]?.index ?? 0}`;\n return (\n <div class=\"k2b-dropdown__section\" role=\"group\" aria-labelledby={group.label ? headingId : undefined}>\n <Show when={group.label}>\n <div id={headingId} class=\"k2b-dropdown__label\">\n {group.label}\n </div>\n </Show>\n <For each={group.entries}>\n {(entry) => (\n // biome-ignore lint/a11y/useKeyWithClickEvents: the host's field handles the keys through aria-activedescendant.\n <div\n id={commandOptionId(props.id, entry.index)}\n role=\"option\"\n class=\"k2b-dropdown__item\"\n aria-selected={entry.index === nav.active()}\n aria-disabled={entry.item.disabled ? \"true\" : undefined}\n aria-busy={statusOf(entry.item)?.state === \"running\" ? \"true\" : undefined}\n data-active={entry.index === nav.active() && !entry.item.disabled ? \"\" : undefined}\n onPointerMove={() => {\n if (entry.index !== nav.active()) nav.setActive(entry.index);\n }}\n onClick={() => nav.choose(entry.index)}\n >\n <Show\n when={statusOf(entry.item)?.state !== \"running\"}\n fallback={<i class=\"ti ti-loader-2 k2b-spin k2b-command-list__busy\" aria-hidden=\"true\" />}\n >\n <Show when={entry.item.leading} fallback={<CommandVisual item={entry.item} />}>\n {(leading) => (\n <span class=\"k2b-command-list__leading\" aria-hidden=\"true\">\n {leading()()}\n </span>\n )}\n </Show>\n </Show>\n {/* One line: the label, then quietly the reason it is unavailable, or what it does. */}\n <span class=\"k2b-dropdown__copy k2b-command-list__text\">\n <span>{entry.item.label}</span>\n <Show when={entry.item.disabled ?? entry.item.description}>\n {(text) => <small class=\"k2b-command-list__description\">{text()}</small>}\n </Show>\n </span>\n <Show when={entry.item.hint}>\n {(hint) => (\n <span class=\"k2b-command-list__hint\" aria-hidden=\"true\">\n {hint()}\n </span>\n )}\n </Show>\n <Show when={entry.item.next}>\n <i class=\"ti ti-chevron-right k2b-command-list__next\" aria-hidden=\"true\" />\n </Show>\n </div>\n )}\n </For>\n </div>\n );\n }}\n </For>\n <Show when={nav.entries().length === 0 && nav.load().state === \"ready\"}>\n <p class=\"k2b-dropdown__empty\">{messages().noResults}</p>\n </Show>\n {/* Entries on their way keep the previous ones in place; the state takes one row at the end. */}\n <Show when={nav.load().state === \"loading\"}>\n <p class=\"k2b-command-list__state\">\n <i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\" />\n <span>{nav.awaitingChoice() ? commandMessages().loadingChoice : commandMessages().loading}</span>\n </p>\n </Show>\n <Show when={nav.load().state === \"failed\" ? (nav.load() as { message?: string }) : undefined}>\n {(failed) => (\n <p class=\"k2b-command-list__state\" data-error=\"\">\n <i class=\"ti ti-alert-circle\" aria-hidden=\"true\" />\n <span>{failed().message ?? commandMessages().loadFailed}</span>\n <button type=\"button\" tabIndex={-1} onMouseDown={(event) => event.preventDefault()} onClick={() => nav.retry()}>\n {messages().retry}\n </button>\n </p>\n )}\n </Show>\n </div>\n </Show>\n {/* Announced once, when the text changes: a confirmation politely, an error at once. */}\n <span class=\"k2b-sr-only\" role=\"status\">\n {status()}\n </span>\n <span class=\"k2b-sr-only\" role=\"alert\">\n {outcomeError() || loadFailure()}\n </span>\n </>\n );\n}\n\n/**\n * A command's outcome in the list's place, one line: a confirmation in the status green, an error in the status red\n * with Retry when the command threw or rejected, or a retry running. The live regions of the list announce its text,\n * so the text is hidden here; its buttons are ordinary buttons, since the list it replaced is gone.\n */\nfunction CommandOutcomeLine(props: {\n navigator: CommandNavigator;\n text: (outcome: CommandOutcome) => string;\n onAction?: () => void;\n}): JSX.Element {\n const messages = useUiMessages();\n const outcome = () => props.navigator.outcome();\n return (\n <Show when={outcome()}>\n {(current) => (\n // biome-ignore lint/a11y/noStaticElementInteractions: it holds the focus only when a menu without a target has nowhere else to keep it.\n <div\n class=\"k2b-command-outcome\"\n data-state={current().state}\n tabIndex={-1}\n onKeyDown={(event) => {\n if (event.key === \"Tab\") {\n // Tab moves between Retry and Close inside the line; only leaving it reaches the menu, which closes.\n const buttons = Array.from(event.currentTarget.querySelectorAll(\"button\"));\n const next = buttons.indexOf(document.activeElement as HTMLButtonElement) + (event.shiftKey ? -1 : 1);\n if (next >= 0 && next < buttons.length) event.stopPropagation();\n return;\n }\n // Keys on the outcome itself are the person moving on, as typing in the text is.\n if (event.target === event.currentTarget && ![\"Escape\", \"Shift\"].includes(event.key)) props.navigator.typedOn();\n }}\n >\n <i\n aria-hidden=\"true\"\n class={\n current().state === \"success\"\n ? \"ti ti-circle-check\"\n : current().state === \"error\"\n ? \"ti ti-alert-circle\"\n : \"ti ti-loader-2 k2b-spin\"\n }\n />\n <span class=\"k2b-command-outcome__text\" title={props.text(current())} aria-hidden=\"true\">\n {props.text(current())}\n </span>\n <Show when={current().state === \"error\" ? (current() as { retry?: () => void }).retry : undefined}>\n {(retry) => (\n <button\n type=\"button\"\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => {\n retry()();\n props.onAction?.();\n }}\n >\n {messages().retry}\n </button>\n )}\n </Show>\n <Show when={current().state === \"error\"}>\n <button\n type=\"button\"\n class=\"k2b-command-outcome__close\"\n aria-label={messages().close}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => {\n props.navigator.clearOutcome();\n props.onAction?.();\n }}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </Show>\n </div>\n )}\n </Show>\n );\n}\n\n/** An entry's image, one per theme when it has two, at icon size; or its icon. */\nfunction CommandVisual(props: { item: CommandItem }): JSX.Element {\n const image = () => props.item.image;\n return (\n <Show when={image()} fallback={<Show when={props.item.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>}>\n {(source) => (\n <span class=\"k2b-command-list__image\" aria-hidden=\"true\">\n <Show\n when={typeof source() === \"object\" ? (source() as { light: string; dark: string }) : undefined}\n fallback={<img src={source() as string} alt=\"\" width=\"16\" height=\"16\" decoding=\"async\" />}\n >\n {(pair) => (\n <>\n <img class=\"k2b-command-list__image-light\" src={pair().light} alt=\"\" width=\"16\" height=\"16\" decoding=\"async\" />\n <img class=\"k2b-command-list__image-dark\" src={pair().dark} alt=\"\" width=\"16\" height=\"16\" decoding=\"async\" />\n </>\n )}\n </Show>\n </span>\n )}\n </Show>\n );\n}\n\n/**\n * The keys of a command list in its host's field: Up, Down, Home, and End mark; Enter and Tab choose; Escape and\n * Backspace on an empty query leave a second list. Returns whether the key was used; Escape in the first list is left\n * to the host, which closes.\n */\nexport const commandListKey = (nav: CommandNavigator, event: KeyboardEvent, query: string): boolean => {\n if (event.isComposing || event.metaKey || event.ctrlKey || event.altKey) return false;\n switch (event.key) {\n case \"ArrowDown\":\n case \"ArrowUp\":\n if (nav.entries().length === 0) return false;\n nav.move(event.key === \"ArrowDown\" ? 1 : -1);\n return true;\n case \"Home\":\n case \"End\":\n if (event.shiftKey || nav.entries().length === 0) return false;\n nav.edge(event.key === \"Home\" ? \"first\" : \"last\");\n return true;\n case \"Enter\":\n case \"Tab\":\n // Enter while entries load takes the first entry of exactly this query once it arrives, never a stale one.\n if (event.key === \"Enter\" && !event.shiftKey && nav.load().state === \"loading\") {\n nav.chooseWhenLoaded();\n return true;\n }\n // Enter asks a list that could not load again.\n if (event.key === \"Enter\" && !event.shiftKey && nav.load().state === \"failed\" && nav.entries().length === 0) {\n nav.retry();\n return true;\n }\n if (event.shiftKey || nav.entries().length === 0) return false;\n nav.choose();\n return true;\n case \"Escape\":\n // A running command is stopped by the host, before any back.\n if (nav.busy()) return false;\n return nav.back();\n case \"Backspace\":\n return query === \"\" && nav.back();\n default:\n return false;\n }\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { memo as _$memo } from "solid-js/web";
|
|
2
|
+
import { createComponent as _$createComponent } from "solid-js/web";
|
|
3
|
+
import { ssr as _$ssr } from "solid-js/web";
|
|
4
|
+
import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
|
|
5
|
+
import { escape as _$escape } from "solid-js/web";
|
|
6
|
+
var _tmpl$ = ["<label class=\"k2b-dropdown__search\"><i class=\"ti ti-search\" aria-hidden=\"true\"></i><input type=\"search\" role=\"combobox\"", " aria-expanded=\"true\"", " aria-autocomplete=\"list\"", " autocomplete=\"off\" spellcheck=\"false\" enterkeyhint=\"go\"", "></label>"];
|
|
7
|
+
import { createEffect, createSignal, createUniqueId, on, onCleanup } from "solid-js";
|
|
8
|
+
import { replaceTextareaRange } from "../inputs/editor-dom";
|
|
9
|
+
import { CommandList, commandListKey, commandOptionId, createCommandNavigator } from "./CommandList";
|
|
10
|
+
import { dockCommandList, followComposer } from "./command-dock";
|
|
11
|
+
import { commandPlace } from "./command-items";
|
|
12
|
+
import { Dropdown, DropdownShell } from "./Dropdown";
|
|
13
|
+
/**
|
|
14
|
+
* A searchable command list beside a trigger or an anchor, with the slash menu's entries and rows: groups, icons,
|
|
15
|
+
* unavailable entries with their reason, and second lists. Focus stays in the search field; Up, Down, Home, and End
|
|
16
|
+
* mark, Enter and Tab choose, Escape or Backspace in an empty field go back, and Escape in the first list closes.
|
|
17
|
+
*/
|
|
18
|
+
function CommandMenuRoot(props) {
|
|
19
|
+
const body = shell => {
|
|
20
|
+
const listId = `k2b-command-menu-${createUniqueId().replace(/[^a-zA-Z0-9_-]/g, "-")}`;
|
|
21
|
+
const [query, setQuery] = createSignal("");
|
|
22
|
+
let input;
|
|
23
|
+
/** The open menu, kept while an outcome replaces the search field that finds it. */
|
|
24
|
+
let menu = null;
|
|
25
|
+
/** Where the focus was when an outcome took the list's place: inside the menu, or in the target. */
|
|
26
|
+
let focusInMenu = false;
|
|
27
|
+
const nav = createCommandNavigator({
|
|
28
|
+
items: () => props.items,
|
|
29
|
+
query,
|
|
30
|
+
onText: item => {
|
|
31
|
+
// Read before closing: closing resets the list.
|
|
32
|
+
const text = item.text ?? "";
|
|
33
|
+
const target = props.target;
|
|
34
|
+
shell.close(!target);
|
|
35
|
+
insert(text);
|
|
36
|
+
},
|
|
37
|
+
context: () => {
|
|
38
|
+
const target = props.target;
|
|
39
|
+
const value = target?.value ?? "";
|
|
40
|
+
const start = target?.selectionStart ?? 0;
|
|
41
|
+
return {
|
|
42
|
+
...commandPlace(value, start, start),
|
|
43
|
+
selection: {
|
|
44
|
+
start,
|
|
45
|
+
end: target?.selectionEnd ?? start
|
|
46
|
+
},
|
|
47
|
+
insert: text => insert(text)
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
active: shell.open,
|
|
51
|
+
// The focus goes back to the trigger only from inside the menu: an entry that wrote into the target, or moved
|
|
52
|
+
// the focus elsewhere itself, leaves it there. An outcome keeps the menu open in the list's place: the person
|
|
53
|
+
// writes on in the target, or, without one, the focus rests on the outcome until it clears.
|
|
54
|
+
afterRun: outcome => {
|
|
55
|
+
// An outcome replaces the search field before this runs, which leaves the focus on the page's body.
|
|
56
|
+
const focused = document.activeElement;
|
|
57
|
+
const inside = !focused || focused === document.body || Boolean(menu?.contains(focused));
|
|
58
|
+
if (!outcome) return shell.close(inside);
|
|
59
|
+
focusInMenu = inside && !props.target;
|
|
60
|
+
if (inside && props.target) props.target.focus({
|
|
61
|
+
preventScroll: true
|
|
62
|
+
});else if (focusInMenu) queueMicrotask(() => menu?.querySelector(".k2b-command-outcome")?.focus({
|
|
63
|
+
preventScroll: true
|
|
64
|
+
}));
|
|
65
|
+
},
|
|
66
|
+
onStep: () => setQuery("")
|
|
67
|
+
});
|
|
68
|
+
/** Writes into the target at its caret, as typing would, or hands the text to `onInsert`. */
|
|
69
|
+
const insert = text => {
|
|
70
|
+
const target = props.target;
|
|
71
|
+
if (!target) return props.onInsert?.(text);
|
|
72
|
+
replaceTextareaRange(target, target.selectionStart ?? 0, target.selectionEnd ?? 0, text);
|
|
73
|
+
};
|
|
74
|
+
// An outcome that cleared closes the menu; the focus returns to the trigger only from inside it.
|
|
75
|
+
createEffect(on(nav.outcome, (outcome, previous) => {
|
|
76
|
+
if (menu) {
|
|
77
|
+
if (outcome) menu.dataset.outcome = outcome.state;else delete menu.dataset.outcome;
|
|
78
|
+
}
|
|
79
|
+
if (!outcome && previous && shell.open()) shell.close(Boolean(menu?.contains(document.activeElement)) || focusInMenu);
|
|
80
|
+
}, {
|
|
81
|
+
defer: true
|
|
82
|
+
}));
|
|
83
|
+
// Typing on in the target clears an outcome once it showed long enough; keys on the outcome itself do too. When
|
|
84
|
+
// the typing opened another list for the target, such as its slash commands, the outcome gives way at once.
|
|
85
|
+
createEffect(() => {
|
|
86
|
+
const target = props.target;
|
|
87
|
+
if (!target || !nav.outcome()) return;
|
|
88
|
+
const typed = () => {
|
|
89
|
+
nav.typedOn();
|
|
90
|
+
queueMicrotask(() => {
|
|
91
|
+
const controls = target.getAttribute("aria-controls");
|
|
92
|
+
if (controls && controls !== listId) nav.clearOutcome();
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
target.addEventListener("input", typed);
|
|
96
|
+
onCleanup(() => target.removeEventListener("input", typed));
|
|
97
|
+
});
|
|
98
|
+
createEffect(on(shell.open, open => {
|
|
99
|
+
menu = input.closest(".k2b-dropdown__menu") ?? menu;
|
|
100
|
+
const docked = menu;
|
|
101
|
+
const dock = props.dock;
|
|
102
|
+
if (open && dock && docked) {
|
|
103
|
+
// A phone's keyboard moves the visible viewport, which the menu follows like the slash list.
|
|
104
|
+
const follow = () => {
|
|
105
|
+
if (docked.matches(":popover-open")) dockCommandList(docked, dock);
|
|
106
|
+
};
|
|
107
|
+
follow();
|
|
108
|
+
const stop = followComposer(dock, follow);
|
|
109
|
+
const closed = () => {
|
|
110
|
+
if (!docked.matches(":popover-open")) {
|
|
111
|
+
stop();
|
|
112
|
+
docked.removeEventListener("toggle", closed);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
docked.addEventListener("toggle", closed);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (open) {
|
|
119
|
+
// The width it opened with stays its least, so filtering never narrows it.
|
|
120
|
+
queueMicrotask(() => {
|
|
121
|
+
if (menu?.matches(":popover-open")) menu.style.minWidth = `min(${menu.getBoundingClientRect().width}px, 100vw - 2rem)`;
|
|
122
|
+
});
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (menu) menu.style.minWidth = "";
|
|
126
|
+
// Closing the menu, with Escape or a press outside, stops a running command and clears its outcome.
|
|
127
|
+
nav.abort();
|
|
128
|
+
nav.clearOutcome();
|
|
129
|
+
nav.reset();
|
|
130
|
+
setQuery("");
|
|
131
|
+
focusInMenu = false;
|
|
132
|
+
}));
|
|
133
|
+
shell.api({
|
|
134
|
+
focus: mark => {
|
|
135
|
+
input.focus({
|
|
136
|
+
preventScroll: true
|
|
137
|
+
});
|
|
138
|
+
if (mark === "last") nav.edge("last");
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
const search = _$ssr(_tmpl$, _$ssrAttribute("aria-label", _$escape(nav.step()?.next?.label ?? props.search, true), false), _$ssrAttribute("aria-controls", _$escape(listId, true), false), _$ssrAttribute("aria-activedescendant", nav.entries()[nav.active()] && !nav.entries()[nav.active()].disabled ? _$escape(commandOptionId(listId, nav.active()), true) : _$escape(undefined, true), false), _$ssrAttribute("placeholder", _$escape(nav.step()?.next?.label ?? props.search, true), false) + _$ssrAttribute("value", _$escape(query(), true), false) + _$ssrAttribute("readonly", _$escape(nav.busy(), true), false));
|
|
142
|
+
return _$createComponent(CommandList, {
|
|
143
|
+
navigator: nav,
|
|
144
|
+
id: listId,
|
|
145
|
+
get label() {
|
|
146
|
+
return props.label;
|
|
147
|
+
},
|
|
148
|
+
query: query,
|
|
149
|
+
header: search,
|
|
150
|
+
onOutcomeAction: () => {
|
|
151
|
+
if (props.target) props.target.focus({
|
|
152
|
+
preventScroll: true
|
|
153
|
+
});else menu?.querySelector(".k2b-command-outcome")?.focus({
|
|
154
|
+
preventScroll: true
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
return _$createComponent(DropdownShell, {
|
|
160
|
+
items: [],
|
|
161
|
+
body: body,
|
|
162
|
+
get label() {
|
|
163
|
+
return props.label;
|
|
164
|
+
},
|
|
165
|
+
menuClass: "k2b-command-menu",
|
|
166
|
+
get placeMenu() {
|
|
167
|
+
return props.dock ? menu => dockCommandList(menu, props.dock) : undefined;
|
|
168
|
+
},
|
|
169
|
+
get position() {
|
|
170
|
+
return props.position;
|
|
171
|
+
},
|
|
172
|
+
get align() {
|
|
173
|
+
return props.align;
|
|
174
|
+
},
|
|
175
|
+
get openAt() {
|
|
176
|
+
return props.openAt;
|
|
177
|
+
},
|
|
178
|
+
get attach() {
|
|
179
|
+
return props.attach;
|
|
180
|
+
},
|
|
181
|
+
get onOpenChange() {
|
|
182
|
+
return props.onOpenChange;
|
|
183
|
+
},
|
|
184
|
+
get disabled() {
|
|
185
|
+
return props.disabled;
|
|
186
|
+
},
|
|
187
|
+
get ["class"]() {
|
|
188
|
+
return props.class;
|
|
189
|
+
},
|
|
190
|
+
get children() {
|
|
191
|
+
return props.children;
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
export const CommandMenu = CommandMenuRoot;
|
|
196
|
+
CommandMenu.Trigger = Dropdown.Trigger;
|
|
197
|
+
//# sourceMappingURL=CommandMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/CommandMenu.tsx"],"sourcesContent":["import { createEffect, createSignal, createUniqueId, type JSX, on, onCleanup } from \"solid-js\";\nimport { replaceTextareaRange } from \"../inputs/editor-dom\";\nimport { CommandList, commandListKey, commandOptionId, createCommandNavigator } from \"./CommandList\";\nimport { dockCommandList, followComposer } from \"./command-dock\";\nimport { type CommandSource, commandPlace } from \"./command-items\";\nimport {\n Dropdown,\n type DropdownAnchor,\n type DropdownBody,\n type DropdownPosition,\n type DropdownReturnFocus,\n DropdownShell,\n} from \"./Dropdown\";\n\nexport type CommandMenuProps = {\n /** The same entries as `MarkdownEditor`'s `commands`, so the slash menu, a \"+\" button, and a chip offer one list. */\n items: CommandSource;\n /** Names the menu and its first list, such as \"Add to message\". */\n label: string;\n /** Names the search field and is its hint, such as \"Search commands\". A second list shows its own label there. */\n search: string;\n /**\n * The field the commands act on, such as the composer's textarea beside a \"+\" button. Its text and selection are the\n * `context` of an `onSelect`, and `context.insert` and entries with `text` write into it as typing would.\n */\n target?: HTMLTextAreaElement | HTMLInputElement;\n /**\n * The composer box the menu docks to, as the slash list does: as wide as the box, just above it, or below it when\n * there is more room there. Without it, the menu opens beside its trigger.\n */\n dock?: HTMLElement;\n /** Receives inserted text when there is no `target`, such as a snippet the host places itself. */\n onInsert?: (text: string) => void;\n /** The `CommandMenu.Trigger`; leave it out for a menu opened through `openAt` or `attach`. */\n children?: JSX.Element;\n position?: DropdownPosition;\n align?: \"start\" | \"end\";\n /** Receives `open`, which shows the menu beside `anchor` without its trigger; focus returns to `returnFocus`. */\n openAt?: (open: (anchor: DropdownAnchor, returnFocus?: DropdownReturnFocus) => void) => void;\n /** Adopts an element rendered elsewhere, such as a server-rendered chip, as the trigger. */\n attach?: () => HTMLElement | null | undefined;\n onOpenChange?: (open: boolean) => void;\n disabled?: boolean;\n class?: string;\n};\n\n/**\n * A searchable command list beside a trigger or an anchor, with the slash menu's entries and rows: groups, icons,\n * unavailable entries with their reason, and second lists. Focus stays in the search field; Up, Down, Home, and End\n * mark, Enter and Tab choose, Escape or Backspace in an empty field go back, and Escape in the first list closes.\n */\nfunction CommandMenuRoot(props: CommandMenuProps): JSX.Element {\n const body: DropdownBody = (shell) => {\n const listId = `k2b-command-menu-${createUniqueId().replace(/[^a-zA-Z0-9_-]/g, \"-\")}`;\n const [query, setQuery] = createSignal(\"\");\n let input!: HTMLInputElement;\n /** The open menu, kept while an outcome replaces the search field that finds it. */\n let menu: HTMLElement | null = null;\n /** Where the focus was when an outcome took the list's place: inside the menu, or in the target. */\n let focusInMenu = false;\n const nav = createCommandNavigator({\n items: () => props.items,\n query,\n onText: (item) => {\n // Read before closing: closing resets the list.\n const text = item.text ?? \"\";\n const target = props.target;\n shell.close(!target);\n insert(text);\n },\n context: () => {\n const target = props.target;\n const value = target?.value ?? \"\";\n const start = target?.selectionStart ?? 0;\n return {\n ...commandPlace(value, start, start),\n selection: { start, end: target?.selectionEnd ?? start },\n insert: (text: string) => insert(text),\n };\n },\n active: shell.open,\n // The focus goes back to the trigger only from inside the menu: an entry that wrote into the target, or moved\n // the focus elsewhere itself, leaves it there. An outcome keeps the menu open in the list's place: the person\n // writes on in the target, or, without one, the focus rests on the outcome until it clears.\n afterRun: (outcome) => {\n // An outcome replaces the search field before this runs, which leaves the focus on the page's body.\n const focused = document.activeElement;\n const inside = !focused || focused === document.body || Boolean(menu?.contains(focused));\n if (!outcome) return shell.close(inside);\n focusInMenu = inside && !props.target;\n if (inside && props.target) props.target.focus({ preventScroll: true });\n else if (focusInMenu)\n queueMicrotask(() => menu?.querySelector<HTMLElement>(\".k2b-command-outcome\")?.focus({ preventScroll: true }));\n },\n onStep: () => setQuery(\"\"),\n });\n /** Writes into the target at its caret, as typing would, or hands the text to `onInsert`. */\n const insert = (text: string) => {\n const target = props.target;\n if (!target) return props.onInsert?.(text);\n replaceTextareaRange(target as HTMLTextAreaElement, target.selectionStart ?? 0, target.selectionEnd ?? 0, text);\n };\n // An outcome that cleared closes the menu; the focus returns to the trigger only from inside it.\n createEffect(\n on(\n nav.outcome,\n (outcome, previous) => {\n if (menu) {\n if (outcome) menu.dataset.outcome = outcome.state;\n else delete menu.dataset.outcome;\n }\n if (!outcome && previous && shell.open()) shell.close(Boolean(menu?.contains(document.activeElement)) || focusInMenu);\n },\n { defer: true },\n ),\n );\n // Typing on in the target clears an outcome once it showed long enough; keys on the outcome itself do too. When\n // the typing opened another list for the target, such as its slash commands, the outcome gives way at once.\n createEffect(() => {\n const target = props.target;\n if (!target || !nav.outcome()) return;\n const typed = () => {\n nav.typedOn();\n queueMicrotask(() => {\n const controls = target.getAttribute(\"aria-controls\");\n if (controls && controls !== listId) nav.clearOutcome();\n });\n };\n target.addEventListener(\"input\", typed);\n onCleanup(() => target.removeEventListener(\"input\", typed));\n });\n createEffect(\n on(shell.open, (open) => {\n menu = input.closest<HTMLElement>(\".k2b-dropdown__menu\") ?? menu;\n const docked = menu;\n const dock = props.dock;\n if (open && dock && docked) {\n // A phone's keyboard moves the visible viewport, which the menu follows like the slash list.\n const follow = () => {\n if (docked.matches(\":popover-open\")) dockCommandList(docked, dock);\n };\n follow();\n const stop = followComposer(dock, follow);\n const closed = () => {\n if (!docked.matches(\":popover-open\")) {\n stop();\n docked.removeEventListener(\"toggle\", closed);\n }\n };\n docked.addEventListener(\"toggle\", closed);\n return;\n }\n if (open) {\n // The width it opened with stays its least, so filtering never narrows it.\n queueMicrotask(() => {\n if (menu?.matches(\":popover-open\")) menu.style.minWidth = `min(${menu.getBoundingClientRect().width}px, 100vw - 2rem)`;\n });\n return;\n }\n if (menu) menu.style.minWidth = \"\";\n // Closing the menu, with Escape or a press outside, stops a running command and clears its outcome.\n nav.abort();\n nav.clearOutcome();\n nav.reset();\n setQuery(\"\");\n focusInMenu = false;\n }),\n );\n shell.api({\n focus: (mark) => {\n input.focus({ preventScroll: true });\n if (mark === \"last\") nav.edge(\"last\");\n },\n });\n const search = (\n <label class=\"k2b-dropdown__search\">\n <i class=\"ti ti-search\" aria-hidden=\"true\" />\n <input\n ref={input}\n type=\"search\"\n role=\"combobox\"\n aria-label={nav.step()?.next?.label ?? props.search}\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n aria-activedescendant={\n nav.entries()[nav.active()] && !nav.entries()[nav.active()]!.disabled ? commandOptionId(listId, nav.active()) : undefined\n }\n autocomplete=\"off\"\n spellcheck={false}\n enterkeyhint=\"go\"\n placeholder={nav.step()?.next?.label ?? props.search}\n value={query()}\n // While a command runs, the list waits for it; the query keeps the running entry in view.\n readOnly={nav.busy()}\n onInput={(event) => setQuery(event.currentTarget.value)}\n onKeyDown={(event) => {\n if (!commandListKey(nav, event, query())) return;\n // Escape that left a second list, and Tab that chose, stay inside the menu.\n event.preventDefault();\n event.stopPropagation();\n }}\n />\n </label>\n );\n return (\n <CommandList\n navigator={nav}\n id={listId}\n label={props.label}\n query={query}\n header={search}\n // After Retry or Close the focus stays where the person works: the target, or the outcome itself.\n onOutcomeAction={() => {\n if (props.target) props.target.focus({ preventScroll: true });\n else menu?.querySelector<HTMLElement>(\".k2b-command-outcome\")?.focus({ preventScroll: true });\n }}\n />\n );\n };\n\n return (\n <DropdownShell\n items={[]}\n body={body}\n label={props.label}\n menuClass=\"k2b-command-menu\"\n placeMenu={props.dock ? (menu) => dockCommandList(menu, props.dock!) : undefined}\n position={props.position}\n align={props.align}\n openAt={props.openAt}\n attach={props.attach}\n onOpenChange={props.onOpenChange}\n disabled={props.disabled}\n class={props.class}\n >\n {props.children}\n </DropdownShell>\n );\n}\n\ntype CommandMenuComponent = ((props: CommandMenuProps) => JSX.Element) & {\n Trigger: typeof Dropdown.Trigger;\n};\n\nexport const CommandMenu = CommandMenuRoot as CommandMenuComponent;\nCommandMenu.Trigger = Dropdown.Trigger;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -468,6 +468,11 @@ function DropdownTrigger(props) {
|
|
|
468
468
|
})];
|
|
469
469
|
}
|
|
470
470
|
|
|
471
|
+
/**
|
|
472
|
+
* Internal: content in place of the entries, as `CommandMenu` renders its command list. It reports where the focus
|
|
473
|
+
* goes as the menu opens, like the search field, and `open` tells it when the menu closed.
|
|
474
|
+
*/
|
|
475
|
+
|
|
471
476
|
/** Accessible top-layer menu with explicit trigger ownership. */
|
|
472
477
|
function DropdownRoot(props) {
|
|
473
478
|
const messages = useUiMessages();
|
|
@@ -500,6 +505,8 @@ function DropdownRoot(props) {
|
|
|
500
505
|
const isOpen = () => props.open ?? internalOpen();
|
|
501
506
|
const position = () => typeof props.position === "function" ? props.position() : props.position ?? (props.align === "end" ? "bottom-left" : "bottom-right");
|
|
502
507
|
const place = () => {
|
|
508
|
+
// Internal: `CommandMenu` docks its menu to a composer instead of its trigger.
|
|
509
|
+
if (props.placeMenu && menuRef) return props.placeMenu(menuRef);
|
|
503
510
|
const at = anchor ?? triggerRef;
|
|
504
511
|
if (!at || !menuRef) return;
|
|
505
512
|
const rect = dropdownPosition(at.getBoundingClientRect(), menuRef.getBoundingClientRect(), position(), {
|
|
@@ -562,7 +569,7 @@ function DropdownRoot(props) {
|
|
|
562
569
|
props.onOpenChange?.(next);
|
|
563
570
|
return;
|
|
564
571
|
}
|
|
565
|
-
if (next && props.phone === "sheet" && prefersMenuSheet()) {
|
|
572
|
+
if (next && props.phone === "sheet" && !props.body && prefersMenuSheet()) {
|
|
566
573
|
if (sheet) return;
|
|
567
574
|
const current = new AbortController();
|
|
568
575
|
sheet = current;
|
|
@@ -601,7 +608,7 @@ function DropdownRoot(props) {
|
|
|
601
608
|
const handleMenuKeyDown = event => {
|
|
602
609
|
const items = actionableItems(menuRef);
|
|
603
610
|
// A searchable menu's field keeps the focus and moves the marked entry itself.
|
|
604
|
-
if (!props.search && (focusMenuRow(items, event.key) || focusRowSegment(items, event.key))) {
|
|
611
|
+
if (!props.search && !props.body && (focusMenuRow(items, event.key) || focusRowSegment(items, event.key))) {
|
|
605
612
|
event.preventDefault();
|
|
606
613
|
} else if (event.key === "Escape") {
|
|
607
614
|
event.preventDefault();
|
|
@@ -638,7 +645,7 @@ function DropdownRoot(props) {
|
|
|
638
645
|
triggerRef = element;
|
|
639
646
|
},
|
|
640
647
|
toggle,
|
|
641
|
-
popup: () => props.search ? "dialog" : "menu",
|
|
648
|
+
popup: () => props.search || props.body ? "dialog" : "menu",
|
|
642
649
|
triggerKeyDown: event => triggerKey(event)
|
|
643
650
|
};
|
|
644
651
|
createEffect(() => {
|
|
@@ -688,23 +695,47 @@ function DropdownRoot(props) {
|
|
|
688
695
|
return _$createComponent(DropdownContext.Provider, {
|
|
689
696
|
value: context,
|
|
690
697
|
get children() {
|
|
691
|
-
return _$ssr(_tmpl$16, `k2b-dropdown ${_$escape(props.class ?? "", true)}`, _$escape(props.children), _$ssrAttribute("id", _$escape(menuId, true), false), _$ssrAttribute("role", props.search ? "dialog" : "menu", false) + _$ssrAttribute("aria-label", _$escape(props.label ?? messages().dropdownMenu, true), false) + _$ssrAttribute("aria-describedby", props.note ? `${_$escape(menuId, true)}-note` : _$escape(undefined, true), false), `k2b-dropdown__menu ${_$escape(props.menuClass ?? "", true)}`, _$ssrStyle(props.width ? {
|
|
698
|
+
return _$ssr(_tmpl$16, `k2b-dropdown ${_$escape(props.class ?? "", true)}`, _$escape(props.children), _$ssrAttribute("id", _$escape(menuId, true), false), _$ssrAttribute("role", props.search || props.body ? "dialog" : "menu", false) + _$ssrAttribute("aria-label", _$escape(props.label ?? messages().dropdownMenu, true), false) + _$ssrAttribute("aria-describedby", props.note ? `${_$escape(menuId, true)}-note` : _$escape(undefined, true), false), `k2b-dropdown__menu ${_$escape(props.menuClass ?? "", true)}`, _$ssrStyle(props.width ? {
|
|
692
699
|
"--k2b-dropdown-width": props.width
|
|
693
|
-
} : undefined), _$ssrAttribute("data-width", props.width ? "fixed" : _$escape(undefined, true), false) + _$ssrAttribute("data-variant", _$escape(props.variant ?? "default", true), false) + _$ssrAttribute("data-icons", props.icons === "tile" ? "tile" : _$escape(undefined, true), false) + _$ssrAttribute("data-search", props.search ? "" : _$escape(undefined, true), false) + _$ssrAttribute("data-position", _$escape(position(), true), false), _$escape(_$createComponent(Show, {
|
|
700
|
+
} : undefined), _$ssrAttribute("data-width", props.width ? "fixed" : _$escape(undefined, true), false) + _$ssrAttribute("data-variant", _$escape(props.variant ?? "default", true), false) + _$ssrAttribute("data-icons", props.icons === "tile" ? "tile" : _$escape(undefined, true), false) + _$ssrAttribute("data-search", props.search || props.body ? "" : _$escape(undefined, true), false) + _$ssrAttribute("data-position", _$escape(position(), true), false), _$escape(_$createComponent(Show, {
|
|
694
701
|
get when() {
|
|
695
702
|
return entriesShown();
|
|
696
703
|
},
|
|
697
704
|
get children() {
|
|
698
705
|
return [_$createComponent(Show, {
|
|
699
706
|
get when() {
|
|
700
|
-
return props.
|
|
707
|
+
return props.body;
|
|
708
|
+
},
|
|
709
|
+
children: body => {
|
|
710
|
+
const Body = body();
|
|
711
|
+
return _$createComponent(Body, {
|
|
712
|
+
close: close,
|
|
713
|
+
open: isOpen,
|
|
714
|
+
api: api => {
|
|
715
|
+
searchApi = api;
|
|
716
|
+
onCleanup(() => {
|
|
717
|
+
if (searchApi === api) searchApi = undefined;
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
}), _$createComponent(Show, {
|
|
723
|
+
get when() {
|
|
724
|
+
return _$memo(() => !!!props.body)() && props.search;
|
|
701
725
|
},
|
|
702
726
|
get fallback() {
|
|
703
|
-
return _$createComponent(
|
|
704
|
-
get
|
|
705
|
-
return props.
|
|
727
|
+
return _$createComponent(Show, {
|
|
728
|
+
get when() {
|
|
729
|
+
return !props.body;
|
|
706
730
|
},
|
|
707
|
-
|
|
731
|
+
get children() {
|
|
732
|
+
return _$createComponent(DropdownItems, {
|
|
733
|
+
get items() {
|
|
734
|
+
return props.items;
|
|
735
|
+
},
|
|
736
|
+
close: close
|
|
737
|
+
});
|
|
738
|
+
}
|
|
708
739
|
});
|
|
709
740
|
},
|
|
710
741
|
children: search => _$createComponent(MenuSearch, {
|
|
@@ -741,6 +772,8 @@ function DropdownRoot(props) {
|
|
|
741
772
|
}
|
|
742
773
|
});
|
|
743
774
|
}
|
|
775
|
+
/** Internal: the menu with a `body`, for `CommandMenu`. */
|
|
776
|
+
export const DropdownShell = DropdownRoot;
|
|
744
777
|
export const Dropdown = DropdownRoot;
|
|
745
778
|
Dropdown.Root = DropdownRoot;
|
|
746
779
|
Dropdown.Trigger = DropdownTrigger;
|