laif-ds 0.2.75 → 0.2.77

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,35 @@ 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.77]
9
+
10
+ ### 🚀 Added
11
+
12
+ - **AppCard**: Added new card wrapper component with 4 visual variants (default, elevated, outlined, ghost), support for title, description, body, footer, and actions props with optional header and footer borders, and comprehensive Storybook examples and documentation
13
+ - **AppForm**: Added column span sizing, configurable icon placement, enhanced search options, and comprehensive TypeScript typing improvements
14
+
15
+ ### 🔧 Changed
16
+
17
+ - **AppForm**: Updated to adopt new form pattern with improved layout, enhanced JSDoc comments, and better type safety across components
18
+ - **General**: Removed "use client" directives and fixed export formatting across components for better compatibility
19
+
20
+ ## [laif-ds@0.2.76]
21
+
22
+ ### 🚀 Added
23
+
24
+ - **FileUploader**: Added support for archive file types including `zip`, `rar`, `7z`, `tar`, `gz`, and `tgz`
25
+ - **TruncatedCell**: Added a new component for displaying truncated text content with tooltip expansion and responsive text handling
26
+ - **DataTable**: Added `rowClassName` prop for custom CSS classes based on row data
27
+ - **DataTable**: Added `headerClassName` and `cellClassName` support in column meta for custom styling
28
+ - **DataTable**: Enhanced utils typing with mapped union for better accessor config type inference
29
+
8
30
  ## [laif-ds@0.2.75]
9
31
 
32
+ ### ⚠️ Breaking changes
33
+
34
+ - **DataTable**: the cell value type is now defined better so some small compatibility issues my emerge with strict typing in precedent versions
35
+ - **general**: Since the introduction of strict EsLint in the repository a big number of components has got updated, some small bugs may emerge
36
+
10
37
  ### 🚀 Added
11
38
 
12
39
  - **Storybook**: Added a dedicated changelog documentation page with markdown rendering and release-oriented navigation
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- var e = {};
2
+ var e = { exports: {} };
3
3
  export {
4
- e as __exports
4
+ e as __module
5
5
  };
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- var e = { exports: {} };
2
+ var e = {};
3
3
  export {
4
- e as __module
4
+ e as __exports
5
5
  };
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-03-09T16:04:40.003Z",
3
+ "generatedAt": "2026-03-24T15:46:53.964Z",
4
4
  "package": {
5
5
  "name": "laif-ds",
6
- "version": "0.2.75"
6
+ "version": "0.2.77"
7
7
  },
8
8
  "summary": {
9
- "scannedFiles": 387,
9
+ "scannedFiles": 393,
10
10
  "deprecatedComponentsCount": 2,
11
11
  "deprecatedComponentsUsedCount": 0,
12
12
  "componentsWithoutExamplesCount": 5,
@@ -15,7 +15,7 @@
15
15
  "lowAiReadinessComponentsCount": 42,
16
16
  "componentsWithoutAccessibilityCoverageCount": 46,
17
17
  "componentsWithWeakStateCoverageCount": 73,
18
- "averageAiReadinessScore": 54.23
18
+ "averageAiReadinessScore": 54.73
19
19
  },
20
20
  "deprecatedUsage": [],
21
21
  "documentationGaps": {
@@ -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",
@@ -380,7 +381,7 @@
380
381
  },
381
382
  {
382
383
  "className": "text-muted-foreground text-sm",
383
- "occurrences": 25,
384
+ "occurrences": 28,
384
385
  "files": [
385
386
  "src/components/stories/app-form.stories.tsx",
386
387
  "src/components/stories/app-stepper.stories.tsx",
@@ -396,6 +397,20 @@
396
397
  "src/components/ui/tables/data-table/components/data-table-filter-inputs.tsx"
397
398
  ]
398
399
  },
400
+ {
401
+ "className": "text-d-muted-foreground text-sm",
402
+ "occurrences": 26,
403
+ "files": [
404
+ "src/components/stories/app-card.stories.tsx",
405
+ "src/components/stories/app-dialog.stories.tsx",
406
+ "src/components/stories/app-kanban.stories.tsx",
407
+ "src/components/stories/changelog.stories.tsx",
408
+ "src/components/stories/date-picker.stories.tsx",
409
+ "src/components/stories/input.stories.tsx",
410
+ "src/components/stories/toaster.stories.tsx",
411
+ "src/components/ui/secure-pdf-viewer.tsx"
412
+ ]
413
+ },
399
414
  {
400
415
  "className": "bg-muted rounded-md p-4",
401
416
  "occurrences": 20,
@@ -406,16 +421,17 @@
406
421
  ]
