Pyric
Navigate

API reference

@pyric/ui/firestore

86 published symbols from @pyric/ui

Generated from the TypeScript declarations shipped at this import path.

Interfaces

CollectionListProps

Properties

PropertyTypeDescription
className?string-
collectionsCollectionReference<DocumentData>[]-
emptyState?ReactNodeOptional empty-state node. Rendered when collections.length is 0 and the list isn’t loading.
error?Error-
isLoading?boolean-
onSelect?(collection: CollectionReference) => voidFired when a list item is clicked. Consumer wires navigation.

DeleteWithConfirmProps

Properties

PropertyTypeDescription
body?ReactNodeConfirm-dialog body.
className?stringClass forwarded to the default trigger button.
confirmLabel?stringLabel on the destructive button.
implRecursiveDeleteImplImplementation that walks the tree + deletes. Consumer-supplied. Sandbox-backed apps usually wire pyric/sandbox introspection; production apps usually call a Cloud Function.
onDeleted?() => voidFired after the delete iterator finishes successfully.
renderTrigger?(props: { isRunning: boolean; onClick: () => void; progress: number; }) => ReactNodeOptional render override for the trigger button.
target| DocumentReference<DocumentData> | CollectionReference<DocumentData>The doc / collection to delete.
title?stringConfirm-dialog title. Defaults to a sensible derivation from the target’s path.

DocumentEditorRootProps

Properties

PropertyTypeDescription
childrenReactNode-
className?string-
fieldEditors?FieldEditorRegistryOverride or extend the built-in field editors.
initial?Record<string, unknown>Initial document data. Built into the editor’s tree on first mount; later changes don’t rebuild — call editor.reset() to re-initialize from a fresh initial.
onChange?(state: UseDocumentEditorResult) => voidCalled on every state change with the latest editor state. The parent typically watches state.isValid + state.isDirty to enable/disable a Save button.

DocumentEditorState

Reducer state. tree is the live document under edit; initial is the snapshot the editor was constructed from (used to implement reset and isDirty).

Extended by

Properties

PropertyTypeDescription
errorCountnumberCount of nodes with an active error. Derived after every action; the reducer keeps it in state to avoid a tree walk on every render.
initialEditorTreeFrozen copy of the tree at construction. reset restores from here; isDirty is computed by comparing serializations.
treeEditorTree-

DocumentListProps

Properties

PropertyTypeDescription
className?string-
documentsQueryDocumentSnapshot<DocumentData>[]-
emptyState?ReactNode-
error?Error-
hasMore?boolean-
isLoading?boolean-
onLoadMore?() => voidFired when the user requests another page. Wire to the hook’s loadMore. The component will not render a Load More button when this is undefined.
onSelect?(ref: DocumentReference) => void-
renderLabel?(doc: QueryDocumentSnapshot) => ReactNodeOptional renderer for the row label. Default renders the doc id. Override to show a field value alongside, an icon, etc.
renderRowAction?(doc: QueryDocumentSnapshot) => ReactNodeOptional per-row action(s), rendered as a SIBLING of the row’s select button inside the entry (not nested in it — so the action carries its own click handling without an invalid button-in-button). Used for row-level affordances like delete.
rowHeight?number | (index: number) => numberEstimated row height when virtualizing. Default 36 — matches a single-line text button at 13px font + ~10px padding. Pass a function for variable sizing (TanStack measures the actual height via ResizeObserver after the first paint anyway).
updateScope?stringStable collection/query identity used to reset update highlighting when the rendered list changes scope.
virtualizedHeight?string | numberPixel height the virtualized scroll container fills. Only applies when documents.length > virtualizeThreshold. Default '60vh' — consumers usually constrain via their layout.
virtualizeThreshold?numberAbove this row count, the list switches to virtualization via <VirtualList>. Default 100. Set to Infinity to disable (e.g. when measuring layout shifts is more important than scroll perf).

DocumentPreviewProps

Properties

PropertyTypeDescription
className?stringForwarded to the root <div>.
documentRef?DocumentReference<DocumentData>The document’s own reference. Required to surface its subcollections — DocumentSnapshot (as typed by pyric/firestore) doesn’t expose .ref, so the consumer threads the ref it already holds from fetching the doc. Without it (or without listSubcollections) the Subcollections section is omitted.
emptyState?ReactNodeContent rendered when the snapshot is missing or !exists(). Defaults to null (renders nothing).
fieldEditors?FieldEditorRegistryOverride or extend the built-in field editors. Merged on top of defaultFieldEditors — only the keys you provide override.
firestore?FirestoreFirestore handle passed to listSubcollections. Required alongside documentRef + listSubcollections to surface the Subcollections section (the same explicit-handle shape ReferencePicker uses).
listSubcollections?ListSubcollectionsInjected lister for the document’s subcollections. The modular Web SDK has no client-side listCollections; sandbox-backed apps wire pyric/sandbox’s in-process listing, production apps pass a known list or a server proxy. Same shape ReferencePicker / useCollectionList use. Omit to hide the Subcollections section.
onReferenceClick?(ref: DocumentReference) => voidFired when a reference field is clicked. When supplied, the reference Display renders as an interactive <button> (with data-pyric-clickable); when omitted, it stays inert as a <span>. Consumers wire navigation here — the library does not depend on a router.
onSubcollectionClick?(collection: CollectionReference) => voidFired when a subcollection’s drill affordance is activated. Receives the subcollection’s CollectionReference (its .path is the navigate target). Consumers wire navigation here.
snapshotDocumentSnapshot<DocumentData>Snapshot from useFirestoreDoc or getDoc. When null / undefined, renders emptyState.

