@object-ui/plugin-timeline 3.1.5 → 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.
Files changed (33) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +20 -0
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +1041 -751
  5. package/dist/index.umd.cjs +31 -6
  6. package/dist/packages/plugin-timeline/src/ObjectTimeline.d.ts.map +1 -0
  7. package/dist/packages/plugin-timeline/src/ObjectTimeline.stories.d.ts.map +1 -0
  8. package/dist/packages/plugin-timeline/src/index.d.ts.map +1 -0
  9. package/dist/packages/plugin-timeline/src/renderer.d.ts.map +1 -0
  10. package/package.json +36 -13
  11. package/.turbo/turbo-build.log +0 -22
  12. package/dist/src/ObjectTimeline.d.ts.map +0 -1
  13. package/dist/src/ObjectTimeline.stories.d.ts.map +0 -1
  14. package/dist/src/index.d.ts.map +0 -1
  15. package/dist/src/renderer.d.ts.map +0 -1
  16. package/src/ObjectTimeline.msw.test.tsx +0 -80
  17. package/src/ObjectTimeline.stories.tsx +0 -113
  18. package/src/ObjectTimeline.test.tsx +0 -138
  19. package/src/ObjectTimeline.tsx +0 -241
  20. package/src/__tests__/ObjectTimeline.spec-config.test.tsx +0 -232
  21. package/src/__tests__/renderer.test.tsx +0 -295
  22. package/src/__tests__/timeline-variants.test.tsx +0 -150
  23. package/src/index.test.tsx +0 -24
  24. package/src/index.tsx +0 -334
  25. package/src/renderer.tsx +0 -477
  26. package/tsconfig.json +0 -18
  27. package/vite.config.ts +0 -63
  28. package/vitest.config.ts +0 -13
  29. package/vitest.setup.ts +0 -1
  30. /package/dist/{src → packages/plugin-timeline/src}/ObjectTimeline.d.ts +0 -0
  31. /package/dist/{src → packages/plugin-timeline/src}/ObjectTimeline.stories.d.ts +0 -0
  32. /package/dist/{src → packages/plugin-timeline/src}/index.d.ts +0 -0
  33. /package/dist/{src → packages/plugin-timeline/src}/renderer.d.ts +0 -0