407
422
  },
408
423
  {
409
- "className": "text-d-muted-foreground text-sm",
424
+ "className": "flex items-center justify-between",
410
425
  "occurrences": 19,
411
426
  "files": [
412
- "src/components/stories/app-dialog.stories.tsx",
413
- "src/components/stories/app-kanban.stories.tsx",
414
- "src/components/stories/changelog.stories.tsx",
415
- "src/components/stories/date-picker.stories.tsx",
416
- "src/components/stories/input.stories.tsx",
417
- "src/components/stories/toaster.stories.tsx",
418
- "src/components/ui/secure-pdf-viewer.tsx"
427
+ "src/components/stories/app-card.stories.tsx",
428
+ "src/components/stories/data-table-utils-example.stories.tsx",
429
+ "src/components/stories/sidebar.stories.tsx",
430
+ "src/components/stories/switch.stories.tsx",
431
+ "src/components/ui/app-form.tsx",
432
+ "src/components/ui/tables/data-cross-table/cell-editor-dialog.tsx",
433
+ "src/components/ui/tables/data-cross-table/data-cross-table.tsx",
434
+ "src/components/ui/tables/data-cross-table/editable-input.tsx"
419
435
  ]
420
436
  },
421
437
  {
@@ -437,16 +453,10 @@
437
453
  ]
438
454
  },
439
455
  {
440
- "className": "flex items-center justify-between",
441
- "occurrences": 15,
456
+ "className": "border-d-border bg-d-muted rounded-lg border p-4",
457
+ "occurrences": 14,
442
458
  "files": [
443
- "src/components/stories/data-table-utils-example.stories.tsx",
444
- "src/components/stories/sidebar.stories.tsx",
445
- "src/components/stories/switch.stories.tsx",
446
- "src/components/ui/app-form.tsx",
447
- "src/components/ui/tables/data-cross-table/cell-editor-dialog.tsx",
448
- "src/components/ui/tables/data-cross-table/data-cross-table.tsx",
449
- "src/components/ui/tables/data-cross-table/editable-input.tsx"
459
+ "src/components/stories/app-form.stories.tsx"
450
460
  ]
451
461
  },
452
462
  {
@@ -456,13 +466,6 @@
456
466
  "src/components/stories/tabs.stories.tsx"
457
467
  ]
458
468
  },
459
- {
460
- "className": "border-d-border bg-d-muted rounded-lg border p-4",
461
- "occurrences": 11,
462
- "files": [
463
- "src/components/stories/app-form.stories.tsx"
464
- ]
465
- },
466
469
  {
467
470
  "className": "flex w-[550px] flex-col gap-6",
468
471
  "occurrences": 10,
@@ -478,6 +481,16 @@
478
481
  "src/components/stories/tabs.stories.tsx"
479
482
  ]
480
483
  },
484
+ {
485
+ "className": "flex flex-col items-center gap-4",
486
+ "occurrences": 8,
487
+ "files": [
488
+ "src/components/stories/app-card.stories.tsx",
489
+ "src/components/stories/confirmer.stories.tsx",
490
+ "src/components/stories/input-selector.stories.tsx",
491
+ "src/components/stories/theme-switcher.stories.tsx"
492
+ ]
493
+ },
481
494
  {
482
495
  "className": "text-d-muted-foreground",
483
496
  "occurrences": 8,
@@ -523,15 +536,6 @@
523
536
  "src/components/stories/button.stories.tsx"
524
537
  ]
525
538
  },