EditorTree

Normalized tree of nodes. nodes is the lookup; childIds is the ordered child list per parent. The root node is itself a map node (its children are the document’s top-level fields).

Properties

PropertyType
childIdsRecord<string, string[]>
nodesRecord<string, FieldNode>
rootIdstring

FieldDisplayProps

Type Parameters

Type ParameterDefault type
Vunknown

Properties

PropertyTypeDescription
fieldEditors?FieldEditorRegistryRecursive editors (Map, Array) need the registry to dispatch on their children. Leaf editors (String, Number, …) can ignore this prop. Required-but-optional because the consumer of the component (<FieldRenderer>, <DocumentPreview>) always threads it through.
path?stringDotted/bracketed path from the document root, e.g. users.alice or tags[0]. Forwarded so consumer styles can target nested positions via [data-field-path="users.alice"].
valueVValue to display. The component’s V generic narrows this.

FieldEditorContract

Contract for one Firestore value type. Display (read-mode) is required; Edit + validate + defaultValue are required for leaf types that participate in M3’s editor. Map/array contracts supply only Display — their edit affordances come from the <DocumentEditor> compound component.

Type Parameters

Type ParameterDefault type
Vunknown

Properties

PropertyType
DisplayComponentType<FieldDisplayProps<V>>
Edit?ComponentType<FieldEditProps<V>>
typeFieldType

FieldEditProps

Props passed to a per-type Edit component. The leaf editors (string, number, …) consume this directly. Map/array editing is handled by the <DocumentEditor> compound component itself, not by individual editors — Firestore’s container shapes are special enough that pushing them through the registry costs more than it’s worth.

Type Parameters

Type ParameterDefault type
Vunknown

Properties

PropertyTypeDescription
error?stringValidation error attached by the reducer. Editors render it inline alongside the input.
onChange(next: V) => voidCommit a new value. The hook wires this to the reducer’s setValue action.
path?stringDotted/bracketed path from the document root.
valueVCurrent value.

FieldNode

One node in the normalized editor tree. Every Firestore field — leaf or container — is a node with a uuid, a parent pointer, a type, and a value. Containers (map, array) carry no value of their own; their children represent the value.

Properties

PropertyTypeDescription
error?stringValidation error message attached to the node by the reducer after every action. undefined when valid. Computed on EVERY action regardless of touchederrorCount / isValid must reflect the true state so Save stays disabled. touched governs only whether a consumer chooses to DISPLAY the error.
idstringStable uuid. Used as React key and as the action target.
keystringMap children carry their key here. Array children carry null (position comes from the parent’s childIds order). The root also carries null (it has no parent).
parentIdstringParent uuid; null for the root.
touched?booleanSet once the field has been blurred (or a submit attempt swept the whole tree via touchAll). Consumers gate error display on touched && error so a freshly-added empty row doesn’t show “Field name is required” before the user has interacted with it.
typeFieldTypeDiscriminated type. Drives which editor renders.
valueunknownLeaf value. undefined for map / array — those carry their value as children. null field type has value === null.

FieldRendererProps

Properties

PropertyTypeDescription
fieldEditorsFieldEditorRegistryRegistry to dispatch through. Pass the merged registry — this component does not fall back to defaults on its own (to avoid a circular import with the editors). <DocumentPreview> is the entry point that merges user overrides into defaults.
path?string-
valueunknown-

ParsedImportDoc

One document to create. id === null means “let Firestore auto-id it” (only produced by the array shape when no generateId option is given — a map key is always a chosen id).

Properties

PropertyType
dataRecord<string, unknown>
idstring

ParseImportOptions

Properties

PropertyTypeDescription
generateId?() => stringWhen provided, array-shape entries get their auto-id GENERATED AT PARSE TIME (instead of id: null / addDoc-at-write-time). Fixing ids at parse makes a retry after a partial failure idempotent: the same parse’s ids are reused, so re-running the import cannot duplicate already-written docs. Use firestoreAutoId for prod-parity ids.

ParseImportResult

Properties

PropertyTypeDescription
docsParsedImportDoc[]-
errorsstring[]Human-readable problems found while parsing. A non-empty errors does NOT necessarily mean docs is empty — the parser is per-item tolerant so one bad entry doesn’t block the rest; the caller decides whether to block on any error or proceed with the valid subset.

QueryBuilderActions

Properties

PropertyTypeDescription
addCondition(c?: Partial<Omit<QueryCondition, "id">>) => void-
buildQuery(base: | Query<DocumentData> | CollectionReference<DocumentData>) => QueryCompose the state into a Firestore Query. Returns the base collection when there are no conditions / orderBy / limit. Conditions with empty field are skipped — the builder UI lets users add a row before they’ve filled it in.
removeCondition(id: string) => void-
reset() => void-
setLimit(limit?: number) => void-
setOrderBy(orderBy?: { direction: QueryOrderDirection; field: string; }) => void-
updateCondition(id: string, patch: Partial<Omit<QueryCondition, "id">>) => void-

QueryBuilderProps

Properties

PropertyTypeDescription
className?string-
initial?Partial<QueryBuilderState>Drives the hook used internally. Both the state and the composed Query are exposed via onChange.
onChange?(builder: UseQueryBuilderResult) => voidFired on every state change with the latest builder API. The parent typically calls builder.buildQuery(collection) and feeds the result into useDocumentList / useFirestoreCollection.

