@saas-ui/forms 2.3.12 → 2.4.0

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.
@@ -19,7 +19,7 @@ export { yupResolver } from '@hookform/resolvers/yup';
19
19
 
20
20
  interface NumberInputOptions {
21
21
  /**
22
- * Hide the stepper.
22
+ * Hide the stepper. This will be true when `rightAddon` is provided.
23
23
  */
24
24
  hideStepper?: boolean;
25
25
  /**
@@ -38,6 +38,14 @@ interface NumberInputOptions {
38
38
  * Props to pass to the NumberInputField component.
39
39
  */
40
40
  fieldProps?: NumberInputFieldProps$1;
41
+ /**
42
+ * Either `InputLeftAddon` or `InputLeftElement`
43
+ */
44
+ leftAddon?: React$1.ReactNode;
45
+ /**
46
+ * Either `InputRightAddon` or `InputRightElement`
47
+ */
48
+ rightAddon?: React$1.ReactNode;
41
49
  }
42
50
  interface NumberInputProps extends NumberInputProps$1, NumberInputOptions {
43
51
  }
@@ -19,7 +19,7 @@ export { zodResolver } from '@hookform/resolvers/zod';
19
19
 
20
20
  interface NumberInputOptions {
21
21
  /**
22
- * Hide the stepper.
22
+ * Hide the stepper. This will be true when `rightAddon` is provided.
23
23
  */
24
24
  hideStepper?: boolean;
25
25
  /**
@@ -38,6 +38,14 @@ interface NumberInputOptions {
38
38
  * Props to pass to the NumberInputField component.
39
39
  */
40
40
  fieldProps?: NumberInputFieldProps$1;
41
+ /**
42
+ * Either `InputLeftAddon` or `InputLeftElement`
43
+ */
44
+ leftAddon?: React$1.ReactNode;
45
+ /**
46
+ * Either `InputRightAddon` or `InputRightElement`
47
+ */
48
+ rightAddon?: React$1.ReactNode;
41
49
  }
42
50
  interface NumberInputProps extends NumberInputProps$1, NumberInputOptions {
43
51
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saas-ui/forms",
3
- "version": "2.3.12",
3
+ "version": "2.4.0",
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.3.6",
107
+ "@saas-ui/core": "2.4.0",
108
108
  "react-hook-form": "^7.50.1"
109
109
  },
