@object-ui/types 3.0.3 → 3.1.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.
Files changed (85) hide show
  1. package/dist/app.d.ts +217 -0
  2. package/dist/app.d.ts.map +1 -1
  3. package/dist/app.js +85 -1
  4. package/dist/complex.d.ts +118 -0
  5. package/dist/complex.d.ts.map +1 -1
  6. package/dist/data-display.d.ts +105 -1
  7. package/dist/data-display.d.ts.map +1 -1
  8. package/dist/data.d.ts +45 -0
  9. package/dist/data.d.ts.map +1 -1
  10. package/dist/designer.d.ts +197 -35
  11. package/dist/designer.d.ts.map +1 -1
  12. package/dist/designer.js +11 -1
  13. package/dist/index.d.ts +21 -10
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +2 -0
  16. package/dist/layout.d.ts +39 -2
  17. package/dist/layout.d.ts.map +1 -1
  18. package/dist/navigation.d.ts +27 -0
  19. package/dist/navigation.d.ts.map +1 -1
  20. package/dist/objectql.d.ts +641 -7
  21. package/dist/objectql.d.ts.map +1 -1
  22. package/dist/record-components.d.ts +160 -0
  23. package/dist/record-components.d.ts.map +1 -0
  24. package/dist/record-components.js +8 -0
  25. package/dist/reports.d.ts +37 -0
  26. package/dist/reports.d.ts.map +1 -1
  27. package/dist/theme.d.ts +5 -0
  28. package/dist/theme.d.ts.map +1 -1
  29. package/dist/views.d.ts +257 -3
  30. package/dist/views.d.ts.map +1 -1
  31. package/dist/workflow.d.ts +198 -0
  32. package/dist/workflow.d.ts.map +1 -1
  33. package/dist/zod/app.zod.d.ts +42 -2
  34. package/dist/zod/app.zod.d.ts.map +1 -1
  35. package/dist/zod/app.zod.js +61 -1
  36. package/dist/zod/complex.zod.d.ts +122 -0
  37. package/dist/zod/complex.zod.d.ts.map +1 -1
  38. package/dist/zod/complex.zod.js +57 -0
  39. package/dist/zod/data-display.zod.d.ts +4 -0
  40. package/dist/zod/data-display.zod.d.ts.map +1 -1
  41. package/dist/zod/data-display.zod.js +2 -0
  42. package/dist/zod/form.zod.d.ts +6 -6
  43. package/dist/zod/index.zod.d.ts +364 -41
  44. package/dist/zod/index.zod.d.ts.map +1 -1
  45. package/dist/zod/index.zod.js +2 -2
  46. package/dist/zod/layout.zod.d.ts +6 -6
  47. package/dist/zod/navigation.zod.d.ts +58 -12
  48. package/dist/zod/navigation.zod.d.ts.map +1 -1
  49. package/dist/zod/navigation.zod.js +21 -9
  50. package/dist/zod/objectql.zod.d.ts +515 -27
  51. package/dist/zod/objectql.zod.d.ts.map +1 -1
  52. package/dist/zod/objectql.zod.js +162 -0
  53. package/dist/zod/reports.zod.d.ts +38 -38
  54. package/dist/zod/views.zod.d.ts +161 -7
  55. package/dist/zod/views.zod.d.ts.map +1 -1
  56. package/dist/zod/views.zod.js +21 -2
  57. package/package.json +2 -2
  58. package/src/__tests__/app-creation-types.test.ts +177 -0
  59. package/src/__tests__/dashboard-config.test.ts +208 -0
  60. package/src/__tests__/examples-metadata-compliance.test.ts +264 -0
  61. package/src/__tests__/navigation-model.test.ts +406 -0
  62. package/src/__tests__/p1-spec-alignment.test.ts +660 -0
  63. package/src/__tests__/p2-spec-exports.test.ts +312 -0
  64. package/src/__tests__/phase2-schemas.test.ts +108 -0
  65. package/src/app.ts +377 -0
  66. package/src/complex.ts +120 -0
  67. package/src/data-display.ts +107 -0
  68. package/src/data.ts +49 -0
  69. package/src/designer.ts +219 -30
  70. package/src/index.ts +192 -3
  71. package/src/layout.ts +55 -2
  72. package/src/navigation.ts +20 -0
  73. package/src/objectql.ts +757 -8
  74. package/src/record-components.ts +188 -0
  75. package/src/reports.ts +43 -0
  76. package/src/theme.ts +6 -0
  77. package/src/views.ts +275 -3
  78. package/src/workflow.ts +226 -0
  79. package/src/zod/app.zod.ts +74 -1
  80. package/src/zod/complex.zod.ts +59 -0
  81. package/src/zod/data-display.zod.ts +2 -0
  82. package/src/zod/index.zod.ts +5 -0
  83. package/src/zod/navigation.zod.ts +22 -10
  84. package/src/zod/objectql.zod.ts +167 -0
  85. package/src/zod/views.zod.ts +21 -2
