@publicplan/kern-react-kit 1.3.2 → 1.3.4
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/index.cjs +120 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +24 -0
- package/dist/index.d.cts +31 -9
- package/dist/index.d.ts +54 -32
- package/dist/index.js +120 -38
- package/dist/index.js.map +1 -1
- package/dist/skills/kern-react-kit/SKILL.md +343 -0
- package/dist/skills/kern-react-kit/references/COMPONENTS.md +686 -0
- package/dist/skills/kern-react-kit/references/REFERENCE.md +316 -0
- package/dist/skills/skills.index.json +10 -0
- package/package.json +10 -4
|
@@ -0,0 +1,686 @@
|
|
|
1
|
+
# Component Catalog: Kern React Kit
|
|
2
|
+
|
|
3
|
+
This is a quick reference to core components in @publicplan/kern-react-kit with import paths, prop types, and usage patterns.
|
|
4
|
+
|
|
5
|
+
## Layout & Structure
|
|
6
|
+
|
|
7
|
+
### Card
|
|
8
|
+
A flexible container component for grouping related content.
|
|
9
|
+
|
|
10
|
+
**Import:**
|
|
11
|
+
```typescript
|
|
12
|
+
import { Card } from '@publicplan/kern-react-kit';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Interface:**
|
|
16
|
+
```typescript
|
|
17
|
+
export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
18
|
+
// Compound sub-components:
|
|
19
|
+
// Card.Root | Card.Container | Card.Header | Card.Body | Card.Footer
|
|
20
|
+
// Card.Title | Card.Subline | Card.Media | Card.Preline
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Usage:**
|
|
25
|
+
```tsx
|
|
26
|
+
// ✅ Compound component pattern (from Storybook)
|
|
27
|
+
<Card style={{ maxWidth: '320px' }}>
|
|
28
|
+
<Card.Media src="https://placehold.co/600x400?text=MEDIA" alt="Card media" />
|
|
29
|
+
<Card.Container>
|
|
30
|
+
<Card.Header>
|
|
31
|
+
<Card.Preline>Preline</Card.Preline>
|
|
32
|
+
<Card.Title>Title</Card.Title>
|
|
33
|
+
<Card.Subline>Subline</Card.Subline>
|
|
34
|
+
</Card.Header>
|
|
35
|
+
<Card.Body>
|
|
36
|
+
Content goes here
|
|
37
|
+
</Card.Body>
|
|
38
|
+
<Card.Footer>
|
|
39
|
+
<Button variant="primary" text="Primäraktion" />
|
|
40
|
+
<Button variant="secondary" text="Aktion" />
|
|
41
|
+
</Card.Footer>
|
|
42
|
+
</Card.Container>
|
|
43
|
+
</Card>
|
|
44
|
+
|
|
45
|
+
// ❌ Incorrect: Flat structure without compound components
|
|
46
|
+
<Card>
|
|
47
|
+
<h2>Title</h2>
|
|
48
|
+
<p>Content</p>
|
|
49
|
+
</Card>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Grid
|
|
53
|
+
Responsive grid system with `Row` and `Column` primitives.
|
|
54
|
+
|
|
55
|
+
**Import:**
|
|
56
|
+
```typescript
|
|
57
|
+
import { Grid } from '@publicplan/kern-react-kit';
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Interface:**
|
|
61
|
+
```typescript
|
|
62
|
+
export interface GridProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
63
|
+
type?: 'container' | 'fluid';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface GridColumnProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
67
|
+
width?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
|
|
68
|
+
breakpoint?: 'sm' | 'md' | 'lg' | 'xl';
|
|
69
|
+
isOffset?: boolean;
|
|
70
|
+
offsetWidth?: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface GridRowProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
74
|
+
alignItems?: 'start' | 'center' | 'end';
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Usage:**
|
|
79
|
+
```tsx
|
|
80
|
+
// ✅ Responsive grid (Storybook pattern)
|
|
81
|
+
<Grid>
|
|
82
|
+
<Grid.Row>
|
|
83
|
+
<Grid.Column width={4}>
|
|
84
|
+
<TextInput label="Name" id="name" name="name" required />
|
|
85
|
+
</Grid.Column>
|
|
86
|
+
<Grid.Column width={4}>
|
|
87
|
+
<TextInput label="Vorname" id="vorname" name="vorname" required />
|
|
88
|
+
</Grid.Column>
|
|
89
|
+
<Grid.Column width={4}>
|
|
90
|
+
<TextInput label="Alter" id="alter" name="alter" required />
|
|
91
|
+
</Grid.Column>
|
|
92
|
+
</Grid.Row>
|
|
93
|
+
</Grid>
|
|
94
|
+
|
|
95
|
+
// ❌ Avoid: Non-responsive, unclear structure
|
|
96
|
+
<div className="custom-grid">
|
|
97
|
+
<Card>Item 1</Card>
|
|
98
|
+
</div>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Input & Forms
|
|
104
|
+
|
|
105
|
+
### TextInput
|
|
106
|
+
Single-line text input field with built-in label, hint, and error states.
|
|
107
|
+
|
|
108
|
+
**Import:**
|
|
109
|
+
```typescript
|
|
110
|
+
import { TextInput } from '@publicplan/kern-react-kit';
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Interface:**
|
|
114
|
+
```typescript
|
|
115
|
+
export interface TextInputProps
|
|
116
|
+
extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
117
|
+
label?: string;
|
|
118
|
+
hintText?: string;
|
|
119
|
+
error?: string | boolean;
|
|
120
|
+
hasOptionalLabel?: boolean;
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Usage:**
|
|
125
|
+
```tsx
|
|
126
|
+
// ✅ With label and error handling
|
|
127
|
+
<TextInput
|
|
128
|
+
id="email"
|
|
129
|
+
name="email"
|
|
130
|
+
label="Email Address"
|
|
131
|
+
hintText="Hint Text"
|
|
132
|
+
error={hasError ? 'Invalid email' : undefined}
|
|
133
|
+
aria-describedby={hasError ? 'error-msg' : undefined}
|
|
134
|
+
required
|
|
135
|
+
/>
|
|
136
|
+
{hasError && <span id="error-msg" role="alert">Invalid email</span>}
|
|
137
|
+
|
|
138
|
+
// ❌ Avoid: No label
|
|
139
|
+
<TextInput type="email" />
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Label
|
|
143
|
+
Associates text with form inputs.
|
|
144
|
+
|
|
145
|
+
**Import:**
|
|
146
|
+
```typescript
|
|
147
|
+
import { Label } from '@publicplan/kern-react-kit';
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Interface:**
|
|
151
|
+
```typescript
|
|
152
|
+
export interface LabelProps
|
|
153
|
+
extends React.LabelHTMLAttributes<HTMLLabelElement> {}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Usage:**
|
|
157
|
+
```tsx
|
|
158
|
+
// ✅ Paired with a custom input via htmlFor
|
|
159
|
+
<Label htmlFor="username">Username</Label>
|
|
160
|
+
<input id="username" className="kern-input" />
|
|
161
|
+
|
|
162
|
+
// ❌ Incorrect: Label disconnected from input
|
|
163
|
+
<Label>Username</Label>
|
|
164
|
+
<input className="kern-input" />
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Fieldset
|
|
168
|
+
Groups form controls with a legend.
|
|
169
|
+
|
|
170
|
+
**Import:**
|
|
171
|
+
```typescript
|
|
172
|
+
import { Fieldset } from '@publicplan/kern-react-kit';
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Interface:**
|
|
176
|
+
```typescript
|
|
177
|
+
export interface FieldsetRootProps
|
|
178
|
+
extends React.FieldsetHTMLAttributes<HTMLFieldSetElement> {
|
|
179
|
+
error?: boolean;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export interface FieldsetLegendProps {
|
|
183
|
+
hasOptionalLabel?: boolean;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface FieldsetContentProps {
|
|
187
|
+
horizontal?: boolean;
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Usage:**
|
|
192
|
+
```tsx
|
|
193
|
+
// ✅ Grouped form section (Storybook pattern)
|
|
194
|
+
<Fieldset.Root>
|
|
195
|
+
<Fieldset.Legend>Ansprechpartner</Fieldset.Legend>
|
|
196
|
+
<Fieldset.Content>
|
|
197
|
+
<TextInput label="Vorname" id="vorname" name="vorname" required />
|
|
198
|
+
<TextInput label="Name" id="name" name="name" required />
|
|
199
|
+
</Fieldset.Content>
|
|
200
|
+
</Fieldset.Root>
|
|
201
|
+
|
|
202
|
+
// ✅ Optional labels and hint
|
|
203
|
+
<Fieldset.Root>
|
|
204
|
+
<Fieldset.Legend hasOptionalLabel>Kontakt</Fieldset.Legend>
|
|
205
|
+
<Fieldset.Hint>Hint Text</Fieldset.Hint>
|
|
206
|
+
<Fieldset.Content>
|
|
207
|
+
<CheckboxInput id="herr" name="geschlecht" label="Herr" />
|
|
208
|
+
<CheckboxInput id="frau" name="geschlecht" label="Frau" />
|
|
209
|
+
</Fieldset.Content>
|
|
210
|
+
</Fieldset.Root>
|
|
211
|
+
|
|
212
|
+
// ✅ Error state
|
|
213
|
+
<Fieldset.Root error>
|
|
214
|
+
<Fieldset.Legend>Ansprechpartner</Fieldset.Legend>
|
|
215
|
+
<Fieldset.Content>
|
|
216
|
+
<TextInput label="Name" id="name" name="name" error required />
|
|
217
|
+
</Fieldset.Content>
|
|
218
|
+
<Fieldset.Error>Der Name darf nicht leer sein</Fieldset.Error>
|
|
219
|
+
</Fieldset.Root>
|
|
220
|
+
|
|
221
|
+
// ❌ Avoid: Ungrouped form fields
|
|
222
|
+
<TextInput placeholder="Name" />
|
|
223
|
+
<TextInput placeholder="Email" />
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Navigation & Interactive
|
|
229
|
+
|
|
230
|
+
### Button
|
|
231
|
+
Primary interactive control.
|
|
232
|
+
|
|
233
|
+
**Import:**
|
|
234
|
+
```typescript
|
|
235
|
+
import { Button } from '@publicplan/kern-react-kit';
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Interface:**
|
|
239
|
+
```typescript
|
|
240
|
+
export interface ButtonProps
|
|
241
|
+
extends Omit<React.ComponentPropsWithoutRef<'button'>, 'text'> {
|
|
242
|
+
variant?: 'primary' | 'secondary' | 'tertiary';
|
|
243
|
+
isBlock?: boolean;
|
|
244
|
+
icon?: IconProps | React.ReactNode;
|
|
245
|
+
iconSize?: 'small' | 'default' | 'large' | 'x-large';
|
|
246
|
+
iconOnly?: boolean;
|
|
247
|
+
iconLeft?: boolean;
|
|
248
|
+
text?: string | null;
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Usage:**
|
|
253
|
+
```tsx
|
|
254
|
+
// ✅ With label and semantic type
|
|
255
|
+
<Button type="submit" variant="primary" text="Save Changes" />
|
|
256
|
+
|
|
257
|
+
<Button
|
|
258
|
+
variant="secondary"
|
|
259
|
+
icon={{ name: 'trash' }}
|
|
260
|
+
iconOnly
|
|
261
|
+
aria-label="Delete item"
|
|
262
|
+
/>
|
|
263
|
+
|
|
264
|
+
// ❌ Avoid: Unlabeled icon button
|
|
265
|
+
<Button icon={{ name: 'X' }} iconOnly />
|
|
266
|
+
|
|
267
|
+
// ❌ Avoid: Styling button as a link
|
|
268
|
+
<Button variant="tertiary">Go to page</Button> {/* Use Link instead */}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Link
|
|
272
|
+
Semantic hyperlink component.
|
|
273
|
+
|
|
274
|
+
**Import:**
|
|
275
|
+
```typescript
|
|
276
|
+
import { Link } from '@publicplan/kern-react-kit';
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Interface:**
|
|
280
|
+
```typescript
|
|
281
|
+
export interface LinkProps
|
|
282
|
+
extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
283
|
+
variant?: 'default' | 'small';
|
|
284
|
+
icon?: IconProps;
|
|
285
|
+
iconLeft?: boolean;
|
|
286
|
+
isStretched?: boolean;
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Usage:**
|
|
291
|
+
```tsx
|
|
292
|
+
// ✅ Title-based links (Storybook pattern)
|
|
293
|
+
<Link
|
|
294
|
+
href="https://www.w3.org/WAI/standards-guidelines/wcag/"
|
|
295
|
+
title="Learn more about accessibility"
|
|
296
|
+
/>
|
|
297
|
+
|
|
298
|
+
// ✅ Icon link (icon hidden from screen readers by default)
|
|
299
|
+
<Link
|
|
300
|
+
href="https://www.w3.org/WAI/standards-guidelines/wcag/"
|
|
301
|
+
title="Learn more about accessibility"
|
|
302
|
+
icon={{ name: 'arrow-forward', size: 'default', 'aria-hidden': true }}
|
|
303
|
+
iconLeft
|
|
304
|
+
/>
|
|
305
|
+
|
|
306
|
+
// ❌ Avoid: Using Button for navigation
|
|
307
|
+
<Button variant="tertiary" text="Go to page" />
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Accordion
|
|
311
|
+
Expandable/collapsible content sections.
|
|
312
|
+
|
|
313
|
+
**Import:**
|
|
314
|
+
```typescript
|
|
315
|
+
import { Accordion } from '@publicplan/kern-react-kit';
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**Interface:**
|
|
319
|
+
```typescript
|
|
320
|
+
export interface AccordionProps
|
|
321
|
+
extends React.HTMLAttributes<HTMLDivElement> {}
|
|
322
|
+
// Compound components:
|
|
323
|
+
// Accordion.Root | Accordion.Group | Accordion.Summary | Accordion.Content
|
|
324
|
+
// Accordion.Summary accepts: title: { title: string; textWrapper: 'h2' | 'h3' | ... }
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Usage:**
|
|
328
|
+
```tsx
|
|
329
|
+
// ✅ Compound accordion structure (Storybook pattern)
|
|
330
|
+
<Accordion.Root>
|
|
331
|
+
<Accordion.Summary title={{ title: 'Accordion 1', textWrapper: 'h2' }} />
|
|
332
|
+
<Accordion.Content>Details for section 1</Accordion.Content>
|
|
333
|
+
</Accordion.Root>
|
|
334
|
+
|
|
335
|
+
<Accordion.Group>
|
|
336
|
+
<Accordion.Root>
|
|
337
|
+
<Accordion.Summary title={{ title: 'Accordion 1', textWrapper: 'h3' }} />
|
|
338
|
+
<Accordion.Content>Details for section 1</Accordion.Content>
|
|
339
|
+
</Accordion.Root>
|
|
340
|
+
<Accordion.Root>
|
|
341
|
+
<Accordion.Summary title={{ title: 'Accordion 2', textWrapper: 'h3' }} />
|
|
342
|
+
<Accordion.Content>Details for section 2</Accordion.Content>
|
|
343
|
+
</Accordion.Root>
|
|
344
|
+
</Accordion.Group>
|
|
345
|
+
|
|
346
|
+
// ❌ Avoid: Flat content structure
|
|
347
|
+
<div className="accordion">
|
|
348
|
+
<button>Section 1</button>
|
|
349
|
+
<p>Details</p>
|
|
350
|
+
</div>
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Content & Display
|
|
356
|
+
|
|
357
|
+
### Heading
|
|
358
|
+
Semantic heading elements (h1–h6).
|
|
359
|
+
|
|
360
|
+
**Import:**
|
|
361
|
+
```typescript
|
|
362
|
+
import { Heading } from '@publicplan/kern-react-kit';
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
**Interface:**
|
|
366
|
+
```typescript
|
|
367
|
+
export interface HeadingProps
|
|
368
|
+
extends React.HTMLAttributes<HTMLHeadingElement> {
|
|
369
|
+
level: 1 | 2 | 3 | 4 | 5 | 6;
|
|
370
|
+
visual?: 'large' | 'medium' | 'small'; // Override visual size
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**Usage:**
|
|
375
|
+
```tsx
|
|
376
|
+
// ✅ Semantic heading hierarchy
|
|
377
|
+
<Heading level={1}>Page Title</Heading>
|
|
378
|
+
<Heading level={2}>Section</Heading>
|
|
379
|
+
<Heading level={3}>Subsection</Heading>
|
|
380
|
+
|
|
381
|
+
// ❌ Avoid: Skipping heading levels
|
|
382
|
+
<Heading level={1}>Page Title</Heading>
|
|
383
|
+
<Heading level={3}>Subsection (skipped level 2)</Heading>
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### Body
|
|
387
|
+
Container for body text content.
|
|
388
|
+
|
|
389
|
+
**Import:**
|
|
390
|
+
```typescript
|
|
391
|
+
import { Body } from '@publicplan/kern-react-kit';
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
**Usage:**
|
|
395
|
+
```tsx
|
|
396
|
+
// ✅ Wrapping text content
|
|
397
|
+
<Body>
|
|
398
|
+
This is body text with consistent styling and line height.
|
|
399
|
+
</Body>
|
|
400
|
+
|
|
401
|
+
// ❌ Avoid: Mixing styled and unstyled text
|
|
402
|
+
<Body>Styled text</Body>
|
|
403
|
+
<p>Unstyled text</p>
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Badge
|
|
407
|
+
Small label or status indicator.
|
|
408
|
+
|
|
409
|
+
**Import:**
|
|
410
|
+
```typescript
|
|
411
|
+
import { Badge } from '@publicplan/kern-react-kit';
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
**Interface:**
|
|
415
|
+
```typescript
|
|
416
|
+
export interface BadgeProps
|
|
417
|
+
extends React.HTMLAttributes<HTMLSpanElement> {
|
|
418
|
+
title?: string;
|
|
419
|
+
variant?: 'info' | 'success' | 'warning' | 'danger';
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
**Usage:**
|
|
424
|
+
```tsx
|
|
425
|
+
// ✅ Status indicator (Storybook pattern)
|
|
426
|
+
<Badge variant="info" title="Information" />
|
|
427
|
+
<Badge variant="success" title="Erfolg" />
|
|
428
|
+
<Badge variant="warning" title="Warnung" />
|
|
429
|
+
<Badge variant="danger" title="Fehler" />
|
|
430
|
+
|
|
431
|
+
// ❌ Avoid: Styling arbitrary text as a badge
|
|
432
|
+
<Badge>Click here</Badge> {/* Use Button instead */}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## Modals & Overlays
|
|
438
|
+
|
|
439
|
+
### Dialog
|
|
440
|
+
Modal dialog/overlay component.
|
|
441
|
+
|
|
442
|
+
**Import:**
|
|
443
|
+
```typescript
|
|
444
|
+
import { Dialog } from '@publicplan/kern-react-kit';
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
**Interface:**
|
|
448
|
+
```typescript
|
|
449
|
+
export interface DialogProps
|
|
450
|
+
extends React.HTMLAttributes<HTMLDivElement> {
|
|
451
|
+
disableOverlayClose?: boolean;
|
|
452
|
+
}
|
|
453
|
+
// Compound components:
|
|
454
|
+
// Dialog.Trigger | Dialog.Modal | Dialog.Header | Dialog.Content | Dialog.Footer | Dialog.Button
|
|
455
|
+
// Dialog.Header accepts: dialogTitle, hasCloseButton
|
|
456
|
+
// Dialog.Modal accepts: open, noOverlay
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
**Usage:**
|
|
460
|
+
```tsx
|
|
461
|
+
// ✅ Dialog with trigger and modal (Storybook pattern)
|
|
462
|
+
<Dialog disableOverlayClose={false}>
|
|
463
|
+
<Dialog.Trigger>
|
|
464
|
+
<Button variant="primary" text="Open Dialog" />
|
|
465
|
+
</Dialog.Trigger>
|
|
466
|
+
<Dialog.Modal>
|
|
467
|
+
<Dialog.Header dialogTitle="Frage?" hasCloseButton />
|
|
468
|
+
<Dialog.Content>Are you sure?</Dialog.Content>
|
|
469
|
+
<Dialog.Footer>
|
|
470
|
+
<Dialog.Button variant="secondary" title="Abbrechen" />
|
|
471
|
+
<Dialog.Button
|
|
472
|
+
variant="primary"
|
|
473
|
+
title="Löschen"
|
|
474
|
+
onClick={(e, context) => {
|
|
475
|
+
context.closeDialog();
|
|
476
|
+
}}
|
|
477
|
+
/>
|
|
478
|
+
</Dialog.Footer>
|
|
479
|
+
</Dialog.Modal>
|
|
480
|
+
</Dialog>
|
|
481
|
+
|
|
482
|
+
// ❌ Avoid: Uncontrolled dialog without focus management
|
|
483
|
+
<div className="modal" style={{ display: 'block' }}>
|
|
484
|
+
Content
|
|
485
|
+
</div>
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
## Data Display
|
|
491
|
+
|
|
492
|
+
### Table
|
|
493
|
+
Semantic table component.
|
|
494
|
+
|
|
495
|
+
**Import:**
|
|
496
|
+
```typescript
|
|
497
|
+
import { Table } from '@publicplan/kern-react-kit';
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
**Interface:**
|
|
501
|
+
```typescript
|
|
502
|
+
export interface TableProps
|
|
503
|
+
extends React.TableHTMLAttributes<HTMLTableElement> {
|
|
504
|
+
variant?: 'default' | 'small';
|
|
505
|
+
caption?: string;
|
|
506
|
+
striped?: boolean;
|
|
507
|
+
responsive?: boolean;
|
|
508
|
+
}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
**Usage:**
|
|
512
|
+
```tsx
|
|
513
|
+
// ✅ Semantic table with headers (Storybook pattern)
|
|
514
|
+
<Table caption="Autovermietung Flotte" variant="default" striped={false}>
|
|
515
|
+
<Table.Header>
|
|
516
|
+
<Table.Row>
|
|
517
|
+
<Table.Column scope="col">Marke</Table.Column>
|
|
518
|
+
<Table.Column scope="col">Verfügbarkeit</Table.Column>
|
|
519
|
+
<Table.Column scope="col" numeric>
|
|
520
|
+
Tagespreis
|
|
521
|
+
</Table.Column>
|
|
522
|
+
</Table.Row>
|
|
523
|
+
</Table.Header>
|
|
524
|
+
<Table.Body>
|
|
525
|
+
<Table.Row>
|
|
526
|
+
<Table.Column scope="row">BMW</Table.Column>
|
|
527
|
+
<Table.Cell>Frei</Table.Cell>
|
|
528
|
+
<Table.Cell numeric>69,00 €</Table.Cell>
|
|
529
|
+
</Table.Row>
|
|
530
|
+
</Table.Body>
|
|
531
|
+
</Table>
|
|
532
|
+
|
|
533
|
+
// ❌ Avoid: Non-semantic data grid
|
|
534
|
+
<div className="custom-table">
|
|
535
|
+
<div className="row">Item 1 | Item 2</div>
|
|
536
|
+
</div>
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
### Progress
|
|
540
|
+
Progress bar component.
|
|
541
|
+
|
|
542
|
+
**Import:**
|
|
543
|
+
```typescript
|
|
544
|
+
import { Progress } from '@publicplan/kern-react-kit';
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
**Interface:**
|
|
548
|
+
```typescript
|
|
549
|
+
export interface ProgressProps
|
|
550
|
+
extends Omit<React.HTMLAttributes<HTMLDivElement>, 'role'> {
|
|
551
|
+
value?: number;
|
|
552
|
+
max?: number;
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
**Usage:**
|
|
557
|
+
```tsx
|
|
558
|
+
// ✅ Progress with Bar and Label (Storybook pattern)
|
|
559
|
+
<Progress value={2} max={5}>
|
|
560
|
+
<Progress.Label>Schritt 2 von 5</Progress.Label>
|
|
561
|
+
<Progress.Bar />
|
|
562
|
+
</Progress>
|
|
563
|
+
|
|
564
|
+
// ❌ Avoid: Progress without context
|
|
565
|
+
<Progress value={50}>
|
|
566
|
+
<Progress.Bar />
|
|
567
|
+
</Progress>
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## Utilities
|
|
573
|
+
|
|
574
|
+
### Icon
|
|
575
|
+
Renders icons from icon set.
|
|
576
|
+
|
|
577
|
+
**Import:**
|
|
578
|
+
```typescript
|
|
579
|
+
import { Icon } from '@publicplan/kern-react-kit';
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
**Interface:**
|
|
583
|
+
```typescript
|
|
584
|
+
export interface IconProps {
|
|
585
|
+
name: string; // e.g., 'arrow-right', 'settings', 'trash'
|
|
586
|
+
size?: 'small' | 'default' | 'large' | 'x-large';
|
|
587
|
+
aria-label?: string; // Required if used as standalone interactive element
|
|
588
|
+
}
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
**Usage:**
|
|
592
|
+
```tsx
|
|
593
|
+
// ✅ Icon in button (button provides accessible name)
|
|
594
|
+
<Button icon={{ name: 'trash' }} iconOnly aria-label="Delete" />
|
|
595
|
+
|
|
596
|
+
// ✅ Icon with text
|
|
597
|
+
<Button icon={{ name: 'arrow-right', size: 'large' }} text="Next" />
|
|
598
|
+
|
|
599
|
+
// ❌ Avoid: Unlabeled icon button
|
|
600
|
+
<Button icon={{ name: 'X' }} iconOnly />
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
### Divider
|
|
604
|
+
Visual separator.
|
|
605
|
+
|
|
606
|
+
**Import:**
|
|
607
|
+
```typescript
|
|
608
|
+
import { Divider } from '@publicplan/kern-react-kit';
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
**Usage:**
|
|
612
|
+
```tsx
|
|
613
|
+
// ✅ Separating content sections
|
|
614
|
+
<Card.Body>Content 1</Card.Body>
|
|
615
|
+
<Divider />
|
|
616
|
+
<Card.Body>Content 2</Card.Body>
|
|
617
|
+
|
|
618
|
+
// ❌ Avoid: Multiple dividers in a row
|
|
619
|
+
<Divider />
|
|
620
|
+
<Divider />
|
|
621
|
+
<Divider />
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### Loader
|
|
625
|
+
Loading spinner indicator.
|
|
626
|
+
|
|
627
|
+
**Import:**
|
|
628
|
+
```typescript
|
|
629
|
+
import { Loader } from '@publicplan/kern-react-kit';
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
**Interface:**
|
|
633
|
+
```typescript
|
|
634
|
+
export interface LoaderProps
|
|
635
|
+
extends React.HTMLAttributes<HTMLDivElement> {
|
|
636
|
+
visible?: boolean;
|
|
637
|
+
srDescription?: string;
|
|
638
|
+
}
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
**Usage:**
|
|
642
|
+
```tsx
|
|
643
|
+
// ✅ With accessible label (Storybook pattern)
|
|
644
|
+
<Loader visible srDescription="Wird geladen..." />
|
|
645
|
+
|
|
646
|
+
// ❌ Avoid: Unlabeled spinner
|
|
647
|
+
<Loader visible />
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
---
|
|
651
|
+
|
|
652
|
+
## Quick Reference Table
|
|
653
|
+
|
|
654
|
+
| Component | Category | Status | Notes |
|
|
655
|
+
|-----------|----------|--------|-------|
|
|
656
|
+
| Accordion | Navigation | ✅ | Compound component |
|
|
657
|
+
| Alert | Feedback | ✅ | Contextual variants |
|
|
658
|
+
| Badge | Content | ✅ | Status indicator |
|
|
659
|
+
| Body | Content | ✅ | Text container |
|
|
660
|
+
| Button | Interactive | ✅ | Multiple variants |
|
|
661
|
+
| Card | Layout | ✅ | Compound component |
|
|
662
|
+
| Divider | Utility | ✅ | Visual separator |
|
|
663
|
+
| Dialog | Modal | ✅ | Compound component |
|
|
664
|
+
| Fieldset | Forms | ✅ | Group controls |
|
|
665
|
+
| Grid | Layout | ✅ | Responsive grid |
|
|
666
|
+
| Heading | Content | ✅ | Semantic h1–h6 |
|
|
667
|
+
| Icon | Utility | ✅ | Icon library |
|
|
668
|
+
| Input (TextInput) | Forms | ✅ | Text, email, etc. |
|
|
669
|
+
| Label | Forms | ✅ | Input association |
|
|
670
|
+
| Link | Navigation | ✅ | Semantic anchor |
|
|
671
|
+
| Loader | Feedback | ✅ | Loading state |
|
|
672
|
+
| Progress | Feedback | ✅ | Progress indicator |
|
|
673
|
+
| Table | Data | ✅ | Semantic table |
|
|
674
|
+
| Title | Content | ✅ | Large heading |
|
|
675
|
+
| TaskList | Lists | ✅ | Checklist component |
|
|
676
|
+
|
|
677
|
+
---
|
|
678
|
+
|
|
679
|
+
**For more details on each component, see the Storybook documentation:**
|
|
680
|
+
```bash
|
|
681
|
+
npm run storybook
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
---
|
|
685
|
+
|
|
686
|
+
*Last updated: 2026-03-03*
|