110
110
  "peerDependencies": {
package/src/auto-form.tsx CHANGED
@@ -27,8 +27,11 @@ interface AutoFormOptions {
27
27
 
28
28
  export interface AutoFormProps<
29
29
  TFieldValues extends FieldValues,
30
- TContext extends object = object
31
- > extends Omit<FormProps<TFieldValues, TContext>, 'schema' | 'children'>,
30
+ TContext extends object = object,
31
+ > extends Omit<
32
+ FormProps<TFieldValues, TContext>,
33
+ 'schema' | 'children' | 'fieldResolver'
34
+ >,
32
35
  AutoFormOptions {
33
36
  children?: React.ReactNode
34
37
  }
@@ -40,7 +43,7 @@ export interface AutoFormProps<
40
43
  export const AutoForm = forwardRef(
41
44
  <
42
45
  TFieldValues extends FieldValues = FieldValues,
43
- TContext extends object = object
46
+ TContext extends object = object,
44
47
  >(
45
48
  props: AutoFormProps<TFieldValues, TContext>,
46
49
  ref: React.ForwardedRef<HTMLFormElement>
@@ -31,9 +31,11 @@ import {
31
31
  NativeSelectProps,
32
32
  SelectButtonProps,
33
33
  SelectListProps,
34
+ SelectOption,
34
35
  } from './select'
35
36
 
36
37
  import { createField } from './create-field'
38
+ import { FieldOption, FieldOptions } from './types'
37
39
 
38
40
  export interface InputFieldProps extends InputProps {
39
41
  type?: string
@@ -95,6 +97,7 @@ export interface SelectFieldProps extends SelectProps {
95
97
  export const SelectField = createField<SelectFieldProps>(
96
98
  forwardRef((props, ref) => {
97
99
  const { buttonProps, listProps, ...rest } = props
100
+
98
101
  return (
99
102
  <Select ref={ref} {...rest}>
100
103
  <SelectButton {...buttonProps} />
@@ -1,6 +1,9 @@
1
- import { BaseFieldProps } from './types'
1
+ import { BaseFieldProps, ValueOf } from './types'
2
2
 
3
3
  import { get } from '@chakra-ui/utils'
4
+ import { ArrayFieldProps } from './array-field'
5
+ import { ObjectFieldProps } from './object-field'
6
+ import { DefaultFields } from './default-fields'
4
7
 
5
8
  export type FieldResolver = {
6
9
  getFields(): BaseFieldProps[]
@@ -9,16 +12,32 @@ export type FieldResolver = {
9
12
 
10
13
  export type GetFieldResolver<TSchema = any> = (schema: TSchema) => FieldResolver
11
14
 
12
- interface SchemaField extends BaseFieldProps {
13
- items?: SchemaField[]
14
- properties?: Record<string, SchemaField>
15
- }
15
+ type FieldTypes<FieldDefs = DefaultFields> = ValueOf<{
16
+ [K in keyof FieldDefs]: FieldDefs[K] extends React.FC<infer Props>
17
+ ? { type?: K } & Omit<Props, 'name'>
18
+ : never
19
+ }>
20
+
21
+ type SchemaField<FieldDefs = DefaultFields> =
22
+ | FieldTypes<FieldDefs>
23
+ | (Omit<ObjectFieldProps, 'name' | 'children'> & {
24
+ type: 'object'
25
+ properties?: Record<string, SchemaField<FieldDefs>>
26
+ })
27
+ | (Omit<ArrayFieldProps, 'name' | 'children'> & {
28
+ type: 'array'
29
+ items?: SchemaField<FieldDefs>
30
+ })
16
31
 
17
- export type ObjectSchema = Record<string, SchemaField>
32
+ export type ObjectSchema<FieldDefs = DefaultFields> = Record<
33
+ string,
34
+ SchemaField<FieldDefs>
35
+ >
18
36
 
19
37
  const mapFields = (schema: ObjectSchema): BaseFieldProps[] =>
20
38
  schema &&
21
- Object.entries(schema).map(([name, { items, label, title, ...field }]) => {
39
+ Object.entries(schema).map(([name, props]) => {
40
+ const { items, label, title, ...field } = props as any
22
41
  return {
23
42
  ...field,
24
43
  name,
@@ -1,4 +1,10 @@
1
- import { Container } from '@chakra-ui/react'
1
+ import {
2
+ Container,
3
+ InputLeftAddon,
4
+ InputLeftElement,
5
+ InputRightAddon,
6
+ InputRightElement,
7
+ } from '@chakra-ui/react'
2
8
  import * as React from 'react'
3
9
  import { Story, Meta } from '@storybook/react'
4
10
 
@@ -6,6 +12,7 @@ import { NumberInput } from '.'
6
12
 
7
13
  export default {
8
14
  title: 'Components/Forms/NumberInput',
15
+ component: NumberInput,
9
16
  decorators: [
10
17
  (Story: any) => (
11
18
  <Container mt="40px">
@@ -15,25 +22,39 @@ export default {
15
22
  ],
16
23
  } as Meta
17
24
 
18
- const Template: Story = (args) => <NumberInput aria-label="Number" {...args} />
25
+ export const Basic = {}
19
26
 
20
- export const Basic = Template.bind({})
21
- Basic.args = {}
27
+ export const HideStepper = {
28
+ args: {
29
+ hideStepper: true,
30
+ },
31
+ }
22
32
 
23
- export const HideStepper = Template.bind({})
24
- HideStepper.args = {
25
- hideStepper: true,
33
+ export const MinMax = {
34
+ args: {
35
+ defaultValue: 5,
36
+ min: 0,
37
+ max: 10,
38
+ },
39
+ }
40
+ export const WithFormatter = {
41
+ args: {
42
+ format: (value: any) => `$${value}`, // use any currency formatter here
43
+ parse: (value: any) => value.replace('$', ''),
44
+ },
26
45
  }
27
46
 
28
- export const MinMax = Template.bind({})
29
- MinMax.args = {
30
- defaultValue: 5,
31
- min: 0,
32
- max: 10,
47
+ export const WithAddons = {
48
+ args: {
49
+ leftAddon: <InputLeftAddon>$</InputLeftAddon>,
50
+ rightAddon: <InputRightAddon>USD</InputRightAddon>,
51
+ hideStepper: true,
52
+ },
33
53
  }
34
54
 
35
- export const WithFormatter = Template.bind({})
36
- WithFormatter.args = {
37
- format: (value: any) => `$${value}`, // use any currency formatter here
38
- parse: (value: any) => value.replace('$', ''),
55
+ export const WithElements = {
56
+ args: {
57
+ leftAddon: <InputLeftElement>$</InputLeftElement>,
58
+ rightAddon: <InputRightElement>USD</InputRightElement>,
59
+ },
39
60
  }
@@ -9,13 +9,18 @@ import {
9
9
  NumberDecrementStepper,
10
10
  NumberInputProps as ChakraNumberInputProps,
11
11
  NumberInputFieldProps,
12
+ InputGroup,
13
+ InputLeftAddon,
14
+ InputRightAddon,
15
+ InputLeftElement,
16
+ InputRightElement,
12
17
  } from '@chakra-ui/react'
13
18
 
14
19
  import { ChevronDownIcon, ChevronUpIcon } from '@saas-ui/core'
15
20
 
16
21
  interface NumberInputOptions {
17
22
  /**
18
- * Hide the stepper.
23
+ * Hide the stepper. This will be true when `rightAddon` is provided.
19
24
  */
20
25
  hideStepper?: boolean
21
26
  /**
@@ -34,8 +39,22 @@ interface NumberInputOptions {
34
39
  * Props to pass to the NumberInputField component.
35
40
  */
36
41
  fieldProps?: NumberInputFieldProps
42
+ /**
43
+ * Either `InputLeftAddon` or `InputLeftElement`
44
+ */
45
+ leftAddon?: React.ReactNode
46
+ /**
47
+ * Either `InputRightAddon` or `InputRightElement`
48
+ */
49
+ rightAddon?: React.ReactNode
37
50
  }
38
51
 
52
+ const Input = forwardRef<NumberInputFieldProps, 'input'>((props, ref) => (
53
+ <NumberInputField ref={ref} {...props} />
54
+ ))
55
+ Input.displayName = 'NumberInputField'
56
+ Input.id = 'Input'
57
+
39
58
  export interface NumberInputProps
40
59
  extends ChakraNumberInputProps,
41
60
  NumberInputOptions {}
@@ -45,6 +64,8 @@ export const NumberInput = forwardRef<NumberInputProps, 'div'>((props, ref) => {
45
64
  hideStepper = false,
46
65
  incrementIcon = <ChevronUpIcon />,
47
66
  decrementIcon = <ChevronDownIcon />,
67
+ leftAddon,
68
+ rightAddon,
48
69
  placeholder,
49
70
  fieldProps: _fieldProps,
50
71
  ...rest
@@ -54,14 +75,17 @@ export const NumberInput = forwardRef<NumberInputProps, 'div'>((props, ref) => {
54
75
 
55
76
  return (
56
77
  <ChakraNumberInput {...rest} ref={ref}>
57
- <NumberInputField {...fieldProps} />
58
-
59
- {!hideStepper && (
78
+ <InputGroup>
79
+ {leftAddon}
80
+ <Input {...fieldProps} />
81
+ {rightAddon}
82
+ </InputGroup>
83
+ {!hideStepper && !rightAddon ? (
60
84
  <NumberInputStepper>
61
85
  <NumberIncrementStepper children={incrementIcon} />
62
86
  <NumberDecrementStepper children={decrementIcon} />
63
87
  </NumberInputStepper>
64
- )}
88
+ ) : null}
65
89
  </ChakraNumberInput>
66
90
  )
67
91
  })