@festo-ui/react 10.1.0-dev.875 → 10.1.1-dev.918

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.
@@ -54,7 +54,11 @@ const Popover = /*#__PURE__*/ forwardRef(({ children, className, style, containe
54
54
  children: [
55
55
  /*#__PURE__*/ jsx("div", {
56
56
  className: className,
57
- style: style,
57
+ style: {
58
+ width: 'fit-content',
59
+ height: 'fit-content',
60
+ ...style
61
+ },
58
62
  ref: (node)=>{
59
63
  refs.setReference(node);
60
64
  if ('function' == typeof handleRef) handleRef(node);
@@ -0,0 +1,20 @@
1
+ # @festo-ui/react — AI Agent Documentation
2
+
3
+ This documentation describes the React component library `@festo-ui/react` of the Festo Design System. It is optimized for AI agents that should use this library in projects.
4
+
5
+ ## Overview
6
+
7
+ | File | Content |
8
+ |------|--------|
9
+ | [installation.md](./installation.md) | Installation, setup, imports |
10
+ | [components.md](./components.md) | All UI components (Accordion, Button, Card, Modal, etc.) |
11
+ | [forms.md](./forms.md) | All form components (TextInput, Select, Checkbox, etc.) |
12
+ | [patterns.md](./patterns.md) | Common patterns: Controlled/Uncontrolled, FormData, Styling |
13
+
14
+ ## Quick Reference
15
+
16
+ **Package:** `@festo-ui/react`
17
+ **CSS:** `@festo-ui/react/index.css`
18
+ **License:** Apache-2.0
19
+ **Peer Dependencies:** React 18+
20
+ **CSS Prefix:** `fwe-` (Festo Web Essentials)
@@ -0,0 +1,661 @@
1
+ # UI Components
2
+
3
+ ## Accordion
4
+
5
+ Collapsible content sections.
6
+
7
+ ### Components
8
+ - `Accordion` — Container
9
+ - `AccordionHeader` — Header of the entire accordion
10
+ - `AccordionItem` — Single collapsible element
11
+ - `AccordionItemHeader` — Header of an item
12
+ - `AccordionItemBody` — Content of an item
13
+
14
+ ### Accordion Props
15
+ | Prop | Type | Default | Description |
16
+ |------|------|---------|-------------|
17
+ | `showMore` | `string` | `"Show more"` | Text for "Show more" |
18
+ | `showLess` | `string` | `"Show less"` | Text for "Show less" |
19
+ | `keepItemsOpen` | `boolean` | `true` | Multiple items open simultaneously. `false` = auto-collapse |
20
+ | `transparent` | `boolean` | `false` | Transparent background |
21
+ | `highlighted` | `boolean` | `true` | Highlighted style |
22
+
23
+ ### AccordionItem Props
24
+ | Prop | Type | Description |
25
+ |------|------|-------------|
26
+ | `expanded` | `boolean` | Controlled: whether open |
27
+ | `defaultExpanded` | `boolean` | Initial state (default: `false`) |
28
+ | `onChange` | `(expanded: boolean, event) => void` | Callback on state change |
29
+
30
+ ### Example — Basic
31
+ ```tsx
32
+ <Accordion>
33
+ <AccordionHeader>Title</AccordionHeader>
34
+ <AccordionItem>
35
+ <AccordionItemHeader>Item 1</AccordionItemHeader>
36
+ <AccordionItemBody>Content 1</AccordionItemBody>
37
+ </AccordionItem>
38
+ <AccordionItem>
39
+ <AccordionItemHeader>Item 2</AccordionItemHeader>
40
+ <AccordionItemBody>Content 2</AccordionItemBody>
41
+ </AccordionItem>
42
+ </Accordion>
43
+ ```
44
+
45
+ ### Example — Auto-Collapse
46
+ ```tsx
47
+ <Accordion keepItemsOpen={false}>
48
+ <AccordionHeader>Title</AccordionHeader>
49
+ <AccordionItem>
50
+ <AccordionItemHeader>Item 1</AccordionItemHeader>
51
+ <AccordionItemBody>Content 1</AccordionItemBody>
52
+ </AccordionItem>
53
+ </Accordion>
54
+ ```
55
+
56
+ ### Example — Controlled
57
+ ```tsx
58
+ const [expanded, setExpanded] = useState('item1');
59
+ const handleChange = (panel) => (isExpanded) => {
60
+ setExpanded(isExpanded ? panel : false);
61
+ };
62
+
63
+ <Accordion>
64
+ <AccordionItem expanded={expanded === 'item1'} onChange={handleChange('item1')}>
65
+ <AccordionItemHeader>Item 1</AccordionItemHeader>
66
+ <AccordionItemBody>Content 1</AccordionItemBody>
67
+ </AccordionItem>
68
+ </Accordion>
69
+ ```
70
+
71
+ ---
72
+
73
+ ## BottomSheet
74
+
75
+ Mobile bottom sheet overlay.
76
+
77
+ ### Props
78
+ | Prop | Type | Default | Description |
79
+ |------|------|---------|-------------|
80
+ | `open` | `boolean` | — | Controlled: whether visible |
81
+ | `defaultExpanded` | `boolean` | — | Initial state |
82
+ | `expandFrom` | `"center" \| "bottom"` | `"center"` | Expand direction |
83
+ | `hasBackdrop` | `boolean` | `true` | Show backdrop overlay |
84
+ | `hideCloseIcon` | `boolean` | — | Hide close icon |
85
+ | `onOpenChange` | `(value: boolean) => void` | — | Callback on open/close |
86
+
87
+ ### Example
88
+ ```tsx
89
+ const [open, setOpen] = useState(false);
90
+
91
+ <button onClick={() => setOpen(true)}>Open</button>
92
+ <BottomSheet open={open} onOpenChange={setOpen}>
93
+ <p>Content</p>
94
+ </BottomSheet>
95
+ ```
96
+
97
+ ---
98
+
99
+ ## Breadcrumb
100
+
101
+ Navigation path display.
102
+
103
+ ### Props
104
+ | Prop | Type | Description |
105
+ |------|------|-------------|
106
+ | `locations` | `BreadcrumbLocation[]` | Array with `{ text, href }` |
107
+ | `onClick` | `(event) => void` | Click handler for links |
108
+
109
+ ### Example — With locations array
110
+ ```tsx
111
+ <Breadcrumb
112
+ locations={[
113
+ { text: 'Home', href: '/' },
114
+ { text: 'Products', href: '/products' },
115
+ { text: 'Current', href: '/products/current' },
116
+ ]}
117
+ onClick={(e) => e.preventDefault()}
118
+ />
119
+ ```
120
+
121
+ ### Example — With children
122
+ ```tsx
123
+ <Breadcrumb>
124
+ <a href="/components">Components</a>
125
+ <a href="/components/breadcrumbs">Breadcrumbs</a>
126
+ </Breadcrumb>
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Button
132
+
133
+ Standard buttons in various variants.
134
+
135
+ ### Props
136
+ | Prop | Type | Default | Description |
137
+ |------|------|---------|-------------|
138
+ | `primary` | `boolean` | `false` | Primary/hero button |
139
+ | `tertiary` | `boolean` | `false` | Tertiary button (text style) |
140
+ | `icon` | `ReactNode` | — | Icon element |
141
+ | `iconOnly` | `boolean` | `false` | Icon only, no text |
142
+ | `large` | `boolean` | `false` | Larger variant |
143
+ | `floating` | `boolean` | `false` | Floating action button |
144
+ | `disabled` | `boolean` | `false` | Disabled |
145
+
146
+ ### Examples
147
+ ```tsx
148
+ <Button>Default</Button>
149
+ <Button primary>Primary</Button>
150
+ <Button tertiary>Tertiary</Button>
151
+ <Button large>Large</Button>
152
+ <Button icon={<IconCoreRangeProduct />}>With Icon</Button>
153
+ <Button iconOnly icon={<IconCoreRangeProduct />} />
154
+ <Button iconOnly large primary floating icon={<IconCoreRangeProduct />} />
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Card
160
+
161
+ Card component with header, body, and notifications.
162
+
163
+ ### Components
164
+ - `Card` — Container
165
+ - `CardHeader` — Header with optional image, subtitle, and action
166
+ - `CardBody` — Text content with optional children
167
+ - `CardNotification` — Notification bar
168
+
169
+ ### Example
170
+ ```tsx
171
+ <Card>
172
+ <CardHeader
173
+ title="Card Title"
174
+ subtitle="Description"
175
+ image={{ src: 'image.webp', alt: 'Image', aspectRatio: '16/9' }}
176
+ action={<button className="fwe-btn fwe-btn-icon">...</button>}
177
+ />
178
+ <CardBody text="Card text">
179
+ <button className="fwe-btn fwe-btn-hero fwe-btn-block">Action</button>
180
+ </CardBody>
181
+ <CardNotification className="fwe-bg-orange" title="Warning" message="Details" />
182
+ </Card>
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Chip / ChipContainer
188
+
189
+ Chips for filters, categories, selection, and actions.
190
+
191
+ ### Chip Props
192
+ | Prop | Type | Default | Description |
193
+ |------|------|---------|-------------|
194
+ | `type` | `ChipType` | `ChipType.Choice` | Chip type: `Choice`, `Category`, `Filter`, `Action`, `Readonly` |
195
+ | `icon` | `ReactNode` | — | Icon |
196
+ | `selected` | `boolean` | `false` | Selected |
197
+ | `disabled` | `boolean` | `false` | Disabled |
198
+ | `large` | `boolean` | `false` | Large |
199
+
200
+ ### ChipContainer Props
201
+ | Prop | Type | Default | Description |
202
+ |------|------|---------|-------------|
203
+ | `large` | `boolean` | `false` | Large chips in container |
204
+
205
+ ### Example
206
+ ```tsx
207
+ import { Chip, ChipContainer, ChipType } from '@festo-ui/react';
208
+
209
+ <ChipContainer>
210
+ <Chip>Choice</Chip>
211
+ <Chip selected>Selected</Chip>
212
+ <Chip type={ChipType.Filter} selected>Filter</Chip>
213
+ <Chip type={ChipType.Action} icon={<IconCoreRangeProduct />}>Action</Chip>
214
+ <Chip type={ChipType.Readonly}>Readonly</Chip>
215
+ </ChipContainer>
216
+ ```
217
+
218
+ ---
219
+
220
+ ## LoadingIndicator
221
+
222
+ Loading indicator in three sizes.
223
+
224
+ ### Props
225
+ | Prop | Type | Default | Description |
226
+ |------|------|---------|-------------|
227
+ | `size` | `"large" \| "medium" \| "small"` | `"large"` | Size |
228
+
229
+ ### Example
230
+ ```tsx
231
+ <LoadingIndicator />
232
+ <LoadingIndicator size="medium">Loading...</LoadingIndicator>
233
+ <LoadingIndicator size="small">Loading...</LoadingIndicator>
234
+ ```
235
+
236
+ ---
237
+
238
+ ## MobileFlyout
239
+
240
+ Mobile navigation with nested pages.
241
+
242
+ ### MobileFlyout Props
243
+ | Prop | Type | Default | Description |
244
+ |------|------|---------|-------------|
245
+ | `open` | `boolean` | — | Controlled: whether open |
246
+ | `defaultOpen` | `boolean` | — | Initial state |
247
+ | `visible` | `string[]` | — | Controlled: visible pages |
248
+ | `defaultVisible` | `string[]` | `['root']` | Initially visible pages |
249
+ | `onOpenChange` | `(value: boolean) => void` | — | Callback |
250
+ | `onVisibleChange` | `(value: string) => void` | — | Callback |
251
+ | `back` | `string` | — | Back text |
252
+
253
+ ### MobileFlyoutItem Props
254
+ | Prop | Type | Description |
255
+ |------|------|-------------|
256
+ | `icon` | `ReactNode` | Icon |
257
+ | `pageLink` | `string` | Links to a MobileFlyoutPage |
258
+ | `active` | `boolean` | Active state |
259
+ | `component` | `ElementType` | Alternative HTML element |
260
+
261
+ ### MobileFlyoutPage Props
262
+ | Prop | Type | Description |
263
+ |------|------|-------------|
264
+ | `name` | `string` | Unique page name |
265
+ | `root` | `boolean` | Whether this is the root page |
266
+ | `back` | `string` | Back text |
267
+
268
+ ### Example
269
+ ```tsx
270
+ <MobileFlyout>
271
+ <MobileFlyoutPage root name="root">
272
+ <MobileFlyoutItem href="/page1">Page 1</MobileFlyoutItem>
273
+ <MobileFlyoutItem icon={<IconSettings />} pageLink="settings">
274
+ Settings
275
+ </MobileFlyoutItem>
276
+ </MobileFlyoutPage>
277
+ <MobileFlyoutPage name="settings">
278
+ <h3>Settings</h3>
279
+ <MobileFlyoutItem pageLink="advanced">Advanced</MobileFlyoutItem>
280
+ </MobileFlyoutPage>
281
+ </MobileFlyout>
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Modals (AlertModal, ConfirmModal, CustomModal, Prompt)
287
+
288
+ Various dialog types.
289
+
290
+ ### AlertModal
291
+ Displays a warning/info dialog.
292
+ ```tsx
293
+ <AlertModal
294
+ isOpen={open}
295
+ onClose={() => setOpen(false)}
296
+ onCancel={() => setOpen(false)}
297
+ onOk={() => setOpen(false)}
298
+ title="Title"
299
+ subtitle="Subtitle"
300
+ body="Message"
301
+ alertType="info" // or "warning"
302
+ cancel="Cancel"
303
+ ok="OK"
304
+ strong={false} // true for strong warning
305
+ />
306
+ ```
307
+
308
+ ### ConfirmModal
309
+ Confirmation dialog.
310
+ ```tsx
311
+ <ConfirmModal
312
+ isOpen={open}
313
+ onClose={() => setOpen(false)}
314
+ onCancel={() => setOpen(false)}
315
+ onOk={() => setOpen(false)}
316
+ title="Confirmation"
317
+ subtitle="Subtitle"
318
+ body="Do you want to continue?"
319
+ cancel="Cancel"
320
+ ok="OK"
321
+ large={false} // true for large scrollable variant
322
+ />
323
+ ```
324
+
325
+ ### Prompt
326
+ Input dialog.
327
+ ```tsx
328
+ <Prompt
329
+ isOpen={open}
330
+ onClose={() => setOpen(false)}
331
+ onCancel={() => setOpen(false)}
332
+ onOk={() => setOpen(false)}
333
+ title="Headline"
334
+ subtitle="Category"
335
+ label="Label"
336
+ hint="Optional hint"
337
+ cancel="Cancel"
338
+ ok="Send"
339
+ />
340
+ ```
341
+
342
+ ### CustomModal
343
+ Freely customizable dialog.
344
+ ```tsx
345
+ <CustomModal
346
+ isOpen={open}
347
+ onClose={() => setOpen(false)}
348
+ title="Title"
349
+ subtitle="Subtitle"
350
+ closeOnBackdrop={false}
351
+ >
352
+ <form onSubmit={handleSubmit}>
353
+ <div className="fwe-modal-body">
354
+ {/* Form content */}
355
+ </div>
356
+ <div className="fwe-modal-footer">
357
+ <div className="fwe-modal-buttons">
358
+ <button type="button" className="fwe-btn fwe-btn-lg" onClick={() => setOpen(false)}>
359
+ Cancel
360
+ </button>
361
+ <button className="fwe-btn fwe-btn-lg fwe-btn-hero" type="submit">
362
+ Submit
363
+ </button>
364
+ </div>
365
+ </div>
366
+ </form>
367
+ </CustomModal>
368
+ ```
369
+
370
+ ### Common Modal Props
371
+ | Prop | Type | Description |
372
+ |------|------|-------------|
373
+ | `isOpen` | `boolean` | **Required.** Whether the dialog is visible |
374
+ | `isLoading` | `boolean` | Show loading state |
375
+ | `closeOnBackdrop` | `boolean` | Close by clicking backdrop (default: `true`) |
376
+ | `onClose` | `() => void` | Callback on close |
377
+ | `onCloseDone` | `() => void` | Callback after close animation |
378
+
379
+ ---
380
+
381
+ ## ImageGallery
382
+
383
+ Fullscreen image gallery overlay.
384
+
385
+ ### Props
386
+ | Prop | Type | Description |
387
+ |------|------|-------------|
388
+ | `isOpen` | `boolean` | **Required.** Whether open |
389
+ | `startIndex` | `number` | **Required.** Starting image index |
390
+ | `images` | `ImageGalleryItemData[]` | Array of images |
391
+ | `thumbnailImages` | `ImageGalleryItemData[]` | Thumbnail images |
392
+ | `pagination` | `number \| boolean` | Show pagination |
393
+ | `showScaleButton` | `boolean` | Show zoom button |
394
+ | `descriptiveContent` | `boolean \| (index: number) => ReactNode` | Descriptive text |
395
+ | `onClose` | `() => void` | Callback on close |
396
+ | `onSlideChanged` | `(index: number) => void` | Callback on slide change |
397
+
398
+ ### Example
399
+ ```tsx
400
+ const [open, setOpen] = useState(false);
401
+
402
+ <button onClick={() => setOpen(true)}>Open Gallery</button>
403
+ <ImageGallery
404
+ isOpen={open}
405
+ onClose={() => setOpen(false)}
406
+ images={images}
407
+ startIndex={0}
408
+ pagination
409
+ thumbnailImages={images}
410
+ showScaleButton
411
+ descriptiveContent
412
+ />
413
+ ```
414
+
415
+ ---
416
+
417
+ ## Pagination
418
+
419
+ Page navigation in three styles.
420
+
421
+ ### Props
422
+ | Prop | Type | Default | Description |
423
+ |------|------|---------|-------------|
424
+ | `type` | `"NUMERIC" \| "SIMPLE" \| "DOTS"` | `"NUMERIC"` | Display style |
425
+ | `pageMax` | `number` | — | **Required.** Maximum page count |
426
+ | `pageCurrent` | `number` | — | Controlled: current page |
427
+ | `defaultPageCurrent` | `number` | `1` | Initial page |
428
+ | `onChange` | `(page: number, event) => void` | — | Callback |
429
+
430
+ ### Example
431
+ ```tsx
432
+ <Pagination pageMax={10} defaultPageCurrent={3} />
433
+ <Pagination pageMax={10} defaultPageCurrent={3} type="SIMPLE" />
434
+ <Pagination pageMax={5} defaultPageCurrent={3} type="DOTS" />
435
+ ```
436
+
437
+ ---
438
+
439
+ ## Popover / Tooltip / Legend / PopoverMenu
440
+
441
+ Overlay elements for additional information.
442
+
443
+ ### Popover Props
444
+ | Prop | Type | Description |
445
+ |------|------|-------------|
446
+ | `content` | `ReactNode` | Popover content |
447
+ | `position` | `Placement` | Position (e.g. `"right"`, `"top"`) |
448
+ | `isOpen` | `boolean` | Controlled |
449
+ | `onChange` | `(isOpen: boolean) => void` | Callback |
450
+ | `openOnHover` | `boolean` | Open on hover |
451
+ | `openByDefault` | `boolean` | Initially open |
452
+ | `onTriggerClick` | `(event) => void` | Custom trigger handler |
453
+
454
+ ### Examples
455
+ ```tsx
456
+ <Popover content="Content">Click me</Popover>
457
+ <Popover position="right" content="Right">Click</Popover>
458
+ <Popover openOnHover content="Hover info">Hover</Popover>
459
+ <Tooltip content="Tooltip text">Element</Tooltip>
460
+
461
+ <PopoverMenu items={[
462
+ { text: 'Download', icon: <IconDownload />, onClick: () => {} },
463
+ { text: 'Delete', icon: <IconDelete />, onClick: () => {} },
464
+ ]}>
465
+ <IconMore size={24} />
466
+ </PopoverMenu>
467
+
468
+ <Legend items={[{ name: 'PN', text: 'Part Number' }]}>
469
+ <button className="fwe-btn fwe-btn-link fwe-dark"><IconInfo />Legend</button>
470
+ </Legend>
471
+ ```
472
+
473
+ ---
474
+
475
+ ## Progress
476
+
477
+ Progress bar.
478
+
479
+ ### Props
480
+ | Prop | Type | Default | Description |
481
+ |------|------|---------|-------------|
482
+ | `progress` | `number` | — | **Required.** Progress 0–100 |
483
+ | `background` | `"white" \| "background" \| "black"` | `"white"` | Background color |
484
+ | `error` | `boolean` | `false` | Error state (red) |
485
+
486
+ ### Example
487
+ ```tsx
488
+ <Progress progress={50} />
489
+ <Progress progress={50} error />
490
+ <Progress progress={75} background="background" />
491
+ ```
492
+
493
+ ---
494
+
495
+ ## SearchInput
496
+
497
+ Search field with autocomplete suggestions.
498
+
499
+ ### SearchInput Props
500
+ | Prop | Type | Description |
501
+ |------|------|-------------|
502
+ | `label` | `string` | Placeholder text |
503
+ | `value` | `string` | Controlled |
504
+ | `defaultValue` | `string` | Initial value |
505
+ | `debounceTime` | `number` | Debounce in ms (default: 0) |
506
+ | `onChange` | `(value: string) => void` | Callback on input |
507
+ | `onSearch` | `(value: string) => void` | Callback on Enter/selection |
508
+
509
+ ### Example
510
+ ```tsx
511
+ const [query, setQuery] = useState('');
512
+ const [results, setResults] = useState([]);
513
+
514
+ function handleChange(value) {
515
+ setQuery(value);
516
+ setResults(allItems.filter(s => s.toLowerCase().includes(value.toLowerCase())));
517
+ }
518
+
519
+ <SearchInput label="Search" onChange={handleChange} onSearch={console.log}>
520
+ {results.map(item => (
521
+ <SearchInputOption key={item} value={item}>
522
+ <SearchResult label={item} query={query} />
523
+ </SearchInputOption>
524
+ ))}
525
+ </SearchInput>
526
+ ```
527
+
528
+ ---
529
+
530
+ ## Snackbar
531
+
532
+ Toast notifications.
533
+
534
+ ### Setup
535
+ Wrap with `SnackbarProvider` at the root:
536
+ ```tsx
537
+ <SnackbarProvider>
538
+ <App />
539
+ </SnackbarProvider>
540
+ ```
541
+
542
+ ### Usage with hook
543
+ ```tsx
544
+ const showSnackbar = useSnackbar();
545
+ showSnackbar({ text: 'Successfully saved!' });
546
+ ```
547
+
548
+ ### Usage without hook
549
+ ```tsx
550
+ import { addSnackbar } from '@festo-ui/react';
551
+ addSnackbar({ text: 'Saved!' });
552
+ ```
553
+
554
+ ---
555
+
556
+ ## Stepper (Vertical & Horizontal)
557
+
558
+ Step indicator for multi-step processes.
559
+
560
+ ### Example — Vertical
561
+ ```tsx
562
+ const [stepIndex, setStepIndex] = useState(0);
563
+
564
+ <StepperVertical stepIndex={stepIndex} onChange={setStepIndex}>
565
+ <StepVertical title="Step 1">
566
+ <p>Content</p>
567
+ <button className="fwe-btn" onClick={() => setStepIndex(stepIndex + 1)}>Next</button>
568
+ </StepVertical>
569
+ <StepVertical title="Step 2">
570
+ <p>Content</p>
571
+ </StepVertical>
572
+ </StepperVertical>
573
+ ```
574
+
575
+ ### Example — Horizontal
576
+ ```tsx
577
+ <StepperHorizontal stepIndex={stepIndex} onChange={setStepIndex}>
578
+ <StepHorizontal title="Step 1">Content</StepHorizontal>
579
+ <StepHorizontal title="Step 2">Content</StepHorizontal>
580
+ </StepperHorizontal>
581
+ ```
582
+
583
+ ---
584
+
585
+ ## Tabs
586
+
587
+ Tab navigation with content areas.
588
+
589
+ ### Props
590
+ | Prop | Type | Default | Description |
591
+ |------|------|---------|-------------|
592
+ | `config` | `TabsConfiguration` | — | Configuration (tabBar, tabItems) |
593
+ | `viewType` | `"responsive" \| "legacy"` | `"responsive"` | View type |
594
+ | `showDivider` | `boolean` | `false` | Divider line under tabs |
595
+ | `onChange` | `({ previous, current }) => void` | — | Callback on tab change |
596
+
597
+ ### TabPane Props
598
+ | Prop | Type | Description |
599
+ |------|------|-------------|
600
+ | `name` | `string` | **Required.** Tab name/label |
601
+ | `icon` | `ReactNode` | Optional: icon in tab |
602
+
603
+ ### Example
604
+ ```tsx
605
+ <Tabs>
606
+ <TabPane name="Tab 1">Content 1</TabPane>
607
+ <TabPane name="Tab 2">Content 2</TabPane>
608
+ <TabPane name="Tab 3">Content 3</TabPane>
609
+ </Tabs>
610
+ ```
611
+
612
+ ### Configuration example
613
+ ```tsx
614
+ <Tabs
615
+ viewType="legacy"
616
+ config={{
617
+ tabBar: { fullWidth: true },
618
+ tabItems: { appearance: 'fill' }, // 'equal' | 'fill'
619
+ }}
620
+ >
621
+ <TabPane name="Tab 1">Content</TabPane>
622
+ </Tabs>
623
+ ```
624
+
625
+ ---
626
+
627
+ ## TableHeaderCell
628
+
629
+ Sortable table header cell.
630
+
631
+ ### Props
632
+ | Prop | Type | Description |
633
+ |------|------|-------------|
634
+ | `active` | `boolean` | Whether this column is actively sorted |
635
+ | `ascending` | `boolean` | **Required.** Sort direction |
636
+
637
+ ### Example
638
+ ```tsx
639
+ const [orderBy, setOrderBy] = useState('name');
640
+ const [ascending, setAscending] = useState(true);
641
+
642
+ <table className="fwe-table">
643
+ <thead>
644
+ <tr>
645
+ <TableHeaderCell
646
+ ascending={ascending}
647
+ active={orderBy === 'name'}
648
+ onClick={() => {
649
+ setAscending(orderBy === 'name' ? !ascending : true);
650
+ setOrderBy('name');
651
+ }}
652
+ >
653
+ Name
654
+ </TableHeaderCell>
655
+ </tr>
656
+ </thead>
657
+ <tbody>
658
+ <tr className="fwe-tr-md"><td>Entry</td></tr>
659
+ </tbody>
660
+ </table>
661
+ ```
@@ -0,0 +1,333 @@
1
+ # Form Components
2
+
3
+ ## TextInput
4
+
5
+ Text field with label, hint, error display, and icon.
6
+
7
+ ### Props
8
+ | Prop | Type | Description |
9
+ |------|------|-------------|
10
+ | `label` | `string` | Label text |
11
+ | `value` | `string` | Controlled |
12
+ | `defaultValue` | `string` | Initial value |
13
+ | `onChange` | `(value: string, event) => void` | Callback |
14
+ | `hint` | `string` | Hint text |
15
+ | `error` | `string` | Error text |
16
+ | `icon` | `ReactNode` | Icon on the right |
17
+ | `readonly` | `boolean` | Read-only |
18
+
19
+ ### Example
20
+ ```tsx
21
+ <TextInput label="Username" defaultValue="max" hint="Hint" placeholder="Enter..." />
22
+ ```
23
+
24
+ ### Controlled
25
+ ```tsx
26
+ const [value, setValue] = useState('');
27
+ <TextInput label="Name" value={value} onChange={setValue} />
28
+ ```
29
+
30
+ ### Validation
31
+ ```tsx
32
+ <TextInput label="Name" defaultValue="" minLength={5} required />
33
+ <TextInput label="Error" aria-invalid error="Required field" icon={<IconClose className="fwe-color-red" />} />
34
+ ```
35
+
36
+ ---
37
+
38
+ ## TextArea
39
+
40
+ Multi-line text field.
41
+
42
+ ### Props
43
+ | Prop | Type | Description |
44
+ |------|------|-------------|
45
+ | `label` | `string` | **Required.** Label |
46
+ | `value` | `string` | Controlled |
47
+ | `defaultValue` | `string` | Initial value |
48
+ | `onChange` | `(value: string, event) => void` | Callback |
49
+ | `hint` | `string` | Hint text |
50
+ | `error` | `string` | Error text |
51
+ | `rows` | `number` | Rows (0 = auto-grow) |
52
+ | `maxLength` | `number` | Max character count |
53
+
54
+ ### Example
55
+ ```tsx
56
+ <TextArea label="Description" rows={3} hint="Hint" maxLength={200} />
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Select
62
+
63
+ Dropdown selection.
64
+
65
+ ### Props
66
+ | Prop | Type | Description |
67
+ |------|------|-------------|
68
+ | `options` | `SelectOption<T>[]` | **Required.** Array with `{ data: T, label: string \| ReactNode }` |
69
+ | `value` | `T` | Controlled |
70
+ | `defaultValue` | `T` | Initial value |
71
+ | `onChange` | `(value: T) => void` | Callback |
72
+ | `label` | `string` | Label |
73
+ | `name` | `string` | FormData name |
74
+ | `hint` | `string` | Hint text |
75
+ | `error` | `string` | Error text |
76
+ | `placeholder` | `string` | Placeholder |
77
+ | `disabled` | `boolean` | Disabled |
78
+ | `required` | `boolean` | Required |
79
+
80
+ ### Example
81
+ ```tsx
82
+ const options = [
83
+ { data: 1, label: 'Option A' },
84
+ { data: 2, label: 'Option B' },
85
+ { data: 3, label: 'Option C' },
86
+ ];
87
+
88
+ <Select label="Selection" options={options} defaultValue={1} />
89
+ ```
90
+
91
+ ### Controlled
92
+ ```tsx
93
+ const [value, setValue] = useState(1);
94
+ <Select label="Selection" options={options} value={value} onChange={setValue} />
95
+ ```
96
+
97
+ ---
98
+
99
+ ## ComboBox
100
+
101
+ Searchable dropdown (Select with text input).
102
+
103
+ ### Props
104
+ Same as `Select`, plus:
105
+ | Prop | Type | Description |
106
+ |------|------|-------------|
107
+ | `onInputChange` | `(value: string) => void` | Callback on text input |
108
+ | `emptyMessage` | `string` | Text when no results |
109
+
110
+ ### Example
111
+ ```tsx
112
+ <ComboBox label="Search" options={options} defaultValue={2} />
113
+ ```
114
+
115
+ ---
116
+
117
+ ## MultiSelect
118
+
119
+ Multi-selection dropdown.
120
+
121
+ ### Props
122
+ | Prop | Type | Description |
123
+ |------|------|-------------|
124
+ | `options` | `SelectOption<T>[]` | Options |
125
+ | `value` | `T[]` | Controlled: selected values |
126
+ | `defaultValue` | `T[]` | Initial values |
127
+ | `onChange` | `(value: T[]) => void` | Callback |
128
+ | `label` | `string` | Label |
129
+ | `name` | `string` | FormData name |
130
+ | `hint` | `string` | Hint text |
131
+ | `error` | `string` | Error text |
132
+ | `placeholder` | `string` | Placeholder |
133
+ | `disabled` | `boolean` | Disabled |
134
+
135
+ ### Example
136
+ ```tsx
137
+ <MultiSelect
138
+ label="Categories"
139
+ options={options}
140
+ defaultValue={[1, 3]}
141
+ placeholder="Select..."
142
+ />
143
+ ```
144
+
145
+ ---
146
+
147
+ ## Checkbox
148
+
149
+ ### Props
150
+ | Prop | Type | Default | Description |
151
+ |------|------|---------|-------------|
152
+ | `checked` | `boolean` | — | Controlled |
153
+ | `defaultChecked` | `boolean` | — | Initial value |
154
+ | `onChange` | `(value: boolean, event) => void` | — | Callback |
155
+ | `large` | `boolean` | `false` | Large |
156
+ | `valid` | `boolean` | `true` | Validation status |
157
+ | `labelPosition` | `"after" \| "before"` | `"after"` | Label position |
158
+ | `indeterminate` | `boolean` | `false` | Indeterminate state |
159
+
160
+ ### Example
161
+ ```tsx
162
+ <Checkbox id="terms" name="acceptTerms">Accept terms</Checkbox>
163
+ <Checkbox id="large" large>Large checkbox</Checkbox>
164
+ <Checkbox valid={false}>Invalid</Checkbox>
165
+ <Checkbox indeterminate>Partial</Checkbox>
166
+ ```
167
+
168
+ ---
169
+
170
+ ## RadioGroup / RadioButton
171
+
172
+ ### RadioGroup Props
173
+ | Prop | Type | Default | Description |
174
+ |------|------|---------|-------------|
175
+ | `value` | `string` | — | Controlled |
176
+ | `defaultValue` | `string` | — | Initial value |
177
+ | `onValueChange` | `(value: string) => void` | — | Callback |
178
+ | `name` | `string` | — | FormData name |
179
+ | `large` | `boolean` | `false` | Large |
180
+ | `labelPosition` | `"after" \| "before" \| "below"` | `"after"` | Label position |
181
+ | `disabled` | `boolean` | `false` | Disabled |
182
+ | `required` | `boolean` | `false` | Required |
183
+
184
+ ### RadioButton Props
185
+ | Prop | Type | Description |
186
+ |------|------|-------------|
187
+ | `value` | `string` | **Required.** Value |
188
+ | `disabled` | `boolean` | Individually disabled |
189
+
190
+ ### Example
191
+ ```tsx
192
+ <RadioGroup name="color" defaultValue="blue">
193
+ <RadioButton value="red">Red</RadioButton>
194
+ <RadioButton value="blue">Blue</RadioButton>
195
+ <RadioButton value="green">Green</RadioButton>
196
+ </RadioGroup>
197
+ ```
198
+
199
+ ### Controlled
200
+ ```tsx
201
+ const [value, setValue] = useState('blue');
202
+ <RadioGroup value={value} onValueChange={setValue}>
203
+ <RadioButton value="red">Red</RadioButton>
204
+ <RadioButton value="blue">Blue</RadioButton>
205
+ </RadioGroup>
206
+ ```
207
+
208
+ ---
209
+
210
+ ## Segment / SegmentControl
211
+
212
+ Segmented control (toggle button group).
213
+
214
+ ### Segment Props
215
+ | Prop | Type | Description |
216
+ |------|------|-------------|
217
+ | `legend` | `string` | **Required.** Description |
218
+ | `config` | `SegmentConfiguration` | `{ outline?: boolean, iconOnly?: boolean }` |
219
+ | `value` | `any` | Controlled |
220
+ | `onChange` | `(value, event) => void` | Callback |
221
+
222
+ ### SegmentControl Props
223
+ | Prop | Type | Description |
224
+ |------|------|-------------|
225
+ | `label` | `string` | **Required.** Label |
226
+ | `value` | `any` | **Required.** Value |
227
+ | `icon` | `ReactNode` | Icon |
228
+ | `checked` | `boolean` | Selected |
229
+ | `iconOnly` | `boolean` | Show icon only |
230
+
231
+ ### Example
232
+ ```tsx
233
+ <Segment legend="Choose view">
234
+ <SegmentControl name="view" label="List" value="list" />
235
+ <SegmentControl name="view" label="Tiles" value="grid" />
236
+ <SegmentControl name="view" label="Table" value="table" />
237
+ </Segment>
238
+ ```
239
+
240
+ ---
241
+
242
+ ## Switch
243
+
244
+ Toggle switch.
245
+
246
+ ### Props
247
+ | Prop | Type | Default | Description |
248
+ |------|------|---------|-------------|
249
+ | `title` | `string` | — | **Required.** Label (also for accessibility) |
250
+ | `value` | `boolean` | — | Controlled |
251
+ | `defaultValue` | `boolean` | — | Initial value |
252
+ | `onChange` | `(value: boolean, event) => void` | — | Callback |
253
+ | `labelPosition` | `"after" \| "before" \| "below"` | `"after"` | Label position |
254
+ | `large` | `boolean` | `false` | Large |
255
+
256
+ ### Example
257
+ ```tsx
258
+ <Switch title="Notifications" defaultValue={true} />
259
+ <Switch title="Large" large labelPosition="before" />
260
+ ```
261
+
262
+ ---
263
+
264
+ ## Slider
265
+
266
+ Range slider.
267
+
268
+ ### Props
269
+ | Prop | Type | Default | Description |
270
+ |------|------|---------|-------------|
271
+ | `min` | `number` | — | **Required.** Minimum |
272
+ | `max` | `number` | — | **Required.** Maximum |
273
+ | `value` | `number` | — | **Required.** Value |
274
+ | `step` | `number` | — | Step size |
275
+ | `onChange` | `(value: number, event) => void` | — | Callback on change |
276
+ | `onChangeCommitted` | `(value: number) => void` | — | Callback on release |
277
+ | `label` | `string` | — | Label |
278
+ | `showValue` | `boolean` | `true` | Show value |
279
+
280
+ ### Example
281
+ ```tsx
282
+ const [value, setValue] = useState(50);
283
+ <Slider min={0} max={100} value={value} onChange={setValue} label="Volume" />
284
+ ```
285
+
286
+ ---
287
+
288
+ ## TimePicker
289
+
290
+ Time selection.
291
+
292
+ ### Props
293
+ | Prop | Type | Description |
294
+ |------|------|-------------|
295
+ | `value` | `Date` | Controlled |
296
+ | `defaultValue` | `Date` | Initial value |
297
+ | `name` | `string` | FormData name |
298
+ | `onChange` | `(date: Date) => void` | Callback |
299
+ | `options` | `TimePickerOptions` | Configuration |
300
+ | `formatDate` | `(date: Date) => string` | Formatting |
301
+ | `disabled` | `boolean` | Disabled |
302
+ | `required` | `boolean` | Required |
303
+ | `error` | `string` | Error text |
304
+ | `hint` | `string` | Hint text |
305
+
306
+ ### TimePickerOptions
307
+ ```ts
308
+ {
309
+ timeFormat?: '12' | '24',
310
+ showSeconds?: boolean,
311
+ minuteStepSize?: number,
312
+ range?: { minValue: Date, maxValue: Date },
313
+ }
314
+ ```
315
+
316
+ ### Example
317
+ ```tsx
318
+ <TimePicker defaultValue={new Date()} style={{ width: 330 }}>
319
+ Time
320
+ </TimePicker>
321
+ ```
322
+
323
+ ### 12h format with seconds
324
+ ```tsx
325
+ <TimePicker
326
+ value={date}
327
+ onChange={setDate}
328
+ options={{ timeFormat: '12', showSeconds: true }}
329
+ formatDate={Intl.DateTimeFormat('en-US', { hour: 'numeric', minute: 'numeric', second: 'numeric' }).format}
330
+ >
331
+ Time AM/PM
332
+ </TimePicker>
333
+ ```
@@ -0,0 +1,75 @@
1
+ # Installation & Setup
2
+
3
+ ## Installation
4
+
5
+ ```bash
6
+ npm install @festo-ui/react
7
+ ```
8
+
9
+ ## Including CSS
10
+
11
+ The library requires its CSS stylesheet. Import it once at the root of your application:
12
+
13
+ ```tsx
14
+ import '@festo-ui/react/index.css';
15
+ ```
16
+
17
+ ## Imports
18
+
19
+ All components are exported as named exports from the main package:
20
+
21
+ ```tsx
22
+ import { Button, TextInput, Select, Modal, Accordion } from '@festo-ui/react';
23
+ ```
24
+
25
+ ### Complete Export List
26
+
27
+ **Components:**
28
+ - `Accordion`, `AccordionHeader`, `AccordionItem`, `AccordionItemBody`, `AccordionItemHeader`
29
+ - `BottomSheet`
30
+ - `Breadcrumb`
31
+ - `Button`
32
+ - `Card`, `CardBody`, `CardHeader`, `CardNotification`
33
+ - `Chip`, `ChipContainer`, `ChipType`
34
+ - `LoadingIndicator`
35
+ - `MobileFlyout`, `MobileFlyoutItem`, `MobileFlyoutPage`
36
+ - `AlertModal`, `ConfirmModal`, `CustomModal`, `Prompt`
37
+ - `ImageGallery`, `ImageGalleryContent`, `ImageGallerySwiper`, `ImageGalleryThumbsSwiper`
38
+ - `Pagination`
39
+ - `Popover`, `PopoverMenu`, `PopoverMenuItem`, `PopoverMenuContext`, `Tooltip`, `Legend`
40
+ - `Progress`
41
+ - `SearchInput`, `SearchInputOption`, `SearchResult`
42
+ - `Snackbar`, `SnackbarProvider`, `addSnackbar`, `useSnackbar`
43
+ - `StepperVertical`, `StepVertical`, `StepperHorizontal`, `StepHorizontal`
44
+ - `Tabs`, `TabPane`
45
+ - `TableHeaderCell`
46
+
47
+ **Forms:**
48
+ - `Checkbox`
49
+ - `ComboBox`
50
+ - `MultiSelect`
51
+ - `RadioGroup`, `RadioButton`
52
+ - `Segment`, `SegmentControl`
53
+ - `Select`
54
+ - `Slider`
55
+ - `Switch`
56
+ - `TextArea`
57
+ - `TextInput`
58
+ - `TimePicker`
59
+
60
+ **Types (TypeScript):**
61
+ All components export their props types, e.g. `ButtonProps`, `TextInputProps`, `SelectProps`, etc.
62
+
63
+ ## CSS Utility Classes
64
+
65
+ The library uses CSS classes with the prefix `fwe-`. Commonly used:
66
+
67
+ - Layout: `fwe-grid`, `fwe-col-{n}`, `fwe-container`, `fwe-d-flex`
68
+ - Spacing: `fwe-m-{size}`, `fwe-p-{size}`, `fwe-mt-{size}`, `fwe-mb-{size}`, `fwe-mr-{size}`, `fwe-ml-{size}`, `fwe-my-{size}`, `fwe-mx-{size}`
69
+ - Sizes: `xxxs`, `xxs`, `xs`, `s`, `m`, `l`, `xl`, `xxl`
70
+ - Buttons: `fwe-btn`, `fwe-btn-hero`, `fwe-btn-icon`, `fwe-btn-link`, `fwe-btn-lg`, `fwe-btn-block`
71
+ - Colors: `fwe-bg-white`, `fwe-bg-background`, `fwe-bg-black`, `fwe-bg-gray-300`, `fwe-color-red`
72
+ - Flex: `fwe-align-items-center`, `fwe-mr-auto`, `fwe-ml-auto`
73
+ - Table: `fwe-table`, `fwe-tr-sm`, `fwe-tr-md`, `fwe-tr-lg`
74
+ - Text: `fwe-font-size-small`
75
+ - Other: `fwe-dark`, `fwe-b`
@@ -0,0 +1,179 @@
1
+ # Patterns & Best Practices
2
+
3
+ ## Controlled vs. Uncontrolled
4
+
5
+ All form components support both modes:
6
+
7
+ ### Uncontrolled (simpler)
8
+ State is managed internally. Use `defaultValue` / `defaultChecked`:
9
+ ```tsx
10
+ <TextInput label="Name" defaultValue="Max" />
11
+ <Checkbox defaultChecked>Option</Checkbox>
12
+ <Select defaultValue={1} options={options} />
13
+ <RadioGroup defaultValue="a"><RadioButton value="a">A</RadioButton></RadioGroup>
14
+ ```
15
+
16
+ ### Controlled (full control)
17
+ State is managed externally. Use `value` + `onChange`:
18
+ ```tsx
19
+ const [value, setValue] = useState('');
20
+ <TextInput label="Name" value={value} onChange={setValue} />
21
+ ```
22
+
23
+ **Note:** The `onChange` signature varies by component:
24
+ - `TextInput`, `TextArea`: `(value: string, event) => void`
25
+ - `Select`, `ComboBox`: `(value: T) => void`
26
+ - `MultiSelect`: `(value: T[]) => void`
27
+ - `Checkbox`: `(value: boolean, event) => void`
28
+ - `Switch`: `(value: boolean, event) => void`
29
+ - `RadioGroup`: `onValueChange: (value: string) => void`
30
+ - `Slider`: `(value: number, event) => void`
31
+ - `TimePicker`: `(date: Date) => void`
32
+
33
+ ---
34
+
35
+ ## FormData Integration
36
+
37
+ All form components support native FormData via the `name` prop:
38
+
39
+ ```tsx
40
+ function handleSubmit(event) {
41
+ event.preventDefault();
42
+ const formData = new FormData(event.currentTarget);
43
+ const value = formData.get('fieldName');
44
+ }
45
+
46
+ <form onSubmit={handleSubmit}>
47
+ <TextInput name="username" label="Username" />
48
+ <Select name="role" label="Role" options={roleOptions} />
49
+ <Checkbox name="acceptTerms">Accept terms</Checkbox>
50
+ <Switch name="notifications" title="Notifications" />
51
+ <RadioGroup name="color">
52
+ <RadioButton value="red">Red</RadioButton>
53
+ <RadioButton value="blue">Blue</RadioButton>
54
+ </RadioGroup>
55
+ <MultiSelect name="categories" label="Categories" options={catOptions} />
56
+ <TimePicker name="meetingTime">Time</TimePicker>
57
+ <Slider name="volume" min={0} max={100} value={50} label="Volume" />
58
+ <button className="fwe-btn fwe-btn-hero" type="submit">Submit</button>
59
+ </form>
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Validation
65
+
66
+ ### Error display
67
+ Most form components have an `error` prop:
68
+ ```tsx
69
+ <TextInput label="Email" error="Invalid email address" />
70
+ <Select label="Selection" error="Please select" options={options} />
71
+ <TextArea label="Text" error="Required field" />
72
+ ```
73
+
74
+ ### HTML5 validation
75
+ ```tsx
76
+ <TextInput label="Name" required minLength={3} />
77
+ <TextArea label="Text" required maxLength={500} />
78
+ ```
79
+
80
+ ### Checkbox validation
81
+ ```tsx
82
+ <Checkbox valid={false}>Invalid option</Checkbox>
83
+ ```
84
+
85
+ ---
86
+
87
+ ## Hint Texts
88
+
89
+ Many components support `hint` for help text:
90
+ ```tsx
91
+ <TextInput label="Email" hint="e.g. max@example.com" />
92
+ <Select label="Role" hint="Choose your primary role" options={options} />
93
+ <TimePicker hint="Please select a time">Time</TimePicker>
94
+ ```
95
+
96
+ ---
97
+
98
+ ## CSS Classes for Layout
99
+
100
+ ### Grid System
101
+ ```tsx
102
+ <div className="fwe-grid">
103
+ <div className="fwe-col-4">1/3 width</div>
104
+ <div className="fwe-col-8">2/3 width</div>
105
+ </div>
106
+ ```
107
+
108
+ ### Container
109
+ ```tsx
110
+ <div className="fwe-container">Centered container</div>
111
+ ```
112
+
113
+ ### Buttons with CSS classes (alternative to Button component)
114
+ ```tsx
115
+ <button className="fwe-btn">Default</button>
116
+ <button className="fwe-btn fwe-btn-hero">Primary</button>
117
+ <button className="fwe-btn fwe-btn-lg">Large</button>
118
+ <button className="fwe-btn fwe-btn-block">Full width</button>
119
+ <button className="fwe-btn fwe-btn-icon"><Icon /></button>
120
+ <button className="fwe-btn fwe-btn-link fwe-dark">Link</button>
121
+ ```
122
+
123
+ ### Spacing
124
+ Prefix `fwe-m-` (margin) and `fwe-p-` (padding), suffixes:
125
+ - Direction: `t` (top), `b` (bottom), `l` (left), `r` (right), `x` (horizontal), `y` (vertical)
126
+ - Sizes: `xxxs`, `xxs`, `xs`, `s`, `m`, `l`, `xl`, `xxl`
127
+
128
+ ```tsx
129
+ <div className="fwe-mt-m fwe-mb-s fwe-px-l">Content with spacing</div>
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Navbar Structure
135
+
136
+ ```tsx
137
+ <header className="fwe-fixed-header">
138
+ <nav className="fwe-navbar">
139
+ <div className="fwe-container">
140
+ <MobileFlyout className="fwe-mr-auto">...</MobileFlyout>
141
+ <div className="fwe-logo-container">
142
+ <div className="fwe-festo-logo" />
143
+ </div>
144
+ </div>
145
+ </nav>
146
+ </header>
147
+ <div className="fwe-navbar-spacer" />
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Tables
153
+
154
+ ```tsx
155
+ <table className="fwe-table">
156
+ <thead>
157
+ <tr>
158
+ <TableHeaderCell ascending={ascending} active={orderBy === 'name'} onClick={...}>
159
+ Name
160
+ </TableHeaderCell>
161
+ </tr>
162
+ </thead>
163
+ <tbody>
164
+ <tr className="fwe-tr-md"><td>Content</td></tr>
165
+ <tr className="fwe-tr-lg"><td>Content</td></tr>
166
+ <tr className="fwe-tr-sm"><td>Content</td></tr>
167
+ </tbody>
168
+ </table>
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Important Notes
174
+
175
+ 1. **Import CSS:** Always include `import '@festo-ui/react/index.css'`
176
+ 2. **Icons:** Icons are provided separately (e.g. `IconCoreRangeProduct`, `IconSettings`, `IconMore`, `IconDownload`, `IconDelete`, `IconInfo`, `IconWarning`, `IconClose`, `IconCheckSmall`, `IconWorksheet`, `IconMessage`, `IconGridView`, `IconListView`)
177
+ 3. **Snackbar:** Requires `<SnackbarProvider>` as wrapper
178
+ 4. **Modals:** All modals are controlled via `isOpen` + `onClose`
179
+ 5. **All components** accept standard HTML attributes like `className`, `style`, `data-testid`, etc.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@festo-ui/react",
3
- "version": "10.1.0-dev.875",
3
+ "version": "10.1.1-dev.918",
4
4
  "author": "Festo UI (styleguide@festo.com)",
5
5
  "copyright": "Copyright (c) 2025 Festo SE & Co. KG. All rights reserved.",
6
6
  "license": "apache-2.0",
@@ -16,7 +16,8 @@
16
16
  "module": "./dist/index.js",
17
17
  "types": "./dist/index.d.ts",
18
18
  "files": [
19
- "dist"
19
+ "dist",
20
+ "llm-doc"
20
21
  ],
21
22
  "sideEffects": [
22
23
  "**/*.css"
@@ -44,6 +45,7 @@
44
45
  "devDependencies": {
45
46
  "@biomejs/biome": "2.3.2",
46
47
  "@chromatic-com/storybook": "^5.0.0",
48
+ "@festo-ui/web-essentials": "*",
47
49
  "@rsbuild/core": "~1.6.2",
48
50
  "@rsbuild/plugin-react": "^1.4.1",
49
51
  "@rsbuild/plugin-sass": "^1.4.0",
@@ -52,6 +54,7 @@
52
54
  "@rstest/core": "^0.6.5",
53
55
  "@rstest/coverage-istanbul": "^0.0.5",
54
56
  "@storybook/addon-docs": "^10.2.3",
57
+ "@storybook/addon-mcp": "^0.6.0",
55
58
  "@testing-library/dom": "^10.4.0",
56
59
  "@testing-library/jest-dom": "^6.9.1",
57
60
  "@testing-library/react": "^16.3.0",