laif-ds 0.2.75 → 0.2.76

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/dist/CHANGELOG.md CHANGED
@@ -5,8 +5,23 @@ All notable technical changes to the laif-ds core will be documented in this fil
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [laif-ds@0.2.76]
9
+
10
+ ### 🚀 Added
11
+
12
+ - **FileUploader**: Added support for archive file types including `zip`, `rar`, `7z`, `tar`, `gz`, and `tgz`
13
+ - **TruncatedCell**: Added a new component for displaying truncated text content with tooltip expansion and responsive text handling
14
+ - **DataTable**: Added `rowClassName` prop for custom CSS classes based on row data
15
+ - **DataTable**: Added `headerClassName` and `cellClassName` support in column meta for custom styling
16
+ - **DataTable**: Enhanced utils typing with mapped union for better accessor config type inference
17
+
8
18
  ## [laif-ds@0.2.75]
9
19
 
20
+ ### ⚠️ Breaking changes
21
+
22
+ - **DataTable**: the cell value type is now defined better so some small compatibility issues my emerge with strict typing in precedent versions
23
+ - **general**: Since the introduction of strict EsLint in the repository a big number of components has got updated, some small bugs may emerge
24
+
10
25
  ### 🚀 Added
11
26
 
12
27
  - **Storybook**: Added a dedicated changelog documentation page with markdown rendering and release-oriented navigation
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-03-09T16:04:40.003Z",
3
+ "generatedAt": "2026-03-13T13:58:51.406Z",
4
4
  "package": {
5
5
  "name": "laif-ds",
6
- "version": "0.2.75"
6
+ "version": "0.2.76"
7
7
  },
