@object-ui/plugin-kanban 3.3.0 → 3.3.2

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 (39) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +24 -0
  3. package/dist/{KanbanEnhanced-TdUe0kQH.js → KanbanEnhanced-Do9ZB1Mh.js} +35 -32
  4. package/dist/{KanbanImpl-BtlPa7GE.js → KanbanImpl-BdocXM5T.js} +1 -1
  5. package/dist/{chevron-down-B6UH8BbF.js → chevron-down-C0JUlGjk.js} +1 -1
  6. package/dist/index.js +3 -3
  7. package/dist/index.umd.cjs +2 -2
  8. package/dist/{plus-BTqoaaEC.js → plus-CHsXVJSY.js} +1 -1
  9. package/package.json +34 -11
  10. package/.turbo/turbo-build.log +0 -32
  11. package/src/CardTemplates.tsx +0 -123
  12. package/src/InlineQuickAdd.tsx +0 -189
  13. package/src/KanbanEnhanced.tsx +0 -525
  14. package/src/KanbanImpl.tsx +0 -597
  15. package/src/ObjectKanban.EdgeCases.stories.tsx +0 -168
  16. package/src/ObjectKanban.msw.test.tsx +0 -95
  17. package/src/ObjectKanban.stories.tsx +0 -152
  18. package/src/ObjectKanban.tsx +0 -276
  19. package/src/__tests__/KanbanEnhanced.test.tsx +0 -260
  20. package/src/__tests__/KanbanGrouping.test.tsx +0 -164
  21. package/src/__tests__/KanbanSwimlanes.test.tsx +0 -194
  22. package/src/__tests__/ObjectKanbanTitle.test.tsx +0 -93
  23. package/src/__tests__/SwimlanePersistence.test.tsx +0 -159
  24. package/src/__tests__/accessibility.test.tsx +0 -296
  25. package/src/__tests__/dnd-undo-integration.test.tsx +0 -525
  26. package/src/__tests__/performance-benchmark.test.tsx +0 -306
  27. package/src/__tests__/phase13-features.test.tsx +0 -387
  28. package/src/__tests__/view-states.test.tsx +0 -403
  29. package/src/index.test.ts +0 -112
  30. package/src/index.tsx +0 -327
  31. package/src/registration.test.tsx +0 -26
  32. package/src/types.ts +0 -185
  33. package/src/useColumnWidths.ts +0 -125
  34. package/src/useCrossSwimlaneMove.ts +0 -116
  35. package/src/useQuickAddReorder.ts +0 -107
  36. package/tsconfig.json +0 -19
  37. package/vite.config.ts +0 -62
  38. package/vitest.config.ts +0 -12
  39. package/vitest.setup.ts +0 -1