package/src/renderer.tsx DELETED
@@ -1,477 +0,0 @@
1
- /**
2
- * ObjectUI
3
- * Copyright (c) 2024-present ObjectStack Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
-
9
- import { ComponentRegistry } from '@object-ui/core';
10
- import type { TimelineSchema } from '@object-ui/types';
11
- import {
12
- Timeline,
13
- TimelineItem,
14
- TimelineMarker,
15
- TimelineContent,
16
- TimelineTitle,
17
- TimelineTime,
18
- TimelineDescription,
19
- TimelineHorizontal,
20
- TimelineHorizontalItem,
21
- TimelineGantt,
22
- TimelineGanttHeader,
23
- TimelineGanttRowLabels,
24
- TimelineGanttGrid,
25
- TimelineGanttRow,
26
- TimelineGanttLabel,
27
- TimelineGanttBar,
28
- TimelineGanttBarContent,
29
- } from './index';
30
- import { renderChildren, cn } from '@object-ui/components';
31
-
32
- // Constants
33
- const MILLISECONDS_PER_WEEK = 7 * 24 * 60 * 60 * 1000;
34
-
35
- // Helper function to calculate date range from items
36
- function calculateDateRange(items: any[]): { minDate: string; maxDate: string } {
37
- const allDates = items.flatMap((row: any) =>
38
- (row.items || []).flatMap((item: any) => [item.startDate, item.endDate])
39
- );
40
-
41
- const minTimestamp = Math.min(...allDates.map((d: string) => new Date(d).getTime()));
42
- const maxTimestamp = Math.max(...allDates.map((d: string) => new Date(d).getTime()));
43
-
44
- return {
45
- minDate: new Date(minTimestamp).toISOString().split('T')[0],
46
- maxDate: new Date(maxTimestamp).toISOString().split('T')[0],
47
- };
48
- }
49
-
50
- // Helper function to calculate bar position and width based on dates
51
- function calculateBarDimensions(
52
- startDate: string,
53
- endDate: string,
54
- minDate: string,
55
- maxDate: string
56
- ): { start: number; width: number } {
57
- const start = new Date(startDate).getTime();
58
- const end = new Date(endDate).getTime();
59
- const min = new Date(minDate).getTime();
60
- const max = new Date(maxDate).getTime();
61
-
62
- const totalDuration = max - min;
63
- const startOffset = start - min;
64
- const duration = end - start;
65
-
66
- return {
67
- start: (startOffset / totalDuration) * 100,
68
- width: (duration / totalDuration) * 100,
69
- };
70
- }
71
-
72
- // Helper function to format date
73
- function formatDate(dateString: string, format?: string): string {
74
- const date = new Date(dateString);
75
- if (format === 'short') {
76
- return date.toLocaleDateString();
77
- }
78
- if (format === 'long') {
79
- return date.toLocaleDateString('en-US', {
80
- year: 'numeric',
81
- month: 'long',
82
- day: 'numeric',
83
- });
84
- }
85
- return date.toISOString().split('T')[0];
86
- }
87
-
88
- export const TimelineRenderer = ({ schema, className, ...props }: { schema: TimelineSchema; className?: string; [key: string]: any }) => {
89
- const {
90
- variant = 'vertical',
91
- items = [],
92
- dateFormat = 'short',
93
- onItemClick,
94
- } = schema;
95
-
96
- // Vertical Timeline
97
- if (variant === 'vertical') {
98
- return (
99
- <Timeline className={className} {...props}>
100
- {items.map((item: any, index: number) => (
101
- <TimelineItem key={index} className={cn(item.className, onItemClick && 'cursor-pointer')} onClick={() => onItemClick?.(item)}>
102
- <TimelineMarker variant={item.variant || 'default'}>
103
- {item.icon && <span className="text-xs">{item.icon}</span>}
104
- </TimelineMarker>
105
- <TimelineContent>
106
- {item.time && (
107
- <TimelineTime dateTime={item.time}>
108
- {formatDate(item.time, dateFormat)}
109
- </TimelineTime>
110
- )}
111
- {item.title && <TimelineTitle>{item.title}</TimelineTitle>}
112
- {item.description && (
113
- <TimelineDescription className="line-clamp-2 sm:line-clamp-none">{item.description}</TimelineDescription>
114
- )}
115
- {item.content && renderChildren(item.content)}
116
- </TimelineContent>
117
- </TimelineItem>
118
- ))}
119
- </Timeline>
120
- );
121
- }
122
-
123
- // Horizontal Timeline
124
- if (variant === 'horizontal') {
125
- return (
126
- <TimelineHorizontal className={cn("overflow-x-auto [-webkit-overflow-scrolling:touch]", className)} {...props}>
127
- {items.map((item: any, index: number) => (
128
- <TimelineHorizontalItem key={index} className={cn(item.className, onItemClick && 'cursor-pointer')} onClick={() => onItemClick?.(item)}>
129
- <div className="flex flex-col items-center">
130
- <TimelineMarker variant={item.variant || 'default'}>
131
- {item.icon && <span className="text-xs">{item.icon}</span>}
132
- </TimelineMarker>
133
- <div className="mt-4 text-center">
134
- {item.time && (
135
- <TimelineTime dateTime={item.time}>
136
- {formatDate(item.time, dateFormat)}
137
- </TimelineTime>
138
- )}
139
- {item.title && <TimelineTitle>{item.title}</TimelineTitle>}
140
- {item.description && (
141
- <TimelineDescription className="text-center line-clamp-2 sm:line-clamp-none">
142
- {item.description}
143
- </TimelineDescription>
144
- )}
145
- {item.content && renderChildren(item.content)}
146
- </div>
147
- </div>
148
- {index < items.length - 1 && (
149
- <div className="absolute left-full w-16 border-t-2 border-gray-200 top-3" />
150
- )}
151
- </TimelineHorizontalItem>
152
- ))}
153
- </TimelineHorizontal>
154
- );
155
- }
156
-
157
- // Gantt/Airtable-style Timeline
158
- if (variant === 'gantt') {
159
- // Calculate date range from all items
160
- const dateRange = calculateDateRange(items);
161
- const minDate = schema.minDate || dateRange.minDate;
162
- const maxDate = schema.maxDate || dateRange.maxDate;
163
-
164
- // Generate time scale headers (months, weeks, etc.)
165
- const timeScale = schema.timeScale || 'month';
166
- const generateTimeHeaders = () => {
167
- const headers: string[] = [];
168
- const start = new Date(minDate);
169
- const end = new Date(maxDate);
170
-
171
- if (timeScale === 'month') {
172
- const current = new Date(start);
173
- while (current <= end) {
174
- headers.push(
175
- current.toLocaleDateString('en-US', {
176
- month: 'short',
177
- year: 'numeric',
178
- })
179
- );
180
- current.setMonth(current.getMonth() + 1);
181
- }
182
- } else if (timeScale === 'week') {
183
- const current = new Date(start);
184
- while (current <= end) {
185
- headers.push(
186
- `Week ${Math.ceil(
187
- (current.getTime() - start.getTime()) / MILLISECONDS_PER_WEEK
188
- ) + 1}`
189
- );
190
- current.setDate(current.getDate() + 7);
191
- }
192
- } else if (timeScale === 'day') {
193
- const current = new Date(start);
194
- while (current <= end) {
195
- headers.push(
196
- current.toLocaleDateString('en-US', {
197
- month: 'short',
198
- day: 'numeric',
199
- })
200
- );
201
- current.setDate(current.getDate() + 1);
202
- }
203
- }
204
-
205
- return headers;
206
- };
207
-
208
- const timeHeaders = generateTimeHeaders();
209
-
210
- return (
211
- <TimelineGantt className={cn("overflow-x-auto [-webkit-overflow-scrolling:touch]", className)} {...props}>
212
- {/* Header */}
213
- <TimelineGanttHeader>
214
- <TimelineGanttRowLabels className="flex items-center px-2 sm:px-4 py-2 sm:py-3">
215
- <span className="font-semibold text-xs sm:text-sm">
216
- {schema.rowLabel || 'Items'}
217
- </span>
218
- </TimelineGanttRowLabels>
219
- <TimelineGanttGrid>
220
- <div className="flex h-full">
221
- {timeHeaders.map((header, index) => (
222
- <div
223
- key={index}
224
- className="flex-1 px-1 sm:px-2 py-2 sm:py-3 border-r text-xs font-medium text-center"
225
- >
226
- {header}
227
- </div>
228
- ))}
229
- </div>
230
- </TimelineGanttGrid>
231
- </TimelineGanttHeader>
232
-
233
- {/* Rows */}
234
- <div>
235
- <div className="flex">
236
- <TimelineGanttRowLabels>
237
- {items.map((row: any, rowIndex: number) => (
238
- <TimelineGanttRow key={rowIndex}>
239
- <TimelineGanttLabel title={row.label} className="truncate">
240
- {row.label}
241
- </TimelineGanttLabel>
242
- </TimelineGanttRow>
243
- ))}
244
- </TimelineGanttRowLabels>
245
- <TimelineGanttGrid className="relative">
246
- {items.map((row: any, rowIndex: number) => (
247
- <TimelineGanttRow key={rowIndex} className="relative">
248
- {(row.items || []).map((item: any, itemIndex: number) => {
249
- const dimensions = calculateBarDimensions(
250
- item.startDate,
251
- item.endDate,
252
- minDate,
253
- maxDate
254
- );
255
-
256
- return (
257
- <TimelineGanttBar
258
- key={itemIndex}
259
- start={dimensions.start}
260
- width={dimensions.width}
261
- variant={item.variant || 'default'}
262
- onClick={() => onItemClick?.(item, row, rowIndex, itemIndex)}
263
- title={`${item.title || ''}\n${formatDate(item.startDate, dateFormat)} - ${formatDate(item.endDate, dateFormat)}`}
264
- >
265
- <TimelineGanttBarContent>
266
- {item.title}
267
- </TimelineGanttBarContent>
268
- </TimelineGanttBar>
269
- );
270
- })}
271
- </TimelineGanttRow>
272
- ))}
273
- </TimelineGanttGrid>
274
- </div>
275
- </div>
276
- </TimelineGantt>
277
- );
278
- }
279
-
280
- return null;
281
- };
282
-
283
- ComponentRegistry.register(
284
- 'timeline',
285
- TimelineRenderer,
286
- {
287
- namespace: 'plugin-timeline',
288
- label: 'Timeline',
289
- category: 'data-display',
290
- inputs: [
291
- {
292
- name: 'variant',
293
- type: 'enum',
294
- enum: ['vertical', 'horizontal', 'gantt'],
295
- label: 'Timeline Variant',
296
- defaultValue: 'vertical',
297
- },
298
- {
299
- name: 'items',
300
- type: 'array',
301
- label: 'Timeline Items',
302
- description:
303
- 'For vertical/horizontal: Array of { time, title, description, variant, icon, content }. For gantt: Array of { label, items: [{ title, startDate, endDate, variant }] }',
304
- },
305
- {
306
- name: 'dateFormat',
307
- type: 'enum',
308
- enum: ['short', 'long', 'iso'],
309
- label: 'Date Format',
310
- defaultValue: 'short',
311
- },
312
- {
313
- name: 'timeScale',
314
- type: 'enum',
315
- enum: ['day', 'week', 'month'],
316
- label: 'Time Scale (Gantt only)',
317
- defaultValue: 'month',
318
- },
319
- {
320
- name: 'rowLabel',
321
- type: 'string',
322
- label: 'Row Label (Gantt only)',
323
- defaultValue: 'Items',
324
- },
325
- {
326
- name: 'minDate',
327
- type: 'string',
328
- label: 'Min Date (Gantt only)',
329
- description: 'Override auto-calculated min date (YYYY-MM-DD)',
330
- },
331
- {
332
- name: 'maxDate',
333
- type: 'string',
334
- label: 'Max Date (Gantt only)',
335
- description: 'Override auto-calculated max date (YYYY-MM-DD)',
336
- },
337
- { name: 'className', type: 'string', label: 'CSS Class' },
338
- ],
339
- defaultProps: {
340
- variant: 'vertical',
341
- dateFormat: 'short',
342
- items: [
343
- {
344
- time: '2024-01-15',
345
- title: 'Project Started',
346
- description: 'Kickoff meeting and initial planning',
347
- variant: 'success',
348
- icon: '🚀',
349
- },
350
- {
351
- time: '2024-02-01',
352
- title: 'First Milestone',
353
- description: 'Completed initial design phase',
354
- variant: 'info',
355
- icon: '🎨',
356
- },
357
- {
358
- time: '2024-03-15',
359
- title: 'Beta Release',
360
- description: 'Released beta version to testers',
361
- variant: 'warning',
362
- icon: '⚡',
363
- },
364
- {
365
- time: '2024-04-01',
366
- title: 'Launch',
367
- description: 'Official product launch',
368
- variant: 'success',
369
- icon: '🎉',
370
- },
371
- ],
372
- },
373
- examples: {
374
- vertical: {
375
- variant: 'vertical',
376
- dateFormat: 'long',
377
- items: [
378
- {
379
- time: '2024-01-15',
380
- title: 'Project Started',
381
- description: 'Kickoff meeting and initial planning',
382
- variant: 'success',
383
- },
384
- {
385
- time: '2024-02-01',
386
- title: 'First Milestone',
387
- description: 'Completed initial design phase',
388
- variant: 'info',
389
- },
390
- ],
391
- },
392
- horizontal: {
393
- variant: 'horizontal',
394
- dateFormat: 'short',
395
- items: [
396
- {
397
- time: '2024-01-01',
398
- title: 'Q1',
399
- description: 'First quarter',
400
- variant: 'default',
401
- },
402
- {
403
- time: '2024-04-01',
404
- title: 'Q2',
405
- description: 'Second quarter',
406
- variant: 'info',
407
- },
408
- {
409
- time: '2024-07-01',
410
- title: 'Q3',
411
- description: 'Third quarter',
412
- variant: 'warning',
413
- },
414
- {
415
- time: '2024-10-01',
416
- title: 'Q4',
417
- description: 'Fourth quarter',
418
- variant: 'success',
419
- },
420
- ],
421
- },
422
- gantt: {
423
- variant: 'gantt',
424
- dateFormat: 'short',
425
- timeScale: 'month',
426
- rowLabel: 'Projects',
427
- items: [
428
- {
429
- label: 'Backend Development',
430
- items: [
431
- {
432
- title: 'API Design',
433
- startDate: '2024-01-01',
434
- endDate: '2024-01-31',
435
- variant: 'success',
436
- },
437
- {
438
- title: 'Implementation',
439
- startDate: '2024-02-01',
440
- endDate: '2024-03-31',
441
- variant: 'info',
442
- },
443
- ],
444
- },
445
- {
446
- label: 'Frontend Development',
447
- items: [
448
- {
449
- title: 'UI Design',
450
- startDate: '2024-01-15',
451
- endDate: '2024-02-15',
452
- variant: 'warning',
453
- },
454
- {
455
- title: 'Component Dev',
456
- startDate: '2024-02-15',
457
- endDate: '2024-04-15',
458
- variant: 'default',
459
- },
460
- ],
461
- },
462
- {
463
- label: 'Testing',
464
- items: [
465
- {
466
- title: 'QA Phase',
467
- startDate: '2024-03-01',
468
- endDate: '2024-04-30',
469
- variant: 'danger',
470
- },
471
- ],
472
- },
473
- ],
474
- },
475
- },
476
- }
477
- );
package/tsconfig.json DELETED
@@ -1,18 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "dist",
5
- "jsx": "react-jsx",
6
- "baseUrl": ".",
7
- "paths": {
8
- "@/*": ["src/*"]
9
- },
10
- "noEmit": false,
11
- "declaration": true,
12
- "composite": true,
13
- "declarationMap": true,
14
- "skipLibCheck": true
15
- },
16
- "include": ["src"],
17
- "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.test.tsx"]
18
- }
package/vite.config.ts DELETED
@@ -1,63 +0,0 @@
1
- /**
2
- * ObjectUI
3
- * Copyright (c) 2024-present ObjectStack Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
-
9
- import { defineConfig } from 'vite';
10
- import react from '@vitejs/plugin-react';
11
- import dts from 'vite-plugin-dts';
12
- import { resolve } from 'path';
13
-
14
- export default defineConfig({
15
- plugins: [
16
- react(),
17
- dts({
18
- insertTypesEntry: true,
19
- include: ['src'],
20
- exclude: ['**/*.test.ts', '**/*.test.tsx', 'node_modules'],
21
- skipDiagnostics: true,
22
- }),
23
- ],
24
- resolve: {
25
- alias: {
26
- '@': resolve(__dirname, './src'),
27
- '@object-ui/core': resolve(__dirname, '../core/src'),
28
- '@object-ui/types': resolve(__dirname, '../types/src'),
29
- '@object-ui/react': resolve(__dirname, '../react/src'),
30
- '@object-ui/components': resolve(__dirname, '../components/src'),
31
- '@object-ui/fields': resolve(__dirname, '../fields/src'),
32
- '@object-ui/mobile': resolve(__dirname, '../mobile/src'),
33
- '@object-ui/plugin-dashboard': resolve(__dirname, '../plugin-dashboard/src'),
34
- '@object-ui/plugin-grid': resolve(__dirname, '../plugin-grid/src'),
35
- },
36
- },
37
- build: {
38
- lib: {
39
- entry: resolve(__dirname, 'src/index.tsx'),
40
- name: 'ObjectUIPluginTimeline',
41
- fileName: 'index',
42
- },
43
- rollupOptions: {
44
- external: ['react', 'react-dom', '@object-ui/components', '@object-ui/core', '@object-ui/react', '@object-ui/mobile'],
45
- output: {
46
- globals: {
47
- react: 'React',
48
- 'react-dom': 'ReactDOM',
49
- '@object-ui/components': 'ObjectUIComponents',
50
- '@object-ui/core': 'ObjectUICore',
51
- '@object-ui/react': 'ObjectUIReact',
52
- '@object-ui/mobile': 'ObjectUIMobile',
53
- },
54
- },
55
- },
56
- },
57
- test: {
58
- setupFiles: ['../../vitest.setup.tsx'],
59
- passWithNoTests: true,
60
- globals: true,
61
- environment: 'jsdom',
62
- },
63
- });
package/vitest.config.ts DELETED
@@ -1,13 +0,0 @@
1
- /// <reference types="vitest" />
2
- import { defineConfig } from 'vite';
3
- import react from '@vitejs/plugin-react';
4
- import path from 'path';
5
-
6
- export default defineConfig({
7
- plugins: [react()],
8
- test: {
9
- environment: 'happy-dom',
10
- globals: true,
11
- setupFiles: ['./vitest.setup.ts'],
12
- },
13
- });
package/vitest.setup.ts DELETED
@@ -1 +0,0 @@
1
- import '@testing-library/jest-dom';