laif-ds 0.2.76 → 0.2.78

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,6 +5,24 @@ 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.78]
9
+
10
+ ### 🐛 Fixed
11
+
12
+ - **AppEditor**: Fixed missing underline text save in the component output
13
+
14
+ ## [laif-ds@0.2.77]
15
+
16
+ ### 🚀 Added
17
+
18
+ - **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
19
+ - **AppForm**: Added column span sizing, configurable icon placement, enhanced search options, and comprehensive TypeScript typing improvements
20
+
21
+ ### 🔧 Changed
22
+
23
+ - **AppForm**: Updated to adopt new form pattern with improved layout, enhanced JSDoc comments, and better type safety across components
24
+ - **General**: Removed "use client" directives and fixed export formatting across components for better compatibility
25
+
8
26
  ## [laif-ds@0.2.76]
9
27
 
10
28
  ### 🚀 Added
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { getDefaultExportFromCjs as e } from "./_commonjsHelpers.js";
3
- import { __require as t } from "../node_modules/eventemitter3/index2.js";
4
- var r = t();
5
- const m = /* @__PURE__ */ e(r);
2
+ import { getDefaultExportFromCjs as r } from "./_commonjsHelpers.js";
3
+ import { __require as e } from "../node_modules/style-to-js/cjs/index.js";
4
+ var t = e();
5
+ const a = /* @__PURE__ */ r(t);
6
6
  export {
7
- m as default
7
+ a as default
8
8
  };
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { getDefaultExportFromCjs as r } from "./_commonjsHelpers.js";
3
- import { __require as e } from "../node_modules/style-to-js/cjs/index.js";
4
- var t = e();
5
- const a = /* @__PURE__ */ r(t);
2
+ import { getDefaultExportFromCjs as e } from "./_commonjsHelpers.js";
3
+ import { __require as r } from "../node_modules/extend/index.js";
4
+ var t = r();
5
+ const x = /* @__PURE__ */ e(t);
6
6
  export {
7
- a as default
7
+ x as default
8
8
  };
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { getDefaultExportFromCjs as e } from "./_commonjsHelpers.js";
3
- import { __require as r } from "../node_modules/extend/index.js";
4
- var t = r();
5
- const x = /* @__PURE__ */ e(t);
3
+ import { __require as t } from "../node_modules/eventemitter3/index2.js";
4
+ var r = t();
5
+ const m = /* @__PURE__ */ e(r);
6
6
  export {
7
- x as default
7
+ m as default
8
8
  };
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-03-13T13:58:51.406Z",
3
+ "generatedAt": "2026-04-01T08:26:06.498Z",
4
4
  "package": {
5
5
  "name": "laif-ds",
6
- "version": "0.2.76"
6
+ "version": "0.2.78"
7
7
  },
8
8
  "summary": {
9
- "scannedFiles": 390,
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": {
@@ -381,7 +381,7 @@
381
381
  },
382
382
  {
383
383
  "className": "text-muted-foreground text-sm",
384
- "occurrences": 25,
384
+ "occurrences": 28,
385
385
  "files": [
386
386
  "src/components/stories/app-form.stories.tsx",
387
387
  "src/components/stories/app-stepper.stories.tsx",
@@ -397,6 +397,20 @@
397
397
  "src/components/ui/tables/data-table/components/data-table-filter-inputs.tsx"
398
398
  ]
399
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
+ },
400
414
  {
401
415
  "className": "bg-muted rounded-md p-4",
402
416
  "occurrences": 20,
@@ -407,16 +421,17 @@
407
421
  ]
408
422
  },
409
423
  {
410
- "className": "text-d-muted-foreground text-sm",
424
+ "className": "flex items-center justify-between",
411
425
  "occurrences": 19,
412
426
  "files": [
413
- "src/components/stories/app-dialog.stories.tsx",
414
- "src/components/stories/app-kanban.stories.tsx",
415
- "src/components/stories/changelog.stories.tsx",
416
- "src/components/stories/date-picker.stories.tsx",
417
- "src/components/stories/input.stories.tsx",
418
- "src/components/stories/toaster.stories.tsx",
419
- "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"
420
435
  ]
421
436
  },
422
437
  {
@@ -438,16 +453,10 @@
438
453
  ]
439
454
  },
440
455
  {
441
- "className": "flex items-center justify-between",
442
- "occurrences": 15,
456
+ "className": "border-d-border bg-d-muted rounded-lg border p-4",
457
+ "occurrences": 14,
443
458
  "files": [
444
- "src/components/stories/data-table-utils-example.stories.tsx",
445
- "src/components/stories/sidebar.stories.tsx",
446
- "src/components/stories/switch.stories.tsx",
447
- "src/components/ui/app-form.tsx",
448
- "src/components/ui/tables/data-cross-table/cell-editor-dialog.tsx",
449
- "src/components/ui/tables/data-cross-table/data-cross-table.tsx",
450
- "src/components/ui/tables/data-cross-table/editable-input.tsx"
459
+ "src/components/stories/app-form.stories.tsx"
451
460
  ]
452
461
  },
