@ixfx/components 0.7.4 → 0.7.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/bundle/index.d.ts +536 -178
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +1324 -442
- package/bundle/index.js.map +1 -1
- package/dist/ac-token.js +1 -1
- package/dist/crumbs.d.ts +5 -1
- package/dist/crumbs.d.ts.map +1 -1
- package/dist/crumbs.js +10 -0
- package/dist/crumbs.js.map +1 -1
- package/dist/{data-grid-BddUjAti.d.ts → data-grid-CtJ35v8L.d.ts} +26 -1
- package/dist/data-grid-CtJ35v8L.d.ts.map +1 -0
- package/dist/data-grid.d.ts +1 -1
- package/dist/data-grid.js +88 -7
- package/dist/data-grid.js.map +1 -1
- package/dist/{detail-list-Br0WAnry.d.ts → detail-list-BS5dRDda.d.ts} +20 -12
- package/dist/detail-list-BS5dRDda.d.ts.map +1 -0
- package/dist/detail-list.d.ts +2 -2
- package/dist/detail-list.js +51 -135
- package/dist/detail-list.js.map +1 -1
- package/dist/{grid-list-B_orPsot.d.ts → grid-list-D-GbghSH.d.ts} +18 -1
- package/dist/grid-list-D-GbghSH.d.ts.map +1 -0
- package/dist/grid-list.d.ts +1 -1
- package/dist/grid-list.js +76 -15
- package/dist/grid-list.js.map +1 -1
- package/dist/incr-search-DpbSJtgj.js +962 -0
- package/dist/incr-search-DpbSJtgj.js.map +1 -0
- package/dist/incr-search.d.ts +2 -2
- package/dist/incr-search.js +2 -3
- package/dist/index-CBS4z1v-.d.ts +365 -0
- package/dist/index-CBS4z1v-.d.ts.map +1 -0
- package/dist/index.d.ts +8 -8
- package/dist/index.js +4 -5
- package/dist/index.js.map +1 -1
- package/dist/{list-selection-controller-CUo-Hhcm.js → list-selection-controller-DTFI40li.js} +2 -76
- package/dist/list-selection-controller-DTFI40li.js.map +1 -0
- package/dist/miller.d.ts +81 -3
- package/dist/miller.d.ts.map +1 -1
- package/dist/miller.js +327 -68
- package/dist/miller.js.map +1 -1
- package/dist/narrowed-text.js +1 -2
- package/dist/narrowed-text.js.map +1 -1
- package/dist/{tree-B74zdI60.js → tree-DAii2A1g.js} +77 -15
- package/dist/tree-DAii2A1g.js.map +1 -0
- package/dist/{tree-component-BvV4muxx.d.ts → tree-component-F6qZ0Gdv.d.ts} +9 -1
- package/dist/{tree-component-BvV4muxx.d.ts.map → tree-component-F6qZ0Gdv.d.ts.map} +1 -1
- package/dist/tree.d.ts +22 -1
- package/dist/tree.d.ts.map +1 -1
- package/dist/tree.js +1 -1
- package/dist/{vertical-list-CQSEVeOT.d.ts → vertical-list-DwtCPy1b.d.ts} +17 -14
- package/dist/vertical-list-DwtCPy1b.d.ts.map +1 -0
- package/dist/vertical-list.d.ts +1 -1
- package/dist/vertical-list.js +59 -127
- package/dist/vertical-list.js.map +1 -1
- package/docs-user/data-grid.md +19 -0
- package/docs-user/detail-list.md +1 -1
- package/docs-user/grid-list.md +24 -0
- package/docs-user/incr-search.md +12 -2
- package/docs-user/index.json +2 -2
- package/docs-user/tree.md +22 -1
- package/docs-user/vertical-list.md +7 -1
- package/package.json +1 -1
- package/dist/data-grid-BddUjAti.d.ts.map +0 -1
- package/dist/detail-list-Br0WAnry.d.ts.map +0 -1
- package/dist/element-search-Y8SRfPGM.js +0 -185
- package/dist/element-search-Y8SRfPGM.js.map +0 -1
- package/dist/grid-list-B_orPsot.d.ts.map +0 -1
- package/dist/incr-search-vCzuao-2.js +0 -137
- package/dist/incr-search-vCzuao-2.js.map +0 -1
- package/dist/index-Cu5i8zZY.d.ts +0 -160
- package/dist/index-Cu5i8zZY.d.ts.map +0 -1
- package/dist/list-selection-controller-CUo-Hhcm.js.map +0 -1
- package/dist/tree-B74zdI60.js.map +0 -1
- package/dist/vertical-list-CQSEVeOT.d.ts.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incr-search-DpbSJtgj.js","names":["FzfAny","DEFAULT_HIGHLIGHT_KEY","#el","#opts","#search","#labelMap","#onInput","#onKeydown","#unsub","#onStateChange","#root","#selector","#map","#observer","#dirty","#rebuild","#host","#adapter","#modes","#mode","#placeholder","#search","#unsub","#onState","#open","#query","#matches","#matchIndex","#observer","#teardownEffects","#focusInput","#filterActive","#applyMode","#currentItems","#cycle","#itemFor","#itemByKey","#onInput","#onKeydown","#highlightKey","#applyHighlights"],"sources":["../src/incr-search/fuzzy.ts","../src/incr-search/ac-adapter.ts","../src/incr-search/incr-search.ts","../src/incr-search/controller-tree.ts","../src/interaction/keyed-list.ts","../src/incr-search/element-list-search-adapter.ts","../src/incr-search/element-search.ts","../src/incr-search/list-search-commands.ts","../src/incr-search/list-search-controller.ts","../src/incr-search/list-search-styles.ts","../src/incr-search/tree-list-search-adapter.ts"],"sourcesContent":["import type { FuzzySearch, FuzzySearchOptions, IncrSearchResult } from './types.js';\nimport { Fzf } from 'fzf';\n\nfunction defaultSelector<T>(item: T): string {\n if (typeof item === `string`)\n return item;\n const r = item as Record<string, unknown>;\n if (typeof r.label === `string`)\n return r.label;\n if (typeof r.key === `string`)\n return r.key;\n if (typeof r.value === `string`)\n return r.value;\n return String(item);\n}\n\nexport function createFuzzySearch<T>(\n items: readonly T[],\n options: FuzzySearchOptions<T> = {},\n): FuzzySearch<T> {\n const selector = options.selector ?? defaultSelector<T>;\n // fzf uses a conditional SyncOptionsTuple<T> rest-parameter overload that TypeScript\n // cannot narrow through a spread when T is generic.\n const FzfAny = Fzf as new (list: readonly T[], opts: any) => { find: (q: string) => Array<{ item: T; positions: ReadonlySet<number>; score: number }> };\n const fzf = new FzfAny(items as readonly T[], { selector, ...(options.fzf ?? {}) });\n\n const find = (query: string): ReadonlyArray<IncrSearchResult<T>> => {\n if (!query.trim()) {\n return items.map(item => ({\n item,\n positions: new Set<number>(),\n score: 0,\n }));\n }\n return fzf.find(query).map(r => ({\n item: r.item,\n positions: r.positions,\n score: r.score,\n }));\n };\n\n return { find, items };\n}\n","import type { FuzzySearchOptions } from './types.js';\nimport { createFuzzySearch } from './fuzzy.js';\n\n/**\n * Creates an ixfx-ac-text-compatible `completionProvider` function from a\n * static item list. Uses synchronous fuzzy search wrapped in a Promise so it\n * fits the async provider signature.\n *\n * Each returned item has `positions` populated with matched character indices,\n * which `ixfx-ac-text` uses to render CSS Custom Highlights on the label.\n *\n * Empty query returns all items in original order (no positions).\n * A cancelled signal causes the returned promise to reject with an AbortError.\n */\nexport function createAcCompletionProvider<T extends { label: string }>(\n items: readonly T[],\n options: Pick<FuzzySearchOptions<T>, `selector`> = {},\n): (query: string, signal: AbortSignal) => Promise<Array<T & { positions: ReadonlySet<number> }>> {\n const selector = options.selector ?? ((item: T) => item.label);\n const fuzzy = createFuzzySearch(items, { selector });\n\n return (\n query: string,\n signal: AbortSignal,\n ): Promise<Array<T & { positions: ReadonlySet<number> }>> =>\n new Promise((resolve, reject) => {\n if (signal.aborted) {\n reject(new DOMException(`Aborted`, `AbortError`));\n return;\n }\n\n const results = fuzzy.find(query).map(r => ({ ...r.item, positions: r.positions }));\n\n if (signal.aborted) {\n reject(new DOMException(`Aborted`, `AbortError`));\n return;\n }\n\n resolve(results);\n });\n}\n","import type {\n IncrSearch,\n IncrSearchChangeCallback,\n IncrSearchOptions,\n IncrSearchState,\n} from './types.js';\nimport { createFuzzySearch } from './fuzzy.js';\n\nfunction buildState<T>(results: ReturnType<ReturnType<typeof createFuzzySearch<T>>[`find`]>, query: string): IncrSearchState<T> {\n const positionsByItem = new Map<T, ReadonlySet<number>>();\n for (const r of results) {\n positionsByItem.set(r.item, r.positions);\n }\n return Object.freeze({\n query,\n results: Object.freeze([...results]),\n positionsByItem,\n });\n}\n\nexport function createIncrSearch<T>(options: IncrSearchOptions<T> = {}): IncrSearch<T> {\n let items: readonly T[] = options.items ?? [];\n let query = ``;\n let fuzzy = createFuzzySearch(items, { selector: options.selector, fzf: options.fzf });\n let state: IncrSearchState<T> = buildState(fuzzy.find(query), query);\n let disposed = false;\n\n const observers = new Set<IncrSearchChangeCallback<T>>();\n\n if (options.onChange) {\n observers.add(options.onChange);\n }\n\n const notify = (s: IncrSearchState<T>): void => {\n for (const cb of observers) {\n cb(s);\n }\n };\n\n const run = async (q: string, signal?: AbortSignal): Promise<IncrSearchState<T>> => {\n // Yield to the microtask queue for a consistent async interface\n await Promise.resolve();\n if (signal?.aborted || disposed) {\n return state;\n }\n const results = fuzzy.find(q);\n if (signal?.aborted || disposed) {\n return state;\n }\n state = buildState(results, q);\n notify(state);\n return state;\n };\n\n return {\n get state() {\n return state;\n },\n\n async setItems(newItems: readonly T[], signal?: AbortSignal): Promise<void> {\n items = newItems;\n fuzzy = createFuzzySearch(items, { selector: options.selector, fzf: options.fzf });\n await run(query, signal);\n },\n\n async setQuery(q: string, signal?: AbortSignal): Promise<IncrSearchState<T>> {\n query = q;\n return run(q, signal);\n },\n\n async clearQuery(): Promise<void> {\n query = ``;\n await run(``, undefined);\n },\n\n onChange(cb: IncrSearchChangeCallback<T>): () => void {\n observers.add(cb);\n cb(state);\n return () => {\n observers.delete(cb);\n };\n },\n\n dispose(): void {\n disposed = true;\n observers.clear();\n items = [];\n },\n };\n}\n","import type { FzfOptions } from 'fzf';\nimport type { TreeSearchHost } from '../common/searchable.js';\nimport type { TreeNode } from '../common/types.js';\nimport type { IncrSearchState } from './types.js';\nimport { applyHighlights, buildHighlightTargets, clearHighlights } from './highlight.js';\nimport { createIncrSearch } from './incr-search.js';\n\nconst DEFAULT_HIGHLIGHT_KEY = `incr-search-highlight`;\n\nexport type IncrSearchTreeOptions = {\n selector: (item: { node: TreeNode; depth: number }) => string;\n /**\n * CSS selector for the label elements inside the shadow root.\n * Defaults to `.tree-label` (suitable for ixfx-tree-list).\n * Use `.label` for ixfx-miller-list.\n */\n labelSelector?: string;\n highlightKey?: string;\n input?: HTMLInputElement;\n fzf?: Partial<FzfOptions<{ node: TreeNode; depth: number }>>;\n};\n\ntype SearchItem = { node: TreeNode; depth: number };\n\n/**\n * External-input filter-search controller for `TreeSearchHost` components.\n *\n * @deprecated `ixfx-tree-list` / `ixfx-miller-list` now have a built-in\n * incremental-search popover with navigate / select / filter modes — invoke\n * `el.registry.invoke('list.search.filter')` (see `docs/infra-incremental.md`)\n * instead of wiring an external `<input>`. This class remains for existing\n * consumers and covers filter mode only.\n *\n * @example Using with ixfx-tree-list:\n * ```typescript\n * const ctrl = new IncrSearchTreeController(myTreeList, {\n * selector: item => item.node.item.label,\n * });\n * ctrl.connect();\n * ```\n *\n * @example Using with ixfx-miller-list (different label selector):\n * ```typescript\n * const ctrl = new IncrSearchTreeController(myMillerList, {\n * selector: item => item.node.item.label,\n * labelSelector: '.label',\n * });\n * ctrl.connect();\n * ```\n */\nexport class IncrSearchTreeController {\n #el: TreeSearchHost;\n #opts: IncrSearchTreeOptions;\n #search: ReturnType<typeof createIncrSearch<SearchItem>>;\n #unsub: (() => void) | undefined;\n #labelMap = new Map<string, SearchItem>();\n\n constructor(el: TreeSearchHost, opts: IncrSearchTreeOptions) {\n this.#el = el;\n this.#opts = opts;\n this.#search = createIncrSearch<SearchItem>({\n selector: opts.selector,\n fzf: opts.fzf,\n });\n }\n\n connect(): void {\n this.disconnect();\n\n const items = this.#el.getNodes();\n for (const item of items) {\n this.#labelMap.set(this.#opts.selector(item), item);\n }\n void this.#search.setItems(items);\n\n if (this.#opts.input) {\n this.#opts.input.addEventListener(`input`, this.#onInput);\n this.#opts.input.addEventListener(`keydown`, this.#onKeydown);\n }\n\n this.#unsub = this.#search.onChange(state => this.#onStateChange(state));\n }\n\n disconnect(): void {\n if (this.#unsub) {\n this.#unsub();\n this.#unsub = undefined;\n }\n if (this.#opts.input) {\n this.#opts.input.removeEventListener(`input`, this.#onInput);\n this.#opts.input.removeEventListener(`keydown`, this.#onKeydown);\n }\n this.#el.filterPredicate = undefined;\n clearHighlights({ key: this.#opts.highlightKey ?? DEFAULT_HIGHLIGHT_KEY });\n this.#labelMap.clear();\n }\n\n async setQuery(query: string): Promise<void> {\n await this.#search.setQuery(query);\n }\n\n async clearQuery(): Promise<void> {\n await this.#search.clearQuery();\n }\n\n #onInput = () => {\n const value = this.#opts.input?.value ?? ``;\n void this.setQuery(value);\n };\n\n #onKeydown = (e: KeyboardEvent) => {\n if (e.key === `Escape` && this.#opts.input) {\n this.#opts.input.value = ``;\n void this.clearQuery();\n }\n };\n\n #onStateChange(state: IncrSearchState<SearchItem>): void {\n const matched = new Set(state.results.map(r => r.item.node.item.key));\n const hasQuery = state.query.trim().length > 0;\n this.#el.filterPredicate = hasQuery && matched.size > 0\n ? (node: TreeNode, _depth: number) => matched.has(node.item.key)\n : undefined;\n\n const key = this.#opts.highlightKey ?? DEFAULT_HIGHLIGHT_KEY;\n if (!this.#el.shadowRoot)\n return;\n\n if (!state.query.trim()) {\n clearHighlights({ key });\n return;\n }\n\n const labelSelector = this.#opts.labelSelector ?? `.tree-label`;\n const targets = buildHighlightTargets(\n this.#el.shadowRoot,\n labelSelector,\n state.positionsByItem,\n (labelEl) => {\n const text = labelEl.textContent ?? ``;\n return this.#labelMap.get(text);\n },\n labelEl => labelEl.textContent ?? ``,\n );\n applyHighlights(targets, { key });\n }\n}\n","/**\n * Helpers for key-based selection on the Element-flavoured list components\n * (`ixfx-vertical-list`, `ixfx-detail-list`, `ixfx-grid-list`).\n *\n * A \"key\" is a stable string the host puts on each item element — `data-key`\n * (preferred) or `data-value`. It survives the host rebuilding the item set\n * (re-fetch, re-sort, filter) where raw `Element` references do not.\n */\n\n/**\n * The stable key for an item element: `data-key`, then `data-value`, else\n * `undefined`.\n */\nexport function keyForElement(el: Element): string | undefined {\n return el.getAttribute(`data-key`) ?? el.getAttribute(`data-value`) ?? undefined;\n}\n\n/**\n * A lazily-built key → element index over a container. Rebuilt on first use\n * and after any child-list mutation under `root`; `invalidate()` forces a\n * rebuild on the next `get()`.\n *\n * ```ts\n * #keyIndex = new KeyedElementIndex(this);\n * // ...\n * const el = this.#keyIndex.get(`row-42`);\n * // on disconnect:\n * this.#keyIndex.dispose();\n * ```\n */\nexport class KeyedElementIndex {\n readonly #root: Element;\n readonly #selector: string;\n readonly #map = new Map<string, Element>();\n #dirty = true;\n readonly #observer: MutationObserver;\n\n /**\n * @param root Container whose descendants are indexed.\n * @param itemSelector Which descendants count as items (default: any `[data-key]`).\n */\n constructor(root: Element, itemSelector = `[data-key]`) {\n this.#root = root;\n this.#selector = itemSelector;\n this.#observer = new MutationObserver(() => {\n this.#dirty = true;\n });\n this.#observer.observe(root, { childList: true, subtree: true });\n }\n\n /** The element with this key, or `undefined`. First match wins on duplicates. */\n get(key: string): Element | undefined {\n if (this.#dirty) {\n this.#rebuild();\n }\n return this.#map.get(key);\n }\n\n /** Force a rebuild on the next `get()` — e.g. after a `data-key` attribute change. */\n invalidate(): void {\n this.#dirty = true;\n }\n\n /** Stop observing and drop the cache. */\n dispose(): void {\n this.#observer.disconnect();\n this.#map.clear();\n }\n\n #rebuild(): void {\n this.#map.clear();\n for (const el of this.#root.querySelectorAll(this.#selector)) {\n const key = keyForElement(el);\n if (key !== undefined && !this.#map.has(key)) {\n this.#map.set(key, el);\n }\n }\n this.#dirty = false;\n }\n}\n","import type { ListSearchAdapter } from './list-search-controller.js';\nimport { keyForElement } from '../interaction/keyed-list.js';\n\n/**\n * The slice of a list component the element adapter drives. `ixfx-grid-list`,\n * `ixfx-vertical-list` and `ixfx-detail-list` all satisfy it.\n */\nexport interface ElementListSearchHost extends HTMLElement {\n focusKey: (key: string) => void;\n selectKeys: (keys: Iterable<string>) => void;\n}\n\nexport interface ElementListSearchAdapterOptions {\n /** Selector for item elements, relative to the host. Default `:scope > *`. */\n itemSelector?: string;\n getLabel?: (el: Element) => string;\n getKey?: (el: Element) => string;\n /** `CSS.highlights` registry key for matched-character highlights. */\n highlightKey?: string;\n}\n\nfunction defaultLabel(el: Element): string {\n return el.getAttribute(`data-search-label`) ?? el.textContent?.trim() ?? ``;\n}\n\n/**\n * A {@link ListSearchAdapter} over the light-DOM item elements of a list\n * component. Filter mode toggles `hidden` (only on elements it hid itself, so a\n * consumer's own `hidden` items are left alone). Highlights are painted on the\n * item elements in the light DOM — the consuming page styles\n * `::highlight(<highlightKey>)`. See `docs/infra-incremental.md`.\n */\nexport function createElementListSearchAdapter(\n host: ElementListSearchHost,\n options: ElementListSearchAdapterOptions = {},\n): ListSearchAdapter<Element> {\n const itemSelector = options.itemSelector ?? `:scope > *`;\n const getLabel = options.getLabel ?? defaultLabel;\n const getKey = options.getKey ?? (el => keyForElement(el) ?? defaultLabel(el));\n const hidden = new Set<Element>();\n\n const items = (): Element[] => Array.from(host.querySelectorAll(itemSelector));\n\n return {\n getItems: items,\n getLabel,\n getKey,\n focusItem: (el) => {\n if (el)\n host.focusKey(getKey(el));\n },\n activateItem: (el) => {\n el.dispatchEvent(new MouseEvent(`click`, { bubbles: true, composed: true }));\n },\n selectItems: (els) => {\n host.selectKeys(els.map(getKey));\n },\n applyFilter: (matched) => {\n if (matched === undefined) {\n for (const el of hidden)\n (el as HTMLElement).hidden = false;\n hidden.clear();\n return;\n }\n for (const el of items()) {\n if (matched.has(getKey(el))) {\n if (hidden.delete(el))\n (el as HTMLElement).hidden = false;\n } else {\n (el as HTMLElement).hidden = true;\n hidden.add(el);\n }\n }\n },\n highlightRoot: () => host,\n highlightSelector: itemSelector,\n highlightKeyOf: el => getKey(el),\n highlightText: getLabel,\n highlightKey: options.highlightKey,\n container: () => host,\n };\n}\n","import type {\n ElementIncrSearchOptions,\n IncrSearchChangeCallback,\n IncrSearchState,\n} from './types.js';\nimport { applyHighlights, buildHighlightTargets, clearHighlights } from './highlight.js';\nimport { createIncrSearch } from './incr-search.js';\n\ntype ElementItem = { readonly key: string; readonly label: string };\n\nconst defaultGetLabel = (el: Element): string => el.textContent?.trim() ?? ``;\n\nfunction defaultGetKey(el: Element): string {\n return el.getAttribute(`data-key`)\n ?? el.getAttribute(`data-value`)\n ?? el.textContent?.trim()\n ?? ``;\n}\n\nexport type ElementIncrSearch = {\n readonly setQuery: (query: string, signal?: AbortSignal) => Promise<void>;\n readonly clearQuery: () => Promise<void>;\n readonly refresh: () => void;\n readonly onChange: (cb: IncrSearchChangeCallback<ElementItem>) => () => void;\n readonly dispose: () => void;\n};\n\n/**\n * DOM filter-search over a container's item elements (sets `hidden` on\n * non-matches, applies highlights).\n *\n * @deprecated The list components (`ixfx-grid-list`, `ixfx-vertical-list`,\n * `ixfx-detail-list`, …) now have a built-in navigate / select / filter search\n * popover — see `docs/infra-incremental.md` and `ListSearchController`. Kept for\n * standalone / non-component use.\n */\nexport function createElementIncrSearch(opts: ElementIncrSearchOptions): ElementIncrSearch {\n const {\n container,\n itemSelector,\n getLabel = defaultGetLabel,\n getKey = defaultGetKey,\n labelSelector,\n highlightKey,\n } = opts;\n\n // Map from key → element reference for highlight lookup\n let elementByKey = new Map<string, Element>();\n\n const search = createIncrSearch<ElementItem>({\n selector: item => item.label,\n fzf: opts.fzf,\n });\n\n const updateVisibility = (state: IncrSearchState<ElementItem>): void => {\n const matchedKeys = new Set(state.results.map(r => r.item.key));\n const hasQuery = state.query.trim().length > 0;\n\n for (const [key, el] of elementByKey) {\n (el as HTMLElement).hidden = hasQuery ? !matchedKeys.has(key) : false;\n }\n };\n\n const updateHighlights = (state: IncrSearchState<ElementItem>): void => {\n if (!state.query.trim()) {\n clearHighlights({ key: highlightKey });\n return;\n }\n\n const sel = labelSelector ?? itemSelector;\n const targets = buildHighlightTargets(\n container,\n sel,\n state.positionsByItem,\n (el) => {\n const key = getKey(el);\n // Find the ElementItem whose key matches this element's key\n const result = state.results.find(r => r.item.key === key);\n return result?.item;\n },\n el => getLabel(el),\n );\n applyHighlights(targets, { key: highlightKey });\n };\n\n const unsubscribeState = search.onChange((state) => {\n updateVisibility(state);\n updateHighlights(state);\n opts.onChange?.(state);\n });\n\n let refreshPending = false;\n\n const refresh = (): void => {\n if (refreshPending)\n return;\n refreshPending = true;\n void Promise.resolve().then(() => {\n refreshPending = false;\n elementByKey = new Map<string, Element>();\n const els = container.querySelectorAll(itemSelector);\n const items: ElementItem[] = [];\n for (const el of els) {\n const key = getKey(el);\n elementByKey.set(key, el);\n items.push({ key, label: getLabel(el) });\n }\n void search.setItems(items);\n });\n };\n\n const observer = new MutationObserver(() => refresh());\n observer.observe(container, { childList: true, subtree: false });\n\n refresh();\n\n return {\n async setQuery(query, signal) {\n await search.setQuery(query, signal);\n },\n\n async clearQuery() {\n await search.clearQuery();\n },\n\n refresh,\n\n onChange(cb) {\n return search.onChange(cb);\n },\n\n dispose() {\n observer.disconnect();\n unsubscribeState();\n search.dispose();\n clearHighlights({ key: highlightKey });\n },\n };\n}\n","import type { CommandRegistry } from '@clinth/ui-commands';\nimport type { ListSearchController, ListSearchMode } from './list-search-controller.js';\n\n/** Command ids registered by {@link registerListSearchCommands}, keyed by mode. */\nexport const LIST_SEARCH_COMMAND_IDS: Readonly<Record<ListSearchMode, string>> = {\n navigate: `list.search.navigate`,\n select: `list.search.select`,\n filter: `list.search.filter`,\n};\n\nconst LABELS: Readonly<Record<ListSearchMode, { label: string; description: string }>> = {\n navigate: { label: `Find`, description: `Type to move the cursor to the best match` },\n select: { label: `Find & Select`, description: `Type to select every matching item` },\n filter: { label: `Filter`, description: `Type to hide items that don't match` },\n};\n\nexport interface RegisterListSearchCommandsOptions {\n /**\n * Prefix for command ids, e.g. `grid-list` ⇒ `grid-list.search.filter`. When\n * omitted the shared ids from {@link LIST_SEARCH_COMMAND_IDS} are used so a\n * single dispatch (`ixfx-grouped-item-lister.dispatch('list.search.filter')`)\n * fans out to every list.\n */\n idPrefix?: string;\n}\n\n/**\n * Register one command per mode the controller offers (see\n * `controller.registeredModes`). Each command opens the search popover in its\n * mode. Returns a function that unregisters them again — call it from\n * `disconnectedCallback`. See `docs/infra-incremental.md`.\n */\nexport function registerListSearchCommands<T>(\n registry: CommandRegistry<unknown>,\n controller: ListSearchController<T>,\n options: RegisterListSearchCommandsOptions = {},\n): () => void {\n const id = (mode: ListSearchMode): string =>\n options.idPrefix ? `${options.idPrefix}.search.${mode}` : LIST_SEARCH_COMMAND_IDS[mode];\n\n const registered: string[] = [];\n for (const mode of controller.registeredModes) {\n const commandId = id(mode);\n if (registry.has(commandId))\n continue;\n registry.register({\n id: commandId,\n label: LABELS[mode].label,\n description: LABELS[mode].description,\n execute: () => controller.open(mode),\n });\n registered.push(commandId);\n }\n\n return () => {\n for (const commandId of registered)\n registry.unregister(commandId);\n };\n}\n","import type { FzfOptions } from 'fzf';\nimport type { ReactiveController, ReactiveControllerHost, TemplateResult } from 'lit';\nimport type { IncrSearchResult, IncrSearchState } from './types.js';\nimport { html, nothing } from 'lit';\nimport { applyHighlights, buildHighlightTargets, clearHighlights } from './highlight.js';\nimport { createIncrSearch } from './incr-search.js';\n\n/**\n * The three things incremental search can do to a list / tree component. See\n * `docs/infra-incremental.md`.\n *\n * - `navigate` — move the cursor to the best match; ↑/↓ cycle between matches;\n * Enter activates the current match and closes.\n * - `select` — (re)select every item whose label matches, live as you type.\n * - `filter` — hide items that don't match; restored when the popover closes.\n */\nexport type ListSearchMode = `navigate` | `select` | `filter`;\n\n/** Canonical order — used for the switch-row and to normalise a requested set. */\nexport const LIST_SEARCH_MODES: readonly ListSearchMode[] = [`navigate`, `select`, `filter`];\n\nconst DEFAULT_HIGHLIGHT_KEY = `incr-search-highlight`;\nconst INPUT_CLASS = `list-search-input`;\n\ntype SearchItem = { readonly key: string; readonly label: string };\n\n/**\n * Everything {@link ListSearchController} needs to drive a specific host. One is\n * supplied per component; `createElementListSearchAdapter` and\n * `createTreeListSearchAdapter` cover the common shapes.\n */\nexport interface ListSearchAdapter<TItem> {\n /** All searchable items, in display order. */\n getItems: () => readonly TItem[];\n /** Text matched against the query. */\n getLabel: (item: TItem) => string;\n /** Stable identity for an item. */\n getKey: (item: TItem) => string;\n /** `navigate`: move the cursor to `item` and reveal it. `undefined` = no-op. */\n focusItem: (item: TItem | undefined) => void;\n /** `navigate` + Enter: activate `item` (falls back to `focusItem`). */\n activateItem?: (item: TItem) => void;\n /** `select` / \"Select matches\": replace the selection with `items`. */\n selectItems: (items: readonly TItem[]) => void;\n /** `filter`: hide items whose key is not in `matchedKeys`; `undefined` clears the filter. */\n applyFilter: (matchedKeys: ReadonlySet<string> | undefined) => void;\n /** Where matched-character highlights are painted (usually the shadow root). */\n highlightRoot?: () => ShadowRoot | Element | null | undefined;\n /** CSS selector for the label elements inside {@link highlightRoot}. */\n highlightSelector?: string;\n /** Given a label element, the key of the item it belongs to. */\n highlightKeyOf?: (labelEl: Element) => string | undefined;\n /** Text of a label element as fzf saw it (defaults to `el.textContent`). */\n highlightText?: (labelEl: Element) => string;\n /** `CSS.highlights` registry key. Defaults to `incr-search-highlight`. */\n highlightKey?: string;\n /** Element whose child-list mutations should trigger a `refresh()`. */\n container?: () => Element | null | undefined;\n}\n\nexport interface ListSearchControllerOptions<TItem> {\n adapter: ListSearchAdapter<TItem>;\n /**\n * Modes this instance offers, as entry points and as in-popover switch\n * targets. The controller intersects this with {@link LIST_SEARCH_MODES}, so\n * pass the intersection of the component's own capability and any\n * consumer-set `search-modes`. Empty ⇒ search disabled. Default: all three.\n */\n modes?: readonly ListSearchMode[];\n fzf?: Partial<FzfOptions<SearchItem>>;\n placeholder?: string;\n}\n\nexport type ListSearchHost = ReactiveControllerHost & HTMLElement & {\n renderRoot?: DocumentFragment | HTMLElement;\n};\n\n/**\n * Shared brain for the three-mode incremental-search popover. A Lit\n * `ReactiveController`: the host adds `listSearchStyles` to `static styles`,\n * drops `${controller.renderField()}` into `render()`, and registers the\n * commands with {@link registerListSearchCommands}. See `docs/infra-incremental.md`.\n */\nexport class ListSearchController<TItem> implements ReactiveController {\n #host: ListSearchHost;\n #adapter: ListSearchAdapter<TItem>;\n #modes: readonly ListSearchMode[];\n #placeholder: string;\n #search: ReturnType<typeof createIncrSearch<SearchItem>>;\n #unsub: (() => void) | undefined;\n #observer: MutationObserver | undefined;\n\n #itemByKey = new Map<string, TItem>();\n\n #open = false;\n #mode: ListSearchMode = `filter`;\n #query = ``;\n #matchIndex = 0;\n #matches: ReadonlyArray<IncrSearchResult<SearchItem>> = [];\n /** Whether a filter has been pushed to the adapter and still needs undoing. */\n #filterActive = false;\n\n constructor(host: ListSearchHost, options: ListSearchControllerOptions<TItem>) {\n this.#host = host;\n host.addController(this);\n this.#adapter = options.adapter;\n const requested = new Set(options.modes ?? LIST_SEARCH_MODES);\n this.#modes = LIST_SEARCH_MODES.filter(m => requested.has(m));\n this.#mode = this.#modes[0] ?? `filter`;\n this.#placeholder = options.placeholder ?? `Search…`;\n this.#search = createIncrSearch<SearchItem>({ selector: i => i.label, fzf: options.fzf });\n this.#unsub = this.#search.onChange(state => this.#onState(state));\n }\n\n // --- Public surface ---\n\n /** `false` when no modes are available — the host should register no commands and render no field. */\n get enabled(): boolean {\n return this.#modes.length > 0;\n }\n\n /** The modes actually offered (component capability ∩ consumer request). */\n get registeredModes(): readonly ListSearchMode[] {\n return this.#modes;\n }\n\n /**\n * Replace the offered mode set (normalised to {@link LIST_SEARCH_MODES}\n * order). If the current mode is dropped the popover closes and falls back to\n * the first remaining mode. Callers should re-run\n * {@link registerListSearchCommands} afterwards.\n */\n setModes(modes: readonly ListSearchMode[]): void {\n const set = new Set(modes);\n this.#modes = LIST_SEARCH_MODES.filter(m => set.has(m));\n if (!this.#modes.includes(this.#mode)) {\n if (this.#open)\n this.close();\n this.#mode = this.#modes[0] ?? `filter`;\n }\n this.#host.requestUpdate();\n }\n\n get isOpen(): boolean {\n return this.#open;\n }\n\n get mode(): ListSearchMode {\n return this.#mode;\n }\n\n get query(): string {\n return this.#query;\n }\n\n get matchCount(): number {\n return this.#matches.length;\n }\n\n get matchIndex(): number {\n return this.#matchIndex;\n }\n\n // --- ReactiveController lifecycle ---\n\n hostConnected(): void {\n const container = this.#adapter.container?.();\n if (container) {\n this.#observer = new MutationObserver(() => this.refresh());\n this.#observer.observe(container, { childList: true, subtree: false });\n }\n this.refresh();\n }\n\n hostDisconnected(): void {\n this.#observer?.disconnect();\n this.#observer = undefined;\n if (this.#open)\n this.#teardownEffects();\n this.#open = false;\n this.#unsub?.();\n this.#unsub = undefined;\n this.#search.dispose();\n }\n\n // --- Commands / actions ---\n\n /** Open the popover in `mode` (clamped to the available set). */\n open(mode: ListSearchMode): void {\n if (!this.enabled)\n return;\n this.#mode = this.#modes.includes(mode) ? mode : this.#modes[0];\n this.#open = true;\n this.#query = ``;\n this.#matchIndex = 0;\n this.#matches = [];\n this.refresh();\n void this.#search.setQuery(``);\n this.#host.requestUpdate();\n void this.#host.updateComplete.then(() => this.#focusInput());\n }\n\n /** Close the popover, restoring any live filter. Selection / cursor stay put. */\n close(): void {\n if (!this.#open)\n return;\n this.#open = false;\n this.#teardownEffects();\n this.#query = ``;\n this.#matches = [];\n void this.#search.clearQuery();\n this.#host.requestUpdate();\n this.#host.focus();\n }\n\n setQuery(query: string): void {\n this.#query = query;\n this.#matchIndex = 0;\n void this.#search.setQuery(query);\n }\n\n /** Re-interpret the current query under a new mode (undoing the old mode's effect). */\n switchMode(next: ListSearchMode): void {\n if (!this.#modes.includes(next) || next === this.#mode)\n return;\n if (this.#mode === `filter` && this.#filterActive) {\n this.#adapter.applyFilter(undefined);\n this.#filterActive = false;\n }\n this.#mode = next;\n this.#applyMode();\n this.#host.requestUpdate();\n void this.#host.updateComplete.then(() => this.#focusInput());\n }\n\n /** One-shot: turn the current match set into the selection, staying in the current mode. */\n selectMatches(): void {\n if (!this.#modes.includes(`select`))\n return;\n this.#adapter.selectItems(this.#currentItems());\n this.#host.requestUpdate();\n }\n\n nextMatch(): void {\n this.#cycle(1);\n }\n\n prevMatch(): void {\n this.#cycle(-1);\n }\n\n /** Enter: in `navigate` activate the current match; then close. */\n commit(): void {\n if (this.#mode === `navigate`) {\n const item = this.#itemFor(this.#matches[this.#matchIndex]);\n if (item) {\n if (this.#adapter.activateItem)\n this.#adapter.activateItem(item);\n else\n this.#adapter.focusItem(item);\n }\n }\n this.close();\n }\n\n /** Rebuild the searchable item set from the adapter. Called on open and on container mutation. */\n refresh(): void {\n this.#itemByKey.clear();\n const items: SearchItem[] = [];\n for (const it of this.#adapter.getItems()) {\n const key = this.#adapter.getKey(it);\n this.#itemByKey.set(key, it);\n items.push({ key, label: this.#adapter.getLabel(it) });\n }\n void this.#search.setItems(items);\n }\n\n // --- Rendering ---\n\n /** Popover markup. Pair with `listSearchStyles` in the host's `static styles`. */\n renderField(): TemplateResult | typeof nothing {\n if (!this.enabled)\n return nothing;\n const hasQuery = this.#query.trim().length > 0;\n const others = this.#modes.filter(m => m !== this.#mode);\n const showSelectMatches = this.#modes.includes(`select`) && this.#mode !== `select`;\n return html`\n <div class=\"list-search\" part=\"search\" ?hidden=${!this.#open}>\n <div class=\"list-search-row\">\n <span class=\"list-search-mode\">${this.#mode}</span>\n <input\n class=${INPUT_CLASS}\n type=\"text\"\n part=\"search-input\"\n placeholder=${this.#placeholder}\n .value=${this.#query}\n @input=${this.#onInput}\n @keydown=${this.#onKeydown}\n />\n ${hasQuery\n ? html`<span class=\"list-search-count\">${this.#matches.length === 0 ? `0` : this.#matchIndex + 1} / ${this.#matches.length}</span>`\n : nothing}\n ${this.#mode === `navigate` && this.#matches.length > 1\n ? html`\n <button class=\"list-search-icon-btn\" title=\"Previous match (↑)\" @click=${() => this.prevMatch()}>‹</button>\n <button class=\"list-search-icon-btn\" title=\"Next match (↓)\" @click=${() => this.nextMatch()}>›</button>\n `\n : nothing}\n <button class=\"list-search-icon-btn\" title=\"Close (Esc)\" @click=${() => this.close()}>✕</button>\n </div>\n ${others.length > 0 || showSelectMatches\n ? html`\n <div class=\"list-search-switch\">\n ${others.map(m => html`<button class=\"list-search-btn\" @click=${() => this.switchMode(m)}>${m}</button>`)}\n ${showSelectMatches\n ? html`<button class=\"list-search-btn\" @click=${() => this.selectMatches()}>Select matches</button>`\n : nothing}\n </div>\n `\n : nothing}\n </div>\n `;\n }\n\n // --- Internals ---\n\n #focusInput(): void {\n this.#host.renderRoot?.querySelector<HTMLInputElement>(`.${INPUT_CLASS}`)?.focus();\n }\n\n #onInput = (e: Event): void => {\n this.setQuery((e.target as HTMLInputElement).value);\n };\n\n #onKeydown = (e: KeyboardEvent): void => {\n switch (e.key) {\n case `Escape`:\n e.preventDefault();\n e.stopPropagation();\n this.close();\n break;\n case `Enter`:\n e.preventDefault();\n e.stopPropagation();\n this.commit();\n break;\n case `ArrowDown`:\n if (this.#mode === `navigate`) {\n e.preventDefault();\n this.nextMatch();\n }\n break;\n case `ArrowUp`:\n if (this.#mode === `navigate`) {\n e.preventDefault();\n this.prevMatch();\n }\n break;\n default:\n break;\n }\n };\n\n #cycle(delta: number): void {\n if (this.#matches.length === 0)\n return;\n const n = this.#matches.length;\n this.#matchIndex = (this.#matchIndex + delta + n) % n;\n if (this.#mode === `navigate`)\n this.#adapter.focusItem(this.#itemFor(this.#matches[this.#matchIndex]));\n this.#host.requestUpdate();\n }\n\n #itemFor(match: IncrSearchResult<SearchItem> | undefined): TItem | undefined {\n return match ? this.#itemByKey.get(match.item.key) : undefined;\n }\n\n #currentItems(): TItem[] {\n return this.#matches\n .map(m => this.#itemFor(m))\n .filter((x): x is TItem => x !== undefined);\n }\n\n get #highlightKey(): string {\n return this.#adapter.highlightKey ?? DEFAULT_HIGHLIGHT_KEY;\n }\n\n #onState(state: IncrSearchState<SearchItem>): void {\n if (!this.#open)\n return;\n const hasQuery = state.query.trim().length > 0;\n this.#matches = hasQuery ? [...state.results] : [];\n if (this.#matchIndex >= this.#matches.length)\n this.#matchIndex = 0;\n this.#applyMode();\n this.#host.requestUpdate();\n }\n\n #applyMode(): void {\n const hasQuery = this.#query.trim().length > 0;\n\n if (!hasQuery) {\n if (this.#filterActive) {\n this.#adapter.applyFilter(undefined);\n this.#filterActive = false;\n }\n this.#applyHighlights();\n return;\n }\n\n switch (this.#mode) {\n case `navigate`:\n this.#adapter.focusItem(this.#itemFor(this.#matches[this.#matchIndex]));\n break;\n case `select`:\n this.#adapter.selectItems(this.#currentItems());\n break;\n case `filter`:\n this.#adapter.applyFilter(new Set(this.#matches.map(m => m.item.key)));\n this.#filterActive = true;\n break;\n }\n this.#applyHighlights();\n }\n\n #applyHighlights(): void {\n const root = this.#adapter.highlightRoot?.();\n const selector = this.#adapter.highlightSelector;\n const keyOf = this.#adapter.highlightKeyOf;\n if (!root || !selector || !keyOf)\n return;\n if (this.#query.trim().length === 0) {\n clearHighlights({ key: this.#highlightKey });\n return;\n }\n const state = this.#search.state;\n const targets = buildHighlightTargets(\n root,\n selector,\n state.positionsByItem,\n (el) => {\n const key = keyOf(el);\n return key === undefined ? undefined : state.results.find(r => r.item.key === key)?.item;\n },\n this.#adapter.highlightText ?? (el => el.textContent ?? ``),\n );\n // Highlights are cosmetic — never let a bad range (label / positions\n // mismatch) surface as an unhandled rejection through the async engine.\n try {\n applyHighlights(targets, { key: this.#highlightKey });\n } catch {\n clearHighlights({ key: this.#highlightKey });\n }\n }\n\n #teardownEffects(): void {\n if (this.#filterActive) {\n this.#adapter.applyFilter(undefined);\n this.#filterActive = false;\n }\n clearHighlights({ key: this.#highlightKey });\n }\n}\n","import { css } from 'lit';\n\n/**\n * Styles for the incremental-search popover rendered by\n * `ListSearchController.renderField()`. Add to a component's `static styles`;\n * the class names are the contract between this fragment and `renderField()`.\n *\n * The host must give the popover a positioned ancestor (a wrapper with\n * `position: relative`, or `:host { position: relative }`). Tunables:\n * `--list-search-inset` (default `8px`) offsets it from the top-right corner.\n *\n * See `docs/infra-incremental.md`.\n */\nexport const listSearchStyles = css`\n .list-search {\n position: absolute;\n top: var(--list-search-inset, 8px);\n right: var(--list-search-inset, 8px);\n z-index: 20;\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 6px;\n box-sizing: border-box;\n background: var(--surface-4, #2a2a2a);\n color: var(--surface-3-text, inherit);\n border: 1px solid var(--border, #444);\n border-radius: var(--radius-m, 6px);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);\n font-size: var(--text-s, 0.85em);\n }\n\n .list-search[hidden] {\n display: none;\n }\n\n .list-search-row {\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .list-search-mode {\n flex: none;\n padding: 1px 7px;\n border-radius: 999px;\n font-weight: 600;\n text-transform: capitalize;\n background: var(--accent, #60a5fa);\n color: var(--accent-text, #000);\n }\n\n .list-search-input {\n flex: 1;\n min-width: 140px;\n background: transparent;\n border: none;\n outline: none;\n color: inherit;\n font: inherit;\n }\n\n .list-search-count {\n flex: none;\n opacity: 0.6;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n }\n\n .list-search-switch {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n }\n\n .list-search-btn {\n padding: 1px 7px;\n background: var(--surface-3, #333);\n color: inherit;\n border: 1px solid var(--border, #444);\n border-radius: var(--radius-s, 4px);\n cursor: pointer;\n font: inherit;\n text-transform: capitalize;\n }\n\n .list-search-btn:hover {\n background: var(--item-bg-tickled, #444);\n }\n\n .list-search-icon-btn {\n flex: none;\n padding: 0 2px;\n background: transparent;\n border: none;\n color: var(--surface-muted-text, #888);\n cursor: pointer;\n font-size: 1.1em;\n line-height: 1;\n }\n\n .list-search-icon-btn:hover {\n color: inherit;\n }\n`;\n","import type { TreeSearchHost } from '../common/tree-component.js';\nimport type { TreeNode } from '../common/types.js';\nimport type { ListSearchAdapter } from './list-search-controller.js';\n\ntype TreeSearchItem = { node: TreeNode; depth: number };\n\nexport interface TreeListSearchAdapterOptions {\n /** Label-element selector inside the shadow root. Default `.tree-label`; `ixfx-miller-list` uses `.label`. */\n labelSelector?: string;\n /** `CSS.highlights` registry key for matched-character highlights. */\n highlightKey?: string;\n getLabel?: (item: TreeSearchItem) => string;\n}\n\n/**\n * A {@link ListSearchAdapter} over any `TreeSearchHost` (`ixfx-tree-list`,\n * `ixfx-miller-list`, `ixfx-crumb-navigation`). Navigate reveals the match\n * (expands its ancestors, moves the cursor); select drives `selectMany`; filter\n * sets `filterPredicate`. The item set is the whole tree — `getNodes()` returns\n * every node regardless of expansion or an active filter — so refining a query\n * can always re-surface a node. See `docs/infra-incremental.md`.\n */\nexport function createTreeListSearchAdapter(\n host: TreeSearchHost,\n options: TreeListSearchAdapterOptions = {},\n): ListSearchAdapter<TreeSearchItem> {\n const getLabel = options.getLabel ?? ((item: TreeSearchItem) => item.node.item.label);\n\n return {\n getItems: () => host.getNodes(),\n getLabel,\n getKey: item => item.node.item.key,\n focusItem: (item) => {\n if (item)\n host.revealKey(item.node.item.key);\n },\n activateItem: (item) => {\n host.revealKey(item.node.item.key);\n host.select(item.node);\n },\n selectItems: (items) => {\n host.selectMany(items.map(i => i.node));\n },\n applyFilter: (matched) => {\n host.filterPredicate = matched === undefined\n ? undefined\n : (node: TreeNode) => matched.has(node.item.key);\n },\n highlightRoot: () => host.shadowRoot,\n highlightSelector: options.labelSelector ?? `.tree-label`,\n highlightKeyOf: el => (el.closest(`[data-key]`) as HTMLElement | null)?.dataset.key,\n highlightKey: options.highlightKey,\n };\n}\n"],"mappings":"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"}
|
package/dist/incr-search.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { type ElementIncrSearch, type ElementIncrSearchOptions, type FuzzySearch, type FuzzySearchOptions, type HighlightOptions, type HighlightTarget, type IncrSearch, type IncrSearchChangeCallback, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, type IncrSearchTreeOptions as IncrSearchMillerOptions, type IncrSearchTreeOptions, type IncrSearchOptions, type IncrSearchResult, type IncrSearchState, applyHighlights, buildHighlightTargets, clearHighlights, createAcCompletionProvider, createElementIncrSearch, createFuzzySearch, createIncrSearch };
|
|
1
|
+
import { A as HighlightTarget, C as IncrSearchTreeController, D as FuzzySearch, E as ElementIncrSearchOptions, F as IncrSearchState, M as IncrSearchChangeCallback, N as IncrSearchOptions, O as FuzzySearchOptions, P as IncrSearchResult, S as ListSearchMode, T as createAcCompletionProvider, _ as LIST_SEARCH_MODES, a as RegisterListSearchCommandsOptions, b as ListSearchControllerOptions, c as applyHighlights, d as createFuzzySearch, f as ElementIncrSearch, g as createElementListSearchAdapter, h as ElementListSearchHost, i as LIST_SEARCH_COMMAND_IDS, j as IncrSearch, k as HighlightOptions, l as buildHighlightTargets, m as ElementListSearchAdapterOptions, n as createTreeListSearchAdapter, o as registerListSearchCommands, p as createElementIncrSearch, r as listSearchStyles, s as createIncrSearch, t as TreeListSearchAdapterOptions, u as clearHighlights, v as ListSearchAdapter, w as IncrSearchTreeOptions, x as ListSearchHost, y as ListSearchController } from "./index-CBS4z1v-.js";
|
|
2
|
+
export { type ElementIncrSearch, type ElementIncrSearchOptions, type ElementListSearchAdapterOptions, type ElementListSearchHost, type FuzzySearch, type FuzzySearchOptions, type HighlightOptions, type HighlightTarget, type IncrSearch, type IncrSearchChangeCallback, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, type IncrSearchTreeOptions as IncrSearchMillerOptions, type IncrSearchTreeOptions, type IncrSearchOptions, type IncrSearchResult, type IncrSearchState, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, type ListSearchAdapter, ListSearchController, type ListSearchControllerOptions, type ListSearchHost, type ListSearchMode, type RegisterListSearchCommandsOptions, type TreeListSearchAdapterOptions, applyHighlights, buildHighlightTargets, clearHighlights, createAcCompletionProvider, createElementIncrSearch, createElementListSearchAdapter, createFuzzySearch, createIncrSearch, createTreeListSearchAdapter, listSearchStyles, registerListSearchCommands };
|
package/dist/incr-search.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import { n as buildHighlightTargets, r as clearHighlights, t as applyHighlights } from "./highlight-B-eQrhhb.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export { IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, applyHighlights, buildHighlightTargets, clearHighlights, createAcCompletionProvider, createElementIncrSearch, createFuzzySearch, createIncrSearch };
|
|
2
|
+
import { a as LIST_SEARCH_COMMAND_IDS, c as createElementListSearchAdapter, d as IncrSearchTreeController, f as createIncrSearch, i as ListSearchController, m as createFuzzySearch, n as listSearchStyles, o as registerListSearchCommands, p as createAcCompletionProvider, r as LIST_SEARCH_MODES, s as createElementIncrSearch, t as createTreeListSearchAdapter } from "./incr-search-DpbSJtgj.js";
|
|
3
|
+
export { IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, ListSearchController, applyHighlights, buildHighlightTargets, clearHighlights, createAcCompletionProvider, createElementIncrSearch, createElementListSearchAdapter, createFuzzySearch, createIncrSearch, createTreeListSearchAdapter, listSearchStyles, registerListSearchCommands };
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import { o as TreeNode } from "./types-Bc23SI94.js";
|
|
2
|
+
import { d as TreeSearchHost } from "./tree-component-F6qZ0Gdv.js";
|
|
3
|
+
import { ReactiveController, ReactiveControllerHost, TemplateResult, nothing } from "lit";
|
|
4
|
+
import { FzfOptions } from "fzf";
|
|
5
|
+
import { CommandRegistry } from "@clinth/ui-commands";
|
|
6
|
+
//#region src/incr-search/types.d.ts
|
|
7
|
+
type IncrSearchResult<T> = {
|
|
8
|
+
readonly item: T;
|
|
9
|
+
readonly positions: ReadonlySet<number>;
|
|
10
|
+
readonly score: number;
|
|
11
|
+
};
|
|
12
|
+
type IncrSearchState<T> = {
|
|
13
|
+
readonly query: string;
|
|
14
|
+
readonly results: ReadonlyArray<IncrSearchResult<T>>;
|
|
15
|
+
readonly positionsByItem: ReadonlyMap<T, ReadonlySet<number>>;
|
|
16
|
+
};
|
|
17
|
+
type IncrSearchChangeCallback<T> = (state: IncrSearchState<T>) => void;
|
|
18
|
+
type IncrSearchOptions<T> = {
|
|
19
|
+
readonly items?: readonly T[];
|
|
20
|
+
readonly selector?: (item: T) => string;
|
|
21
|
+
readonly fzf?: Partial<FzfOptions<T>>;
|
|
22
|
+
readonly onChange?: IncrSearchChangeCallback<T>;
|
|
23
|
+
};
|
|
24
|
+
type IncrSearch<T> = {
|
|
25
|
+
readonly setItems: (items: readonly T[], signal?: AbortSignal) => Promise<void>;
|
|
26
|
+
readonly setQuery: (query: string, signal?: AbortSignal) => Promise<IncrSearchState<T>>;
|
|
27
|
+
readonly clearQuery: () => Promise<void>;
|
|
28
|
+
readonly state: IncrSearchState<T>;
|
|
29
|
+
readonly onChange: (cb: IncrSearchChangeCallback<T>) => () => void;
|
|
30
|
+
readonly dispose: () => void;
|
|
31
|
+
};
|
|
32
|
+
type FuzzySearchOptions<T> = {
|
|
33
|
+
readonly selector?: (item: T) => string;
|
|
34
|
+
readonly fzf?: Partial<FzfOptions<T>>;
|
|
35
|
+
};
|
|
36
|
+
type FuzzySearch<T> = {
|
|
37
|
+
readonly find: (query: string) => ReadonlyArray<IncrSearchResult<T>>;
|
|
38
|
+
readonly items: readonly T[];
|
|
39
|
+
};
|
|
40
|
+
type HighlightTarget = {
|
|
41
|
+
readonly element: Element;
|
|
42
|
+
readonly text?: string;
|
|
43
|
+
readonly positions: ReadonlySet<number>;
|
|
44
|
+
};
|
|
45
|
+
type HighlightOptions = {
|
|
46
|
+
readonly key?: string;
|
|
47
|
+
};
|
|
48
|
+
type ElementIncrSearchOptions = {
|
|
49
|
+
readonly container: Element;
|
|
50
|
+
readonly itemSelector: string;
|
|
51
|
+
readonly getLabel?: (el: Element) => string;
|
|
52
|
+
readonly getKey?: (el: Element) => string;
|
|
53
|
+
readonly labelSelector?: string;
|
|
54
|
+
readonly highlightKey?: string;
|
|
55
|
+
readonly fzf?: Partial<FzfOptions<{
|
|
56
|
+
key: string;
|
|
57
|
+
label: string;
|
|
58
|
+
}>>;
|
|
59
|
+
readonly onChange?: IncrSearchChangeCallback<{
|
|
60
|
+
key: string;
|
|
61
|
+
label: string;
|
|
62
|
+
}>;
|
|
63
|
+
};
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region src/incr-search/ac-adapter.d.ts
|
|
66
|
+
/**
|
|
67
|
+
* Creates an ixfx-ac-text-compatible `completionProvider` function from a
|
|
68
|
+
* static item list. Uses synchronous fuzzy search wrapped in a Promise so it
|
|
69
|
+
* fits the async provider signature.
|
|
70
|
+
*
|
|
71
|
+
* Each returned item has `positions` populated with matched character indices,
|
|
72
|
+
* which `ixfx-ac-text` uses to render CSS Custom Highlights on the label.
|
|
73
|
+
*
|
|
74
|
+
* Empty query returns all items in original order (no positions).
|
|
75
|
+
* A cancelled signal causes the returned promise to reject with an AbortError.
|
|
76
|
+
*/
|
|
77
|
+
declare function createAcCompletionProvider<T extends {
|
|
78
|
+
label: string;
|
|
79
|
+
}>(items: readonly T[], options?: Pick<FuzzySearchOptions<T>, `selector`>): (query: string, signal: AbortSignal) => Promise<Array<T & {
|
|
80
|
+
positions: ReadonlySet<number>;
|
|
81
|
+
}>>;
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/incr-search/controller-tree.d.ts
|
|
84
|
+
type IncrSearchTreeOptions = {
|
|
85
|
+
selector: (item: {
|
|
86
|
+
node: TreeNode;
|
|
87
|
+
depth: number;
|
|
88
|
+
}) => string;
|
|
89
|
+
/**
|
|
90
|
+
* CSS selector for the label elements inside the shadow root.
|
|
91
|
+
* Defaults to `.tree-label` (suitable for ixfx-tree-list).
|
|
92
|
+
* Use `.label` for ixfx-miller-list.
|
|
93
|
+
*/
|
|
94
|
+
labelSelector?: string;
|
|
95
|
+
highlightKey?: string;
|
|
96
|
+
input?: HTMLInputElement;
|
|
97
|
+
fzf?: Partial<FzfOptions<{
|
|
98
|
+
node: TreeNode;
|
|
99
|
+
depth: number;
|
|
100
|
+
}>>;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* External-input filter-search controller for `TreeSearchHost` components.
|
|
104
|
+
*
|
|
105
|
+
* @deprecated `ixfx-tree-list` / `ixfx-miller-list` now have a built-in
|
|
106
|
+
* incremental-search popover with navigate / select / filter modes — invoke
|
|
107
|
+
* `el.registry.invoke('list.search.filter')` (see `docs/infra-incremental.md`)
|
|
108
|
+
* instead of wiring an external `<input>`. This class remains for existing
|
|
109
|
+
* consumers and covers filter mode only.
|
|
110
|
+
*
|
|
111
|
+
* @example Using with ixfx-tree-list:
|
|
112
|
+
* ```typescript
|
|
113
|
+
* const ctrl = new IncrSearchTreeController(myTreeList, {
|
|
114
|
+
* selector: item => item.node.item.label,
|
|
115
|
+
* });
|
|
116
|
+
* ctrl.connect();
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @example Using with ixfx-miller-list (different label selector):
|
|
120
|
+
* ```typescript
|
|
121
|
+
* const ctrl = new IncrSearchTreeController(myMillerList, {
|
|
122
|
+
* selector: item => item.node.item.label,
|
|
123
|
+
* labelSelector: '.label',
|
|
124
|
+
* });
|
|
125
|
+
* ctrl.connect();
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
declare class IncrSearchTreeController {
|
|
129
|
+
#private;
|
|
130
|
+
constructor(el: TreeSearchHost, opts: IncrSearchTreeOptions);
|
|
131
|
+
connect(): void;
|
|
132
|
+
disconnect(): void;
|
|
133
|
+
setQuery(query: string): Promise<void>;
|
|
134
|
+
clearQuery(): Promise<void>;
|
|
135
|
+
}
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region src/incr-search/list-search-controller.d.ts
|
|
138
|
+
/**
|
|
139
|
+
* The three things incremental search can do to a list / tree component. See
|
|
140
|
+
* `docs/infra-incremental.md`.
|
|
141
|
+
*
|
|
142
|
+
* - `navigate` — move the cursor to the best match; ↑/↓ cycle between matches;
|
|
143
|
+
* Enter activates the current match and closes.
|
|
144
|
+
* - `select` — (re)select every item whose label matches, live as you type.
|
|
145
|
+
* - `filter` — hide items that don't match; restored when the popover closes.
|
|
146
|
+
*/
|
|
147
|
+
type ListSearchMode = `navigate` | `select` | `filter`;
|
|
148
|
+
/** Canonical order — used for the switch-row and to normalise a requested set. */
|
|
149
|
+
declare const LIST_SEARCH_MODES: readonly ListSearchMode[];
|
|
150
|
+
type SearchItem = {
|
|
151
|
+
readonly key: string;
|
|
152
|
+
readonly label: string;
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Everything {@link ListSearchController} needs to drive a specific host. One is
|
|
156
|
+
* supplied per component; `createElementListSearchAdapter` and
|
|
157
|
+
* `createTreeListSearchAdapter` cover the common shapes.
|
|
158
|
+
*/
|
|
159
|
+
interface ListSearchAdapter<TItem> {
|
|
160
|
+
/** All searchable items, in display order. */
|
|
161
|
+
getItems: () => readonly TItem[];
|
|
162
|
+
/** Text matched against the query. */
|
|
163
|
+
getLabel: (item: TItem) => string;
|
|
164
|
+
/** Stable identity for an item. */
|
|
165
|
+
getKey: (item: TItem) => string;
|
|
166
|
+
/** `navigate`: move the cursor to `item` and reveal it. `undefined` = no-op. */
|
|
167
|
+
focusItem: (item: TItem | undefined) => void;
|
|
168
|
+
/** `navigate` + Enter: activate `item` (falls back to `focusItem`). */
|
|
169
|
+
activateItem?: (item: TItem) => void;
|
|
170
|
+
/** `select` / "Select matches": replace the selection with `items`. */
|
|
171
|
+
selectItems: (items: readonly TItem[]) => void;
|
|
172
|
+
/** `filter`: hide items whose key is not in `matchedKeys`; `undefined` clears the filter. */
|
|
173
|
+
applyFilter: (matchedKeys: ReadonlySet<string> | undefined) => void;
|
|
174
|
+
/** Where matched-character highlights are painted (usually the shadow root). */
|
|
175
|
+
highlightRoot?: () => ShadowRoot | Element | null | undefined;
|
|
176
|
+
/** CSS selector for the label elements inside {@link highlightRoot}. */
|
|
177
|
+
highlightSelector?: string;
|
|
178
|
+
/** Given a label element, the key of the item it belongs to. */
|
|
179
|
+
highlightKeyOf?: (labelEl: Element) => string | undefined;
|
|
180
|
+
/** Text of a label element as fzf saw it (defaults to `el.textContent`). */
|
|
181
|
+
highlightText?: (labelEl: Element) => string;
|
|
182
|
+
/** `CSS.highlights` registry key. Defaults to `incr-search-highlight`. */
|
|
183
|
+
highlightKey?: string;
|
|
184
|
+
/** Element whose child-list mutations should trigger a `refresh()`. */
|
|
185
|
+
container?: () => Element | null | undefined;
|
|
186
|
+
}
|
|
187
|
+
interface ListSearchControllerOptions<TItem> {
|
|
188
|
+
adapter: ListSearchAdapter<TItem>;
|
|
189
|
+
/**
|
|
190
|
+
* Modes this instance offers, as entry points and as in-popover switch
|
|
191
|
+
* targets. The controller intersects this with {@link LIST_SEARCH_MODES}, so
|
|
192
|
+
* pass the intersection of the component's own capability and any
|
|
193
|
+
* consumer-set `search-modes`. Empty ⇒ search disabled. Default: all three.
|
|
194
|
+
*/
|
|
195
|
+
modes?: readonly ListSearchMode[];
|
|
196
|
+
fzf?: Partial<FzfOptions<SearchItem>>;
|
|
197
|
+
placeholder?: string;
|
|
198
|
+
}
|
|
199
|
+
type ListSearchHost = ReactiveControllerHost & HTMLElement & {
|
|
200
|
+
renderRoot?: DocumentFragment | HTMLElement;
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* Shared brain for the three-mode incremental-search popover. A Lit
|
|
204
|
+
* `ReactiveController`: the host adds `listSearchStyles` to `static styles`,
|
|
205
|
+
* drops `${controller.renderField()}` into `render()`, and registers the
|
|
206
|
+
* commands with {@link registerListSearchCommands}. See `docs/infra-incremental.md`.
|
|
207
|
+
*/
|
|
208
|
+
declare class ListSearchController<TItem> implements ReactiveController {
|
|
209
|
+
#private;
|
|
210
|
+
constructor(host: ListSearchHost, options: ListSearchControllerOptions<TItem>);
|
|
211
|
+
/** `false` when no modes are available — the host should register no commands and render no field. */
|
|
212
|
+
get enabled(): boolean;
|
|
213
|
+
/** The modes actually offered (component capability ∩ consumer request). */
|
|
214
|
+
get registeredModes(): readonly ListSearchMode[];
|
|
215
|
+
/**
|
|
216
|
+
* Replace the offered mode set (normalised to {@link LIST_SEARCH_MODES}
|
|
217
|
+
* order). If the current mode is dropped the popover closes and falls back to
|
|
218
|
+
* the first remaining mode. Callers should re-run
|
|
219
|
+
* {@link registerListSearchCommands} afterwards.
|
|
220
|
+
*/
|
|
221
|
+
setModes(modes: readonly ListSearchMode[]): void;
|
|
222
|
+
get isOpen(): boolean;
|
|
223
|
+
get mode(): ListSearchMode;
|
|
224
|
+
get query(): string;
|
|
225
|
+
get matchCount(): number;
|
|
226
|
+
get matchIndex(): number;
|
|
227
|
+
hostConnected(): void;
|
|
228
|
+
hostDisconnected(): void;
|
|
229
|
+
/** Open the popover in `mode` (clamped to the available set). */
|
|
230
|
+
open(mode: ListSearchMode): void;
|
|
231
|
+
/** Close the popover, restoring any live filter. Selection / cursor stay put. */
|
|
232
|
+
close(): void;
|
|
233
|
+
setQuery(query: string): void;
|
|
234
|
+
/** Re-interpret the current query under a new mode (undoing the old mode's effect). */
|
|
235
|
+
switchMode(next: ListSearchMode): void;
|
|
236
|
+
/** One-shot: turn the current match set into the selection, staying in the current mode. */
|
|
237
|
+
selectMatches(): void;
|
|
238
|
+
nextMatch(): void;
|
|
239
|
+
prevMatch(): void;
|
|
240
|
+
/** Enter: in `navigate` activate the current match; then close. */
|
|
241
|
+
commit(): void;
|
|
242
|
+
/** Rebuild the searchable item set from the adapter. Called on open and on container mutation. */
|
|
243
|
+
refresh(): void;
|
|
244
|
+
/** Popover markup. Pair with `listSearchStyles` in the host's `static styles`. */
|
|
245
|
+
renderField(): TemplateResult | typeof nothing;
|
|
246
|
+
}
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src/incr-search/element-list-search-adapter.d.ts
|
|
249
|
+
/**
|
|
250
|
+
* The slice of a list component the element adapter drives. `ixfx-grid-list`,
|
|
251
|
+
* `ixfx-vertical-list` and `ixfx-detail-list` all satisfy it.
|
|
252
|
+
*/
|
|
253
|
+
interface ElementListSearchHost extends HTMLElement {
|
|
254
|
+
focusKey: (key: string) => void;
|
|
255
|
+
selectKeys: (keys: Iterable<string>) => void;
|
|
256
|
+
}
|
|
257
|
+
interface ElementListSearchAdapterOptions {
|
|
258
|
+
/** Selector for item elements, relative to the host. Default `:scope > *`. */
|
|
259
|
+
itemSelector?: string;
|
|
260
|
+
getLabel?: (el: Element) => string;
|
|
261
|
+
getKey?: (el: Element) => string;
|
|
262
|
+
/** `CSS.highlights` registry key for matched-character highlights. */
|
|
263
|
+
highlightKey?: string;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* A {@link ListSearchAdapter} over the light-DOM item elements of a list
|
|
267
|
+
* component. Filter mode toggles `hidden` (only on elements it hid itself, so a
|
|
268
|
+
* consumer's own `hidden` items are left alone). Highlights are painted on the
|
|
269
|
+
* item elements in the light DOM — the consuming page styles
|
|
270
|
+
* `::highlight(<highlightKey>)`. See `docs/infra-incremental.md`.
|
|
271
|
+
*/
|
|
272
|
+
declare function createElementListSearchAdapter(host: ElementListSearchHost, options?: ElementListSearchAdapterOptions): ListSearchAdapter<Element>;
|
|
273
|
+
//#endregion
|
|
274
|
+
//#region src/incr-search/element-search.d.ts
|
|
275
|
+
type ElementItem = {
|
|
276
|
+
readonly key: string;
|
|
277
|
+
readonly label: string;
|
|
278
|
+
};
|
|
279
|
+
type ElementIncrSearch = {
|
|
280
|
+
readonly setQuery: (query: string, signal?: AbortSignal) => Promise<void>;
|
|
281
|
+
readonly clearQuery: () => Promise<void>;
|
|
282
|
+
readonly refresh: () => void;
|
|
283
|
+
readonly onChange: (cb: IncrSearchChangeCallback<ElementItem>) => () => void;
|
|
284
|
+
readonly dispose: () => void;
|
|
285
|
+
};
|
|
286
|
+
/**
|
|
287
|
+
* DOM filter-search over a container's item elements (sets `hidden` on
|
|
288
|
+
* non-matches, applies highlights).
|
|
289
|
+
*
|
|
290
|
+
* @deprecated The list components (`ixfx-grid-list`, `ixfx-vertical-list`,
|
|
291
|
+
* `ixfx-detail-list`, …) now have a built-in navigate / select / filter search
|
|
292
|
+
* popover — see `docs/infra-incremental.md` and `ListSearchController`. Kept for
|
|
293
|
+
* standalone / non-component use.
|
|
294
|
+
*/
|
|
295
|
+
declare function createElementIncrSearch(opts: ElementIncrSearchOptions): ElementIncrSearch;
|
|
296
|
+
//#endregion
|
|
297
|
+
//#region src/incr-search/fuzzy.d.ts
|
|
298
|
+
declare function createFuzzySearch<T>(items: readonly T[], options?: FuzzySearchOptions<T>): FuzzySearch<T>;
|
|
299
|
+
//#endregion
|
|
300
|
+
//#region src/incr-search/highlight.d.ts
|
|
301
|
+
declare function applyHighlights(targets: readonly HighlightTarget[], options?: HighlightOptions): void;
|
|
302
|
+
declare function clearHighlights(options?: HighlightOptions): void;
|
|
303
|
+
declare function buildHighlightTargets<T>(root: ShadowRoot | Element, itemSelector: string, positionsByItem: ReadonlyMap<T, ReadonlySet<number>>, getItem: (el: Element) => T | undefined, getText: (el: Element) => string): HighlightTarget[];
|
|
304
|
+
//#endregion
|
|
305
|
+
//#region src/incr-search/incr-search.d.ts
|
|
306
|
+
declare function createIncrSearch<T>(options?: IncrSearchOptions<T>): IncrSearch<T>;
|
|
307
|
+
//#endregion
|
|
308
|
+
//#region src/incr-search/list-search-commands.d.ts
|
|
309
|
+
/** Command ids registered by {@link registerListSearchCommands}, keyed by mode. */
|
|
310
|
+
declare const LIST_SEARCH_COMMAND_IDS: Readonly<Record<ListSearchMode, string>>;
|
|
311
|
+
interface RegisterListSearchCommandsOptions {
|
|
312
|
+
/**
|
|
313
|
+
* Prefix for command ids, e.g. `grid-list` ⇒ `grid-list.search.filter`. When
|
|
314
|
+
* omitted the shared ids from {@link LIST_SEARCH_COMMAND_IDS} are used so a
|
|
315
|
+
* single dispatch (`ixfx-grouped-item-lister.dispatch('list.search.filter')`)
|
|
316
|
+
* fans out to every list.
|
|
317
|
+
*/
|
|
318
|
+
idPrefix?: string;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Register one command per mode the controller offers (see
|
|
322
|
+
* `controller.registeredModes`). Each command opens the search popover in its
|
|
323
|
+
* mode. Returns a function that unregisters them again — call it from
|
|
324
|
+
* `disconnectedCallback`. See `docs/infra-incremental.md`.
|
|
325
|
+
*/
|
|
326
|
+
declare function registerListSearchCommands<T>(registry: CommandRegistry<unknown>, controller: ListSearchController<T>, options?: RegisterListSearchCommandsOptions): () => void;
|
|
327
|
+
//#endregion
|
|
328
|
+
//#region src/incr-search/list-search-styles.d.ts
|
|
329
|
+
/**
|
|
330
|
+
* Styles for the incremental-search popover rendered by
|
|
331
|
+
* `ListSearchController.renderField()`. Add to a component's `static styles`;
|
|
332
|
+
* the class names are the contract between this fragment and `renderField()`.
|
|
333
|
+
*
|
|
334
|
+
* The host must give the popover a positioned ancestor (a wrapper with
|
|
335
|
+
* `position: relative`, or `:host { position: relative }`). Tunables:
|
|
336
|
+
* `--list-search-inset` (default `8px`) offsets it from the top-right corner.
|
|
337
|
+
*
|
|
338
|
+
* See `docs/infra-incremental.md`.
|
|
339
|
+
*/
|
|
340
|
+
declare const listSearchStyles: import("lit").CSSResult;
|
|
341
|
+
//#endregion
|
|
342
|
+
//#region src/incr-search/tree-list-search-adapter.d.ts
|
|
343
|
+
type TreeSearchItem = {
|
|
344
|
+
node: TreeNode;
|
|
345
|
+
depth: number;
|
|
346
|
+
};
|
|
347
|
+
interface TreeListSearchAdapterOptions {
|
|
348
|
+
/** Label-element selector inside the shadow root. Default `.tree-label`; `ixfx-miller-list` uses `.label`. */
|
|
349
|
+
labelSelector?: string;
|
|
350
|
+
/** `CSS.highlights` registry key for matched-character highlights. */
|
|
351
|
+
highlightKey?: string;
|
|
352
|
+
getLabel?: (item: TreeSearchItem) => string;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* A {@link ListSearchAdapter} over any `TreeSearchHost` (`ixfx-tree-list`,
|
|
356
|
+
* `ixfx-miller-list`, `ixfx-crumb-navigation`). Navigate reveals the match
|
|
357
|
+
* (expands its ancestors, moves the cursor); select drives `selectMany`; filter
|
|
358
|
+
* sets `filterPredicate`. The item set is the whole tree — `getNodes()` returns
|
|
359
|
+
* every node regardless of expansion or an active filter — so refining a query
|
|
360
|
+
* can always re-surface a node. See `docs/infra-incremental.md`.
|
|
361
|
+
*/
|
|
362
|
+
declare function createTreeListSearchAdapter(host: TreeSearchHost, options?: TreeListSearchAdapterOptions): ListSearchAdapter<TreeSearchItem>;
|
|
363
|
+
//#endregion
|
|
364
|
+
export { HighlightTarget as A, IncrSearchTreeController as C, FuzzySearch as D, ElementIncrSearchOptions as E, IncrSearchState as F, IncrSearchChangeCallback as M, IncrSearchOptions as N, FuzzySearchOptions as O, IncrSearchResult as P, ListSearchMode as S, createAcCompletionProvider as T, LIST_SEARCH_MODES as _, RegisterListSearchCommandsOptions as a, ListSearchControllerOptions as b, applyHighlights as c, createFuzzySearch as d, ElementIncrSearch as f, createElementListSearchAdapter as g, ElementListSearchHost as h, LIST_SEARCH_COMMAND_IDS as i, IncrSearch as j, HighlightOptions as k, buildHighlightTargets as l, ElementListSearchAdapterOptions as m, createTreeListSearchAdapter as n, registerListSearchCommands as o, createElementIncrSearch as p, listSearchStyles as r, createIncrSearch as s, TreeListSearchAdapterOptions as t, clearHighlights as u, ListSearchAdapter as v, IncrSearchTreeOptions as w, ListSearchHost as x, ListSearchController as y };
|
|
365
|
+
//# sourceMappingURL=index-CBS4z1v-.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-CBS4z1v-.d.ts","names":[],"sources":["../src/incr-search/types.ts","../src/incr-search/ac-adapter.ts","../src/incr-search/controller-tree.ts","../src/incr-search/list-search-controller.ts","../src/incr-search/element-list-search-adapter.ts","../src/incr-search/element-search.ts","../src/incr-search/fuzzy.ts","../src/incr-search/highlight.ts","../src/incr-search/incr-search.ts","../src/incr-search/list-search-commands.ts","../src/incr-search/list-search-styles.ts","../src/incr-search/tree-list-search-adapter.ts"],"mappings":"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"}
|