zod-collection-ui 0.0.1

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.
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Collection Affordance Schema — Core Types
3
+ *
4
+ * Defines the vocabulary for declaring what operations a collection of typed items
5
+ * supports, both at the collection level and per-field level.
6
+ *
7
+ * Terminology (following Gibson/Norman affordance theory):
8
+ * - Affordance: a declared capability (what the system CAN do)
9
+ * - Signifier: a UI element that communicates an affordance (what the user SEES)
10
+ * - Collection: a typed, queryable set of items
11
+ * - Item: a single member of a collection
12
+ * - Field: a named property of an item's type
13
+ * - Operation: a concrete action invokable on items/selection/collection
14
+ */
15
+ /** How a field can be sorted */
16
+ export type SortDirection = 'asc' | 'desc' | 'both' | 'none';
17
+ /** What kind of filter UI is appropriate for a field */
18
+ export type FilterType = 'exact' | 'search' | 'select' | 'multiSelect' | 'range' | 'contains' | 'boolean' | 'fuzzy';
19
+ /** Aggregation functions applicable to a field */
20
+ export type AggregationFn = 'sum' | 'avg' | 'min' | 'max' | 'count' | 'median' | 'uniqueCount';
21
+ /**
22
+ * Declares what operations are meaningful on a single field of an item.
23
+ *
24
+ * Design principle: exclusion-based (OData pattern).
25
+ * If not specified, defaults are inferred from the Zod type.
26
+ */
27
+ export interface FieldAffordance {
28
+ /** Can items be ordered by this field? Default: inferred from type. */
29
+ sortable?: boolean | SortDirection;
30
+ /** Can items be narrowed by this field? Default: inferred from type. */
31
+ filterable?: boolean | FilterType;
32
+ /** Is this field included in full-text search? Default: true for strings. */
33
+ searchable?: boolean;
34
+ /** Can items be grouped by this field's values? Default: true for enums. */
35
+ groupable?: boolean;
36
+ /** Aggregate functions applicable to this field. Default: inferred from numeric types. */
37
+ aggregatable?: boolean | AggregationFn[];
38
+ /** Is this field returned in responses? Default: true. */
39
+ readable?: boolean;
40
+ /** Can this field be modified? Default: inferred from field name/type. */
41
+ editable?: boolean;
42
+ /** Can be edited directly in the collection view (click-to-edit)? */
43
+ inlineEditable?: boolean;
44
+ /** Required when creating a new item (but not on update)? */
45
+ requiredOnCreate?: boolean;
46
+ /** Required when updating an item? */
47
+ requiredOnUpdate?: boolean;
48
+ /** Editable on create but read-only on update? */
49
+ immutableAfterCreate?: boolean;
50
+ /** Whether this field appears in the collection view. Default: true. */
51
+ visible?: boolean;
52
+ /** Explicitly hidden (stronger than visible: false — cannot be toggled by user). */
53
+ hidden?: boolean;
54
+ /** Only shown in detail/edit view, never in list/table. */
55
+ detailOnly?: boolean;
56
+ /** Appears in compact/summary views. */
57
+ summaryField?: boolean;
58
+ /** Default column width in pixels. */
59
+ columnWidth?: number;
60
+ /** Minimum column width. */
61
+ minWidth?: number;
62
+ /** Maximum column width. */
63
+ maxWidth?: number;
64
+ /** Can the user resize this column? Default: true. */
65
+ resizable?: boolean;
66
+ /** Pin to left or right edge. */
67
+ pinned?: 'left' | 'right' | false;
68
+ /** Position in field/column order (lower = earlier). */
69
+ order?: number;
70
+ /** Human-readable label for this field. Default: humanized from key. */
71
+ title?: string;
72
+ /** Description/help text for this field. */
73
+ description?: string;
74
+ /** Format string or function for display. */
75
+ displayFormat?: string;
76
+ /** Map enum values to badge variant names. */
77
+ badge?: Record<string, string>;
78
+ /** Make the value copyable with a clipboard button. */
79
+ copyable?: boolean;
80
+ /** Max characters before truncation. */
81
+ truncate?: number;
82
+ /** Show full value on hover when truncated. */
83
+ tooltip?: boolean;
84
+ /** Override the default edit widget type. */
85
+ editWidget?: string;
86
+ /** Placeholder text for edit widget. */
87
+ editPlaceholder?: string;
88
+ /** Help text shown below edit widget. */
89
+ editHelp?: string;
90
+ }
91
+ export interface PaginationConfig {
92
+ defaultPageSize?: number;
93
+ pageSizeOptions?: number[];
94
+ style?: 'pages' | 'loadMore' | 'infinite';
95
+ serverSide?: boolean;
96
+ }
97
+ export interface SearchConfig {
98
+ debounce?: number;
99
+ minChars?: number;
100
+ highlight?: boolean;
101
+ placeholder?: string;
102
+ }
103
+ export interface MultiSortConfig {
104
+ maxColumns?: number;
105
+ }
106
+ export interface GroupByConfig {
107
+ defaultField?: string;
108
+ collapsible?: boolean;
109
+ defaultState?: 'collapsed' | 'expanded';
110
+ }
111
+ export interface FilterPreset {
112
+ name: string;
113
+ label: string;
114
+ filters: Record<string, unknown>;
115
+ icon?: string;
116
+ }
117
+ export type ViewMode = 'table' | 'grid' | 'list' | 'kanban';
118
+ /**
119
+ * Declares what operations the collection as a whole supports.
120
+ *
121
+ * Design principle: opt-in for operations (create, delete, export),
122
+ * opt-out for query capabilities (filtering, sorting default to true).
123
+ */
124
+ export interface CollectionAffordances {
125
+ create?: boolean;
126
+ read?: boolean;
127
+ update?: boolean;
128
+ delete?: boolean;
129
+ bulkDelete?: boolean;
130
+ /** true = all editable fields, string[] = specific fields */
131
+ bulkEdit?: boolean | string[];
132
+ bulkArchive?: boolean;
133
+ search?: boolean | SearchConfig;
134
+ pagination?: boolean | PaginationConfig;
135
+ defaultSort?: {
136
+ field: string;
137
+ direction: 'asc' | 'desc';
138
+ };
139
+ multiSort?: boolean | MultiSortConfig;
140
+ filterPanel?: boolean;
141
+ filterPresets?: FilterPreset[];
142
+ savedFilters?: boolean;
143
+ groupBy?: boolean | GroupByConfig;
144
+ defaultView?: ViewMode;
145
+ views?: ViewMode[];
146
+ savedViews?: boolean;
147
+ export?: boolean | string[];
148
+ import?: boolean | string[];
149
+ selectable?: boolean | 'single' | 'multi';
150
+ refresh?: boolean;
151
+ autoRefresh?: number;
152
+ columnVisibility?: boolean;
153
+ columnOrder?: boolean;
154
+ columnResize?: boolean;
155
+ columnPin?: boolean;
156
+ reorder?: boolean;
157
+ undo?: boolean;
158
+ }
159
+ export type OperationScope = 'item' | 'selection' | 'collection';
160
+ export interface OperationConfirmation {
161
+ title: string;
162
+ message: string;
163
+ confirmLabel?: string;
164
+ cancelLabel?: string;
165
+ variant?: 'default' | 'destructive';
166
+ }
167
+ export interface OperationDefinition<TParams = unknown> {
168
+ /** Unique identifier for this operation. */
169
+ name: string;
170
+ /** Human-readable label. */
171
+ label: string;
172
+ /** What the operation acts on. */
173
+ scope: OperationScope;
174
+ /** Icon name (from icon library). */
175
+ icon?: string;
176
+ /** Visual style. */
177
+ variant?: 'default' | 'destructive' | 'secondary' | 'ghost';
178
+ /** Confirmation dialog before execution. */
179
+ confirm?: boolean | OperationConfirmation;
180
+ /** Keyboard shortcut (e.g., "ctrl+d", "delete"). */
181
+ keyboardShortcut?: string;
182
+ }
183
+ export interface CollectionConfig<TShape extends Record<string, unknown> = Record<string, unknown>> {
184
+ /** Collection-level affordances. */
185
+ affordances?: CollectionAffordances;
186
+ /** Per-field affordance overrides (merged with Zod .meta()). */
187
+ fields?: Partial<Record<keyof TShape, Partial<FieldAffordance>>>;
188
+ /** Custom operations beyond CRUD. */
189
+ operations?: OperationDefinition[];
190
+ /** Which field uniquely identifies items. Default: 'id'. */
191
+ idField?: string;
192
+ /** Which field is the human-readable label. Default: first string field. */
193
+ labelField?: string;
194
+ }
195
+ export interface ResolvedFieldAffordance extends Required<Pick<FieldAffordance, 'sortable' | 'filterable' | 'searchable' | 'groupable' | 'editable' | 'visible'>> {
196
+ title: string;
197
+ zodType: string;
198
+ zodDef: unknown;
199
+ [key: string]: unknown;
200
+ }
201
+ export interface ResolvedCollectionAffordances extends Required<Pick<CollectionAffordances, 'create' | 'read' | 'update' | 'delete' | 'selectable'>> {
202
+ search: false | SearchConfig;
203
+ pagination: false | Required<PaginationConfig>;
204
+ [key: string]: unknown;
205
+ }
package/dist/types.js ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Collection Affordance Schema — Core Types
3
+ *
4
+ * Defines the vocabulary for declaring what operations a collection of typed items
5
+ * supports, both at the collection level and per-field level.
6
+ *
7
+ * Terminology (following Gibson/Norman affordance theory):
8
+ * - Affordance: a declared capability (what the system CAN do)
9
+ * - Signifier: a UI element that communicates an affordance (what the user SEES)
10
+ * - Collection: a typed, queryable set of items
11
+ * - Item: a single member of a collection
12
+ * - Field: a named property of an item's type
13
+ * - Operation: a concrete action invokable on items/selection/collection
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "zod-collection-ui",
3
+ "version": "0.0.1",
4
+ "description": "Declare once, render anywhere. Schema-driven collection UIs from Zod — auto-generated table columns, form fields, filters, state, and data providers.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.build.json",
21
+ "prepublishOnly": "npm run build",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest",
24
+ "typecheck": "tsc --noEmit",
25
+ "example:basic": "tsx examples/01-basic-usage.ts",
26
+ "example:ecommerce": "tsx examples/02-ecommerce-catalog.ts",
27
+ "example:tasks": "tsx examples/03-task-tracker.ts",
28
+ "example:zero": "tsx examples/04-zero-config.ts"
29
+ },
30
+ "keywords": [
31
+ "zod",
32
+ "schema",
33
+ "ui",
34
+ "collection",
35
+ "table",
36
+ "form",
37
+ "filter",
38
+ "tanstack",
39
+ "headless",
40
+ "affordance",
41
+ "crud",
42
+ "schema-driven",
43
+ "declarative",
44
+ "code-generation"
45
+ ],
46
+ "author": "Thor Whalen",
47
+ "license": "MIT",
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "https://github.com/thorwhalen/zod-collection-ui"
51
+ },
52
+ "homepage": "https://github.com/thorwhalen/zod-collection-ui#readme",
53
+ "bugs": {
54
+ "url": "https://github.com/thorwhalen/zod-collection-ui/issues"
55
+ },
56
+ "peerDependencies": {
57
+ "zod": ">=4.0.0"
58
+ },
59
+ "devDependencies": {
60
+ "@types/node": "^22.0.0",
61
+ "tsx": "^4.21.0",
62
+ "typescript": "^5.7.0",
63
+ "vitest": "^3.0.0",
64
+ "zod": "^4.0.0"
65
+ }
66
+ }