@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/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