Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .changeset/spec-bridge-listview-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@object-ui/react": patch
---

refactor(spec-bridge): retire the hand-written `ListViewSpec`/`ListColumn` mirrors in the list-view bridge (#2231 follow-up)

The SpecBridge's list-view bridge kept a third hand-written copy of the ListView shape
(after the zod schema and the TS interface unified in the previous #2231 PR). It now
derives its input type from `@objectstack/spec/ui` (`Partial<ListView>`, spec `ListColumn`),
so the bridge can no longer drift from the protocol.

Behavior fix surfaced by the real types: spec `columns` is `string[] | ListColumn[]`, but
the old local interface only admitted `ListColumn[]` — a bare field-name column would have
produced a broken `{ accessorKey: undefined }` mapping. String columns now map to a default
column (`{ accessorKey: field, header: field }`).
79 changes: 14 additions & 65 deletions packages/react/src/spec-bridge/bridges/list-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,74 +8,23 @@

import type { SchemaNode } from '@object-ui/core';
import type { BridgeContext, BridgeFn } from '../types';
import type { ListViewGalleryConfig, ListViewTimelineConfig } from '@object-ui/types';
import type { ListView, ListColumn } from '@objectstack/spec/ui';

interface ListColumn {
field: string;
label?: string;
width?: number;
align?: string;
hidden?: boolean;
sortable?: boolean;
resizable?: boolean;
wrap?: boolean;
type?: string;
pinned?: string;
summary?: any;
link?: any;
action?: any;
}
/**
* Bridge input: the spec-canonical ListView (#2231 — the former hand-written
* `ListViewSpec`/`ListColumn` mirrors are retired; the shape now derives from
* `@objectstack/spec/ui` and can no longer drift). Relaxed to `Partial` because
* hosts routinely hand the bridge fragmentary view-configs (every field was
* optional in the old mirror too, including spec-required `columns`).
*/
type ListViewSpec = Partial<ListView>;

interface ListViewSpec {
name?: string;
label?: string;
type?: string;
data?: any;
columns?: ListColumn[];
filter?: any;
sort?: any;
searchableFields?: string[];
filterableFields?: string[];
selection?: any;
pagination?: any;
rowHeight?: string;
resizable?: boolean;
striped?: boolean;
bordered?: boolean;
grouping?: any;
rowColor?: any;
navigation?: any;
kanban?: any;
calendar?: any;
gantt?: any;
gallery?: ListViewGalleryConfig;
timeline?: ListViewTimelineConfig;
// P1.1 additions
rowActions?: string[];
bulkActions?: string[];
bulkActionDefs?: any[];
virtualScroll?: boolean;
conditionalFormatting?: Array<{ condition: string; style: Record<string, string> }>;
inlineEdit?: boolean;
exportOptions?: any;
emptyState?: { title?: string; message?: string; icon?: string };
userActions?: any;
appearance?: any;
/** UX-only hint: collapse appearance/grouping cluster into a single popover. */
compactToolbar?: boolean;
tabs?: any[];
addRecord?: any;
showRecordCount?: boolean;
allowPrinting?: boolean;
// P1.6 i18n & ARIA
aria?: { ariaLabel?: string; ariaDescribedBy?: string; role?: string };
sharing?: any;
hiddenFields?: string[];
fieldOrder?: string[];
description?: string;
}
function mapColumn(col: ListColumn | string): Record<string, any> {
// Spec-legacy shorthand: a bare field name stands for a default column.
if (typeof col === 'string') {
return { accessorKey: col, header: col };
}

function mapColumn(col: ListColumn): Record<string, any> {
const mapped: Record<string, any> = {
accessorKey: col.field,
header: col.label ?? col.field,
Expand Down
Loading