@object-ui/components 3.3.0 → 3.3.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.
- package/CHANGELOG.md +20 -0
- package/README.md +21 -1
- package/dist/index.css +6339 -2
- package/dist/index.js +17600 -17481
- package/dist/index.umd.cjs +36 -36
- package/dist/packages/components/src/custom/empty.d.ts +12 -1
- package/dist/packages/components/src/renderers/action/action-bar.d.ts +12 -1
- package/dist/packages/components/src/ui/chart.d.ts +10 -29
- package/package.json +65 -44
- package/.turbo/turbo-build.log +0 -84
- package/README_SHADCN_SYNC.md +0 -281
- package/TESTING.md +0 -335
- package/docs/FilterBuilder.md +0 -268
- package/metadata/Chart.component.yml +0 -30
- package/metadata/FilterBuilder.component.yml +0 -39
- package/metadata/GridLayout.component.yml +0 -27
- package/metadata/Menu.component.yml +0 -31
- package/metadata/ObjectForm.component.yml +0 -34
- package/metadata/ObjectGrid.component.yml +0 -72
- package/metadata/Page.component.yml +0 -24
- package/postcss.config.js +0 -14
- package/shadcn-components.json +0 -440
- package/src/SchemaRenderer.tsx +0 -28
- package/src/__tests__/PageRendererRegions.test.tsx +0 -668
- package/src/__tests__/README.md +0 -124
- package/src/__tests__/__snapshots__/snapshot-critical.test.tsx.snap +0 -811
- package/src/__tests__/__snapshots__/snapshot.test.tsx.snap +0 -327
- package/src/__tests__/accessibility.test.tsx +0 -137
- package/src/__tests__/action-bar.test.tsx +0 -206
- package/src/__tests__/api-consistency.test.tsx +0 -596
- package/src/__tests__/basic-renderers.test.tsx +0 -255
- package/src/__tests__/color-contrast.test.tsx +0 -212
- package/src/__tests__/complex-disclosure-renderers.test.tsx +0 -302
- package/src/__tests__/compliance.test.tsx +0 -72
- package/src/__tests__/config-field-renderer.test.tsx +0 -307
- package/src/__tests__/config-panel-renderer.test.tsx +0 -580
- package/src/__tests__/config-primitives.test.tsx +0 -106
- package/src/__tests__/edge-cases.test.tsx +0 -285
- package/src/__tests__/feedback-overlay-renderers.test.tsx +0 -349
- package/src/__tests__/filter-builder.test.tsx +0 -409
- package/src/__tests__/form-renderers.test.tsx +0 -364
- package/src/__tests__/layout-data-renderers.test.tsx +0 -340
- package/src/__tests__/mobile-accessibility.test.tsx +0 -120
- package/src/__tests__/navigation-overlay.test.tsx +0 -370
- package/src/__tests__/snapshot-critical.test.tsx +0 -317
- package/src/__tests__/snapshot.test.tsx +0 -205
- package/src/__tests__/test-utils.tsx +0 -190
- package/src/__tests__/use-config-draft.test.tsx +0 -295
- package/src/__tests__/view-compliance.test.tsx +0 -153
- package/src/__tests__/wcag-audit.test.tsx +0 -493
- package/src/custom/action-param-dialog.tsx +0 -264
- package/src/custom/button-group.tsx +0 -91
- package/src/custom/combobox.tsx +0 -104
- package/src/custom/config-field-renderer.tsx +0 -276
- package/src/custom/config-panel-renderer.tsx +0 -306
- package/src/custom/config-row.tsx +0 -50
- package/src/custom/date-picker.tsx +0 -61
- package/src/custom/empty.tsx +0 -112
- package/src/custom/field.tsx +0 -81
- package/src/custom/filter-builder.tsx +0 -418
- package/src/custom/index.ts +0 -21
- package/src/custom/input-group.tsx +0 -53
- package/src/custom/item.tsx +0 -201
- package/src/custom/kbd.tsx +0 -36
- package/src/custom/mobile-dialog-content.tsx +0 -67
- package/src/custom/native-select.tsx +0 -33
- package/src/custom/navigation-overlay.tsx +0 -334
- package/src/custom/section-header.tsx +0 -68
- package/src/custom/sort-builder.tsx +0 -129
- package/src/custom/spinner.tsx +0 -26
- package/src/custom/view-skeleton.tsx +0 -243
- package/src/custom/view-states.tsx +0 -153
- package/src/debug/DebugPanel.tsx +0 -313
- package/src/debug/__tests__/DebugPanel.test.tsx +0 -134
- package/src/debug/index.ts +0 -10
- package/src/hooks/use-config-draft.ts +0 -127
- package/src/hooks/use-mobile.tsx +0 -27
- package/src/index.css +0 -245
- package/src/index.ts +0 -47
- package/src/lib/use-sync-external-store-shim.ts +0 -10
- package/src/lib/use-sync-external-store-with-selector-shim.ts +0 -90
- package/src/lib/utils.tsx +0 -35
- package/src/new-components.test.ts +0 -73
- package/src/renderers/action/action-bar.tsx +0 -221
- package/src/renderers/action/action-button.tsx +0 -158
- package/src/renderers/action/action-group.tsx +0 -270
- package/src/renderers/action/action-icon.tsx +0 -150
- package/src/renderers/action/action-menu.tsx +0 -203
- package/src/renderers/action/index.ts +0 -19
- package/src/renderers/action/resolve-icon.ts +0 -35
- package/src/renderers/basic/button-group.tsx +0 -79
- package/src/renderers/basic/div.tsx +0 -60
- package/src/renderers/basic/html.tsx +0 -43
- package/src/renderers/basic/icon.tsx +0 -89
- package/src/renderers/basic/image.tsx +0 -49
- package/src/renderers/basic/index.ts +0 -18
- package/src/renderers/basic/navigation-menu.tsx +0 -81
- package/src/renderers/basic/pagination.tsx +0 -109
- package/src/renderers/basic/separator.tsx +0 -57
- package/src/renderers/basic/span.tsx +0 -63
- package/src/renderers/basic/text.tsx +0 -52
- package/src/renderers/complex/README-KANBAN.md +0 -208
- package/src/renderers/complex/TIMELINE.md +0 -353
- package/src/renderers/complex/__tests__/data-table-airtable-ux.test.tsx +0 -239
- package/src/renderers/complex/__tests__/data-table-batch-editing.test.tsx +0 -275
- package/src/renderers/complex/__tests__/data-table-cell-renderer.test.tsx +0 -120
- package/src/renderers/complex/__tests__/data-table-editing.test.tsx +0 -221
- package/src/renderers/complex/__tests__/data-table.test.ts +0 -76
- package/src/renderers/complex/carousel.tsx +0 -69
- package/src/renderers/complex/data-table.tsx +0 -1243
- package/src/renderers/complex/filter-builder.tsx +0 -77
- package/src/renderers/complex/index.ts +0 -16
- package/src/renderers/complex/resizable.tsx +0 -66
- package/src/renderers/complex/scroll-area.tsx +0 -58
- package/src/renderers/complex/table.tsx +0 -95
- package/src/renderers/data-display/alert.tsx +0 -46
- package/src/renderers/data-display/avatar.tsx +0 -38
- package/src/renderers/data-display/badge.tsx +0 -55
- package/src/renderers/data-display/breadcrumb.tsx +0 -61
- package/src/renderers/data-display/index.ts +0 -18
- package/src/renderers/data-display/kbd.tsx +0 -50
- package/src/renderers/data-display/list.tsx +0 -75
- package/src/renderers/data-display/statistic.tsx +0 -95
- package/src/renderers/data-display/table.tsx +0 -78
- package/src/renderers/data-display/tree-view.tsx +0 -176
- package/src/renderers/disclosure/accordion.tsx +0 -69
- package/src/renderers/disclosure/collapsible.tsx +0 -53
- package/src/renderers/disclosure/index.ts +0 -11
- package/src/renderers/disclosure/toggle-group.tsx +0 -79
- package/src/renderers/feedback/empty.tsx +0 -49
- package/src/renderers/feedback/index.ts +0 -16
- package/src/renderers/feedback/loading.tsx +0 -78
- package/src/renderers/feedback/progress.tsx +0 -29
- package/src/renderers/feedback/skeleton.tsx +0 -31
- package/src/renderers/feedback/sonner.tsx +0 -56
- package/src/renderers/feedback/spinner.tsx +0 -55
- package/src/renderers/feedback/toast.tsx +0 -59
- package/src/renderers/feedback/toaster.tsx +0 -23
- package/src/renderers/form/button.tsx +0 -103
- package/src/renderers/form/calendar.tsx +0 -34
- package/src/renderers/form/checkbox.tsx +0 -71
- package/src/renderers/form/combobox.tsx +0 -48
- package/src/renderers/form/command.tsx +0 -58
- package/src/renderers/form/date-picker.tsx +0 -84
- package/src/renderers/form/file-upload.tsx +0 -184
- package/src/renderers/form/form.tsx +0 -540
- package/src/renderers/form/index.ts +0 -26
- package/src/renderers/form/input-otp.tsx +0 -51
- package/src/renderers/form/input.tsx +0 -121
- package/src/renderers/form/label.tsx +0 -45
- package/src/renderers/form/radio-group.tsx +0 -63
- package/src/renderers/form/select.tsx +0 -94
- package/src/renderers/form/slider.tsx +0 -61
- package/src/renderers/form/switch.tsx +0 -48
- package/src/renderers/form/textarea.tsx +0 -76
- package/src/renderers/form/toggle.tsx +0 -42
- package/src/renderers/index.ts +0 -18
- package/src/renderers/layout/aspect-ratio.tsx +0 -51
- package/src/renderers/layout/card.tsx +0 -85
- package/src/renderers/layout/container.tsx +0 -122
- package/src/renderers/layout/flex.tsx +0 -132
- package/src/renderers/layout/grid.tsx +0 -178
- package/src/renderers/layout/index.ts +0 -19
- package/src/renderers/layout/page.tsx +0 -466
- package/src/renderers/layout/semantic.tsx +0 -48
- package/src/renderers/layout/stack.tsx +0 -132
- package/src/renderers/layout/tabs.tsx +0 -97
- package/src/renderers/navigation/header-bar.tsx +0 -118
- package/src/renderers/navigation/index.ts +0 -10
- package/src/renderers/navigation/sidebar.tsx +0 -208
- package/src/renderers/overlay/alert-dialog.tsx +0 -72
- package/src/renderers/overlay/context-menu.tsx +0 -100
- package/src/renderers/overlay/dialog.tsx +0 -77
- package/src/renderers/overlay/drawer.tsx +0 -77
- package/src/renderers/overlay/dropdown-menu.tsx +0 -99
- package/src/renderers/overlay/hover-card.tsx +0 -55
- package/src/renderers/overlay/index.ts +0 -18
- package/src/renderers/overlay/menubar.tsx +0 -76
- package/src/renderers/overlay/popover.tsx +0 -56
- package/src/renderers/overlay/sheet.tsx +0 -77
- package/src/renderers/overlay/tooltip.tsx +0 -67
- package/src/renderers/placeholders.tsx +0 -107
- package/src/stories/CRMApp.stories.tsx +0 -706
- package/src/stories/ConfigPanel.stories.tsx +0 -232
- package/src/stories/Guide.mdx +0 -55
- package/src/stories/MockedData.stories.tsx +0 -121
- package/src/stories/assets/accessibility.png +0 -0
- package/src/stories/assets/accessibility.svg +0 -1
- package/src/stories/assets/addon-library.png +0 -0
- package/src/stories/assets/assets.png +0 -0
- package/src/stories/assets/avif-test-image.avif +0 -0
- package/src/stories/assets/context.png +0 -0
- package/src/stories/assets/discord.svg +0 -1
- package/src/stories/assets/docs.png +0 -0
- package/src/stories/assets/figma-plugin.png +0 -0
- package/src/stories/assets/github.svg +0 -1
- package/src/stories/assets/share.png +0 -0
- package/src/stories/assets/styling.png +0 -0
- package/src/stories/assets/testing.png +0 -0
- package/src/stories/assets/theming.png +0 -0
- package/src/stories/assets/tutorials.svg +0 -1
- package/src/stories/assets/youtube.svg +0 -1
- package/src/stories/button.css +0 -30
- package/src/stories/header.css +0 -32
- package/src/stories/page.css +0 -68
- package/src/stories-json/Accessibility.mdx +0 -297
- package/src/stories-json/EdgeCases.stories.tsx +0 -160
- package/src/stories-json/GettingStarted.mdx +0 -89
- package/src/stories-json/Introduction.mdx +0 -127
- package/src/stories-json/accordion.stories.tsx +0 -43
- package/src/stories-json/aggrid.stories.tsx +0 -103
- package/src/stories-json/alert.stories.tsx +0 -39
- package/src/stories-json/aspect-ratio.stories.tsx +0 -34
- package/src/stories-json/avatar.stories.tsx +0 -38
- package/src/stories-json/badge.stories.tsx +0 -53
- package/src/stories-json/breadcrumb.stories.tsx +0 -30
- package/src/stories-json/button-group.stories.tsx +0 -43
- package/src/stories-json/button.stories.tsx +0 -73
- package/src/stories-json/calendar.stories.tsx +0 -85
- package/src/stories-json/card.stories.tsx +0 -48
- package/src/stories-json/carousel.stories.tsx +0 -33
- package/src/stories-json/charts.stories.tsx +0 -195
- package/src/stories-json/chatbot.stories.tsx +0 -349
- package/src/stories-json/code-editor.stories.tsx +0 -92
- package/src/stories-json/collapsible.stories.tsx +0 -40
- package/src/stories-json/controls.stories.tsx +0 -36
- package/src/stories-json/crm-live-data.stories.tsx +0 -154
- package/src/stories-json/dashboard.stories.tsx +0 -318
- package/src/stories-json/data-table.stories.tsx +0 -136
- package/src/stories-json/data_display_extras.stories.tsx +0 -102
- package/src/stories-json/date-picker.stories.tsx +0 -28
- package/src/stories-json/detail-view.stories.tsx +0 -258
- package/src/stories-json/dialog.stories.tsx +0 -43
- package/src/stories-json/feedback_extras.stories.tsx +0 -40
- package/src/stories-json/feedback_others.stories.tsx +0 -46
- package/src/stories-json/form-variants.stories.tsx +0 -210
- package/src/stories-json/form_advanced.stories.tsx +0 -117
- package/src/stories-json/form_extras.stories.tsx +0 -123
- package/src/stories-json/grid.stories.tsx +0 -56
- package/src/stories-json/icon.stories.tsx +0 -36
- package/src/stories-json/input.stories.tsx +0 -52
- package/src/stories-json/kanban.stories.tsx +0 -295
- package/src/stories-json/layout_extended.stories.tsx +0 -76
- package/src/stories-json/layout_flex.stories.tsx +0 -107
- package/src/stories-json/list-view.stories.tsx +0 -97
- package/src/stories-json/markdown.stories.tsx +0 -129
- package/src/stories-json/menus.stories.tsx +0 -63
- package/src/stories-json/metric-card.stories.tsx +0 -143
- package/src/stories-json/navigation-menu.stories.tsx +0 -37
- package/src/stories-json/object-aggrid-advanced.stories.tsx +0 -389
- package/src/stories-json/object-aggrid.stories.tsx +0 -252
- package/src/stories-json/object-form.stories.tsx +0 -130
- package/src/stories-json/object-gantt.stories.tsx +0 -114
- package/src/stories-json/object-grid.stories.tsx +0 -315
- package/src/stories-json/object-map.stories.tsx +0 -116
- package/src/stories-json/object-view.stories.tsx +0 -118
- package/src/stories-json/overlay_extras.stories.tsx +0 -113
- package/src/stories-json/overlay_others.stories.tsx +0 -76
- package/src/stories-json/page.stories.tsx +0 -55
- package/src/stories-json/reports.stories.tsx +0 -163
- package/src/stories-json/resizable.stories.tsx +0 -44
- package/src/stories-json/select.stories.tsx +0 -34
- package/src/stories-json/separator.stories.tsx +0 -41
- package/src/stories-json/sidebar.stories.tsx +0 -147
- package/src/stories-json/statistic.stories.tsx +0 -44
- package/src/stories-json/tabs.stories.tsx +0 -51
- package/src/stories-json/timeline.stories.tsx +0 -188
- package/src/stories-json/typography.stories.tsx +0 -45
- package/src/types/config-panel.ts +0 -101
- package/src/ui/accordion.tsx +0 -66
- package/src/ui/alert-dialog.tsx +0 -149
- package/src/ui/alert.tsx +0 -67
- package/src/ui/aspect-ratio.tsx +0 -15
- package/src/ui/avatar.tsx +0 -58
- package/src/ui/badge.tsx +0 -44
- package/src/ui/breadcrumb.tsx +0 -123
- package/src/ui/button.tsx +0 -64
- package/src/ui/calendar.tsx +0 -221
- package/src/ui/card.tsx +0 -87
- package/src/ui/carousel.tsx +0 -270
- package/src/ui/chart.tsx +0 -377
- package/src/ui/checkbox.tsx +0 -38
- package/src/ui/collapsible.tsx +0 -19
- package/src/ui/command.tsx +0 -161
- package/src/ui/context-menu.tsx +0 -208
- package/src/ui/dialog.tsx +0 -130
- package/src/ui/drawer.tsx +0 -126
- package/src/ui/dropdown-menu.tsx +0 -208
- package/src/ui/form.tsx +0 -186
- package/src/ui/hover-card.tsx +0 -37
- package/src/ui/index.ts +0 -56
- package/src/ui/input-otp.tsx +0 -79
- package/src/ui/input.tsx +0 -30
- package/src/ui/label.tsx +0 -34
- package/src/ui/menubar.tsx +0 -264
- package/src/ui/navigation-menu.tsx +0 -136
- package/src/ui/pagination.tsx +0 -125
- package/src/ui/popover.tsx +0 -39
- package/src/ui/progress.tsx +0 -36
- package/src/ui/radio-group.tsx +0 -52
- package/src/ui/resizable.tsx +0 -53
- package/src/ui/scroll-area.tsx +0 -56
- package/src/ui/select.tsx +0 -168
- package/src/ui/separator.tsx +0 -39
- package/src/ui/sheet.tsx +0 -150
- package/src/ui/sidebar.tsx +0 -781
- package/src/ui/skeleton.tsx +0 -23
- package/src/ui/slider.tsx +0 -39
- package/src/ui/sonner.tsx +0 -53
- package/src/ui/switch.tsx +0 -37
- package/src/ui/table.tsx +0 -125
- package/src/ui/tabs.tsx +0 -63
- package/src/ui/textarea.tsx +0 -30
- package/src/ui/toast.tsx +0 -137
- package/src/ui/toggle-group.tsx +0 -69
- package/src/ui/toggle.tsx +0 -53
- package/src/ui/tooltip.tsx +0 -38
- package/src/ui/typography.tsx +0 -85
- package/tsconfig.json +0 -19
- package/vite.config.ts +0 -71
- package/vitest.config.ts +0 -5
|
@@ -1,353 +0,0 @@
|
|
|
1
|
-
# Timeline Component
|
|
2
|
-
|
|
3
|
-
A comprehensive, feature-rich timeline component for Object UI that supports three distinct variants: vertical, horizontal, and Gantt-style (Airtable-like) timelines.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- 🎯 **Three Variants**: Vertical, Horizontal, and Gantt/Airtable-style timelines
|
|
8
|
-
- 🎨 **Color Variants**: Support for default, success, warning, danger, and info colors
|
|
9
|
-
- 📅 **Date Formatting**: Configurable date formats (short, long, ISO)
|
|
10
|
-
- ⏱️ **Time Scales**: Gantt view supports day, week, and month scales
|
|
11
|
-
- 🔄 **Interactive**: Click handlers for timeline items
|
|
12
|
-
- 🎭 **Icon Support**: Add custom icons or emojis to timeline markers
|
|
13
|
-
- 📊 **Multi-track**: Gantt view supports multiple rows/tracks
|
|
14
|
-
- 🔢 **Auto-calculated**: Automatic date range calculation for Gantt view
|
|
15
|
-
- 💅 **Tailwind CSS**: Fully styled with Tailwind, customizable with className
|
|
16
|
-
|
|
17
|
-
## Installation
|
|
18
|
-
|
|
19
|
-
The timeline component is included in `@object-ui/components`.
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npm install @object-ui/components @object-ui/react @object-ui/core
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Usage
|
|
26
|
-
|
|
27
|
-
### Vertical Timeline
|
|
28
|
-
|
|
29
|
-
Perfect for showing project milestones, history, or chronological events.
|
|
30
|
-
|
|
31
|
-
```json
|
|
32
|
-
{
|
|
33
|
-
"type": "timeline",
|
|
34
|
-
"variant": "vertical",
|
|
35
|
-
"dateFormat": "long",
|
|
36
|
-
"items": [
|
|
37
|
-
{
|
|
38
|
-
"time": "2024-01-15",
|
|
39
|
-
"title": "Project Kickoff",
|
|
40
|
-
"description": "Initial meeting with stakeholders and project planning",
|
|
41
|
-
"variant": "success",
|
|
42
|
-
"icon": "🚀"
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
"time": "2024-02-01",
|
|
46
|
-
"title": "Design Phase Complete",
|
|
47
|
-
"description": "UI/UX designs approved and ready for development",
|
|
48
|
-
"variant": "info",
|
|
49
|
-
"icon": "🎨"
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
"time": "2024-03-15",
|
|
53
|
-
"title": "Beta Release",
|
|
54
|
-
"description": "Internal testing phase begins",
|
|
55
|
-
"variant": "warning",
|
|
56
|
-
"icon": "⚡"
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
"time": "2024-04-01",
|
|
60
|
-
"title": "Official Launch",
|
|
61
|
-
"description": "Product goes live to all users",
|
|
62
|
-
"variant": "success",
|
|
63
|
-
"icon": "🎉"
|
|
64
|
-
}
|
|
65
|
-
]
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Horizontal Timeline
|
|
70
|
-
|
|
71
|
-
Ideal for roadmaps, quarterly plans, or linear progressions.
|
|
72
|
-
|
|
73
|
-
```json
|
|
74
|
-
{
|
|
75
|
-
"type": "timeline",
|
|
76
|
-
"variant": "horizontal",
|
|
77
|
-
"dateFormat": "short",
|
|
78
|
-
"items": [
|
|
79
|
-
{
|
|
80
|
-
"time": "2024-01-01",
|
|
81
|
-
"title": "Q1 2024",
|
|
82
|
-
"description": "Planning & Design",
|
|
83
|
-
"variant": "success"
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
"time": "2024-04-01",
|
|
87
|
-
"title": "Q2 2024",
|
|
88
|
-
"description": "Development",
|
|
89
|
-
"variant": "info"
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
"time": "2024-07-01",
|
|
93
|
-
"title": "Q3 2024",
|
|
94
|
-
"description": "Testing & QA",
|
|
95
|
-
"variant": "warning"
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
"time": "2024-10-01",
|
|
99
|
-
"title": "Q4 2024",
|
|
100
|
-
"description": "Launch & Scale",
|
|
101
|
-
"variant": "success"
|
|
102
|
-
}
|
|
103
|
-
]
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Gantt Timeline (Airtable Style)
|
|
108
|
-
|
|
109
|
-
Perfect for project management, resource planning, and multi-track timelines.
|
|
110
|
-
|
|
111
|
-
```json
|
|
112
|
-
{
|
|
113
|
-
"type": "timeline",
|
|
114
|
-
"variant": "gantt",
|
|
115
|
-
"dateFormat": "short",
|
|
116
|
-
"timeScale": "month",
|
|
117
|
-
"rowLabel": "Project Tasks",
|
|
118
|
-
"items": [
|
|
119
|
-
{
|
|
120
|
-
"label": "Backend Development",
|
|
121
|
-
"items": [
|
|
122
|
-
{
|
|
123
|
-
"title": "API Design",
|
|
124
|
-
"startDate": "2024-01-01",
|
|
125
|
-
"endDate": "2024-01-31",
|
|
126
|
-
"variant": "success"
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
"title": "Database Schema",
|
|
130
|
-
"startDate": "2024-01-15",
|
|
131
|
-
"endDate": "2024-02-15",
|
|
132
|
-
"variant": "info"
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
"title": "API Implementation",
|
|
136
|
-
"startDate": "2024-02-01",
|
|
137
|
-
"endDate": "2024-03-31",
|
|
138
|
-
"variant": "default"
|
|
139
|
-
}
|
|
140
|
-
]
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
"label": "Frontend Development",
|
|
144
|
-
"items": [
|
|
145
|
-
{
|
|
146
|
-
"title": "UI Design",
|
|
147
|
-
"startDate": "2024-01-15",
|
|
148
|
-
"endDate": "2024-02-15",
|
|
149
|
-
"variant": "warning"
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
"title": "Component Library",
|
|
153
|
-
"startDate": "2024-02-01",
|
|
154
|
-
"endDate": "2024-03-15",
|
|
155
|
-
"variant": "info"
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
"title": "Integration",
|
|
159
|
-
"startDate": "2024-03-01",
|
|
160
|
-
"endDate": "2024-04-15",
|
|
161
|
-
"variant": "default"
|
|
162
|
-
}
|
|
163
|
-
]
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
"label": "Testing & QA",
|
|
167
|
-
"items": [
|
|
168
|
-
{
|
|
169
|
-
"title": "Unit Tests",
|
|
170
|
-
"startDate": "2024-02-15",
|
|
171
|
-
"endDate": "2024-03-15",
|
|
172
|
-
"variant": "success"
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
"title": "Integration Tests",
|
|
176
|
-
"startDate": "2024-03-01",
|
|
177
|
-
"endDate": "2024-04-01",
|
|
178
|
-
"variant": "info"
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
"title": "User Acceptance Testing",
|
|
182
|
-
"startDate": "2024-04-01",
|
|
183
|
-
"endDate": "2024-04-30",
|
|
184
|
-
"variant": "danger"
|
|
185
|
-
}
|
|
186
|
-
]
|
|
187
|
-
}
|
|
188
|
-
]
|
|
189
|
-
}
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
## Props
|
|
193
|
-
|
|
194
|
-
### Common Props
|
|
195
|
-
|
|
196
|
-
| Prop | Type | Default | Description |
|
|
197
|
-
|------|------|---------|-------------|
|
|
198
|
-
| `variant` | `'vertical' \| 'horizontal' \| 'gantt'` | `'vertical'` | Timeline variant to render |
|
|
199
|
-
| `dateFormat` | `'short' \| 'long' \| 'iso'` | `'short'` | Date formatting style |
|
|
200
|
-
| `items` | `TimelineItem[]` | `[]` | Array of timeline items (structure varies by variant) |
|
|
201
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
202
|
-
|
|
203
|
-
### Vertical/Horizontal Item Props
|
|
204
|
-
|
|
205
|
-
| Prop | Type | Description |
|
|
206
|
-
|------|------|-------------|
|
|
207
|
-
| `time` | `string` | ISO date string (e.g., "2024-01-15") |
|
|
208
|
-
| `title` | `string` | Item title |
|
|
209
|
-
| `description` | `string` | Item description |
|
|
210
|
-
| `variant` | `'default' \| 'success' \| 'warning' \| 'danger' \| 'info'` | Color variant |
|
|
211
|
-
| `icon` | `string` | Icon or emoji to display in marker |
|
|
212
|
-
| `content` | `SchemaNode` | Custom content schema |
|
|
213
|
-
| `className` | `string` | Additional CSS classes |
|
|
214
|
-
|
|
215
|
-
### Gantt-Specific Props
|
|
216
|
-
|
|
217
|
-
| Prop | Type | Default | Description |
|
|
218
|
-
|------|------|---------|-------------|
|
|
219
|
-
| `timeScale` | `'day' \| 'week' \| 'month'` | `'month'` | Time scale for the timeline header |
|
|
220
|
-
| `rowLabel` | `string` | `'Items'` | Label for the row header column |
|
|
221
|
-
| `minDate` | `string` | Auto-calculated | Override minimum date (YYYY-MM-DD) |
|
|
222
|
-
| `maxDate` | `string` | Auto-calculated | Override maximum date (YYYY-MM-DD) |
|
|
223
|
-
|
|
224
|
-
### Gantt Item Structure
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
{
|
|
228
|
-
label: string; // Row label
|
|
229
|
-
items: Array<{
|
|
230
|
-
title: string; // Bar label
|
|
231
|
-
startDate: string; // ISO date string
|
|
232
|
-
endDate: string; // ISO date string
|
|
233
|
-
variant?: string; // Color variant
|
|
234
|
-
}>;
|
|
235
|
-
}
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
## Color Variants
|
|
239
|
-
|
|
240
|
-
The timeline component supports 5 color variants:
|
|
241
|
-
|
|
242
|
-
- `default` - Blue (default color)
|
|
243
|
-
- `success` - Green
|
|
244
|
-
- `warning` - Yellow/Orange
|
|
245
|
-
- `danger` - Red
|
|
246
|
-
- `info` - Purple
|
|
247
|
-
|
|
248
|
-
Each variant applies to markers (vertical/horizontal) or bars (Gantt).
|
|
249
|
-
|
|
250
|
-
## Date Formats
|
|
251
|
-
|
|
252
|
-
- `short` - MM/DD/YYYY (e.g., "1/15/2024")
|
|
253
|
-
- `long` - Month DD, YYYY (e.g., "January 15, 2024")
|
|
254
|
-
- `iso` - YYYY-MM-DD (e.g., "2024-01-15")
|
|
255
|
-
|
|
256
|
-
## Time Scales (Gantt Only)
|
|
257
|
-
|
|
258
|
-
- `day` - Daily granularity
|
|
259
|
-
- `week` - Weekly granularity
|
|
260
|
-
- `month` - Monthly granularity (default)
|
|
261
|
-
|
|
262
|
-
## Advanced Usage
|
|
263
|
-
|
|
264
|
-
### Custom Styling
|
|
265
|
-
|
|
266
|
-
Use Tailwind CSS classes for custom styling:
|
|
267
|
-
|
|
268
|
-
```json
|
|
269
|
-
{
|
|
270
|
-
"type": "timeline",
|
|
271
|
-
"variant": "vertical",
|
|
272
|
-
"className": "max-w-3xl mx-auto",
|
|
273
|
-
"items": [
|
|
274
|
-
{
|
|
275
|
-
"time": "2024-01-15",
|
|
276
|
-
"title": "Custom Styled Item",
|
|
277
|
-
"className": "bg-blue-50 p-4 rounded-lg",
|
|
278
|
-
"variant": "info"
|
|
279
|
-
}
|
|
280
|
-
]
|
|
281
|
-
}
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
### With Custom Content
|
|
285
|
-
|
|
286
|
-
You can add custom content schemas to vertical/horizontal timeline items:
|
|
287
|
-
|
|
288
|
-
```json
|
|
289
|
-
{
|
|
290
|
-
"type": "timeline",
|
|
291
|
-
"variant": "vertical",
|
|
292
|
-
"items": [
|
|
293
|
-
{
|
|
294
|
-
"time": "2024-01-15",
|
|
295
|
-
"title": "Custom Content",
|
|
296
|
-
"content": [
|
|
297
|
-
{
|
|
298
|
-
"type": "button",
|
|
299
|
-
"label": "View Details",
|
|
300
|
-
"className": "mt-2"
|
|
301
|
-
}
|
|
302
|
-
]
|
|
303
|
-
}
|
|
304
|
-
]
|
|
305
|
-
}
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
### Interactive Items
|
|
309
|
-
|
|
310
|
-
Handle item clicks in Gantt view:
|
|
311
|
-
|
|
312
|
-
```typescript
|
|
313
|
-
// In React component
|
|
314
|
-
<SchemaRenderer
|
|
315
|
-
schema={{
|
|
316
|
-
type: 'timeline',
|
|
317
|
-
variant: 'gantt',
|
|
318
|
-
onItemClick: (item, row, rowIndex, itemIndex) => {
|
|
319
|
-
console.log('Clicked:', item.title, 'in row:', row.label);
|
|
320
|
-
},
|
|
321
|
-
items: [...]
|
|
322
|
-
}}
|
|
323
|
-
/>
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
## UI Components
|
|
327
|
-
|
|
328
|
-
The timeline component is built using these base UI components:
|
|
329
|
-
|
|
330
|
-
### Vertical/Horizontal
|
|
331
|
-
- `Timeline` - Container
|
|
332
|
-
- `TimelineItem` - Individual item
|
|
333
|
-
- `TimelineMarker` - Marker/dot
|
|
334
|
-
- `TimelineContent` - Content wrapper
|
|
335
|
-
- `TimelineTitle` - Title heading
|
|
336
|
-
- `TimelineTime` - Time display
|
|
337
|
-
- `TimelineDescription` - Description text
|
|
338
|
-
|
|
339
|
-
### Gantt
|
|
340
|
-
- `TimelineGantt` - Container
|
|
341
|
-
- `TimelineGanttHeader` - Header with time scale
|
|
342
|
-
- `TimelineGanttRow` - Individual row
|
|
343
|
-
- `TimelineGanttLabel` - Row label
|
|
344
|
-
- `TimelineGanttBar` - Task bar
|
|
345
|
-
- `TimelineGanttBarContent` - Bar content/text
|
|
346
|
-
|
|
347
|
-
## Examples
|
|
348
|
-
|
|
349
|
-
See the [prototype app](../../examples/prototype/src/App.tsx) for comprehensive examples of all three timeline variants in action.
|
|
350
|
-
|
|
351
|
-
## License
|
|
352
|
-
|
|
353
|
-
MIT
|
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Data Table - Airtable UX Enhancements Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests for row hover expand button, column header context menu,
|
|
5
|
-
* and hide column functionality.
|
|
6
|
-
*/
|
|
7
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
8
|
-
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
|
|
9
|
-
import '@testing-library/jest-dom';
|
|
10
|
-
import React from 'react';
|
|
11
|
-
import { SchemaRenderer } from '@object-ui/react';
|
|
12
|
-
|
|
13
|
-
// Import data-table to ensure it's registered
|
|
14
|
-
import '../data-table';
|
|
15
|
-
|
|
16
|
-
const baseSchema = {
|
|
17
|
-
type: 'data-table',
|
|
18
|
-
columns: [
|
|
19
|
-
{ header: 'Name', accessorKey: 'name' },
|
|
20
|
-
{ header: 'Email', accessorKey: 'email' },
|
|
21
|
-
{ header: 'Role', accessorKey: 'role' },
|
|
22
|
-
],
|
|
23
|
-
data: [
|
|
24
|
-
{ id: 1, name: 'Alice', email: 'alice@test.com', role: 'Admin' },
|
|
25
|
-
{ id: 2, name: 'Bob', email: 'bob@test.com', role: 'User' },
|
|
26
|
-
],
|
|
27
|
-
pagination: false,
|
|
28
|
-
searchable: false,
|
|
29
|
-
showRowNumbers: true,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// =========================================================================
|
|
33
|
-
// 1. Row hover expand button
|
|
34
|
-
// =========================================================================
|
|
35
|
-
describe('Row hover expand button', () => {
|
|
36
|
-
it('should render expand buttons on rows when onRowClick is configured', async () => {
|
|
37
|
-
const onRowClick = vi.fn();
|
|
38
|
-
render(
|
|
39
|
-
<SchemaRenderer
|
|
40
|
-
schema={{ ...baseSchema, onRowClick }}
|
|
41
|
-
/>
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
await waitFor(() => {
|
|
45
|
-
expect(screen.getByText('Alice')).toBeInTheDocument();
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// Expand buttons should exist (hidden via CSS, visible on hover)
|
|
49
|
-
const expandButtons = screen.getAllByTestId('row-expand-button');
|
|
50
|
-
expect(expandButtons.length).toBe(2);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('should not render expand buttons when onRowClick is not configured', async () => {
|
|
54
|
-
render(<SchemaRenderer schema={baseSchema} />);
|
|
55
|
-
|
|
56
|
-
await waitFor(() => {
|
|
57
|
-
expect(screen.getByText('Alice')).toBeInTheDocument();
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
expect(screen.queryAllByTestId('row-expand-button')).toHaveLength(0);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should call onRowClick when expand button is clicked', async () => {
|
|
64
|
-
const onRowClick = vi.fn();
|
|
65
|
-
render(
|
|
66
|
-
<SchemaRenderer
|
|
67
|
-
schema={{ ...baseSchema, onRowClick }}
|
|
68
|
-
/>
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
await waitFor(() => {
|
|
72
|
-
expect(screen.getByText('Alice')).toBeInTheDocument();
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
const expandButtons = screen.getAllByTestId('row-expand-button');
|
|
76
|
-
fireEvent.click(expandButtons[0]);
|
|
77
|
-
|
|
78
|
-
expect(onRowClick).toHaveBeenCalledTimes(1);
|
|
79
|
-
expect(onRowClick).toHaveBeenCalledWith(
|
|
80
|
-
expect.objectContaining({ name: 'Alice' })
|
|
81
|
-
);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// =========================================================================
|
|
86
|
-
// 2. Column header context menu
|
|
87
|
-
// =========================================================================
|
|
88
|
-
describe('Column header context menu', () => {
|
|
89
|
-
it('should show context menu on right-click of column header', async () => {
|
|
90
|
-
render(<SchemaRenderer schema={baseSchema} />);
|
|
91
|
-
|
|
92
|
-
await waitFor(() => {
|
|
93
|
-
expect(screen.getByText('Name')).toBeInTheDocument();
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
// Right-click on the "Name" column header
|
|
97
|
-
const nameHeader = screen.getByText('Name').closest('th');
|
|
98
|
-
expect(nameHeader).toBeTruthy();
|
|
99
|
-
fireEvent.contextMenu(nameHeader!);
|
|
100
|
-
|
|
101
|
-
// Context menu should appear
|
|
102
|
-
await waitFor(() => {
|
|
103
|
-
expect(screen.getByTestId('column-context-menu')).toBeInTheDocument();
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// Should contain Sort and Hide options
|
|
107
|
-
expect(screen.getByText('Sort ascending')).toBeInTheDocument();
|
|
108
|
-
expect(screen.getByText('Sort descending')).toBeInTheDocument();
|
|
109
|
-
expect(screen.getByText('Hide column')).toBeInTheDocument();
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('should hide column when "Hide column" is clicked', async () => {
|
|
113
|
-
render(<SchemaRenderer schema={baseSchema} />);
|
|
114
|
-
|
|
115
|
-
await waitFor(() => {
|
|
116
|
-
expect(screen.getByText('Email')).toBeInTheDocument();
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// Right-click on the "Email" column header
|
|
120
|
-
const emailHeader = screen.getByText('Email').closest('th');
|
|
121
|
-
fireEvent.contextMenu(emailHeader!);
|
|
122
|
-
|
|
123
|
-
await waitFor(() => {
|
|
124
|
-
expect(screen.getByTestId('column-context-menu')).toBeInTheDocument();
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
// Click "Hide column"
|
|
128
|
-
fireEvent.click(screen.getByText('Hide column'));
|
|
129
|
-
|
|
130
|
-
// The "Email" column should no longer be visible
|
|
131
|
-
await waitFor(() => {
|
|
132
|
-
expect(screen.queryByText('Email')).not.toBeInTheDocument();
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// Other columns should still be visible
|
|
136
|
-
expect(screen.getByText('Name')).toBeInTheDocument();
|
|
137
|
-
expect(screen.getByText('Role')).toBeInTheDocument();
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it('should sort ascending when "Sort ascending" is clicked from context menu', async () => {
|
|
141
|
-
render(
|
|
142
|
-
<SchemaRenderer
|
|
143
|
-
schema={{
|
|
144
|
-
...baseSchema,
|
|
145
|
-
sortable: true,
|
|
146
|
-
}}
|
|
147
|
-
/>
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
await waitFor(() => {
|
|
151
|
-
expect(screen.getByText('Name')).toBeInTheDocument();
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// Right-click on the "Name" column header
|
|
155
|
-
const nameHeader = screen.getByText('Name').closest('th');
|
|
156
|
-
fireEvent.contextMenu(nameHeader!);
|
|
157
|
-
|
|
158
|
-
await waitFor(() => {
|
|
159
|
-
expect(screen.getByTestId('column-context-menu')).toBeInTheDocument();
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
// Click "Sort ascending"
|
|
163
|
-
fireEvent.click(screen.getByText('Sort ascending'));
|
|
164
|
-
|
|
165
|
-
// Context menu should close
|
|
166
|
-
await waitFor(() => {
|
|
167
|
-
expect(screen.queryByTestId('column-context-menu')).not.toBeInTheDocument();
|
|
168
|
-
});
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
// =========================================================================
|
|
173
|
-
// 3. Group/row hover styling
|
|
174
|
-
// =========================================================================
|
|
175
|
-
describe('Row group hover class', () => {
|
|
176
|
-
it('should apply group/row hover class to table rows', async () => {
|
|
177
|
-
render(<SchemaRenderer schema={baseSchema} />);
|
|
178
|
-
|
|
179
|
-
await waitFor(() => {
|
|
180
|
-
expect(screen.getByText('Alice')).toBeInTheDocument();
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
// Data rows should have group/row class for hover effects
|
|
184
|
-
const aliceRow = screen.getByText('Alice').closest('tr');
|
|
185
|
-
expect(aliceRow).toHaveClass('group/row');
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
// =========================================================================
|
|
190
|
-
// 5. Filler rows behavior
|
|
191
|
-
// =========================================================================
|
|
192
|
-
describe('Filler rows', () => {
|
|
193
|
-
it('should not render filler rows when pagination is disabled', async () => {
|
|
194
|
-
// pagination: false with pageSize: 10 and only 2 data rows
|
|
195
|
-
// should NOT produce empty filler rows
|
|
196
|
-
render(
|
|
197
|
-
<SchemaRenderer
|
|
198
|
-
schema={{ ...baseSchema, pagination: false, pageSize: 10 }}
|
|
199
|
-
/>
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
await waitFor(() => {
|
|
203
|
-
expect(screen.getByText('Alice')).toBeInTheDocument();
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
const table = screen.getByRole('table');
|
|
207
|
-
const tbody = table.querySelector('tbody');
|
|
208
|
-
const allRows = tbody!.querySelectorAll('tr');
|
|
209
|
-
|
|
210
|
-
// Should only have data rows (2) + add-record row if any, no filler rows
|
|
211
|
-
// With 2 data items and no add-record, expect exactly 2 rows
|
|
212
|
-
const fillerRows = Array.from(allRows).filter(
|
|
213
|
-
(row) => row.querySelector('td[class*="p-0"]') && row.textContent === ''
|
|
214
|
-
);
|
|
215
|
-
expect(fillerRows).toHaveLength(0);
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
it('should render filler rows when pagination is enabled and page is not full', async () => {
|
|
219
|
-
render(
|
|
220
|
-
<SchemaRenderer
|
|
221
|
-
schema={{ ...baseSchema, pagination: true, pageSize: 5, searchable: false }}
|
|
222
|
-
/>
|
|
223
|
-
);
|
|
224
|
-
|
|
225
|
-
await waitFor(() => {
|
|
226
|
-
expect(screen.getByText('Alice')).toBeInTheDocument();
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
const table = screen.getByRole('table');
|
|
230
|
-
const tbody = table.querySelector('tbody');
|
|
231
|
-
const allRows = tbody!.querySelectorAll('tr');
|
|
232
|
-
|
|
233
|
-
// With 2 data rows and pageSize 5, expect 3 filler rows (5 - 2 = 3)
|
|
234
|
-
const fillerRows = Array.from(allRows).filter(
|
|
235
|
-
(row) => row.querySelector('td[class*="p-0"]') && row.textContent === ''
|
|
236
|
-
);
|
|
237
|
-
expect(fillerRows).toHaveLength(3);
|
|
238
|
-
});
|
|
239
|
-
});
|