526
- {
527
- "className": "flex flex-col items-center gap-4",
528
- "occurrences": 7,
529
- "files": [
530
- "src/components/stories/confirmer.stories.tsx",
531
- "src/components/stories/input-selector.stories.tsx",
532
- "src/components/stories/theme-switcher.stories.tsx"
533
- ]
534
- },
535
539
  {
536
540
  "className": "flex flex-col items-center gap-2",
537
541
  "occurrences": 7,
@@ -0,0 +1,308 @@
1
+ # AppCard
2
+
3
+ ## Overview
4
+
5
+ Enhanced card component built on top of the base Card component. Provides a simplified prop-based API with built-in header, body, and footer sections, 10 visual variants (including semantic states), size control, loading skeleton state, and sub-components for advanced composition.
6
+
7
+ ---
8
+
9
+ ## Props
10
+
11
+ ### AppCardProps
12
+
13
+ | Prop | Type | Default | Description |
14
+ | ------------------ | ------------------------------------------------------------------------------------------------------ | ----------- | ------------------------------------------------------------------- |
15
+ | `title` | `string \| React.ReactNode` | `undefined` | Card title displayed in the header. |
16
+ | `description` | `string \| React.ReactNode` | `undefined` | Card description displayed below the title. |
17
+ | `header` | `React.ReactNode` | `undefined` | Custom header content; overrides `title` and `description`. |
18
+ | `body` | `React.ReactNode` | `undefined` | Main content rendered inside CardContent. |
19
+ | `children` | `React.ReactNode` | `undefined` | Fallback body content when `body` is not provided. |
20
+ | `actions` | `React.ReactNode` | `undefined` | Right-aligned action elements inside the header. |
21
+ | `footer` | `React.ReactNode` | `undefined` | Footer content (typically action buttons). |
22
+ | `variant` | `AppCardVariant` | `"default"` | Visual variant of the card (see table below). |
23
+ | `size` | `"sm" \| "default" \| "lg" \| "none"` | `undefined` | Controls internal padding via the base Card component. |
24
+ | `isLoading` | `boolean` | `false` | When true, renders skeleton placeholders instead of content. |
25
+ | `showHeaderBorder` | `boolean` | `false` | Displays a border between the header and body sections. |
26
+ | `showFooterBorder` | `boolean` | `false` | Displays a border between the body and footer sections. |
27
+ | `className` | `string` | `undefined` | Additional classes for the card container. |
28
+ | `headerClassName` | `string` | `undefined` | Additional classes for the header section. |
29
+ | `bodyClassName` | `string` | `undefined` | Additional classes for the body section. |
30
+ | `footerClassName` | `string` | `undefined` | Additional classes for the footer section. |
31
+
32
+ ### Variant Reference
33
+
34
+ | Variant | Description |
35
+ | ------------- | ------------------------------------------------------------------------------- |
36
+ | `default` | Standard card with background, border, and subtle shadow. |
37
+ | `elevated` | Stronger shadow for layered or floating layouts. |
38
+ | `outlined` | Transparent background with visible border; no shadow. |
39
+ | `ghost` | No border, no shadow — blends seamlessly into the background. |
40
+ | `flat` | Muted background, no border or shadow; ideal for nested card contexts. |
41
+ | `interactive` | Default styling with hover shadow and border accent; pointer cursor for clicks. |
42
+ | `success` | Green-tinted semantic card for positive states and confirmations. |
43
+ | `warning` | Amber-tinted semantic card for cautionary messages and alerts. |
44
+ | `destructive` | Red-tinted semantic card for errors, danger states, or critical notices. |
45
+ | `info` | Primary-tinted semantic card for informational context and updates. |
46
+
47
+ ### Size Reference
48
+
49
+ | Size | Description |
50
+ | --------- | ---------------------------------------------------- |
51
+ | `sm` | Reduced padding — compact cards and nested contexts. |
52
+ | `default` | Standard padding (base Card default). |
53
+ | `lg` | Spacious padding for prominent content areas. |
54
+ | `none` | No default padding — apply custom padding manually. |
55
+
56
+ ---
57
+
58
+ ## Exports
59
+
60
+ - **AppCard**: Main card component.
61
+ - **AppCardHeader**: Sub-component for composing custom headers.
62
+ - **AppCardBody**: Sub-component for composing custom body sections.
63
+ - **AppCardFooter**: Sub-component for composing custom footer sections.
64
+ - **AppCardProps**: TypeScript interface for AppCard props.
65
+ - **AppCardHeaderProps**: TypeScript interface for AppCardHeader props.
66
+ - **AppCardVariant**: Union type of all 10 variant values.
67
+ - **AppCardSize**: Union type of all size values (`"sm" | "default" | "lg" | "none"`).
68
+
69
+ ---
70
+
71
+ ## Behavior
72
+
73
+ - **`body` vs `children`**: `body` takes precedence. When `body` is omitted, `children` is rendered inside `CardContent`. This allows both prop-based and JSX-composition patterns.
74
+ - **`isLoading`**: When true, all section content is replaced with a skeleton showing a title placeholder, description placeholder, and three text-line placeholders. The skeleton respects the `size` and `variant` of the card.
75
+ - **`size` passthrough**: The `size` prop is forwarded to the underlying `Card` component, controlling padding and gap via the base `paddingMap`.
76
+ - **Conditional sections**: Header, body, and footer sections are only rendered if their corresponding props have content. An empty card renders just the card container.
77
+ - **Header border**: Setting `showHeaderBorder` adds `border-b` to the `CardHeader`. When absent, the body section removes its top padding to maintain visual continuity.
78
+ - **Footer border**: Setting `showFooterBorder` adds `border-b` to the body `CardContent`. When absent, the footer section removes its top padding.
79
+ - **`interactive` variant**: Adds `cursor-pointer` and hover-triggered shadow/border transitions. The card is a `div`, so attach `onClick` directly to the `AppCard` element.
80
+ - **Focus management**: The card container uses `focusRingWithin` from `designTokens`, so focusable elements inside the card display the system focus ring.
81
+
82
+ ---
83
+
84
+ ## Examples
85
+
86
+ ### Basic
87
+
88
+ ```tsx
89
+ import { AppCard, Button } from "laif-ds";
90
+
91
+ export function BasicCard() {
92
+ return (
93
+ <AppCard
94
+ title="Card Title"
95
+ description="Optional description providing additional context."
96
+ body={<p>Main content of the card.</p>}
97
+ footer={<Button>Primary Action</Button>}
98
+ className="w-[380px]"
99
+ />
100
+ );
101
+ }
102
+ ```
103
+
104
+ ### Semantic Variants
105
+
106
+ ```tsx
107
+ import { AppCard } from "laif-ds";
108
+
109
+ export function SemanticCards() {
110
+ return (
111
+ <div className="grid grid-cols-2 gap-4">
112
+ <AppCard
113
+ title="Operation Successful"
114
+ description="All services are running normally."
115
+ body={<p>Deployment completed in 2m 34s.</p>}
116
+ variant="success"
117
+ className="w-[300px]"
118
+ />
119
+ <AppCard
120
+ title="Warning"
121
+ description="Storage usage is high."
122
+ body={<p>Disk at 80% capacity. Consider cleanup.</p>}
123
+ variant="warning"
124
+ className="w-[300px]"
125
+ />
126
+ <AppCard
127
+ title="Error Detected"
128
+ description="Service is not responding."
129
+ body={<p>Payment gateway returned a 503 error.</p>}
130
+ variant="destructive"
131
+ className="w-[300px]"
132
+ />
133
+ <AppCard
134
+ title="Update Available"
135
+ description="Version 2.4.0 is ready to install."
136
+ body={<p>Includes security patches and new features.</p>}
137
+ variant="info"
138
+ className="w-[300px]"
139
+ />
140
+ </div>
141
+ );
142
+ }
143
+ ```
144
+
145
+ ### Interactive Card with onClick
146
+
147
+ ```tsx
148
+ import { useState } from "react";
149
+ import { AppCard } from "laif-ds";
150
+
151
+ export function ClickableCard() {
152
+ const [count, setCount] = useState(0);
153
+
154
+ return (
155
+ <AppCard
156
+ title="Clickable Card"
157
+ description="Click anywhere on the card"
158
+ body={<p className="text-sm">Clicked {count} times.</p>}
159
+ variant="interactive"
160
+ onClick={() => setCount((c) => c + 1)}
161
+ className="w-[320px]"
162
+ />
163
+ );
164
+ }
165
+ ```
166
+
167
+ ### Loading State
168
+
169
+ ```tsx
170
+ import { useState } from "react";
171
+ import { AppCard, Button } from "laif-ds";
172
+
173
+ export function LoadingCard() {
174
+ const [loading, setLoading] = useState(true);
175
+
176
+ return (
177
+ <div className="flex flex-col gap-4">
178
+ <Button onClick={() => setLoading((v) => !v)}>Toggle Loading</Button>
179
+ <AppCard
180
+ title="Remote Data Card"
181
+ description="Loaded from external source"
182
+ body={<p>This is the real content.</p>}
183
+ footer={<Button>Action</Button>}
184
+ isLoading={loading}
185
+ className="w-[380px]"
186
+ />
187
+ </div>
188
+ );
189
+ }
190
+ ```
191
+
192
+ ### Nested Flat Cards
193
+
194
+ ```tsx
195
+ import { AppCard } from "laif-ds";
196
+
197
+ export function NestedCards() {
198
+ return (
199
+ <AppCard
200
+ title="Parent Card"
201
+ description="Contains nested flat sub-cards"
202
+ body={
203
+ <div className="flex flex-col gap-3">
204
+ <AppCard
205
+ title="Nested Item A"
206
+ body={<p className="text-sm">Flat cards have no border or shadow.</p>}
207
+ variant="flat"
208
+ size="sm"
209
+ />
210
+ <AppCard
211
+ title="Nested Item B"
212
+ body={<p className="text-sm">Good for secondary content regions.</p>}
213
+ variant="flat"
214
+ size="sm"
215
+ />
216
+ </div>
217
+ }
218
+ className="w-[420px]"
219
+ />
220
+ );
221
+ }
222
+ ```
223
+
224
+ ### Size Variants
225
+
226
+ ```tsx
227
+ import { AppCard } from "laif-ds";
228
+
229
+ export function SizeVariants() {
230
+ return (
231
+ <div className="flex flex-col gap-6 w-[400px]">
232
+ <AppCard
233
+ size="sm"
234
+ title="Size: Small"
235
+ description="Reduced padding for compact layouts"
236
+ body={<p>This card uses size="sm".</p>}
237
+ />
238
+ <AppCard
239
+ size="default"
240
+ title="Size: Default"
241
+ description="Standard padding"
242
+ body={<p>This card uses size="default".</p>}
243
+ />
244
+ <AppCard
245
+ size="lg"
246
+ title="Size: Large"
247
+ description="Spacious padding for prominent content"
248
+ body={<p>This card uses size="lg".</p>}
249
+ />
250
+ </div>
251
+ );
252
+ }
253
+ ```
254
+
255
+ ### Children as Fallback Body
256
+
257
+ ```tsx
258
+ import { AppCard } from "laif-ds";
259
+
260
+ export function ChildrenCard() {
261
+ return (
262
+ <AppCard title="Card with Children" className="w-[380px]">
263
+ <p>This content is passed as children and rendered inside CardContent.</p>
264
+ </AppCard>
265
+ );
266
+ }
267
+ ```
268
+
269
+ ### Advanced Composition with Sub-components
270
+
271
+ ```tsx
272
+ import {
273
+ AppCard,
274
+ AppCardHeader,
275
+ AppCardBody,
276
+ AppCardFooter,
277
+ Button,
278
+ Badge,
279
+ } from "laif-ds";
280
+
281
+ export function ComposedCard() {
282
+ return (
283
+ <AppCard className="w-[380px]">
284
+ <AppCardHeader
285
+ title="Advanced Composition"
286
+ description="Using sub-components directly"
287
+ actions={<Badge>New</Badge>}
288
+ />
289
+ <AppCardBody>
290
+ <p>Full control over each section independently.</p>
291
+ </AppCardBody>
292
+ <AppCardFooter>
293
+ <Button className="w-full">Confirm</Button>
294
+ </AppCardFooter>
295
+ </AppCard>
296
+ );
297
+ }
298
+ ```
299
+
300
+ ---
301
+
302
+ ## Notes
303
+
304
+ - **`body` vs `children` precedence**: If both are provided, `body` wins. Use `body` for the prop-based API and `children` when composing JSX naturally.
305
+ - **`interactive` variant and accessibility**: The `interactive` variant only adds visual affordances (hover states, pointer cursor). For keyboard accessibility on a clickable card, consider wrapping with an `<a>` or `<button>` using `asChild` on a child component, or ensure the card content includes a focusable element.
306
+ - **Sub-components**: `AppCardHeader`, `AppCardBody`, and `AppCardFooter` wrap the base `CardHeader`, `CardContent`, and `CardFooter` respectively. Use them when the prop API of `AppCard` is insufficient for your layout needs.
307
+ - **vs Card**: Use `AppCard` for most card use cases — it handles conditional rendering and spacing automatically. Use the base `Card` and its sub-components directly when you need maximum layout control with no abstraction overhead.
308
+ - **Semantic variants and theming**: The semantic variant colors (`success`, `warning`, `destructive`, `info`) use CSS variable tokens that respond to light/dark mode automatically.