QueryBuilderState

Properties

PropertyType
conditionsQueryCondition[]
limit?number
orderBy?{ direction: QueryOrderDirection; field: string; }
orderBy.directionQueryOrderDirection
orderBy.fieldstring

QueryCondition

Properties

PropertyType
fieldstring
idstring
opQueryWhereFilterOp
valueunknown

RecursiveDeleteImpl

Implementation injected by the consumer. The library doesn’t ship one — sandbox-backed apps usually walk pyric/sandbox’s in-process tree; production apps usually call a Cloud Function. Either way, start returns an async iterator emitting progress.

Properties

PropertyType
start(target: | DocumentReference<DocumentData> | CollectionReference<DocumentData>) => AsyncIterableIterator<RecursiveDeleteProgress>

RecursiveDeleteProgress

Properties

PropertyTypeDescription
deletedCountnumberTotal nodes deleted so far.
donebooleanTrue for the final emission.

ReferencePickerProps

Properties

PropertyTypeDescription
className?stringForwarded to the root.
firestoreFirestore-
initialPath?stringInitial path text.
listCollections(firestore: Firestore, parent: DocumentReference<DocumentData>) => Promise<CollectionReference<DocumentData>[]>Lister for subcollections. Required — see useReferencePicker docs for the rationale.
onPick?(ref: DocumentReference) => voidFired when the user commits a picked reference (browse pick OR a valid manually-typed path with the Commit button).
pathLabel?stringLabel for the path text input. Default ‘Document path’.

SubscriptionState

Type Parameters

Type Parameter
T

Properties

PropertyType
dataT
errorError
isLoadingboolean

UseCollectionListOptions

Properties

PropertyTypeDescription
firestoreFirestore-
listCollections(firestore: Firestore, parent: DocumentReference<DocumentData>) => Promise<CollectionReference<DocumentData>[]>Injected collection-listing function. The library doesn’t ship a default — the modular Web SDK doesn’t expose listCollections on the client. Sandbox-backed apps usually wire pyric/sandbox’s in-process listing; production apps either pass a known list (e.g. from a schema) or call a server proxy.
parent?DocumentReference<DocumentData>Parent document, or null/undefined for root collections.

UseCollectionListResult

Properties

PropertyTypeDescription
collectionsCollectionReference<DocumentData>[]-
createCollection(collectionId: string, firstDoc: { data: Record<string, unknown>; id: string; }) => Promise<DocumentReference<DocumentData>>Create a new collection by writing its first document. Firestore collections don’t exist independently of their documents — setDoc on the first child path materializes the collection.
errorError-
isLoadingboolean-
refresh() => voidRe-run the listing function.

UseDocumentEditorOptions

Properties

PropertyTypeDescription
initial?Record<string, unknown>Initial document data — the same shape a DocumentSnapshot.data() call returns.

UseDocumentEditorResult

Reducer state. tree is the live document under edit; initial is the snapshot the editor was constructed from (used to implement reset and isDirty).

Extends

Properties

PropertyTypeDescription
addArrayEntry(parentId: string, childType: FieldType) => voidAppend a child to an array. Nested arrays are silently rejected by the reducer (Firestore disallows them).
addMapEntry(parentId: string, key: string, childType: FieldType) => voidAppend a child to a map.
dispatch(action: DocumentEditorAction) => voidRaw dispatch — drops to the reducer-action surface. Prefer the named helpers below.
errorCountnumberCount of nodes with an active error. Derived after every action; the reducer keeps it in state to avoid a tree walk on every render.
initialEditorTreeFrozen copy of the tree at construction. reset restores from here; isDirty is computed by comparing serializations.
isDirtybooleantrue once any modifying action has fired since the last reset. Cleared by reset. Does NOT clear when the user manually re-enters the original values — checking that would require a full serialization comparison on every dispatch.
isValidbooleanConvenience: errorCount === 0.
remove(nodeId: string) => voidRemove a node (and all its descendants). Removing the root is a no-op.
replaceData(data: Record<string, unknown>) => voidReplace the editor with a newly delivered snapshot and adopt it as the clean baseline. Intended for live document viewers.
reset() => voidRestore the tree to its initial state. Clears isDirty.
setKey(nodeId: string, key: string) => voidSet a map-child’s key.
setType(nodeId: string, newType: FieldType) => voidSwitch a node’s type. Map/array nodes drop their children.
setValue(nodeId: string, value: unknown) => voidUpdate a leaf value.
toData() => Record<string, unknown>Serialize the tree back to a Firestore-shaped object suitable for setDoc / updateDoc.
touch(nodeId: string) => voidMark one node touched (dispatch on blur). Gates error display — a freshly-added row stays quiet until the user leaves it.
touchAll() => voidMark every node touched (dispatch on a submit attempt) so any hidden errors surface at once.
treeEditorTree-

UseDocumentListOptions

Properties

PropertyTypeDescription
collectionCollectionReference-
mode?"paged" | "live"paged preserves the historical get-based cursor behavior. live keeps the currently requested window under an onSnapshot subscription and grows that window when loadMore is requested. Default paged.
pageSize?numberPage size for cursor-based pagination. Default 50.
query?QueryOptional filter / sort. If omitted, the raw collection is used.

UseDocumentListResult

Properties

