@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saas-ui/forms",
3
- "version": "2.5.4",
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.4.4",
107
+ "@saas-ui/core": "2.5.0",
108
108
  "react-hook-form": "^7.50.1"
109
109
  },
110
110
  "peerDependencies": {
@@ -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?: string | string[]
33
+ value?: Value
31
34
  /**
32
35
  * The initial value of the select field.
33
36
  */
34
- defaultValue?: string | string[]
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: string | string[]) => void
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?: boolean
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: string | string[]) => React.ReactNode
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 { StoryFn } from '@storybook/react'
4
+ import { StoryObj } from '@storybook/react'
13
5
 
14
- import { Select, SelectButton, SelectList, SelectOption } from './select'
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
- const Template: StoryFn<typeof Select> = (args) => (
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: Template,
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 Test = {
119
- render: () => (
120
- <Tag variant="outline" colorScheme="teal">
121
- Test
122
- </Tag>
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">
@@ -36,10 +36,14 @@ export interface SelectOption
36
36
  extends Omit<MenuItemOptionProps, 'value'>,
37
37
  FieldOption {}
38
38
 
39
- export interface SelectProps
40
- extends Omit<MenuProps, 'children' | 'variant' | 'size'>,
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<SelectProps, 'select'>((props, ref) => {
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