453
462
  {
@@ -457,13 +466,6 @@
457
466
  "src/components/stories/tabs.stories.tsx"
458
467
  ]
459
468
  },
460
- {
461
- "className": "border-d-border bg-d-muted rounded-lg border p-4",
462
- "occurrences": 11,
463
- "files": [
464
- "src/components/stories/app-form.stories.tsx"
465
- ]
466
- },
467
469
  {
468
470
  "className": "flex w-[550px] flex-col gap-6",
469
471
  "occurrences": 10,
@@ -479,6 +481,16 @@
479
481
  "src/components/stories/tabs.stories.tsx"
480
482
  ]
481
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
+ },
482
494
  {
483
495
  "className": "text-d-muted-foreground",
484
496
  "occurrences": 8,
@@ -524,15 +536,6 @@
524
536
  "src/components/stories/button.stories.tsx"
525
537
  ]
526
538
  },
527
- {
528
- "className": "flex flex-col items-center gap-4",
529
- "occurrences": 7,
530
- "files": [
531
- "src/components/stories/confirmer.stories.tsx",
532
- "src/components/stories/input-selector.stories.tsx",
533
- "src/components/stories/theme-switcher.stories.tsx"
534
- ]
535
- },
536
539
  {
537
540
  "className": "flex flex-col items-center gap-2",
538
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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- Rich text editor powered by Lexical with optional Markdown sync. Supports configurable toolbars (block format, font format, history), clear action, and character counter.
5
+ Rich text editor powered by Lexical with optional Markdown sync. Supports configurable toolbars (block format, font format, history), clear action, character counter, and extended Markdown syntax including underline support.
6
6
 
7
7
  ---
8
8
 
@@ -23,14 +23,16 @@ Rich text editor powered by Lexical with optional Markdown sync. Supports config
23
23
  ## Behavior
24
24
 
25
25
  - **Markdown sync**: When `onlyMarkdown=true`, initializes from Markdown and emits Markdown on every change.
26
+ - **Extended Markdown**: Supports standard Markdown plus underline syntax using `++text++` (e.g., `++underlined text++`).
26
27
  - **Toolbars**:
27
28
  - `history`: undo/redo toolbar.
28
- - `block-format`: heading levels, list types, quote.
29
- - `font-format`: bold/italic/underline/strikethrough.
29
+ - `block-format`: heading levels (h1-h3), numbered/bulleted/check lists, blockquote.
30
+ - `font-format`: bold, italic, underline, strikethrough, inline code.
30
31
  - **Plugins**:
31
32
  - `clear`: clear actions in the footer.
32
33
  - `counter`: UTF-16 character counter in the footer.
33
34
  - **Editing**: Autosave via `onMarkdownEdit`. Keyboard navigation and selection per Lexical defaults.
35
+ - **Markdown Features**: Full support for headings, lists, quotes, links, inline code, bold, italic, strikethrough, and custom underline syntax.
34
36
 
35
37
  ---
36
38
 
@@ -69,7 +71,7 @@ import * as React from "react";
69
71
  import { AppEditor } from "laif-ds";
70
72
 
71
73
  export function MarkdownDefault() {
72
- const initial = "**Titolo** con testo in markdown";
74
+ const initial = "**Titolo** con testo in ++markdown++ e *corsivo*";
73
75
  const [md, setMd] = React.useState(initial);
74
76
  return (
75
77
  <AppEditor
@@ -81,10 +83,31 @@ export function MarkdownDefault() {
81
83
  }
82
84
  ```
83
85
 
86
+ ### Underline Support
87
+
88
+ ```tsx
89
+ import * as React from "react";
90
+ import { AppEditor } from "laif-ds";
91
+
92
+ export function UnderlineExample() {
93
+ const initial = "Testo normale ++testo sottolineato++ altro normale";
94
+ const [md, setMd] = React.useState(initial);
95
+ return (
96
+ <AppEditor
97
+ defaultValue={initial}
98
+ onMarkdownEdit={setMd}
99
+ toolbars={["font-format"]}
100
+ />
101
+ );
102
+ }
103
+ ```
104
+
84
105
  ---
85
106
 
86
107
  ## Notes
87
108
 
88
- - **Sizing**: Control height via `className` (e.g., `h-96`).
109
+ - **Sizing**: Control height via `className` (e.g., `h-96`). Default height is `h-72`.
89
110
  - **Performance**: Prefer Markdown mode for content pipelines that store Markdown; use `onlyMarkdown=false` for plain text initialization.
90
111
  - **Accessibility**: Toolbar buttons and editor area follow Lexical best practices.
112
+ - **Underline Syntax**: Uses `++text++` format which is not standard Markdown but supported in this component for rich text export/import.
113
+ - **Theme**: Uses design system tokens for consistent styling with `border-d-border`, `bg-d-background`, etc.