PropertyTypeDescription
createDocument(id: string, data: Record<string, unknown>, opts?: { onExisting?: "overwrite" | "fail"; }) => Promise<DocumentReference<DocumentData>>Create a document. If id is null, Firestore generates one via addDoc. With onExisting: 'fail' (CREATE semantics, the admin create() analog) an id that already exists rejects with code: 'already-exists' instead of silently overwriting — checked against the BACKEND (a getDoc probe), not any loaded page, so it is honest beyond pagination. Default: ‘overwrite’ (plain setDoc, the historical behavior).
deleteDocument(ref: DocumentReference) => Promise<void>-
documentsQueryDocumentSnapshot<DocumentData>[]-
errorError-
hasMorebooleanTrue if there might be another page. The hook tracks this via the last fetch’s length === pageSize.
isLoadingboolean-
loadMore() => voidFetch the next page; live mode grows and re-establishes its window.
refresh() => voidRe-establish the active read/subscription. Useful after the consumer mutates data outside this hook.
subscriptionGenerationnumberIdentifies the active live subscription. Consumers that diff result snapshots can include this in their scope so a re-subscription (including load-more) establishes a silent baseline instead of looking like writes.

UseDocumentSubcollectionsOptions

Properties

PropertyTypeDescription
documentRefDocumentReference<DocumentData>The document whose subcollections to list. When null/undefined the hook stays idle (empty, not loading) — used when the preview has no ref to drill from.
firestoreFirestore-
listSubcollectionsListSubcollections-

UseDocumentSubcollectionsResult

Properties

PropertyType
errorError
isLoadingboolean
subcollectionsCollectionReference<DocumentData>[]

UseQueryBuilderOptions

Properties

PropertyTypeDescription
initial?Partial<QueryBuilderState>Pre-populate the builder.

UseRecursiveDeleteResult

Properties

PropertyTypeDescription
delete(target: | DocumentReference<DocumentData> | CollectionReference<DocumentData>) => Promise<void>Run the delete. Resolves when the iterator signals done.
errorErrorError thrown by the iterator, if any. Cleared at the start of the next call.
isRunningbooleanTrue while an iteration is in flight.
progressnumberNumber of nodes deleted in the current/last run.

UseReferencePickerOptions

Properties

PropertyTypeDescription
firestoreFirestore-
initialPath?stringInitial value to pre-populate the text input + parse.
listCollections(firestore: Firestore, parent: DocumentReference<DocumentData>) => Promise<CollectionReference<DocumentData>[]>Lister for subcollections under a parent (or root when parent == null). The library does not ship a default — see useCollectionList for the same rationale (the modular Web SDK can’t enumerate collections client-side).
pageSize?numberDefault page size for the document list when browsing inside a collection. Default 20.

UseReferencePickerResult

Properties

PropertyTypeDescription
browseLocationBrowseLocationCurrent browse position in the tree.
canDrillBackbooleanWhether drillBack has anywhere to go.
clear() => voidClear the path input + reset browse to root.
collectionsCollectionReference<DocumentData>[]Collections available at the current browse level. Populated when browseLocation is root or document.
documentsQueryDocumentSnapshot<DocumentData>[]First page of documents in the current collection — populated when browseLocation.kind === 'collection'.
drillBack() => voidStep back one level. No-op when at root.
drillIntoCollection(ref: CollectionReference) => voidDrill into a collection — fetches its first page of documents.
drillIntoDocument(ref: DocumentReference) => voidDrill into a document — fetches its subcollections.
errorstringParse error, or null when valid.
isLoadingbooleanTrue while a fetch is in flight.
pathInputstringCurrent text input value.
pick(ref: DocumentReference) => voidCommit a chosen reference. Updates pathInput (and therefore the parsed reference).
referenceDocumentReference<DocumentData>Validated DocumentReference parsed from pathInput, or null when the path is empty / invalid.
setPathInput(path: string) => voidSet the text-input value. Parses on every change.

VectorView

Normalized read-side view of a Firestore vector (embedding) value. Editors and the renderer work against this rather than the raw shape so they don’t have to care which backend produced the value.

Properties

PropertyModifierTypeDescription
dimensionreadonlynumberNumber of components. Equivalent to values.length; surfaced separately because that’s what the UI labels (vector · <dims>).
valuesreadonlynumber[]The embedding components. Defensive copy — safe to read freely.

Type Aliases

BrowseLocation

type BrowseLocation =
  | {
  kind: "root";
}
  | {
  kind: "document";
  ref: DocumentReference;
}
  | {
  kind: "collection";
  ref: CollectionReference;
};

DocumentEditorAction

type DocumentEditorAction =
  | {
  nodeId: string;
  type: "setValue";
  value: unknown;
}
  | {
  newType: FieldType;
  nodeId: string;
  type: "setType";
}
  | {
  key: string;
  nodeId: string;
  type: "setKey";
}
  | {
  childType: FieldType;
  key: string;
  parentId: string;
  type: "addMapEntry";
}
  | {
  childType: FieldType;
  parentId: string;
  type: "addArrayEntry";
}
  | {
  nodeId: string;
  type: "remove";
}
  | {
  type: "reset";
}
  | {
  data: Record<string, unknown>;
  type: "replaceData";
}
  | {
  nodeId: string;
  type: "touch";
}
  | {
  type: "touchAll";
};

Discriminated union of every action the reducer accepts. Each action carries a type discriminator plus the data the reducer needs to apply it.

Type Declaration

