@saas-ui/forms 2.5.4 → 2.6.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|