@dxos/react-ui-query 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/index.mjs +44 -6
- package/dist/lib/index.mjs.map +1 -1
- package/dist/lib/translations.mjs +13 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/types/src/components/QueryEditor/QueryEditor.d.ts +2 -2
- package/dist/types/src/components/QueryEditor/QueryEditor.d.ts.map +1 -1
- package/dist/types/src/components/QueryForm/Picker.d.ts.map +1 -1
- package/dist/types/src/components/QueryForm/QueryForm.d.ts +2 -2
- package/dist/types/src/components/QueryForm/QueryForm.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/usePersistentQuery.d.ts +20 -0
- package/dist/types/src/hooks/usePersistentQuery.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +17 -17
- package/src/components/QueryEditor/QueryEditor.stories.tsx +1 -1
- package/src/components/QueryEditor/QueryEditor.tsx +5 -4
- package/src/components/QueryForm/Picker.tsx +3 -2
- package/src/components/QueryForm/QueryForm.stories.tsx +1 -1
- package/src/components/QueryForm/QueryForm.tsx +4 -4
- package/src/hooks/index.ts +1 -0
- package/src/hooks/usePersistentQuery.ts +57 -0
- package/src/translations.ts +2 -2
package/dist/lib/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { EditorState, Prec, RangeSetBuilder, StateField } from "@codemirror/state";
|
|
2
2
|
import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { QueryBuilder, QueryDSL, findTagByToken, formatTag } from "@dxos/echo-query";
|
|
4
|
-
import { Select, useThemeMode, useTranslation } from "@dxos/react-ui";
|
|
5
4
|
import { Editor, createMenuGroup } from "@dxos/react-ui-editor";
|
|
5
|
+
import * as Hooks from "@dxos/react-ui/Hooks";
|
|
6
6
|
import { createBasicExtensions, createThemeExtensions, focus, focusField, keymap, staticCompletion, typeahead } from "@dxos/ui-editor";
|
|
7
7
|
import { translationKey } from "#translations";
|
|
8
8
|
import { Filter, Obj, Query, Type } from "@dxos/echo";
|
|
@@ -14,7 +14,9 @@ import { Domino } from "@dxos/ui";
|
|
|
14
14
|
import { getHashHue, getStyles, mx } from "@dxos/ui-theme";
|
|
15
15
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
16
|
import * as Option from "effect/Option";
|
|
17
|
+
import * as Select from "@dxos/react-ui/Select";
|
|
17
18
|
import * as Match from "effect/Match";
|
|
19
|
+
import { useManagerOptional, useViewState, useViewStateActions } from "@dxos/react-ui-attention";
|
|
18
20
|
//#region src/components/QueryEditor/autocomplete.ts
|
|
19
21
|
/**
|
|
20
22
|
* Tag labels as they must appear in the document. Selecting a completion REPLACES the whole trigger
|
|
@@ -465,7 +467,7 @@ var bareTagRanges = (state, tagged) => {
|
|
|
465
467
|
* Query editor with decorations and autocomplete.
|
|
466
468
|
*/
|
|
467
469
|
var QueryEditor = forwardRef(({ db, tags, value, readonly, numItems = 8, onChange, onFilterChange, ...props }, forwardedRef) => {
|
|
468
|
-
const { t } = useTranslation(translationKey);
|
|
470
|
+
const { t } = Hooks.useTranslation(translationKey);
|
|
469
471
|
const getOptions = useMemo(() => completions({
|
|
470
472
|
db,
|
|
471
473
|
tags
|
|
@@ -483,7 +485,7 @@ var QueryEditor = forwardRef(({ db, tags, value, readonly, numItems = 8, onChang
|
|
|
483
485
|
const tagsKey = useMemo(() => Object.values(tags ?? {}).map((tag) => `${tag.id}:${tag.label}:${tag.hue ?? ""}`).join(), [tags]);
|
|
484
486
|
const tagsRef = useRef(tags);
|
|
485
487
|
tagsRef.current = tags;
|
|
486
|
-
const themeMode = useThemeMode();
|
|
488
|
+
const themeMode = Hooks.useThemeMode();
|
|
487
489
|
const extensions = useMemo(() => [
|
|
488
490
|
createBasicExtensions({
|
|
489
491
|
readOnly: readonly,
|
|
@@ -527,7 +529,7 @@ var QueryEditor = forwardRef(({ db, tags, value, readonly, numItems = 8, onChang
|
|
|
527
529
|
//#region src/components/QueryForm/Picker.tsx
|
|
528
530
|
var NULL = "__NULL__";
|
|
529
531
|
var Picker = ({ placeholder, values, value, onChange }) => {
|
|
530
|
-
const { t } = useTranslation(translationKey);
|
|
532
|
+
const { t } = Hooks.useTranslation(translationKey);
|
|
531
533
|
const sorted = useMemo(() => values?.sort(({ label: a }, { label: b }) => a.localeCompare(b)) ?? [], [values]);
|
|
532
534
|
return /* @__PURE__ */ jsxs(Select.Root, {
|
|
533
535
|
items: [{
|
|
@@ -570,7 +572,7 @@ var extractTagFromFilter = (filter) => {
|
|
|
570
572
|
//#endregion
|
|
571
573
|
//#region src/components/QueryForm/QueryForm.tsx
|
|
572
574
|
var QueryForm = ({ classNames, initialQuery, types, tags, onChange }) => {
|
|
573
|
-
const { t } = useTranslation(translationKey);
|
|
575
|
+
const { t } = Hooks.useTranslation(translationKey);
|
|
574
576
|
const initialType = initialQuery ? Option.getOrUndefined(extractTypename(initialQuery)) : void 0;
|
|
575
577
|
const initialTag = initialQuery ? Option.getOrUndefined(extractTag(initialQuery)) : void 0;
|
|
576
578
|
const [type, setType] = useState(initialType ?? null);
|
|
@@ -632,6 +634,42 @@ var useQueryBuilder = (query) => {
|
|
|
632
634
|
return filter;
|
|
633
635
|
};
|
|
634
636
|
//#endregion
|
|
635
|
-
|
|
637
|
+
//#region src/hooks/usePersistentQuery.ts
|
|
638
|
+
/**
|
|
639
|
+
* A list's filter query, held in a `ViewState` aspect (so it persists per device and per `contextId`)
|
|
640
|
+
* and mirrored into the {@link QueryEditor} behind `editorRef`.
|
|
641
|
+
*
|
|
642
|
+
* The editor takes its text once, as `initialValue`, so a write that did not come from typing — a
|
|
643
|
+
* picker over the same text, clear, another view of the same list, another tab — is pushed into it
|
|
644
|
+
* here. Pushed from the subscription rather than from a render effect: the subscription fires as the
|
|
645
|
+
* value is written, when the editor already holds whatever was just typed, whereas an effect can run
|
|
646
|
+
* for a render that trails fast typing and rewrite the document back to older text.
|
|
647
|
+
*/
|
|
648
|
+
var usePersistentQuery = (aspect, contextId, editorRef) => {
|
|
649
|
+
const manager = useManagerOptional();
|
|
650
|
+
const { query } = useViewState(aspect, contextId);
|
|
651
|
+
const { update } = useViewStateActions(aspect, contextId);
|
|
652
|
+
useEffect(() => {
|
|
653
|
+
if (!manager || !contextId) return;
|
|
654
|
+
return manager.subscribe(aspect, contextId, ({ query }) => {
|
|
655
|
+
const editor = editorRef.current;
|
|
656
|
+
if (editor && editor.getText() !== query) editor.setText(query);
|
|
657
|
+
});
|
|
658
|
+
}, [
|
|
659
|
+
manager,
|
|
660
|
+
aspect,
|
|
661
|
+
contextId,
|
|
662
|
+
editorRef
|
|
663
|
+
]);
|
|
664
|
+
return [query, useCallback((next) => update((view) => {
|
|
665
|
+
const query = typeof next === "function" ? next(view.query) : next;
|
|
666
|
+
return view.query === query ? view : {
|
|
667
|
+
...view,
|
|
668
|
+
query
|
|
669
|
+
};
|
|
670
|
+
}), [update])];
|
|
671
|
+
};
|
|
672
|
+
//#endregion
|
|
673
|
+
export { QueryEditor, QueryForm, usePersistentQuery, useQueryBuilder };
|
|
636
674
|
|
|
637
675
|
//# sourceMappingURL=index.mjs.map
|
package/dist/lib/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/components/QueryEditor/autocomplete.ts","../../src/components/QueryEditor/query-extension.ts","../../src/components/QueryEditor/QueryEditor.tsx","../../src/components/QueryForm/Picker.tsx","../../src/components/QueryForm/query.ts","../../src/components/QueryForm/QueryForm.tsx","../../src/hooks/useQueryBuilder.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Database, type Tag, Type } from '@dxos/echo';\nimport { QueryDSL, formatTag } from '@dxos/echo-query';\nimport { type GetMenuContext } from '@dxos/react-ui-editor';\n\nexport type CompletionOptions = {\n db?: Database.Database;\n tags?: Tag.Map;\n};\n\n/**\n * Tag labels as they must appear in the document. Selecting a completion REPLACES the whole trigger\n * range, `#` included, and inserts the item verbatim — so an unprefixed label would silently drop the\n * `#` and leave text that no longer parses as a tag.\n */\nconst tagCompletions = (tags: Tag.Map): string[] => Object.values(tags).map((tag) => formatTag(tag.label));\n\n/**\n * Whether the caret sits in a tag the user is still typing: a `#` at the start of the current word,\n * with only label characters between it and `pos`.\n */\nconst isTypingTag = (text: string, pos: number): boolean => {\n let index = pos;\n while (index > 0 && /[a-zA-Z0-9_-]/.test(text[index - 1])) {\n index--;\n }\n\n return index > 0 && text[index - 1] === '#';\n};\n\nexport const completions = ({ db, tags }: CompletionOptions) => {\n const parser = QueryDSL.Parser.configure({ strict: false });\n return ({ state, pos }: GetMenuContext): string[] => {\n const text = state.sliceDoc();\n const tree = parser.parse(text);\n const { node } = tree.cursorAt(pos, -1);\n\n // A `#` with no label yet is an error node, not a `TagFilter` — the grammar needs a label\n // character before it accepts one — so the tree cannot answer for the keystroke that opens a tag.\n // Inside a string it is content, so the tree is still what settles that.\n if (tags && isTypingTag(text, pos) && node.type.id !== QueryDSL.Node.String) {\n return tagCompletions(tags);\n }\n\n switch (node.parent?.type.id) {\n case QueryDSL.Node.TypeFilter: {\n let range: { from: number; to: number } | undefined;\n if (node?.type.id === QueryDSL.Node.Identifier) {\n range = { from: node.from, to: node.to };\n } else if (node?.type.name === ':') {\n range = { from: node.from + 1, to: node.to };\n }\n\n if (range) {\n const schema = db ? [...db.graph.registry.list().filter(Type.isType)] : [];\n return schema.map((schema) => Type.getTypename(schema));\n }\n\n break;\n }\n\n case QueryDSL.Node.TagFilter: {\n if (tags) {\n return tagCompletions(tags);\n }\n\n break;\n }\n }\n\n return [];\n };\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { HighlightStyle, LanguageSupport, LRLanguage, syntaxHighlighting, syntaxTree } from '@codemirror/language';\nimport { EditorState, type Extension, RangeSetBuilder, StateField, type TransactionSpec } from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, WidgetType } from '@codemirror/view';\nimport { type SyntaxNodeRef } from '@lezer/common';\nimport { styleTags, tags as t } from '@lezer/highlight';\nimport JSON5 from 'json5';\n\nimport { type Tag } from '@dxos/echo';\nimport { QueryDSL, findTagByToken } from '@dxos/echo-query';\nimport { Domino } from '@dxos/ui';\nimport { type CompletionContext, focus, focusField, staticCompletion, typeahead } from '@dxos/ui-editor';\nimport { getHashHue, getStyles, mx } from '@dxos/ui-theme';\n\nexport type QueryOptions = {\n tags?: Tag.Map;\n};\n\n/**\n * Create a CodeMirror extension for the query language with syntax highlighting.\n */\nexport const query = ({ tags }: QueryOptions = {}): Extension => {\n return [\n new LanguageSupport(queryLanguage),\n syntaxHighlighting(queryHighlightStyle),\n decorations({ tags }),\n spacing,\n typeahead({\n onComplete: ({ line }: CompletionContext) => {\n const words = line.split(/\\s+/).filter(Boolean);\n if (words.length > 0) {\n // TODO(burdon): Get suggestion from parser.\n return staticCompletion(['type:', 'AND', 'OR', 'NOT'])({ line });\n }\n },\n }),\n focus,\n styles,\n ];\n};\n\n/**\n * The extension's decorations for a given state.\n *\n * Exported as a pure function of `(state, options)` so the atomicity rules — which govern whether a\n * tag can still be edited — are testable without mounting an `EditorView`.\n */\nexport const buildQueryDecorations = (state: EditorState, { tags }: QueryOptions = {}): DecorationSet => {\n {\n const hasFocus = state.field(focusField);\n const isInside = (node: SyntaxNodeRef) => {\n const range = intersectRanges(state.selection.main, node);\n return hasFocus && range && (state.selection.main.from > 0 || range.to - range.from > 0);\n };\n\n // Collected rather than fed straight to a `RangeSetBuilder`, which demands ascending `from`:\n // the bare-`#` ranges below come from a document scan and interleave with the tree's own.\n const collected: { from: number; to: number; deco: Decoration }[] = [];\n const deco = {\n add: (from: number, to: number, value: Decoration) => collected.push({ from, to, deco: value }),\n };\n const tagged: Range[] = [];\n syntaxTree(state).iterate({\n enter: (node) => {\n if (node.type.id === QueryDSL.Node.Tag) {\n tagged.push({ from: node.from, to: node.to });\n }\n switch (node.type.name) {\n case '(':\n case ')': {\n deco.add(\n node.from,\n node.to,\n Decoration.mark({\n class: 'px-1',\n }),\n );\n break;\n }\n\n case '=': {\n deco.add(\n node.from,\n node.to,\n Decoration.mark({\n class: 'text-fg-subtle',\n }),\n );\n break;\n }\n }\n\n switch (node.type.id) {\n case QueryDSL.Node.TypeFilter: {\n if (isInside(node)) {\n break;\n }\n\n const identifier = node.node.getChild(QueryDSL.Node.Identifier);\n if (identifier) {\n deco.add(\n node.from,\n node.to,\n Decoration.widget({\n widget: new TypeWidget(state.sliceDoc(identifier.from, identifier.to)),\n }),\n );\n }\n break;\n }\n\n case QueryDSL.Node.TagFilter: {\n const tagNode = node.node.getChild(QueryDSL.Node.Tag);\n if (tagNode) {\n const token = state.sliceDoc(tagNode.from, tagNode.to);\n const match = findTagByToken(tags, token);\n // The chip names the tag as the user wrote it, not the token form it had to be typed in.\n const label = match?.tag.label ?? token.slice(1);\n const hue = match?.tag.hue ?? getHashHue(match?.key ?? label);\n // Atomic at its own edges too, so Backspace against a tag takes the chip rather than a\n // character of the label; typing still grows it, since an insertion at the range's\n // boundary lands outside it.\n //\n // `replace`, not `widget`: a widget is a POINT decoration, so one covering a range that\n // starts at offset 0 paints before that offset's coordinate and the caret draws to its\n // right — pressing Home appeared to leave the caret after the tag.\n deco.add(node.from, node.to, Decoration.replace({ widget: new TagWidget(label, hue), atomic: true }));\n }\n break;\n }\n\n case QueryDSL.Node.ObjectLiteral: {\n if (isInside(node)) {\n break;\n }\n\n try {\n const props = JSON5.parse(state.sliceDoc(node.from, node.to));\n if (props) {\n deco.add(\n node.from,\n node.to,\n Decoration.widget({\n widget: new ObjectWidget(props),\n }),\n );\n }\n } catch {\n // Ignore malformed JSON.\n }\n break;\n }\n\n case QueryDSL.Node.Not:\n case QueryDSL.Node.And:\n case QueryDSL.Node.Or: {\n deco.add(\n node.from,\n node.to,\n Decoration.mark({\n class: 'pe-1 uppercase',\n atomic: true,\n }),\n );\n break;\n }\n\n case QueryDSL.Node.ArrowRight:\n case QueryDSL.Node.ArrowLeft: {\n deco.add(\n node.from,\n node.to,\n Decoration.widget({\n widget: new SymbolWidget(node.type.id === QueryDSL.Node.ArrowRight ? '\\u2192' : '\\u2190'),\n atomic: true,\n }),\n );\n break;\n }\n\n // default: {\n // console.log(node.type.name);\n // }\n }\n },\n });\n\n // A `#` with no label yet parses as an error, not a `Tag`, so the tree cannot decorate it — but\n // the affordance has to appear on the keystroke that opens the tag, not once it is valid.\n // A lone `#` is an error node, not a `Tag` — the grammar needs a label character — so it gets a\n // plain highlight until the first one arrives and the chip takes over.\n for (const range of bareTagRanges(state, tagged)) {\n collected.push({\n from: range.from,\n to: range.to,\n deco: Decoration.mark({ class: mx('rounded-xs px-0.5', getStyles(getHashHue('')).surface) }),\n });\n }\n\n const builder = new RangeSetBuilder<Decoration>();\n // Equal starts sort WIDEST first so an enclosing mark (the chip's border) nests the inner ones.\n collected.sort((a, b) => a.from - b.from || b.to - a.to);\n for (const { from, to, deco } of collected) {\n builder.add(from, to, deco);\n }\n\n return builder.finish();\n }\n};\n\n/**\n * Decorations\n */\nconst decorations = ({ tags }: QueryOptions): Extension => {\n return [\n StateField.define<DecorationSet>({\n create: (state) => buildQueryDecorations(state, { tags }),\n update: (deco, tr) => {\n if (tr.docChanged || tr.newSelection) {\n return buildQueryDecorations(tr.state, { tags });\n }\n\n return deco;\n },\n provide: (field) => [\n EditorView.decorations.from(field),\n EditorView.atomicRanges.of((view) => {\n const builder = new RangeSetBuilder<Decoration>();\n const cursor = view.state.field(field).iter();\n while (cursor.value) {\n if (cursor.value.spec.atomic) {\n builder.add(cursor.from, cursor.to, cursor.value);\n }\n cursor.next();\n }\n\n return builder.finish();\n }),\n ],\n }),\n ];\n};\n\n/**\n * Keeps typed text from being glued onto a tag chip.\n *\n * Two rules, both applied as follow-up changes so the user's own transaction is left intact:\n * 1. Text typed immediately before a tag is separated from it by a space.\n * 2. An insertion leaves a trailing space at the end of the document, so there is always somewhere to\n * type that is not adjacent to a chip. Deletions are exempt, or backspace at the end of the\n * document would only ever delete a space this rule puts straight back.\n */\nexport const spacing: Extension = EditorState.transactionFilter.of((tr) => {\n if (!tr.docChanged) {\n return tr;\n }\n\n const tagStarts = new Set<number>();\n syntaxTree(tr.startState).iterate({\n enter: (node) => {\n if (node.type.id === QueryDSL.Node.Tag) {\n tagStarts.add(node.from);\n }\n },\n });\n\n let inserting = false;\n let separator: number | undefined;\n tr.changes.iterChanges((fromA, toA, _fromB, toB, inserted) => {\n if (!inserted.length) {\n return;\n }\n\n inserting = true;\n // Keyed on `toA`, the offset the inserted text ends against: that covers a replacement whose\n // range ends at the tag as well as a plain insertion, where `fromA` and `toA` are the same.\n if (tagStarts.has(toA) && !/\\s$/.test(inserted.toString())) {\n separator = toB;\n }\n });\n\n const specs: TransactionSpec[] = [tr];\n let text = tr.newDoc.toString();\n if (separator !== undefined) {\n specs.push({ changes: { from: separator, insert: ' ' }, sequential: true });\n text = text.slice(0, separator) + ' ' + text.slice(separator);\n }\n if (inserting && text.length > 0 && !/\\s$/.test(text)) {\n specs.push({ changes: { from: text.length, insert: ' ' }, sequential: true });\n }\n\n return specs;\n});\n\nconst lineHeight = '30px';\n\n/** The outer box vertically aligns the inner text with content in the outer div. */\nconst CHIP_OUTER = 'inline-flex h-[28px] align-middle';\nconst CHIP_INNER = 'inline-flex h-[26px] border rounded-xs';\n\nconst container = (classNames: string, ...children: Domino<HTMLElement>[]) => {\n const inner = Domino.of('span')\n .classNames(mx(CHIP_INNER, classNames))\n .append(...children);\n return Domino.of('span').classNames(CHIP_OUTER).append(inner).root;\n};\n\n/** A tag chip's parts, keyed by the nesting {@link container} produces. */\nconst chipClasses = (hue: string) => {\n const { bg, fg, surface } = getStyles(hue);\n return {\n hash: mx('flex items-center px-1 text-black text-xs', bg),\n label: mx('flex items-center px-1 text-sm', surface, fg),\n };\n};\n\n/**\n * TypeKeyword:Identifier\n */\nclass TypeWidget extends WidgetType {\n constructor(private readonly _identifier: string) {\n super();\n }\n\n override ignoreEvent() {\n return false;\n }\n\n override eq(other: this) {\n return this._identifier === other._identifier;\n }\n\n override toDOM() {\n const label: string = this._identifier.split(/\\W/).at(-1)!;\n return container(\n 'border-sky-500',\n Domino.of('span').classNames(mx('flex items-center px-1 text-black text-xs bg-sky-500')).text('type'),\n Domino.of('span').classNames(mx('flex items-center px-1 text-fg-muted')).text(label),\n );\n }\n}\n\n/**\n * Tag\n */\nclass TagWidget extends WidgetType {\n constructor(\n private readonly _str: string,\n private readonly _hue: string,\n ) {\n super();\n }\n\n override eq(other: this) {\n return this._str === other._str;\n }\n\n override toDOM() {\n const { hash, label } = chipClasses(this._hue);\n return container(\n getStyles(this._hue).border,\n Domino.of('span').classNames(hash).text('#'),\n Domino.of('span').classNames(label).text(this._str),\n );\n }\n}\n\n/**\n * { type: \"value\" }\n */\nclass ObjectWidget extends WidgetType {\n private readonly _entries: [string, any][];\n private readonly _json: string;\n\n constructor(private readonly _props: any) {\n super();\n this._entries = Object.entries(this._props);\n this._json = JSON.stringify(this._props);\n }\n\n override ignoreEvent() {\n return false;\n }\n\n override eq(other: this) {\n return this._json === other._json;\n }\n\n override toDOM() {\n return container(\n 'border-separator divide-x divide-separator',\n ...this._entries.map(([key, value]) => {\n const keyEl = Domino.of('span')\n .classNames('flex items-center px-1 text-fg-muted text-xs bg-modal-surface first:rounded-l-xs')\n .text(key);\n const valueEl = Domino.of('span').classNames('flex items-center px-1 text-fg-muted').text(value);\n return Domino.of('span').classNames('inline-flex items-stretch').append(keyEl, valueEl);\n }),\n );\n }\n}\n\n/**\n * Symbol\n */\nclass SymbolWidget extends WidgetType {\n constructor(private readonly _str: string) {\n super();\n }\n\n override eq(other: this) {\n return this._str === other._str;\n }\n\n override toDOM() {\n return Domino.of('span').text(this._str).root;\n }\n}\n\nconst styles = EditorView.theme({\n '.cm-line': {\n lineHeight,\n },\n // Match the standard Input block size (md density): 2.5rem, 2rem on pointer-fine devices.\n '.cm-scroller': {\n alignItems: 'center',\n minHeight: '2.5rem',\n },\n '@media (pointer: fine)': {\n '.cm-scroller': {\n minHeight: '2rem',\n },\n },\n});\n\n/**\n * Define syntax highlighting tags for the query language.\n */\nconst queryHighlighting = styleTags({\n // Keywords\n 'Not And Or': t.keyword,\n 'TypeKeyword': t.attributeName,\n\n // Literals\n 'String': t.string,\n 'Number': t.number,\n 'Boolean': t.bool,\n 'Null': t.null,\n\n // Identifiers\n // NOT `Tag`: it is drawn as a chip, whose own foreground would be fighting a highlight class here.\n 'Identifier': t.variableName,\n 'PropertyPath': t.propertyName,\n\n // Punctuation\n '{ }': t.brace,\n '[ ]': t.squareBracket,\n '( )': t.paren,\n ':': t.definitionOperator,\n ',': t.separator,\n '.': t.derefOperator,\n});\n\n/**\n * Create the query language with the parser and highlighting.\n */\nconst queryLanguage = LRLanguage.define({\n parser: QueryDSL.Parser.configure({\n props: [queryHighlighting],\n strict: false,\n }),\n languageData: {\n commentTokens: { line: '//' },\n },\n});\n\n/**\n * Define a custom highlight style for the query language.\n */\nconst queryHighlightStyle = HighlightStyle.define([\n { tag: t.keyword, class: 'text-blue-text' },\n { tag: t.string, class: 'text-orange-text' },\n { tag: t.number, class: 'text-green-text' },\n { tag: t.bool, class: 'text-green-text' },\n { tag: t.null, class: 'text-neutral-text' },\n { tag: t.attributeName, class: 'text-blue-text' },\n { tag: t.variableName, class: 'text-teal-text' },\n { tag: t.propertyName, class: 'text-teal-text' },\n { tag: t.definitionOperator, class: 'text-fg-subtle' },\n { tag: t.separator, class: 'text-fg-subtle' },\n { tag: t.derefOperator, class: 'text-fg-subtle' },\n { tag: t.brace, class: 'text-fg-subtle' },\n { tag: t.squareBracket, class: 'text-fg-subtle' },\n { tag: t.operator, class: 'text-fg-subtle' },\n { tag: t.paren, class: 'text-amber-text' },\n]);\n\ntype Range = { from: number; to: number };\nfunction intersectRanges(a: Range, b: Range): Range | null {\n const start = Math.max(a.from, b.from);\n const end = Math.min(a.to, b.to);\n return start <= end ? { from: start, to: end } : null;\n}\n\n/** Label characters the grammar admits after `#` (`Tag { \"#\" $[a-zA-Z0-9_\\-]+ }`). */\nconst TAG_LABEL_CHAR = /[a-zA-Z0-9_-]/;\n\n/**\n * Ranges of an in-progress tag — a `#` the parser has not yet accepted as a {@link QueryDSL.Node.Tag},\n * because the grammar requires at least one label character after it. Skips offsets the tree already\n * claimed, and any `#` inside a string, where it is content rather than a tag.\n */\nconst bareTagRanges = (state: EditorState, tagged: readonly Range[]): Range[] => {\n const ranges: Range[] = [];\n const text = state.sliceDoc();\n const covered = (index: number) => tagged.some(({ from, to }) => index >= from && index < to);\n for (let index = text.indexOf('#'); index !== -1; index = text.indexOf('#', index + 1)) {\n if (covered(index) || syntaxTree(state).resolveInner(index, 1).type.id === QueryDSL.Node.String) {\n continue;\n }\n let end = index + 1;\n while (end < text.length && TAG_LABEL_CHAR.test(text[end])) {\n end++;\n }\n ranges.push({ from: index, to: end });\n }\n\n return ranges;\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Extension, Prec } from '@codemirror/state';\nimport React, { forwardRef, useCallback, useMemo, useRef } from 'react';\n\nimport { type BuildResult, QueryBuilder } from '@dxos/echo-query';\nimport { type ThemedClassName, useThemeMode, useTranslation } from '@dxos/react-ui';\nimport {\n Editor,\n type EditorController,\n type EditorMenuProviderProps,\n type EditorViewProps,\n type UseEditorMenuProps,\n createMenuGroup,\n} from '@dxos/react-ui-editor';\nimport { createBasicExtensions, createThemeExtensions, keymap } from '@dxos/ui-editor';\n\nimport { translationKey } from '#translations';\n\nimport { type CompletionOptions, completions } from './autocomplete.ts';\nimport { query } from './query-extension.ts';\n\nexport type QueryEditorProps = ThemedClassName<\n {\n value?: string;\n readonly?: boolean;\n /**\n * The parsed query, rebuilt on every edit. `filter` is undefined while the text does not parse,\n * which is what a caller gates a \"save this view\" affordance on.\n *\n * Supplying this is what opts the editor into building a filter at all — the DSL is otherwise\n * parsed only for decoration, and a caller that wants the raw text pays nothing for a parse it\n * will not read.\n */\n onFilterChange?: (result: BuildResult) => void;\n } & (CompletionOptions & Omit<EditorViewProps, 'initialValue'> & Pick<EditorMenuProviderProps, 'numItems'>)\n>;\n\n/**\n * Query editor with decorations and autocomplete.\n */\nexport const QueryEditor = forwardRef<EditorController, QueryEditorProps>(\n ({ db, tags, value, readonly, numItems = 8, onChange, onFilterChange, ...props }, forwardedRef) => {\n const { t } = useTranslation(translationKey);\n\n const getOptions = useMemo(() => completions({ db, tags }), [db, tags]);\n const getMenu = useCallback<NonNullable<UseEditorMenuProps['getMenu']>>(\n async (context) => [createMenuGroup({ items: getOptions(context) })],\n [getOptions],\n );\n\n // The editor owns the parse that used to be repeated by every consumer: the DSL was already being\n // parsed here for decorations, so a caller building its own `QueryBuilder` parsed each keystroke\n // twice.\n const builder = useMemo(() => (onFilterChange ? new QueryBuilder(tags) : undefined), [onFilterChange, tags]);\n const handleChange = useCallback(\n (doc: string) => {\n onChange?.(doc);\n if (builder) {\n onFilterChange?.(builder.build(doc));\n }\n },\n [onChange, onFilterChange, builder],\n );\n\n // Keyed on the tag map's CONTENTS, not its identity: callers rebuild the map each render, and\n // `useTextEditor` destroys and recreates the view whenever `extensions` changes — so depending on\n // the object blurred the editor on every keystroke.\n const tagsKey = useMemo(\n () =>\n Object.values(tags ?? {})\n .map((tag) => `${tag.id}:${tag.label}:${tag.hue ?? ''}`)\n .join(),\n [tags],\n );\n const tagsRef = useRef(tags);\n tagsRef.current = tags;\n\n const themeMode = useThemeMode();\n const extensions = useMemo<Extension[]>(\n () => [\n createBasicExtensions({\n readOnly: readonly,\n lineWrapping: false,\n placeholder: t('query-editor.placeholder'),\n // A single-line query gains nothing from bracket matching, and CodeMirror's default paints\n // `.cm-matchingBracket` with a background while focused — a coloured wash over the braces of\n // an object literal the moment the caret reaches it.\n bracketMatching: false,\n }),\n createThemeExtensions({ themeMode, slots: { scroller: { className: 'scrollbar-none' } } }),\n query({ tags: tagsRef.current }),\n Prec.highest(\n keymap.of([\n {\n key: 'Enter',\n run: () => {\n // Prevent newline.\n return true;\n },\n },\n ]),\n ),\n ],\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [readonly, themeMode, tagsKey],\n );\n\n return (\n <Editor.Root\n ref={forwardedRef}\n extensions={extensions}\n numItems={numItems}\n // `#` opens the tag list. `:` cannot be a trigger — `popoverKeymap` only fires one at a line\n // start or after a space, and a typename's colon follows `type`; `activateOnTyping` covers it\n // instead, since `:` is a completion delimiter so the word under the caret is the typename.\n // The explicit key stays, for re-opening a dismissed menu.\n trigger={['#']}\n // NOT `activateOnTyping`: that opens the menu on every word character, and the popover takes\n // focus each keystroke while returning nothing for most positions. `:` is the only delimiter\n // with a list behind it, so the typename menu opens there and nowhere else.\n activateOnDelimiters={[':']}\n triggerKey='Ctrl-Space'\n getMenu={getMenu}\n >\n {/* `initialValue`, never the controlled `value`: the sync effect behind `value` compares the\n prop against the document a frame later, and a caller whose state trails fast typing then\n rewrites the document back to the older text, dropping characters. A caller rewriting the\n query itself does it through `EditorController.setText`. */}\n <Editor.View {...props} initialValue={value} onChange={handleChange} selectionEnd />\n </Editor.Root>\n );\n },\n);\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { useMemo } from 'react';\n\nimport { Select, useTranslation } from '@dxos/react-ui';\n\nimport { translationKey } from '#translations';\n\nconst NULL = '__NULL__';\n\nexport type PickerProps<T extends { value: string; label: string }> = {\n placeholder?: string;\n values?: T[];\n value?: string | null;\n onChange?: (value: string | null) => void;\n};\n\n// TODO(wittjosiah): Should use `SelectInput` from `react-ui-form` instead.\nexport const Picker = <T extends { value: string; label: string }>({\n placeholder,\n values,\n value,\n onChange,\n}: PickerProps<T>) => {\n const { t } = useTranslation(translationKey);\n const sorted = useMemo(() => values?.sort(({ label: a }, { label: b }) => a.localeCompare(b)) ?? [], [values]);\n\n return (\n <Select.Root\n items={[{ value: NULL, label: t('picker-none.label') }, ...sorted]}\n value={[value ?? NULL]}\n onValueChange={({ value: [value] }) => onChange?.(value === NULL ? null : value)}\n >\n <Select.Trigger placeholder={placeholder ?? t('picker-select.label')} />\n <Select.Content>\n <Select.ItemGroup>\n <Select.Item item={{ value: NULL, label: t('picker-none.label') }} />\n {sorted.map(({ value, label }) => (\n <Select.Item key={value} item={{ value: value, label: label }} />\n ))}\n </Select.ItemGroup>\n </Select.Content>\n </Select.Root>\n );\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Match from 'effect/Match';\nimport * as Option from 'effect/Option';\n\nimport { type QueryAST } from '@dxos/echo';\nimport { type URI } from '@dxos/keys';\n\n// Helper to extract type URI from query AST\nexport const extractTypename = (query: QueryAST.Query): Option.Option<URI.URI> => {\n return Match.value(query).pipe(\n Match.withReturnType<Option.Option<URI.URI>>(),\n Match.when({ type: 'select' }, (q) => extractTypenameFromFilter(q.filter)),\n Match.when({ type: 'filter' }, (q) => {\n const selectionTypename = extractTypename(q.selection);\n const filterTypename = extractTypenameFromFilter(q.filter);\n return Option.isSome(selectionTypename) ? selectionTypename : filterTypename;\n }),\n Match.when({ type: 'options' }, (q) => extractTypename(q.query)),\n Match.when({ type: 'from' }, (q) => extractTypename(q.query)),\n Match.when({ type: 'order' }, (q) => extractTypename(q.query)),\n Match.when({ type: 'limit' }, (q) => extractTypename(q.query)),\n Match.orElse(() => Option.none()),\n );\n};\n\n// Helper to extract tag from query AST\nexport const extractTag = (query: QueryAST.Query): Option.Option<string> => {\n return Match.value(query).pipe(\n Match.withReturnType<Option.Option<string>>(),\n Match.when({ type: 'select' }, (q) => extractTagFromFilter(q.filter)),\n Match.when({ type: 'filter' }, (q) => {\n const selectionTag = extractTag(q.selection);\n const filterTag = extractTagFromFilter(q.filter);\n return Option.isSome(filterTag) ? filterTag : selectionTag;\n }),\n Match.when({ type: 'options' }, (q) => extractTag(q.query)),\n Match.when({ type: 'from' }, (q) => extractTag(q.query)),\n Match.when({ type: 'order' }, (q) => extractTag(q.query)),\n Match.when({ type: 'limit' }, (q) => extractTag(q.query)),\n Match.orElse(() => Option.none()),\n );\n};\n\n// Helper to extract type URI from filter AST\nconst extractTypenameFromFilter = (filter: QueryAST.Filter): Option.Option<URI.URI> => {\n return Match.value(filter).pipe(\n Match.withReturnType<Option.Option<URI.URI>>(),\n Match.when({ type: 'object' }, (f) => Option.fromNullishOr(f.typename)),\n Match.when({ type: 'and' }, (f) =>\n f.filters.reduce(\n (acc: Option.Option<URI.URI>, filterItem: QueryAST.Filter) =>\n Option.isSome(acc) ? acc : extractTypenameFromFilter(filterItem),\n Option.none<URI.URI>(),\n ),\n ),\n Match.when({ type: 'or' }, (f) =>\n f.filters.reduce(\n (acc: Option.Option<URI.URI>, filterItem: QueryAST.Filter) =>\n Option.isSome(acc) ? acc : extractTypenameFromFilter(filterItem),\n Option.none<URI.URI>(),\n ),\n ),\n Match.orElse(() => Option.none()),\n );\n};\n\n// Helper to extract tag from filter AST\nconst extractTagFromFilter = (filter: QueryAST.Filter): Option.Option<string> => {\n return Match.value(filter).pipe(\n Match.withReturnType<Option.Option<string>>(),\n Match.when({ type: 'tag' }, (f) => Option.some(f.tag)),\n Match.when({ type: 'and' }, (f) =>\n f.filters.reduce(\n (acc: Option.Option<string>, filterItem: QueryAST.Filter) =>\n Option.isSome(acc) ? acc : extractTagFromFilter(filterItem),\n Option.none<string>(),\n ),\n ),\n Match.when({ type: 'or' }, (f) =>\n f.filters.reduce(\n (acc: Option.Option<string>, filterItem: QueryAST.Filter) =>\n Option.isSome(acc) ? acc : extractTagFromFilter(filterItem),\n Option.none<string>(),\n ),\n ),\n Match.orElse(() => Option.none()),\n );\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Option from 'effect/Option';\nimport React, { useCallback, useMemo, useState } from 'react';\n\nimport { Filter, Obj, Query, type QueryAST, type Tag } from '@dxos/echo';\nimport { URI } from '@dxos/keys';\nimport { type ThemedClassName } from '@dxos/react-ui';\nimport { useTranslation } from '@dxos/react-ui';\nimport { mx } from '@dxos/ui-theme';\n\nimport { translationKey } from '#translations';\n\nimport { Picker } from './Picker.tsx';\nimport { extractTag, extractTypename } from './query.ts';\n\nexport type QueryFormProps = ThemedClassName<{\n initialQuery?: QueryAST.Query;\n types?: { value: URI.URI; label: string }[];\n tags?: Tag.Tag[];\n onChange?: (query: Query.Any) => void;\n}>;\n\n// TODO(wittjosiah): Support more complex queries and traversals.\nexport const QueryForm = ({ classNames, initialQuery, types, tags, onChange }: QueryFormProps) => {\n const { t } = useTranslation(translationKey);\n\n const initialType = initialQuery ? Option.getOrUndefined(extractTypename(initialQuery)) : undefined;\n const initialTag = initialQuery ? Option.getOrUndefined(extractTag(initialQuery)) : undefined;\n\n const [type, setType] = useState<URI.URI | null>(initialType ?? null);\n const [tag, setTag] = useState<string | null>(initialTag ?? null);\n\n const tagOptions = useMemo(() => tags?.map((tag) => ({ value: Obj.getURI(tag), label: tag.label })), [tags]);\n\n const handleChange = useCallback(\n ({ type, tag }: { type: URI.URI | null; tag: string | null }) => {\n const typeFilter = type ? Filter.type(type) : null;\n const tagFilter = tag ? Filter.tag(tag) : null;\n const combined =\n typeFilter && tagFilter ? Filter.and(typeFilter, tagFilter) : (typeFilter ?? tagFilter ?? Filter.nothing());\n onChange?.(Query.select(combined));\n },\n [onChange],\n );\n\n const handleTypeChange = useCallback(\n (value: string | null) => {\n // Select.onValueChange returns bare string; values come from types[].value which are URI.URI.\n const uri = value as URI.URI | null;\n setType(uri);\n handleChange({ type: uri, tag });\n },\n [handleChange, tag],\n );\n\n const handleTagChange = useCallback(\n (tag: string | null) => {\n setTag(tag);\n handleChange({ type, tag });\n },\n [handleChange, type],\n );\n\n return (\n <div className={mx('grid grid-cols-2 gap-2', classNames)}>\n {types && (\n <Picker placeholder={t('picker-type.placeholder')} values={types} value={type} onChange={handleTypeChange} />\n )}\n {tags && (\n <Picker placeholder={t('picker-tag.placeholder')} values={tagOptions} value={tag} onChange={handleTagChange} />\n )}\n </div>\n );\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { useEffect, useMemo, useState } from 'react';\n\nimport { Filter } from '@dxos/echo';\nimport { QueryBuilder } from '@dxos/echo-query';\n/**\n * Creates a filter from a query string.\n */\nexport const useQueryBuilder = (query?: string): Filter.Any => {\n const builder = useMemo(() => new QueryBuilder(), []);\n const [filter, setFilter] = useState<Filter.Any>(Filter.everything());\n useEffect(() => {\n if (query) {\n const { filter } = builder.build(query);\n setFilter(filter ?? Filter.everything());\n } else {\n setFilter(Filter.everything());\n }\n }, [builder, query]);\n\n return filter;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/components/QueryEditor/autocomplete.ts","../../src/components/QueryEditor/query-extension.ts","../../src/components/QueryEditor/QueryEditor.tsx","../../src/components/QueryForm/Picker.tsx","../../src/components/QueryForm/query.ts","../../src/components/QueryForm/QueryForm.tsx","../../src/hooks/useQueryBuilder.ts","../../src/hooks/usePersistentQuery.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Database, type Tag, Type } from '@dxos/echo';\nimport { QueryDSL, formatTag } from '@dxos/echo-query';\nimport { type GetMenuContext } from '@dxos/react-ui-editor';\n\nexport type CompletionOptions = {\n db?: Database.Database;\n tags?: Tag.Map;\n};\n\n/**\n * Tag labels as they must appear in the document. Selecting a completion REPLACES the whole trigger\n * range, `#` included, and inserts the item verbatim — so an unprefixed label would silently drop the\n * `#` and leave text that no longer parses as a tag.\n */\nconst tagCompletions = (tags: Tag.Map): string[] => Object.values(tags).map((tag) => formatTag(tag.label));\n\n/**\n * Whether the caret sits in a tag the user is still typing: a `#` at the start of the current word,\n * with only label characters between it and `pos`.\n */\nconst isTypingTag = (text: string, pos: number): boolean => {\n let index = pos;\n while (index > 0 && /[a-zA-Z0-9_-]/.test(text[index - 1])) {\n index--;\n }\n\n return index > 0 && text[index - 1] === '#';\n};\n\nexport const completions = ({ db, tags }: CompletionOptions) => {\n const parser = QueryDSL.Parser.configure({ strict: false });\n return ({ state, pos }: GetMenuContext): string[] => {\n const text = state.sliceDoc();\n const tree = parser.parse(text);\n const { node } = tree.cursorAt(pos, -1);\n\n // A `#` with no label yet is an error node, not a `TagFilter` — the grammar needs a label\n // character before it accepts one — so the tree cannot answer for the keystroke that opens a tag.\n // Inside a string it is content, so the tree is still what settles that.\n if (tags && isTypingTag(text, pos) && node.type.id !== QueryDSL.Node.String) {\n return tagCompletions(tags);\n }\n\n switch (node.parent?.type.id) {\n case QueryDSL.Node.TypeFilter: {\n let range: { from: number; to: number } | undefined;\n if (node?.type.id === QueryDSL.Node.Identifier) {\n range = { from: node.from, to: node.to };\n } else if (node?.type.name === ':') {\n range = { from: node.from + 1, to: node.to };\n }\n\n if (range) {\n const schema = db ? [...db.graph.registry.list().filter(Type.isType)] : [];\n return schema.map((schema) => Type.getTypename(schema));\n }\n\n break;\n }\n\n case QueryDSL.Node.TagFilter: {\n if (tags) {\n return tagCompletions(tags);\n }\n\n break;\n }\n }\n\n return [];\n };\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { HighlightStyle, LanguageSupport, LRLanguage, syntaxHighlighting, syntaxTree } from '@codemirror/language';\nimport { EditorState, type Extension, RangeSetBuilder, StateField, type TransactionSpec } from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, WidgetType } from '@codemirror/view';\nimport { type SyntaxNodeRef } from '@lezer/common';\nimport { styleTags, tags as t } from '@lezer/highlight';\nimport JSON5 from 'json5';\n\nimport { type Tag } from '@dxos/echo';\nimport { QueryDSL, findTagByToken } from '@dxos/echo-query';\nimport { Domino } from '@dxos/ui';\nimport { type CompletionContext, focus, focusField, staticCompletion, typeahead } from '@dxos/ui-editor';\nimport { getHashHue, getStyles, mx } from '@dxos/ui-theme';\n\nexport type QueryOptions = {\n tags?: Tag.Map;\n};\n\n/**\n * Create a CodeMirror extension for the query language with syntax highlighting.\n */\nexport const query = ({ tags }: QueryOptions = {}): Extension => {\n return [\n new LanguageSupport(queryLanguage),\n syntaxHighlighting(queryHighlightStyle),\n decorations({ tags }),\n spacing,\n typeahead({\n onComplete: ({ line }: CompletionContext) => {\n const words = line.split(/\\s+/).filter(Boolean);\n if (words.length > 0) {\n // TODO(burdon): Get suggestion from parser.\n return staticCompletion(['type:', 'AND', 'OR', 'NOT'])({ line });\n }\n },\n }),\n focus,\n styles,\n ];\n};\n\n/**\n * The extension's decorations for a given state.\n *\n * Exported as a pure function of `(state, options)` so the atomicity rules — which govern whether a\n * tag can still be edited — are testable without mounting an `EditorView`.\n */\nexport const buildQueryDecorations = (state: EditorState, { tags }: QueryOptions = {}): DecorationSet => {\n {\n const hasFocus = state.field(focusField);\n const isInside = (node: SyntaxNodeRef) => {\n const range = intersectRanges(state.selection.main, node);\n return hasFocus && range && (state.selection.main.from > 0 || range.to - range.from > 0);\n };\n\n // Collected rather than fed straight to a `RangeSetBuilder`, which demands ascending `from`:\n // the bare-`#` ranges below come from a document scan and interleave with the tree's own.\n const collected: { from: number; to: number; deco: Decoration }[] = [];\n const deco = {\n add: (from: number, to: number, value: Decoration) => collected.push({ from, to, deco: value }),\n };\n const tagged: Range[] = [];\n syntaxTree(state).iterate({\n enter: (node) => {\n if (node.type.id === QueryDSL.Node.Tag) {\n tagged.push({ from: node.from, to: node.to });\n }\n switch (node.type.name) {\n case '(':\n case ')': {\n deco.add(\n node.from,\n node.to,\n Decoration.mark({\n class: 'px-1',\n }),\n );\n break;\n }\n\n case '=': {\n deco.add(\n node.from,\n node.to,\n Decoration.mark({\n class: 'text-fg-subtle',\n }),\n );\n break;\n }\n }\n\n switch (node.type.id) {\n case QueryDSL.Node.TypeFilter: {\n if (isInside(node)) {\n break;\n }\n\n const identifier = node.node.getChild(QueryDSL.Node.Identifier);\n if (identifier) {\n deco.add(\n node.from,\n node.to,\n Decoration.widget({\n widget: new TypeWidget(state.sliceDoc(identifier.from, identifier.to)),\n }),\n );\n }\n break;\n }\n\n case QueryDSL.Node.TagFilter: {\n const tagNode = node.node.getChild(QueryDSL.Node.Tag);\n if (tagNode) {\n const token = state.sliceDoc(tagNode.from, tagNode.to);\n const match = findTagByToken(tags, token);\n // The chip names the tag as the user wrote it, not the token form it had to be typed in.\n const label = match?.tag.label ?? token.slice(1);\n const hue = match?.tag.hue ?? getHashHue(match?.key ?? label);\n // Atomic at its own edges too, so Backspace against a tag takes the chip rather than a\n // character of the label; typing still grows it, since an insertion at the range's\n // boundary lands outside it.\n //\n // `replace`, not `widget`: a widget is a POINT decoration, so one covering a range that\n // starts at offset 0 paints before that offset's coordinate and the caret draws to its\n // right — pressing Home appeared to leave the caret after the tag.\n deco.add(node.from, node.to, Decoration.replace({ widget: new TagWidget(label, hue), atomic: true }));\n }\n break;\n }\n\n case QueryDSL.Node.ObjectLiteral: {\n if (isInside(node)) {\n break;\n }\n\n try {\n const props = JSON5.parse(state.sliceDoc(node.from, node.to));\n if (props) {\n deco.add(\n node.from,\n node.to,\n Decoration.widget({\n widget: new ObjectWidget(props),\n }),\n );\n }\n } catch {\n // Ignore malformed JSON.\n }\n break;\n }\n\n case QueryDSL.Node.Not:\n case QueryDSL.Node.And:\n case QueryDSL.Node.Or: {\n deco.add(\n node.from,\n node.to,\n Decoration.mark({\n class: 'pe-1 uppercase',\n atomic: true,\n }),\n );\n break;\n }\n\n case QueryDSL.Node.ArrowRight:\n case QueryDSL.Node.ArrowLeft: {\n deco.add(\n node.from,\n node.to,\n Decoration.widget({\n widget: new SymbolWidget(node.type.id === QueryDSL.Node.ArrowRight ? '\\u2192' : '\\u2190'),\n atomic: true,\n }),\n );\n break;\n }\n\n // default: {\n // console.log(node.type.name);\n // }\n }\n },\n });\n\n // A `#` with no label yet parses as an error, not a `Tag`, so the tree cannot decorate it — but\n // the affordance has to appear on the keystroke that opens the tag, not once it is valid.\n // A lone `#` is an error node, not a `Tag` — the grammar needs a label character — so it gets a\n // plain highlight until the first one arrives and the chip takes over.\n for (const range of bareTagRanges(state, tagged)) {\n collected.push({\n from: range.from,\n to: range.to,\n deco: Decoration.mark({ class: mx('rounded-xs px-0.5', getStyles(getHashHue('')).surface) }),\n });\n }\n\n const builder = new RangeSetBuilder<Decoration>();\n // Equal starts sort WIDEST first so an enclosing mark (the chip's border) nests the inner ones.\n collected.sort((a, b) => a.from - b.from || b.to - a.to);\n for (const { from, to, deco } of collected) {\n builder.add(from, to, deco);\n }\n\n return builder.finish();\n }\n};\n\n/**\n * Decorations\n */\nconst decorations = ({ tags }: QueryOptions): Extension => {\n return [\n StateField.define<DecorationSet>({\n create: (state) => buildQueryDecorations(state, { tags }),\n update: (deco, tr) => {\n if (tr.docChanged || tr.newSelection) {\n return buildQueryDecorations(tr.state, { tags });\n }\n\n return deco;\n },\n provide: (field) => [\n EditorView.decorations.from(field),\n EditorView.atomicRanges.of((view) => {\n const builder = new RangeSetBuilder<Decoration>();\n const cursor = view.state.field(field).iter();\n while (cursor.value) {\n if (cursor.value.spec.atomic) {\n builder.add(cursor.from, cursor.to, cursor.value);\n }\n cursor.next();\n }\n\n return builder.finish();\n }),\n ],\n }),\n ];\n};\n\n/**\n * Keeps typed text from being glued onto a tag chip.\n *\n * Two rules, both applied as follow-up changes so the user's own transaction is left intact:\n * 1. Text typed immediately before a tag is separated from it by a space.\n * 2. An insertion leaves a trailing space at the end of the document, so there is always somewhere to\n * type that is not adjacent to a chip. Deletions are exempt, or backspace at the end of the\n * document would only ever delete a space this rule puts straight back.\n */\nexport const spacing: Extension = EditorState.transactionFilter.of((tr) => {\n if (!tr.docChanged) {\n return tr;\n }\n\n const tagStarts = new Set<number>();\n syntaxTree(tr.startState).iterate({\n enter: (node) => {\n if (node.type.id === QueryDSL.Node.Tag) {\n tagStarts.add(node.from);\n }\n },\n });\n\n let inserting = false;\n let separator: number | undefined;\n tr.changes.iterChanges((fromA, toA, _fromB, toB, inserted) => {\n if (!inserted.length) {\n return;\n }\n\n inserting = true;\n // Keyed on `toA`, the offset the inserted text ends against: that covers a replacement whose\n // range ends at the tag as well as a plain insertion, where `fromA` and `toA` are the same.\n if (tagStarts.has(toA) && !/\\s$/.test(inserted.toString())) {\n separator = toB;\n }\n });\n\n const specs: TransactionSpec[] = [tr];\n let text = tr.newDoc.toString();\n if (separator !== undefined) {\n specs.push({ changes: { from: separator, insert: ' ' }, sequential: true });\n text = text.slice(0, separator) + ' ' + text.slice(separator);\n }\n if (inserting && text.length > 0 && !/\\s$/.test(text)) {\n specs.push({ changes: { from: text.length, insert: ' ' }, sequential: true });\n }\n\n return specs;\n});\n\nconst lineHeight = '30px';\n\n/** The outer box vertically aligns the inner text with content in the outer div. */\nconst CHIP_OUTER = 'inline-flex h-[28px] align-middle';\nconst CHIP_INNER = 'inline-flex h-[26px] border rounded-xs';\n\nconst container = (classNames: string, ...children: Domino<HTMLElement>[]) => {\n const inner = Domino.of('span')\n .classNames(mx(CHIP_INNER, classNames))\n .append(...children);\n return Domino.of('span').classNames(CHIP_OUTER).append(inner).root;\n};\n\n/** A tag chip's parts, keyed by the nesting {@link container} produces. */\nconst chipClasses = (hue: string) => {\n const { bg, fg, surface } = getStyles(hue);\n return {\n hash: mx('flex items-center px-1 text-black text-xs', bg),\n label: mx('flex items-center px-1 text-sm', surface, fg),\n };\n};\n\n/**\n * TypeKeyword:Identifier\n */\nclass TypeWidget extends WidgetType {\n constructor(private readonly _identifier: string) {\n super();\n }\n\n override ignoreEvent() {\n return false;\n }\n\n override eq(other: this) {\n return this._identifier === other._identifier;\n }\n\n override toDOM() {\n const label: string = this._identifier.split(/\\W/).at(-1)!;\n return container(\n 'border-sky-500',\n Domino.of('span').classNames(mx('flex items-center px-1 text-black text-xs bg-sky-500')).text('type'),\n Domino.of('span').classNames(mx('flex items-center px-1 text-fg-muted')).text(label),\n );\n }\n}\n\n/**\n * Tag\n */\nclass TagWidget extends WidgetType {\n constructor(\n private readonly _str: string,\n private readonly _hue: string,\n ) {\n super();\n }\n\n override eq(other: this) {\n return this._str === other._str;\n }\n\n override toDOM() {\n const { hash, label } = chipClasses(this._hue);\n return container(\n getStyles(this._hue).border,\n Domino.of('span').classNames(hash).text('#'),\n Domino.of('span').classNames(label).text(this._str),\n );\n }\n}\n\n/**\n * { type: \"value\" }\n */\nclass ObjectWidget extends WidgetType {\n private readonly _entries: [string, any][];\n private readonly _json: string;\n\n constructor(private readonly _props: any) {\n super();\n this._entries = Object.entries(this._props);\n this._json = JSON.stringify(this._props);\n }\n\n override ignoreEvent() {\n return false;\n }\n\n override eq(other: this) {\n return this._json === other._json;\n }\n\n override toDOM() {\n return container(\n 'border-separator divide-x divide-separator',\n ...this._entries.map(([key, value]) => {\n const keyEl = Domino.of('span')\n .classNames('flex items-center px-1 text-fg-muted text-xs bg-modal-surface first:rounded-l-xs')\n .text(key);\n const valueEl = Domino.of('span').classNames('flex items-center px-1 text-fg-muted').text(value);\n return Domino.of('span').classNames('inline-flex items-stretch').append(keyEl, valueEl);\n }),\n );\n }\n}\n\n/**\n * Symbol\n */\nclass SymbolWidget extends WidgetType {\n constructor(private readonly _str: string) {\n super();\n }\n\n override eq(other: this) {\n return this._str === other._str;\n }\n\n override toDOM() {\n return Domino.of('span').text(this._str).root;\n }\n}\n\nconst styles = EditorView.theme({\n '.cm-line': {\n lineHeight,\n },\n // Match the standard Input block size (md density): 2.5rem, 2rem on pointer-fine devices.\n '.cm-scroller': {\n alignItems: 'center',\n minHeight: '2.5rem',\n },\n '@media (pointer: fine)': {\n '.cm-scroller': {\n minHeight: '2rem',\n },\n },\n});\n\n/**\n * Define syntax highlighting tags for the query language.\n */\nconst queryHighlighting = styleTags({\n // Keywords\n 'Not And Or': t.keyword,\n 'TypeKeyword': t.attributeName,\n\n // Literals\n 'String': t.string,\n 'Number': t.number,\n 'Boolean': t.bool,\n 'Null': t.null,\n\n // Identifiers\n // NOT `Tag`: it is drawn as a chip, whose own foreground would be fighting a highlight class here.\n 'Identifier': t.variableName,\n 'PropertyPath': t.propertyName,\n\n // Punctuation\n '{ }': t.brace,\n '[ ]': t.squareBracket,\n '( )': t.paren,\n ':': t.definitionOperator,\n ',': t.separator,\n '.': t.derefOperator,\n});\n\n/**\n * Create the query language with the parser and highlighting.\n */\nconst queryLanguage = LRLanguage.define({\n parser: QueryDSL.Parser.configure({\n props: [queryHighlighting],\n strict: false,\n }),\n languageData: {\n commentTokens: { line: '//' },\n },\n});\n\n/**\n * Define a custom highlight style for the query language.\n */\nconst queryHighlightStyle = HighlightStyle.define([\n { tag: t.keyword, class: 'text-blue-text' },\n { tag: t.string, class: 'text-orange-text' },\n { tag: t.number, class: 'text-green-text' },\n { tag: t.bool, class: 'text-green-text' },\n { tag: t.null, class: 'text-neutral-text' },\n { tag: t.attributeName, class: 'text-blue-text' },\n { tag: t.variableName, class: 'text-teal-text' },\n { tag: t.propertyName, class: 'text-teal-text' },\n { tag: t.definitionOperator, class: 'text-fg-subtle' },\n { tag: t.separator, class: 'text-fg-subtle' },\n { tag: t.derefOperator, class: 'text-fg-subtle' },\n { tag: t.brace, class: 'text-fg-subtle' },\n { tag: t.squareBracket, class: 'text-fg-subtle' },\n { tag: t.operator, class: 'text-fg-subtle' },\n { tag: t.paren, class: 'text-amber-text' },\n]);\n\ntype Range = { from: number; to: number };\nfunction intersectRanges(a: Range, b: Range): Range | null {\n const start = Math.max(a.from, b.from);\n const end = Math.min(a.to, b.to);\n return start <= end ? { from: start, to: end } : null;\n}\n\n/** Label characters the grammar admits after `#` (`Tag { \"#\" $[a-zA-Z0-9_\\-]+ }`). */\nconst TAG_LABEL_CHAR = /[a-zA-Z0-9_-]/;\n\n/**\n * Ranges of an in-progress tag — a `#` the parser has not yet accepted as a {@link QueryDSL.Node.Tag},\n * because the grammar requires at least one label character after it. Skips offsets the tree already\n * claimed, and any `#` inside a string, where it is content rather than a tag.\n */\nconst bareTagRanges = (state: EditorState, tagged: readonly Range[]): Range[] => {\n const ranges: Range[] = [];\n const text = state.sliceDoc();\n const covered = (index: number) => tagged.some(({ from, to }) => index >= from && index < to);\n for (let index = text.indexOf('#'); index !== -1; index = text.indexOf('#', index + 1)) {\n if (covered(index) || syntaxTree(state).resolveInner(index, 1).type.id === QueryDSL.Node.String) {\n continue;\n }\n let end = index + 1;\n while (end < text.length && TAG_LABEL_CHAR.test(text[end])) {\n end++;\n }\n ranges.push({ from: index, to: end });\n }\n\n return ranges;\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Extension, Prec } from '@codemirror/state';\nimport React, { forwardRef, useCallback, useMemo, useRef } from 'react';\n\nimport { type BuildResult, QueryBuilder } from '@dxos/echo-query';\nimport {\n Editor,\n type EditorController,\n type EditorMenuProviderProps,\n type EditorViewProps,\n type UseEditorMenuProps,\n createMenuGroup,\n} from '@dxos/react-ui-editor';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { createBasicExtensions, createThemeExtensions, keymap } from '@dxos/ui-editor';\n\nimport { translationKey } from '#translations';\n\nimport { type CompletionOptions, completions } from './autocomplete.ts';\nimport { query } from './query-extension.ts';\n\nexport type QueryEditorProps = Util.ThemedClassName<\n {\n value?: string;\n readonly?: boolean;\n /**\n * The parsed query, rebuilt on every edit. `filter` is undefined while the text does not parse,\n * which is what a caller gates a \"save this view\" affordance on.\n *\n * Supplying this is what opts the editor into building a filter at all — the DSL is otherwise\n * parsed only for decoration, and a caller that wants the raw text pays nothing for a parse it\n * will not read.\n */\n onFilterChange?: (result: BuildResult) => void;\n } & (CompletionOptions & Omit<EditorViewProps, 'initialValue'> & Pick<EditorMenuProviderProps, 'numItems'>)\n>;\n\n/**\n * Query editor with decorations and autocomplete.\n */\nexport const QueryEditor = forwardRef<EditorController, QueryEditorProps>(\n ({ db, tags, value, readonly, numItems = 8, onChange, onFilterChange, ...props }, forwardedRef) => {\n const { t } = Hooks.useTranslation(translationKey);\n\n const getOptions = useMemo(() => completions({ db, tags }), [db, tags]);\n const getMenu = useCallback<NonNullable<UseEditorMenuProps['getMenu']>>(\n async (context) => [createMenuGroup({ items: getOptions(context) })],\n [getOptions],\n );\n\n // The editor owns the parse that used to be repeated by every consumer: the DSL was already being\n // parsed here for decorations, so a caller building its own `QueryBuilder` parsed each keystroke\n // twice.\n const builder = useMemo(() => (onFilterChange ? new QueryBuilder(tags) : undefined), [onFilterChange, tags]);\n const handleChange = useCallback(\n (doc: string) => {\n onChange?.(doc);\n if (builder) {\n onFilterChange?.(builder.build(doc));\n }\n },\n [onChange, onFilterChange, builder],\n );\n\n // Keyed on the tag map's CONTENTS, not its identity: callers rebuild the map each render, and\n // `useTextEditor` destroys and recreates the view whenever `extensions` changes — so depending on\n // the object blurred the editor on every keystroke.\n const tagsKey = useMemo(\n () =>\n Object.values(tags ?? {})\n .map((tag) => `${tag.id}:${tag.label}:${tag.hue ?? ''}`)\n .join(),\n [tags],\n );\n const tagsRef = useRef(tags);\n tagsRef.current = tags;\n\n const themeMode = Hooks.useThemeMode();\n const extensions = useMemo<Extension[]>(\n () => [\n createBasicExtensions({\n readOnly: readonly,\n lineWrapping: false,\n placeholder: t('query-editor.placeholder'),\n // A single-line query gains nothing from bracket matching, and CodeMirror's default paints\n // `.cm-matchingBracket` with a background while focused — a coloured wash over the braces of\n // an object literal the moment the caret reaches it.\n bracketMatching: false,\n }),\n createThemeExtensions({ themeMode, slots: { scroller: { className: 'scrollbar-none' } } }),\n query({ tags: tagsRef.current }),\n Prec.highest(\n keymap.of([\n {\n key: 'Enter',\n run: () => {\n // Prevent newline.\n return true;\n },\n },\n ]),\n ),\n ],\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [readonly, themeMode, tagsKey],\n );\n\n return (\n <Editor.Root\n ref={forwardedRef}\n extensions={extensions}\n numItems={numItems}\n // `#` opens the tag list. `:` cannot be a trigger — `popoverKeymap` only fires one at a line\n // start or after a space, and a typename's colon follows `type`; `activateOnTyping` covers it\n // instead, since `:` is a completion delimiter so the word under the caret is the typename.\n // The explicit key stays, for re-opening a dismissed menu.\n trigger={['#']}\n // NOT `activateOnTyping`: that opens the menu on every word character, and the popover takes\n // focus each keystroke while returning nothing for most positions. `:` is the only delimiter\n // with a list behind it, so the typename menu opens there and nowhere else.\n activateOnDelimiters={[':']}\n triggerKey='Ctrl-Space'\n getMenu={getMenu}\n >\n {/* `initialValue`, never the controlled `value`: the sync effect behind `value` compares the\n prop against the document a frame later, and a caller whose state trails fast typing then\n rewrites the document back to the older text, dropping characters. A caller rewriting the\n query itself does it through `EditorController.setText`. */}\n <Editor.View {...props} initialValue={value} onChange={handleChange} selectionEnd />\n </Editor.Root>\n );\n },\n);\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { useMemo } from 'react';\n\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport * as Select from '@dxos/react-ui/Select';\n\nimport { translationKey } from '#translations';\n\nconst NULL = '__NULL__';\n\nexport type PickerProps<T extends { value: string; label: string }> = {\n placeholder?: string;\n values?: T[];\n value?: string | null;\n onChange?: (value: string | null) => void;\n};\n\n// TODO(wittjosiah): Should use `SelectInput` from `react-ui-form` instead.\nexport const Picker = <T extends { value: string; label: string }>({\n placeholder,\n values,\n value,\n onChange,\n}: PickerProps<T>) => {\n const { t } = Hooks.useTranslation(translationKey);\n const sorted = useMemo(() => values?.sort(({ label: a }, { label: b }) => a.localeCompare(b)) ?? [], [values]);\n\n return (\n <Select.Root\n items={[{ value: NULL, label: t('picker-none.label') }, ...sorted]}\n value={[value ?? NULL]}\n onValueChange={({ value: [value] }) => onChange?.(value === NULL ? null : value)}\n >\n <Select.Trigger placeholder={placeholder ?? t('picker-select.label')} />\n <Select.Content>\n <Select.ItemGroup>\n <Select.Item item={{ value: NULL, label: t('picker-none.label') }} />\n {sorted.map(({ value, label }) => (\n <Select.Item key={value} item={{ value: value, label: label }} />\n ))}\n </Select.ItemGroup>\n </Select.Content>\n </Select.Root>\n );\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Match from 'effect/Match';\nimport * as Option from 'effect/Option';\n\nimport { type QueryAST } from '@dxos/echo';\nimport { type URI } from '@dxos/keys';\n\n// Helper to extract type URI from query AST\nexport const extractTypename = (query: QueryAST.Query): Option.Option<URI.URI> => {\n return Match.value(query).pipe(\n Match.withReturnType<Option.Option<URI.URI>>(),\n Match.when({ type: 'select' }, (q) => extractTypenameFromFilter(q.filter)),\n Match.when({ type: 'filter' }, (q) => {\n const selectionTypename = extractTypename(q.selection);\n const filterTypename = extractTypenameFromFilter(q.filter);\n return Option.isSome(selectionTypename) ? selectionTypename : filterTypename;\n }),\n Match.when({ type: 'options' }, (q) => extractTypename(q.query)),\n Match.when({ type: 'from' }, (q) => extractTypename(q.query)),\n Match.when({ type: 'order' }, (q) => extractTypename(q.query)),\n Match.when({ type: 'limit' }, (q) => extractTypename(q.query)),\n Match.orElse(() => Option.none()),\n );\n};\n\n// Helper to extract tag from query AST\nexport const extractTag = (query: QueryAST.Query): Option.Option<string> => {\n return Match.value(query).pipe(\n Match.withReturnType<Option.Option<string>>(),\n Match.when({ type: 'select' }, (q) => extractTagFromFilter(q.filter)),\n Match.when({ type: 'filter' }, (q) => {\n const selectionTag = extractTag(q.selection);\n const filterTag = extractTagFromFilter(q.filter);\n return Option.isSome(filterTag) ? filterTag : selectionTag;\n }),\n Match.when({ type: 'options' }, (q) => extractTag(q.query)),\n Match.when({ type: 'from' }, (q) => extractTag(q.query)),\n Match.when({ type: 'order' }, (q) => extractTag(q.query)),\n Match.when({ type: 'limit' }, (q) => extractTag(q.query)),\n Match.orElse(() => Option.none()),\n );\n};\n\n// Helper to extract type URI from filter AST\nconst extractTypenameFromFilter = (filter: QueryAST.Filter): Option.Option<URI.URI> => {\n return Match.value(filter).pipe(\n Match.withReturnType<Option.Option<URI.URI>>(),\n Match.when({ type: 'object' }, (f) => Option.fromNullishOr(f.typename)),\n Match.when({ type: 'and' }, (f) =>\n f.filters.reduce(\n (acc: Option.Option<URI.URI>, filterItem: QueryAST.Filter) =>\n Option.isSome(acc) ? acc : extractTypenameFromFilter(filterItem),\n Option.none<URI.URI>(),\n ),\n ),\n Match.when({ type: 'or' }, (f) =>\n f.filters.reduce(\n (acc: Option.Option<URI.URI>, filterItem: QueryAST.Filter) =>\n Option.isSome(acc) ? acc : extractTypenameFromFilter(filterItem),\n Option.none<URI.URI>(),\n ),\n ),\n Match.orElse(() => Option.none()),\n );\n};\n\n// Helper to extract tag from filter AST\nconst extractTagFromFilter = (filter: QueryAST.Filter): Option.Option<string> => {\n return Match.value(filter).pipe(\n Match.withReturnType<Option.Option<string>>(),\n Match.when({ type: 'tag' }, (f) => Option.some(f.tag)),\n Match.when({ type: 'and' }, (f) =>\n f.filters.reduce(\n (acc: Option.Option<string>, filterItem: QueryAST.Filter) =>\n Option.isSome(acc) ? acc : extractTagFromFilter(filterItem),\n Option.none<string>(),\n ),\n ),\n Match.when({ type: 'or' }, (f) =>\n f.filters.reduce(\n (acc: Option.Option<string>, filterItem: QueryAST.Filter) =>\n Option.isSome(acc) ? acc : extractTagFromFilter(filterItem),\n Option.none<string>(),\n ),\n ),\n Match.orElse(() => Option.none()),\n );\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Option from 'effect/Option';\nimport React, { useCallback, useMemo, useState } from 'react';\n\nimport { Filter, Obj, Query, type QueryAST, type Tag } from '@dxos/echo';\nimport { URI } from '@dxos/keys';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { mx } from '@dxos/ui-theme';\n\nimport { translationKey } from '#translations';\n\nimport { Picker } from './Picker.tsx';\nimport { extractTag, extractTypename } from './query.ts';\n\nexport type QueryFormProps = Util.ThemedClassName<{\n initialQuery?: QueryAST.Query;\n types?: { value: URI.URI; label: string }[];\n tags?: Tag.Tag[];\n onChange?: (query: Query.Any) => void;\n}>;\n\n// TODO(wittjosiah): Support more complex queries and traversals.\nexport const QueryForm = ({ classNames, initialQuery, types, tags, onChange }: QueryFormProps) => {\n const { t } = Hooks.useTranslation(translationKey);\n\n const initialType = initialQuery ? Option.getOrUndefined(extractTypename(initialQuery)) : undefined;\n const initialTag = initialQuery ? Option.getOrUndefined(extractTag(initialQuery)) : undefined;\n\n const [type, setType] = useState<URI.URI | null>(initialType ?? null);\n const [tag, setTag] = useState<string | null>(initialTag ?? null);\n\n const tagOptions = useMemo(() => tags?.map((tag) => ({ value: Obj.getURI(tag), label: tag.label })), [tags]);\n\n const handleChange = useCallback(\n ({ type, tag }: { type: URI.URI | null; tag: string | null }) => {\n const typeFilter = type ? Filter.type(type) : null;\n const tagFilter = tag ? Filter.tag(tag) : null;\n const combined =\n typeFilter && tagFilter ? Filter.and(typeFilter, tagFilter) : (typeFilter ?? tagFilter ?? Filter.nothing());\n onChange?.(Query.select(combined));\n },\n [onChange],\n );\n\n const handleTypeChange = useCallback(\n (value: string | null) => {\n // Select.onValueChange returns bare string; values come from types[].value which are URI.URI.\n const uri = value as URI.URI | null;\n setType(uri);\n handleChange({ type: uri, tag });\n },\n [handleChange, tag],\n );\n\n const handleTagChange = useCallback(\n (tag: string | null) => {\n setTag(tag);\n handleChange({ type, tag });\n },\n [handleChange, type],\n );\n\n return (\n <div className={mx('grid grid-cols-2 gap-2', classNames)}>\n {types && (\n <Picker placeholder={t('picker-type.placeholder')} values={types} value={type} onChange={handleTypeChange} />\n )}\n {tags && (\n <Picker placeholder={t('picker-tag.placeholder')} values={tagOptions} value={tag} onChange={handleTagChange} />\n )}\n </div>\n );\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { useEffect, useMemo, useState } from 'react';\n\nimport { Filter } from '@dxos/echo';\nimport { QueryBuilder } from '@dxos/echo-query';\n/**\n * Creates a filter from a query string.\n */\nexport const useQueryBuilder = (query?: string): Filter.Any => {\n const builder = useMemo(() => new QueryBuilder(), []);\n const [filter, setFilter] = useState<Filter.Any>(Filter.everything());\n useEffect(() => {\n if (query) {\n const { filter } = builder.build(query);\n setFilter(filter ?? Filter.everything());\n } else {\n setFilter(Filter.everything());\n }\n }, [builder, query]);\n\n return filter;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type RefObject, useCallback, useEffect } from 'react';\n\nimport { useManagerOptional, useViewState, useViewStateActions } from '@dxos/react-ui-attention';\nimport { type ViewState } from '@dxos/react-ui-attention/types';\nimport { type EditorController } from '@dxos/react-ui-editor';\n\n/** A view-state value that carries a {@link QueryEditor}'s text beside whatever else the view persists. */\nexport type QueryViewState = { query: string };\n\nexport type PersistentQuerySetter = (query: string | ((query: string) => string)) => void;\n\n/**\n * A list's filter query, held in a `ViewState` aspect (so it persists per device and per `contextId`)\n * and mirrored into the {@link QueryEditor} behind `editorRef`.\n *\n * The editor takes its text once, as `initialValue`, so a write that did not come from typing — a\n * picker over the same text, clear, another view of the same list, another tab — is pushed into it\n * here. Pushed from the subscription rather than from a render effect: the subscription fires as the\n * value is written, when the editor already holds whatever was just typed, whereas an effect can run\n * for a render that trails fast typing and rewrite the document back to older text.\n */\nexport const usePersistentQuery = <T extends QueryViewState, Encoded = T>(\n aspect: ViewState.Aspect<T, Encoded>,\n contextId: string | undefined,\n editorRef: RefObject<EditorController | null>,\n): [string, PersistentQuerySetter] => {\n const manager = useManagerOptional();\n const { query } = useViewState(aspect, contextId);\n const { update } = useViewStateActions(aspect, contextId);\n useEffect(() => {\n if (!manager || !contextId) {\n return;\n }\n return manager.subscribe(aspect, contextId, ({ query }) => {\n const editor = editorRef.current;\n if (editor && editor.getText() !== query) {\n editor.setText(query);\n }\n });\n }, [manager, aspect, contextId, editorRef]);\n\n // Unchanged text keeps the same value, so the editor echoing a pushed text back is not a write.\n const setQuery = useCallback<PersistentQuerySetter>(\n (next) =>\n update((view) => {\n const query = typeof next === 'function' ? next(view.query) : next;\n return view.query === query ? view : { ...view, query };\n }),\n [update],\n );\n\n return [query, setQuery];\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/translations.ts
|
|
2
|
+
var translationKey = "@dxos/react-ui-query";
|
|
3
|
+
var translations = [{ "en-US": { [translationKey]: {
|
|
4
|
+
"query-editor.placeholder": "Enter text to filter, or a query (e.g., \"#tag\")",
|
|
5
|
+
"picker-select.label": "Select",
|
|
6
|
+
"picker-none.label": "None",
|
|
7
|
+
"picker-type.placeholder": "Type",
|
|
8
|
+
"picker-tag.placeholder": "Tag"
|
|
9
|
+
} } }];
|
|
10
|
+
//#endregion
|
|
11
|
+
export { translationKey, translations };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=translations.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translations.mjs","names":[],"sources":["../../src/translations.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport type * as Theme from '@dxos/react-ui/Theme';\n\nexport const translationKey = '@dxos/react-ui-query';\n\nexport const translations = [\n {\n 'en-US': {\n [translationKey]: {\n 'query-editor.placeholder': 'Enter text to filter, or a query (e.g., \"#tag\")',\n\n 'picker-select.label': 'Select',\n 'picker-none.label': 'None',\n 'picker-type.placeholder': 'Type',\n 'picker-tag.placeholder': 'Tag',\n },\n },\n },\n] as const satisfies Theme.Resource[];\n"],"mappings":";AAMA,IAAa,iBAAiB;AAE9B,IAAa,eAAe,CAC1B,EACE,SAAS,GACN,iBAAiB;CAChB,4BAA4B;CAE5B,uBAAuB;CACvB,qBAAqB;CACrB,2BAA2B;CAC3B,0BAA0B;AAC5B,EACF,EACF,CACF"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { type BuildResult } from '@dxos/echo-query';
|
|
3
|
-
import { type ThemedClassName } from '@dxos/react-ui';
|
|
4
3
|
import { type EditorController, type EditorMenuProviderProps, type EditorViewProps } from '@dxos/react-ui-editor';
|
|
4
|
+
import type * as Util from '@dxos/react-ui/Util';
|
|
5
5
|
import { type CompletionOptions } from './autocomplete.ts';
|
|
6
|
-
export type QueryEditorProps = ThemedClassName<{
|
|
6
|
+
export type QueryEditorProps = Util.ThemedClassName<{
|
|
7
7
|
value?: string;
|
|
8
8
|
readonly?: boolean;
|
|
9
9
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryEditor.d.ts","sourceRoot":"","sources":["../../../../../src/components/QueryEditor/QueryEditor.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAExE,OAAO,EAAE,KAAK,WAAW,EAAgB,MAAM,kBAAkB,CAAC;AAClE,OAAO,
|
|
1
|
+
{"version":3,"file":"QueryEditor.d.ts","sourceRoot":"","sources":["../../../../../src/components/QueryEditor/QueryEditor.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAExE,OAAO,EAAE,KAAK,WAAW,EAAgB,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EAGrB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,KAAK,IAAI,MAAM,qBAAqB,CAAC;AAKjD,OAAO,EAAE,KAAK,iBAAiB,EAAe,MAAM,mBAAmB,CAAC;AAGxE,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,eAAe,CACjD;IACE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;CAChD,GAAG,CAAC,iBAAiB,GAAG,IAAI,CAAC,eAAe,EAAE,cAAc,CAAC,GAAG,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC,CAAC,CAC5G,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW;YAjBZ,MAAM;eACH,OAAO;IAClB;;;;;;;OAOG;qBACc,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI;;;0CAmGjD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Picker.d.ts","sourceRoot":"","sources":["../../../../../src/components/QueryForm/Picker.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAkB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Picker.d.ts","sourceRoot":"","sources":["../../../../../src/components/QueryForm/Picker.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAkB,MAAM,OAAO,CAAC;AASvC,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,IAAI;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAC3C,CAAC;AAGF,eAAO,MAAM,MAAM,GAAI,CAAC,SAAS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,6CAK9D,WAAW,CAAC,CAAC,CAAC,sBAqBhB,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Query, type QueryAST, type Tag } from '@dxos/echo';
|
|
3
3
|
import { URI } from '@dxos/keys';
|
|
4
|
-
import
|
|
5
|
-
export type QueryFormProps = ThemedClassName<{
|
|
4
|
+
import type * as Util from '@dxos/react-ui/Util';
|
|
5
|
+
export type QueryFormProps = Util.ThemedClassName<{
|
|
6
6
|
initialQuery?: QueryAST.Query;
|
|
7
7
|
types?: {
|
|
8
8
|
value: URI.URI;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryForm.d.ts","sourceRoot":"","sources":["../../../../../src/components/QueryForm/QueryForm.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAE9D,OAAO,EAAe,KAAK,EAAE,KAAK,QAAQ,EAAE,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"QueryForm.d.ts","sourceRoot":"","sources":["../../../../../src/components/QueryForm/QueryForm.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAE9D,OAAO,EAAe,KAAK,EAAE,KAAK,QAAQ,EAAE,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEjC,OAAO,KAAK,KAAK,IAAI,MAAM,qBAAqB,CAAC;AAQjD,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC;IAChD,YAAY,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC;IAC9B,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC;CACvC,CAAC,CAAC;AAGH,eAAO,MAAM,SAAS,wDAAyD,cAAc,sBAkD5F,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAIA,cAAc,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAIA,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
import { type ViewState } from '@dxos/react-ui-attention/types';
|
|
3
|
+
import { type EditorController } from '@dxos/react-ui-editor';
|
|
4
|
+
/** A view-state value that carries a {@link QueryEditor}'s text beside whatever else the view persists. */
|
|
5
|
+
export type QueryViewState = {
|
|
6
|
+
query: string;
|
|
7
|
+
};
|
|
8
|
+
export type PersistentQuerySetter = (query: string | ((query: string) => string)) => void;
|
|
9
|
+
/**
|
|
10
|
+
* A list's filter query, held in a `ViewState` aspect (so it persists per device and per `contextId`)
|
|
11
|
+
* and mirrored into the {@link QueryEditor} behind `editorRef`.
|
|
12
|
+
*
|
|
13
|
+
* The editor takes its text once, as `initialValue`, so a write that did not come from typing — a
|
|
14
|
+
* picker over the same text, clear, another view of the same list, another tab — is pushed into it
|
|
15
|
+
* here. Pushed from the subscription rather than from a render effect: the subscription fires as the
|
|
16
|
+
* value is written, when the editor already holds whatever was just typed, whereas an effect can run
|
|
17
|
+
* for a render that trails fast typing and rewrite the document back to older text.
|
|
18
|
+
*/
|
|
19
|
+
export declare const usePersistentQuery: <T extends QueryViewState, Encoded = T>(aspect: ViewState.Aspect<T, Encoded>, contextId: string | undefined, editorRef: RefObject<EditorController | null>) => [string, PersistentQuerySetter];
|
|
20
|
+
//# sourceMappingURL=usePersistentQuery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePersistentQuery.d.ts","sourceRoot":"","sources":["../../../../src/hooks/usePersistentQuery.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAA0B,MAAM,OAAO,CAAC;AAG/D,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,2GAA2G;AAC3G,MAAM,MAAM,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/C,MAAM,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,KAAK,IAAI,CAAC;AAE1F;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAAI,CAAC,SAAS,cAAc,EAAE,OAAO,GAAG,CAAC,UAC9D,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,aACzB,MAAM,GAAG,SAAS,aAClB,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,KAC5C,CAAC,MAAM,EAAE,qBAAqB,CA2BhC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translations.d.ts","sourceRoot":"","sources":["../../../src/translations.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,cAAc,yBAAyB,CAAC;AAErD,eAAO,MAAM,YAAY;;;qBAIjB,0BAA0B,EAAE,iDAAiD;qBAE7E,qBAAqB,EAAE,QAAQ;qBAC/B,mBAAmB,EAAE,MAAM;qBAC3B,yBAAyB,EAAE,MAAM;qBACjC,wBAAwB,EAAE,KAAK;;;
|
|
1
|
+
{"version":3,"file":"translations.d.ts","sourceRoot":"","sources":["../../../src/translations.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,cAAc,yBAAyB,CAAC;AAErD,eAAO,MAAM,YAAY;;;qBAIjB,0BAA0B,EAAE,iDAAiD;qBAE7E,qBAAqB,EAAE,QAAQ;qBAC/B,mBAAmB,EAAE,MAAM;qBAC3B,yBAAyB,EAAE,MAAM;qBACjC,wBAAwB,EAAE,KAAK;;;EAIF,CAAC"}
|