@saas-ui/forms 1.5.3 → 2.0.0-next.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. package/CHANGELOG.md +11 -2
  2. package/dist/ajv/index.d.ts +21 -2
  3. package/dist/ajv/index.js +31 -2
  4. package/dist/ajv/index.js.map +1 -1
  5. package/dist/ajv/index.mjs +25 -0
  6. package/dist/ajv/index.mjs.map +1 -0
  7. package/dist/index.d.ts +606 -18
  8. package/dist/index.js +1251 -2
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +1140 -0
  11. package/dist/index.mjs.map +1 -0
  12. package/dist/yup/index.d.ts +41 -2
  13. package/dist/yup/index.js +95 -2
  14. package/dist/yup/index.js.map +1 -1
  15. package/dist/yup/index.mjs +86 -0
  16. package/dist/yup/index.mjs.map +1 -0
  17. package/dist/zod/index.d.ts +38 -2
  18. package/dist/zod/index.js +95 -2
  19. package/dist/zod/index.js.map +1 -1
  20. package/dist/zod/index.mjs +85 -0
  21. package/dist/zod/index.mjs.map +1 -0
  22. package/package.json +18 -28
  23. package/src/array-field.tsx +20 -13
  24. package/src/auto-form.tsx +13 -19
  25. package/src/field-resolver.ts +1 -1
  26. package/src/field.tsx +4 -9
  27. package/src/fields.tsx +1 -3
  28. package/src/form.tsx +69 -25
  29. package/src/index.ts +3 -0
  30. package/src/input-right-button/index.ts +1 -0
  31. package/src/input-right-button/input-right-button.stories.tsx +47 -0
  32. package/src/input-right-button/input-right-button.test.tsx +12 -0
  33. package/src/input-right-button/input-right-button.tsx +26 -0
  34. package/src/layout.tsx +1 -1
  35. package/src/number-input/index.ts +1 -0
  36. package/src/number-input/number-input.stories.tsx +39 -0
  37. package/src/number-input/number-input.test.tsx +6 -0
  38. package/src/number-input/number-input.tsx +56 -0
  39. package/src/object-field.tsx +1 -1
  40. package/src/password-input/index.ts +1 -0
  41. package/src/password-input/password-input.stories.tsx +50 -0
  42. package/src/password-input/password-input.test.tsx +20 -0
  43. package/src/password-input/password-input.tsx +69 -0
  44. package/src/pin-input/index.ts +1 -0
  45. package/src/pin-input/pin-input.stories.tsx +38 -0
  46. package/src/pin-input/pin-input.test.tsx +6 -0
  47. package/src/pin-input/pin-input.tsx +50 -0
  48. package/src/radio/index.ts +1 -0
  49. package/src/radio/radio-input.stories.tsx +45 -0
  50. package/src/radio/radio-input.tsx +58 -0
  51. package/src/radio/radio.test.tsx +6 -0
  52. package/src/select/index.ts +2 -0
  53. package/src/select/native-select.tsx +42 -0
  54. package/src/select/select.stories.tsx +144 -0
  55. package/src/select/select.test.tsx +8 -0
  56. package/src/select/select.tsx +185 -0
  57. package/src/step-form.tsx +24 -13
  58. package/src/submit-button.tsx +32 -38
  59. package/src/use-step-form.tsx +1 -1
  60. package/ajv/package.json +0 -28
  61. package/dist/ajv/ajv-resolver.d.ts +0 -11
  62. package/dist/ajv/ajv-resolver.d.ts.map +0 -1
  63. package/dist/ajv/index.d.ts.map +0 -1
  64. package/dist/ajv/index.modern.mjs +0 -2
  65. package/dist/ajv/index.modern.mjs.map +0 -1
  66. package/dist/array-field.d.ts +0 -64
  67. package/dist/array-field.d.ts.map +0 -1
  68. package/dist/auto-form.d.ts +0 -32
  69. package/dist/auto-form.d.ts.map +0 -1
  70. package/dist/display-field.d.ts +0 -10
  71. package/dist/display-field.d.ts.map +0 -1
  72. package/dist/display-if.d.ts +0 -15
  73. package/dist/display-if.d.ts.map +0 -1
  74. package/dist/field-resolver.d.ts +0 -13
  75. package/dist/field-resolver.d.ts.map +0 -1
  76. package/dist/field.d.ts +0 -147
  77. package/dist/field.d.ts.map +0 -1
  78. package/dist/fields.d.ts +0 -9
  79. package/dist/fields.d.ts.map +0 -1
  80. package/dist/form.d.ts +0 -44
  81. package/dist/form.d.ts.map +0 -1
  82. package/dist/index.d.ts.map +0 -1
  83. package/dist/index.modern.mjs +0 -2
  84. package/dist/index.modern.mjs.map +0 -1
  85. package/dist/layout.d.ts +0 -14
  86. package/dist/layout.d.ts.map +0 -1
  87. package/dist/object-field.d.ts +0 -12
  88. package/dist/object-field.d.ts.map +0 -1
  89. package/dist/step-form.d.ts +0 -38
  90. package/dist/step-form.d.ts.map +0 -1
  91. package/dist/submit-button.d.ts +0 -20
  92. package/dist/submit-button.d.ts.map +0 -1
  93. package/dist/use-array-field.d.ts +0 -95
  94. package/dist/use-array-field.d.ts.map +0 -1
  95. package/dist/use-step-form.d.ts +0 -40
  96. package/dist/use-step-form.d.ts.map +0 -1
  97. package/dist/utils.d.ts +0 -3
  98. package/dist/utils.d.ts.map +0 -1
  99. package/dist/watch-field.d.ts +0 -11
  100. package/dist/watch-field.d.ts.map +0 -1
  101. package/dist/yup/index.d.ts.map +0 -1
  102. package/dist/yup/index.modern.mjs +0 -2
  103. package/dist/yup/index.modern.mjs.map +0 -1
  104. package/dist/yup/yup-resolver.d.ts +0 -29
  105. package/dist/yup/yup-resolver.d.ts.map +0 -1
  106. package/dist/zod/index.d.ts.map +0 -1
  107. package/dist/zod/index.modern.mjs +0 -2
  108. package/dist/zod/index.modern.mjs.map +0 -1
  109. package/dist/zod/zod-resolver.d.ts +0 -35
  110. package/dist/zod/zod-resolver.d.ts.map +0 -1
  111. package/yup/package.json +0 -26
  112. package/zod/package.json +0 -27