package/src/app.ts CHANGED
@@ -11,10 +11,144 @@
11
11
  *
12
12
  * Defines the metadata structure for a complete application, including
13
13
  * global layout, navigation menus, and routing configuration.
14
+ *
15
+ * ## Navigation Model
16
+ *
17
+ * ObjectUI uses a unified `NavigationItem` model aligned with @objectstack/spec.
18
+ * The legacy `MenuItem` type is retained for backward compatibility but new
19
+ * configurations should use `NavigationItem` and the `navigation` / `areas` fields.
14
20
  */
15
21
 
16
22
  import type { BaseSchema } from './base';
17
23
 
24
+ // ============================================================================
25
+ // Unified Navigation Model (aligned with @objectstack/spec)
26
+ // ============================================================================
27
+
28
+ /**
29
+ * Navigation item type — determines the target and required fields.
30
+ */
31
+ export type NavigationItemType =
32
+ | 'object'
33
+ | 'dashboard'
34
+ | 'page'
35
+ | 'report'
36
+ | 'url'
37
+ | 'group'
38
+ | 'separator'
39
+ | 'action';
40
+
41
+ /**
42
+ * Unified Navigation Item
43
+ *
44
+ * The single navigation primitive used across ObjectUI and @objectstack/spec.
45
+ * Replaces the legacy `MenuItem` for application navigation trees.
46
+ *
47
+ * Supports typed navigation targets (object, dashboard, page, report, url),
48
+ * nested groups, visibility expressions, RBAC permissions, and UX enhancements
49
+ * like badges, pinning, and sort ordering.
50
+ */
51
+ export interface NavigationItem {
52
+ /** Unique identifier */
53
+ id: string;
54
+
55
+ /** Navigation item type */
56
+ type: NavigationItemType;
57
+
58
+ /** Display label (plain string or I18nLabel object for internationalization) */
59
+ label: string | { key: string; defaultValue?: string; params?: Record<string, any> };
60
+
61
+ /** Icon name (Lucide) */
62
+ icon?: string;
63
+
64
+ // -- Type-specific target fields --
65
+
66
+ /** Target object name (for type: 'object') */
67
+ objectName?: string;
68
+
69
+ /** Target view name (for type: 'object') — opens a specific named list view e.g. 'calendar', 'pipeline' */
70
+ viewName?: string;
71
+
72
+ /** Target dashboard name (for type: 'dashboard') */
73
+ dashboardName?: string;
74
+
75
+ /** Target page name (for type: 'page') */
76
+ pageName?: string;
77
+
78
+ /** Target report name (for type: 'report') */
79
+ reportName?: string;
80
+
81
+ /** Target URL (for type: 'url') */
82
+ url?: string;
83
+
84
+ /** Link target (for type: 'url') */
85
+ target?: '_blank' | '_self';
86
+
87
+ // -- Grouping --
88
+
89
+ /** Child navigation items (for type: 'group') */
90
+ children?: NavigationItem[];
91
+
92
+ // -- Visibility & Permissions --
93
+
94
+ /** Visibility expression — boolean or expression string e.g. "${user.role === 'admin'}" */
95
+ visible?: boolean | string;
96
+
97
+ /** Required permissions to see/access this item */
98
+ requiredPermissions?: string[];
99
+
100
+ // -- UX Enhancements --
101
+
102
+ /** Badge text or count */
103
+ badge?: string | number;
104
+
105
+ /** Badge visual variant */
106
+ badgeVariant?: 'default' | 'destructive' | 'outline';
107
+
108
+ /** Whether group is expanded by default (for type: 'group') */
109
+ defaultOpen?: boolean;
110
+
111
+ /** Whether this item is pinned */
112
+ pinned?: boolean;
113
+
114
+ /** Sort order weight (lower = higher) */
115
+ order?: number;
116
+ }
117
+
118
+ /**
119
+ * Navigation Area — a business-domain partition of navigation items.
120
+ *
121
+ * Inspired by Salesforce Lightning App → Area → Tab model and
122
+ * Microsoft Power Apps Area → Group → Subarea pattern.
123
+ *
124
+ * Each area contains an independent navigation tree, allowing large
125
+ * enterprise applications to organise navigation by domain (e.g.
126
+ * Sales, Service, Marketing).
127
+ */
128
+ export interface NavigationArea {
129
+ /** Unique identifier */
130
+ id: string;
131
+
132
+ /** Display label (plain string or I18nLabel object for internationalization) */
133
+ label: string | { key: string; defaultValue?: string; params?: Record<string, any> };
134
+
135
+ /** Icon name (Lucide) */
136
+ icon?: string;
137
+
138
+ /** Navigation items within this area */
139
+ navigation: NavigationItem[];
140
+
141
+ /** Visibility expression */
142
+ visible?: boolean | string;
143
+
144
+ /** Required permissions to see this area */
145
+ requiredPermissions?: string[];
146
+ }
147
+
148
+ // ============================================================================
149
+ // Application Schema
150
+ // ============================================================================
151
+
18
152
  /**
19
153
  * Top-level Application Configuration (app.json)
20
154
  */
