@saas-ui/forms 2.5.4 → 2.6.1
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/CHANGELOG.md +23 -5
- package/dist/index.d.mts +14 -9
- package/dist/index.d.ts +14 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/default-fields.tsx +1 -1
- package/src/select/select-context.tsx +10 -7
- package/src/select/select.stories.tsx +117 -38
- package/src/select/select.tsx +15 -5
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@saas-ui/forms",
|
3
|
-
"version": "2.
|
3
|
+
"version": "2.6.1",
|
4
4
|
"description": "Fully functional forms for Chakra UI.",
|
5
5
|
"source": "src/index.ts",
|
6
6
|
"exports": {
|
@@ -104,7 +104,7 @@
|
|
104
104
|
"@chakra-ui/react-utils": "^2.0.12",
|
105
105
|
"@chakra-ui/utils": "^2.0.15",
|
106
106
|
"@hookform/resolvers": "^3.3.4",
|
107
|
-
"@saas-ui/core": "2.
|
107
|
+
"@saas-ui/core": "2.5.0",
|
108
108
|
"react-hook-form": "^7.50.1"
|
109
109
|
},
|
110
110
|
"peerDependencies": {
|
package/src/default-fields.tsx
CHANGED
@@ -87,7 +87,7 @@ export const SwitchField = createField<SwitchFieldProps>(
|
|
87
87
|
}
|
88
88
|
)
|
89
89
|
|
90
|
-
export interface SelectFieldProps extends SelectProps {
|
90
|
+
export interface SelectFieldProps extends SelectProps<boolean> {
|
91
91
|
buttonProps?: SelectButtonProps
|
92
92
|
listProps?: SelectListProps
|
93
93
|
}
|
@@ -19,7 +19,10 @@ export const [SelectProvider, useSelectContext] = createContext<
|
|
19
19
|
strict: true,
|
20
20
|
})
|
21
21
|
|
22
|
-
export interface SelectOptions
|
22
|
+
export interface SelectOptions<
|
23
|
+
Multiple extends boolean = false,
|
24
|
+
Value = Multiple extends true ? string[] : string,
|
25
|
+
> {
|
23
26
|
/**
|
24
27
|
* The name of the input field in a native form.
|
25
28
|
*/
|
@@ -27,16 +30,16 @@ export interface SelectOptions {
|
|
27
30
|
/**
|
28
31
|
* The value of the select field.
|
29
32
|
*/
|
30
|
-
value?:
|
33
|
+
value?: Value
|
31
34
|
/**
|
32
35
|
* The initial value of the select field.
|
33
36
|
*/
|
34
|
-
defaultValue?:
|
37
|
+
defaultValue?: Value
|
35
38
|
/**
|
36
39
|
* The callback invoked when the value of the select field changes.
|
37
40
|
* @param value The value of the select field.
|
38
41
|
*/
|
39
|
-
onChange?: (value:
|
42
|
+
onChange?: (value: Value) => void
|
40
43
|
/**
|
41
44
|
* The placeholder text when there's no value.
|
42
45
|
*/
|
@@ -53,16 +56,16 @@ export interface SelectOptions {
|
|
53
56
|
/**
|
54
57
|
* Enable multiple select.
|
55
58
|
*/
|
56
|
-
multiple?:
|
59
|
+
multiple?: Multiple
|
57
60
|
/**
|
58
61
|
* The function used to render the value of the select field.
|
59
62
|
* @param value The value of the select field.
|
60
63
|
* @returns The rendered value.
|
61
64
|
*/
|
62
|
-
renderValue?: (value:
|
65
|
+
renderValue?: (value: Value) => React.ReactNode
|
63
66
|
}
|
64
67
|
|
65
|
-
export const useSelect = (props: SelectOptions) => {
|
68
|
+
export const useSelect = (props: SelectOptions<boolean>) => {
|
66
69
|
const {
|
67
70
|
name,
|
68
71
|
value,
|
@@ -1,31 +1,24 @@
|
|
1
|
-
import {
|
2
|
-
Container,
|
3
|
-
Icon,
|
4
|
-
MenuItemOption,
|
5
|
-
Stack,
|
6
|
-
Tag,
|
7
|
-
Wrap,
|
8
|
-
WrapItem,
|
9
|
-
} from '@chakra-ui/react'
|
1
|
+
import { Container, Icon, Stack, Tag, Wrap, WrapItem } from '@chakra-ui/react'
|
10
2
|
import * as React from 'react'
|
11
3
|
|
12
|
-
import {
|
4
|
+
import { StoryObj } from '@storybook/react'
|
13
5
|
|
14
|
-
import {
|
6
|
+
import {
|
7
|
+
Select,
|
8
|
+
SelectButton,
|
9
|
+
SelectList,
|
10
|
+
SelectOption,
|
11
|
+
SelectProps,
|
12
|
+
} from './select'
|
15
13
|
import { NativeSelect } from './native-select'
|
16
14
|
|
17
15
|
import { FiSmile } from 'react-icons/fi'
|
18
16
|
|
19
|
-
|
20
|
-
<Select placeholder="Select an option..." {...args}>
|
21
|
-
<SelectButton />
|
22
|
-
<SelectList />
|
23
|
-
</Select>
|
24
|
-
)
|
17
|
+
type Story<Multiple extends boolean = false> = StoryObj<SelectProps<Multiple>>
|
25
18
|
|
26
19
|
export default {
|
27
20
|
title: 'Components/Forms/Select',
|
28
|
-
component:
|
21
|
+
component: Select,
|
29
22
|
decorators: [
|
30
23
|
(Story: any) => (
|
31
24
|
<Container mt="40px" maxW="320px">
|
@@ -43,62 +36,104 @@ const getOptions = (length = 6) =>
|
|
43
36
|
|
44
37
|
const options = getOptions()
|
45
38
|
|
46
|
-
export const Basic = {
|
39
|
+
export const Basic: Story = {
|
47
40
|
args: {
|
48
41
|
name: 'select',
|
49
42
|
options,
|
43
|
+
children: (
|
44
|
+
<>
|
45
|
+
<SelectButton />
|
46
|
+
<SelectList />
|
47
|
+
</>
|
48
|
+
),
|
50
49
|
},
|
51
50
|
}
|
52
51
|
|
53
|
-
export const DefaultValue = {
|
52
|
+
export const DefaultValue: Story = {
|
54
53
|
args: {
|
55
54
|
name: 'select',
|
56
55
|
options,
|
57
56
|
defaultValue: '1',
|
57
|
+
children: (
|
58
|
+
<>
|
59
|
+
<SelectButton />
|
60
|
+
<SelectList />
|
61
|
+
</>
|
62
|
+
),
|
58
63
|
},
|
59
64
|
}
|
60
65
|
|
61
|
-
export const Placeholder = {
|
66
|
+
export const Placeholder: Story = {
|
62
67
|
args: {
|
63
68
|
name: 'select',
|
64
69
|
options,
|
65
70
|
placeholder: 'Select an option...',
|
71
|
+
children: (
|
72
|
+
<>
|
73
|
+
<SelectButton />
|
74
|
+
<SelectList />
|
75
|
+
</>
|
76
|
+
),
|
66
77
|
},
|
67
78
|
}
|
68
|
-
export const Disabled = {
|
79
|
+
export const Disabled: Story = {
|
69
80
|
args: {
|
70
81
|
name: 'select',
|
71
82
|
options,
|
72
83
|
placeholder: 'Disabled.',
|
73
84
|
isDisabled: true,
|
85
|
+
children: (
|
86
|
+
<>
|
87
|
+
<SelectButton />
|
88
|
+
<SelectList />
|
89
|
+
</>
|
90
|
+
),
|
74
91
|
},
|
75
92
|
}
|
76
93
|
|
77
|
-
export const Multi = {
|
94
|
+
export const Multi: Story<true> = {
|
78
95
|
args: {
|
79
96
|
name: 'select',
|
80
97
|
options,
|
81
98
|
placeholder: 'Multiple.',
|
82
99
|
multiple: true,
|
100
|
+
children: (
|
101
|
+
<>
|
102
|
+
<SelectButton />
|
103
|
+
<SelectList />
|
104
|
+
</>
|
105
|
+
),
|
83
106
|
},
|
84
107
|
}
|
85
108
|
|
86
|
-
export const MultiWithDefaultValue = {
|
109
|
+
export const MultiWithDefaultValue: Story<true> = {
|
87
110
|
args: {
|
88
111
|
name: 'select',
|
89
112
|
options,
|
90
113
|
placeholder: 'Select an option...',
|
91
114
|
multiple: true,
|
92
115
|
defaultValue: ['1'],
|
116
|
+
children: (
|
117
|
+
<>
|
118
|
+
<SelectButton />
|
119
|
+
<SelectList />
|
120
|
+
</>
|
121
|
+
),
|
93
122
|
},
|
94
123
|
}
|
95
124
|
|
96
|
-
export const MultiWithTags = {
|
125
|
+
export const MultiWithTags: Story<true> = {
|
97
126
|
args: {
|
98
127
|
name: 'select',
|
99
128
|
options,
|
100
129
|
placeholder: 'Select options...',
|
101
130
|
multiple: true,
|
131
|
+
children: (
|
132
|
+
<>
|
133
|
+
<SelectButton />
|
134
|
+
<SelectList />
|
135
|
+
</>
|
136
|
+
),
|
102
137
|
renderValue: (selected) => {
|
103
138
|
if (selected?.length) {
|
104
139
|
return (
|
@@ -115,15 +150,52 @@ export const MultiWithTags = {
|
|
115
150
|
},
|
116
151
|
}
|
117
152
|
|
118
|
-
export const
|
119
|
-
render: () =>
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
153
|
+
export const Controlled: Story = {
|
154
|
+
render: (args) => {
|
155
|
+
const [value, setValue] = React.useState('1')
|
156
|
+
|
157
|
+
return (
|
158
|
+
<Select
|
159
|
+
placeholder="Select an option..."
|
160
|
+
value={value}
|
161
|
+
onChange={(value) => setValue(value)}
|
162
|
+
{...args}
|
163
|
+
>
|
164
|
+
<SelectButton />
|
165
|
+
<SelectList />
|
166
|
+
</Select>
|
167
|
+
)
|
168
|
+
},
|
169
|
+
args: {
|
170
|
+
name: 'select',
|
171
|
+
options,
|
172
|
+
},
|
173
|
+
}
|
174
|
+
|
175
|
+
export const ControlledMulti: Story<true> = {
|
176
|
+
render: (args) => {
|
177
|
+
const [value, setValue] = React.useState(['1'])
|
178
|
+
|
179
|
+
return (
|
180
|
+
<Select
|
181
|
+
placeholder="Select an option..."
|
182
|
+
value={value}
|
183
|
+
onChange={(value) => setValue(value)}
|
184
|
+
{...args}
|
185
|
+
>
|
186
|
+
<SelectButton />
|
187
|
+
<SelectList />
|
188
|
+
</Select>
|
189
|
+
)
|
190
|
+
},
|
191
|
+
args: {
|
192
|
+
name: 'select',
|
193
|
+
options,
|
194
|
+
multiple: true,
|
195
|
+
},
|
124
196
|
}
|
125
197
|
|
126
|
-
export const WithIcons = {
|
198
|
+
export const WithIcons: Story = {
|
127
199
|
render: (args) => (
|
128
200
|
<Select placeholder="Select an option..." {...args}>
|
129
201
|
<SelectButton leftIcon={<Icon as={FiSmile} />} />
|
@@ -137,14 +209,21 @@ export const WithIcons = {
|
|
137
209
|
},
|
138
210
|
}
|
139
211
|
|
140
|
-
export const MaxHeight = {
|
212
|
+
export const MaxHeight: Story = {
|
141
213
|
args: {
|
142
214
|
name: 'select',
|
143
215
|
options: getOptions(100),
|
216
|
+
placeholder: 'Select an option...',
|
217
|
+
children: (
|
218
|
+
<>
|
219
|
+
<SelectButton />
|
220
|
+
<SelectList />
|
221
|
+
</>
|
222
|
+
),
|
144
223
|
},
|
145
224
|
}
|
146
225
|
|
147
|
-
export const WithChildren = {
|
226
|
+
export const WithChildren: Story = {
|
148
227
|
render: () => (
|
149
228
|
<Select name="select" defaultValue="1">
|
150
229
|
<SelectButton />
|
@@ -156,7 +235,7 @@ export const WithChildren = {
|
|
156
235
|
),
|
157
236
|
}
|
158
237
|
|
159
|
-
export const WithEmptyOption = {
|
238
|
+
export const WithEmptyOption: Story = {
|
160
239
|
render: () => (
|
161
240
|
<Select name="select" defaultValue="1">
|
162
241
|
<SelectButton />
|
@@ -169,13 +248,13 @@ export const WithEmptyOption = {
|
|
169
248
|
),
|
170
249
|
}
|
171
250
|
|
172
|
-
export const WithNativeSelect = {
|
251
|
+
export const WithNativeSelect: Story = {
|
173
252
|
render: () => (
|
174
253
|
<NativeSelect name="select" options={options} aria-label="Select" />
|
175
254
|
),
|
176
255
|
}
|
177
256
|
|
178
|
-
export const Sizes = {
|
257
|
+
export const Sizes: Story = {
|
179
258
|
render: () => (
|
180
259
|
<Stack>
|
181
260
|
<Select name="select" defaultValue="1" size="xs">
|
@@ -214,7 +293,7 @@ export const Sizes = {
|
|
214
293
|
),
|
215
294
|
}
|
216
295
|
|
217
|
-
export const Variants = {
|
296
|
+
export const Variants: Story = {
|
218
297
|
render: () => (
|
219
298
|
<Stack>
|
220
299
|
<Select name="select" defaultValue="1" variant="outline">
|
package/src/select/select.tsx
CHANGED
@@ -36,10 +36,14 @@ export interface SelectOption
|
|
36
36
|
extends Omit<MenuItemOptionProps, 'value'>,
|
37
37
|
FieldOption {}
|
38
38
|
|
39
|
-
export interface SelectProps
|
40
|
-
extends
|
39
|
+
export interface SelectProps<
|
40
|
+
Multiple extends boolean = false,
|
41
|
+
Value = Multiple extends true ? string[] : string,
|
42
|
+
> extends Omit<MenuProps, 'children' | 'variant' | 'size'>,
|
41
43
|
ThemingProps<'SuiSelect'>,
|
42
|
-
SelectOptions {
|
44
|
+
SelectOptions<Multiple, Value> {
|
45
|
+
children: React.ReactNode
|
46
|
+
}
|
43
47
|
|
44
48
|
export interface SelectButtonProps
|
45
49
|
extends Omit<ButtonProps, 'size' | 'variant'> {}
|
@@ -143,7 +147,7 @@ SelectButton.displayName = 'SelectButton'
|
|
143
147
|
*
|
144
148
|
* @see https://saas-ui.dev/docs/components/forms/select
|
145
149
|
*/
|
146
|
-
export const Select = forwardRef
|
150
|
+
export const Select = forwardRef((props, ref) => {
|
147
151
|
const { name, children, isDisabled, multiple, ...rest } = props
|
148
152
|
|
149
153
|
const styles = useMultiStyleConfig('SuiSelect', props)
|
@@ -173,7 +177,13 @@ export const Select = forwardRef<SelectProps, 'select'>((props, ref) => {
|
|
173
177
|
</SelectStylesProvider>
|
174
178
|
</SelectProvider>
|
175
179
|
)
|
176
|
-
})
|
180
|
+
}) as (<Multiple extends boolean = false>(
|
181
|
+
props: SelectProps<Multiple> & {
|
182
|
+
ref?: React.ForwardedRef<HTMLFormElement>
|
183
|
+
}
|
184
|
+
) => React.ReactElement) & {
|
185
|
+
displayName?: string
|
186
|
+
}
|
177
187
|
|
178
188
|
export interface SelectListProps extends MenuListProps {}
|
179
189
|
|