package/src/layout.tsx CHANGED
@@ -38,7 +38,7 @@ export const FormLayout = ({ children, ...props }: FormLayoutProps) => {
38
38
  return (
39
39
  <SimpleGrid
40
40
  {...gridProps}
41
- className={cx('saas-form__layout', props.className)}
41
+ className={cx('sui-form__layout', props.className)}
42
42
  >
43
43
  {React.Children.map(children, (child) => {
44
44
  if (React.isValidElement(child)) {
@@ -0,0 +1 @@
1
+ export * from './number-input'
@@ -0,0 +1,39 @@
1
+ import { Container } from '@chakra-ui/react'
2
+ import * as React from 'react'
3
+ import { Story, Meta } from '@storybook/react'
4
+
5
+ import { NumberInput } from '../src'
6
+
7
+ export default {
8
+ title: 'Components/Forms/NumberInput',
9
+ decorators: [
10
+ (Story: any) => (
11
+ <Container mt="40px">
12
+ <Story />
13
+ </Container>
14
+ ),
15
+ ],
16
+ } as Meta
17
+
18
+ const Template: Story = (args) => <NumberInput aria-label="Number" {...args} />
19
+
20
+ export const Basic = Template.bind({})
21
+ Basic.args = {}
22
+
23
+ export const HideStepper = Template.bind({})
24
+ HideStepper.args = {
25
+ hideStepper: true,
26
+ }
27
+
28
+ export const MinMax = Template.bind({})
29
+ MinMax.args = {
30
+ defaultValue: 5,
31
+ min: 0,
32
+ max: 10,
33
+ }
34
+
35
+ export const WithFormatter = Template.bind({})
36
+ WithFormatter.args = {
37
+ format: (value) => `$${value}`, // use any currency formatter here
38
+ parse: (value) => value.replace('$', ''),
39
+ }
@@ -0,0 +1,6 @@
1
+ import * as React from 'react'
2
+
3
+ import { render, testStories } from '@saas-ui/test-utils'
4
+ import * as stories from './number-input.stories'
5
+
6
+ testStories<typeof stories>(stories)
@@ -0,0 +1,56 @@
1
+ import * as React from 'react'
2
+
3
+ import {
4
+ forwardRef,
5
+ NumberInput as ChakraNumberInput,
6
+ NumberInputField,
7
+ NumberInputStepper,
8
+ NumberIncrementStepper,
9
+ NumberDecrementStepper,
10
+ NumberInputProps as ChakraNumberInputProps,
11
+ } from '@chakra-ui/react'
12
+ import { __DEV__ } from '@chakra-ui/utils'
13
+
14
+ interface NumberInputOptions {
15
+ /**
16
+ * Hide the stepper.
17
+ */
18
+ hideStepper?: boolean
19
+ /**
20
+ * Render a custom increment icon.
21
+ */
22
+ incrementIcon?: React.ReactNode
23
+ /**
24
+ * Render a custom decrement icon.
25
+ */
26
+ decrementIcon?: React.ReactNode
27
+ }
28
+
29
+ export interface NumberInputProps
30
+ extends ChakraNumberInputProps,
31
+ NumberInputOptions {}
32
+
33
+ export const NumberInput = forwardRef<NumberInputProps, 'div'>((props, ref) => {
34
+ const { hideStepper, incrementIcon, decrementIcon, ...rest } = props
35
+
36
+ return (
37
+ <ChakraNumberInput {...rest} ref={ref}>
38
+ <NumberInputField />
39
+
40
+ {!hideStepper && (
41
+ <NumberInputStepper>
42
+ <NumberIncrementStepper children={incrementIcon} />
43
+ <NumberDecrementStepper children={decrementIcon} />
44
+ </NumberInputStepper>
45
+ )}
46
+ </ChakraNumberInput>
47
+ )
48
+ })
49
+
50
+ NumberInput.defaultProps = {
51
+ hideStepper: false,
52
+ }
53
+
54
+ if (__DEV__) {
55
+ NumberInput.displayName = 'NumberInput'
56
+ }
@@ -21,7 +21,7 @@ export interface ObjectFieldProps extends FieldProps {
21
21
  }
22
22
 
23
23
  export const FormLegend = (props: FormLabelProps) => {
24
- const styles = useStyleConfig('FormLegend')
24
+ const styles = useStyleConfig('SuiFormLegend')
25
25
  return <FormLabel as="legend" sx={styles} {...props} />
26
26
  }
27
27
 
@@ -0,0 +1 @@
1
+ export * from './password-input'
@@ -0,0 +1,50 @@
1
+ import { Container, FormControl, FormLabel, Icon } from '@chakra-ui/react'
2
+ import { Story } from '@storybook/react'
3
+ import * as React from 'react'
4
+
5
+ import { FiEye, FiEyeOff } from 'react-icons/fi'
6
+
7
+ import { PasswordInput } from './password-input'
8
+
9
+ export default {
10
+ title: 'Components/Forms/PasswordInput',
11
+ decorators: [
12
+ (Story: any) => (
13
+ <Container mt="40px">
14
+ <Story />
15
+ </Container>
16
+ ),
17
+ ],
18
+ }
19
+
20
+ export const Basic: Story = () => (
21
+ <FormControl>
22
+ <FormLabel>Password</FormLabel>
23
+ <PasswordInput name="password" placeholder="Password" />
24
+ </FormControl>
25
+ )
26
+
27
+ export const ReactIcons: Story = () => (
28
+ <>
29
+ <PasswordInput
30
+ name="password"
31
+ placeholder="Password"
32
+ viewIcon={<Icon as={FiEye} />}
33
+ viewOffIcon={<Icon as={FiEyeOff} />}
34
+ />
35
+ </>
36
+ )
37
+
38
+ export const Variant: Story = () => (
39
+ <FormControl>
40
+ <FormLabel>Password</FormLabel>
41
+ <PasswordInput name="password" variant="flushed" />
42
+ </FormControl>
43
+ )
44
+
45
+ export const CustomWidth: Story = () => (
46
+ <FormControl>
47
+ <FormLabel>Password</FormLabel>
48
+ <PasswordInput name="password" width="200px" />
49
+ </FormControl>
50
+ )
@@ -0,0 +1,20 @@
1
+ import * as React from 'react'
2
+
3
+ import { render, act, fireEvent, testStories } from '@saas-ui/test-utils'
4
+ import * as stories from './password-input.stories'
5
+
6
+ const { Basic } = testStories<typeof stories>(stories)
7
+
8
+ test('should render correct aria labels', async () => {
9
+ const { getByText, getByLabelText, getByPlaceholderText, getByRole } = render(
10
+ <Basic />
11
+ )
12
+
13
+ const toggle = getByLabelText('Show password')
14
+
15
+ await act(async () => {
16
+ fireEvent.click(toggle)
17
+ })
18
+
19
+ expect(toggle).toHaveAttribute('aria-label', 'Hide password')
20
+ })
@@ -0,0 +1,69 @@
1
+ import React, { useState } from 'react'
2
+
3
+ import { forwardRef, InputGroup, Input, InputProps } from '@chakra-ui/react'
4
+ import { __DEV__ } from '@chakra-ui/utils'
5
+ import { ViewIcon, ViewOffIcon } from '@chakra-ui/icons'
6
+
7
+ import { InputRightButton } from '../input-right-button'
8
+
9
+ interface PasswordOptions {
10
+ viewIcon?: React.ReactNode
11
+ viewOffIcon?: React.ReactNode
12
+ }
13
+
14
+ export interface PasswordInputProps extends InputProps, PasswordOptions {}
15
+
16
+ export const PasswordInput = forwardRef<PasswordInputProps, 'div'>(
17
+ (props, ref) => {
18
+ const {
19
+ viewIcon,
20
+ viewOffIcon,
21
+ autoComplete,
22
+ w,
23
+ width,
24
+ size,
25
+ variant,
26
+ ...inputProps
27
+ } = props
28
+ const [show, setShow] = useState(false)
29
+ const handleClick = () => setShow(!show)
30
+
31
+ const label = show ? 'Hide password' : 'Show password'
32
+
33
+ let icon
34
+ if (show) {
35
+ icon = viewIcon || <ViewIcon />
36
+ } else {
37
+ icon = viewOffIcon || <ViewOffIcon />
38
+ }
39
+
40
+ const groupProps = {
41
+ width: w || width,
42
+ size,
43
+ variant,
44
+ }
45
+
46
+ return (
47
+ <InputGroup {...groupProps}>
48
+ <Input
49
+ {...inputProps}
50
+ ref={ref}
51
+ type={show ? 'text' : 'password'}
52
+ autoComplete={show ? 'off' : autoComplete}
53
+ />
54
+
55
+ <InputRightButton
56
+ onClick={handleClick}
57
+ aria-label={label}
58
+ variant="ghost"
59
+ >
60
+ {icon}
61
+ </InputRightButton>
62
+ </InputGroup>
63
+ )
64
+ }
65
+ )
66
+
67
+ if (__DEV__) {
68
+ PasswordInput.displayName = 'PasswordInput'
69
+ }
@@ -0,0 +1 @@
1
+ export * from './pin-input'
@@ -0,0 +1,38 @@
1
+ import { Container } from '@chakra-ui/react'
2
+ import * as React from 'react'
3
+
4
+ import { ComponentStory } from '@storybook/react'
5
+
6
+ import { PinInput } from './pin-input'
7
+
8
+ export default {
9
+ title: 'Components/Forms/PinInput',
10
+ decorators: [
11
+ (Story: any) => (
12
+ <Container mt="40px">
13
+ <Story />
14
+ </Container>
15
+ ),
16
+ ],
17
+ }
18
+
19
+ const Template: ComponentStory<typeof PinInput> = (args) => (
20
+ <PinInput {...args} />
21
+ )
22
+
23
+ export const Basic = Template.bind({})
24
+ Basic.args = {
25
+ /**
26
+ * Description
27
+ */
28
+ name: 'pin-input',
29
+ }
30
+
31
+ export const PinLength = Template.bind({})
32
+ PinLength.args = {
33
+ /**
34
+ * Description
35
+ */
36
+ name: 'pin-input',
37
+ pinLength: 10,
38
+ }
@@ -0,0 +1,6 @@
1
+ import * as React from 'react'
2
+
3
+ import { render, testStories } from '@saas-ui/test-utils'
4
+ import * as stories from './pin-input.stories'
5
+
6
+ testStories<typeof stories>(stories)
@@ -0,0 +1,50 @@
1
+ import * as React from 'react'
2
+ import {
3
+ forwardRef,
4
+ PinInput as ChakraPinInput,
5
+ UsePinInputProps,
6
+ PinInputField,
7
+ HStack,
8
+ SystemProps,
9
+ } from '@chakra-ui/react'
10
+
11
+ import { __DEV__ } from '@chakra-ui/utils'
12
+
13
+ interface PinInputOptions {
14
+ /**
15
+ * The pin length.
16
+ */
17
+ pinLength?: number
18
+ /**
19
+ * Spacing between the inputs.
20
+ */
21
+ spacing?: SystemProps['margin']
22
+ }
23
+
24
+ export interface PinInputProps extends UsePinInputProps, PinInputOptions {}
25
+
26
+ /**
27
+ * @deprecated
28
+ */
29
+ export const PinInput = forwardRef<PinInputProps, 'div'>((props, ref) => {
30
+ const { pinLength = 4, spacing, ...inputProps } = props
31
+
32
+ const inputs: React.ReactNode[] = []
33
+ for (let i = 0; i < pinLength; i++) {
34
+ inputs.push(<PinInputField key={i} ref={ref} />)
35
+ }
36
+
37
+ return (
38
+ <HStack spacing={spacing}>
39
+ <ChakraPinInput {...inputProps}>{inputs}</ChakraPinInput>
40
+ </HStack>
41
+ )
42
+ })
43
+
44
+ PinInput.defaultProps = {
45
+ pinLength: 4,
46
+ }
47
+
48
+ if (__DEV__) {
49
+ PinInput.displayName = 'PinInput'
50
+ }
@@ -0,0 +1 @@
1
+ export * from './radio-input'
@@ -0,0 +1,45 @@
1
+ import { Container } from '@chakra-ui/react'
2
+ import * as React from 'react'
3
+
4
+ import { ComponentStory } from '@storybook/react'
5
+
6
+ import { RadioInput } from './'
7
+
8
+ export default {
9
+ title: 'Components/Forms/Radio',
10
+ decorators: [
11
+ (Story: any) => (
12
+ <Container mt="40px">
13
+ <Story />
14
+ </Container>
15
+ ),
16
+ ],
17
+ }
18
+
19
+ const options = [
20
+ {
21
+ value: '1',
22
+ label: 'Option 1',
23
+ },
24
+ {
25
+ value: '2',
26
+ label: 'Option 2',
27
+ },
28
+ ]
29
+
30
+ const Template: ComponentStory<typeof RadioInput> = (args) => (
31
+ <RadioInput {...args} />
32
+ )
33
+
34
+ export const Basic = Template.bind({})
35
+ Basic.args = {
36
+ name: 'radio',
37
+ options,
38
+ }
39
+
40
+ export const Direction = Template.bind({})
41
+ Direction.args = {
42
+ name: 'radio',
43
+ direction: 'row',
44
+ options,
45
+ }
@@ -0,0 +1,58 @@
1
+ import * as React from 'react'
2
+
3
+ import {
4
+ forwardRef,
5
+ Stack,
6
+ RadioGroup,
7
+ RadioGroupProps,
8
+ Radio,
9
+ RadioProps,
10
+ SystemProps,
11
+ StackDirection,
12
+ } from '@chakra-ui/react'
13
+ import { __DEV__ } from '@chakra-ui/utils'
14
+
15
+ interface Option extends RadioProps {
16
+ value: string
17
+ label?: string
18
+ }
19
+
20
+ interface RadioInputOptions {
21
+ options: Option[]
22
+ spacing?: SystemProps['margin']
23
+ direction?: StackDirection
24
+ }
25
+
26
+ export interface RadioInputProps
27
+ extends Omit<RadioGroupProps, 'children'>,
28
+ RadioInputOptions {}
29
+
30
+ export const RadioInput = forwardRef<RadioInputProps, 'div'>(
31
+ ({ options, spacing, direction, ...props }, ref) => {
32
+ const { onBlur, onChange, ...groupProps } = props
33
+
34
+ return (
35
+ <RadioGroup onChange={onChange} {...groupProps}>
36
+ <Stack spacing={spacing} direction={direction}>
37
+ {options.map(({ value, label, ...radioProps }, i) => {
38
+ return (
39
+ <Radio
40
+ key={i}
41
+ onBlur={onBlur}
42
+ value={value}
43
+ ref={ref}
44
+ {...radioProps}
45
+ >
46
+ {label || value}
47
+ </Radio>
48
+ )
49
+ })}
50
+ </Stack>
51
+ </RadioGroup>
52
+ )
53
+ }
54
+ )
55
+
56
+ if (__DEV__) {
57
+ RadioInput.displayName = 'RadioInput'
58
+ }
@@ -0,0 +1,6 @@
1
+ import * as React from 'react'
2
+
3
+ import { render, testStories } from '@saas-ui/test-utils'
4
+ import * as stories from './radio-input.stories'
5
+
6
+ testStories<typeof stories>(stories)
@@ -0,0 +1,2 @@
1
+ export * from './select'
2
+ export * from './native-select'
@@ -0,0 +1,42 @@
1
+ import * as React from 'react'
2
+
3
+ import {
4
+ forwardRef,
5
+ Select as ChakraSelect,
6
+ SelectProps as ChakraSelectProps,
7
+ } from '@chakra-ui/react'
8
+ import { __DEV__ } from '@chakra-ui/utils'
9
+
10
+ interface Option {
11
+ value: string
12
+ label?: string
13
+ }
14
+
15
+ interface NativeSelectOptions {
16
+ options?: Option[]
17
+ }
18
+
19
+ export interface NativeSelectProps
20
+ extends ChakraSelectProps,
21
+ NativeSelectOptions {}
22
+
23
+ export const NativeSelect = forwardRef<NativeSelectProps, 'select'>(
24
+ ({ options, children, ...props }, ref) => {
25
+ return (
26
+ <ChakraSelect ref={ref} {...props}>
27
+ {children ||
28
+ options?.map(({ value, label }) => {
29
+ return (
30
+ <option key={value} value={value}>
31
+ {label || value}
32
+ </option>
33
+ )
34
+ })}
35
+ </ChakraSelect>
36
+ )
37
+ }
38
+ )
39
+
40
+ if (__DEV__) {
41
+ NativeSelect.displayName = 'NativeSelect'
42
+ }
@@ -0,0 +1,144 @@
1
+ import {
2
+ Container,
3
+ Icon,
4
+ MenuItemOption,
5
+ Tag,
6
+ Wrap,
7
+ WrapItem,
8
+ } from '@chakra-ui/react'
9
+ import * as React from 'react'
10
+
11
+ import { ComponentStory } from '@storybook/react'
12
+
13
+ import { Select } from '../src/select'
14
+ import { NativeSelect } from '../src/native-select'
15
+
16
+ import { FiSmile } from 'react-icons/fi'
17
+
18
+ export default {
19
+ title: 'Components/Forms/Select',
20
+ decorators: [
21
+ (Story: any) => (
22
+ <Container mt="40px" maxW="320px">
23
+ <Story />
24
+ </Container>
25
+ ),
26
+ ],
27
+ }
28
+
29
+ const getOptions = (length = 6) =>
30
+ Array.from({ length }).map((_node, index) => ({
31
+ value: String(index),
32
+ label: `Option ${index + 1}`,
33
+ }))
34
+
35
+ const options = getOptions()
36
+
37
+ const Template: ComponentStory<typeof Select> = (args) => (
38
+ <Select placeholder="Select an option..." {...args} />
39
+ )
40
+
41
+ export const Basic = Template.bind({})
42
+ Basic.args = {
43
+ name: 'select',
44
+ options,
45
+ }
46
+
47
+ export const DefaultValue = Template.bind({})
48
+ DefaultValue.args = {
49
+ name: 'select',
50
+ options,
51
+ defaultValue: 1,
52
+ }
53
+
54
+ export const Placeholder = Template.bind({})
55
+ Placeholder.args = {
56
+ name: 'select',
57
+ options,
58
+ placeholder: 'Select an option...',
59
+ }
60
+
61
+ export const Disabled = Template.bind({})
62
+ Disabled.args = {
63
+ name: 'select',
64
+ options,
65
+ placeholder: 'Disabled.',
66
+ isDisabled: true,
67
+ }
68
+
69
+ export const Multi = Template.bind({})
70
+ Multi.args = {
71
+ name: 'select',
72
+ options,
73
+ placeholder: 'Multiple.',
74
+ multiple: true,
75
+ }
76
+
77
+ export const MultiWithDefaultValue = Template.bind({})
78
+ MultiWithDefaultValue.args = {
79
+ name: 'select',
80
+ options,
81
+ placeholder: 'Select an option...',
82
+ multiple: true,
83
+ defaultValue: ['1'],
84
+ }
85
+
86
+ export const MultiWithTags = Template.bind({})
87
+ MultiWithTags.args = {
88
+ name: 'select',
89
+ options,
90
+ placeholder: 'Select options...',
91
+ multiple: true,
92
+ renderValue: (selected) => {
93
+ if (selected?.length) {
94
+ return (
95
+ <Wrap py="1">
96
+ {selected.map((value) => (
97
+ <WrapItem>
98
+ <Tag>{value}</Tag>
99
+ </WrapItem>
100
+ ))}
101
+ </Wrap>
102
+ )
103
+ }
104
+ },
105
+ }
106
+
107
+ export const WithIcons = Template.bind({})
108
+ WithIcons.args = {
109
+ name: 'select',
110
+ options,
111
+ value: 1,
112
+ leftIcon: <Icon as={FiSmile} />,
113
+ }
114
+
115
+ export const MaxHeight = Template.bind({})
116
+ MaxHeight.args = {
117
+ name: 'select',
118
+ options: getOptions(100),
119
+ }
120
+
121
+ export const WithChildren = () => {
122
+ return (
123
+ <Select name="select" value="1">
124
+ <MenuItemOption value="1">Option 1</MenuItemOption>
125
+ <MenuItemOption value="2">Option 1</MenuItemOption>
126
+ </Select>
127
+ )
128
+ }
129
+
130
+ export const WithEmptyOption = () => {
131
+ return (
132
+ <Select name="select" value="1">
133
+ <MenuItemOption value="">None</MenuItemOption>
134
+ <MenuItemOption value="1">Option 1</MenuItemOption>
135
+ <MenuItemOption value="2">Option 1</MenuItemOption>
136
+ </Select>
137
+ )
138
+ }
139
+
140
+ export const WithNativeSelect = () => (
141
+ <>
142
+ <NativeSelect name="select" options={options} aria-label="Select" />
143
+ </>
144
+ )
@@ -0,0 +1,8 @@
1
+ import * as React from 'react'
2
+
3
+ import { render, testStories } from '@saas-ui/test-utils'
4
+ import * as stories from '../stories/select.stories'
5
+
6
+ const { MaxHeight, ...rest } = stories
7
+
8
+ testStories<typeof rest>(rest)