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 +15 -0
- package/dist/agent-docs/adoption-report.json +5 -4
- package/dist/agent-docs/components/DataTable.md +3 -0
- package/dist/agent-docs/components/FileUploader.md +7 -1
- package/dist/agent-docs/components-list.md +1 -0
- package/dist/agent-docs/manifest.json +11 -9
- package/dist/agent-docs/truncated-cell.md +342 -0
- package/dist/components/ui/file-uploader.js +86 -78
- package/dist/components/ui/tables/data-table/components/data-table-body.js +123 -115
- package/dist/components/ui/tables/data-table/components/data-table-header.js +6 -5
- package/dist/components/ui/tables/data-table/data-table.js +71 -69
- package/dist/components/ui/tables/data-table/data-table.utils.js +23 -15
- package/dist/components/ui/truncated-cell.js +100 -0
- package/dist/index.d.ts +35 -4
- package/dist/index.js +375 -373
- package/dist/styles.v3.css +1 -1
- package/package.json +1 -1
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-
|
|
3
|
+
"generatedAt": "2026-03-13T13:58:51.406Z",
|
|
4
4
|
"package": {
|
|
5
5
|
"name": "laif-ds",
|
|
6
|
-
"version": "0.2.
|
|
6
|
+
"version": "0.2.76"
|
|
7
7
|
},
|
|
8
8
|
"summary": {
|
|
9
|
-
"scannedFiles":
|
|
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":
|
|
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-
|
|
3
|
+
"generatedAt": "2026-03-13T13:58:51.155Z",
|
|
4
4
|
"package": {
|
|
5
5
|
"name": "laif-ds",
|
|
6
|
-
"version": "0.2.
|
|
6
|
+
"version": "0.2.76"
|
|
7
7
|
},
|
|
8
8
|
"stats": {
|
|
9
9
|
"documentedComponentCount": 91,
|
|
10
|
-
"catalogedComponentCount":
|
|
11
|
-
"missingFromDocsCount":
|
|
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":
|
|
2590
|
+
"totalProps": 23,
|
|
2589
2591
|
"requiredPropsCount": 0,
|
|
2590
|
-
"typedPropsCount":
|
|
2591
|
-
"describedPropsCount":
|
|
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": "
|
|
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
|