{
  nodeId: string;
  type: "setValue";
  value: unknown;
}
nodeId
nodeId: string;
type
type: "setValue";
value
value: unknown;
{
  newType: FieldType;
  nodeId: string;
  type: "setType";
}
newType
newType: FieldType;
nodeId
nodeId: string;
type
type: "setType";
{
  key: string;
  nodeId: string;
  type: "setKey";
}
key
key: string;
nodeId
nodeId: string;
type
type: "setKey";
{
  childType: FieldType;
  key: string;
  parentId: string;
  type: "addMapEntry";
}
childType
childType: FieldType;
key
key: string;
parentId
parentId: string;
type
type: "addMapEntry";
{
  childType: FieldType;
  parentId: string;
  type: "addArrayEntry";
}
childType
childType: FieldType;
parentId
parentId: string;
type
type: "addArrayEntry";
{
  nodeId: string;
  type: "remove";
}
nodeId
nodeId: string;
type
type: "remove";
{
  type: "reset";
}
type
type: "reset";
{
  data: Record<string, unknown>;
  type: "replaceData";
}
data
data: Record<string, unknown>;
type
type: "replaceData";
{
  nodeId: string;
  type: "touch";
}
nodeId
nodeId: string;
type
type: "touch";

Mark one node touched (dispatched on blur). Doesn’t change any value — only gates error display for consumers that check it.

{
  type: "touchAll";
}
type
type: "touchAll";

Mark every node touched (dispatched on a submit attempt), so errors that were hidden pre-interaction all surface at once.


FieldEditorRegistry

type FieldEditorRegistry = Partial<Record<FieldType, FieldEditorContract<any>>>;

Map of field-type to editor contract. Partial<…> so consumers can override one type without re-supplying the rest — the merge happens at the <DocumentPreview> boundary.

The stored value type is FieldEditorContract<any> rather than FieldEditorContract<unknown> because each per-type contract narrows its generic (e.g., FieldEditorContract<Timestamp> for timestamp) and TypeScript’s ComponentType is invariant in props. any at the registry layer means the type-safety lives at the per-contract definition site, not in the dispatch map. FieldRenderer narrows back from unknown -> the right contract via inferType at dispatch time.


FieldType

type FieldType =
  | "string"
  | "number"
  | "boolean"
  | "null"
  | "timestamp"
  | "geopoint"
  | "reference"
  | "bytes"
  | "map"
  | "array"
  | "vector";

The set of value types @pyric/ui knows how to display + edit. Maps 1:1 to Firestore’s serializable value shapes; consumers can extend the registry but the built-in editors cover these.


FirestoreApi

type FirestoreApi = Pick<pyric-firestore-reference-api,
  | "addDoc"
  | "collection"
  | "deleteDoc"
  | "doc"
  | "getDoc"
  | "getDocs"
  | "limit"
  | "onSnapshot"
  | "query"
  | "setDoc"
| "startAfter">;

The modular Firestore functions the data hooks call, as an INJECTABLE bundle.

WHY: the hooks default to the in-process pyric/firestore API, but Pyric Studio’s served mode drives the SAME ops over a SharedWorker via a PARALLEL modular client (@pyric/cli/serve/worker: its own collection/getDocs/… over a MessagePort, and a ClientDb that is not a pyric/firestore Firestore). Statically importing the in-process fns hardwires the hooks to the in-page sandbox; reading them from this context lets a consumer inject the worker client’s fns so the hooks operate on the live worker backend without the hooks (or the components) knowing which backend they hit.

The bundle is typed to the in-process signatures. A worker bundle is adapted (cast) to this shape at the Studio boundary: the worker handles + snapshots are runtime-compatible at the surface the hooks use (.id / .data() / .docs / .ref), which is the contract function-injection relies on.

Default = the real pyric/firestore fns, so every existing consumer (the dev-seed review build, tests, any app embedding @pyric/ui) is unchanged: no provider needed unless you are swapping the backend.


ListSubcollections()

type ListSubcollections = (firestore: Firestore, parent: DocumentReference) => Promise<CollectionReference[]>;

Lister for a document’s own subcollections. Same injected-lister shape as useCollectionList / ReferencePicker use — the modular Web SDK doesn’t expose a native listCollections on the client, so the caller wires it (sandbox in-process listing, a server proxy, or a known schema list).

Parameters

ParameterType
firestoreFirestore
parentDocumentReference

Returns

Promise<CollectionReference[]>


QueryOp

type QueryOp = WhereFilterOp;

UseQueryBuilderResult

type UseQueryBuilderResult = QueryBuilderState & QueryBuilderActions;

Variables

defaultFieldEditors

const defaultFieldEditors: FieldEditorRegistry;

Default registry. Covers every FieldType. Consumers extend or override by passing their own (partial) registry into <DocumentPreview> / <FieldRenderer> — the components merge overrides into these defaults so a consumer can swap just one editor without re-declaring the rest.


DocumentEditor

const DocumentEditor: {
  Fields: typeof DocumentEditorFields;
  Root: typeof DocumentEditorRoot;
};

Compound root export. Consumers pattern-match via dot access:

<DocumentEditor.Root initial={data} onChange={…}> <DocumentEditor.Fields /> </DocumentEditor.Root>

Type Declaration

Fields
Fields: typeof DocumentEditorFields;

Root
Root: typeof DocumentEditorRoot;

MULTI_VALUE_OPS

const MULTI_VALUE_OPS: ReadonlySet<QueryOp>;

Ops that accept an array of values. The value editor in the bundled parses the input as JSON for these.


QUERY_OPS

const QUERY_OPS: readonly QueryOp[];

