@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/SearchBar.tsx
CHANGED
|
@@ -5,21 +5,22 @@ import { useRef } from 'react';
|
|
|
5
5
|
import { MenuItem, MenuProps, Menu } from './Menu';
|
|
6
6
|
import { Portal } from './Portal';
|
|
7
7
|
import { TextInputProps, TextInput } from './TextInput';
|
|
8
|
+
import { Txt } from './Txt';
|
|
8
9
|
import { useFloatingMenu } from './hooks/useFloatingMenu';
|
|
9
10
|
import { useId } from './hooks/useId';
|
|
10
11
|
//import { useFloatingMenu } from './hooks/useFloatingMenu';
|
|
11
12
|
|
|
12
|
-
export type SearchBarProps = Pick<MenuProps
|
|
13
|
+
export type SearchBarProps<T extends MenuItem = MenuItem> = Pick<MenuProps<T>, 'itemCount' | 'noResultsMessage'> &
|
|
13
14
|
Pick<TextInputProps, 'aria-label' | 'id' | 'inputRef' | 'name' | 'placeholder' | 'size'> & {
|
|
14
15
|
/** The current value of the search bar. */
|
|
15
|
-
|
|
16
|
+
value?: string;
|
|
16
17
|
/**
|
|
17
18
|
* Handler for state updates.
|
|
18
19
|
*
|
|
19
20
|
* @type (value: String) => void
|
|
20
21
|
* @required
|
|
21
22
|
*/
|
|
22
|
-
|
|
23
|
+
onChange: (value: string) => void;
|
|
23
24
|
/*
|
|
24
25
|
* Handler for item selection.
|
|
25
26
|
*
|
|
@@ -27,6 +28,32 @@ export type SearchBarProps = Pick<MenuProps, 'itemCount' | 'items' | 'noResultsM
|
|
|
27
28
|
* @required
|
|
28
29
|
*/
|
|
29
30
|
onSelect: (item?: MenuItem) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Content to display in the menu.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* [
|
|
36
|
+
* { value: '1', label: 'Apple Pie' },
|
|
37
|
+
* { value: '2', label: 'Banana Split' },
|
|
38
|
+
* { value: '3', label: 'Cherry Tart' },
|
|
39
|
+
* { value: '4', label: 'Dragonfruit Sorbet' },
|
|
40
|
+
* { value: '5', label: 'Elderberry Jam' },
|
|
41
|
+
* { value: '6', label: 'Fig Newton' },
|
|
42
|
+
* { value: '7', label: 'Grape Soda' },
|
|
43
|
+
* { value: '8', label: 'Honeydew Smoothie' },
|
|
44
|
+
* { value: '9', label: 'Ice Cream Sandwich' },
|
|
45
|
+
* { value: '10', label: 'Jackfruit Pudding' },
|
|
46
|
+
* ];
|
|
47
|
+
*
|
|
48
|
+
* @type Array<MenuItem>
|
|
49
|
+
*/
|
|
50
|
+
items?: T[];
|
|
51
|
+
/**
|
|
52
|
+
* Message to display when no results are found
|
|
53
|
+
*
|
|
54
|
+
* @type multiline
|
|
55
|
+
*/
|
|
56
|
+
noResultsMessage?: string;
|
|
30
57
|
};
|
|
31
58
|
|
|
32
59
|
/**
|
|
@@ -45,8 +72,8 @@ function SearchBar({
|
|
|
45
72
|
name,
|
|
46
73
|
size = 'medium',
|
|
47
74
|
onSelect,
|
|
48
|
-
|
|
49
|
-
|
|
75
|
+
value,
|
|
76
|
+
onChange,
|
|
50
77
|
}: SearchBarProps) {
|
|
51
78
|
const id = useId(idProp);
|
|
52
79
|
const {
|
|
@@ -61,49 +88,65 @@ function SearchBar({
|
|
|
61
88
|
|
|
62
89
|
return (
|
|
63
90
|
<>
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
91
|
+
<div data-bspk="search-bar">
|
|
92
|
+
<TextInput
|
|
93
|
+
aria-label={ariaLabel}
|
|
94
|
+
autoComplete="off"
|
|
95
|
+
containerRef={triggerRef}
|
|
96
|
+
id={id}
|
|
97
|
+
inputRef={(node) => {
|
|
98
|
+
inputRef?.(node || null);
|
|
99
|
+
inputRefLocal.current = node;
|
|
100
|
+
}}
|
|
101
|
+
leading={<SvgSearch />}
|
|
102
|
+
name={name}
|
|
103
|
+
onChange={(str) => onChange(str)}
|
|
104
|
+
placeholder={placeholder}
|
|
105
|
+
size={size}
|
|
106
|
+
value={value}
|
|
107
|
+
{...triggerProps}
|
|
108
|
+
onClick={(event) => {
|
|
109
|
+
if (items?.length) onClick(event);
|
|
110
|
+
}}
|
|
111
|
+
onKeyDownCapture={(event) => {
|
|
112
|
+
const handled = onKeyDownCapture(event);
|
|
86
113
|
|
|
87
|
-
|
|
114
|
+
if (handled) return;
|
|
88
115
|
|
|
89
|
-
|
|
90
|
-
}}
|
|
91
|
-
/>
|
|
92
|
-
<Portal>
|
|
93
|
-
<Menu
|
|
94
|
-
itemCount={itemCount}
|
|
95
|
-
items={items}
|
|
96
|
-
noResultsMessage={noResultsMessage}
|
|
97
|
-
onChange={(selectedValues, event) => {
|
|
98
|
-
event?.preventDefault();
|
|
99
|
-
const item = items?.find((i) => i.value === selectedValues[0]);
|
|
100
|
-
onSelect?.(item);
|
|
101
|
-
setSearchValue(item?.label || '');
|
|
102
|
-
closeMenu();
|
|
116
|
+
inputRefLocal.current?.focus();
|
|
103
117
|
}}
|
|
104
|
-
{...menuProps}
|
|
105
118
|
/>
|
|
106
|
-
</
|
|
119
|
+
</div>
|
|
120
|
+
{!!value?.trim().length && (
|
|
121
|
+
<Portal>
|
|
122
|
+
<Menu
|
|
123
|
+
itemCount={itemCount}
|
|
124
|
+
items={items}
|
|
125
|
+
noResultsMessage={
|
|
126
|
+
!!value?.length && (
|
|
127
|
+
<>
|
|
128
|
+
<Txt as="div" variant="heading-h5">
|
|
129
|
+
No results found
|
|
130
|
+
</Txt>
|
|
131
|
+
{noResultsMessage && (
|
|
132
|
+
<Txt as="div" variant="body-base">
|
|
133
|
+
{noResultsMessage}
|
|
134
|
+
</Txt>
|
|
135
|
+
)}
|
|
136
|
+
</>
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
onChange={(selectedValues, event) => {
|
|
140
|
+
event?.preventDefault();
|
|
141
|
+
const item = items?.find((i) => i.value === selectedValues[0]);
|
|
142
|
+
onSelect?.(item);
|
|
143
|
+
onChange(item?.label || '');
|
|
144
|
+
closeMenu();
|
|
145
|
+
}}
|
|
146
|
+
{...menuProps}
|
|
147
|
+
/>
|
|
148
|
+
</Portal>
|
|
149
|
+
)}
|
|
107
150
|
</>
|
|
108
151
|
);
|
|
109
152
|
}
|
package/src/SegmentedControl.tsx
CHANGED
|
@@ -21,8 +21,17 @@ export type SegmentedControlOption = {
|
|
|
21
21
|
disabled?: boolean;
|
|
22
22
|
/** The value of the option. If not provided, the label will be used as the value. */
|
|
23
23
|
value?: string;
|
|
24
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* The the icon to display before the label.
|
|
26
|
+
*
|
|
27
|
+
* @type BspkIcon
|
|
28
|
+
*/
|
|
25
29
|
icon?: React.ReactNode;
|
|
30
|
+
/**
|
|
31
|
+
* The icon to display before the label when the option is active.
|
|
32
|
+
*
|
|
33
|
+
* @type BspkIcon
|
|
34
|
+
*/
|
|
26
35
|
iconActive?: React.ReactNode;
|
|
27
36
|
};
|
|
28
37
|
|
|
@@ -30,13 +39,23 @@ export type SegmentedControlProps = {
|
|
|
30
39
|
/**
|
|
31
40
|
* The options to display. Each option has a label and an optional leading icon.
|
|
32
41
|
*
|
|
33
|
-
* @
|
|
42
|
+
* @example
|
|
43
|
+
* [
|
|
44
|
+
* { value: '1', label: 'Option 1' },
|
|
45
|
+
* { value: '2', label: 'Option 2' },
|
|
46
|
+
* { value: '3', label: 'Option 3' },
|
|
47
|
+
* ];
|
|
48
|
+
*
|
|
49
|
+
* @type Array<SegmentedControlOption>
|
|
34
50
|
* @required
|
|
35
51
|
*/
|
|
36
52
|
options: SegmentedControlOption[];
|
|
37
53
|
/**
|
|
38
54
|
* The id of the selected option.
|
|
39
55
|
*
|
|
56
|
+
* @example
|
|
57
|
+
* 1;
|
|
58
|
+
*
|
|
40
59
|
* @required
|
|
41
60
|
*/
|
|
42
61
|
value: SegmentedControlOption['value'];
|
package/src/Switch.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import { ChangeEvent } from 'react';
|
|
|
3
3
|
|
|
4
4
|
import { CommonProps } from './';
|
|
5
5
|
|
|
6
|
-
export type SwitchProps = CommonProps<'aria-label' | 'disabled' | 'name' | '
|
|
6
|
+
export type SwitchProps = CommonProps<'aria-label' | 'disabled' | 'name' | 'value'> & {
|
|
7
7
|
/**
|
|
8
8
|
* Marks the control as checked.
|
|
9
9
|
*
|
package/src/SwitchGroup.tsx
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Switch } from './Switch';
|
|
2
2
|
import { ToggleOptionProps, ToggleOption } from './ToggleOption';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { ElementProps, CommonProps } from './';
|
|
5
5
|
|
|
6
|
-
export type SwitchGroupOption = Pick<
|
|
7
|
-
Pick<ToggleOptionProps, 'description' | 'label'>;
|
|
6
|
+
export type SwitchGroupOption = Pick<ToggleOptionProps, 'description' | 'label'> & Required<CommonProps<'value'>>;
|
|
8
7
|
|
|
9
8
|
export type SwitchGroupProps = CommonProps<'aria-label' | 'name'> & {
|
|
10
9
|
/**
|
|
@@ -16,16 +15,23 @@ export type SwitchGroupProps = CommonProps<'aria-label' | 'name'> & {
|
|
|
16
15
|
/**
|
|
17
16
|
* The options for the switches.
|
|
18
17
|
*
|
|
19
|
-
* @
|
|
18
|
+
* @example
|
|
19
|
+
* [
|
|
20
|
+
* { value: '1', label: 'Option 1' },
|
|
21
|
+
* { value: '2', label: 'Option 2' },
|
|
22
|
+
* { value: '3', label: 'Option 3' },
|
|
23
|
+
* ];
|
|
24
|
+
*
|
|
25
|
+
* @type Array<SwitchGroupOption>
|
|
20
26
|
* @required
|
|
21
27
|
*/
|
|
22
28
|
options: SwitchGroupOption[];
|
|
23
29
|
/**
|
|
24
30
|
* The values of the switches in the on state.
|
|
25
31
|
*
|
|
26
|
-
* @type string
|
|
32
|
+
* @type Array<string>
|
|
27
33
|
*/
|
|
28
|
-
|
|
34
|
+
value?: SwitchGroupProps['options'][number]['value'][];
|
|
29
35
|
};
|
|
30
36
|
|
|
31
37
|
/**
|
|
@@ -33,7 +39,13 @@ export type SwitchGroupProps = CommonProps<'aria-label' | 'name'> & {
|
|
|
33
39
|
*
|
|
34
40
|
* @name SwitchGroup
|
|
35
41
|
*/
|
|
36
|
-
function SwitchGroup({
|
|
42
|
+
function SwitchGroup({
|
|
43
|
+
onChange,
|
|
44
|
+
options = [],
|
|
45
|
+
name,
|
|
46
|
+
value: values = [],
|
|
47
|
+
...props
|
|
48
|
+
}: ElementProps<SwitchGroupProps, 'div'>) {
|
|
37
49
|
return (
|
|
38
50
|
<div {...props} data-bspk="switch-group" role="group">
|
|
39
51
|
{options.map(({ label, description, value }) => (
|
package/src/TabGroup.tsx
CHANGED
|
@@ -33,11 +33,19 @@ export type TabGroupOption = {
|
|
|
33
33
|
* If not provided, the label will be used as the value.
|
|
34
34
|
*/
|
|
35
35
|
value?: string;
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* The icon to display on the left side of the tab.
|
|
38
|
+
*
|
|
39
|
+
* @type BspkIcon
|
|
40
|
+
*/
|
|
37
41
|
icon?: ReactNode;
|
|
38
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* The icon to display on the left side of the tab when the tab is active.
|
|
44
|
+
*
|
|
45
|
+
* @type BspkIcon
|
|
46
|
+
*/
|
|
39
47
|
iconActive?: ReactNode;
|
|
40
|
-
/** The badge count to display on the tab
|
|
48
|
+
/** The badge count to display on the tab */
|
|
41
49
|
badge?: number;
|
|
42
50
|
};
|
|
43
51
|
|
|
@@ -45,12 +53,22 @@ export type TabGroupProps = {
|
|
|
45
53
|
/**
|
|
46
54
|
* The tabs to display. Each tab has a label and an optional leading icon.
|
|
47
55
|
*
|
|
48
|
-
* @
|
|
56
|
+
* @example
|
|
57
|
+
* [
|
|
58
|
+
* { value: '1', label: 'Option 1' },
|
|
59
|
+
* { value: '2', label: 'Option 2' },
|
|
60
|
+
* { value: '3', label: 'Option 3' },
|
|
61
|
+
* ];
|
|
62
|
+
*
|
|
63
|
+
* @type Array<TabGroupOption>
|
|
49
64
|
* @required
|
|
50
65
|
*/
|
|
51
66
|
options: TabGroupOption[];
|
|
52
67
|
/**
|
|
53
|
-
* The
|
|
68
|
+
* The value of the selected tab.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* 1;
|
|
54
72
|
*
|
|
55
73
|
* @required
|
|
56
74
|
*/
|
package/src/Tag.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import './tag.scss';
|
|
2
1
|
import { ElementType, ReactNode } from 'react';
|
|
3
2
|
|
|
4
3
|
import { ColorVariant } from './utils/colorVariants';
|
|
5
4
|
|
|
6
5
|
import { ElementProps } from './';
|
|
6
|
+
import './tag.scss';
|
|
7
7
|
|
|
8
8
|
export type TagProps<As extends ElementType = 'span'> = {
|
|
9
9
|
/**
|
|
@@ -16,6 +16,9 @@ export type TagProps<As extends ElementType = 'span'> = {
|
|
|
16
16
|
/**
|
|
17
17
|
* The content of the tag.
|
|
18
18
|
*
|
|
19
|
+
* @example
|
|
20
|
+
* New;
|
|
21
|
+
*
|
|
19
22
|
* @required
|
|
20
23
|
*/
|
|
21
24
|
children: ReactNode;
|
|
@@ -28,7 +31,7 @@ export type TagProps<As extends ElementType = 'span'> = {
|
|
|
28
31
|
/**
|
|
29
32
|
* The color of the tag.
|
|
30
33
|
*
|
|
31
|
-
* @default
|
|
34
|
+
* @default grey
|
|
32
35
|
*/
|
|
33
36
|
color?: ColorVariant;
|
|
34
37
|
/**
|
package/src/TextInput.tsx
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { SvgCancel } from '@bspk/icons/Cancel';
|
|
2
|
-
import './text-input.scss';
|
|
3
2
|
import { ChangeEvent, HTMLInputAutoCompleteAttribute, HTMLInputTypeAttribute, ReactNode } from 'react';
|
|
4
3
|
|
|
5
4
|
import { useId } from './hooks/useId';
|
|
6
5
|
|
|
7
|
-
import { ElementProps, CommonProps, InvalidPropsLibrary } from '.';
|
|
6
|
+
import { ElementProps, CommonProps, InvalidPropsLibrary, SetRef } from '.';
|
|
7
|
+
|
|
8
|
+
import './text-input.scss';
|
|
9
|
+
|
|
10
|
+
export const DEFAULT = {
|
|
11
|
+
size: 'medium',
|
|
12
|
+
value: '',
|
|
13
|
+
type: 'text' as Extract<HTMLInputTypeAttribute, 'number' | 'text'>,
|
|
14
|
+
autoComplete: 'off',
|
|
15
|
+
} as const;
|
|
8
16
|
|
|
9
17
|
export type TextInputProps = CommonProps<
|
|
10
18
|
'aria-label' | 'disabled' | 'id' | 'name' | 'readOnly' | 'required' | 'size' | 'value'
|
|
@@ -13,21 +21,24 @@ export type TextInputProps = CommonProps<
|
|
|
13
21
|
/**
|
|
14
22
|
* Callback when the value of the field changes.
|
|
15
23
|
*
|
|
16
|
-
* @type (next: String, Event) => void
|
|
17
24
|
* @required
|
|
18
25
|
*/
|
|
19
26
|
onChange: (next: string, event?: ChangeEvent<HTMLInputElement>) => void;
|
|
20
27
|
/** The ref of the container. */
|
|
21
|
-
containerRef?:
|
|
28
|
+
containerRef?: SetRef<HTMLDivElement>;
|
|
22
29
|
/** The ref of the input. */
|
|
23
|
-
inputRef?:
|
|
30
|
+
inputRef?: SetRef<HTMLInputElement>;
|
|
24
31
|
/** The trailing element to display in the field. */
|
|
25
32
|
trailing?: ReactNode;
|
|
26
33
|
/** The leading element to display in the field. */
|
|
27
34
|
leading?: ReactNode;
|
|
28
35
|
/** The placeholder of the field. */
|
|
29
36
|
placeholder?: string;
|
|
30
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* The type of the input.
|
|
39
|
+
*
|
|
40
|
+
* @default text
|
|
41
|
+
*/
|
|
31
42
|
type?: Extract<HTMLInputTypeAttribute, 'number' | 'text'>;
|
|
32
43
|
/**
|
|
33
44
|
* Specifies if user agent has any permission to provide automated assistance in filling out form field values.
|
|
@@ -49,8 +60,8 @@ export type TextInputProps = CommonProps<
|
|
|
49
60
|
function TextInput({
|
|
50
61
|
invalid: invalidProp,
|
|
51
62
|
onChange,
|
|
52
|
-
size =
|
|
53
|
-
value =
|
|
63
|
+
size = DEFAULT.size,
|
|
64
|
+
value = DEFAULT.value,
|
|
54
65
|
name,
|
|
55
66
|
'aria-label': ariaLabel,
|
|
56
67
|
inputRef,
|
|
@@ -59,10 +70,10 @@ function TextInput({
|
|
|
59
70
|
id: idProp,
|
|
60
71
|
leading,
|
|
61
72
|
trailing,
|
|
62
|
-
type,
|
|
73
|
+
type = DEFAULT.type,
|
|
63
74
|
readOnly,
|
|
64
75
|
disabled,
|
|
65
|
-
autoComplete =
|
|
76
|
+
autoComplete = DEFAULT.autoComplete,
|
|
66
77
|
containerRef,
|
|
67
78
|
errorMessage,
|
|
68
79
|
...otherProps
|
|
@@ -75,6 +86,7 @@ function TextInput({
|
|
|
75
86
|
<div
|
|
76
87
|
data-bspk="text-input"
|
|
77
88
|
data-disabled={disabled || undefined}
|
|
89
|
+
data-empty={!value.toString().length || undefined}
|
|
78
90
|
data-invalid={invalid || undefined}
|
|
79
91
|
data-readonly={readOnly || undefined}
|
|
80
92
|
data-required={required || undefined}
|
|
@@ -102,11 +114,9 @@ function TextInput({
|
|
|
102
114
|
value={value}
|
|
103
115
|
/>
|
|
104
116
|
{trailing && <span data-trailing>{trailing}</span>}
|
|
105
|
-
{
|
|
106
|
-
<
|
|
107
|
-
|
|
108
|
-
</button>
|
|
109
|
-
)}
|
|
117
|
+
<button aria-label="clear" data-clear onClick={() => onChange('')}>
|
|
118
|
+
<SvgCancel />
|
|
119
|
+
</button>
|
|
110
120
|
</div>
|
|
111
121
|
);
|
|
112
122
|
}
|
package/src/Textarea.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import './textarea.scss';
|
|
2
|
-
import { ChangeEvent, CSSProperties
|
|
2
|
+
import { ChangeEvent, CSSProperties } from 'react';
|
|
3
3
|
|
|
4
4
|
import { useId } from './hooks/useId';
|
|
5
5
|
|
|
6
|
-
import { CommonProps, InvalidPropsLibrary } from './';
|
|
6
|
+
import { CommonProps, InvalidPropsLibrary, SetRef } from './';
|
|
7
7
|
|
|
8
8
|
const DEFAULT = {
|
|
9
9
|
minRows: 3,
|
|
@@ -39,7 +39,7 @@ export type TextareaProps = CommonProps<'aria-label' | 'disabled' | 'id' | 'read
|
|
|
39
39
|
*/
|
|
40
40
|
name: string;
|
|
41
41
|
/** The ref of the field. */
|
|
42
|
-
innerRef?:
|
|
42
|
+
innerRef?: SetRef<HTMLTextAreaElement>;
|
|
43
43
|
/** The placeholder of the field. */
|
|
44
44
|
placeholder?: string;
|
|
45
45
|
/**
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[data-bspk='avatar-group'] {
|
|
2
|
+
width: 100%;
|
|
3
|
+
|
|
4
|
+
[data-wrap] {
|
|
5
|
+
width: 100%;
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: row;
|
|
8
|
+
align-items: end;
|
|
9
|
+
justify-content: end;
|
|
10
|
+
gap: var(--spacing-sizing-02);
|
|
11
|
+
overflow: hidden;
|
|
12
|
+
|
|
13
|
+
& > * + * {
|
|
14
|
+
// margin-left: calc(var(--spacing-sizing-01) * -1);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
package/src/avatar.scss
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
[data-bspk='avatar'] {
|
|
2
2
|
--height: var(--spacing-sizing-10);
|
|
3
3
|
--font: var(--labels-base);
|
|
4
|
-
--
|
|
5
|
-
|
|
4
|
+
--svg-size: var(--spacing-sizing-10);
|
|
5
|
+
|
|
6
|
+
&:not([data-color]) {
|
|
7
|
+
--foreground: var(--foreground-neutral-on-surface);
|
|
8
|
+
--background: var(--surface-neutral-t3-low);
|
|
9
|
+
}
|
|
6
10
|
|
|
7
11
|
display: flex;
|
|
8
12
|
flex-direction: column;
|
|
@@ -25,49 +29,69 @@
|
|
|
25
29
|
max-width: 100%;
|
|
26
30
|
}
|
|
27
31
|
|
|
32
|
+
svg {
|
|
33
|
+
width: var(--svg-size);
|
|
34
|
+
height: var(--svg-size);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
[data-icon] {
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: center;
|
|
41
|
+
}
|
|
42
|
+
|
|
28
43
|
&[data-size='x-small'] {
|
|
29
44
|
--height: var(--spacing-sizing-06);
|
|
30
45
|
--font: var(--labels-x-small);
|
|
46
|
+
--svg-size: var(--spacing-sizing-04);
|
|
31
47
|
}
|
|
32
48
|
|
|
33
49
|
&[data-size='small'] {
|
|
34
50
|
--height: var(--spacing-sizing-08);
|
|
35
51
|
--font: var(--labels-small);
|
|
52
|
+
--svg-size: var(--spacing-sizing-05);
|
|
36
53
|
}
|
|
37
54
|
|
|
38
55
|
&[data-size='medium'] {
|
|
39
56
|
--height: var(--spacing-sizing-10);
|
|
40
57
|
--font: var(--labels-base);
|
|
58
|
+
--svg-size: var(--spacing-sizing-05);
|
|
41
59
|
}
|
|
42
60
|
|
|
43
61
|
&[data-size='large'] {
|
|
44
62
|
--height: var(--spacing-sizing-12);
|
|
45
63
|
--font: var(--labels-large);
|
|
64
|
+
--svg-size: var(--spacing-sizing-06);
|
|
46
65
|
}
|
|
47
66
|
|
|
48
67
|
&[data-size='x-large'] {
|
|
49
68
|
--height: var(--spacing-sizing-14);
|
|
50
69
|
--font: var(--subheader-x-large);
|
|
70
|
+
--svg-size: var(--spacing-sizing-08);
|
|
51
71
|
}
|
|
52
72
|
|
|
53
73
|
&[data-size='xx-large'] {
|
|
54
74
|
--height: var(--spacing-sizing-17);
|
|
55
75
|
--font: var(--subheader-xx-large);
|
|
76
|
+
--svg-size: var(--spacing-sizing-09);
|
|
56
77
|
}
|
|
57
78
|
|
|
58
79
|
&[data-size='xxx-large'] {
|
|
59
80
|
--height: var(--spacing-sizing-19);
|
|
60
81
|
--font: var(--display-regular-small);
|
|
82
|
+
--svg-size: var(--spacing-sizing-12);
|
|
61
83
|
}
|
|
62
84
|
|
|
63
85
|
&[data-size='xxxx-large'] {
|
|
64
86
|
--height: var(--spacing-sizing-21);
|
|
65
87
|
--font: var(--display-regular-medium);
|
|
88
|
+
--svg-size: var(--spacing-sizing-15);
|
|
66
89
|
}
|
|
67
90
|
|
|
68
91
|
&[data-size='xxxxx-large'] {
|
|
69
92
|
--height: var(--spacing-sizing-23);
|
|
70
93
|
--font: var(--display-regular-large);
|
|
94
|
+
--svg-size: var(--spacing-sizing-17);
|
|
71
95
|
}
|
|
72
96
|
}
|
|
73
97
|
|
package/src/badge.scss
CHANGED
package/src/button.scss
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useId } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Button } from '../Button';
|
|
4
|
+
import { ModalProps, Modal } from '../Modal';
|
|
5
|
+
import { useModalState } from '../hooks/useModalState';
|
|
6
|
+
|
|
7
|
+
import { Preset, DemoSetState } from './examples';
|
|
8
|
+
|
|
9
|
+
export function ExampleModalRender({
|
|
10
|
+
props,
|
|
11
|
+
preset,
|
|
12
|
+
setState,
|
|
13
|
+
}: {
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
|
+
props: ModalProps & Record<string, any>;
|
|
16
|
+
preset?: Preset<ModalProps>;
|
|
17
|
+
setState: DemoSetState;
|
|
18
|
+
}) {
|
|
19
|
+
let label = 'Open Modal';
|
|
20
|
+
|
|
21
|
+
const dialogId = useId();
|
|
22
|
+
const openKey = `${dialogId}-open`;
|
|
23
|
+
|
|
24
|
+
const { open, onClose, onOpen } = useModalState(!!props[openKey], (next) => setState({ [openKey]: next }));
|
|
25
|
+
|
|
26
|
+
const presetState: Partial<ModalProps> = preset?.state || {};
|
|
27
|
+
if (presetState?.placement) label += ` (${presetState?.placement})`;
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<>
|
|
31
|
+
<Button label={label} onClick={() => onOpen()} />
|
|
32
|
+
<Modal data-example-component id="exampleId" {...props} onClose={onClose} open={open}>
|
|
33
|
+
<pre>{JSON.stringify(props, null, '\t')}</pre>
|
|
34
|
+
</Modal>
|
|
35
|
+
</>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { ElementProps } from '..';
|
|
4
|
+
import { Txt } from '../Txt';
|
|
5
|
+
|
|
6
|
+
const dimension = (value: number | string) => (typeof value === 'number' ? `${value}px` : `${value}`);
|
|
7
|
+
|
|
8
|
+
export function ExamplePlaceholder({
|
|
9
|
+
hideSize = false,
|
|
10
|
+
height = 100,
|
|
11
|
+
width = '100%',
|
|
12
|
+
direction = 'row',
|
|
13
|
+
...props
|
|
14
|
+
}: ElementProps<
|
|
15
|
+
{ hideSize?: boolean; height?: number | string; width?: number | string; direction?: 'column' | 'row' },
|
|
16
|
+
'div'
|
|
17
|
+
>) {
|
|
18
|
+
const ref = useRef<HTMLDivElement | null>(null);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div
|
|
22
|
+
{...props}
|
|
23
|
+
data-example-placeholder
|
|
24
|
+
ref={ref}
|
|
25
|
+
style={{
|
|
26
|
+
width: dimension(width),
|
|
27
|
+
height: dimension(height),
|
|
28
|
+
flexDirection: direction,
|
|
29
|
+
}}
|
|
30
|
+
>
|
|
31
|
+
{!hideSize && (
|
|
32
|
+
<>
|
|
33
|
+
<Txt variant="labels-large">{dimension(width)}</Txt>
|
|
34
|
+
<Txt>×</Txt>
|
|
35
|
+
<Txt variant="labels-large">{dimension(height)}</Txt>
|
|
36
|
+
</>
|
|
37
|
+
)}
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|