@saas-ui/forms 1.5.3 → 2.0.0-next.1
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +19 -2
- package/dist/ajv/index.d.ts +21 -2
- package/dist/ajv/index.js +31 -2
- package/dist/ajv/index.js.map +1 -1
- package/dist/ajv/index.mjs +25 -0
- package/dist/ajv/index.mjs.map +1 -0
- package/dist/index.d.ts +606 -18
- package/dist/index.js +1251 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1140 -0
- package/dist/index.mjs.map +1 -0
- package/dist/yup/index.d.ts +41 -2
- package/dist/yup/index.js +95 -2
- package/dist/yup/index.js.map +1 -1
- package/dist/yup/index.mjs +86 -0
- package/dist/yup/index.mjs.map +1 -0
- package/dist/zod/index.d.ts +38 -2
- package/dist/zod/index.js +95 -2
- package/dist/zod/index.js.map +1 -1
- package/dist/zod/index.mjs +85 -0
- package/dist/zod/index.mjs.map +1 -0
- package/package.json +23 -33
- package/src/array-field.tsx +20 -13
- package/src/auto-form.tsx +13 -19
- package/src/field-resolver.ts +1 -1
- package/src/field.tsx +4 -9
- package/src/fields.tsx +1 -3
- package/src/form.tsx +69 -25
- package/src/index.ts +3 -0
- package/src/input-right-button/index.ts +1 -0
- package/src/input-right-button/input-right-button.stories.tsx +47 -0
- package/src/input-right-button/input-right-button.test.tsx +12 -0
- package/src/input-right-button/input-right-button.tsx +26 -0
- package/src/layout.tsx +1 -1
- package/src/number-input/index.ts +1 -0
- package/src/number-input/number-input.stories.tsx +39 -0
- package/src/number-input/number-input.test.tsx +6 -0
- package/src/number-input/number-input.tsx +56 -0
- package/src/object-field.tsx +1 -1
- package/src/password-input/index.ts +1 -0
- package/src/password-input/password-input.stories.tsx +50 -0
- package/src/password-input/password-input.test.tsx +20 -0
- package/src/password-input/password-input.tsx +69 -0
- package/src/pin-input/index.ts +1 -0
- package/src/pin-input/pin-input.stories.tsx +38 -0
- package/src/pin-input/pin-input.test.tsx +6 -0
- package/src/pin-input/pin-input.tsx +50 -0
- package/src/radio/index.ts +1 -0
- package/src/radio/radio-input.stories.tsx +45 -0
- package/src/radio/radio-input.tsx +58 -0
- package/src/radio/radio.test.tsx +6 -0
- package/src/select/index.ts +2 -0
- package/src/select/native-select.tsx +42 -0
- package/src/select/select.stories.tsx +144 -0
- package/src/select/select.test.tsx +8 -0
- package/src/select/select.tsx +185 -0
- package/src/step-form.tsx +24 -13
- package/src/submit-button.tsx +32 -38
- package/src/use-step-form.tsx +1 -1
- package/ajv/package.json +0 -28
- package/dist/ajv/ajv-resolver.d.ts +0 -11
- package/dist/ajv/ajv-resolver.d.ts.map +0 -1
- package/dist/ajv/index.d.ts.map +0 -1
- package/dist/ajv/index.modern.mjs +0 -2
- package/dist/ajv/index.modern.mjs.map +0 -1
- package/dist/array-field.d.ts +0 -64
- package/dist/array-field.d.ts.map +0 -1
- package/dist/auto-form.d.ts +0 -32
- package/dist/auto-form.d.ts.map +0 -1
- package/dist/display-field.d.ts +0 -10
- package/dist/display-field.d.ts.map +0 -1
- package/dist/display-if.d.ts +0 -15
- package/dist/display-if.d.ts.map +0 -1
- package/dist/field-resolver.d.ts +0 -13
- package/dist/field-resolver.d.ts.map +0 -1
- package/dist/field.d.ts +0 -147
- package/dist/field.d.ts.map +0 -1
- package/dist/fields.d.ts +0 -9
- package/dist/fields.d.ts.map +0 -1
- package/dist/form.d.ts +0 -44
- package/dist/form.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.modern.mjs +0 -2
- package/dist/index.modern.mjs.map +0 -1
- package/dist/layout.d.ts +0 -14
- package/dist/layout.d.ts.map +0 -1
- package/dist/object-field.d.ts +0 -12
- package/dist/object-field.d.ts.map +0 -1
- package/dist/step-form.d.ts +0 -38
- package/dist/step-form.d.ts.map +0 -1
- package/dist/submit-button.d.ts +0 -20
- package/dist/submit-button.d.ts.map +0 -1
- package/dist/use-array-field.d.ts +0 -95
- package/dist/use-array-field.d.ts.map +0 -1
- package/dist/use-step-form.d.ts +0 -40
- package/dist/use-step-form.d.ts.map +0 -1
- package/dist/utils.d.ts +0 -3
- package/dist/utils.d.ts.map +0 -1
- package/dist/watch-field.d.ts +0 -11
- package/dist/watch-field.d.ts.map +0 -1
- package/dist/yup/index.d.ts.map +0 -1
- package/dist/yup/index.modern.mjs +0 -2
- package/dist/yup/index.modern.mjs.map +0 -1
- package/dist/yup/yup-resolver.d.ts +0 -29
- package/dist/yup/yup-resolver.d.ts.map +0 -1
- package/dist/zod/index.d.ts.map +0 -1
- package/dist/zod/index.modern.mjs +0 -2
- package/dist/zod/index.modern.mjs.map +0 -1
- package/dist/zod/zod-resolver.d.ts +0 -35
- package/dist/zod/zod-resolver.d.ts.map +0 -1
- package/yup/package.json +0 -26
- package/zod/package.json +0 -27
@@ -0,0 +1,12 @@
|
|
1
|
+
import * as React from 'react'
|
2
|
+
|
3
|
+
import { render, testStories } from '@saas-ui/test-utils'
|
4
|
+
import * as stories from './input-right-button.stories'
|
5
|
+
|
6
|
+
const { Basic } = testStories<typeof stories>(stories)
|
7
|
+
|
8
|
+
test('should render a label', async () => {
|
9
|
+
const { getByText } = render(<Basic />)
|
10
|
+
|
11
|
+
expect(getByText('Save')).toBeVisible()
|
12
|
+
})
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import * as React from 'react'
|
2
|
+
|
3
|
+
import {
|
4
|
+
Button,
|
5
|
+
ButtonProps,
|
6
|
+
forwardRef,
|
7
|
+
InputRightElement,
|
8
|
+
} from '@chakra-ui/react'
|
9
|
+
|
10
|
+
import { __DEV__ } from '@chakra-ui/utils'
|
11
|
+
|
12
|
+
export type InputRightButtonProps = ButtonProps
|
13
|
+
|
14
|
+
export const InputRightButton = forwardRef<InputRightButtonProps, 'div'>(
|
15
|
+
(props, ref) => {
|
16
|
+
return (
|
17
|
+
<InputRightElement w="auto" px="1" py="1" alignItems="stretch">
|
18
|
+
<Button ref={ref} height="auto" {...props} />
|
19
|
+
</InputRightElement>
|
20
|
+
)
|
21
|
+
}
|
22
|
+
)
|
23
|
+
|
24
|
+
InputRightButton.id = 'InputRightElement'
|
25
|
+
|
26
|
+
InputRightButton.displayName = 'InputRightButton'
|
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('
|
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,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
|
+
}
|
package/src/object-field.tsx
CHANGED
@@ -21,7 +21,7 @@ export interface ObjectFieldProps extends FieldProps {
|
|
21
21
|
}
|
22
22
|
|
23
23
|
export const FormLegend = (props: FormLabelProps) => {
|
24
|
-
const styles = useStyleConfig('
|
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,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,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
|
+
}
|