/** * URL (de)serialization for the v8 table view vocabulary (`TableView` from * `@urbicon-ui/table`: search, sort, page, pageSize, filters, groupBy). * * The types in this module are a **structural mirror** of the table package's * view types — deliberately not imported, so this package carries no * dependency on `@urbicon-ui/table`. A type-parity test over there guards the * shapes against drift; `bindViewToUrl` accepts any object shaped like * {@link TableViewLike}, which the real `TableView` is. * * The key scheme is the shipped one (`q`, `page`, `size`, `sort`, `dir`, * `group`, `filter`) — deep links written for v7 keep parsing. The write * side adds one compatible extension: an empty `filter=` marker, analogous * to `sort=`, so a cleared filter set elides like every other axis (the * shipped read side already tolerated it). */ /** * Filter operators supported by the table. Mirrors `FilterOperator` from * `@urbicon-ui/table`. Used as the runtime whitelist when parsing `filter` * params from the URL. */ export declare const TABLE_VIEW_FILTER_OPERATORS: readonly ["contains", "equals", "startsWith", "endsWith", "greaterThan", "lessThan"]; /** Filter operator of a view filter. Mirrors `@urbicon-ui/table`. */ export type TableViewFilterOperator = (typeof TABLE_VIEW_FILTER_OPERATORS)[number]; /** Single column filter on the `filters` axis. Mirrors `Filter` from `@urbicon-ui/table`. */ export interface TableViewFilter { /** Column ID the filter applies to. */ column: string; /** Filter operator. */ operator: TableViewFilterOperator; /** Filter value (always a string, numeric operators convert internally). */ value: string; } /** One of the six view axes. Mirrors `ViewAxis` from `@urbicon-ui/table`. */ export type TableViewAxis = 'search' | 'sort' | 'page' | 'pageSize' | 'filters' | 'groupBy'; /** All six view axes, in vocabulary order. */ export declare const TABLE_VIEW_AXES: readonly TableViewAxis[]; /** Sort state of a view. Mirrors `ViewSort` from `@urbicon-ui/table`. */ export interface TableViewSort { /** Column ID to sort by. */ column: string; /** Sort direction. */ direction: 'asc' | 'desc'; } /** * A fully resolved view state — never `undefined` anywhere. Mirrors * `TableViewSnapshot` from `@urbicon-ui/table`. */ export interface TableViewSnapshot { search: string; sort: TableViewSort | null; page: number; pageSize: number; filters: TableViewFilter[]; groupBy: string | null; } /** * The surface {@link bindViewToUrl} needs from a view object — a structural * mirror of the table package's `TableView` class. Field reads are reactive, * field writes count as the reader's own change; `applyExternal` is the * binding write surface, `claimAxes`/`releaseAxes` the fail-loud composition * registry, and `originOf` the per-axis (revision, origin) bookkeeping the * bindings decide by. */ export interface TableViewLike { readonly defaults: TableViewSnapshot; search: string; sort: TableViewSort | null; page: number; pageSize: number; filters: TableViewFilter[]; groupBy: string | null; applyExternal(partial: Partial, origin: 'external'): void; claimAxes(kind: 'url' | 'storage', axes: readonly TableViewAxis[]): void; releaseAxes(kind: 'url' | 'storage', axes: readonly TableViewAxis[]): void; markInitApplied(axes: readonly TableViewAxis[]): void; wasInitApplied(axis: TableViewAxis): boolean; originOf(axis: TableViewAxis): { revision: number; origin: 'user' | 'external' | 'init'; }; snapshot(): TableViewSnapshot; } /** The URL keys a set of axes owns, with the configured prefix applied. */ export declare function viewAxisKeys(axes: readonly TableViewAxis[], prefix?: string): string[]; /** The axes a URL names — presence only for params it actually carries. */ export declare function viewAxesNamedBy(sp: URLSearchParams, prefix?: string): TableViewAxis[]; /** * Parse search params into a **partial** view snapshot — a key per axis the * URL actually carries, and nothing else. Read tolerant per key: an * unparsable value on a *present* key falls back to the configured default * for that axis (the key was present, so the axis stays claimed), and * malformed filter entries are skipped individually. */ export declare function searchParamsToViewPartial(sp: URLSearchParams, defaults: Pick, prefix?: string): Partial; /** * Resolve a full view snapshot from search params: every axis the URL names * comes from the URL, every other one from `defaults` — the same resolution * the URL binding performs at init, for code that has no view (a server * `load`). * * This is also what a server `load` hands its fetch. Since v9 the view and * the query speak one vocabulary (#162), so there is nothing to project on * the way out: the object below is the same shape a managed `source.query` * receives. The `searchParamsToViewQuery` / `viewSnapshotToTableQuery` pair * that used to do the projecting were identity functions once the names * agreed, and are gone. * * The `defaults` argument is the point: it takes the very object * `createTableView({ defaults })` takes, so the server cannot resolve an * absent param differently from the client — and a default filter set is * expressible, which the old wire-vocabulary baseline could not manage no * matter how it was written (#157 finding 2). * * @example * ```ts * // shared with the component that calls createTableView({ defaults }) * export const invoiceView = { pageSize: 25, sort: { column: 'date', direction: 'desc' } }; * * export const load = async ({ url }) => ({ * initialResult: await fetchInvoices(searchParamsToViewSnapshot(url.searchParams, invoiceView)) * }); * ``` */ export declare function searchParamsToViewSnapshot(sp: URLSearchParams, defaults?: Partial, prefix?: string): TableViewSnapshot; /** * Serialize a snapshot, eliding every axis that equals the defaults — the * elision baseline *is* the view's defaults, structurally. `axes` restricts * the output to a binding's own axes: an unbound axis never reaches the URL, * no matter what the view holds. */ export declare function viewSnapshotToSearchParams(snapshot: TableViewSnapshot, defaults: TableViewSnapshot, axes?: readonly TableViewAxis[], prefix?: string): URLSearchParams; /** * Write-side validation: never serialize structurally invalid state. * * The strict half of the module's read-tolerant / write-strict contract, and * deliberately NOT called by {@link viewSnapshotToSearchParams}: that one runs * inside the URL binding on every view change, where a throw would take the * whole table down over a `view.page = 0` a consumer wrote. Serializing a bad * page there costs a wrong URL; throwing there costs the page. * * @throws TypeError when an axis holds a value the URL scheme cannot mean. */ export declare function assertValidViewSnapshot(snapshot: TableViewSnapshot): void; /** * Merge a view into existing search params: every key the given axes own is * replaced by the serialized snapshot, and every other param is preserved * untouched. Keys whose axis returned to its default are removed (the same * elision {@link viewSnapshotToSearchParams} applies). * * This is the one thing the axis-scoped serializer cannot do on its own — * everything else the retired `./table-query` module offered was the same * codec under wire-vocabulary names (#162). * * @param existing - Current search params (not mutated — a copy is returned). * @param snapshot - The view state to write. * @param defaults - Elision baseline, structurally the view's own defaults. * @param axes - Axes to write; every other axis is left alone in `existing`. * @param prefix - Key prefix, to namespace multiple synced tables on a page. * @returns New `URLSearchParams` with the view applied. * @throws TypeError when the snapshot is structurally invalid (write strict). */ export declare function applyViewToSearchParams(existing: URLSearchParams, snapshot: TableViewSnapshot, defaults: TableViewSnapshot, axes?: readonly TableViewAxis[], prefix?: string): URLSearchParams;