8
8
  "summary": {
9
- "scannedFiles": 387,
9
+ "scannedFiles": 390,
10
10
  "deprecatedComponentsCount": 2,
11
11
  "deprecatedComponentsUsedCount": 0,
12
12
  "componentsWithoutExamplesCount": 5,
@@ -358,7 +358,7 @@
358
358
  "repeatedClassNames": [
359
359
  {
360
360
  "className": "flex items-center gap-2",
361
- "occurrences": 34,
361
+ "occurrences": 36,
362
362
  "files": [
363
363
  "src/components/stories/app-checkbox.stories.tsx",
364
364
  "src/components/stories/app-dialog.stories.tsx",
@@ -371,6 +371,7 @@
371
371
  "src/components/stories/data-table-no-utils-example.stories.tsx",
372
372
  "src/components/stories/data-table-utils-example.stories.tsx",
373
373
  "src/components/stories/playground.stories.tsx",
374
+ "src/components/stories/truncated-cell.stories.tsx",
374
375
  "src/components/ui/app-form.tsx",
375
376
  "src/components/ui/app-kanban.tsx",
376
377
  "src/components/ui/app-sidebar.tsx",
@@ -32,6 +32,7 @@ Powerful table built on TanStack Table v8. Supports client-side and server-side
32
32
  | `disableAutoPageSize` | `boolean` | `false` | Disable auto pageSize (still updates pageIndex). |
33
33
  | `id` | `string` | `undefined` | Test/accessibility hook for the root element. |
34
34
  | `data-testid` | `string` | `undefined` | Test identifier forwarded to the root element. |
35
+ | `rowClassName` | `string \| ((row) => string)` | `undefined` | Add custom CSS classes to table rows based on row data or state. |
35
36
 
36
37
  ---
37
38
 
@@ -56,6 +57,8 @@ type ColumnMeta = {
56
57
  searchable?: boolean;
57
58
  pinned?: "left" | "right";
58
59
  listOptions?: { value: string; label: string }[];
60
+ cellClassName?: string | ((value: any, row: TData) => string);
61
+ headerClassName?: string;
59
62
  };
60
63
  ```
61
64
 
@@ -20,7 +20,7 @@ Drag-and-drop uploader with keyboard activation, file type filtering, limits (co
20
20
  | `maxTotalSize` | `number` (bytes) | `undefined` | Maximum total size of selected files. |
21
21
  | `maxFiles` | `number` | `undefined` | Maximum number of files (when `multiple` is true). |
22
22
 
23
- `AcceptItem` includes: `pdf | doc | docx | xls | xlsx | ppt | pptx | txt | csv | jpg | jpeg | png | gif | image | video | audio`.
23
+ `AcceptItem` includes: `pdf | doc | docx | xls | xlsx | ppt | pptx | txt | csv | jpg | jpeg | png | gif | image | video | audio | zip | rar | 7z | tar | gz | tgz`.
24
24
 
25
25
  ---
26
26
 
@@ -68,6 +68,12 @@ const exts: AcceptItem[] = [
68
68
  "image",
69
69
  "video",
70
70
  "audio",
71
+ "zip",
72
+ "rar",
73
+ "7z",
74
+ "tar",
75
+ "gz",
76
+ "tgz",
71
77
  ];
72
78
 
73
79
  export function MultiUploader() {
@@ -85,6 +85,7 @@ This document provides a complete mapping of all components available in the lai
85
85
  - **Pagination** - Page navigation component for paginated content
86
86
  - **Table** - Basic table component with styling
87
87
  - **TableSkeleton** - Loading skeleton for table components
88
+ - **TruncatedCell** - Text display component with automatic truncation detection and popover preview
88
89
  - **Typo** - Typography component for consistent text styling
89
90
 
90
91
  ### Content & Media Components
@@ -1,20 +1,22 @@
1
1
  {
2
2
  "schemaVersion": "1.1.0",
3
- "generatedAt": "2026-03-09T16:04:39.745Z",
3
+ "generatedAt": "2026-03-13T13:58:51.155Z",
4
4
  "package": {
5
5
  "name": "laif-ds",
6
- "version": "0.2.75"
6
+ "version": "0.2.76"
7
7
  },
8
8
  "stats": {
9
9
  "documentedComponentCount": 91,
10
- "catalogedComponentCount": 90,
11
- "missingFromDocsCount": 0,
10
+ "catalogedComponentCount": 91,
11
+ "missingFromDocsCount": 1,
12
12
  "deprecatedComponentCount": 2,
13
13
  "averageAiReadinessScore": 54.23,
14
14
  "highAiReadinessCount": 35,
15
15
  "lowAiReadinessCount": 42
16
16
  },
17
- "missingFromDocs": [],
17
+ "missingFromDocs": [
18
+ "TruncatedCell"
19
+ ],
18
20
  "components": [
19
21
  {
20
22
  "name": "Accordion",
@@ -2585,10 +2587,10 @@
2585
2587
  },
2586
2588
  "metadata": {
2587
2589
  "props": {
2588
- "totalProps": 22,
2590
+ "totalProps": 23,
2589
2591
  "requiredPropsCount": 0,
2590
- "typedPropsCount": 22,
2591
- "describedPropsCount": 22
2592
+ "typedPropsCount": 23,
2593
+ "describedPropsCount": 23
2592
2594
  },
2593
2595
  "accessibility": {
2594
2596
  "hasCoverage": true
@@ -5975,5 +5977,5 @@
5975
5977
  ]
5976
5978
  }
5977
5979
  ],
5978
- "checksum": "10e072f1a2d3f682aff594d6c5319ff53034c93de21a31cb6a1b3c2c3407fbd4"
5980
+ "checksum": "49d7886a951266036bed08eafc023f23f4363c035bbc722af5d0b7b2415862cd"
5979
5981
  }
@@ -0,0 +1,342 @@
1
+ # TruncatedCell
2
+
3
+ The TruncatedCell component is designed to display text that may be too long for its container. It automatically detects when text is truncated and provides a popover to show the full content.
4
+
5
+ ## Features
6
+
7
+ - **Flexible Content**: Accepts plain text or rich ReactNode content
8
+ - **Automatic Truncation Detection**: Uses scrollWidth vs clientWidth comparison to detect if content is truncated
9
+ - **Responsive**: Re-checks truncation on resize using ResizeObserver for better performance
10
+ - **Controlled Popover**: Manages popover state programmatically for better UX
11
+ - **Eye Icon Hint**: Displays an eye icon hint only when content is truncated, with smooth fade-in animation
12
+ - **Button Visibility Control**: Optional `showButton` prop to control eye button visibility
13
+ - **Custom Popover Styling**: `popoverClassName` prop for custom popover content styling
14
+ - **Keyboard Accessibility**: Full keyboard navigation support (Enter/Space to open popover)
15
+ - **Screen Reader Support**: Proper ARIA labels and roles for accessibility
16
+ - **Empty State**: Shows "-" with muted styling when no content is provided
17
+ - **Custom Empty Fallback**: Supports a custom placeholder for empty values
18
+ - **Customizable Styling**: Supports custom CSS classes for container, cell, and popover
19
+ - **Dialog Title**: Optional title for the popover header
20
+ - **Custom Content**: Full JSX support for custom popover content
21
+ - **Hover Effects**: Smooth underline on content hover and button appearance
22
+ - **Scrollable Content**: Long content in popover is scrollable with max height
23
+ - **DX-first API**: Rich children work out of the box, and `text` is only needed when you want explicit popover/accessibility text
24
+
25
+ ## Usage
26
+
27
+ ```tsx
28
+ import { TruncatedCell } from "laif-ds";
29
+
30
+ // Basic usage with string content
31
+ <TruncatedCell text="Short text" />
32
+
33
+ // Long text that will be truncated
34
+ <TruncatedCell
35
+ text="This is a very long text that will be truncated because it exceeds the container width"
36
+ wrapperClassName="w-56"
37
+ />
38
+
39
+ // String children also work without text
40
+ <TruncatedCell wrapperClassName="w-56">
41
+ This is a string content
42
+ </TruncatedCell>
43
+
44
+ // Rich content works without duplicating text
45
+ <TruncatedCell wrapperClassName="w-56">
46
+ <div className="flex items-center gap-2">
47
+ <Avatar src="/avatar.jpg" />
48
+ <div className="min-w-0">
49
+ <p className="font-semibold">John Doe</p>
50
+ <p className="text-sm text-gray-600">john@example.com</p>
51
+ </div>
52
+ </div>
53
+ </TruncatedCell>
54
+
55
+ // Provide text when you want explicit popover or accessibility content
56
+ <TruncatedCell
57
+ text="John Doe - john@example.com"
58
+ title="User details"
59
+ wrapperClassName="w-56"
60
+ >
61
+ <UserSummary />
62
+ </TruncatedCell>
63
+
64
+ // With custom styling and title
65
+ <TruncatedCell
66
+ text="Custom styled truncated text"
67
+ title="Full Content"
68
+ wrapperClassName="w-40"
69
+ className="max-w-40"
70
+ />
71
+
72
+ // With custom popover content and styling
73
+ <TruncatedCell
74
+ text="Text with custom popover content"
75
+ title="Custom Content"
76
+ popoverContent={
77
+ <div className="space-y-3">
78
+ <p>Custom JSX content here</p>
79
+ <button>Action Button</button>
80
+ </div>
81
+ }
82
+ popoverClassName="max-w-md"
83
+ showButton={true}
84
+ />
85
+
86
+ // Hide the eye hint
87
+ <TruncatedCell
88
+ text="Text without eye button"
89
+ showButton={false}
90
+ />
91
+
92
+ // Empty text
93
+ <TruncatedCell text="" />
94
+
95
+ // Custom empty fallback
96
+ <TruncatedCell text="" emptyFallback="No value" />
97
+ ```
98
+
99
+ ## Props
100
+
101
+ | Prop | Type | Default | Description |
102
+ | ------------------ | ----------- | ----------- | ---------------------------------------------------------------------------- |
103
+ | `children` | `ReactNode` | `undefined` | Content to display |
104
+ | `text` | `string` | `undefined` | Optional text used for truncation detection, accessibility, and popover copy |
105
+ | `title` | `string` | `undefined` | Optional title for the popover dialog |
106
+ | `popoverContent` | `ReactNode` | `undefined` | Custom popover content (JSX) |
107
+ | `wrapperClassName` | `string` | `""` | Preferred CSS classes for the wrapper container |
108
+ | `className` | `string` | `""` | CSS classes for the cell content |
109
+ | `popoverClassName` | `string` | `""` | CSS classes for the popover content |
110
+ | `showButton` | `boolean` | `true` | Flag used to show/hide the eye hint |
111
+ | `emptyFallback` | `ReactNode` | `"-"` | Custom placeholder rendered when no content is available |
112
+
113
+ ## Behavior
114
+
115
+ ### Truncation Detection
116
+
117
+ - Component monitors the text element's scrollWidth vs clientWidth
118
+ - If scrollWidth > clientWidth, the text is considered truncated
119
+ - Detection runs on mount and on resize
120
+ - When `text` is not provided, the component also extracts `textContent` from the rendered node to power the default popover content
121
+
122
+ ### Visual States
123
+
124
+ 1. **Normal State**: Text is displayed with truncation (CSS `truncate`)
125
+ 2. **Truncated State**: Text is truncated + eye icon hint appears
126
+ 3. **Empty State**: Shows "-" when text is empty/undefined
127
+ 4. **Popover State**: Opens when there is content to inspect, and the eye icon hint appears only when the rendered value is truncated
128
+
129
+ ### Styling
130
+
131
+ - Container: `flex max-w-60 gap-2` + custom classes
132
+ - Text container: `flex min-w-0 flex-1`
133
+ - Text element: `w-full min-w-0 truncate whitespace-nowrap`
134
+ - Popover: `w-96` with `whitespace-pre-wrap` for multiline support
135
+
136
+ ### Content Types
137
+
138
+ The TruncatedCell component supports two main usage patterns:
139
+
140
+ #### 1. String Content (Simple)
141
+
142
+ ```tsx
143
+ // Direct text prop
144
+ <TruncatedCell text="Simple text content" />
145
+
146
+ // String children (text prop optional)
147
+ <TruncatedCell wrapperClassName="w-56">
148
+ String content as children
149
+ </TruncatedCell>
150
+ ```
151
+
152
+ #### 2. ReactNode Content (Advanced)
153
+
154
+ ```tsx
155
+ // Rich children work without text
156
+ <TruncatedCell wrapperClassName="w-56">
157
+ <div className="flex items-center gap-2">
158
+ <Avatar src="/avatar.jpg" />
159
+ <div className="min-w-0">
160
+ <p className="font-semibold">John Doe</p>
161
+ <p className="text-sm text-gray-600">john@example.com</p>
162
+ </div>
163
+ </div>
164
+ </TruncatedCell>
165
+
166
+ // Add text when you want explicit popover content
167
+ <TruncatedCell text="User profile - John Doe" wrapperClassName="w-56">
168
+ <UserSummary />
169
+ </TruncatedCell>
170
+ ```
171
+
172
+ ### Choosing Between `children` and `text`
173
+
174
+ - Use `text` for the simplest plain-text case
175
+ - Use `children` when you need custom rendering inside the truncated area
176
+ - Add `text` together with `children` when the rendered content is visual or abbreviated and you want more descriptive text in the popover
177
+
178
+ ```tsx
179
+ // Plain text
180
+ <TruncatedCell text="Contract pending signature" />
181
+
182
+ // Rich UI with automatic text extraction
183
+ <TruncatedCell wrapperClassName="w-56">
184
+ <div>Complex content</div>
185
+ </TruncatedCell>
186
+
187
+ // Rich UI with explicit popover and a11y text
188
+ <TruncatedCell text="Complex content description" wrapperClassName="w-56">
189
+ <div>Complex content</div>
190
+ </TruncatedCell>
191
+ ```
192
+
193
+ ### Custom Popover Content
194
+
195
+ The `popoverContent` prop allows you to override the default text display with custom JSX content:
196
+
197
+ - **Full Flexibility**: Any React components can be used as popover content
198
+ - **Backward Compatible**: When not provided, defaults to displaying the text with Typo component
199
+ - **Title Support**: Works seamlessly with the `title` prop for popover headers
200
+ - **Custom Styling**: Use `popoverClassName` to style the popover container
201
+ - **Button Control**: Use `showButton` to control eye hint visibility
202
+ - **Open Behavior**: Custom popover content can open even when the displayed value itself is not truncated
203
+
204
+ ```tsx
205
+ <TruncatedCell
206
+ text="User profile"
207
+ title="User Details"
208
+ popoverContent={
209
+ <div className="space-y-2">
210
+ <div className="flex items-center gap-2">
211
+ <Avatar src="/avatar.jpg" />
212
+ <div>
213
+ <p className="font-semibold">John Doe</p>
214
+ <p className="text-sm text-gray-600">john@example.com</p>
215
+ </div>
216
+ </div>
217
+ <div className="flex gap-2">
218
+ <Button size="sm">Edit</Button>
219
+ <Button size="sm" variant="outline">
220
+ View Profile
221
+ </Button>
222
+ </div>
223
+ </div>
224
+ }
225
+ popoverClassName="max-w-md"
226
+ showButton={true}
227
+ />
228
+ ```
229
+
230
+ ### Button Visibility Control
231
+
232
+ The `showButton` prop gives you control over the eye hint visibility:
233
+
234
+ ```tsx
235
+ // Show eye hint (default)
236
+ <TruncatedCell text="Long text that will be truncated" showButton={true} />
237
+
238
+ // Hide eye hint
239
+ <TruncatedCell text="Long text without eye hint" showButton={false} />
240
+ ```
241
+
242
+ ### Empty Fallback
243
+
244
+ ```tsx
245
+ // Default placeholder
246
+ <TruncatedCell text="" />
247
+
248
+ // Custom placeholder
249
+ <TruncatedCell text="" emptyFallback="No value" />
250
+ ```
251
+
252
+ ### Popover Styling
253
+
254
+ The `popoverClassName` prop allows custom styling of the popover container:
255
+
256
+ ```tsx
257
+ <TruncatedCell
258
+ text="Custom styled popover"
259
+ popoverClassName="max-w-md bg-blue-50 border-blue-200"
260
+ />
261
+ ```
262
+
263
+ ## Technical Details
264
+
265
+ ### Dependencies
266
+
267
+ - React hooks: `useState`, `useEffect`, `useRef`, `useCallback`
268
+ - Laif-DS components: `Popover`, `PopoverContent`, `PopoverTrigger`, `Typo`, `Icon`
269
+ - Utility: `cn` for class merging
270
+
271
+ ### Performance Optimizations
272
+
273
+ - **ResizeObserver**: Uses modern ResizeObserver API for better performance than window resize events
274
+ - **useCallback**: Memoizes truncation check function to prevent unnecessary re-renders
275
+ - **Controlled State**: Manages popover state programmatically to avoid prop drilling
276
+ - **Cleanup**: Proper cleanup of observers and event listeners
277
+ - **Optimized Re-renders**: Only re-checks truncation when content changes
278
+
279
+ ### Event Handling
280
+
281
+ - ResizeObserver for element-specific resize detection
282
+ - Fallback window resize listener for older browsers
283
+ - Click on the cell trigger opens the popover when available
284
+ - Keyboard support (Enter/Space keys)
285
+ - Hover effects with smooth transitions
286
+
287
+ ### Accessibility Features
288
+
289
+ - **Semantic Trigger**: Uses a real `button` element as the interactive trigger
290
+ - **Keyboard Navigation**: Full support for Enter and Space keys
291
+ - **Screen Reader Labels**: Dynamic `aria-label` based on truncation state
292
+ - **Focus Management**: Native button focus behavior
293
+ - **Semantic HTML**: Popover content remains accessible even for multiline values
294
+
295
+ ## Accessibility
296
+
297
+ - Text container has cursor pointer to indicate interactivity
298
+ - Hover state provides visual feedback
299
+ - Popover provides full text access for screen readers
300
+ - Eye icon provides a clear visual hint that more content is available
301
+
302
+ ## Examples
303
+
304
+ ### In a Table Cell
305
+
306
+ ```tsx
307
+ const TableCell = ({ value }: { value: string }) => (
308
+ <TruncatedCell text={value} wrapperClassName="w-56" className="py-2" />
309
+ );
310
+ ```
311
+
312
+ ### With Maximum Width Constraint
313
+
314
+ ```tsx
315
+ <TruncatedCell
316
+ text="Constrained width text that will truncate"
317
+ wrapperClassName="w-32"
318
+ />
319
+ ```
320
+
321
+ ### Multiline Text Support
322
+
323
+ ```tsx
324
+ <TruncatedCell text="Line 1\nLine 2\nLine 3" className="max-w-48" />
325
+ ```
326
+
327
+ ## Comparison with Alternatives
328
+
329
+ ### vs Tooltip
330
+
331
+ - **TruncatedCell**: Supports click-to-inspect content, and visually hints with the eye icon when text is actually truncated
332
+ - **Tooltip**: Always shows on hover regardless of truncation
333
+
334
+ ### vs CSS text-overflow alone
335
+
336
+ - **TruncatedCell**: Provides access to full content
337
+ - **CSS only**: Content is inaccessible when truncated
338
+
339
+ ### vs Expandable Text
340
+
341
+ - **TruncatedCell**: Compact, popover-based approach
342
+ - **Expandable**: Takes more space, inline expansion