@vielzeug/refine 26.10.1 → 26.10.5
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/command-palette.cjs +9 -1
- package/dist/command-palette.cjs.map +1 -1
- package/dist/command-palette.js +9 -1
- package/dist/command-palette.js.map +1 -1
- package/dist/custom-elements.json +19 -0
- package/dist/overlay/command-palette/command-palette.css.cjs +1 -1
- package/dist/overlay/command-palette/command-palette.css.cjs.map +1 -1
- package/dist/overlay/command-palette/command-palette.css.js +1 -1
- package/dist/overlay/command-palette/command-palette.css.js.map +1 -1
- package/dist/overlay/command-palette/command-palette.d.ts +4 -0
- package/dist/overlay/command-palette/command-palette.d.ts.map +1 -1
- package/dist/overlay/command-palette/command-palette.types.d.ts +10 -0
- package/dist/overlay/command-palette/command-palette.types.d.ts.map +1 -1
- package/dist/refine.cjs +9 -1
- package/dist/refine.cjs.map +1 -1
- package/dist/refine.iife.js +9 -1
- package/dist/refine.iife.js.map +1 -1
- package/dist/refine.js +9 -1
- package/dist/refine.js.map +1 -1
- package/package.json +13 -13
package/dist/command-palette.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/accessibility.css.cjs"),t=require("./core/announcer.cjs");require("./_dev.cjs");const n=require("./core/ore.cjs"),r=require("./core/nav.cjs"),i=require("./core/parse.cjs"),a=require("./icon.cjs"),o=require("./overlay/shared/use-dialog.cjs"),s=require("./overlay/command-palette/command-palette.css.cjs"),c=require("./overlay/command-palette/command-palette-items.cjs"),l=require("./keyboard-key.cjs");let u=require("@vielzeug/ripple"),d=require("@vielzeug/ore"),f=require("@vielzeug/keymap");var p=`ore-command-palette-item`;(0,d.define)(p,{setup(){return d.html``}});var m=`ore-command-palette`;(0,d.define)(m,{props:{"default-open":d.prop.bool(!1),"empty-text":d.prop.string(`No results found.`),items:d.prop.data(),"keep-open-on-select":d.prop.bool(!1),label:d.prop.string(`Command palette`),loading:d.prop.bool(!1),"no-filter":d.prop.bool(!1),open:{default:void 0,parse:i.parseOptionalBool},placeholder:d.prop.string(`Type a command or search…`),shortcut:d.prop.string(`mod+k`)},setup(e){let i=(0,d.getHost)(),a=(0,d.useEmit)(),s=n.lifecycleSignal(d.onCleanup),l=(0,d.ref)(),p=(0,d.ref)(),m=`cmdk-listbox`,h=null,g=(0,u.signal)(``),_=(0,u.signal)([]),reparseSlottedItems=()=>{_.value=c.parseSlottedItems([...i.children])};reparseSlottedItems();let v=new MutationObserver(reparseSlottedItems);v.observe(i,{characterData:!0,childList:!0,subtree:!0}),(0,d.onCleanup)(()=>v.disconnect());let y=(0,u.computed)(()=>{let t=e.items.value;return Array.isArray(t)?t.map(c.normalizeItem):_.value}),b=(0,u.computed)(()=>c.filterItems(y.value,g.value,!!e[`no-filter`].value)),x=(0,u.computed)(()=>c.buildRows(b.value)),scrollFocusedIntoView=()=>{h?.querySelector(`[data-focused]`)?.scrollIntoView({block:`nearest`})},S=r.createListControl({getItems:()=>b.value,isItemDisabled:e=>e.disabled,onNavigate:scrollFocusedIntoView,signal:s}),{focusedIndex:C}=S,resetSearch=()=>{g.value=``,S.reset()},{closeWithAnimation:
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/accessibility.css.cjs"),t=require("./core/announcer.cjs");require("./_dev.cjs");const n=require("./core/ore.cjs"),r=require("./core/nav.cjs"),i=require("./core/parse.cjs"),a=require("./icon.cjs"),o=require("./overlay/shared/use-dialog.cjs"),s=require("./overlay/command-palette/command-palette.css.cjs"),c=require("./overlay/command-palette/command-palette-items.cjs"),l=require("./keyboard-key.cjs");let u=require("@vielzeug/ripple"),d=require("@vielzeug/ore"),f=require("@vielzeug/keymap");var p=`ore-command-palette-item`;(0,d.define)(p,{setup(){return d.html``}});var m=`ore-command-palette`;(0,d.define)(m,{props:{"default-open":d.prop.bool(!1),"empty-text":d.prop.string(`No results found.`),items:d.prop.data(),"keep-open-on-select":d.prop.bool(!1),label:d.prop.string(`Command palette`),loading:d.prop.bool(!1),"no-filter":d.prop.bool(!1),open:{default:void 0,parse:i.parseOptionalBool},placeholder:d.prop.string(`Type a command or search…`),shortcut:d.prop.string(`mod+k`)},setup(e){let i=(0,d.getHost)(),a=(0,d.useEmit)(),s=n.lifecycleSignal(d.onCleanup),l=(0,d.ref)(),p=(0,d.ref)(),m=`cmdk-listbox`,h=null,g=(0,u.signal)(``),_=(0,u.signal)([]),reparseSlottedItems=()=>{_.value=c.parseSlottedItems([...i.children])};reparseSlottedItems();let v=new MutationObserver(reparseSlottedItems);v.observe(i,{characterData:!0,childList:!0,subtree:!0}),(0,d.onCleanup)(()=>v.disconnect());let y=(0,u.computed)(()=>{let t=e.items.value;return Array.isArray(t)?t.map(c.normalizeItem):_.value}),b=(0,u.computed)(()=>c.filterItems(y.value,g.value,!!e[`no-filter`].value)),x=(0,u.computed)(()=>c.buildRows(b.value)),scrollFocusedIntoView=()=>{h?.querySelector(`[data-focused]`)?.scrollIntoView({block:`nearest`})},S=r.createListControl({getItems:()=>b.value,isItemDisabled:e=>e.disabled,onNavigate:scrollFocusedIntoView,signal:s}),{focusedIndex:C}=S;(0,u.watch)(()=>b.value[C.value],e=>{a(`active-change`,e?{item:e,label:e.label,value:e.value}:{label:``,value:``})});let w=(0,u.signal)(!1),resetSearch=()=>{g.value=``,S.reset()},{closeWithAnimation:T,handleBackdropClick:E,overlay:D,requestClose:O,mount:k}=o.useDialogControl({defaultOpen:e[`default-open`],dialogRef:l,getPanelEl:()=>l.value?.querySelector(`.panel`),host:i,initialFocus:(0,u.computed)(()=>`.search-input`),isPersistent:()=>!1,onCleanup:d.onCleanup,onEvent:d.onEvent,onNativeClose:e=>{a(`open-change`,{open:!1,reason:e}),resetSearch()},onOpen:e=>{a(`open-change`,{open:!0,reason:e}),S.navigate(`first`)},openProp:e.open,performClose:()=>T(),returnFocus:(0,u.computed)(()=>!0)}),A=(0,f.createKeymap)();A.mount(window),(0,d.onCleanup)(()=>A.dispose());let j=null;(0,u.watch)(e.shortcut,e=>{j?.(),j=null;let t=(e??``).trim();if(t)try{j=A.bind({handler:()=>{D.toggle(`keyboard`,`trigger`)},id:`command-palette-toggle`,shortcut:t})}catch(e){`${t}${e instanceof Error?e.message:String(e)}`}},{immediate:!0}),(0,d.onMounted)(()=>{k(),l.value&&(0,d.onEvent)(l.value,`click`,E)});function selectItem(t){t.disabled||(a(`select`,{item:t,label:t.label,value:t.value}),e[`keep-open-on-select`].value?p.value?.focus():O(`trigger`))}function handleInput(n){let r=n.target.value;g.value=r,S.navigate(`first`),a(`search`,{query:r});let o=b.value.length;t.announce(o===0?e[`empty-text`].value:`${o} result${o===1?``:`s`} found`,{document:i.ownerDocument})}function handleKeydown(e){if(!S.handleKeydown(e)&&e.key===`Enter`){let t=S.getActiveItem()??b.value.find(e=>!e.disabled);t&&(e.preventDefault(),selectItem(t))}}return d.html`
|
|
2
2
|
<dialog ref="${l}" class="dialog" part="dialog" aria-label="${e.label}" aria-modal="true">
|
|
3
3
|
<div class="panel" part="panel">
|
|
4
4
|
<div class="search" part="search">
|
|
@@ -21,6 +21,7 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
|
|
|
21
21
|
@keydown="${handleKeydown}" />
|
|
22
22
|
<span class="search-loader" ?hidden="${()=>!e.loading.value}" aria-hidden="true"></span>
|
|
23
23
|
</div>
|
|
24
|
+
<div class="body">
|
|
24
25
|
<div
|
|
25
26
|
class="listbox"
|
|
26
27
|
part="listbox"
|
|
@@ -61,6 +62,13 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
|
|
|
61
62
|
</div>
|
|
62
63
|
`)}
|
|
63
64
|
</div>
|
|
65
|
+
<div class="preview" part="preview" role="region" aria-label="Preview" ?hidden="${()=>!w.value}">
|
|
66
|
+
<slot
|
|
67
|
+
name="preview"
|
|
68
|
+
@slotchange="${e=>{w.value=e.target.assignedElements().length>0}}"
|
|
69
|
+
></slot>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
64
72
|
<div class="footer" part="footer">
|
|
65
73
|
<span class="footer-hint">
|
|
66
74
|
<ore-keyboard-key>↑</ore-keyboard-key>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-palette.cjs","names":[],"sources":["../src/overlay/command-palette/command-palette.ts"],"sourcesContent":["import { createKeymap } from '@vielzeug/keymap';\nimport { define, getHost, html, onCleanup, onEvent, onMounted, prop, ref, useEmit } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\nimport { warn } from '../../_dev';\n\nimport { announce, createListControl, lifecycleSignal, parseOptionalBool } from '../../core';\nimport { reducedMotionMixin } from '../../styles';\nimport { useDialogControl } from '../shared/use-dialog';\nimport componentStyles from './command-palette.css?inline';\nimport type { CommandPaletteItem, OreCommandPaletteEvents, OreCommandPaletteProps } from './command-palette.types';\nimport { buildRows, filterItems, normalizeItem, parseSlottedItems, splitShortcutKeys } from './command-palette-items';\n\nexport { ICON_TAG } from '../../content/icon/icon';\nexport { KEYBOARD_SHORTCUT_TAG } from '../../content/keyboard-key/keyboard-key';\nexport type { OreCommandPaletteEvents, OreCommandPaletteProps } from './command-palette.types';\n\n/**\n * A pure data node describing one command. Never rendered directly: `ore-command-palette`\n * reads its attributes/text content and renders the visible row itself.\n *\n * @element ore-command-palette-item\n *\n * @attr {string} value - Value emitted by the `select` event and matched against the search query\n * @attr {string} label - Explicit label text; falls back to the element's text content\n * @attr {string} group - Group heading the item is clustered under\n * @attr {string} shortcut - Display-only keyboard hint rendered at the end of the row, one `<kbd>` per `+`-separated key (e.g. `\"⌘+S\"` renders two keycaps; a literal `+` key isn't representable: spell it out, e.g. `\"Ctrl+Plus\"`)\n * @attr {boolean} disabled - Excludes the item from keyboard navigation and selection\n *\n * @slot icon - Optional leading icon content\n *\n * @example\n * ```html\n * <ore-command-palette-item value=\"new-file\" group=\"File\" shortcut=\"⌘+N\">New File</ore-command-palette-item>\n * ```\n */\nexport const COMMAND_PALETTE_ITEM_TAG = 'ore-command-palette-item' as const;\ndefine(COMMAND_PALETTE_ITEM_TAG, {\n setup() {\n return html``;\n },\n});\n\n/**\n * A searchable, keyboard-driven list of commands presented in a centered modal :\n * the \"⌘K\" pattern popularized by editors and productivity apps. Built on the\n * native `<dialog>` element (focus trap, top-layer stacking, `Escape`-to-close)\n * and `@vielzeug/keymap` for the global shortcut that opens it.\n *\n * @element ore-command-palette\n * @element ore-command-palette-item - Slotted command definition (place in default slot)\n *\n * @attr {boolean} open - Controls the open state of the palette\n * @attr {boolean} default-open - Initial uncontrolled open state\n * @attr {string} label - Accessible label for the dialog (screen-reader-only heading)\n * @attr {string} placeholder - Placeholder text for the search input\n * @attr {string} shortcut - Global keyboard shortcut (keymap syntax) that toggles the palette. Default `\"mod+k\"`; set to `\"\"` to disable\n * @attr {boolean} no-filter - Disable built-in client-side filtering (for server-driven search)\n * @attr {boolean} loading - Shows a loading row below the search input\n * @attr {string} empty-text - Message shown when no item matches the query\n * @attr {boolean} keep-open-on-select - Keep the palette open after an item is selected\n *\n * @fires open-change - Fired when the palette state changes. detail: `{ open, reason }`\n * @fires search - Fired on every keystroke in the search input. detail: `{ query }`\n * @fires select - Fired when a command is chosen (click or `Enter`). detail: `{ value, label, item }`\n *\n * @slot - `<ore-command-palette-item>` elements (alternative/supplement to the `items` prop)\n *\n * @cssprop --command-palette-bg - Panel background color\n * @cssprop --command-palette-border-color - Panel border color\n * @cssprop --command-palette-radius - Panel border radius\n * @cssprop --command-palette-shadow - Panel drop shadow\n * @cssprop --command-palette-max-width - Maximum panel width\n * @cssprop --command-palette-backdrop - Backdrop overlay color\n * @cssprop --command-palette-option-hover-bg - Item background on hover\n * @cssprop --command-palette-option-focus-bg - Item background when keyboard-focused\n *\n * @part dialog - Dialog root container\n * @part panel - Panel container\n * @part input - Search input\n * @part listbox - Listbox of matching commands\n *\n * @example\n * ```html\n * <ore-command-palette label=\"Command palette\" placeholder=\"Type a command…\">\n * <ore-command-palette-item value=\"new-file\" group=\"File\" shortcut=\"⌘+N\">New File</ore-command-palette-item>\n * <ore-command-palette-item value=\"open-file\" group=\"File\" shortcut=\"⌘+O\">Open File…</ore-command-palette-item>\n * <ore-command-palette-item value=\"toggle-theme\" group=\"View\">Toggle Theme</ore-command-palette-item>\n * </ore-command-palette>\n * ```\n */\nexport const COMMAND_PALETTE_TAG = 'ore-command-palette' as const;\ndefine<OreCommandPaletteProps>(COMMAND_PALETTE_TAG, {\n props: {\n 'default-open': prop.bool(false),\n 'empty-text': prop.string('No results found.'),\n items: prop.data<OreCommandPaletteProps['items']>(),\n 'keep-open-on-select': prop.bool(false),\n label: prop.string('Command palette'),\n loading: prop.bool(false),\n 'no-filter': prop.bool(false),\n open: { default: undefined as boolean | undefined, parse: parseOptionalBool },\n placeholder: prop.string('Type a command or search…'),\n shortcut: prop.string('mod+k'),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCommandPaletteEvents>();\n const abortSignal = lifecycleSignal(onCleanup);\n\n const dialogRef = ref<HTMLDialogElement>();\n const searchInputRef = ref<HTMLInputElement>();\n const listboxId = 'cmdk-listbox';\n\n let listboxEl: HTMLElement | null = null;\n\n const query = signal('');\n\n // ── Items: slotted <ore-command-palette-item> elements, merged with the `items` prop ──\n // Items are pure data nodes (see `ore-command-palette-item`'s own doc comment): they're\n // never projected through a `<slot>`, just read directly off the host's light DOM. That\n // sidesteps `useSlots()`/`slotchange` entirely: a plain MutationObserver on the host\n // already covers everything `slotchange` would (an item added or removed) *and* the case\n // it can't: an already-assigned item's own text/attributes changing. For items written\n // as static, inline HTML, the browser's parser can insert the last item before appending\n // its text-node child; without watching `characterData`, that would permanently cache an\n // empty label, since nothing else re-triggers once the element itself stops changing.\n const slottedItems = signal<CommandPaletteItem[]>([]);\n\n const reparseSlottedItems = (): void => {\n slottedItems.value = parseSlottedItems([...el.children]);\n };\n\n reparseSlottedItems();\n\n const lightDomObserver = new MutationObserver(reparseSlottedItems);\n\n lightDomObserver.observe(el, { characterData: true, childList: true, subtree: true });\n onCleanup(() => lightDomObserver.disconnect());\n\n const allItems = computed<CommandPaletteItem[]>(() => {\n const explicit = props.items.value;\n\n return Array.isArray(explicit) ? explicit.map(normalizeItem) : slottedItems.value;\n });\n\n const filteredItems = computed(() => filterItems(allItems.value, query.value, Boolean(props['no-filter'].value)));\n const rows = computed(() => buildRows(filteredItems.value));\n\n // ── Keyboard navigation over the filtered list (Up/Down/Home/End) ──\n const scrollFocusedIntoView = (): void => {\n listboxEl?.querySelector<HTMLElement>('[data-focused]')?.scrollIntoView({ block: 'nearest' });\n };\n\n const list = createListControl<CommandPaletteItem>({\n getItems: () => filteredItems.value,\n isItemDisabled: (item) => item.disabled,\n onNavigate: scrollFocusedIntoView,\n signal: abortSignal,\n });\n const { focusedIndex } = list;\n\n // ── Dialog chrome: native <dialog>, focus trap, Escape, backdrop click ──\n const resetSearch = (): void => {\n query.value = '';\n list.reset();\n };\n\n const { closeWithAnimation, handleBackdropClick, overlay, requestClose, mount } = useDialogControl({\n defaultOpen: props['default-open'],\n dialogRef,\n getPanelEl: () => dialogRef.value?.querySelector<HTMLElement>('.panel'),\n host: el,\n initialFocus: computed(() => '.search-input'),\n isPersistent: () => false,\n onCleanup,\n onEvent,\n onNativeClose: (reason) => {\n emit('open-change', { open: false, reason });\n resetSearch();\n },\n onOpen: (reason) => {\n emit('open-change', { open: true, reason });\n list.navigate('first');\n },\n openProp: props.open,\n performClose: () => closeWithAnimation(),\n returnFocus: computed(() => true),\n });\n\n // ── Global keyboard shortcut (opens/closes the palette from anywhere) ──\n const globalKeymap = createKeymap();\n\n globalKeymap.mount(window);\n onCleanup(() => globalKeymap.dispose());\n\n let unbindShortcut: (() => void) | null = null;\n\n watch(\n props.shortcut,\n (shortcutStr) => {\n unbindShortcut?.();\n unbindShortcut = null;\n\n const trimmed = (shortcutStr ?? '').trim();\n\n if (!trimmed) return;\n\n try {\n unbindShortcut = globalKeymap.bind({\n handler: () => {\n overlay.toggle('keyboard', 'trigger');\n },\n id: 'command-palette-toggle',\n shortcut: trimmed,\n });\n } catch (error) {\n warn(`invalid \"shortcut\" value \"${trimmed}\": ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n { immediate: true },\n );\n\n onMounted(() => {\n mount();\n if (dialogRef.value) onEvent(dialogRef.value, 'click', handleBackdropClick);\n });\n\n // ── Selection ────────────────────────────────────────────────────────────\n function selectItem(item: CommandPaletteItem): void {\n if (item.disabled) return;\n\n emit('select', { item, label: item.label, value: item.value });\n\n if (props['keep-open-on-select'].value) {\n searchInputRef.value?.focus();\n } else {\n requestClose('trigger');\n }\n }\n\n function handleInput(e: Event): void {\n const value = (e.target as HTMLInputElement).value;\n\n query.value = value;\n list.navigate('first');\n emit('search', { query: value });\n\n const count = filteredItems.value.length;\n\n announce(count === 0 ? props['empty-text'].value! : `${count} result${count === 1 ? '' : 's'} found`, {\n document: el.ownerDocument,\n });\n }\n\n function handleKeydown(e: KeyboardEvent): void {\n if (list.handleKeydown(e)) return;\n\n if (e.key === 'Enter') {\n // `list.navigate('first')` (called on open and on every keystroke) already keeps\n // the focused row off a disabled item, so this fallback is only ever reached when\n // nothing has been focused yet, but it mirrors `selectItem`'s own disabled guard\n // rather than blindly grabbing index 0, in case that navigate-on-open wiring ever\n // changes.\n const active = list.getActiveItem() ?? filteredItems.value.find((item) => !item.disabled);\n\n if (active) {\n e.preventDefault();\n selectItem(active);\n }\n }\n }\n\n return html`\n <dialog ref=\"${dialogRef}\" class=\"dialog\" part=\"dialog\" aria-label=\"${props.label}\" aria-modal=\"true\">\n <div class=\"panel\" part=\"panel\">\n <div class=\"search\" part=\"search\">\n <span class=\"search-icon\" aria-hidden=\"true\"><ore-icon name=\"search\" size=\"18\"></ore-icon></span>\n <input\n ref=\"${searchInputRef}\"\n class=\"search-input\"\n part=\"input\"\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-expanded=\"true\"\n aria-autocomplete=\"list\"\n aria-controls=\"${listboxId}\"\n aria-activedescendant=\"${() => (focusedIndex.value >= 0 ? `${listboxId}-opt-${focusedIndex.value}` : '')}\"\n placeholder=\"${props.placeholder}\"\n value=\"${query}\"\n @input=\"${handleInput}\"\n @keydown=\"${handleKeydown}\" />\n <span class=\"search-loader\" ?hidden=\"${() => !props.loading.value}\" aria-hidden=\"true\"></span>\n </div>\n <div\n class=\"listbox\"\n part=\"listbox\"\n role=\"listbox\"\n id=\"${listboxId}\"\n aria-label=\"Commands\"\n ref=\"${(listEl: HTMLElement) => {\n listboxEl = listEl;\n }}\">\n <div class=\"empty\" role=\"presentation\" ?hidden=\"${() => props.loading.value || rows.value.length > 0}\">\n ${() => props['empty-text'].value}\n </div>\n ${() =>\n rows.value.map((row) =>\n row.type === 'group'\n ? html`\n <div class=\"group-heading\" role=\"presentation\">${row.group}</div>\n `\n : html`\n <div\n class=\"item\"\n part=\"item\"\n role=\"option\"\n id=\"${`${listboxId}-opt-${row.idx}`}\"\n aria-selected=\"${() => String(focusedIndex.value === row.idx)}\"\n aria-disabled=\"${() => String(row.item.disabled)}\"\n ?data-focused=\"${() => focusedIndex.value === row.idx}\"\n ?data-disabled=\"${() => row.item.disabled}\"\n @click=\"${(e: MouseEvent) => {\n e.stopPropagation();\n selectItem(row.item);\n }}\"\n @pointerenter=\"${() => {\n list.set(row.idx);\n }}\">\n ${\n row.item.icon\n ? html`\n <span class=\"item-icon\" aria-hidden=\"true\">\n <ore-icon name=\"${row.item.icon}\" size=\"16\"></ore-icon>\n </span>\n `\n : ''\n }\n <span class=\"item-label\">${row.item.label}</span>\n ${\n row.item.shortcut\n ? html`\n <span class=\"item-shortcut\">\n ${splitShortcutKeys(row.item.shortcut).map(\n (key) => html`\n <ore-keyboard-key>${key}</ore-keyboard-key>\n `,\n )}\n </span>\n `\n : ''\n }\n </div>\n `,\n )}\n </div>\n <div class=\"footer\" part=\"footer\">\n <span class=\"footer-hint\">\n <ore-keyboard-key>↑</ore-keyboard-key>\n <ore-keyboard-key>↓</ore-keyboard-key>\n Navigate\n </span>\n <span class=\"footer-hint\">\n <ore-keyboard-key>Enter</ore-keyboard-key>\n Select\n </span>\n <span class=\"footer-hint\">\n <ore-keyboard-key>Esc</ore-keyboard-key>\n Close\n </span>\n </div>\n </div>\n </dialog>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"command-palette.cjs","names":[],"sources":["../src/overlay/command-palette/command-palette.ts"],"sourcesContent":["import { createKeymap } from '@vielzeug/keymap';\nimport { define, getHost, html, onCleanup, onEvent, onMounted, prop, ref, useEmit } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\nimport { warn } from '../../_dev';\n\nimport { announce, createListControl, lifecycleSignal, parseOptionalBool } from '../../core';\nimport { reducedMotionMixin } from '../../styles';\nimport { useDialogControl } from '../shared/use-dialog';\nimport componentStyles from './command-palette.css?inline';\nimport type { CommandPaletteItem, OreCommandPaletteEvents, OreCommandPaletteProps } from './command-palette.types';\nimport { buildRows, filterItems, normalizeItem, parseSlottedItems, splitShortcutKeys } from './command-palette-items';\n\nexport { ICON_TAG } from '../../content/icon/icon';\nexport { KEYBOARD_SHORTCUT_TAG } from '../../content/keyboard-key/keyboard-key';\nexport type { OreCommandPaletteEvents, OreCommandPaletteProps } from './command-palette.types';\n\n/**\n * A pure data node describing one command. Never rendered directly: `ore-command-palette`\n * reads its attributes/text content and renders the visible row itself.\n *\n * @element ore-command-palette-item\n *\n * @attr {string} value - Value emitted by the `select` event and matched against the search query\n * @attr {string} label - Explicit label text; falls back to the element's text content\n * @attr {string} group - Group heading the item is clustered under\n * @attr {string} shortcut - Display-only keyboard hint rendered at the end of the row, one `<kbd>` per `+`-separated key (e.g. `\"⌘+S\"` renders two keycaps; a literal `+` key isn't representable: spell it out, e.g. `\"Ctrl+Plus\"`)\n * @attr {boolean} disabled - Excludes the item from keyboard navigation and selection\n *\n * @slot icon - Optional leading icon content\n *\n * @example\n * ```html\n * <ore-command-palette-item value=\"new-file\" group=\"File\" shortcut=\"⌘+N\">New File</ore-command-palette-item>\n * ```\n */\nexport const COMMAND_PALETTE_ITEM_TAG = 'ore-command-palette-item' as const;\ndefine(COMMAND_PALETTE_ITEM_TAG, {\n setup() {\n return html``;\n },\n});\n\n/**\n * A searchable, keyboard-driven list of commands presented in a centered modal :\n * the \"⌘K\" pattern popularized by editors and productivity apps. Built on the\n * native `<dialog>` element (focus trap, top-layer stacking, `Escape`-to-close)\n * and `@vielzeug/keymap` for the global shortcut that opens it.\n *\n * @element ore-command-palette\n * @element ore-command-palette-item - Slotted command definition (place in default slot)\n *\n * @attr {boolean} open - Controls the open state of the palette\n * @attr {boolean} default-open - Initial uncontrolled open state\n * @attr {string} label - Accessible label for the dialog (screen-reader-only heading)\n * @attr {string} placeholder - Placeholder text for the search input\n * @attr {string} shortcut - Global keyboard shortcut (keymap syntax) that toggles the palette. Default `\"mod+k\"`; set to `\"\"` to disable\n * @attr {boolean} no-filter - Disable built-in client-side filtering (for server-driven search)\n * @attr {boolean} loading - Shows a loading row below the search input\n * @attr {string} empty-text - Message shown when no item matches the query\n * @attr {boolean} keep-open-on-select - Keep the palette open after an item is selected\n *\n * @fires active-change - Fired when the focused row changes (keyboard, hover, typing, open, close). detail: `{ value, label, item }`; `item` is `undefined` and `value` empty when no row is active\n * @fires open-change - Fired when the palette state changes. detail: `{ open, reason }`\n * @fires search - Fired on every keystroke in the search input. detail: `{ query }`\n * @fires select - Fired when a command is chosen (click or `Enter`). detail: `{ value, label, item }`\n *\n * @slot - `<ore-command-palette-item>` elements (alternative/supplement to the `items` prop)\n * @slot preview - Optional detail panel rendered beside the list, shown while it has content. Pair it with `active-change` to preview the focused row\n *\n * @cssprop --command-palette-bg - Panel background color\n * @cssprop --command-palette-border-color - Panel border color\n * @cssprop --command-palette-radius - Panel border radius\n * @cssprop --command-palette-shadow - Panel drop shadow\n * @cssprop --command-palette-max-width - Maximum panel width\n * @cssprop --command-palette-backdrop - Backdrop overlay color\n * @cssprop --command-palette-option-hover-bg - Item background on hover\n * @cssprop --command-palette-option-focus-bg - Item background when keyboard-focused\n * @cssprop --command-palette-preview-width - Preview panel width when the `preview` slot has content\n *\n * @part dialog - Dialog root container\n * @part panel - Panel container\n * @part input - Search input\n * @part listbox - Listbox of matching commands\n * @part preview - Preview panel shown beside the list\n *\n * @example\n * ```html\n * <ore-command-palette label=\"Command palette\" placeholder=\"Type a command…\">\n * <ore-command-palette-item value=\"new-file\" group=\"File\" shortcut=\"⌘+N\">New File</ore-command-palette-item>\n * <ore-command-palette-item value=\"open-file\" group=\"File\" shortcut=\"⌘+O\">Open File…</ore-command-palette-item>\n * <ore-command-palette-item value=\"toggle-theme\" group=\"View\">Toggle Theme</ore-command-palette-item>\n * </ore-command-palette>\n * ```\n */\nexport const COMMAND_PALETTE_TAG = 'ore-command-palette' as const;\ndefine<OreCommandPaletteProps>(COMMAND_PALETTE_TAG, {\n props: {\n 'default-open': prop.bool(false),\n 'empty-text': prop.string('No results found.'),\n items: prop.data<OreCommandPaletteProps['items']>(),\n 'keep-open-on-select': prop.bool(false),\n label: prop.string('Command palette'),\n loading: prop.bool(false),\n 'no-filter': prop.bool(false),\n open: { default: undefined as boolean | undefined, parse: parseOptionalBool },\n placeholder: prop.string('Type a command or search…'),\n shortcut: prop.string('mod+k'),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCommandPaletteEvents>();\n const abortSignal = lifecycleSignal(onCleanup);\n\n const dialogRef = ref<HTMLDialogElement>();\n const searchInputRef = ref<HTMLInputElement>();\n const listboxId = 'cmdk-listbox';\n\n let listboxEl: HTMLElement | null = null;\n\n const query = signal('');\n\n // ── Items: slotted <ore-command-palette-item> elements, merged with the `items` prop ──\n // Items are pure data nodes (see `ore-command-palette-item`'s own doc comment): they're\n // never projected through a `<slot>`, just read directly off the host's light DOM. That\n // sidesteps `useSlots()`/`slotchange` entirely: a plain MutationObserver on the host\n // already covers everything `slotchange` would (an item added or removed) *and* the case\n // it can't: an already-assigned item's own text/attributes changing. For items written\n // as static, inline HTML, the browser's parser can insert the last item before appending\n // its text-node child; without watching `characterData`, that would permanently cache an\n // empty label, since nothing else re-triggers once the element itself stops changing.\n const slottedItems = signal<CommandPaletteItem[]>([]);\n\n const reparseSlottedItems = (): void => {\n slottedItems.value = parseSlottedItems([...el.children]);\n };\n\n reparseSlottedItems();\n\n const lightDomObserver = new MutationObserver(reparseSlottedItems);\n\n lightDomObserver.observe(el, { characterData: true, childList: true, subtree: true });\n onCleanup(() => lightDomObserver.disconnect());\n\n const allItems = computed<CommandPaletteItem[]>(() => {\n const explicit = props.items.value;\n\n return Array.isArray(explicit) ? explicit.map(normalizeItem) : slottedItems.value;\n });\n\n const filteredItems = computed(() => filterItems(allItems.value, query.value, Boolean(props['no-filter'].value)));\n const rows = computed(() => buildRows(filteredItems.value));\n\n // ── Keyboard navigation over the filtered list (Up/Down/Home/End) ──\n const scrollFocusedIntoView = (): void => {\n listboxEl?.querySelector<HTMLElement>('[data-focused]')?.scrollIntoView({ block: 'nearest' });\n };\n\n const list = createListControl<CommandPaletteItem>({\n getItems: () => filteredItems.value,\n isItemDisabled: (item) => item.disabled,\n onNavigate: scrollFocusedIntoView,\n signal: abortSignal,\n });\n const { focusedIndex } = list;\n\n // ── Active row: mirrors the focused row to the host so a `preview` slot can ──\n // follow keyboard, hover and typing without the host reaching into the listbox.\n // Watching the derived item (not just the index) also catches the row under a\n // stable index changing because the filtered list itself changed.\n watch(\n () => filteredItems.value[focusedIndex.value],\n (item) => {\n emit('active-change', item ? { item, label: item.label, value: item.value } : { label: '', value: '' });\n },\n );\n\n // The preview pane folds away while its slot is empty, so a palette that never\n // uses it keeps the plain single-column layout.\n const hasPreview = signal(false);\n\n // ── Dialog chrome: native <dialog>, focus trap, Escape, backdrop click ──\n const resetSearch = (): void => {\n query.value = '';\n list.reset();\n };\n\n const { closeWithAnimation, handleBackdropClick, overlay, requestClose, mount } = useDialogControl({\n defaultOpen: props['default-open'],\n dialogRef,\n getPanelEl: () => dialogRef.value?.querySelector<HTMLElement>('.panel'),\n host: el,\n initialFocus: computed(() => '.search-input'),\n isPersistent: () => false,\n onCleanup,\n onEvent,\n onNativeClose: (reason) => {\n emit('open-change', { open: false, reason });\n resetSearch();\n },\n onOpen: (reason) => {\n emit('open-change', { open: true, reason });\n list.navigate('first');\n },\n openProp: props.open,\n performClose: () => closeWithAnimation(),\n returnFocus: computed(() => true),\n });\n\n // ── Global keyboard shortcut (opens/closes the palette from anywhere) ──\n const globalKeymap = createKeymap();\n\n globalKeymap.mount(window);\n onCleanup(() => globalKeymap.dispose());\n\n let unbindShortcut: (() => void) | null = null;\n\n watch(\n props.shortcut,\n (shortcutStr) => {\n unbindShortcut?.();\n unbindShortcut = null;\n\n const trimmed = (shortcutStr ?? '').trim();\n\n if (!trimmed) return;\n\n try {\n unbindShortcut = globalKeymap.bind({\n handler: () => {\n overlay.toggle('keyboard', 'trigger');\n },\n id: 'command-palette-toggle',\n shortcut: trimmed,\n });\n } catch (error) {\n warn(`invalid \"shortcut\" value \"${trimmed}\": ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n { immediate: true },\n );\n\n onMounted(() => {\n mount();\n if (dialogRef.value) onEvent(dialogRef.value, 'click', handleBackdropClick);\n });\n\n // ── Selection ────────────────────────────────────────────────────────────\n function selectItem(item: CommandPaletteItem): void {\n if (item.disabled) return;\n\n emit('select', { item, label: item.label, value: item.value });\n\n if (props['keep-open-on-select'].value) {\n searchInputRef.value?.focus();\n } else {\n requestClose('trigger');\n }\n }\n\n function handleInput(e: Event): void {\n const value = (e.target as HTMLInputElement).value;\n\n query.value = value;\n list.navigate('first');\n emit('search', { query: value });\n\n const count = filteredItems.value.length;\n\n announce(count === 0 ? props['empty-text'].value! : `${count} result${count === 1 ? '' : 's'} found`, {\n document: el.ownerDocument,\n });\n }\n\n function handleKeydown(e: KeyboardEvent): void {\n if (list.handleKeydown(e)) return;\n\n if (e.key === 'Enter') {\n // `list.navigate('first')` (called on open and on every keystroke) already keeps\n // the focused row off a disabled item, so this fallback is only ever reached when\n // nothing has been focused yet, but it mirrors `selectItem`'s own disabled guard\n // rather than blindly grabbing index 0, in case that navigate-on-open wiring ever\n // changes.\n const active = list.getActiveItem() ?? filteredItems.value.find((item) => !item.disabled);\n\n if (active) {\n e.preventDefault();\n selectItem(active);\n }\n }\n }\n\n return html`\n <dialog ref=\"${dialogRef}\" class=\"dialog\" part=\"dialog\" aria-label=\"${props.label}\" aria-modal=\"true\">\n <div class=\"panel\" part=\"panel\">\n <div class=\"search\" part=\"search\">\n <span class=\"search-icon\" aria-hidden=\"true\"><ore-icon name=\"search\" size=\"18\"></ore-icon></span>\n <input\n ref=\"${searchInputRef}\"\n class=\"search-input\"\n part=\"input\"\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-expanded=\"true\"\n aria-autocomplete=\"list\"\n aria-controls=\"${listboxId}\"\n aria-activedescendant=\"${() => (focusedIndex.value >= 0 ? `${listboxId}-opt-${focusedIndex.value}` : '')}\"\n placeholder=\"${props.placeholder}\"\n value=\"${query}\"\n @input=\"${handleInput}\"\n @keydown=\"${handleKeydown}\" />\n <span class=\"search-loader\" ?hidden=\"${() => !props.loading.value}\" aria-hidden=\"true\"></span>\n </div>\n <div class=\"body\">\n <div\n class=\"listbox\"\n part=\"listbox\"\n role=\"listbox\"\n id=\"${listboxId}\"\n aria-label=\"Commands\"\n ref=\"${(listEl: HTMLElement) => {\n listboxEl = listEl;\n }}\">\n <div class=\"empty\" role=\"presentation\" ?hidden=\"${() => props.loading.value || rows.value.length > 0}\">\n ${() => props['empty-text'].value}\n </div>\n ${() =>\n rows.value.map((row) =>\n row.type === 'group'\n ? html`\n <div class=\"group-heading\" role=\"presentation\">${row.group}</div>\n `\n : html`\n <div\n class=\"item\"\n part=\"item\"\n role=\"option\"\n id=\"${`${listboxId}-opt-${row.idx}`}\"\n aria-selected=\"${() => String(focusedIndex.value === row.idx)}\"\n aria-disabled=\"${() => String(row.item.disabled)}\"\n ?data-focused=\"${() => focusedIndex.value === row.idx}\"\n ?data-disabled=\"${() => row.item.disabled}\"\n @click=\"${(e: MouseEvent) => {\n e.stopPropagation();\n selectItem(row.item);\n }}\"\n @pointerenter=\"${() => {\n list.set(row.idx);\n }}\">\n ${\n row.item.icon\n ? html`\n <span class=\"item-icon\" aria-hidden=\"true\">\n <ore-icon name=\"${row.item.icon}\" size=\"16\"></ore-icon>\n </span>\n `\n : ''\n }\n <span class=\"item-label\">${row.item.label}</span>\n ${\n row.item.shortcut\n ? html`\n <span class=\"item-shortcut\">\n ${splitShortcutKeys(row.item.shortcut).map(\n (key) => html`\n <ore-keyboard-key>${key}</ore-keyboard-key>\n `,\n )}\n </span>\n `\n : ''\n }\n </div>\n `,\n )}\n </div>\n <div class=\"preview\" part=\"preview\" role=\"region\" aria-label=\"Preview\" ?hidden=\"${() => !hasPreview.value}\">\n <slot\n name=\"preview\"\n @slotchange=\"${(e: Event) => {\n hasPreview.value = (e.target as HTMLSlotElement).assignedElements().length > 0;\n }}\"\n ></slot>\n </div>\n </div>\n <div class=\"footer\" part=\"footer\">\n <span class=\"footer-hint\">\n <ore-keyboard-key>↑</ore-keyboard-key>\n <ore-keyboard-key>↓</ore-keyboard-key>\n Navigate\n </span>\n <span class=\"footer-hint\">\n <ore-keyboard-key>Enter</ore-keyboard-key>\n Select\n </span>\n <span class=\"footer-hint\">\n <ore-keyboard-key>Esc</ore-keyboard-key>\n Close\n </span>\n </div>\n </div>\n </dialog>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
|
package/dist/command-palette.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{reducedMotionMixin as e}from"./styles/mixins/accessibility.css.js";import{announce as t}from"./core/announcer.js";import"./_dev.js";import{lifecycleSignal as n}from"./core/ore.js";import{createListControl as r}from"./core/nav.js";import{parseOptionalBool as i}from"./core/parse.js";import{ICON_TAG as a}from"./icon.js";import{useDialogControl as o}from"./overlay/shared/use-dialog.js";import s from"./overlay/command-palette/command-palette.css.js";import{buildRows as c,filterItems as l,normalizeItem as u,parseSlottedItems as d,splitShortcutKeys as f}from"./overlay/command-palette/command-palette-items.js";import{KEYBOARD_SHORTCUT_TAG as p}from"./keyboard-key.js";import{computed as m,signal as h,watch as g}from"@vielzeug/ripple";import{define as _,getHost as v,html as y,onCleanup as b,onEvent as x,onMounted as S,prop as C,ref as w,useEmit as T}from"@vielzeug/ore";import{createKeymap as E}from"@vielzeug/keymap";var D=`ore-command-palette-item`;_(D,{setup(){return y``}});var O=`ore-command-palette`;_(O,{props:{"default-open":C.bool(!1),"empty-text":C.string(`No results found.`),items:C.data(),"keep-open-on-select":C.bool(!1),label:C.string(`Command palette`),loading:C.bool(!1),"no-filter":C.bool(!1),open:{default:void 0,parse:i},placeholder:C.string(`Type a command or search…`),shortcut:C.string(`mod+k`)},setup(e){let i=v(),a=T(),s=n(b),p=w(),_=w(),C=`cmdk-listbox`,D=null,O=h(``),k=h([]),reparseSlottedItems=()=>{k.value=d([...i.children])};reparseSlottedItems();let A=new MutationObserver(reparseSlottedItems);A.observe(i,{characterData:!0,childList:!0,subtree:!0}),b(()=>A.disconnect());let j=m(()=>{let t=e.items.value;return Array.isArray(t)?t.map(u):k.value}),M=m(()=>l(j.value,O.value,!!e[`no-filter`].value)),N=m(()=>c(M.value)),scrollFocusedIntoView=()=>{D?.querySelector(`[data-focused]`)?.scrollIntoView({block:`nearest`})},P=r({getItems:()=>M.value,isItemDisabled:e=>e.disabled,onNavigate:scrollFocusedIntoView,signal:s}),{focusedIndex:F}=P,resetSearch=()=>{O.value=``,P.reset()},{closeWithAnimation:
|
|
1
|
+
import{reducedMotionMixin as e}from"./styles/mixins/accessibility.css.js";import{announce as t}from"./core/announcer.js";import"./_dev.js";import{lifecycleSignal as n}from"./core/ore.js";import{createListControl as r}from"./core/nav.js";import{parseOptionalBool as i}from"./core/parse.js";import{ICON_TAG as a}from"./icon.js";import{useDialogControl as o}from"./overlay/shared/use-dialog.js";import s from"./overlay/command-palette/command-palette.css.js";import{buildRows as c,filterItems as l,normalizeItem as u,parseSlottedItems as d,splitShortcutKeys as f}from"./overlay/command-palette/command-palette-items.js";import{KEYBOARD_SHORTCUT_TAG as p}from"./keyboard-key.js";import{computed as m,signal as h,watch as g}from"@vielzeug/ripple";import{define as _,getHost as v,html as y,onCleanup as b,onEvent as x,onMounted as S,prop as C,ref as w,useEmit as T}from"@vielzeug/ore";import{createKeymap as E}from"@vielzeug/keymap";var D=`ore-command-palette-item`;_(D,{setup(){return y``}});var O=`ore-command-palette`;_(O,{props:{"default-open":C.bool(!1),"empty-text":C.string(`No results found.`),items:C.data(),"keep-open-on-select":C.bool(!1),label:C.string(`Command palette`),loading:C.bool(!1),"no-filter":C.bool(!1),open:{default:void 0,parse:i},placeholder:C.string(`Type a command or search…`),shortcut:C.string(`mod+k`)},setup(e){let i=v(),a=T(),s=n(b),p=w(),_=w(),C=`cmdk-listbox`,D=null,O=h(``),k=h([]),reparseSlottedItems=()=>{k.value=d([...i.children])};reparseSlottedItems();let A=new MutationObserver(reparseSlottedItems);A.observe(i,{characterData:!0,childList:!0,subtree:!0}),b(()=>A.disconnect());let j=m(()=>{let t=e.items.value;return Array.isArray(t)?t.map(u):k.value}),M=m(()=>l(j.value,O.value,!!e[`no-filter`].value)),N=m(()=>c(M.value)),scrollFocusedIntoView=()=>{D?.querySelector(`[data-focused]`)?.scrollIntoView({block:`nearest`})},P=r({getItems:()=>M.value,isItemDisabled:e=>e.disabled,onNavigate:scrollFocusedIntoView,signal:s}),{focusedIndex:F}=P;g(()=>M.value[F.value],e=>{a(`active-change`,e?{item:e,label:e.label,value:e.value}:{label:``,value:``})});let I=h(!1),resetSearch=()=>{O.value=``,P.reset()},{closeWithAnimation:L,handleBackdropClick:R,overlay:z,requestClose:B,mount:V}=o({defaultOpen:e[`default-open`],dialogRef:p,getPanelEl:()=>p.value?.querySelector(`.panel`),host:i,initialFocus:m(()=>`.search-input`),isPersistent:()=>!1,onCleanup:b,onEvent:x,onNativeClose:e=>{a(`open-change`,{open:!1,reason:e}),resetSearch()},onOpen:e=>{a(`open-change`,{open:!0,reason:e}),P.navigate(`first`)},openProp:e.open,performClose:()=>L(),returnFocus:m(()=>!0)}),H=E();H.mount(window),b(()=>H.dispose());let U=null;g(e.shortcut,e=>{U?.(),U=null;let t=(e??``).trim();if(t)try{U=H.bind({handler:()=>{z.toggle(`keyboard`,`trigger`)},id:`command-palette-toggle`,shortcut:t})}catch(e){`${t}${e instanceof Error?e.message:String(e)}`}},{immediate:!0}),S(()=>{V(),p.value&&x(p.value,`click`,R)});function selectItem(t){t.disabled||(a(`select`,{item:t,label:t.label,value:t.value}),e[`keep-open-on-select`].value?_.value?.focus():B(`trigger`))}function handleInput(n){let r=n.target.value;O.value=r,P.navigate(`first`),a(`search`,{query:r});let o=M.value.length;t(o===0?e[`empty-text`].value:`${o} result${o===1?``:`s`} found`,{document:i.ownerDocument})}function handleKeydown(e){if(!P.handleKeydown(e)&&e.key===`Enter`){let t=P.getActiveItem()??M.value.find(e=>!e.disabled);t&&(e.preventDefault(),selectItem(t))}}return y`
|
|
2
2
|
<dialog ref="${p}" class="dialog" part="dialog" aria-label="${e.label}" aria-modal="true">
|
|
3
3
|
<div class="panel" part="panel">
|
|
4
4
|
<div class="search" part="search">
|
|
@@ -21,6 +21,7 @@ import{reducedMotionMixin as e}from"./styles/mixins/accessibility.css.js";import
|
|
|
21
21
|
@keydown="${handleKeydown}" />
|
|
22
22
|
<span class="search-loader" ?hidden="${()=>!e.loading.value}" aria-hidden="true"></span>
|
|
23
23
|
</div>
|
|
24
|
+
<div class="body">
|
|
24
25
|
<div
|
|
25
26
|
class="listbox"
|
|
26
27
|
part="listbox"
|
|
@@ -61,6 +62,13 @@ import{reducedMotionMixin as e}from"./styles/mixins/accessibility.css.js";import
|
|
|
61
62
|
</div>
|
|
62
63
|
`)}
|
|
63
64
|
</div>
|
|
65
|
+
<div class="preview" part="preview" role="region" aria-label="Preview" ?hidden="${()=>!I.value}">
|
|
66
|
+
<slot
|
|
67
|
+
name="preview"
|
|
68
|
+
@slotchange="${e=>{I.value=e.target.assignedElements().length>0}}"
|
|
69
|
+
></slot>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
64
72
|
<div class="footer" part="footer">
|
|
65
73
|
<span class="footer-hint">
|
|
66
74
|
<ore-keyboard-key>↑</ore-keyboard-key>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-palette.js","names":[],"sources":["../src/overlay/command-palette/command-palette.ts"],"sourcesContent":["import { createKeymap } from '@vielzeug/keymap';\nimport { define, getHost, html, onCleanup, onEvent, onMounted, prop, ref, useEmit } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\nimport { warn } from '../../_dev';\n\nimport { announce, createListControl, lifecycleSignal, parseOptionalBool } from '../../core';\nimport { reducedMotionMixin } from '../../styles';\nimport { useDialogControl } from '../shared/use-dialog';\nimport componentStyles from './command-palette.css?inline';\nimport type { CommandPaletteItem, OreCommandPaletteEvents, OreCommandPaletteProps } from './command-palette.types';\nimport { buildRows, filterItems, normalizeItem, parseSlottedItems, splitShortcutKeys } from './command-palette-items';\n\nexport { ICON_TAG } from '../../content/icon/icon';\nexport { KEYBOARD_SHORTCUT_TAG } from '../../content/keyboard-key/keyboard-key';\nexport type { OreCommandPaletteEvents, OreCommandPaletteProps } from './command-palette.types';\n\n/**\n * A pure data node describing one command. Never rendered directly: `ore-command-palette`\n * reads its attributes/text content and renders the visible row itself.\n *\n * @element ore-command-palette-item\n *\n * @attr {string} value - Value emitted by the `select` event and matched against the search query\n * @attr {string} label - Explicit label text; falls back to the element's text content\n * @attr {string} group - Group heading the item is clustered under\n * @attr {string} shortcut - Display-only keyboard hint rendered at the end of the row, one `<kbd>` per `+`-separated key (e.g. `\"⌘+S\"` renders two keycaps; a literal `+` key isn't representable: spell it out, e.g. `\"Ctrl+Plus\"`)\n * @attr {boolean} disabled - Excludes the item from keyboard navigation and selection\n *\n * @slot icon - Optional leading icon content\n *\n * @example\n * ```html\n * <ore-command-palette-item value=\"new-file\" group=\"File\" shortcut=\"⌘+N\">New File</ore-command-palette-item>\n * ```\n */\nexport const COMMAND_PALETTE_ITEM_TAG = 'ore-command-palette-item' as const;\ndefine(COMMAND_PALETTE_ITEM_TAG, {\n setup() {\n return html``;\n },\n});\n\n/**\n * A searchable, keyboard-driven list of commands presented in a centered modal :\n * the \"⌘K\" pattern popularized by editors and productivity apps. Built on the\n * native `<dialog>` element (focus trap, top-layer stacking, `Escape`-to-close)\n * and `@vielzeug/keymap` for the global shortcut that opens it.\n *\n * @element ore-command-palette\n * @element ore-command-palette-item - Slotted command definition (place in default slot)\n *\n * @attr {boolean} open - Controls the open state of the palette\n * @attr {boolean} default-open - Initial uncontrolled open state\n * @attr {string} label - Accessible label for the dialog (screen-reader-only heading)\n * @attr {string} placeholder - Placeholder text for the search input\n * @attr {string} shortcut - Global keyboard shortcut (keymap syntax) that toggles the palette. Default `\"mod+k\"`; set to `\"\"` to disable\n * @attr {boolean} no-filter - Disable built-in client-side filtering (for server-driven search)\n * @attr {boolean} loading - Shows a loading row below the search input\n * @attr {string} empty-text - Message shown when no item matches the query\n * @attr {boolean} keep-open-on-select - Keep the palette open after an item is selected\n *\n * @fires open-change - Fired when the palette state changes. detail: `{ open, reason }`\n * @fires search - Fired on every keystroke in the search input. detail: `{ query }`\n * @fires select - Fired when a command is chosen (click or `Enter`). detail: `{ value, label, item }`\n *\n * @slot - `<ore-command-palette-item>` elements (alternative/supplement to the `items` prop)\n *\n * @cssprop --command-palette-bg - Panel background color\n * @cssprop --command-palette-border-color - Panel border color\n * @cssprop --command-palette-radius - Panel border radius\n * @cssprop --command-palette-shadow - Panel drop shadow\n * @cssprop --command-palette-max-width - Maximum panel width\n * @cssprop --command-palette-backdrop - Backdrop overlay color\n * @cssprop --command-palette-option-hover-bg - Item background on hover\n * @cssprop --command-palette-option-focus-bg - Item background when keyboard-focused\n *\n * @part dialog - Dialog root container\n * @part panel - Panel container\n * @part input - Search input\n * @part listbox - Listbox of matching commands\n *\n * @example\n * ```html\n * <ore-command-palette label=\"Command palette\" placeholder=\"Type a command…\">\n * <ore-command-palette-item value=\"new-file\" group=\"File\" shortcut=\"⌘+N\">New File</ore-command-palette-item>\n * <ore-command-palette-item value=\"open-file\" group=\"File\" shortcut=\"⌘+O\">Open File…</ore-command-palette-item>\n * <ore-command-palette-item value=\"toggle-theme\" group=\"View\">Toggle Theme</ore-command-palette-item>\n * </ore-command-palette>\n * ```\n */\nexport const COMMAND_PALETTE_TAG = 'ore-command-palette' as const;\ndefine<OreCommandPaletteProps>(COMMAND_PALETTE_TAG, {\n props: {\n 'default-open': prop.bool(false),\n 'empty-text': prop.string('No results found.'),\n items: prop.data<OreCommandPaletteProps['items']>(),\n 'keep-open-on-select': prop.bool(false),\n label: prop.string('Command palette'),\n loading: prop.bool(false),\n 'no-filter': prop.bool(false),\n open: { default: undefined as boolean | undefined, parse: parseOptionalBool },\n placeholder: prop.string('Type a command or search…'),\n shortcut: prop.string('mod+k'),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCommandPaletteEvents>();\n const abortSignal = lifecycleSignal(onCleanup);\n\n const dialogRef = ref<HTMLDialogElement>();\n const searchInputRef = ref<HTMLInputElement>();\n const listboxId = 'cmdk-listbox';\n\n let listboxEl: HTMLElement | null = null;\n\n const query = signal('');\n\n // ── Items: slotted <ore-command-palette-item> elements, merged with the `items` prop ──\n // Items are pure data nodes (see `ore-command-palette-item`'s own doc comment): they're\n // never projected through a `<slot>`, just read directly off the host's light DOM. That\n // sidesteps `useSlots()`/`slotchange` entirely: a plain MutationObserver on the host\n // already covers everything `slotchange` would (an item added or removed) *and* the case\n // it can't: an already-assigned item's own text/attributes changing. For items written\n // as static, inline HTML, the browser's parser can insert the last item before appending\n // its text-node child; without watching `characterData`, that would permanently cache an\n // empty label, since nothing else re-triggers once the element itself stops changing.\n const slottedItems = signal<CommandPaletteItem[]>([]);\n\n const reparseSlottedItems = (): void => {\n slottedItems.value = parseSlottedItems([...el.children]);\n };\n\n reparseSlottedItems();\n\n const lightDomObserver = new MutationObserver(reparseSlottedItems);\n\n lightDomObserver.observe(el, { characterData: true, childList: true, subtree: true });\n onCleanup(() => lightDomObserver.disconnect());\n\n const allItems = computed<CommandPaletteItem[]>(() => {\n const explicit = props.items.value;\n\n return Array.isArray(explicit) ? explicit.map(normalizeItem) : slottedItems.value;\n });\n\n const filteredItems = computed(() => filterItems(allItems.value, query.value, Boolean(props['no-filter'].value)));\n const rows = computed(() => buildRows(filteredItems.value));\n\n // ── Keyboard navigation over the filtered list (Up/Down/Home/End) ──\n const scrollFocusedIntoView = (): void => {\n listboxEl?.querySelector<HTMLElement>('[data-focused]')?.scrollIntoView({ block: 'nearest' });\n };\n\n const list = createListControl<CommandPaletteItem>({\n getItems: () => filteredItems.value,\n isItemDisabled: (item) => item.disabled,\n onNavigate: scrollFocusedIntoView,\n signal: abortSignal,\n });\n const { focusedIndex } = list;\n\n // ── Dialog chrome: native <dialog>, focus trap, Escape, backdrop click ──\n const resetSearch = (): void => {\n query.value = '';\n list.reset();\n };\n\n const { closeWithAnimation, handleBackdropClick, overlay, requestClose, mount } = useDialogControl({\n defaultOpen: props['default-open'],\n dialogRef,\n getPanelEl: () => dialogRef.value?.querySelector<HTMLElement>('.panel'),\n host: el,\n initialFocus: computed(() => '.search-input'),\n isPersistent: () => false,\n onCleanup,\n onEvent,\n onNativeClose: (reason) => {\n emit('open-change', { open: false, reason });\n resetSearch();\n },\n onOpen: (reason) => {\n emit('open-change', { open: true, reason });\n list.navigate('first');\n },\n openProp: props.open,\n performClose: () => closeWithAnimation(),\n returnFocus: computed(() => true),\n });\n\n // ── Global keyboard shortcut (opens/closes the palette from anywhere) ──\n const globalKeymap = createKeymap();\n\n globalKeymap.mount(window);\n onCleanup(() => globalKeymap.dispose());\n\n let unbindShortcut: (() => void) | null = null;\n\n watch(\n props.shortcut,\n (shortcutStr) => {\n unbindShortcut?.();\n unbindShortcut = null;\n\n const trimmed = (shortcutStr ?? '').trim();\n\n if (!trimmed) return;\n\n try {\n unbindShortcut = globalKeymap.bind({\n handler: () => {\n overlay.toggle('keyboard', 'trigger');\n },\n id: 'command-palette-toggle',\n shortcut: trimmed,\n });\n } catch (error) {\n warn(`invalid \"shortcut\" value \"${trimmed}\": ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n { immediate: true },\n );\n\n onMounted(() => {\n mount();\n if (dialogRef.value) onEvent(dialogRef.value, 'click', handleBackdropClick);\n });\n\n // ── Selection ────────────────────────────────────────────────────────────\n function selectItem(item: CommandPaletteItem): void {\n if (item.disabled) return;\n\n emit('select', { item, label: item.label, value: item.value });\n\n if (props['keep-open-on-select'].value) {\n searchInputRef.value?.focus();\n } else {\n requestClose('trigger');\n }\n }\n\n function handleInput(e: Event): void {\n const value = (e.target as HTMLInputElement).value;\n\n query.value = value;\n list.navigate('first');\n emit('search', { query: value });\n\n const count = filteredItems.value.length;\n\n announce(count === 0 ? props['empty-text'].value! : `${count} result${count === 1 ? '' : 's'} found`, {\n document: el.ownerDocument,\n });\n }\n\n function handleKeydown(e: KeyboardEvent): void {\n if (list.handleKeydown(e)) return;\n\n if (e.key === 'Enter') {\n // `list.navigate('first')` (called on open and on every keystroke) already keeps\n // the focused row off a disabled item, so this fallback is only ever reached when\n // nothing has been focused yet, but it mirrors `selectItem`'s own disabled guard\n // rather than blindly grabbing index 0, in case that navigate-on-open wiring ever\n // changes.\n const active = list.getActiveItem() ?? filteredItems.value.find((item) => !item.disabled);\n\n if (active) {\n e.preventDefault();\n selectItem(active);\n }\n }\n }\n\n return html`\n <dialog ref=\"${dialogRef}\" class=\"dialog\" part=\"dialog\" aria-label=\"${props.label}\" aria-modal=\"true\">\n <div class=\"panel\" part=\"panel\">\n <div class=\"search\" part=\"search\">\n <span class=\"search-icon\" aria-hidden=\"true\"><ore-icon name=\"search\" size=\"18\"></ore-icon></span>\n <input\n ref=\"${searchInputRef}\"\n class=\"search-input\"\n part=\"input\"\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-expanded=\"true\"\n aria-autocomplete=\"list\"\n aria-controls=\"${listboxId}\"\n aria-activedescendant=\"${() => (focusedIndex.value >= 0 ? `${listboxId}-opt-${focusedIndex.value}` : '')}\"\n placeholder=\"${props.placeholder}\"\n value=\"${query}\"\n @input=\"${handleInput}\"\n @keydown=\"${handleKeydown}\" />\n <span class=\"search-loader\" ?hidden=\"${() => !props.loading.value}\" aria-hidden=\"true\"></span>\n </div>\n <div\n class=\"listbox\"\n part=\"listbox\"\n role=\"listbox\"\n id=\"${listboxId}\"\n aria-label=\"Commands\"\n ref=\"${(listEl: HTMLElement) => {\n listboxEl = listEl;\n }}\">\n <div class=\"empty\" role=\"presentation\" ?hidden=\"${() => props.loading.value || rows.value.length > 0}\">\n ${() => props['empty-text'].value}\n </div>\n ${() =>\n rows.value.map((row) =>\n row.type === 'group'\n ? html`\n <div class=\"group-heading\" role=\"presentation\">${row.group}</div>\n `\n : html`\n <div\n class=\"item\"\n part=\"item\"\n role=\"option\"\n id=\"${`${listboxId}-opt-${row.idx}`}\"\n aria-selected=\"${() => String(focusedIndex.value === row.idx)}\"\n aria-disabled=\"${() => String(row.item.disabled)}\"\n ?data-focused=\"${() => focusedIndex.value === row.idx}\"\n ?data-disabled=\"${() => row.item.disabled}\"\n @click=\"${(e: MouseEvent) => {\n e.stopPropagation();\n selectItem(row.item);\n }}\"\n @pointerenter=\"${() => {\n list.set(row.idx);\n }}\">\n ${\n row.item.icon\n ? html`\n <span class=\"item-icon\" aria-hidden=\"true\">\n <ore-icon name=\"${row.item.icon}\" size=\"16\"></ore-icon>\n </span>\n `\n : ''\n }\n <span class=\"item-label\">${row.item.label}</span>\n ${\n row.item.shortcut\n ? html`\n <span class=\"item-shortcut\">\n ${splitShortcutKeys(row.item.shortcut).map(\n (key) => html`\n <ore-keyboard-key>${key}</ore-keyboard-key>\n `,\n )}\n </span>\n `\n : ''\n }\n </div>\n `,\n )}\n </div>\n <div class=\"footer\" part=\"footer\">\n <span class=\"footer-hint\">\n <ore-keyboard-key>↑</ore-keyboard-key>\n <ore-keyboard-key>↓</ore-keyboard-key>\n Navigate\n </span>\n <span class=\"footer-hint\">\n <ore-keyboard-key>Enter</ore-keyboard-key>\n Select\n </span>\n <span class=\"footer-hint\">\n <ore-keyboard-key>Esc</ore-keyboard-key>\n Close\n </span>\n </div>\n </div>\n </dialog>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"command-palette.js","names":[],"sources":["../src/overlay/command-palette/command-palette.ts"],"sourcesContent":["import { createKeymap } from '@vielzeug/keymap';\nimport { define, getHost, html, onCleanup, onEvent, onMounted, prop, ref, useEmit } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\nimport { warn } from '../../_dev';\n\nimport { announce, createListControl, lifecycleSignal, parseOptionalBool } from '../../core';\nimport { reducedMotionMixin } from '../../styles';\nimport { useDialogControl } from '../shared/use-dialog';\nimport componentStyles from './command-palette.css?inline';\nimport type { CommandPaletteItem, OreCommandPaletteEvents, OreCommandPaletteProps } from './command-palette.types';\nimport { buildRows, filterItems, normalizeItem, parseSlottedItems, splitShortcutKeys } from './command-palette-items';\n\nexport { ICON_TAG } from '../../content/icon/icon';\nexport { KEYBOARD_SHORTCUT_TAG } from '../../content/keyboard-key/keyboard-key';\nexport type { OreCommandPaletteEvents, OreCommandPaletteProps } from './command-palette.types';\n\n/**\n * A pure data node describing one command. Never rendered directly: `ore-command-palette`\n * reads its attributes/text content and renders the visible row itself.\n *\n * @element ore-command-palette-item\n *\n * @attr {string} value - Value emitted by the `select` event and matched against the search query\n * @attr {string} label - Explicit label text; falls back to the element's text content\n * @attr {string} group - Group heading the item is clustered under\n * @attr {string} shortcut - Display-only keyboard hint rendered at the end of the row, one `<kbd>` per `+`-separated key (e.g. `\"⌘+S\"` renders two keycaps; a literal `+` key isn't representable: spell it out, e.g. `\"Ctrl+Plus\"`)\n * @attr {boolean} disabled - Excludes the item from keyboard navigation and selection\n *\n * @slot icon - Optional leading icon content\n *\n * @example\n * ```html\n * <ore-command-palette-item value=\"new-file\" group=\"File\" shortcut=\"⌘+N\">New File</ore-command-palette-item>\n * ```\n */\nexport const COMMAND_PALETTE_ITEM_TAG = 'ore-command-palette-item' as const;\ndefine(COMMAND_PALETTE_ITEM_TAG, {\n setup() {\n return html``;\n },\n});\n\n/**\n * A searchable, keyboard-driven list of commands presented in a centered modal :\n * the \"⌘K\" pattern popularized by editors and productivity apps. Built on the\n * native `<dialog>` element (focus trap, top-layer stacking, `Escape`-to-close)\n * and `@vielzeug/keymap` for the global shortcut that opens it.\n *\n * @element ore-command-palette\n * @element ore-command-palette-item - Slotted command definition (place in default slot)\n *\n * @attr {boolean} open - Controls the open state of the palette\n * @attr {boolean} default-open - Initial uncontrolled open state\n * @attr {string} label - Accessible label for the dialog (screen-reader-only heading)\n * @attr {string} placeholder - Placeholder text for the search input\n * @attr {string} shortcut - Global keyboard shortcut (keymap syntax) that toggles the palette. Default `\"mod+k\"`; set to `\"\"` to disable\n * @attr {boolean} no-filter - Disable built-in client-side filtering (for server-driven search)\n * @attr {boolean} loading - Shows a loading row below the search input\n * @attr {string} empty-text - Message shown when no item matches the query\n * @attr {boolean} keep-open-on-select - Keep the palette open after an item is selected\n *\n * @fires active-change - Fired when the focused row changes (keyboard, hover, typing, open, close). detail: `{ value, label, item }`; `item` is `undefined` and `value` empty when no row is active\n * @fires open-change - Fired when the palette state changes. detail: `{ open, reason }`\n * @fires search - Fired on every keystroke in the search input. detail: `{ query }`\n * @fires select - Fired when a command is chosen (click or `Enter`). detail: `{ value, label, item }`\n *\n * @slot - `<ore-command-palette-item>` elements (alternative/supplement to the `items` prop)\n * @slot preview - Optional detail panel rendered beside the list, shown while it has content. Pair it with `active-change` to preview the focused row\n *\n * @cssprop --command-palette-bg - Panel background color\n * @cssprop --command-palette-border-color - Panel border color\n * @cssprop --command-palette-radius - Panel border radius\n * @cssprop --command-palette-shadow - Panel drop shadow\n * @cssprop --command-palette-max-width - Maximum panel width\n * @cssprop --command-palette-backdrop - Backdrop overlay color\n * @cssprop --command-palette-option-hover-bg - Item background on hover\n * @cssprop --command-palette-option-focus-bg - Item background when keyboard-focused\n * @cssprop --command-palette-preview-width - Preview panel width when the `preview` slot has content\n *\n * @part dialog - Dialog root container\n * @part panel - Panel container\n * @part input - Search input\n * @part listbox - Listbox of matching commands\n * @part preview - Preview panel shown beside the list\n *\n * @example\n * ```html\n * <ore-command-palette label=\"Command palette\" placeholder=\"Type a command…\">\n * <ore-command-palette-item value=\"new-file\" group=\"File\" shortcut=\"⌘+N\">New File</ore-command-palette-item>\n * <ore-command-palette-item value=\"open-file\" group=\"File\" shortcut=\"⌘+O\">Open File…</ore-command-palette-item>\n * <ore-command-palette-item value=\"toggle-theme\" group=\"View\">Toggle Theme</ore-command-palette-item>\n * </ore-command-palette>\n * ```\n */\nexport const COMMAND_PALETTE_TAG = 'ore-command-palette' as const;\ndefine<OreCommandPaletteProps>(COMMAND_PALETTE_TAG, {\n props: {\n 'default-open': prop.bool(false),\n 'empty-text': prop.string('No results found.'),\n items: prop.data<OreCommandPaletteProps['items']>(),\n 'keep-open-on-select': prop.bool(false),\n label: prop.string('Command palette'),\n loading: prop.bool(false),\n 'no-filter': prop.bool(false),\n open: { default: undefined as boolean | undefined, parse: parseOptionalBool },\n placeholder: prop.string('Type a command or search…'),\n shortcut: prop.string('mod+k'),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCommandPaletteEvents>();\n const abortSignal = lifecycleSignal(onCleanup);\n\n const dialogRef = ref<HTMLDialogElement>();\n const searchInputRef = ref<HTMLInputElement>();\n const listboxId = 'cmdk-listbox';\n\n let listboxEl: HTMLElement | null = null;\n\n const query = signal('');\n\n // ── Items: slotted <ore-command-palette-item> elements, merged with the `items` prop ──\n // Items are pure data nodes (see `ore-command-palette-item`'s own doc comment): they're\n // never projected through a `<slot>`, just read directly off the host's light DOM. That\n // sidesteps `useSlots()`/`slotchange` entirely: a plain MutationObserver on the host\n // already covers everything `slotchange` would (an item added or removed) *and* the case\n // it can't: an already-assigned item's own text/attributes changing. For items written\n // as static, inline HTML, the browser's parser can insert the last item before appending\n // its text-node child; without watching `characterData`, that would permanently cache an\n // empty label, since nothing else re-triggers once the element itself stops changing.\n const slottedItems = signal<CommandPaletteItem[]>([]);\n\n const reparseSlottedItems = (): void => {\n slottedItems.value = parseSlottedItems([...el.children]);\n };\n\n reparseSlottedItems();\n\n const lightDomObserver = new MutationObserver(reparseSlottedItems);\n\n lightDomObserver.observe(el, { characterData: true, childList: true, subtree: true });\n onCleanup(() => lightDomObserver.disconnect());\n\n const allItems = computed<CommandPaletteItem[]>(() => {\n const explicit = props.items.value;\n\n return Array.isArray(explicit) ? explicit.map(normalizeItem) : slottedItems.value;\n });\n\n const filteredItems = computed(() => filterItems(allItems.value, query.value, Boolean(props['no-filter'].value)));\n const rows = computed(() => buildRows(filteredItems.value));\n\n // ── Keyboard navigation over the filtered list (Up/Down/Home/End) ──\n const scrollFocusedIntoView = (): void => {\n listboxEl?.querySelector<HTMLElement>('[data-focused]')?.scrollIntoView({ block: 'nearest' });\n };\n\n const list = createListControl<CommandPaletteItem>({\n getItems: () => filteredItems.value,\n isItemDisabled: (item) => item.disabled,\n onNavigate: scrollFocusedIntoView,\n signal: abortSignal,\n });\n const { focusedIndex } = list;\n\n // ── Active row: mirrors the focused row to the host so a `preview` slot can ──\n // follow keyboard, hover and typing without the host reaching into the listbox.\n // Watching the derived item (not just the index) also catches the row under a\n // stable index changing because the filtered list itself changed.\n watch(\n () => filteredItems.value[focusedIndex.value],\n (item) => {\n emit('active-change', item ? { item, label: item.label, value: item.value } : { label: '', value: '' });\n },\n );\n\n // The preview pane folds away while its slot is empty, so a palette that never\n // uses it keeps the plain single-column layout.\n const hasPreview = signal(false);\n\n // ── Dialog chrome: native <dialog>, focus trap, Escape, backdrop click ──\n const resetSearch = (): void => {\n query.value = '';\n list.reset();\n };\n\n const { closeWithAnimation, handleBackdropClick, overlay, requestClose, mount } = useDialogControl({\n defaultOpen: props['default-open'],\n dialogRef,\n getPanelEl: () => dialogRef.value?.querySelector<HTMLElement>('.panel'),\n host: el,\n initialFocus: computed(() => '.search-input'),\n isPersistent: () => false,\n onCleanup,\n onEvent,\n onNativeClose: (reason) => {\n emit('open-change', { open: false, reason });\n resetSearch();\n },\n onOpen: (reason) => {\n emit('open-change', { open: true, reason });\n list.navigate('first');\n },\n openProp: props.open,\n performClose: () => closeWithAnimation(),\n returnFocus: computed(() => true),\n });\n\n // ── Global keyboard shortcut (opens/closes the palette from anywhere) ──\n const globalKeymap = createKeymap();\n\n globalKeymap.mount(window);\n onCleanup(() => globalKeymap.dispose());\n\n let unbindShortcut: (() => void) | null = null;\n\n watch(\n props.shortcut,\n (shortcutStr) => {\n unbindShortcut?.();\n unbindShortcut = null;\n\n const trimmed = (shortcutStr ?? '').trim();\n\n if (!trimmed) return;\n\n try {\n unbindShortcut = globalKeymap.bind({\n handler: () => {\n overlay.toggle('keyboard', 'trigger');\n },\n id: 'command-palette-toggle',\n shortcut: trimmed,\n });\n } catch (error) {\n warn(`invalid \"shortcut\" value \"${trimmed}\": ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n { immediate: true },\n );\n\n onMounted(() => {\n mount();\n if (dialogRef.value) onEvent(dialogRef.value, 'click', handleBackdropClick);\n });\n\n // ── Selection ────────────────────────────────────────────────────────────\n function selectItem(item: CommandPaletteItem): void {\n if (item.disabled) return;\n\n emit('select', { item, label: item.label, value: item.value });\n\n if (props['keep-open-on-select'].value) {\n searchInputRef.value?.focus();\n } else {\n requestClose('trigger');\n }\n }\n\n function handleInput(e: Event): void {\n const value = (e.target as HTMLInputElement).value;\n\n query.value = value;\n list.navigate('first');\n emit('search', { query: value });\n\n const count = filteredItems.value.length;\n\n announce(count === 0 ? props['empty-text'].value! : `${count} result${count === 1 ? '' : 's'} found`, {\n document: el.ownerDocument,\n });\n }\n\n function handleKeydown(e: KeyboardEvent): void {\n if (list.handleKeydown(e)) return;\n\n if (e.key === 'Enter') {\n // `list.navigate('first')` (called on open and on every keystroke) already keeps\n // the focused row off a disabled item, so this fallback is only ever reached when\n // nothing has been focused yet, but it mirrors `selectItem`'s own disabled guard\n // rather than blindly grabbing index 0, in case that navigate-on-open wiring ever\n // changes.\n const active = list.getActiveItem() ?? filteredItems.value.find((item) => !item.disabled);\n\n if (active) {\n e.preventDefault();\n selectItem(active);\n }\n }\n }\n\n return html`\n <dialog ref=\"${dialogRef}\" class=\"dialog\" part=\"dialog\" aria-label=\"${props.label}\" aria-modal=\"true\">\n <div class=\"panel\" part=\"panel\">\n <div class=\"search\" part=\"search\">\n <span class=\"search-icon\" aria-hidden=\"true\"><ore-icon name=\"search\" size=\"18\"></ore-icon></span>\n <input\n ref=\"${searchInputRef}\"\n class=\"search-input\"\n part=\"input\"\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-expanded=\"true\"\n aria-autocomplete=\"list\"\n aria-controls=\"${listboxId}\"\n aria-activedescendant=\"${() => (focusedIndex.value >= 0 ? `${listboxId}-opt-${focusedIndex.value}` : '')}\"\n placeholder=\"${props.placeholder}\"\n value=\"${query}\"\n @input=\"${handleInput}\"\n @keydown=\"${handleKeydown}\" />\n <span class=\"search-loader\" ?hidden=\"${() => !props.loading.value}\" aria-hidden=\"true\"></span>\n </div>\n <div class=\"body\">\n <div\n class=\"listbox\"\n part=\"listbox\"\n role=\"listbox\"\n id=\"${listboxId}\"\n aria-label=\"Commands\"\n ref=\"${(listEl: HTMLElement) => {\n listboxEl = listEl;\n }}\">\n <div class=\"empty\" role=\"presentation\" ?hidden=\"${() => props.loading.value || rows.value.length > 0}\">\n ${() => props['empty-text'].value}\n </div>\n ${() =>\n rows.value.map((row) =>\n row.type === 'group'\n ? html`\n <div class=\"group-heading\" role=\"presentation\">${row.group}</div>\n `\n : html`\n <div\n class=\"item\"\n part=\"item\"\n role=\"option\"\n id=\"${`${listboxId}-opt-${row.idx}`}\"\n aria-selected=\"${() => String(focusedIndex.value === row.idx)}\"\n aria-disabled=\"${() => String(row.item.disabled)}\"\n ?data-focused=\"${() => focusedIndex.value === row.idx}\"\n ?data-disabled=\"${() => row.item.disabled}\"\n @click=\"${(e: MouseEvent) => {\n e.stopPropagation();\n selectItem(row.item);\n }}\"\n @pointerenter=\"${() => {\n list.set(row.idx);\n }}\">\n ${\n row.item.icon\n ? html`\n <span class=\"item-icon\" aria-hidden=\"true\">\n <ore-icon name=\"${row.item.icon}\" size=\"16\"></ore-icon>\n </span>\n `\n : ''\n }\n <span class=\"item-label\">${row.item.label}</span>\n ${\n row.item.shortcut\n ? html`\n <span class=\"item-shortcut\">\n ${splitShortcutKeys(row.item.shortcut).map(\n (key) => html`\n <ore-keyboard-key>${key}</ore-keyboard-key>\n `,\n )}\n </span>\n `\n : ''\n }\n </div>\n `,\n )}\n </div>\n <div class=\"preview\" part=\"preview\" role=\"region\" aria-label=\"Preview\" ?hidden=\"${() => !hasPreview.value}\">\n <slot\n name=\"preview\"\n @slotchange=\"${(e: Event) => {\n hasPreview.value = (e.target as HTMLSlotElement).assignedElements().length > 0;\n }}\"\n ></slot>\n </div>\n </div>\n <div class=\"footer\" part=\"footer\">\n <span class=\"footer-hint\">\n <ore-keyboard-key>↑</ore-keyboard-key>\n <ore-keyboard-key>↓</ore-keyboard-key>\n Navigate\n </span>\n <span class=\"footer-hint\">\n <ore-keyboard-key>Enter</ore-keyboard-key>\n Select\n </span>\n <span class=\"footer-hint\">\n <ore-keyboard-key>Esc</ore-keyboard-key>\n Close\n </span>\n </div>\n </div>\n </dialog>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
|
|
@@ -16265,6 +16265,13 @@
|
|
|
16265
16265
|
}
|
|
16266
16266
|
],
|
|
16267
16267
|
"events": [
|
|
16268
|
+
{
|
|
16269
|
+
"name": "active-change",
|
|
16270
|
+
"description": "Fired when the focused row changes (keyboard, hover, typing, open, close). detail: `{ value, label, item }`; `item` is `undefined` and `value` empty when no row is active",
|
|
16271
|
+
"type": {
|
|
16272
|
+
"text": "CustomEvent"
|
|
16273
|
+
}
|
|
16274
|
+
},
|
|
16268
16275
|
{
|
|
16269
16276
|
"name": "open-change",
|
|
16270
16277
|
"description": "Fired when the palette state changes. detail: `{ open, reason }`",
|
|
@@ -16291,6 +16298,10 @@
|
|
|
16291
16298
|
{
|
|
16292
16299
|
"name": "",
|
|
16293
16300
|
"description": "`<ore-command-palette-item>` elements (alternative/supplement to the `items` prop)"
|
|
16301
|
+
},
|
|
16302
|
+
{
|
|
16303
|
+
"name": "preview",
|
|
16304
|
+
"description": "Optional detail panel rendered beside the list, shown while it has content. Pair it with `active-change` to preview the focused row"
|
|
16294
16305
|
}
|
|
16295
16306
|
],
|
|
16296
16307
|
"cssParts": [
|
|
@@ -16309,6 +16320,10 @@
|
|
|
16309
16320
|
{
|
|
16310
16321
|
"name": "listbox",
|
|
16311
16322
|
"description": "Listbox of matching commands"
|
|
16323
|
+
},
|
|
16324
|
+
{
|
|
16325
|
+
"name": "preview",
|
|
16326
|
+
"description": "Preview panel shown beside the list"
|
|
16312
16327
|
}
|
|
16313
16328
|
],
|
|
16314
16329
|
"cssProperties": [
|
|
@@ -16343,6 +16358,10 @@
|
|
|
16343
16358
|
{
|
|
16344
16359
|
"name": "--command-palette-option-focus-bg",
|
|
16345
16360
|
"description": "Item background when keyboard-focused"
|
|
16361
|
+
},
|
|
16362
|
+
{
|
|
16363
|
+
"name": "--command-palette-preview-width",
|
|
16364
|
+
"description": "Preview panel width when the `preview` slot has content"
|
|
16346
16365
|
}
|
|
16347
16366
|
],
|
|
16348
16367
|
"demos": [
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e=`@layer refine.base{:host{--_radius:var(--command-palette-radius,var(--rounded-lg));--_max-width:var(--command-palette-max-width,40rem);--_backdrop-bg:var(--command-palette-backdrop,color-mix(in oklch, var(--color-canvas) 40%, transparent));--_panel-bg:var(--command-palette-bg,var(--color-canvas));--_panel-border-color:var(--command-palette-border-color,var(--color-divider));--_option-hover-bg:var(--command-palette-option-hover-bg,var(--color-contrast-100));--_option-focus-bg:var(--command-palette-option-focus-bg,color-mix(in oklch, var(--color-primary) 12%, var(--color-contrast-100)));display:contents}dialog{all:unset;box-sizing:border-box;pointer-events:none;width:100%;max-width:100%;height:100%;max-height:100%;transition:display .2s allow-discrete, overlay .2s allow-discrete;padding-top:min(14vh, var(--size-24));background:0 0;border:none;justify-content:center;align-items:flex-start;margin:0;display:flex;position:fixed;inset:0;overflow:hidden}dialog:not([open]),dialog:not([open]) .panel{display:none}dialog[open]{pointer-events:auto}dialog::-ms-backdrop{background:var(--_backdrop-bg);opacity:1;-webkit-backdrop-filter:blur(var(--blur-xs));backdrop-filter:blur(var(--blur-xs));transition:opacity var(--transition-normal), overlay var(--transition-normal) allow-discrete, display var(--transition-normal) allow-discrete}@starting-style{dialog::-ms-backdrop{opacity:0}}dialog::backdrop{background:var(--_backdrop-bg);opacity:1;-webkit-backdrop-filter:blur(var(--blur-xs));backdrop-filter:blur(var(--blur-xs));transition:opacity var(--transition-normal), overlay var(--transition-normal) allow-discrete, display var(--transition-normal) allow-discrete}@starting-style{dialog::backdrop{opacity:0}}dialog.closing::-ms-backdrop{opacity:0}dialog.closing::backdrop{opacity:0}.panel{box-sizing:border-box;width:var(--_max-width);max-width:calc(100vw - var(--size-8));max-height:min(28rem, calc(100dvh - var(--size-16)));background:var(--_panel-bg);border:var(--border) solid var(--_panel-border-color);border-radius:var(--_radius);box-shadow:var(--command-palette-shadow,var(--shadow-2xl));opacity:1;-webkit-backdrop-filter:blur(var(--blur-md));backdrop-filter:blur(var(--blur-md));transition:opacity .2s var(--ease-spring), transform .2s var(--ease-spring);flex-direction:column;display:flex;position:relative;overflow:hidden;transform:scale(1)translateY(0)}@starting-style{.panel{opacity:0;transform:scale(var(--overlay-enter-scale-dialog)) translateY(-4px)}}dialog.closing .panel{opacity:0;transform:scale(var(--overlay-enter-scale-dialog)) translateY(-4px);transition:opacity .15s var(--ease-spring), transform .15s var(--ease-spring)}@media (width<=640px){.panel{width:calc(100vw - var(--size-4));max-width:calc(100vw - var(--size-4))}dialog{padding-top:var(--size-4)}}.search{gap:var(--size-2);padding:var(--size-3) var(--size-4);border-bottom:var(--border) solid var(--color-contrast-100);flex-shrink:0;align-items:center;display:flex}.search-icon{color:var(--color-contrast-400);flex-shrink:0;display:inline-flex}.search-input{min-width:0;font:inherit;font-size:var(--text-md);color:var(--color-contrast-900);background:0 0;border:none;outline:none;flex:1;padding:0}.search-input::placeholder{color:var(--color-contrast-400)}.search-loader{border:2px solid var(--color-contrast-300);width:1em;height:1em;animation:command-palette-spin var(--transition-loader) infinite;border-radius:50%;flex-shrink:0;display:inline-flex}.search-loader:not(:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))){border-right-color:#0000}.search-loader:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)){border-left-color:#0000}.search-loader[hidden]{display:none}@keyframes command-palette-spin{to{transform:rotate(360deg)}}.listbox{padding:var(--size-1);overscroll-behavior:contain;scrollbar-width:thin;flex:1;overflow-y:auto}.empty{padding:var(--size-6) var(--size-3);font-size:var(--text-sm);color:var(--color-contrast-400);text-align:center}.group-heading{padding:var(--size-2) var(--size-2-5) var(--size-1);font-size:var(--text-xs);font-weight:var(--font-semibold);color:var(--color-contrast-500);text-transform:uppercase;letter-spacing:var(--tracking-wide,.05em)}.item{gap:var(--size-2-5);padding:var(--size-2) var(--size-2-5);font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--color-contrast-800);cursor:pointer;border-radius:var(--rounded-md);transition:background var(--transition-fast);align-items:center;display:flex}.item:hover:not([data-disabled]){background:var(--_option-hover-bg)}.item[data-focused]:not([data-disabled]){background:var(--_option-focus-bg)}.item[data-disabled]{color:var(--color-contrast-400);cursor:not-allowed;opacity:.6}.item-icon{color:var(--color-contrast-500);flex-shrink:0;align-items:center;display:inline-flex}.item-label{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.item-shortcut{gap:var(--size-1);flex-shrink:0;display:inline-flex}.footer{gap:var(--size-4);padding:var(--size-2) var(--size-4);font-size:var(--text-xs);color:var(--color-contrast-500);border-top:var(--border) solid var(--color-contrast-100);flex-shrink:0;align-items:center;display:flex}.footer-hint{gap:var(--size-1);align-items:center;display:inline-flex}.footer ore-keyboard-key{--keyboard-key-font-family:inherit;--keyboard-key-padding-inline:var(--size-1)}::slotted(ore-command-palette-item){display:none}}`;exports.default=e;
|
|
1
|
+
var e=`@layer refine.base{:host{--_radius:var(--command-palette-radius,var(--rounded-lg));--_max-width:var(--command-palette-max-width,40rem);--_preview-width:var(--command-palette-preview-width,18rem);--_backdrop-bg:var(--command-palette-backdrop,color-mix(in oklch, var(--color-canvas) 40%, transparent));--_panel-bg:var(--command-palette-bg,var(--color-canvas));--_panel-border-color:var(--command-palette-border-color,var(--color-divider));--_option-hover-bg:var(--command-palette-option-hover-bg,var(--color-contrast-100));--_option-focus-bg:var(--command-palette-option-focus-bg,color-mix(in oklch, var(--color-primary) 12%, var(--color-contrast-100)));display:contents}dialog{all:unset;box-sizing:border-box;pointer-events:none;width:100%;max-width:100%;height:100%;max-height:100%;transition:display .2s allow-discrete, overlay .2s allow-discrete;padding-top:min(14vh, var(--size-24));background:0 0;border:none;justify-content:center;align-items:flex-start;margin:0;display:flex;position:fixed;inset:0;overflow:hidden}dialog:not([open]),dialog:not([open]) .panel{display:none}dialog[open]{pointer-events:auto}dialog::-ms-backdrop{background:var(--_backdrop-bg);opacity:1;-webkit-backdrop-filter:blur(var(--blur-xs));backdrop-filter:blur(var(--blur-xs));transition:opacity var(--transition-normal), overlay var(--transition-normal) allow-discrete, display var(--transition-normal) allow-discrete}@starting-style{dialog::-ms-backdrop{opacity:0}}dialog::backdrop{background:var(--_backdrop-bg);opacity:1;-webkit-backdrop-filter:blur(var(--blur-xs));backdrop-filter:blur(var(--blur-xs));transition:opacity var(--transition-normal), overlay var(--transition-normal) allow-discrete, display var(--transition-normal) allow-discrete}@starting-style{dialog::backdrop{opacity:0}}dialog.closing::-ms-backdrop{opacity:0}dialog.closing::backdrop{opacity:0}.panel{box-sizing:border-box;width:var(--_max-width);max-width:calc(100vw - var(--size-8));max-height:min(28rem, calc(100dvh - var(--size-16)));background:var(--_panel-bg);border:var(--border) solid var(--_panel-border-color);border-radius:var(--_radius);box-shadow:var(--command-palette-shadow,var(--shadow-2xl));opacity:1;-webkit-backdrop-filter:blur(var(--blur-md));backdrop-filter:blur(var(--blur-md));transition:opacity .2s var(--ease-spring), transform .2s var(--ease-spring);flex-direction:column;display:flex;position:relative;overflow:hidden;transform:scale(1)translateY(0)}@starting-style{.panel{opacity:0;transform:scale(var(--overlay-enter-scale-dialog)) translateY(-4px)}}dialog.closing .panel{opacity:0;transform:scale(var(--overlay-enter-scale-dialog)) translateY(-4px);transition:opacity .15s var(--ease-spring), transform .15s var(--ease-spring)}@media (width<=640px){.panel{width:calc(100vw - var(--size-4));max-width:calc(100vw - var(--size-4))}dialog{padding-top:var(--size-4)}.body{flex-direction:column}.preview{border-top:var(--border) solid var(--color-contrast-100);width:auto;max-height:40%}.preview:not(:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))){border-left:0}.preview:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)){border-right:0}}.search{gap:var(--size-2);padding:var(--size-3) var(--size-4);border-bottom:var(--border) solid var(--color-contrast-100);flex-shrink:0;align-items:center;display:flex}.search-icon{color:var(--color-contrast-400);flex-shrink:0;display:inline-flex}.search-input{min-width:0;font:inherit;font-size:var(--text-md);color:var(--color-contrast-900);background:0 0;border:none;outline:none;flex:1;padding:0}.search-input::placeholder{color:var(--color-contrast-400)}.search-loader{border:2px solid var(--color-contrast-300);width:1em;height:1em;animation:command-palette-spin var(--transition-loader) infinite;border-radius:50%;flex-shrink:0;display:inline-flex}.search-loader:not(:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))){border-right-color:#0000}.search-loader:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)){border-left-color:#0000}.search-loader[hidden]{display:none}@keyframes command-palette-spin{to{transform:rotate(360deg)}}.body{flex:1;min-height:0;display:flex}.listbox{min-width:0;padding:var(--size-1);overscroll-behavior:contain;scrollbar-width:thin;flex:1;overflow-y:auto}.preview{width:var(--_preview-width);padding:var(--size-3) var(--size-4);overscroll-behavior:contain;font-size:var(--text-sm);color:var(--color-contrast-700);scrollbar-width:thin;flex-shrink:0;overflow-y:auto}.preview:not(:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))){border-left:var(--border) solid var(--color-contrast-100)}.preview:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)){border-right:var(--border) solid var(--color-contrast-100)}.preview[hidden]{display:none}.empty{padding:var(--size-6) var(--size-3);font-size:var(--text-sm);color:var(--color-contrast-400);text-align:center}.group-heading{padding:var(--size-2) var(--size-2-5) var(--size-1);font-size:var(--text-xs);font-weight:var(--font-semibold);color:var(--color-contrast-500);text-transform:uppercase;letter-spacing:var(--tracking-wide,.05em)}.item{gap:var(--size-2-5);padding:var(--size-2) var(--size-2-5);font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--color-contrast-800);cursor:pointer;border-radius:var(--rounded-md);transition:background var(--transition-fast);align-items:center;display:flex}.item:hover:not([data-disabled]){background:var(--_option-hover-bg)}.item[data-focused]:not([data-disabled]){background:var(--_option-focus-bg)}.item[data-disabled]{color:var(--color-contrast-400);cursor:not-allowed;opacity:.6}.item-icon{color:var(--color-contrast-500);flex-shrink:0;align-items:center;display:inline-flex}.item-label{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.item-shortcut{gap:var(--size-1);flex-shrink:0;display:inline-flex}.footer{gap:var(--size-4);padding:var(--size-2) var(--size-4);font-size:var(--text-xs);color:var(--color-contrast-500);border-top:var(--border) solid var(--color-contrast-100);flex-shrink:0;align-items:center;display:flex}.footer-hint{gap:var(--size-1);align-items:center;display:inline-flex}.footer ore-keyboard-key{--keyboard-key-font-family:inherit;--keyboard-key-padding-inline:var(--size-1)}::slotted(ore-command-palette-item){display:none}}`;exports.default=e;
|
|
2
2
|
//# sourceMappingURL=command-palette.css.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-palette.css.cjs","names":[],"sources":["../../../src/overlay/command-palette/command-palette.css?inline"],"sourcesContent":["@layer refine.base {\n :host {\n --_radius: var(--command-palette-radius, var(--rounded-lg));\n --_max-width: var(--command-palette-max-width, 40rem);\n --_backdrop-bg: var(--command-palette-backdrop, color-mix(in oklch, var(--color-canvas) 40%, transparent));\n --_panel-bg: var(--command-palette-bg, var(--color-canvas));\n --_panel-border-color: var(--command-palette-border-color, var(--color-divider));\n --_option-hover-bg: var(--command-palette-option-hover-bg, var(--color-contrast-100));\n --_option-focus-bg: var(\n --command-palette-option-focus-bg,\n color-mix(in oklch, var(--color-primary) 12%, var(--color-contrast-100))\n );\n\n display: contents;\n }\n\n /* =====================\n Native <dialog> resets: see ore-dialog for the full rationale.\n ===================== */\n\n dialog {\n all: unset;\n position: fixed;\n inset: 0;\n box-sizing: border-box;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n width: 100%;\n max-width: 100%;\n height: 100%;\n max-height: 100%;\n padding-block-start: min(14vh, var(--size-24));\n margin: 0;\n overflow: hidden;\n pointer-events: none;\n background: transparent;\n border: none;\n transition:\n display 200ms allow-discrete,\n overlay 200ms allow-discrete;\n }\n\n dialog:not([open]) {\n display: none;\n }\n\n dialog:not([open]) .panel {\n display: none;\n }\n\n dialog[open] {\n pointer-events: auto;\n }\n\n dialog::backdrop {\n background: var(--_backdrop-bg);\n opacity: 1;\n backdrop-filter: blur(var(--blur-xs));\n transition:\n opacity var(--transition-normal),\n overlay var(--transition-normal) allow-discrete,\n display var(--transition-normal) allow-discrete;\n\n @starting-style {\n opacity: 0;\n }\n }\n\n dialog.closing::backdrop {\n opacity: 0;\n }\n\n /* =====================\n Panel\n ===================== */\n\n .panel {\n position: relative;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n width: var(--_max-width);\n max-width: calc(100vw - var(--size-8));\n max-height: min(28rem, calc(100dvh - var(--size-16)));\n overflow: hidden;\n background: var(--_panel-bg);\n border: var(--border) solid var(--_panel-border-color);\n border-radius: var(--_radius);\n box-shadow: var(--command-palette-shadow, var(--shadow-2xl));\n opacity: 1;\n backdrop-filter: blur(var(--blur-md));\n transform: scale(1) translateY(0);\n transition:\n opacity 200ms var(--ease-spring),\n transform 200ms var(--ease-spring);\n\n @starting-style {\n opacity: 0;\n transform: scale(var(--overlay-enter-scale-dialog)) translateY(-4px);\n }\n }\n\n dialog.closing .panel {\n opacity: 0;\n transform: scale(var(--overlay-enter-scale-dialog)) translateY(-4px);\n transition:\n opacity 150ms var(--ease-spring),\n transform 150ms var(--ease-spring);\n }\n\n @media (width <= 640px) {\n .panel {\n width: calc(100vw - var(--size-4));\n max-width: calc(100vw - var(--size-4));\n }\n\n dialog {\n padding-block-start: var(--size-4);\n }\n }\n\n /* =====================\n Search field\n ===================== */\n\n .search {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-2);\n align-items: center;\n padding: var(--size-3) var(--size-4);\n border-block-end: var(--border) solid var(--color-contrast-100);\n }\n\n .search-icon {\n display: inline-flex;\n flex-shrink: 0;\n color: var(--color-contrast-400);\n }\n\n .search-input {\n flex: 1;\n min-width: 0;\n padding: 0;\n font: inherit;\n font-size: var(--text-md);\n color: var(--color-contrast-900);\n outline: none;\n background: transparent;\n border: none;\n }\n\n .search-input::placeholder {\n color: var(--color-contrast-400);\n }\n\n .search-loader {\n display: inline-flex;\n flex-shrink: 0;\n width: 1em;\n height: 1em;\n border: 2px solid var(--color-contrast-300);\n border-inline-end-color: transparent;\n border-radius: 50%;\n animation: command-palette-spin var(--transition-loader) infinite;\n }\n\n .search-loader[hidden] {\n display: none;\n }\n\n @keyframes command-palette-spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n /* =====================\n Listbox\n ===================== */\n\n .listbox {\n flex: 1;\n padding: var(--size-1);\n overflow-y: auto;\n overscroll-behavior: contain;\n scrollbar-width: thin;\n }\n\n .empty {\n padding: var(--size-6) var(--size-3);\n font-size: var(--text-sm);\n color: var(--color-contrast-400);\n text-align: center;\n }\n\n .group-heading {\n padding: var(--size-2) var(--size-2-5) var(--size-1);\n font-size: var(--text-xs);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-500);\n text-transform: uppercase;\n letter-spacing: var(--tracking-wide, 0.05em);\n }\n\n .item {\n display: flex;\n gap: var(--size-2-5);\n align-items: center;\n padding: var(--size-2) var(--size-2-5);\n font-size: var(--text-sm);\n line-height: var(--leading-normal);\n color: var(--color-contrast-800);\n cursor: pointer;\n border-radius: var(--rounded-md);\n transition: background var(--transition-fast);\n }\n\n .item:hover:not([data-disabled]) {\n background: var(--_option-hover-bg);\n }\n\n .item[data-focused]:not([data-disabled]) {\n background: var(--_option-focus-bg);\n }\n\n .item[data-disabled] {\n color: var(--color-contrast-400);\n cursor: not-allowed;\n opacity: 0.6;\n }\n\n .item-icon {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n color: var(--color-contrast-500);\n }\n\n .item-label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .item-shortcut {\n display: inline-flex;\n flex-shrink: 0;\n gap: var(--size-1);\n }\n\n /* =====================\n Footer hints\n ===================== */\n\n .footer {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-4);\n align-items: center;\n padding: var(--size-2) var(--size-4);\n font-size: var(--text-xs);\n color: var(--color-contrast-500);\n border-block-start: var(--border) solid var(--color-contrast-100);\n }\n\n .footer-hint {\n display: inline-flex;\n gap: var(--size-1);\n align-items: center;\n }\n\n .footer ore-keyboard-key {\n --keyboard-key-font-family: inherit;\n --keyboard-key-padding-inline: var(--size-1);\n }\n\n /* Slotted item elements are pure data nodes: never rendered directly. */\n ::slotted(ore-command-palette-item) {\n display: none;\n }\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"command-palette.css.cjs","names":[],"sources":["../../../src/overlay/command-palette/command-palette.css?inline"],"sourcesContent":["@layer refine.base {\n :host {\n --_radius: var(--command-palette-radius, var(--rounded-lg));\n --_max-width: var(--command-palette-max-width, 40rem);\n --_preview-width: var(--command-palette-preview-width, 18rem);\n --_backdrop-bg: var(--command-palette-backdrop, color-mix(in oklch, var(--color-canvas) 40%, transparent));\n --_panel-bg: var(--command-palette-bg, var(--color-canvas));\n --_panel-border-color: var(--command-palette-border-color, var(--color-divider));\n --_option-hover-bg: var(--command-palette-option-hover-bg, var(--color-contrast-100));\n --_option-focus-bg: var(\n --command-palette-option-focus-bg,\n color-mix(in oklch, var(--color-primary) 12%, var(--color-contrast-100))\n );\n\n display: contents;\n }\n\n /* =====================\n Native <dialog> resets: see ore-dialog for the full rationale.\n ===================== */\n\n dialog {\n all: unset;\n position: fixed;\n inset: 0;\n box-sizing: border-box;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n width: 100%;\n max-width: 100%;\n height: 100%;\n max-height: 100%;\n padding-block-start: min(14vh, var(--size-24));\n margin: 0;\n overflow: hidden;\n pointer-events: none;\n background: transparent;\n border: none;\n transition:\n display 200ms allow-discrete,\n overlay 200ms allow-discrete;\n }\n\n dialog:not([open]) {\n display: none;\n }\n\n dialog:not([open]) .panel {\n display: none;\n }\n\n dialog[open] {\n pointer-events: auto;\n }\n\n dialog::backdrop {\n background: var(--_backdrop-bg);\n opacity: 1;\n backdrop-filter: blur(var(--blur-xs));\n transition:\n opacity var(--transition-normal),\n overlay var(--transition-normal) allow-discrete,\n display var(--transition-normal) allow-discrete;\n\n @starting-style {\n opacity: 0;\n }\n }\n\n dialog.closing::backdrop {\n opacity: 0;\n }\n\n /* =====================\n Panel\n ===================== */\n\n .panel {\n position: relative;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n width: var(--_max-width);\n max-width: calc(100vw - var(--size-8));\n max-height: min(28rem, calc(100dvh - var(--size-16)));\n overflow: hidden;\n background: var(--_panel-bg);\n border: var(--border) solid var(--_panel-border-color);\n border-radius: var(--_radius);\n box-shadow: var(--command-palette-shadow, var(--shadow-2xl));\n opacity: 1;\n backdrop-filter: blur(var(--blur-md));\n transform: scale(1) translateY(0);\n transition:\n opacity 200ms var(--ease-spring),\n transform 200ms var(--ease-spring);\n\n @starting-style {\n opacity: 0;\n transform: scale(var(--overlay-enter-scale-dialog)) translateY(-4px);\n }\n }\n\n dialog.closing .panel {\n opacity: 0;\n transform: scale(var(--overlay-enter-scale-dialog)) translateY(-4px);\n transition:\n opacity 150ms var(--ease-spring),\n transform 150ms var(--ease-spring);\n }\n\n @media (width <= 640px) {\n .panel {\n width: calc(100vw - var(--size-4));\n max-width: calc(100vw - var(--size-4));\n }\n\n dialog {\n padding-block-start: var(--size-4);\n }\n\n /* No horizontal room for a side-by-side pane: the preview drops under the\n list with its own capped height, keeping the rows scannable. */\n .body {\n flex-direction: column;\n }\n\n .preview {\n width: auto;\n max-height: 40%;\n border-block-start: var(--border) solid var(--color-contrast-100);\n border-inline-start: 0;\n }\n }\n\n /* =====================\n Search field\n ===================== */\n\n .search {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-2);\n align-items: center;\n padding: var(--size-3) var(--size-4);\n border-block-end: var(--border) solid var(--color-contrast-100);\n }\n\n .search-icon {\n display: inline-flex;\n flex-shrink: 0;\n color: var(--color-contrast-400);\n }\n\n .search-input {\n flex: 1;\n min-width: 0;\n padding: 0;\n font: inherit;\n font-size: var(--text-md);\n color: var(--color-contrast-900);\n outline: none;\n background: transparent;\n border: none;\n }\n\n .search-input::placeholder {\n color: var(--color-contrast-400);\n }\n\n .search-loader {\n display: inline-flex;\n flex-shrink: 0;\n width: 1em;\n height: 1em;\n border: 2px solid var(--color-contrast-300);\n border-inline-end-color: transparent;\n border-radius: 50%;\n animation: command-palette-spin var(--transition-loader) infinite;\n }\n\n .search-loader[hidden] {\n display: none;\n }\n\n @keyframes command-palette-spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n /* =====================\n Listbox\n ===================== */\n\n /* Row holding the listbox and the optional preview pane side by side. The\n preview folds away (hidden attribute) while its slot is empty, so palettes\n that never use it keep the plain single-column panel. */\n .body {\n display: flex;\n flex: 1;\n /* The listbox scrolls inside this row: without min-height the flex item\n grows past the panel instead of honoring max-height. */\n min-height: 0;\n }\n\n .listbox {\n flex: 1;\n min-width: 0;\n padding: var(--size-1);\n overflow-y: auto;\n overscroll-behavior: contain;\n scrollbar-width: thin;\n }\n\n .preview {\n flex-shrink: 0;\n width: var(--_preview-width);\n padding: var(--size-3) var(--size-4);\n overflow-y: auto;\n overscroll-behavior: contain;\n font-size: var(--text-sm);\n color: var(--color-contrast-700);\n scrollbar-width: thin;\n border-inline-start: var(--border) solid var(--color-contrast-100);\n }\n\n .preview[hidden] {\n display: none;\n }\n\n .empty {\n padding: var(--size-6) var(--size-3);\n font-size: var(--text-sm);\n color: var(--color-contrast-400);\n text-align: center;\n }\n\n .group-heading {\n padding: var(--size-2) var(--size-2-5) var(--size-1);\n font-size: var(--text-xs);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-500);\n text-transform: uppercase;\n letter-spacing: var(--tracking-wide, 0.05em);\n }\n\n .item {\n display: flex;\n gap: var(--size-2-5);\n align-items: center;\n padding: var(--size-2) var(--size-2-5);\n font-size: var(--text-sm);\n line-height: var(--leading-normal);\n color: var(--color-contrast-800);\n cursor: pointer;\n border-radius: var(--rounded-md);\n transition: background var(--transition-fast);\n }\n\n .item:hover:not([data-disabled]) {\n background: var(--_option-hover-bg);\n }\n\n .item[data-focused]:not([data-disabled]) {\n background: var(--_option-focus-bg);\n }\n\n .item[data-disabled] {\n color: var(--color-contrast-400);\n cursor: not-allowed;\n opacity: 0.6;\n }\n\n .item-icon {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n color: var(--color-contrast-500);\n }\n\n .item-label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .item-shortcut {\n display: inline-flex;\n flex-shrink: 0;\n gap: var(--size-1);\n }\n\n /* =====================\n Footer hints\n ===================== */\n\n .footer {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-4);\n align-items: center;\n padding: var(--size-2) var(--size-4);\n font-size: var(--text-xs);\n color: var(--color-contrast-500);\n border-block-start: var(--border) solid var(--color-contrast-100);\n }\n\n .footer-hint {\n display: inline-flex;\n gap: var(--size-1);\n align-items: center;\n }\n\n .footer ore-keyboard-key {\n --keyboard-key-font-family: inherit;\n --keyboard-key-padding-inline: var(--size-1);\n }\n\n /* Slotted item elements are pure data nodes: never rendered directly. */\n ::slotted(ore-command-palette-item) {\n display: none;\n }\n}\n"],"mappings":""}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e=`@layer refine.base{:host{--_radius:var(--command-palette-radius,var(--rounded-lg));--_max-width:var(--command-palette-max-width,40rem);--_backdrop-bg:var(--command-palette-backdrop,color-mix(in oklch, var(--color-canvas) 40%, transparent));--_panel-bg:var(--command-palette-bg,var(--color-canvas));--_panel-border-color:var(--command-palette-border-color,var(--color-divider));--_option-hover-bg:var(--command-palette-option-hover-bg,var(--color-contrast-100));--_option-focus-bg:var(--command-palette-option-focus-bg,color-mix(in oklch, var(--color-primary) 12%, var(--color-contrast-100)));display:contents}dialog{all:unset;box-sizing:border-box;pointer-events:none;width:100%;max-width:100%;height:100%;max-height:100%;transition:display .2s allow-discrete, overlay .2s allow-discrete;padding-top:min(14vh, var(--size-24));background:0 0;border:none;justify-content:center;align-items:flex-start;margin:0;display:flex;position:fixed;inset:0;overflow:hidden}dialog:not([open]),dialog:not([open]) .panel{display:none}dialog[open]{pointer-events:auto}dialog::-ms-backdrop{background:var(--_backdrop-bg);opacity:1;-webkit-backdrop-filter:blur(var(--blur-xs));backdrop-filter:blur(var(--blur-xs));transition:opacity var(--transition-normal), overlay var(--transition-normal) allow-discrete, display var(--transition-normal) allow-discrete}@starting-style{dialog::-ms-backdrop{opacity:0}}dialog::backdrop{background:var(--_backdrop-bg);opacity:1;-webkit-backdrop-filter:blur(var(--blur-xs));backdrop-filter:blur(var(--blur-xs));transition:opacity var(--transition-normal), overlay var(--transition-normal) allow-discrete, display var(--transition-normal) allow-discrete}@starting-style{dialog::backdrop{opacity:0}}dialog.closing::-ms-backdrop{opacity:0}dialog.closing::backdrop{opacity:0}.panel{box-sizing:border-box;width:var(--_max-width);max-width:calc(100vw - var(--size-8));max-height:min(28rem, calc(100dvh - var(--size-16)));background:var(--_panel-bg);border:var(--border) solid var(--_panel-border-color);border-radius:var(--_radius);box-shadow:var(--command-palette-shadow,var(--shadow-2xl));opacity:1;-webkit-backdrop-filter:blur(var(--blur-md));backdrop-filter:blur(var(--blur-md));transition:opacity .2s var(--ease-spring), transform .2s var(--ease-spring);flex-direction:column;display:flex;position:relative;overflow:hidden;transform:scale(1)translateY(0)}@starting-style{.panel{opacity:0;transform:scale(var(--overlay-enter-scale-dialog)) translateY(-4px)}}dialog.closing .panel{opacity:0;transform:scale(var(--overlay-enter-scale-dialog)) translateY(-4px);transition:opacity .15s var(--ease-spring), transform .15s var(--ease-spring)}@media (width<=640px){.panel{width:calc(100vw - var(--size-4));max-width:calc(100vw - var(--size-4))}dialog{padding-top:var(--size-4)}}.search{gap:var(--size-2);padding:var(--size-3) var(--size-4);border-bottom:var(--border) solid var(--color-contrast-100);flex-shrink:0;align-items:center;display:flex}.search-icon{color:var(--color-contrast-400);flex-shrink:0;display:inline-flex}.search-input{min-width:0;font:inherit;font-size:var(--text-md);color:var(--color-contrast-900);background:0 0;border:none;outline:none;flex:1;padding:0}.search-input::placeholder{color:var(--color-contrast-400)}.search-loader{border:2px solid var(--color-contrast-300);width:1em;height:1em;animation:command-palette-spin var(--transition-loader) infinite;border-radius:50%;flex-shrink:0;display:inline-flex}.search-loader:not(:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))){border-right-color:#0000}.search-loader:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)){border-left-color:#0000}.search-loader[hidden]{display:none}@keyframes command-palette-spin{to{transform:rotate(360deg)}}.listbox{padding:var(--size-1);overscroll-behavior:contain;scrollbar-width:thin;flex:1;overflow-y:auto}.empty{padding:var(--size-6) var(--size-3);font-size:var(--text-sm);color:var(--color-contrast-400);text-align:center}.group-heading{padding:var(--size-2) var(--size-2-5) var(--size-1);font-size:var(--text-xs);font-weight:var(--font-semibold);color:var(--color-contrast-500);text-transform:uppercase;letter-spacing:var(--tracking-wide,.05em)}.item{gap:var(--size-2-5);padding:var(--size-2) var(--size-2-5);font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--color-contrast-800);cursor:pointer;border-radius:var(--rounded-md);transition:background var(--transition-fast);align-items:center;display:flex}.item:hover:not([data-disabled]){background:var(--_option-hover-bg)}.item[data-focused]:not([data-disabled]){background:var(--_option-focus-bg)}.item[data-disabled]{color:var(--color-contrast-400);cursor:not-allowed;opacity:.6}.item-icon{color:var(--color-contrast-500);flex-shrink:0;align-items:center;display:inline-flex}.item-label{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.item-shortcut{gap:var(--size-1);flex-shrink:0;display:inline-flex}.footer{gap:var(--size-4);padding:var(--size-2) var(--size-4);font-size:var(--text-xs);color:var(--color-contrast-500);border-top:var(--border) solid var(--color-contrast-100);flex-shrink:0;align-items:center;display:flex}.footer-hint{gap:var(--size-1);align-items:center;display:inline-flex}.footer ore-keyboard-key{--keyboard-key-font-family:inherit;--keyboard-key-padding-inline:var(--size-1)}::slotted(ore-command-palette-item){display:none}}`;export{e as default};
|
|
1
|
+
var e=`@layer refine.base{:host{--_radius:var(--command-palette-radius,var(--rounded-lg));--_max-width:var(--command-palette-max-width,40rem);--_preview-width:var(--command-palette-preview-width,18rem);--_backdrop-bg:var(--command-palette-backdrop,color-mix(in oklch, var(--color-canvas) 40%, transparent));--_panel-bg:var(--command-palette-bg,var(--color-canvas));--_panel-border-color:var(--command-palette-border-color,var(--color-divider));--_option-hover-bg:var(--command-palette-option-hover-bg,var(--color-contrast-100));--_option-focus-bg:var(--command-palette-option-focus-bg,color-mix(in oklch, var(--color-primary) 12%, var(--color-contrast-100)));display:contents}dialog{all:unset;box-sizing:border-box;pointer-events:none;width:100%;max-width:100%;height:100%;max-height:100%;transition:display .2s allow-discrete, overlay .2s allow-discrete;padding-top:min(14vh, var(--size-24));background:0 0;border:none;justify-content:center;align-items:flex-start;margin:0;display:flex;position:fixed;inset:0;overflow:hidden}dialog:not([open]),dialog:not([open]) .panel{display:none}dialog[open]{pointer-events:auto}dialog::-ms-backdrop{background:var(--_backdrop-bg);opacity:1;-webkit-backdrop-filter:blur(var(--blur-xs));backdrop-filter:blur(var(--blur-xs));transition:opacity var(--transition-normal), overlay var(--transition-normal) allow-discrete, display var(--transition-normal) allow-discrete}@starting-style{dialog::-ms-backdrop{opacity:0}}dialog::backdrop{background:var(--_backdrop-bg);opacity:1;-webkit-backdrop-filter:blur(var(--blur-xs));backdrop-filter:blur(var(--blur-xs));transition:opacity var(--transition-normal), overlay var(--transition-normal) allow-discrete, display var(--transition-normal) allow-discrete}@starting-style{dialog::backdrop{opacity:0}}dialog.closing::-ms-backdrop{opacity:0}dialog.closing::backdrop{opacity:0}.panel{box-sizing:border-box;width:var(--_max-width);max-width:calc(100vw - var(--size-8));max-height:min(28rem, calc(100dvh - var(--size-16)));background:var(--_panel-bg);border:var(--border) solid var(--_panel-border-color);border-radius:var(--_radius);box-shadow:var(--command-palette-shadow,var(--shadow-2xl));opacity:1;-webkit-backdrop-filter:blur(var(--blur-md));backdrop-filter:blur(var(--blur-md));transition:opacity .2s var(--ease-spring), transform .2s var(--ease-spring);flex-direction:column;display:flex;position:relative;overflow:hidden;transform:scale(1)translateY(0)}@starting-style{.panel{opacity:0;transform:scale(var(--overlay-enter-scale-dialog)) translateY(-4px)}}dialog.closing .panel{opacity:0;transform:scale(var(--overlay-enter-scale-dialog)) translateY(-4px);transition:opacity .15s var(--ease-spring), transform .15s var(--ease-spring)}@media (width<=640px){.panel{width:calc(100vw - var(--size-4));max-width:calc(100vw - var(--size-4))}dialog{padding-top:var(--size-4)}.body{flex-direction:column}.preview{border-top:var(--border) solid var(--color-contrast-100);width:auto;max-height:40%}.preview:not(:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))){border-left:0}.preview:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)){border-right:0}}.search{gap:var(--size-2);padding:var(--size-3) var(--size-4);border-bottom:var(--border) solid var(--color-contrast-100);flex-shrink:0;align-items:center;display:flex}.search-icon{color:var(--color-contrast-400);flex-shrink:0;display:inline-flex}.search-input{min-width:0;font:inherit;font-size:var(--text-md);color:var(--color-contrast-900);background:0 0;border:none;outline:none;flex:1;padding:0}.search-input::placeholder{color:var(--color-contrast-400)}.search-loader{border:2px solid var(--color-contrast-300);width:1em;height:1em;animation:command-palette-spin var(--transition-loader) infinite;border-radius:50%;flex-shrink:0;display:inline-flex}.search-loader:not(:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))){border-right-color:#0000}.search-loader:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)){border-left-color:#0000}.search-loader[hidden]{display:none}@keyframes command-palette-spin{to{transform:rotate(360deg)}}.body{flex:1;min-height:0;display:flex}.listbox{min-width:0;padding:var(--size-1);overscroll-behavior:contain;scrollbar-width:thin;flex:1;overflow-y:auto}.preview{width:var(--_preview-width);padding:var(--size-3) var(--size-4);overscroll-behavior:contain;font-size:var(--text-sm);color:var(--color-contrast-700);scrollbar-width:thin;flex-shrink:0;overflow-y:auto}.preview:not(:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))){border-left:var(--border) solid var(--color-contrast-100)}.preview:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)){border-right:var(--border) solid var(--color-contrast-100)}.preview[hidden]{display:none}.empty{padding:var(--size-6) var(--size-3);font-size:var(--text-sm);color:var(--color-contrast-400);text-align:center}.group-heading{padding:var(--size-2) var(--size-2-5) var(--size-1);font-size:var(--text-xs);font-weight:var(--font-semibold);color:var(--color-contrast-500);text-transform:uppercase;letter-spacing:var(--tracking-wide,.05em)}.item{gap:var(--size-2-5);padding:var(--size-2) var(--size-2-5);font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--color-contrast-800);cursor:pointer;border-radius:var(--rounded-md);transition:background var(--transition-fast);align-items:center;display:flex}.item:hover:not([data-disabled]){background:var(--_option-hover-bg)}.item[data-focused]:not([data-disabled]){background:var(--_option-focus-bg)}.item[data-disabled]{color:var(--color-contrast-400);cursor:not-allowed;opacity:.6}.item-icon{color:var(--color-contrast-500);flex-shrink:0;align-items:center;display:inline-flex}.item-label{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.item-shortcut{gap:var(--size-1);flex-shrink:0;display:inline-flex}.footer{gap:var(--size-4);padding:var(--size-2) var(--size-4);font-size:var(--text-xs);color:var(--color-contrast-500);border-top:var(--border) solid var(--color-contrast-100);flex-shrink:0;align-items:center;display:flex}.footer-hint{gap:var(--size-1);align-items:center;display:inline-flex}.footer ore-keyboard-key{--keyboard-key-font-family:inherit;--keyboard-key-padding-inline:var(--size-1)}::slotted(ore-command-palette-item){display:none}}`;export{e as default};
|
|
2
2
|
//# sourceMappingURL=command-palette.css.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-palette.css.js","names":[],"sources":["../../../src/overlay/command-palette/command-palette.css?inline"],"sourcesContent":["@layer refine.base {\n :host {\n --_radius: var(--command-palette-radius, var(--rounded-lg));\n --_max-width: var(--command-palette-max-width, 40rem);\n --_backdrop-bg: var(--command-palette-backdrop, color-mix(in oklch, var(--color-canvas) 40%, transparent));\n --_panel-bg: var(--command-palette-bg, var(--color-canvas));\n --_panel-border-color: var(--command-palette-border-color, var(--color-divider));\n --_option-hover-bg: var(--command-palette-option-hover-bg, var(--color-contrast-100));\n --_option-focus-bg: var(\n --command-palette-option-focus-bg,\n color-mix(in oklch, var(--color-primary) 12%, var(--color-contrast-100))\n );\n\n display: contents;\n }\n\n /* =====================\n Native <dialog> resets: see ore-dialog for the full rationale.\n ===================== */\n\n dialog {\n all: unset;\n position: fixed;\n inset: 0;\n box-sizing: border-box;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n width: 100%;\n max-width: 100%;\n height: 100%;\n max-height: 100%;\n padding-block-start: min(14vh, var(--size-24));\n margin: 0;\n overflow: hidden;\n pointer-events: none;\n background: transparent;\n border: none;\n transition:\n display 200ms allow-discrete,\n overlay 200ms allow-discrete;\n }\n\n dialog:not([open]) {\n display: none;\n }\n\n dialog:not([open]) .panel {\n display: none;\n }\n\n dialog[open] {\n pointer-events: auto;\n }\n\n dialog::backdrop {\n background: var(--_backdrop-bg);\n opacity: 1;\n backdrop-filter: blur(var(--blur-xs));\n transition:\n opacity var(--transition-normal),\n overlay var(--transition-normal) allow-discrete,\n display var(--transition-normal) allow-discrete;\n\n @starting-style {\n opacity: 0;\n }\n }\n\n dialog.closing::backdrop {\n opacity: 0;\n }\n\n /* =====================\n Panel\n ===================== */\n\n .panel {\n position: relative;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n width: var(--_max-width);\n max-width: calc(100vw - var(--size-8));\n max-height: min(28rem, calc(100dvh - var(--size-16)));\n overflow: hidden;\n background: var(--_panel-bg);\n border: var(--border) solid var(--_panel-border-color);\n border-radius: var(--_radius);\n box-shadow: var(--command-palette-shadow, var(--shadow-2xl));\n opacity: 1;\n backdrop-filter: blur(var(--blur-md));\n transform: scale(1) translateY(0);\n transition:\n opacity 200ms var(--ease-spring),\n transform 200ms var(--ease-spring);\n\n @starting-style {\n opacity: 0;\n transform: scale(var(--overlay-enter-scale-dialog)) translateY(-4px);\n }\n }\n\n dialog.closing .panel {\n opacity: 0;\n transform: scale(var(--overlay-enter-scale-dialog)) translateY(-4px);\n transition:\n opacity 150ms var(--ease-spring),\n transform 150ms var(--ease-spring);\n }\n\n @media (width <= 640px) {\n .panel {\n width: calc(100vw - var(--size-4));\n max-width: calc(100vw - var(--size-4));\n }\n\n dialog {\n padding-block-start: var(--size-4);\n }\n }\n\n /* =====================\n Search field\n ===================== */\n\n .search {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-2);\n align-items: center;\n padding: var(--size-3) var(--size-4);\n border-block-end: var(--border) solid var(--color-contrast-100);\n }\n\n .search-icon {\n display: inline-flex;\n flex-shrink: 0;\n color: var(--color-contrast-400);\n }\n\n .search-input {\n flex: 1;\n min-width: 0;\n padding: 0;\n font: inherit;\n font-size: var(--text-md);\n color: var(--color-contrast-900);\n outline: none;\n background: transparent;\n border: none;\n }\n\n .search-input::placeholder {\n color: var(--color-contrast-400);\n }\n\n .search-loader {\n display: inline-flex;\n flex-shrink: 0;\n width: 1em;\n height: 1em;\n border: 2px solid var(--color-contrast-300);\n border-inline-end-color: transparent;\n border-radius: 50%;\n animation: command-palette-spin var(--transition-loader) infinite;\n }\n\n .search-loader[hidden] {\n display: none;\n }\n\n @keyframes command-palette-spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n /* =====================\n Listbox\n ===================== */\n\n .listbox {\n flex: 1;\n padding: var(--size-1);\n overflow-y: auto;\n overscroll-behavior: contain;\n scrollbar-width: thin;\n }\n\n .empty {\n padding: var(--size-6) var(--size-3);\n font-size: var(--text-sm);\n color: var(--color-contrast-400);\n text-align: center;\n }\n\n .group-heading {\n padding: var(--size-2) var(--size-2-5) var(--size-1);\n font-size: var(--text-xs);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-500);\n text-transform: uppercase;\n letter-spacing: var(--tracking-wide, 0.05em);\n }\n\n .item {\n display: flex;\n gap: var(--size-2-5);\n align-items: center;\n padding: var(--size-2) var(--size-2-5);\n font-size: var(--text-sm);\n line-height: var(--leading-normal);\n color: var(--color-contrast-800);\n cursor: pointer;\n border-radius: var(--rounded-md);\n transition: background var(--transition-fast);\n }\n\n .item:hover:not([data-disabled]) {\n background: var(--_option-hover-bg);\n }\n\n .item[data-focused]:not([data-disabled]) {\n background: var(--_option-focus-bg);\n }\n\n .item[data-disabled] {\n color: var(--color-contrast-400);\n cursor: not-allowed;\n opacity: 0.6;\n }\n\n .item-icon {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n color: var(--color-contrast-500);\n }\n\n .item-label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .item-shortcut {\n display: inline-flex;\n flex-shrink: 0;\n gap: var(--size-1);\n }\n\n /* =====================\n Footer hints\n ===================== */\n\n .footer {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-4);\n align-items: center;\n padding: var(--size-2) var(--size-4);\n font-size: var(--text-xs);\n color: var(--color-contrast-500);\n border-block-start: var(--border) solid var(--color-contrast-100);\n }\n\n .footer-hint {\n display: inline-flex;\n gap: var(--size-1);\n align-items: center;\n }\n\n .footer ore-keyboard-key {\n --keyboard-key-font-family: inherit;\n --keyboard-key-padding-inline: var(--size-1);\n }\n\n /* Slotted item elements are pure data nodes: never rendered directly. */\n ::slotted(ore-command-palette-item) {\n display: none;\n }\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"command-palette.css.js","names":[],"sources":["../../../src/overlay/command-palette/command-palette.css?inline"],"sourcesContent":["@layer refine.base {\n :host {\n --_radius: var(--command-palette-radius, var(--rounded-lg));\n --_max-width: var(--command-palette-max-width, 40rem);\n --_preview-width: var(--command-palette-preview-width, 18rem);\n --_backdrop-bg: var(--command-palette-backdrop, color-mix(in oklch, var(--color-canvas) 40%, transparent));\n --_panel-bg: var(--command-palette-bg, var(--color-canvas));\n --_panel-border-color: var(--command-palette-border-color, var(--color-divider));\n --_option-hover-bg: var(--command-palette-option-hover-bg, var(--color-contrast-100));\n --_option-focus-bg: var(\n --command-palette-option-focus-bg,\n color-mix(in oklch, var(--color-primary) 12%, var(--color-contrast-100))\n );\n\n display: contents;\n }\n\n /* =====================\n Native <dialog> resets: see ore-dialog for the full rationale.\n ===================== */\n\n dialog {\n all: unset;\n position: fixed;\n inset: 0;\n box-sizing: border-box;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n width: 100%;\n max-width: 100%;\n height: 100%;\n max-height: 100%;\n padding-block-start: min(14vh, var(--size-24));\n margin: 0;\n overflow: hidden;\n pointer-events: none;\n background: transparent;\n border: none;\n transition:\n display 200ms allow-discrete,\n overlay 200ms allow-discrete;\n }\n\n dialog:not([open]) {\n display: none;\n }\n\n dialog:not([open]) .panel {\n display: none;\n }\n\n dialog[open] {\n pointer-events: auto;\n }\n\n dialog::backdrop {\n background: var(--_backdrop-bg);\n opacity: 1;\n backdrop-filter: blur(var(--blur-xs));\n transition:\n opacity var(--transition-normal),\n overlay var(--transition-normal) allow-discrete,\n display var(--transition-normal) allow-discrete;\n\n @starting-style {\n opacity: 0;\n }\n }\n\n dialog.closing::backdrop {\n opacity: 0;\n }\n\n /* =====================\n Panel\n ===================== */\n\n .panel {\n position: relative;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n width: var(--_max-width);\n max-width: calc(100vw - var(--size-8));\n max-height: min(28rem, calc(100dvh - var(--size-16)));\n overflow: hidden;\n background: var(--_panel-bg);\n border: var(--border) solid var(--_panel-border-color);\n border-radius: var(--_radius);\n box-shadow: var(--command-palette-shadow, var(--shadow-2xl));\n opacity: 1;\n backdrop-filter: blur(var(--blur-md));\n transform: scale(1) translateY(0);\n transition:\n opacity 200ms var(--ease-spring),\n transform 200ms var(--ease-spring);\n\n @starting-style {\n opacity: 0;\n transform: scale(var(--overlay-enter-scale-dialog)) translateY(-4px);\n }\n }\n\n dialog.closing .panel {\n opacity: 0;\n transform: scale(var(--overlay-enter-scale-dialog)) translateY(-4px);\n transition:\n opacity 150ms var(--ease-spring),\n transform 150ms var(--ease-spring);\n }\n\n @media (width <= 640px) {\n .panel {\n width: calc(100vw - var(--size-4));\n max-width: calc(100vw - var(--size-4));\n }\n\n dialog {\n padding-block-start: var(--size-4);\n }\n\n /* No horizontal room for a side-by-side pane: the preview drops under the\n list with its own capped height, keeping the rows scannable. */\n .body {\n flex-direction: column;\n }\n\n .preview {\n width: auto;\n max-height: 40%;\n border-block-start: var(--border) solid var(--color-contrast-100);\n border-inline-start: 0;\n }\n }\n\n /* =====================\n Search field\n ===================== */\n\n .search {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-2);\n align-items: center;\n padding: var(--size-3) var(--size-4);\n border-block-end: var(--border) solid var(--color-contrast-100);\n }\n\n .search-icon {\n display: inline-flex;\n flex-shrink: 0;\n color: var(--color-contrast-400);\n }\n\n .search-input {\n flex: 1;\n min-width: 0;\n padding: 0;\n font: inherit;\n font-size: var(--text-md);\n color: var(--color-contrast-900);\n outline: none;\n background: transparent;\n border: none;\n }\n\n .search-input::placeholder {\n color: var(--color-contrast-400);\n }\n\n .search-loader {\n display: inline-flex;\n flex-shrink: 0;\n width: 1em;\n height: 1em;\n border: 2px solid var(--color-contrast-300);\n border-inline-end-color: transparent;\n border-radius: 50%;\n animation: command-palette-spin var(--transition-loader) infinite;\n }\n\n .search-loader[hidden] {\n display: none;\n }\n\n @keyframes command-palette-spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n /* =====================\n Listbox\n ===================== */\n\n /* Row holding the listbox and the optional preview pane side by side. The\n preview folds away (hidden attribute) while its slot is empty, so palettes\n that never use it keep the plain single-column panel. */\n .body {\n display: flex;\n flex: 1;\n /* The listbox scrolls inside this row: without min-height the flex item\n grows past the panel instead of honoring max-height. */\n min-height: 0;\n }\n\n .listbox {\n flex: 1;\n min-width: 0;\n padding: var(--size-1);\n overflow-y: auto;\n overscroll-behavior: contain;\n scrollbar-width: thin;\n }\n\n .preview {\n flex-shrink: 0;\n width: var(--_preview-width);\n padding: var(--size-3) var(--size-4);\n overflow-y: auto;\n overscroll-behavior: contain;\n font-size: var(--text-sm);\n color: var(--color-contrast-700);\n scrollbar-width: thin;\n border-inline-start: var(--border) solid var(--color-contrast-100);\n }\n\n .preview[hidden] {\n display: none;\n }\n\n .empty {\n padding: var(--size-6) var(--size-3);\n font-size: var(--text-sm);\n color: var(--color-contrast-400);\n text-align: center;\n }\n\n .group-heading {\n padding: var(--size-2) var(--size-2-5) var(--size-1);\n font-size: var(--text-xs);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-500);\n text-transform: uppercase;\n letter-spacing: var(--tracking-wide, 0.05em);\n }\n\n .item {\n display: flex;\n gap: var(--size-2-5);\n align-items: center;\n padding: var(--size-2) var(--size-2-5);\n font-size: var(--text-sm);\n line-height: var(--leading-normal);\n color: var(--color-contrast-800);\n cursor: pointer;\n border-radius: var(--rounded-md);\n transition: background var(--transition-fast);\n }\n\n .item:hover:not([data-disabled]) {\n background: var(--_option-hover-bg);\n }\n\n .item[data-focused]:not([data-disabled]) {\n background: var(--_option-focus-bg);\n }\n\n .item[data-disabled] {\n color: var(--color-contrast-400);\n cursor: not-allowed;\n opacity: 0.6;\n }\n\n .item-icon {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n color: var(--color-contrast-500);\n }\n\n .item-label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .item-shortcut {\n display: inline-flex;\n flex-shrink: 0;\n gap: var(--size-1);\n }\n\n /* =====================\n Footer hints\n ===================== */\n\n .footer {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-4);\n align-items: center;\n padding: var(--size-2) var(--size-4);\n font-size: var(--text-xs);\n color: var(--color-contrast-500);\n border-block-start: var(--border) solid var(--color-contrast-100);\n }\n\n .footer-hint {\n display: inline-flex;\n gap: var(--size-1);\n align-items: center;\n }\n\n .footer ore-keyboard-key {\n --keyboard-key-font-family: inherit;\n --keyboard-key-padding-inline: var(--size-1);\n }\n\n /* Slotted item elements are pure data nodes: never rendered directly. */\n ::slotted(ore-command-palette-item) {\n display: none;\n }\n}\n"],"mappings":""}
|
|
@@ -40,11 +40,13 @@ export declare const COMMAND_PALETTE_ITEM_TAG: "ore-command-palette-item";
|
|
|
40
40
|
* @attr {string} empty-text - Message shown when no item matches the query
|
|
41
41
|
* @attr {boolean} keep-open-on-select - Keep the palette open after an item is selected
|
|
42
42
|
*
|
|
43
|
+
* @fires active-change - Fired when the focused row changes (keyboard, hover, typing, open, close). detail: `{ value, label, item }`; `item` is `undefined` and `value` empty when no row is active
|
|
43
44
|
* @fires open-change - Fired when the palette state changes. detail: `{ open, reason }`
|
|
44
45
|
* @fires search - Fired on every keystroke in the search input. detail: `{ query }`
|
|
45
46
|
* @fires select - Fired when a command is chosen (click or `Enter`). detail: `{ value, label, item }`
|
|
46
47
|
*
|
|
47
48
|
* @slot - `<ore-command-palette-item>` elements (alternative/supplement to the `items` prop)
|
|
49
|
+
* @slot preview - Optional detail panel rendered beside the list, shown while it has content. Pair it with `active-change` to preview the focused row
|
|
48
50
|
*
|
|
49
51
|
* @cssprop --command-palette-bg - Panel background color
|
|
50
52
|
* @cssprop --command-palette-border-color - Panel border color
|
|
@@ -54,11 +56,13 @@ export declare const COMMAND_PALETTE_ITEM_TAG: "ore-command-palette-item";
|
|
|
54
56
|
* @cssprop --command-palette-backdrop - Backdrop overlay color
|
|
55
57
|
* @cssprop --command-palette-option-hover-bg - Item background on hover
|
|
56
58
|
* @cssprop --command-palette-option-focus-bg - Item background when keyboard-focused
|
|
59
|
+
* @cssprop --command-palette-preview-width - Preview panel width when the `preview` slot has content
|
|
57
60
|
*
|
|
58
61
|
* @part dialog - Dialog root container
|
|
59
62
|
* @part panel - Panel container
|
|
60
63
|
* @part input - Search input
|
|
61
64
|
* @part listbox - Listbox of matching commands
|
|
65
|
+
* @part preview - Preview panel shown beside the list
|
|
62
66
|
*
|
|
63
67
|
* @example
|
|
64
68
|
* ```html
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-palette.d.ts","sourceRoot":"","sources":["../../../src/overlay/command-palette/command-palette.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AAChF,YAAY,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAE/F;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,wBAAwB,EAAG,0BAAmC,CAAC;AAO5E
|
|
1
|
+
{"version":3,"file":"command-palette.d.ts","sourceRoot":"","sources":["../../../src/overlay/command-palette/command-palette.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AAChF,YAAY,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAE/F;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,wBAAwB,EAAG,0BAAmC,CAAC;AAO5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,eAAO,MAAM,mBAAmB,EAAG,qBAA8B,CAAC"}
|
|
@@ -30,7 +30,17 @@ export type CommandPaletteSelectDetail = {
|
|
|
30
30
|
label: string;
|
|
31
31
|
value: string;
|
|
32
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* The row the palette currently points at. `item` is `undefined` when the list is empty or the
|
|
35
|
+
* palette has no focus, which is also when a `preview` slot should be emptied by its owner.
|
|
36
|
+
*/
|
|
37
|
+
export type CommandPaletteActiveChangeDetail = {
|
|
38
|
+
item?: CommandPaletteItem;
|
|
39
|
+
label: string;
|
|
40
|
+
value: string;
|
|
41
|
+
};
|
|
33
42
|
export type OreCommandPaletteEvents = {
|
|
43
|
+
'active-change': CommandPaletteActiveChangeDetail;
|
|
34
44
|
'open-change': OverlayOpenChangeDetail;
|
|
35
45
|
search: {
|
|
36
46
|
query: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-palette.types.d.ts","sourceRoot":"","sources":["../../../src/overlay/command-palette/command-palette.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8FAA8F;IAC9F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,aAAa,EAAE,uBAAuB,CAAC;IACvC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1B,MAAM,EAAE,0BAA0B,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,mEAAmE;IACnE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kGAAkG;IAClG,KAAK,CAAC,EAAE,uBAAuB,EAAE,CAAC;IAClC,kFAAkF;IAClF,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,iGAAiG;IACjG,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kGAAkG;IAClG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iGAAiG;IACjG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC"}
|
|
1
|
+
{"version":3,"file":"command-palette.types.d.ts","sourceRoot":"","sources":["../../../src/overlay/command-palette/command-palette.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8FAA8F;IAC9F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,gCAAgC,GAAG;IAC7C,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,eAAe,EAAE,gCAAgC,CAAC;IAClD,aAAa,EAAE,uBAAuB,CAAC;IACvC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1B,MAAM,EAAE,0BAA0B,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,mEAAmE;IACnE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kGAAkG;IAClG,KAAK,CAAC,EAAE,uBAAuB,EAAE,CAAC;IAClC,kFAAkF;IAClF,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,iGAAiG;IACjG,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kGAAkG;IAClG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iGAAiG;IACjG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC"}
|