@bspk/ui 1.1.17 → 1.1.19
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/Avatar.d.ts +17 -6
- package/dist/Avatar.js +15 -6
- package/dist/Avatar.js.map +1 -1
- package/dist/AvatarGroup.d.ts +49 -0
- package/dist/AvatarGroup.js +18 -0
- package/dist/AvatarGroup.js.map +1 -0
- package/dist/Badge.js +1 -1
- package/dist/Button.d.ts +14 -4
- package/dist/Button.js +1 -1
- package/dist/Button.js.map +1 -1
- package/dist/Checkbox.d.ts +15 -2
- package/dist/Checkbox.js.map +1 -1
- package/dist/CheckboxGroup.d.ts +6 -3
- package/dist/CheckboxGroup.js.map +1 -1
- package/dist/CheckboxOption.d.ts +8 -1
- package/dist/CheckboxOption.js.map +1 -1
- package/dist/Chip.d.ts +3 -1
- package/dist/Chip.js.map +1 -1
- package/dist/Dialog.d.ts +3 -3
- package/dist/Dialog.js.map +1 -1
- package/dist/Divider.js +1 -1
- package/dist/Dropdown.d.ts +33 -7
- package/dist/Dropdown.js +5 -5
- package/dist/Dropdown.js.map +1 -1
- package/dist/ListItem.js +1 -1
- package/dist/Menu.d.ts +40 -21
- package/dist/Menu.js +63 -41
- package/dist/Menu.js.map +1 -1
- package/dist/NumberInput.d.ts +5 -1
- package/dist/NumberInput.js +7 -5
- package/dist/NumberInput.js.map +1 -1
- package/dist/Portal.d.ts +5 -1
- package/dist/Portal.js.map +1 -1
- package/dist/ProgressBar.d.ts +4 -0
- package/dist/ProgressBar.js.map +1 -1
- package/dist/ProgressionStepper.d.ts +9 -2
- package/dist/ProgressionStepper.js +1 -1
- package/dist/ProgressionStepper.js.map +1 -1
- package/dist/ProgressionStepperBar.d.ts +6 -0
- package/dist/ProgressionStepperBar.js.map +1 -1
- package/dist/Radio.d.ts +16 -2
- package/dist/Radio.js +2 -2
- package/dist/Radio.js.map +1 -1
- package/dist/RadioGroup.d.ts +26 -3
- package/dist/RadioGroup.js +3 -3
- package/dist/RadioGroup.js.map +1 -1
- package/dist/RadioOption.d.ts +9 -1
- package/dist/RadioOption.js.map +1 -1
- package/dist/SearchBar.d.ts +30 -4
- package/dist/SearchBar.js +16 -15
- package/dist/SearchBar.js.map +1 -1
- package/dist/SegmentedControl.d.ts +21 -2
- package/dist/SegmentedControl.js +1 -1
- package/dist/SegmentedControl.js.map +1 -1
- package/dist/Switch.d.ts +1 -1
- package/dist/SwitchGroup.d.ts +13 -6
- package/dist/SwitchGroup.js +1 -1
- package/dist/SwitchGroup.js.map +1 -1
- package/dist/TabGroup.d.ts +23 -5
- package/dist/TabGroup.js +1 -1
- package/dist/TabGroup.js.map +1 -1
- package/dist/Tag.d.ts +5 -2
- package/dist/Tag.js +1 -1
- package/dist/Tag.js.map +1 -1
- package/dist/TextInput.d.ts +15 -6
- package/dist/TextInput.js +11 -5
- package/dist/TextInput.js.map +1 -1
- package/dist/Textarea.d.ts +3 -3
- package/dist/avatar-group.css +1 -0
- package/dist/avatar.css +1 -1
- package/dist/badge.css +1 -1
- package/dist/button.css +1 -1
- package/dist/demo/ExampleModalRender.d.ts +7 -0
- package/dist/demo/ExampleModalRender.js +16 -0
- package/dist/demo/ExampleModalRender.js.map +1 -0
- package/dist/demo/ExamplePlaceholder.d.ts +7 -0
- package/dist/demo/ExamplePlaceholder.js +13 -0
- package/dist/demo/ExamplePlaceholder.js.map +1 -0
- package/dist/demo/examples.d.ts +101 -0
- package/dist/demo/examples.js +483 -0
- package/dist/demo/examples.js.map +1 -0
- package/dist/divider.css +1 -1
- package/dist/dropdown.css +1 -1
- package/dist/hooks/useKeyboardNavigation.js +5 -2
- package/dist/hooks/useKeyboardNavigation.js.map +1 -1
- package/dist/hooks/useOptionIconsInvalid.d.ts +10 -1
- package/dist/hooks/useOptionIconsInvalid.js.map +1 -1
- package/dist/index.d.ts +4 -26
- package/dist/index.js.map +1 -1
- package/dist/list-item.css +1 -1
- package/dist/menu.css +1 -1
- package/dist/segmented-control.css +1 -1
- package/dist/tab-group.css +1 -1
- package/dist/tag.css +1 -1
- package/dist/text-input.css +1 -1
- package/dist/utils/children.js.map +1 -1
- package/meta-types.ts +2 -0
- package/meta.ts +76 -42
- package/package.json +1 -1
- package/src/Avatar.tsx +35 -8
- package/src/AvatarGroup.tsx +71 -0
- package/src/Button.tsx +14 -4
- package/src/Checkbox.tsx +25 -11
- package/src/CheckboxGroup.tsx +6 -3
- package/src/CheckboxOption.tsx +9 -2
- package/src/Chip.tsx +3 -1
- package/src/Dialog.tsx +3 -3
- package/src/Dropdown.tsx +40 -11
- package/src/Menu.tsx +159 -108
- package/src/NumberInput.tsx +15 -6
- package/src/Portal.tsx +5 -1
- package/src/ProgressBar.tsx +4 -0
- package/src/ProgressionStepper.tsx +9 -2
- package/src/ProgressionStepperBar.tsx +6 -0
- package/src/Radio.tsx +21 -4
- package/src/RadioGroup.tsx +34 -6
- package/src/RadioOption.tsx +11 -2
- package/src/SearchBar.tsx +87 -44
- package/src/SegmentedControl.tsx +21 -2
- package/src/Switch.tsx +1 -1
- package/src/SwitchGroup.tsx +19 -7
- package/src/TabGroup.tsx +23 -5
- package/src/Tag.tsx +5 -2
- package/src/TextInput.tsx +25 -15
- package/src/Textarea.tsx +3 -3
- package/src/avatar-group.scss +17 -0
- package/src/avatar.scss +26 -2
- package/src/badge.scss +1 -0
- package/src/button.scss +1 -0
- package/src/demo/ExampleModalRender.tsx +37 -0
- package/src/demo/ExamplePlaceholder.tsx +40 -0
- package/src/demo/examples.tsx +699 -0
- package/src/divider.scss +2 -0
- package/src/dropdown.scss +5 -0
- package/src/hooks/useKeyboardNavigation.ts +3 -2
- package/src/hooks/useOptionIconsInvalid.ts +10 -1
- package/src/index.ts +5 -32
- package/src/list-item.scss +5 -1
- package/src/menu.scss +5 -1
- package/src/segmented-control.scss +1 -0
- package/src/tab-group.scss +1 -0
- package/src/tag.scss +1 -0
- package/src/text-input.scss +13 -18
- package/src/utils/children.ts +1 -1
package/src/Menu.tsx
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import './menu.scss';
|
|
2
|
-
import { ComponentProps, CSSProperties,
|
|
2
|
+
import { ComponentProps, CSSProperties, ReactNode, useMemo } from 'react';
|
|
3
3
|
|
|
4
4
|
import { Checkbox } from './Checkbox';
|
|
5
5
|
import { ListItem } from './ListItem';
|
|
6
|
-
import { Txt } from './Txt';
|
|
7
6
|
import { useId } from './hooks/useId';
|
|
8
7
|
|
|
9
|
-
import { CommonProps, ElementProps } from './';
|
|
8
|
+
import { CommonProps, ElementProps, SetRef } from './';
|
|
9
|
+
|
|
10
|
+
const DEFAULT = {
|
|
11
|
+
selectAll: 'Select All',
|
|
12
|
+
};
|
|
10
13
|
|
|
11
14
|
export const MIN_ITEM_COUNT = 3;
|
|
12
15
|
export const MAX_ITEM_COUNT = 10;
|
|
@@ -16,12 +19,12 @@ export function menuItemId(menuId: string, index: number) {
|
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
/** The props for the renderListItem function. Useful for customizing menu list items. */
|
|
19
|
-
export type RenderListItemParams<
|
|
20
|
-
MenuProps<
|
|
22
|
+
export type RenderListItemParams<T extends MenuItem = MenuItem> = Pick<
|
|
23
|
+
MenuProps<T>,
|
|
21
24
|
'activeIndex' | 'isMulti' | 'selectedValues'
|
|
22
25
|
> & {
|
|
23
26
|
index: number;
|
|
24
|
-
item:
|
|
27
|
+
item: T;
|
|
25
28
|
menuId: string;
|
|
26
29
|
selected: boolean;
|
|
27
30
|
itemId?: string;
|
|
@@ -37,7 +40,7 @@ export type MenuItem = CommonProps<'disabled'> & {
|
|
|
37
40
|
id?: string;
|
|
38
41
|
};
|
|
39
42
|
|
|
40
|
-
export type MenuProps<
|
|
43
|
+
export type MenuProps<T extends MenuItem = MenuItem> = CommonProps<'disabled' | 'id'> & {
|
|
41
44
|
/**
|
|
42
45
|
* The number of items to display in the menu
|
|
43
46
|
*
|
|
@@ -49,17 +52,27 @@ export type MenuProps<Item extends MenuItem = MenuItem> = CommonProps<'disabled'
|
|
|
49
52
|
/**
|
|
50
53
|
* Content to display in the menu.
|
|
51
54
|
*
|
|
52
|
-
* @
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
*
|
|
55
|
+
* @example
|
|
56
|
+
* [
|
|
57
|
+
* { value: '1', label: 'Option 1' },
|
|
58
|
+
* { value: '2', label: 'Option 2' },
|
|
59
|
+
* { value: '3', label: 'Option 3' },
|
|
60
|
+
* { value: '4', label: 'Option 4' },
|
|
61
|
+
* { value: '5', label: 'Option 5' },
|
|
62
|
+
* { value: '6', label: 'Option 6' },
|
|
63
|
+
* { value: '7', label: 'Option 7' },
|
|
64
|
+
* { value: '8', label: 'Option 8' },
|
|
65
|
+
* { value: '9', label: 'Option 9' },
|
|
66
|
+
* { value: '10', label: 'Option 10' },
|
|
67
|
+
* ];
|
|
59
68
|
*
|
|
60
|
-
* @type
|
|
69
|
+
* @type Array<MenuItem>
|
|
61
70
|
*/
|
|
62
|
-
|
|
71
|
+
items?: T[];
|
|
72
|
+
/** A ref to the inner div element. */
|
|
73
|
+
innerRef?: SetRef<HTMLDivElement>;
|
|
74
|
+
/** Message to display when no results are found */
|
|
75
|
+
noResultsMessage?: ReactNode;
|
|
63
76
|
/** The index of the currently highlighted item. */
|
|
64
77
|
activeIndex?: number;
|
|
65
78
|
/** The values of the selected items */
|
|
@@ -71,22 +84,31 @@ export type MenuProps<Item extends MenuItem = MenuItem> = CommonProps<'disabled'
|
|
|
71
84
|
* @param {RenderListItemParams} props
|
|
72
85
|
* @returns {ComponentProps<typeof ListItem>}
|
|
73
86
|
*/
|
|
74
|
-
renderListItem?: (props: RenderListItemParams<
|
|
87
|
+
renderListItem?: (props: RenderListItemParams<T>) => Partial<ComponentProps<typeof ListItem>>;
|
|
75
88
|
/**
|
|
76
89
|
* Whether the menu allows multiple selections.
|
|
77
90
|
*
|
|
78
91
|
* @default false
|
|
79
92
|
*/
|
|
80
93
|
isMulti?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* The label for the "Select All" option.
|
|
96
|
+
*
|
|
97
|
+
* Ignored if `isMulti` is false.
|
|
98
|
+
*
|
|
99
|
+
* If `isMulti` is `true`, defaults to "Select All". If a string, it will be used as the label. If false the select
|
|
100
|
+
* all option will not be rendered.
|
|
101
|
+
*
|
|
102
|
+
* @default false
|
|
103
|
+
*/
|
|
104
|
+
selectAll?: boolean | string;
|
|
81
105
|
/**
|
|
82
106
|
* The function to call when the selected values change.
|
|
83
107
|
*
|
|
84
|
-
* @
|
|
85
|
-
*
|
|
86
|
-
* @param {ChangeEvent} event
|
|
87
|
-
* @returns {void}
|
|
108
|
+
* @example
|
|
109
|
+
* (selectedValues, event) => setState({ selectedValues });
|
|
88
110
|
*/
|
|
89
|
-
onChange?: (selectedValues: string[], event?:
|
|
111
|
+
onChange?: (selectedValues: string[], event?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
|
90
112
|
};
|
|
91
113
|
|
|
92
114
|
/**
|
|
@@ -94,7 +116,7 @@ export type MenuProps<Item extends MenuItem = MenuItem> = CommonProps<'disabled'
|
|
|
94
116
|
*
|
|
95
117
|
* @name Menu
|
|
96
118
|
*/
|
|
97
|
-
function Menu
|
|
119
|
+
function Menu({
|
|
98
120
|
itemCount: itemCountProp = 5,
|
|
99
121
|
items: itemsProp = [],
|
|
100
122
|
noResultsMessage,
|
|
@@ -106,24 +128,39 @@ function Menu<Item extends MenuItem = MenuItem>({
|
|
|
106
128
|
id: idProp,
|
|
107
129
|
renderListItem,
|
|
108
130
|
isMulti,
|
|
131
|
+
selectAll: selectAllProp,
|
|
109
132
|
...props
|
|
110
|
-
}: ElementProps<MenuProps
|
|
133
|
+
}: ElementProps<MenuProps, 'div'>) {
|
|
111
134
|
const menuId = useId(idProp);
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
()
|
|
135
|
+
|
|
136
|
+
const selectAll = useMemo(() => {
|
|
137
|
+
if (!isMulti) return false;
|
|
138
|
+
if (selectAllProp && typeof selectAllProp === 'string') return selectAllProp;
|
|
139
|
+
return selectAllProp === true ? DEFAULT.selectAll : false;
|
|
140
|
+
}, [isMulti, selectAllProp]);
|
|
141
|
+
|
|
142
|
+
const { items, itemCount } = useMemo(() => {
|
|
143
|
+
const itemsNext = Array.isArray(itemsProp) ? itemsProp : [];
|
|
144
|
+
return {
|
|
145
|
+
items: itemsNext,
|
|
115
146
|
// Ensure itemCount is within the range of items.length
|
|
116
|
-
Math.min(
|
|
117
|
-
|
|
147
|
+
itemCount: Math.min(
|
|
148
|
+
itemsNext.length,
|
|
118
149
|
// pin itemCountProp to a range of 3 to 10
|
|
119
150
|
Math.max(MIN_ITEM_COUNT, Math.min(itemCountProp, MAX_ITEM_COUNT)),
|
|
120
151
|
),
|
|
121
|
-
|
|
152
|
+
};
|
|
153
|
+
}, [itemCountProp, itemsProp]);
|
|
154
|
+
|
|
155
|
+
const allSelected = useMemo(
|
|
156
|
+
() => !!(items.length && items.every((item) => selectedValues.includes(item.value))),
|
|
157
|
+
[items, selectedValues],
|
|
122
158
|
);
|
|
123
159
|
|
|
124
160
|
return (
|
|
125
161
|
<div
|
|
126
162
|
{...props}
|
|
163
|
+
aria-multiselectable={isMulti || undefined}
|
|
127
164
|
data-bspk="menu"
|
|
128
165
|
data-disabled={disabled || undefined}
|
|
129
166
|
data-item-count={itemCount || undefined}
|
|
@@ -133,87 +170,101 @@ function Menu<Item extends MenuItem = MenuItem>({
|
|
|
133
170
|
role="listbox"
|
|
134
171
|
style={{ ...props.style, '--item-count': itemCount } as CSSProperties}
|
|
135
172
|
>
|
|
136
|
-
{
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
<ListItem
|
|
155
|
-
{...renderProps}
|
|
156
|
-
active={activeIndex === index || undefined}
|
|
157
|
-
aria-disabled={item.disabled || undefined}
|
|
158
|
-
aria-posinset={index + 1}
|
|
159
|
-
aria-selected={selected || undefined}
|
|
160
|
-
as="button"
|
|
161
|
-
data-menu-item
|
|
162
|
-
data-selected={selected || undefined}
|
|
163
|
-
disabled={item.disabled || undefined}
|
|
164
|
-
id={itemId}
|
|
165
|
-
key={itemId}
|
|
166
|
-
label={renderProps?.label?.toString() || item.label?.toString()}
|
|
167
|
-
onClick={(event: ReactMouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
168
|
-
if (renderProps) renderProps?.onClick?.(event);
|
|
169
|
-
|
|
170
|
-
if (onChange) {
|
|
171
|
-
if (!isMulti) {
|
|
172
|
-
onChange?.([item.value], event);
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
onChange(
|
|
176
|
-
selected
|
|
177
|
-
? selectedValues.filter((value) => value !== item.value)
|
|
178
|
-
: [...selectedValues, item.value],
|
|
179
|
-
event,
|
|
180
|
-
);
|
|
181
|
-
}
|
|
173
|
+
{isMulti && selectAll && (
|
|
174
|
+
<ListItem
|
|
175
|
+
as="button"
|
|
176
|
+
data-selected={allSelected || undefined}
|
|
177
|
+
key="select-all"
|
|
178
|
+
label={selectAll}
|
|
179
|
+
onClick={(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
180
|
+
onChange?.(allSelected ? [] : items.map((item) => item.value), event);
|
|
181
|
+
}}
|
|
182
|
+
role="option"
|
|
183
|
+
tabIndex={-1}
|
|
184
|
+
trailing={
|
|
185
|
+
<Checkbox
|
|
186
|
+
aria-label={selectAll}
|
|
187
|
+
checked={!!allSelected}
|
|
188
|
+
name=""
|
|
189
|
+
onChange={(checked) => {
|
|
190
|
+
onChange?.(checked ? items.map((item) => item.value) : []);
|
|
182
191
|
}}
|
|
183
|
-
|
|
184
|
-
tabIndex={-1}
|
|
185
|
-
trailing={
|
|
186
|
-
isMulti ? (
|
|
187
|
-
<Checkbox
|
|
188
|
-
aria-label={item.label}
|
|
189
|
-
checked={selected}
|
|
190
|
-
name={item.value}
|
|
191
|
-
onChange={(checked) => {
|
|
192
|
-
onChange?.(
|
|
193
|
-
checked
|
|
194
|
-
? selectedValues.filter((value) => value !== item.value)
|
|
195
|
-
: [...selectedValues, item.value],
|
|
196
|
-
);
|
|
197
|
-
}}
|
|
198
|
-
value={item.value}
|
|
199
|
-
/>
|
|
200
|
-
) : (
|
|
201
|
-
renderProps?.trailing
|
|
202
|
-
)
|
|
203
|
-
}
|
|
192
|
+
value=""
|
|
204
193
|
/>
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
) : (
|
|
208
|
-
<>
|
|
209
|
-
<Txt as="div" variant="heading-h5">
|
|
210
|
-
No results found
|
|
211
|
-
</Txt>
|
|
212
|
-
<Txt as="div" variant="body-base">
|
|
213
|
-
{noResultsMessage}
|
|
214
|
-
</Txt>
|
|
215
|
-
</>
|
|
194
|
+
}
|
|
195
|
+
/>
|
|
216
196
|
)}
|
|
197
|
+
{items.length
|
|
198
|
+
? items.map((item, index) => {
|
|
199
|
+
const itemId = item.id || menuItemId(menuId, index);
|
|
200
|
+
|
|
201
|
+
const selected = Boolean(Array.isArray(selectedValues) && selectedValues.includes(item.value));
|
|
202
|
+
|
|
203
|
+
const renderProps = renderListItem?.({
|
|
204
|
+
activeIndex,
|
|
205
|
+
index,
|
|
206
|
+
item,
|
|
207
|
+
selectedValues,
|
|
208
|
+
isMulti,
|
|
209
|
+
menuId: menuId || '',
|
|
210
|
+
selected,
|
|
211
|
+
itemId,
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
<ListItem
|
|
216
|
+
{...renderProps}
|
|
217
|
+
active={activeIndex === index || undefined}
|
|
218
|
+
aria-disabled={item.disabled || undefined}
|
|
219
|
+
aria-posinset={index + 1}
|
|
220
|
+
aria-selected={selected || undefined}
|
|
221
|
+
as="button"
|
|
222
|
+
//data-selected={selected || undefined}
|
|
223
|
+
disabled={item.disabled || undefined}
|
|
224
|
+
id={itemId}
|
|
225
|
+
key={itemId}
|
|
226
|
+
label={renderProps?.label?.toString() || item.label?.toString()}
|
|
227
|
+
onClick={(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
228
|
+
if (renderProps) renderProps?.onClick?.(event);
|
|
229
|
+
|
|
230
|
+
if (onChange) {
|
|
231
|
+
if (!isMulti) {
|
|
232
|
+
onChange?.([item.value], event);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
onChange(
|
|
236
|
+
selected
|
|
237
|
+
? selectedValues.filter((value) => value !== item.value)
|
|
238
|
+
: [...selectedValues, item.value],
|
|
239
|
+
event,
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
}}
|
|
243
|
+
role="option"
|
|
244
|
+
tabIndex={-1}
|
|
245
|
+
trailing={
|
|
246
|
+
isMulti ? (
|
|
247
|
+
<Checkbox
|
|
248
|
+
aria-label={item.label}
|
|
249
|
+
checked={selected}
|
|
250
|
+
name={item.value}
|
|
251
|
+
onChange={(checked) => {
|
|
252
|
+
onChange?.(
|
|
253
|
+
checked
|
|
254
|
+
? selectedValues.filter((value) => value !== item.value)
|
|
255
|
+
: [...selectedValues, item.value],
|
|
256
|
+
);
|
|
257
|
+
}}
|
|
258
|
+
value={item.value}
|
|
259
|
+
/>
|
|
260
|
+
) : (
|
|
261
|
+
renderProps?.trailing
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
/>
|
|
265
|
+
);
|
|
266
|
+
})
|
|
267
|
+
: noResultsMessage}
|
|
217
268
|
</div>
|
|
218
269
|
);
|
|
219
270
|
}
|
package/src/NumberInput.tsx
CHANGED
|
@@ -25,7 +25,11 @@ export type NumberInputProps = CommonProps<'aria-label' | 'disabled' | 'id' | 'n
|
|
|
25
25
|
InvalidPropsLibrary & {
|
|
26
26
|
/** The value of the control. */
|
|
27
27
|
value?: number;
|
|
28
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Callback when the value changes.
|
|
30
|
+
*
|
|
31
|
+
* @required
|
|
32
|
+
*/
|
|
29
33
|
onChange: (value: number | undefined) => void;
|
|
30
34
|
/**
|
|
31
35
|
* The alignment of the input box. Centered between the plus and minus buttons or to the left of the buttons.
|
|
@@ -78,8 +82,10 @@ function NumberInput({
|
|
|
78
82
|
const max = isNumber(maxProp);
|
|
79
83
|
const min = isNumber(minProp);
|
|
80
84
|
|
|
81
|
-
const fix = (
|
|
82
|
-
|
|
85
|
+
const fix = (nextValue: number | string | undefined) => {
|
|
86
|
+
const next = isNumber(nextValue);
|
|
87
|
+
|
|
88
|
+
if (typeof next !== 'number' || isNaN(next)) {
|
|
83
89
|
onChange(undefined);
|
|
84
90
|
return;
|
|
85
91
|
}
|
|
@@ -116,12 +122,15 @@ function NumberInput({
|
|
|
116
122
|
aria-label={ariaLabel}
|
|
117
123
|
disabled={disabled}
|
|
118
124
|
id={inputId}
|
|
125
|
+
max={max}
|
|
126
|
+
min={min}
|
|
119
127
|
name={name}
|
|
120
|
-
onBlur={() => {
|
|
121
|
-
|
|
128
|
+
onBlur={(event) => {
|
|
129
|
+
// Fix the value on blur to ensure it is a valid number
|
|
130
|
+
fix(event.target.value);
|
|
122
131
|
}}
|
|
123
132
|
onChange={(event) => {
|
|
124
|
-
onChange(event.target.value
|
|
133
|
+
onChange(isNumber(event.target.value));
|
|
125
134
|
}}
|
|
126
135
|
readOnly={readOnly}
|
|
127
136
|
type="number"
|
package/src/Portal.tsx
CHANGED
package/src/ProgressBar.tsx
CHANGED
|
@@ -30,7 +30,14 @@ export type ProgressionStepperProps = {
|
|
|
30
30
|
/**
|
|
31
31
|
* The steps to display in the progress bar.
|
|
32
32
|
*
|
|
33
|
-
* @
|
|
33
|
+
* @example
|
|
34
|
+
* [
|
|
35
|
+
* { name: '[Name of step to proceed forward 1]' },
|
|
36
|
+
* { name: '[Name of step to proceed forward 2]' },
|
|
37
|
+
* { name: '[Name of step to proceed forward 3]' },
|
|
38
|
+
* ];
|
|
39
|
+
*
|
|
40
|
+
* @type Array<ProgressionStepperItem>
|
|
34
41
|
* @required
|
|
35
42
|
*/
|
|
36
43
|
steps: ProgressionStepperItem[];
|
|
@@ -67,7 +74,7 @@ function ProgressionStepper({
|
|
|
67
74
|
...containerProps
|
|
68
75
|
}: ElementProps<ProgressionStepperProps, 'div'>) {
|
|
69
76
|
const currentStep = Math.max(0, Math.min(currentStepProp, steps.length + 1));
|
|
70
|
-
return (
|
|
77
|
+
return !steps?.length ? null : (
|
|
71
78
|
<div {...containerProps} data-bspk="progression-stepper" data-variant={variant}>
|
|
72
79
|
{variant === 'widget' && (
|
|
73
80
|
<label>
|
|
@@ -5,6 +5,9 @@ export type ProgressionStepperBarProps = {
|
|
|
5
5
|
/**
|
|
6
6
|
* The number of steps in the progress bar.
|
|
7
7
|
*
|
|
8
|
+
* @example
|
|
9
|
+
* 5;
|
|
10
|
+
*
|
|
8
11
|
* @minimum 2
|
|
9
12
|
* @maximum 10
|
|
10
13
|
* @required
|
|
@@ -13,6 +16,9 @@ export type ProgressionStepperBarProps = {
|
|
|
13
16
|
/**
|
|
14
17
|
* The last step completed.
|
|
15
18
|
*
|
|
19
|
+
* @example
|
|
20
|
+
* 2;
|
|
21
|
+
*
|
|
16
22
|
* @default 0
|
|
17
23
|
* @minimum 0
|
|
18
24
|
*/
|
package/src/Radio.tsx
CHANGED
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
import './radio.scss';
|
|
2
|
-
import {
|
|
2
|
+
import { ChangeEvent } from 'react';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import { ElementProps, InvalidPropsLibrary, CommonProps } from './';
|
|
5
|
+
|
|
6
|
+
export type RadioProps = CommonProps<'aria-label' | 'disabled' | 'name'> &
|
|
7
|
+
InvalidPropsLibrary &
|
|
8
|
+
Required<CommonProps<'value'>> & {
|
|
9
|
+
/**
|
|
10
|
+
* Marks the radio as checked.
|
|
11
|
+
*
|
|
12
|
+
* @default false
|
|
13
|
+
*/
|
|
14
|
+
checked?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The function to call when the radio is checked.
|
|
17
|
+
*
|
|
18
|
+
* @required
|
|
19
|
+
*/
|
|
20
|
+
onChange: (checked: boolean, event: ChangeEvent<HTMLInputElement>) => void;
|
|
21
|
+
};
|
|
6
22
|
|
|
7
23
|
/**
|
|
8
24
|
* A round control that allows user to choose one option from a set. This is the base element and if used directly you
|
|
@@ -13,13 +29,14 @@ export type RadioProps = InvalidPropsLibrary &
|
|
|
13
29
|
* @name Radio
|
|
14
30
|
*/
|
|
15
31
|
function Radio(props: ElementProps<RadioProps, 'input'>) {
|
|
16
|
-
const { checked = false, invalid, disabled, onChange, ...otherProps } = props;
|
|
32
|
+
const { checked = false, invalid, disabled, onChange, errorMessage, ...otherProps } = props;
|
|
17
33
|
|
|
18
34
|
return (
|
|
19
35
|
<span data-bspk="radio">
|
|
20
36
|
<input
|
|
21
37
|
{...otherProps}
|
|
22
38
|
checked={!!checked}
|
|
39
|
+
data-errormessage={errorMessage || undefined}
|
|
23
40
|
data-invalid={invalid || undefined}
|
|
24
41
|
disabled={disabled || undefined}
|
|
25
42
|
onChange={(event) => onChange(!!event.target.checked, event)}
|
package/src/RadioGroup.tsx
CHANGED
|
@@ -5,21 +5,44 @@ import { ElementProps, CommonProps } from './';
|
|
|
5
5
|
|
|
6
6
|
export type RadioGroupOption = Pick<ToggleOptionProps, 'description' | 'label'> & Required<CommonProps<'value'>>;
|
|
7
7
|
|
|
8
|
-
export type RadioGroupProps = CommonProps<'name'
|
|
8
|
+
export type RadioGroupProps = CommonProps<'name'> & {
|
|
9
|
+
/**
|
|
10
|
+
* The value of the control.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* 1;
|
|
14
|
+
*
|
|
15
|
+
* @required
|
|
16
|
+
*/
|
|
17
|
+
value: string;
|
|
9
18
|
/**
|
|
10
19
|
* The function to call when the radios are changed.
|
|
11
20
|
*
|
|
21
|
+
* @example
|
|
22
|
+
* (value) => setState({ value }),
|
|
23
|
+
*
|
|
12
24
|
* @required
|
|
13
25
|
*/
|
|
14
26
|
onChange: (value: string) => void;
|
|
15
27
|
/**
|
|
16
28
|
* The options for the radios.
|
|
17
29
|
*
|
|
18
|
-
* @
|
|
30
|
+
* @example
|
|
31
|
+
* [
|
|
32
|
+
* { value: '1', label: 'Option 1', description: 'Description here' },
|
|
33
|
+
* { value: '2', label: 'Option 2' },
|
|
34
|
+
* { value: '3', label: 'Option 3' },
|
|
35
|
+
* ];
|
|
36
|
+
*
|
|
37
|
+
* @type Array<RadioGroupOption>
|
|
19
38
|
* @required
|
|
20
39
|
*/
|
|
21
40
|
options: RadioGroupOption[];
|
|
22
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* The size of the radio group labels.
|
|
43
|
+
*
|
|
44
|
+
* @default base
|
|
45
|
+
*/
|
|
23
46
|
size?: 'base' | 'large' | 'small';
|
|
24
47
|
};
|
|
25
48
|
|
|
@@ -33,14 +56,19 @@ function RadioGroup({
|
|
|
33
56
|
options = [],
|
|
34
57
|
name,
|
|
35
58
|
value: groupValue,
|
|
36
|
-
size,
|
|
59
|
+
size = 'base',
|
|
37
60
|
...props
|
|
38
61
|
}: ElementProps<RadioGroupProps, 'div'>) {
|
|
39
62
|
return (
|
|
40
63
|
<div {...props} data-bspk="radio-group" role="radiogroup" style={{ display: 'contents' }}>
|
|
41
|
-
{options.map(({ label, description, value }) => {
|
|
64
|
+
{options.map(({ label, description, value }, index) => {
|
|
42
65
|
return (
|
|
43
|
-
<ToggleOption
|
|
66
|
+
<ToggleOption
|
|
67
|
+
description={description}
|
|
68
|
+
key={`toggle-option-${value || index}`}
|
|
69
|
+
label={label}
|
|
70
|
+
size={size}
|
|
71
|
+
>
|
|
44
72
|
<Radio
|
|
45
73
|
aria-label={label}
|
|
46
74
|
checked={groupValue === value}
|
package/src/RadioOption.tsx
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
|
+
import { ChangeEvent } from 'react';
|
|
2
|
+
|
|
1
3
|
import { RadioProps, Radio } from './Radio';
|
|
2
4
|
import { ToggleOptionProps, ToggleOption } from './ToggleOption';
|
|
3
5
|
|
|
4
6
|
import { InvalidPropsLibrary } from '.';
|
|
5
7
|
|
|
6
8
|
export type RadioOptionProps = InvalidPropsLibrary &
|
|
7
|
-
Pick<RadioProps, 'checked' | 'disabled' | 'name' | '
|
|
8
|
-
Pick<ToggleOptionProps, 'description' | 'label'
|
|
9
|
+
Pick<RadioProps, 'checked' | 'disabled' | 'name' | 'value'> &
|
|
10
|
+
Pick<ToggleOptionProps, 'description' | 'label'> & {
|
|
11
|
+
/**
|
|
12
|
+
* The function to call when the radio is checked.
|
|
13
|
+
*
|
|
14
|
+
* @required
|
|
15
|
+
*/
|
|
16
|
+
onChange: (checked: boolean, event: ChangeEvent<HTMLInputElement>) => void;
|
|
17
|
+
};
|
|
9
18
|
|
|
10
19
|
/**
|
|
11
20
|
* A control that allows users to choose one or more items from a list or turn an feature on or off.
|