Functions

asVectorView()

function asVectorView(value: unknown): VectorView;

Detect + normalize a Firestore vector value, or return null if the value isn’t a vector. Vectors reach @pyric/ui in several runtime shapes depending on the backend the snapshot came from — there is no single VectorValue class pyric/firestore re-exports, so we match structurally (the same strategy isDocumentReferenceShape uses for refs):

  1. pyric Vector wrapper — frozen .value: number[] array plus a .dimension getter (sandbox / rules-side reads).
  2. firebase/firestore (web) VectorValue — exposes .toArray() and nothing else publicly.
  3. firebase-admin VectorValue — internal ._values: number[] (also a .toArray()).
  4. wire sentinel{ __type__: '__vector__', value: number[] }, the plain-object encoded form a discover crawler / seed emits.

A bare number[] is intentionally NOT a vector — those stay array. Only the typed/branded shapes above match.

Parameters

ParameterType
valueunknown

Returns

VectorView


CollectionList()

function CollectionList(__namedParameters: CollectionListProps): Element;

Headless collection list. Takes a pre-fetched array of references (from useCollectionList) plus a select callback. Renders one row per collection with data-pyric-collection-id for styling and testing. The library does not own the data fetch — the hook does — so this component is a thin presentational layer.

Parameters

ParameterType
__namedParametersCollectionListProps

Returns

Element


DeleteWithConfirm()

function DeleteWithConfirm(__namedParameters: DeleteWithConfirmProps): Element;

Composition that wires useConfirm + useRecursiveDelete. Requires a <ConfirmProvider> ancestor.

The default trigger renders a plain <button> carrying the destructive intent (the consumer styles via [data-pyric-destructive]). Consumers wanting different chrome pass renderTrigger.

Parameters

ParameterType
__namedParametersDeleteWithConfirmProps

Returns

Element


detectCollisions()

function detectCollisions(existingIds: readonly string[], docs: readonly ParsedImportDoc[]): string[];

Ids in docs (map-shape entries only — id !== null) that already exist in existingIds. The UI shows the skip-or-overwrite policy choice ONLY when this returns a non-empty list.

Parameters

ParameterType
existingIdsreadonly string[]
docsreadonly ParsedImportDoc[]

Returns

string[]


DocumentEditorFields()

function DocumentEditorFields(): Element;

Renders the top-level fields of the document. For finer control, a consumer can call useDocumentEditorContext() and render the tree themselves.

Returns

Element


DocumentEditorRoot()

function DocumentEditorRoot(__namedParameters: DocumentEditorRootProps): Element;

Wires the useDocumentEditor hook + field-editor registry into a React context so <DocumentEditor.Fields> and <DocumentEditor.AddField> can render the tree without prop drilling.

Pattern: hook + compound component. Consumers wanting full control over the layout call useDocumentEditor directly and render their own tree; consumers wanting the default rendering use this.

Parameters

ParameterType
__namedParametersDocumentEditorRootProps

Returns

Element


DocumentList()

function DocumentList(__namedParameters: DocumentListProps): Element;

Headless document list. Below virtualizeThreshold, renders a plain <ul>; above it, switches to TanStack-Virtual via <VirtualList> so 10k-doc collections don’t bloat the DOM.

The hook owns pagination state; this component just renders. The Load More button only renders when hasMore is true AND onLoadMore is provided. Consumers wanting infinite scroll trigger onLoadMore from a sentinel IntersectionObserver in their own code — the component doesn’t bake that policy in.

Parameters

ParameterType
__namedParametersDocumentListProps

Returns

Element


DocumentPreview()

function DocumentPreview(__namedParameters: DocumentPreviewProps): Element;

Read-only renderer for a Firestore document. Iterates top-level fields in lexicographic order; each field dispatches through the field-editor registry on its inferred type.

Headless — no shipped CSS. Consumers style via className on the root and [data-pyric-field-type] / [data-pyric-field-path] attribute selectors on the per-field nodes.

Editing arrives in M3 (<DocumentEditor>). M2 only displays.

Parameters

ParameterType
__namedParametersDocumentPreviewProps

Returns

Element


FieldRenderer()

function FieldRenderer(__namedParameters: FieldRendererProps): Element;

Dispatches a single value to its registered display component. Recursive editors (Map, Array) re-enter through this component for their children, threading the same registry.

Parameters

ParameterType
__namedParametersFieldRendererProps

Returns

Element


FirestoreApiProvider()

function FirestoreApiProvider(__namedParameters: {
  children: ReactNode;
  value: FirestoreApi;
}): FunctionComponentElement<ProviderProps<FirestoreApi>>;

Provide a Firestore API bundle to the subtree. Pyric Studio wraps its data surface with this, supplying the in-process bundle for dev-seed review and the SharedWorker client bundle under pyric dev --ui.

Parameters

ParameterType
__namedParameters{ children: ReactNode; value: FirestoreApi; }
__namedParameters.childrenReactNode
__namedParameters.valueFirestoreApi

Returns

FunctionComponentElement<ProviderProps<FirestoreApi>>


firestoreAutoId()

function firestoreAutoId(): string;

A Firestore-style 20-char auto id (same alphabet/length the SDK uses).

Returns

string


firestoreValuesEqual()

function firestoreValuesEqual(previous: unknown, next: unknown): boolean;

Firestore-aware structural equality for values delivered by either the in-process SDK or the SharedWorker serializer.

Parameters

ParameterType
previousunknown
nextunknown

Returns

