@festo-ui/react 10.1.0 → 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.
@@ -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
+ ```