@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.
- package/dist/components/pagination/Pagination.d.ts +1 -5
- package/dist/components/pagination/Pagination.js +6 -12
- package/dist/components/popovers/popover/Popover.js +11 -4
- package/dist/components/search-input/SearchInput.css +12 -0
- package/dist/components/search-input/SearchInput.d.ts +18 -6
- package/dist/components/search-input/SearchInput.js +82 -58
- package/dist/components/search-input/SearchInputOption.d.ts +5 -0
- package/dist/components/search-input/SearchInputOption.js +18 -0
- package/dist/components/search-input/SearchResult.d.ts +8 -0
- package/dist/components/search-input/SearchResult.js +48 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -2
- package/llm-doc/README.md +20 -0
- package/llm-doc/components.md +661 -0
- package/llm-doc/forms.md +333 -0
- package/llm-doc/installation.md +75 -0
- package/llm-doc/patterns.md +179 -0
- package/package.json +5 -2
- package/dist/components/search-input/ClearButton.d.ts +0 -1
- package/dist/components/search-input/ClearButton.js +0 -11
- package/dist/components/search-input/SearchSuggestion.d.ts +0 -17
- package/dist/components/search-input/SearchSuggestion.js +0 -21
- package/dist/components/search-input/useSearchInput.d.ts +0 -13
- package/dist/components/search-input/useSearchInput.js +0 -85
package/llm-doc/forms.md
ADDED
|
@@ -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.
|
|
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",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const ClearButton: (props: Omit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & import("react").RefAttributes<HTMLButtonElement>) => React.ReactElement | null;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef } from "react";
|
|
3
|
-
const ClearButton = /*#__PURE__*/ forwardRef((props, ref)=>/*#__PURE__*/ jsx("button", {
|
|
4
|
-
type: "button",
|
|
5
|
-
className: "fwe-clear-icon fr-search-input-clear-button",
|
|
6
|
-
"aria-label": "Clear",
|
|
7
|
-
ref: ref,
|
|
8
|
-
...props
|
|
9
|
-
}));
|
|
10
|
-
ClearButton.displayName = 'ClearButton';
|
|
11
|
-
export { ClearButton };
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export declare class SearchSuggestion {
|
|
2
|
-
/**
|
|
3
|
-
* a html-string. e.g.: '<b> hello </b>'
|
|
4
|
-
*/
|
|
5
|
-
template: string;
|
|
6
|
-
/**
|
|
7
|
-
* This Value will be used as new query when the user selects the suggestion.
|
|
8
|
-
*/
|
|
9
|
-
value: string;
|
|
10
|
-
/**
|
|
11
|
-
* Creates a basic Suggestion from a string. The first query match is highlighted by bold tags.
|
|
12
|
-
* @param suggestionString The suggested string (should contain the whole query)
|
|
13
|
-
* @param query The current query. This string will be highlighted.
|
|
14
|
-
* @returns a html-string.
|
|
15
|
-
*/
|
|
16
|
-
static basicSuggestion(suggestionString: string, query: string): SearchSuggestion;
|
|
17
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
class SearchSuggestion {
|
|
2
|
-
template;
|
|
3
|
-
value;
|
|
4
|
-
static basicSuggestion(suggestionString, query) {
|
|
5
|
-
const i = suggestionString.toLocaleLowerCase().indexOf(query.toLocaleLowerCase());
|
|
6
|
-
let template = suggestionString;
|
|
7
|
-
if (-1 !== i) {
|
|
8
|
-
const boldStart = i;
|
|
9
|
-
const boldEnd = i + query.length;
|
|
10
|
-
const part1 = suggestionString.substring(0, boldStart);
|
|
11
|
-
const part2 = suggestionString.substring(boldStart, boldEnd);
|
|
12
|
-
const part3 = suggestionString.substring(boldEnd, suggestionString.length);
|
|
13
|
-
template = `${part1}<strong>${part2}</strong>${part3}`;
|
|
14
|
-
}
|
|
15
|
-
return {
|
|
16
|
-
value: suggestionString,
|
|
17
|
-
template
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
export { SearchSuggestion };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type React from 'react';
|
|
2
|
-
import type { SearchSuggestion } from './SearchSuggestion';
|
|
3
|
-
export declare function useSearchInput(inputRef: React.RefObject<HTMLInputElement | null>, cappedSuggestions: SearchSuggestion[], value?: string, defaultValue?: string, onChange?: (value: string) => void, onSearch?: (value: string) => void, onKeyboardNavigate?: (value: string) => void): {
|
|
4
|
-
innerValue: string | undefined;
|
|
5
|
-
hideSuggestionList: boolean;
|
|
6
|
-
selectedSuggestionIndex: number;
|
|
7
|
-
handleClearQuery: () => void;
|
|
8
|
-
handleFocus: () => void;
|
|
9
|
-
handleInput: (event: any) => void;
|
|
10
|
-
handleSuggestionClick: (suggestion: SearchSuggestion) => void;
|
|
11
|
-
handleOutsideClick: () => void;
|
|
12
|
-
handleKeyDown: (event: React.KeyboardEvent) => void;
|
|
13
|
-
};
|