package/src/index.tsx DELETED
@@ -1,327 +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 React, { Suspense } from 'react';
10
- import { ComponentRegistry } from '@object-ui/core';
11
- import { useSchemaContext } from '@object-ui/react';
12
- import { Skeleton } from '@object-ui/components';
13
- import { ObjectKanban } from './ObjectKanban';
14
-
15
- // Export types for external use
16
- export type { KanbanSchema, KanbanCard, KanbanColumn, CardTemplate, ColumnWidthConfig, InlineFieldDefinition } from './types';
17
- export { ObjectKanban };
18
- export type { ObjectKanbanProps } from './ObjectKanban';
19
-
20
- // Phase 13 L2/L3: New components and hooks
21
- export { InlineQuickAdd } from './InlineQuickAdd';
22
- export type { InlineQuickAddProps } from './InlineQuickAdd';
23
- export { CardTemplates } from './CardTemplates';
24
- export type { CardTemplatesProps } from './CardTemplates';
25
- export { useColumnWidths } from './useColumnWidths';
26
- export type { UseColumnWidthsOptions, UseColumnWidthsReturn } from './useColumnWidths';
27
- export { useCrossSwimlaneMove } from './useCrossSwimlaneMove';
28
- export type { Swimlane, CrossSwimlaneMoveEvent, UseCrossSwimlaneOptions, UseCrossSwimlaneMoveReturn } from './useCrossSwimlaneMove';
29
- export { useQuickAddReorder } from './useQuickAddReorder';
30
- export type { UseQuickAddReorderOptions, UseQuickAddReorderReturn } from './useQuickAddReorder';
31
-
32
- // 🚀 Lazy load the implementation files
33
- const LazyKanban = React.lazy(() => import('./KanbanImpl'));
34
- const LazyKanbanEnhanced = React.lazy(() => import('./KanbanEnhanced'));
35
-
36
- export interface KanbanRendererProps {
37
- schema: {
38
- type: string;
39
- id?: string;
40
- className?: string;
41
- columns?: Array<any>;
42
- data?: Array<any>;
43
- groupBy?: string;
44
- swimlaneField?: string;
45
- onCardMove?: (cardId: string, fromColumnId: string, toColumnId: string, newIndex: number) => void;
46
- onCardClick?: (card: any) => void;
47
- quickAdd?: boolean;
48
- onQuickAdd?: (columnId: string, title: string) => void;
49
- coverImageField?: string;
50
- conditionalFormatting?: Array<{
51
- field: string;
52
- operator: 'equals' | 'not_equals' | 'contains' | 'in';
53
- value: string | string[];
54
- backgroundColor?: string;
55
- borderColor?: string;
56
- }>;
57
- };
58
- }
59
-
60
- /**
61
- * KanbanRenderer - The public API for the kanban board component
62
- * This wrapper handles lazy loading internally using React.Suspense
63
- */
64
- export const KanbanRenderer: React.FC<KanbanRendererProps> = ({ schema }) => {
65
- // ⚡️ Adapter: Map flat 'data' + 'groupBy' to nested 'cards' structure
66
- const processedColumns = React.useMemo(() => {
67
- const { columns = [], data, groupBy, coverImageField } = schema;
68
-
69
- // Helper to map cover image field onto cards
70
- const mapCoverImage = (item: any) => {
71
- if (!coverImageField) return item;
72
- const imgValue = item[coverImageField];
73
- if (!imgValue) return item;
74
- const coverImage = typeof imgValue === 'string' ? imgValue : imgValue?.url;
75
- return coverImage ? { ...item, coverImage } : item;
76
- };
77
-
78
- // If we have flat data and a grouping key, distribute items into columns
79
- if (data && groupBy && Array.isArray(data)) {
80
- // Build label→id mapping so data values (labels like "In Progress")
81
- // match column IDs (option values like "in_progress")
82
- const labelToColumnId: Record<string, string> = {};
83
- columns.forEach((col: any) => {
84
- if (col.id) labelToColumnId[String(col.id).toLowerCase()] = col.id;
85
- if (col.title) labelToColumnId[String(col.title).toLowerCase()] = col.id;
86
- });
87
-
88
- // 1. Group data by key, normalizing via label→id mapping
89
- const groups = data.reduce((acc, item) => {
90
- const rawKey = String(item[groupBy] ?? '');
91
- const key = labelToColumnId[rawKey.toLowerCase()] ?? rawKey;
92
- if (!acc[key]) acc[key] = [];
93
- acc[key].push(mapCoverImage(item));
94
- return acc;
95
- }, {} as Record<string, any[]>);
96
-
97
- // 2. Inject into columns
98
- return columns.map((col: any) => ({
99
- ...col,
100
- cards: [
101
- ...(col.cards || []).map(mapCoverImage), // Preserve static cards
102
- ...(groups[col.id] || []) // Add dynamic cards
103
- ]
104
- }));
105
- }
106
-
107
- // Default: Return columns as-is, mapping cover images
108
- return columns.map((col: any) => ({
109
- ...col,
110
- cards: (col.cards || []).map(mapCoverImage),
111
- }));
112
- }, [schema]);
113
-
114
- return (
115
- <Suspense fallback={<Skeleton className="w-full h-[600px]" />}>
116
- <LazyKanban
117
- columns={processedColumns}
118
- onCardMove={schema.onCardMove}
119
- onCardClick={schema.onCardClick}
120
- className={schema.className}
121
- quickAdd={schema.quickAdd}
122
- onQuickAdd={schema.onQuickAdd}
123
- coverImageField={schema.coverImageField}
124
- conditionalFormatting={schema.conditionalFormatting}
125
- swimlaneField={schema.swimlaneField}
126
- />
127
- </Suspense>
128
- );
129
- };
130
-
131
- // Register the component with the ComponentRegistry
132
- ComponentRegistry.register(
133
- 'kanban-ui',
134
- KanbanRenderer,
135
- {
136
- namespace: 'plugin-kanban',
137
- label: 'Kanban Board',
138
- icon: 'LayoutDashboard',
139
- category: 'plugin',
140
- inputs: [
141
- {
142
- name: 'columns',
143
- type: 'array',
144
- label: 'Columns',
145
- description: 'Array of { id, title, cards, limit, className }',
146
- required: true
147
- },
148
- {
149
- name: 'onCardMove',
150
- type: 'code',
151
- label: 'On Card Move',
152
- description: 'Callback when a card is moved',
153
- advanced: true
154
- },
155
- {
156
- name: 'className',
157
- type: 'string',
158
- label: 'CSS Class'
159
- }
160
- ],
161
- defaultProps: {
162
- columns: [
163
- {
164
- id: 'todo',
165
- title: 'To Do',
166
- cards: [
167
- {
168
- id: 'card-1',
169
- title: 'Task 1',
170
- description: 'This is the first task',
171
- badges: [
172
- { label: 'High Priority', variant: 'destructive' },
173
- { label: 'Feature', variant: 'default' }
174
- ]
175
- },
176
- {
177
- id: 'card-2',
178
- title: 'Task 2',
179
- description: 'This is the second task',
180
- badges: [
181
- { label: 'Bug', variant: 'destructive' }
182
- ]
183
- }
184
- ]
185
- },
186
- {
187
- id: 'in-progress',
188
- title: 'In Progress',
189
- limit: 3,
190
- cards: [
191
- {
192
- id: 'card-3',
193
- title: 'Task 3',
194
- description: 'Currently working on this',
195
- badges: [
196
- { label: 'In Progress', variant: 'default' }
197
- ]
198
- }
199
- ]
200
- },
201
- {
202
- id: 'done',
203
- title: 'Done',
204
- cards: [
205
- {
206
- id: 'card-4',
207
- title: 'Task 4',
208
- description: 'This task is completed',
209
- badges: [
210
- { label: 'Completed', variant: 'outline' }
211
- ]
212
- },
213
- {
214
- id: 'card-5',
215
- title: 'Task 5',
216
- description: 'Another completed task',
217
- badges: [
218
- { label: 'Completed', variant: 'outline' }
219
- ]
220
- }
221
- ]
222
- }
223
- ],
224
- className: 'w-full'
225
- }
226
- }
227
- );
228
-
229
- // Standard Export Protocol - for manual integration
230
- export const kanbanComponents = {
231
- 'kanban': KanbanRenderer,
232
- 'kanban-enhanced': LazyKanbanEnhanced,
233
- 'object-kanban': ObjectKanban,
234
- };
235
-
236
- // Register enhanced Kanban
237
- ComponentRegistry.register(
238
- 'kanban-enhanced',
239
- ({ schema }: { schema: any }) => {
240
- const processedColumns = React.useMemo(() => {
241
- const { columns = [], data, groupBy } = schema;
242
- if (data && groupBy && Array.isArray(data)) {
243
- const groups = data.reduce((acc, item) => {
244
- const key = item[groupBy];
245
- if (!acc[key]) acc[key] = [];
246
- acc[key].push(item);
247
- return acc;
248
- }, {} as Record<string, any[]>);
249
- return columns.map((col: any) => ({
250
- ...col,
251
- cards: [...(col.cards || []), ...(groups[col.id] || [])]
252
- }));
253
- }
254
- return columns;
255
- }, [schema]);
256
-
257
- return (
258
- <Suspense fallback={<Skeleton className="w-full h-[600px]" />}>
259
- <LazyKanbanEnhanced
260
- columns={processedColumns}
261
- onCardMove={schema.onCardMove}
262
- onColumnToggle={schema.onColumnToggle}
263
- enableVirtualScrolling={schema.enableVirtualScrolling}
264
- virtualScrollThreshold={schema.virtualScrollThreshold}
265
- className={schema.className}
266
- quickAdd={schema.quickAdd}
267
- onQuickAdd={schema.onQuickAdd}
268
- conditionalFormatting={schema.conditionalFormatting}
269
- />
270
- </Suspense>
271
- );
272
- },
273
- {
274
- namespace: 'plugin-kanban',
275
- label: 'Kanban Board (Enhanced)',
276
- icon: 'LayoutGrid',
277
- category: 'plugin',
278
- inputs: [
279
- { name: 'columns', type: 'array', label: 'Columns', required: true },
280
- { name: 'enableVirtualScrolling', type: 'boolean', label: 'Virtual Scrolling', defaultValue: false },
281
- { name: 'virtualScrollThreshold', type: 'number', label: 'Virtual Scroll Threshold', defaultValue: 50 },
282
- { name: 'onCardMove', type: 'code', label: 'On Card Move', advanced: true },
283
- { name: 'onColumnToggle', type: 'code', label: 'On Column Toggle', advanced: true },
284
- { name: 'className', type: 'string', label: 'CSS Class' }
285
- ],
286
- defaultProps: {
287
- columns: [],
288
- enableVirtualScrolling: false,
289
- virtualScrollThreshold: 50,
290
- className: 'w-full'
291
- }
292
- }
293
- );
294
-
295
- // Register object-kanban for ListView integration
296
- export const ObjectKanbanRenderer: React.FC<{ schema: any; [key: string]: any }> = ({ schema, ...props }) => {
297
- const { dataSource } = useSchemaContext() || {};
298
- return <ObjectKanban schema={schema} dataSource={dataSource} {...props} />;
299
- };
300
-
301
- ComponentRegistry.register(
302
- 'object-kanban',
303
- ObjectKanbanRenderer,
304
- {
305
- namespace: 'plugin-kanban',
306
- label: 'Object Kanban',
307
- category: 'view',
308
- inputs: [
309
- { name: 'objectName', type: 'string', label: 'Object Name', required: true },
310
- { name: 'columns', type: 'array', label: 'Columns' }
311
- ]
312
- }
313
- );
314
-
315
- ComponentRegistry.register(
316
- 'kanban',
317
- ObjectKanbanRenderer,
318
- {
319
- namespace: 'view',
320
- label: 'Kanban Board',
321
- category: 'view',
322
- inputs: [
323
- { name: 'objectName', type: 'string', label: 'Object Name', required: true },
324
- { name: 'columns', type: 'array', label: 'Columns' }
325
- ]
326
- }
327
- );
@@ -1,26 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { render, screen } from '@testing-library/react';
3
- import React from 'react';
4
- import { ObjectKanbanRenderer } from './index';
5
-
6
- // Mock dependencies
7
- vi.mock('@object-ui/react', () => ({
8
- useSchemaContext: vi.fn(() => ({ dataSource: { type: 'mock-datasource' } })),
9
- }));
10
-
11
- // Mock the implementation
12
- vi.mock('./ObjectKanban', () => ({
13
- ObjectKanban: ({ dataSource }: any) => (
14
- <div data-testid="kanban-mock">
15
- {dataSource ? `DataSource: ${dataSource.type}` : 'No DataSource'}
16
- </div>
17
- )
18
- }));
19
-
20
- describe('Plugin Kanban Registration', () => {
21
- it('renderer passes dataSource from context', () => {
22
-
23
- render(<ObjectKanbanRenderer schema={{ type: 'object-kanban' }} />);
24
- expect(screen.getByTestId('kanban-mock')).toHaveTextContent('DataSource: mock-datasource');
25
- });
26
- });
package/src/types.ts DELETED
@@ -1,185 +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 type { BaseSchema, GroupingConfig } from '@object-ui/types';
10
-
11
- /**
12
- * Kanban card interface.
13
- */
14
- export interface KanbanCard {
15
- id: string;
16
- title: string;
17
- description?: string;
18
- badges?: Array<{ label: string; variant?: "default" | "secondary" | "destructive" | "outline" }>;
19
- [key: string]: any;
20
- }
21
-
22
- /**
23
- * Kanban column interface.
24
- */
25
- export interface KanbanColumn {
26
- id: string;
27
- title: string;
28
- cards: KanbanCard[];
29
- limit?: number;
30
- className?: string;
31
- }
32
-
33
- /**
34
- * Kanban Board component schema.
35
- * Renders a drag-and-drop kanban board for task management.
36
- */
37
- export interface KanbanSchema extends BaseSchema {
38
- type: 'kanban';
39
-
40
- /**
41
- * Object name to fetch data from.
42
- */
43
- objectName?: string;
44
-
45
- /**
46
- * Field to group records by (maps to column IDs).
47
- */
48
- groupBy?: string;
49
-
50
- /**
51
- * Field for swimlane rows (2D grouping). When set, cards are grouped
52
- * vertically by `groupBy` (columns) and horizontally by `swimlaneField` (rows).
53
- */
54
- swimlaneField?: string;
55
-
56
- /**
57
- * Field to use as the card title.
58
- */
59
- cardTitle?: string;
60
-
61
- /**
62
- * Fields to display on the card.
63
- */
64
- cardFields?: string[];
65
-
66
- /**
67
- * Static data or bound data.
68
- */
69
- data?: any[];
70
-
71
- /**
72
- * Array of columns to display in the kanban board.
73
- * Each column contains an array of cards.
74
- */
75
- columns?: KanbanColumn[];
76
-
77
- /**
78
- * Callback function when a card is moved between columns or reordered.
79
- */
80
- onCardMove?: (cardId: string, fromColumnId: string, toColumnId: string, newIndex: number) => void;
81
-
82
- /**
83
- * Optional CSS class name to apply custom styling.
84
- */
85
- className?: string;
86
-
87
- /**
88
- * Enable Quick Add button at the bottom of each column.
89
- * When true, a "+" button appears allowing inline card creation.
90
- * @default false
91
- */
92
- quickAdd?: boolean;
93
-
94
- /**
95
- * Callback when a new card is created via Quick Add.
96
- */
97
- onQuickAdd?: (columnId: string, title: string) => void;
98
-
99
- /**
100
- * Field name to use as cover image on cards.
101
- * The field value should be a URL string or file object with a `url` property.
102
- */
103
- coverImageField?: string;
104
-
105
- /**
106
- * Allow columns to be collapsed/expanded.
107
- * @default false
108
- */
109
- allowCollapse?: boolean;
110
-
111
- /**
112
- * Conditional formatting rules for card coloring.
113
- */
114
- conditionalFormatting?: Array<{
115
- field: string;
116
- operator: 'equals' | 'not_equals' | 'contains' | 'in';
117
- value: string | string[];
118
- backgroundColor?: string;
119
- borderColor?: string;
120
- }>;
121
-
122
- /**
123
- * Predefined card templates for quick-add.
124
- * Each template pre-fills the quick-add form with default values.
125
- */
126
- cardTemplates?: CardTemplate[];
127
-
128
- /**
129
- * Custom column width configuration.
130
- * Supports per-column overrides with min/max constraints.
131
- */
132
- columnWidths?: ColumnWidthConfig;
133
-
134
- /**
135
- * Grouping configuration from ListView.
136
- * When set, the first grouping field is used as swimlaneField fallback.
137
- */
138
- grouping?: GroupingConfig;
139
- }
140
-
141
- /**
142
- * A predefined card template with pre-filled field values.
143
- */
144
- export interface CardTemplate {
145
- /** Unique template identifier */
146
- id: string;
147
- /** Human-readable template name */
148
- name: string;
149
- /** Optional Lucide icon name */
150
- icon?: string;
151
- /** Pre-filled field values */
152
- values: Record<string, any>;
153
- }
154
-
155
- /**
156
- * Configuration for custom column widths.
157
- */
158
- export interface ColumnWidthConfig {
159
- /** Default column width in pixels */
160
- defaultWidth?: number;
161
- /** Minimum column width in pixels */
162
- minWidth?: number;
163
- /** Maximum column width in pixels */
164
- maxWidth?: number;
165
- /** Per-column width overrides keyed by column ID */
166
- overrides?: Record<string, number>;
167
- }
168
-
169
- /**
170
- * Field definition for inline quick-add forms.
171
- */
172
- export interface InlineFieldDefinition {
173
- /** Field name (key in the resulting values object) */
174
- name: string;
175
- /** Display label */
176
- label?: string;
177
- /** Field type */
178
- type: 'text' | 'number' | 'select';
179
- /** Placeholder text */
180
- placeholder?: string;
181
- /** Default value */
182
- defaultValue?: any;
183
- /** Options for select fields */
184
- options?: Array<{ label: string; value: string }>;
185
- }
@@ -1,125 +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 { useState, useCallback, useMemo } from "react"
10
- import type { KanbanColumn, ColumnWidthConfig } from "./types"
11
-
12
- const STORAGE_KEY = "objectui:kanban-column-widths"
13
-
14
- export interface UseColumnWidthsOptions {
15
- /** Columns on the board */
16
- columns: KanbanColumn[]
17
- /** Default width in pixels applied to every column */
18
- defaultWidth?: number
19
- /** Minimum allowed column width in pixels */
20
- minWidth?: number
21
- /** Maximum allowed column width in pixels */
22
- maxWidth?: number
23
- /** Optional persistence key suffix (to scope per-board) */
24
- storageKey?: string
25
- }
26
-
27
- export interface UseColumnWidthsReturn {
28
- /** Get the current width for a column (in px) */
29
- getColumnWidth: (columnId: string) => number
30
- /** Set an override width for a column */
31
- setColumnWidth: (columnId: string, width: number) => void
32
- /** Reset all overrides back to default widths */
33
- resetWidths: () => void
34
- /** The full config (useful for serialization) */
35
- config: ColumnWidthConfig
36
- }
37
-
38
- function loadPersistedWidths(key: string): Record<string, number> {
39
- try {
40
- const raw = localStorage.getItem(key)
41
- if (raw) {
42
- const parsed = JSON.parse(raw)
43
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
44
- return parsed as Record<string, number>
45
- }
46
- }
47
- } catch {
48
- /* ignore corrupt data */
49
- }
50
- return {}
51
- }
52
-
53
- function persistWidths(key: string, overrides: Record<string, number>) {
54
- try {
55
- localStorage.setItem(key, JSON.stringify(overrides))
56
- } catch {
57
- /* quota exceeded */
58
- }
59
- }
60
-
61
- /**
62
- * Hook for managing custom per-column widths with localStorage persistence.
63
- * Supports per-column overrides clamped between minWidth and maxWidth.
64
- */
65
- export function useColumnWidths({
66
- columns: _columns,
67
- defaultWidth = 320,
68
- minWidth = 200,
69
- maxWidth = 600,
70
- storageKey,
71
- }: UseColumnWidthsOptions): UseColumnWidthsReturn {
72
- const fullKey = storageKey ? `${STORAGE_KEY}:${storageKey}` : STORAGE_KEY
73
-
74
- const [overrides, setOverrides] = useState<Record<string, number>>(() =>
75
- loadPersistedWidths(fullKey),
76
- )
77
-
78
- const clamp = useCallback(
79
- (value: number) => Math.max(minWidth, Math.min(maxWidth, value)),
80
- [minWidth, maxWidth],
81
- )
82
-
83
- const getColumnWidth = useCallback(
84
- (columnId: string): number => {
85
- const override = overrides[columnId]
86
- return override != null ? clamp(override) : defaultWidth
87
- },
88
- [overrides, defaultWidth, clamp],
89
- )
90
-
91
- const setColumnWidth = useCallback(
92
- (columnId: string, width: number) => {
93
- const clamped = clamp(width)
94
- setOverrides(prev => {
95
- const next = { ...prev, [columnId]: clamped }
96
- persistWidths(fullKey, next)
97
- return next
98
- })
99
- },
100
- [clamp, fullKey],
101
- )
102
-
103
- const resetWidths = useCallback(() => {
104
- setOverrides({})
105
- try {
106
- localStorage.removeItem(fullKey)
107
- } catch {
108
- /* ignore */
109
- }
110
- }, [fullKey])
111
-
112
- const config: ColumnWidthConfig = useMemo(
113
- () => ({
114
- defaultWidth,
115
- minWidth,
116
- maxWidth,
117
- overrides: { ...overrides },
118
- }),
119
- [defaultWidth, minWidth, maxWidth, overrides],
120
- )
121
-
122
- return { getColumnWidth, setColumnWidth, resetWidths, config }
123
- }
124
-
125
- export default useColumnWidths