@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.
@@ -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*