@@ -31,11 +165,21 @@ export interface AppSchema extends BaseSchema {
31
165
  */
32
166
  title?: string;
33
167
 
168
+ /**
169
+ * Display Label (used in navigation and app switcher)
170
+ */
171
+ label?: string;
172
+
34
173
  /**
35
174
  * Application Description
36
175
  */
37
176
  description?: string;
38
177
 
178
+ /**
179
+ * Icon name (Lucide) for app switcher and navigation
180
+ */
181
+ icon?: string;
182
+
39
183
  /**
40
184
  * Logo URL or Icon name
41
185
  */
@@ -46,6 +190,17 @@ export interface AppSchema extends BaseSchema {
46
190
  */
47
191
  favicon?: string;
48
192
 
193
+ /**
194
+ * Branding configuration
195
+ */
196
+ branding?: BrandingConfig;
197
+
198
+ /**
199
+ * Whether the application is active (visible in app switcher)
200
+ * @default true
201
+ */
202
+ active?: boolean;
203
+
49
204
  /**
50
205
  * Global Layout Strategy
51
206
  * - sidebar: Standard admin layout with left sidebar
@@ -57,9 +212,23 @@ export interface AppSchema extends BaseSchema {
57
212
 
58
213
  /**
59
214
  * Global Navigation Menu
215
+ * @deprecated Use `navigation` instead. Retained for backward compatibility.
60
216
  */
61
217
  menu?: MenuItem[];
62
218
 
219
+ /**
220
+ * Unified navigation tree (aligned with @objectstack/spec NavigationItem model).
221
+ * Takes precedence over `menu` when both are present.
222
+ */
223
+ navigation?: NavigationItem[];
224
+
225
+ /**
226
+ * Navigation areas / business-domain partitions.
227
+ * When provided, the sidebar displays an area switcher and renders
228
+ * the selected area's navigation tree.
229
+ */
230
+ areas?: NavigationArea[];
231
+
63
232
  /**
64
233
  * Global Actions (User Profile, Settings, etc)
65
234
  */
@@ -78,8 +247,13 @@ export interface AppSchema extends BaseSchema {
78
247
  requiredPermissions?: string[];
79
248
  }
80
249
 
250
+ // ============================================================================
251
+ // Legacy MenuItem (backward compat — prefer NavigationItem)
252
+ // ============================================================================
253
+
81
254
  /**
82
255
  * Navigation Menu Item
256
+ * @deprecated Use `NavigationItem` instead.
83
257
  */
84
258
  export interface MenuItem {
85
259
  /**
@@ -123,6 +297,209 @@ export interface MenuItem {
123
297
  hidden?: boolean | string;
124
298
  }
125
299
 
300
+ // ============================================================================
301
+ // MenuItem → NavigationItem Transform
302
+ // ============================================================================
303
+
304
+ /**
305
+ * Convert a legacy `MenuItem` to a `NavigationItem`.
306
+ *
307
+ * Mapping rules:
308
+ * - `type: 'item'` → inferred from `href` (url) or `path` (page)
309
+ * - `type: 'group'` → `type: 'group'`
310
+ * - `type: 'separator'` → `type: 'separator'`
311
+ * - `hidden` → `visible` (inverted)
312
+ * - `path` → `pageName` (last segment) or kept as-is for url
313
+ * - `href` → `url` with `target: '_blank'`
314
+ */
315
+ export function menuItemToNavigationItem(
316
+ item: MenuItem,
317
+ index: number = 0,
318
+ ): NavigationItem {
319
+ const id = `migrated_${index}`;
320
+
321
+ if (item.type === 'separator') {
322
+ return {
323
+ id,
324
+ type: 'separator',
325
+ label: item.label || '',
326
+ };
327
+ }
328
+
329
+ if (item.type === 'group') {
330
+ return {
331
+ id,
332
+ type: 'group',
333
+ label: item.label || '',
334
+ icon: item.icon,
335
+ children: (item.children || []).map((child, i) =>
336
+ menuItemToNavigationItem(child, index * 100 + i),
337
+ ),
338
+ visible: item.hidden !== undefined ? !item.hidden : undefined,
339
+ badge: item.badge,
340
+ defaultOpen: true,
341
+ };
342
+ }
343
+
344
+ // Default: 'item' type — infer target from href / path
345
+ if (item.href) {
346
+ return {
347
+ id,
348
+ type: 'url',
349
+ label: item.label || '',
350
+ icon: item.icon,
351
+ url: item.href,
352
+ target: '_blank',
353
+ visible: item.hidden !== undefined ? !item.hidden : undefined,
354
+ badge: item.badge,
355
+ };
356
+ }
357
+
358
+ // Path-based item → treat as page navigation
359
+ return {
360
+ id,
361
+ type: 'page',
362
+ label: item.label || '',
363
+ icon: item.icon,
364
+ pageName: item.path || '',
365
+ visible: item.hidden !== undefined ? !item.hidden : undefined,
366
+ badge: item.badge,
367
+ };
368
+ }
369
+
370
+ // ============================================================================
371
+ // App Creation Wizard Types
372
+ // ============================================================================
373
+
374
+ /**
375
+ * Wizard step identifier for app creation flow.
376
+ */
377
+ export type AppWizardStepId = 'basic' | 'objects' | 'navigation' | 'branding';
378
+
379
+ /**
380
+ * App wizard step definition.
381
+ */
382
+ export interface AppWizardStep {
383
+ /** Step identifier */
384
+ id: AppWizardStepId;
385
+
386
+ /** Display label */
387
+ label: string;
388
+
389
+ /** Step description */
390
+ description?: string;
391
+
392
+ /** Icon name (Lucide) */
393
+ icon?: string;
394
+
395
+ /** Whether the step is optional */
396
+ optional?: boolean;
397
+ }
398
+
399
+ /**
400
+ * Branding configuration for an application.
401
+ */
402
+ export interface BrandingConfig {
403
+ /** Logo URL or base64 data URI */
404
+ logo?: string;
405
+
406
+ /** Primary brand color (hex) */
407
+ primaryColor?: string;
408
+
409
+ /** Favicon URL */
410
+ favicon?: string;
411
+
412
+ /** Font family override */
413
+ fontFamily?: string;
414
+ }
415
+
416
+ /**
417
+ * Object selection entry for the wizard.
418
+ */
419
+ export interface ObjectSelection {
420
+ /** Object name (snake_case) */
421
+ name: string;
422
+
423
+ /** Display label */
424
+ label: string;
425
+
426
+ /** Icon name (Lucide) */
427
+ icon?: string;
428
+
429
+ /** Whether this object is selected */
430
+ selected: boolean;
431
+ }
432
+
433
+ /**
434
+ * App creation wizard draft state — represents the in-progress
435
+ * application configuration before it is finalized into an AppSchema.
436
+ */
437
+ export interface AppWizardDraft {
438
+ /** App name (snake_case, validated) */
439
+ name: string;
440
+
441
+ /** Display title */
442
+ title: string;
443
+
444
+ /** Description */
445
+ description?: string;
446
+
447
+ /** App icon name (Lucide) */
448
+ icon?: string;
449
+
450
+ /** Template to start from */
451
+ template?: string;
452
+
453
+ /** Layout strategy */
454
+ layout: 'sidebar' | 'header' | 'empty';
455
+
456
+ /** Selected business objects */
457
+ objects: ObjectSelection[];
458
+
459
+ /** Navigation tree being built */
460
+ navigation: NavigationItem[];
461
+
462
+ /** Branding configuration */
463
+ branding: BrandingConfig;
464
+ }
465
+
466
+ /**
467
+ * Editor mode for the app designer.
468
+ */
469
+ export type EditorMode = 'edit' | 'preview' | 'code';
470
+
471
+ /**
472
+ * Validate an app name is snake_case.
473
+ * Pattern: starts with lowercase letter, followed by lowercase letters/digits,
474
+ * with optional underscore-separated segments (no trailing/leading/double underscores).
475
+ */
476
+ export function isValidAppName(name: string): boolean {
477
+ return /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/.test(name);
478
+ }
479
+
480
+ /**
481
+ * Convert an AppWizardDraft to an AppSchema.
482
+ */
483
+ export function wizardDraftToAppSchema(draft: AppWizardDraft): AppSchema {
484
+ return {
485
+ type: 'app',
486
+ name: draft.name,
487
+ title: draft.title,
488
+ label: draft.title,
489
+ description: draft.description,
490
+ icon: draft.icon,
491
+ logo: draft.branding.logo,
492
+ favicon: draft.branding.favicon,
493
+ branding: draft.branding,
494
+ layout: draft.layout,
495
+ navigation: draft.navigation,
496
+ };
497
+ }
498
+
499
+ // ============================================================================
500
+ // Application Actions
501
+ // ============================================================================
502
+
126
503
  /**
127
504
  * Application Header/Toolbar Action
128
505
  */
package/src/complex.ts CHANGED
@@ -482,6 +482,8 @@ export interface DashboardWidgetLayout {
482
482
  export interface DashboardWidgetSchema {
483
483
  id?: string;
484
484
  title?: string;
485
+ /** Widget description */
486
+ description?: string;
485
487
  /** Component schema (legacy format) */
486
488
  component?: SchemaNode;
487
489
  layout?: DashboardWidgetLayout;
@@ -489,6 +491,68 @@ export interface DashboardWidgetSchema {
489
491
  type?: string;
490
492
  /** Widget-specific configuration (spec shorthand format) */
491
493
  options?: unknown;
494
+ /** Chart configuration for chart-type widgets */
495
+ chartConfig?: any;
496
+ /**
497
+ * Widget color variant.
498
+ * Aligned with @objectstack/spec WidgetColorVariantSchema.
499
+ */
500
+ colorVariant?: 'default' | 'blue' | 'teal' | 'orange' | 'purple' | 'success' | 'warning' | 'danger';
501
+ /** Action URL for clickable widgets */
502
+ actionUrl?: string;
503
+ /** Action type for widget interactions */
504
+ actionType?: string;
505
+ /** Action icon name */
506
+ actionIcon?: string;
507
+ /**
508
+ * Data binding: Object name for data source.
509
+ * Aligned with @objectstack/spec DashboardWidgetSchema.object.
510
+ */
511
+ object?: string;
512
+ /**
513
+ * Data binding: Filter conditions.
514
+ * Aligned with @objectstack/spec DashboardWidgetSchema.filter.
515
+ */
516
+ filter?: any;
517
+ /**
518
+ * Data binding: Category field for grouping.
519
+ * Aligned with @objectstack/spec DashboardWidgetSchema.categoryField.
520
+ */
521
+ categoryField?: string;
522
+ /**
523
+ * Data binding: Value field for aggregation.
524
+ * Aligned with @objectstack/spec DashboardWidgetSchema.valueField.
525
+ */
526
+ valueField?: string;
527
+ /**
528
+ * Aggregation function.
529
+ * Aligned with @objectstack/spec DashboardWidgetSchema.aggregate.
530
+ */
531
+ aggregate?: string;
532
+ /**
533
+ * Multiple measures for pivot/matrix display.
534
+ * Aligned with @objectstack/spec WidgetMeasureSchema.
535
+ */
536
+ measures?: Array<{
537
+ valueField: string;
538
+ aggregate: string;
539
+ label?: string;
540
+ format?: string;
541
+ }>;
542
+ /**
543
+ * Responsive configuration per breakpoint.
544
+ * Aligned with @objectstack/spec DashboardWidgetSchema.responsive.
545
+ */
546
+ responsive?: any;
547
+ /**
548
+ * ARIA accessibility attributes.
549
+ * Aligned with @objectstack/spec AriaPropsSchema.
550
+ */
551
+ aria?: {
552
+ ariaLabel?: string;
553
+ ariaDescribedBy?: string;
554
+ role?: string;
555
+ };
492
556
  }
493
557
 
494
558
  /**
@@ -496,11 +560,67 @@ export interface DashboardWidgetSchema {
496
560
  */
497
561
  export interface DashboardSchema extends BaseSchema {
498
562
  type: 'dashboard';
563
+ /** Dashboard title displayed in the header */
564
+ title?: string;
499
565
  columns?: number;
500
566
  gap?: number;
501
567
  widgets: DashboardWidgetSchema[];
502
568
  /** Auto-refresh interval in seconds. When set, the dashboard will periodically trigger onRefresh. */
503
569
  refreshInterval?: number;
570
+ /**
571
+ * Dashboard header configuration.
572
+ * Aligned with @objectstack/spec DashboardHeaderSchema.
573
+ */
574
+ header?: {
575
+ showTitle?: boolean;
576
+ showDescription?: boolean;
577
+ actions?: Array<{
578
+ label: string;
579
+ actionUrl?: string;
580
+ actionType?: string;
581
+ icon?: string;
582
+ }>;
583
+ };
584
+ /**
585
+ * Global filter configurations.
586
+ * Applied across all dashboard widgets.
587
+ * Aligned with @objectstack/spec GlobalFilterSchema.
588
+ */
589
+ globalFilters?: Array<{
590
+ field: string;
591
+ label?: string;
592
+ type?: 'text' | 'select' | 'date' | 'number' | 'lookup';
593
+ options?: string[];
594
+ optionsFrom?: {
595
+ object: string;
596
+ valueField: string;
597
+ labelField?: string;
598
+ filter?: any;
599
+ };
600
+ defaultValue?: any;
601
+ scope?: string;
602
+ targetWidgets?: string[];
603
+ }>;
604
+ /**
605
+ * Date range filter configuration.
606
+ * Aligned with @objectstack/spec DashboardSchema.dateRange.
607
+ */
608
+ dateRange?: {
609
+ field?: string;
610
+ defaultRange?: 'today' | 'yesterday' | 'this_week' | 'last_week' | 'this_month' | 'last_month'
611
+ | 'this_quarter' | 'last_quarter' | 'this_year' | 'last_year'
612
+ | 'last_7_days' | 'last_30_days' | 'last_90_days' | 'custom';
613
+ allowCustomRange?: boolean;
614
+ };
615
+ /**
616
+ * ARIA accessibility attributes.
617
+ * Aligned with @objectstack/spec AriaPropsSchema.
618
+ */
619
+ aria?: {
620
+ ariaLabel?: string;
621
+ ariaDescribedBy?: string;
622
+ role?: string;
623
+ };
504
624
  }
505
625
 
506
626
  /**
@@ -341,6 +341,13 @@ export interface DataTableSchema extends BaseSchema {
341
341
  * @default false
342
342
  */
343
343
  selectable?: boolean | 'single' | 'multiple';
344
+ /**
345
+ * Selection checkbox display style
346
+ * - 'always': Checkboxes are always visible
347
+ * - 'hover': Checkboxes only appear on row hover
348
+ * @default 'always'
349
+ */
350
+ selectionStyle?: 'always' | 'hover';
344
351
  /**
345
352
  * Enable column sorting
346
353
  * @default true
@@ -388,6 +395,12 @@ export interface DataTableSchema extends BaseSchema {
388
395
  * @default false
389
396
  */
390
397
  editable?: boolean;
398
+ /**
399
+ * Enable single-click editing mode
400
+ * When true with editable, clicking a cell enters edit mode (instead of double-click)
401
+ * @default false
402
+ */
403
+ singleClickEdit?: boolean;
391
404
  /**
392
405
  * Cell value change handler
393
406
  * Called when a cell value is edited
@@ -413,6 +426,41 @@ export interface DataTableSchema extends BaseSchema {
413
426
  * Function that returns a CSS class string for each row
414
427
  */
415
428
  rowClassName?: (row: any, index: number) => string | undefined;
429
+ /**
430
+ * Dynamic row inline style
431
+ * Function that returns CSSProperties for each row (e.g., from conditionalFormatting).
432
+ */
433
+ rowStyle?: (row: any, index: number) => React.CSSProperties | undefined;
434
+ /**
435
+ * Number of columns to freeze (left-pin)
436
+ * When set, the first N columns remain fixed while the rest scroll horizontally.
437
+ * @default 0
438
+ */
439
+ frozenColumns?: number;
440
+ /**
441
+ * Show row numbers in the first column (Airtable-style)
442
+ * @default false
443
+ */
444
+ showRowNumbers?: boolean;
445
+ /**
446
+ * Show "+ Add record" row at the bottom of the table (Airtable-style)
447
+ * @default false
448
+ */
449
+ showAddRow?: boolean;
450
+ /**
451
+ * Callback when the "+ Add record" row is clicked
452
+ */
453
+ onAddRecord?: () => void;
454
+ /**
455
+ * Column resize handler
456
+ * Called when a column is resized
457
+ */
458
+ onColumnResize?: (columnKey: string, width: number) => void;
459
+ /**
460
+ * Column reorder handler (new order of accessorKeys)
461
+ * Called when columns are reordered via drag-and-drop
462
+ */
463
+ onColumnReorder?: (newOrder: string[]) => void;
416
464
  }
417
465
 
418
466
  /**
@@ -593,6 +641,64 @@ export interface ChartSchema extends BaseSchema {
593
641
  config?: Record<string, any>;
594
642
  }
595
643
 
644
+ /**
645
+ * Aggregation function for pivot table values
646
+ */
647
+ export type PivotAggregation = 'sum' | 'count' | 'avg' | 'min' | 'max';
648
+
649
+ /**
650
+ * Pivot table (cross-tabulation) component
651
+ *
652
+ * Renders a matrix where rows correspond to one field,
653
+ * columns to another, and cells show an aggregated value.
654
+ */
655
+ export interface PivotTableSchema extends BaseSchema {
656
+ type: 'pivot';
657
+ /**
658
+ * Pivot table title
659
+ */
660
+ title?: string;
661
+ /**
662
+ * Field used for row headers
663
+ */
664
+ rowField: string;
665
+ /**
666
+ * Field used for column headers
667
+ */
668
+ columnField: string;
669
+ /**
670
+ * Field whose values are aggregated in cells
671
+ */
672
+ valueField: string;
673
+ /**
674
+ * Aggregation function applied to valueField
675
+ * @default 'sum'
676
+ */
677
+ aggregation?: PivotAggregation;
678
+ /**
679
+ * Source data rows
680
+ */
681
+ data: Record<string, unknown>[];
682
+ /**
683
+ * Show a totals column on the right
684
+ * @default false
685
+ */
686
+ showRowTotals?: boolean;
687
+ /**
688
+ * Show a totals row at the bottom
689
+ * @default false
690
+ */
691
+ showColumnTotals?: boolean;
692
+ /**
693
+ * Numeric format string (e.g. "$,.2f") — applied via simple prefix/suffix/decimals
694
+ */
695
+ format?: string;
696
+ /**
697
+ * Mapping of column header values to Tailwind text-color classes
698
+ */
699
+ columnColors?: Record<string, string>;
700
+ }
701
+
596
702
  /**
597
703
  * Timeline event
598
704
  */
@@ -706,6 +812,7 @@ export type DataDisplaySchema =
706
812
  | MarkdownSchema
707
813
  | TreeViewSchema
708
814
  | ChartSchema
815
+ | PivotTableSchema
709
816
  | TimelineSchema
710
817
  | HtmlSchema
711
818
  | StatisticSchema