boolean


inferType()

function inferType(value: unknown): FieldType;

Runtime-classify a value into one of the FieldTypes.

The discrimination order matters:

  • null checked before typeof === 'object' (null is an object)
  • vector (a typed embedding wrapper) checked before Array.isArray and before generic objects — its wire-sentinel shape is a plain object, and a bare number[] must stay array, not vector
  • Array.isArray checked before generic objects
  • Firestore special types (Timestamp/GeoPoint/Bytes/DocumentRef) checked before falling through to map

undefined values aren’t legal Firestore field values; we coerce them to 'null' rather than throw — the caller can decide whether to display or filter.

Parameters

ParameterType
valueunknown

Returns

FieldType


initState()

function initState(initial: Record<string, unknown>): DocumentEditorState;

Initial state factory. Builds tree + initial snapshot + error count.

Parameters

ParameterType
initialRecord<string, unknown>

Returns

DocumentEditorState


mergeFieldEditors()

function mergeFieldEditors(override: Partial<Record<FieldType, FieldEditorContract<any>>>): FieldEditorRegistry;

Merge a consumer-supplied registry over the defaults. undefined input returns the defaults as-is. Used internally by <DocumentPreview> so consumers don’t have to spread manually.

Parameters

ParameterType
overridePartial<Record<FieldType, FieldEditorContract<any>>>

Returns

FieldEditorRegistry


parseImport()

function parseImport(input: string, options?: ParseImportOptions): ParseImportResult;

Parse raw JSON text into the documents it would create. Never throws — a JSON syntax error or a wrong top-level shape becomes an entry in errors with an empty docs array.

Parameters

ParameterType
inputstring
options?ParseImportOptions

Returns

ParseImportResult


QueryBuilder()

function QueryBuilder(__namedParameters: QueryBuilderProps): Element;

Default visible composition over useQueryBuilder. Renders the condition list + orderBy + limit form. Headless — every node carries data-pyric-* for styling.

Values are JSON-parsed on input. 42, "text", true, null, and [1, 2, 3] (for in/not-in/array-contains-any) all work; raw strings that aren’t JSON-parsable fall through as-is. For non-JSON Firestore values (Timestamp, GeoPoint, Reference, Bytes), consumers either use the hook directly with their own value editors or swap the rendered component out.

Parameters

ParameterType
__namedParametersQueryBuilderProps

Returns

Element


reducer()

function reducer(state: DocumentEditorState, action: DocumentEditorAction): DocumentEditorState;

Pure reducer. Every action returns a fresh state — no in-place mutation of state.tree. Validation re-runs after the structural change so errorCount is always current. Container nodes (map / array) ignore actions that don’t apply to them rather than throwing; the components only render valid affordances per type.

Parameters

Returns

DocumentEditorState


ReferencePicker()

function ReferencePicker(__namedParameters: ReferencePickerProps): Element;

Visible reference picker — text input + browseable panel.

Two ways to commit a reference:

  1. Type a path, then click Commit (enabled only when the path parses to a valid DocumentReference).
  2. Drill into a collection in the panel and click a document row.

Either path fires onPick(ref). Headless — emits structural data-pyric-* for styling.

Parameters

ParameterType
__namedParametersReferencePickerProps

Returns

Element


treeFromData()

function treeFromData(data: Record<string, unknown>): EditorTree;

Build a normalized editor tree from a Firestore-shaped object. The root node is a virtual map that holds the document’s top-level fields. Order of children mirrors Object.entries (the renderer is responsible for any sort it wants).

Parameters

ParameterType
dataRecord<string, unknown>

Returns

EditorTree


treeToData()

function treeToData(tree: EditorTree): Record<string, unknown>;

Serialize a tree back to a Firestore-shaped object. Leaf values pass through unchanged (so a Timestamp round-trips as the same Timestamp instance). Maps recurse with their sorted keys; arrays recurse in childIds order.

Parameters

ParameterType
treeEditorTree

Returns

Record<string, unknown>


truncateVectorsForDisplay()

function truncateVectorsForDisplay(value: unknown): unknown;

Deep-replace any vector-shaped value with a compact preview STRING, so the result can be JSON.stringify’d / formatted without dumping full embeddings. Recurses plain objects + arrays; class instances (Timestamp/GeoPoint) and scalars pass through untouched. Vector instances/sentinels are caught first.

Parameters

ParameterType
valueunknown

Returns

unknown


useCollectionList()

function useCollectionList(__namedParameters: UseCollectionListOptions): UseCollectionListResult;

Operational read + create for collections under a parent (or root). Listing is injected because the modular Web SDK doesn’t expose a native listCollections on the client — see options docs.

Parameters

ParameterType
__namedParametersUseCollectionListOptions

Returns

UseCollectionListResult


useDocumentEditor()

function useDocumentEditor(options?: UseDocumentEditorOptions): UseDocumentEditorResult;

Headless document editor. Owns the entire edit state for one document via a pure reducer. Consumers either render the bundled <DocumentEditor> compound component over this hook, or render their own tree using the returned state.

The hook builds its tree from initial on first mount. Changing initial later does NOT rebuild the tree; live viewers explicitly call replaceData() when a newer snapshot should become the clean baseline. This matches the firebase-tools-ui pattern of treating the editor as a stateful workspace while still allowing snapshot-driven reconciliation.

Parameters

ParameterType
options?UseDocumentEditorOptions

Returns

UseDocumentEditorResult


useDocumentEditorContext()

function useDocumentEditorContext(): UseDocumentEditorResult;

Read access to the underlying editor state from inside a Root.

Returns

UseDocumentEditorResult


useDocumentList()

function useDocumentList(__namedParameters: UseDocumentListOptions): UseDocumentListResult;

Paginated document list with two acquisition strategies. The default paged mode uses startAfter and accumulates one-shot reads. live keeps the requested prefix under one onSnapshot listener; loading more grows that prefix and establishes a new subscription baseline.

Parameters

ParameterType
__namedParametersUseDocumentListOptions

Returns

UseDocumentListResult


useDocumentSubcollections()

function useDocumentSubcollections(__namedParameters: UseDocumentSubcollectionsOptions): UseDocumentSubcollectionsResult;

Read a single document’s subcollection list. A thin specialization of the useCollectionList pattern, scoped to one parent document and read-only (no create — that lives in useCollectionList).

Parameters

ParameterType
__namedParametersUseDocumentSubcollectionsOptions

Returns

UseDocumentSubcollectionsResult


useFirestoreApi()

function useFirestoreApi(): FirestoreApi;

Read the active Firestore API bundle (defaults to in-process pyric/firestore).

Returns

FirestoreApi


useFirestoreCollection()

function useFirestoreCollection(query: Query<DocumentData>): SubscriptionState<QuerySnapshot<DocumentData>>;

Subscribe to a Firestore query (a Query from pyric/firestore’s modular surface, including any CollectionReference, which extends Query). Returns { data, error, isLoading }.

Null/undefined query short-circuits to idle. Cleanup is automatic on unmount or query change. Query objects don’t have a stable structural identity, so the consumer must memoize at the call site — pass the same instance across renders to avoid re-subscribing.

Parameters

ParameterType
queryQuery<DocumentData>

Returns

SubscriptionState<QuerySnapshot<DocumentData>>


useFirestoreDoc()

function useFirestoreDoc(ref: DocumentReference<DocumentData>): SubscriptionState<DocumentSnapshot<DocumentData>>;

Subscribe to a single Firestore document. Returns { data, error, isLoading }. Null/undefined ref short-circuits to an idle state (data: undefined, error: undefined, isLoading: false) — useful for conditional rendering before a ref is known.

Cleanup is automatic on unmount or ref change. Memoize the ref at the call site; this hook’s effect re-runs on identity change.

Parameters

Returns

SubscriptionState<DocumentSnapshot<DocumentData>>


useQueryBuilder()

function useQueryBuilder(options?: UseQueryBuilderOptions): UseQueryBuilderResult;

Headless query-builder state machine. Single-level — no nested and()/or() groups in v1. Consumers compose the state into a Firestore Query via buildQuery(base) and feed that into useDocumentList / useFirestoreCollection.

Parameters

ParameterType
options?UseQueryBuilderOptions

Returns

UseQueryBuilderResult


useRecursiveDelete()

function useRecursiveDelete(impl: RecursiveDeleteImpl): UseRecursiveDeleteResult;

Drive a RecursiveDeleteImpl from a React component. Tracks progress + running state so the consumer can render a progress indicator. Errors are caught and surfaced via the returned state, not thrown.

Stale-run protection: if the component remounts (or the user cancels and starts a new run) before a previous iteration finishes, the older run’s progress updates are dropped via a generation token.

Parameters

ParameterType
implRecursiveDeleteImpl

Returns

UseRecursiveDeleteResult


useReferencePicker()

function useReferencePicker(__namedParameters: UseReferencePickerOptions): UseReferencePickerResult;

Picker state machine. Browses a Firestore tree level-by-level (root → collection → document → collection → …), maintains a separately-validated text-input path, and commits a chosen reference via pick.

Headless — consumers compose the resulting state into their own UI, or use the bundled <ReferencePicker> component.

Parameters

ParameterType
__namedParametersUseReferencePickerOptions

Returns

UseReferencePickerResult


validateCollectionId()

function validateCollectionId(id: string): string;

Validate a collection id. Returns an error message, or undefined when valid.

Parameters

ParameterType
idstring

Returns

string


validateDocumentId()

function validateDocumentId(id: string): string;

Validate a document id. Returns an error message, or undefined when valid.

Parameters

ParameterType
idstring

Returns

string


validateLeaf()

function validateLeaf(type: FieldType, value: unknown): string;

Per-type leaf validator. Returns an error message when the value doesn’t satisfy the type’s constraints, undefined when valid.

map and array aren’t validated here — their integrity comes from their children + (for maps) sibling-key uniqueness, which is enforced in validateTree.

Parameters

ParameterType
typeFieldType
valueunknown

Returns

string


validateTree()

function validateTree(tree: EditorTree): {
  errorCount: number;
  tree: EditorTree;
};

Walk the tree, attach an error to each node, and return the mutated tree along with the total error count. The function does not mutate the input; it returns a fresh tree.

Per-leaf errors come from validateLeaf. Map nodes additionally surface duplicate-key + empty-key errors on the offending children (not on the parent).

Parameters

ParameterType
treeEditorTree

Returns

{
  errorCount: number;
  tree: EditorTree;
}
errorCount
errorCount: number;
tree
tree: EditorTree;

vectorPreview()

function vectorPreview(view: VectorView): string;

Compact, display-safe rendering of a vector: vector · <dim> [a, b, c, …]. So a real embedding never dumps its full array into a diff, a rules trace, or a debugger panel.

Parameters

ParameterType
viewVectorView

Returns

string