@saas-ui/modals 2.0.0-next.14 → 2.0.0-next.16

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/src/form.tsx CHANGED
@@ -1,6 +1,12 @@
1
1
  import * as React from 'react'
2
2
 
3
- import { ModalBody, ModalFooter, Button, forwardRef } from '@chakra-ui/react'
3
+ import {
4
+ ModalBody,
5
+ ModalFooter,
6
+ Button,
7
+ forwardRef,
8
+ ButtonProps,
9
+ } from '@chakra-ui/react'
4
10
  import { runIfFn } from '@saas-ui/react-utils'
5
11
 
6
12
  import {
@@ -11,10 +17,19 @@ import {
11
17
  FieldValues,
12
18
  FieldResolver,
13
19
  FieldProps,
20
+ FormType,
21
+ DefaultFieldOverrides,
14
22
  } from '@saas-ui/forms'
15
23
 
24
+ import { YupFormType } from '@saas-ui/forms/yup'
25
+ import { ZodFormType } from '@saas-ui/forms/zod'
26
+
16
27
  import { BaseModal, BaseModalProps } from './modal'
17
28
 
29
+ export type FormDialogFieldOverrides = DefaultFieldOverrides & {
30
+ cancel?: ButtonProps
31
+ }
32
+
18
33
  export interface FormDialogProps<
19
34
  TFieldValues extends FieldValues = FieldValues,
20
35
  TContext extends object = object,
@@ -46,100 +61,149 @@ export interface FormDialogProps<
46
61
  * Defaults to a cancel and submit button.
47
62
  */
48
63
  footer?: React.ReactNode
49
- /**
50
- * The cancel button label
51
- * @default "Cancel"
52
- */
53
- cancelLabel?: React.ReactNode
54
- /**
55
- * The submit button label
56
- * @default "Submit"
57
- */
58
- submitLabel?: React.ReactNode
59
64
  /**
60
65
  * A schema field resolver used to auto generate form fields.
61
66
  */
62
67
  fieldResolver?: FieldResolver
68
+ /**
69
+ * Field overrides
70
+ */
71
+ fields?: FormDialogFieldOverrides
72
+ }
73
+
74
+ const useFormProps = (props: FormDialogProps) => {
75
+ const {
76
+ schema,
77
+ resolver,
78
+ fieldResolver,
79
+ defaultValues,
80
+ values,
81
+ context,
82
+ onChange,
83
+ onSubmit,
84
+ onError,
85
+ mode,
86
+ reValidateMode,
87
+ shouldFocusError = true,
88
+ shouldUnregister,
89
+ shouldUseNativeValidation,
90
+ criteriaMode,
91
+ delayError = 100,
92
+ fields,
93
+ ...modalProps
94
+ } = props
95
+
96
+ const formProps = {
97
+ schema,
98
+ resolver,
99
+ defaultValues,
100
+ values,
101
+ context,
102
+ onChange,
103
+ onSubmit,
104
+ onError,
105
+ mode,
106
+ reValidateMode,
107
+ shouldFocusError,
108
+ shouldUnregister,
109
+ shouldUseNativeValidation,
110
+ criteriaMode,
111
+ delayError,
112
+ fields,
113
+ }
114
+
115
+ return { modalProps, formProps, fields }
63
116
  }
117
+
64
118
  /**
65
- * Can be used to quickly request information from people without leaving the current page.
66
- *
67
- * @see Docs https://saas-ui.dev/docs/components/overlay/form-dialog
119
+ * @todo make this dynamic to support other schema types
68
120
  */
69
- export const FormDialog = forwardRef(
70
- <
71
- TFieldValues extends FieldValues = FieldValues,
72
- TContext extends object = object
73
- >(
74
- props: FormDialogProps<TFieldValues, TContext>,
75
- ref: React.ForwardedRef<HTMLFormElement>
76
- ) => {
77
- const {
78
- children,
79
- schema,
80
- resolver,
81
- fieldResolver,
82
- defaultValues,
83
- values,
84
- context,
85
- onChange,
86
- onSubmit,
87
- onError,
88
- mode,
89
- reValidateMode,
90
- shouldFocusError = true,
91
- shouldUnregister,
92
- shouldUseNativeValidation,
93
- criteriaMode,
94
- delayError = 100,
95
- cancelLabel = 'Cancel',
96
- submitLabel = 'Submit',
97
- footer,
98
- isOpen,
99
- onClose,
100
- ...rest
101
- } = props
102
-
103
- const formProps = {
104
- ref,
105
- schema,
106
- resolver,
107
- defaultValues,
108
- values,
109
- context,
110
- onChange,
111
- onSubmit,
112
- onError,
113
- mode,
114
- reValidateMode,
115
- shouldFocusError,
116
- shouldUnregister,
117
- shouldUseNativeValidation,
118
- criteriaMode,
119
- delayError,
120
- }
121
+ type MergeDialogProps<T> = T extends YupFormType<
122
+ infer FieldDefs,
123
+ infer ExtraProps,
124
+ infer ExtraOverrides,
125
+ 'yup'
126
+ >
127
+ ? YupFormType<
128
+ FieldDefs,
129
+ ExtraProps & Omit<BaseModalProps, 'children'>,
130
+ ExtraOverrides & FormDialogFieldOverrides
131
+ >
132
+ : T extends ZodFormType<
133
+ infer FieldDefs,
134
+ infer ExtraProps,
135
+ infer ExtraOverrides,
136
+ 'zod'
137
+ >
138
+ ? ZodFormType<
139
+ FieldDefs,
140
+ ExtraProps & Omit<BaseModalProps, 'children'>,
141
+ ExtraOverrides & FormDialogFieldOverrides
142
+ >
143
+ : T extends FormType<infer FieldDefs, infer ExtraProps, infer ExtraOverrides>
144
+ ? FormType<
145
+ FieldDefs,
146
+ ExtraProps & Omit<BaseModalProps, 'children'>,
147
+ ExtraOverrides & FormDialogFieldOverrides
148
+ >
149
+ : never
150
+
151
+ type IsSchemaType<T, Schema, FieldDefs> = T extends DefaultFormType<FieldDefs>
152
+ ? T extends (
153
+ props: FormProps<infer TFieldValues, infer TContext, infer TSchema>
154
+ ) => any
155
+ ? Schema extends TSchema
156
+ ? true
157
+ : false
158
+ : false
159
+ : false
121
160
 
161
+ export type DefaultFormType<
162
+ FieldDefs = any,
163
+ ExtraProps = object,
164
+ ExtraOverrides = FormDialogFieldOverrides
165
+ > = (<
166
+ TFieldValues extends Record<string, any> = any,
167
+ TContext extends object = object,
168
+ TSchema = unknown
169
+ >(
170
+ props: any
171
+ ) => React.ReactElement) & {
172
+ displayName?: string
173
+ id?: string
174
+ }
175
+
176
+ export function createFormDialog<
177
+ FieldDefs = any,
178
+ ExtraProps = object,
179
+ ExtraOverrides = FormDialogFieldOverrides,
180
+ TFormType extends DefaultFormType<
181
+ FieldDefs,
182
+ ExtraProps,
183
+ ExtraOverrides
184
+ > = DefaultFormType<FieldDefs, ExtraProps, ExtraOverrides>
185
+ >(Form: TFormType) {
186
+ const Dialog = forwardRef<any, 'div'>((props, ref) => {
187
+ const { isOpen, onClose, footer, children, ...rest } = props
188
+ const { modalProps, formProps, fields } = useFormProps(rest)
122
189
  return (
123
- <BaseModal isOpen={isOpen} onClose={onClose} {...rest}>
124
- <Form {...formProps} ref={ref}>
125
- {(form) => (
190
+ <BaseModal {...modalProps} isOpen={isOpen} onClose={onClose}>
191
+ <Form ref={ref} {...(formProps as any)}>
192
+ {(form: any) => (
126
193
  <>
127
- <ModalBody>
128
- {runIfFn(children, form) || (
129
- <AutoFields
130
- schema={schema}
131
- fieldResolver={fieldResolver}
132
- focusFirstField
133
- />
134
- )}
135
- </ModalBody>
194
+ <ModalBody>{runIfFn(children, form) || <AutoFields />}</ModalBody>
136
195
 
137
196
  {footer || (
138
197
  <ModalFooter>
139
- <Button variant="ghost" mr={3} onClick={onClose}>
140
- {cancelLabel}
198
+ <Button
199
+ variant="ghost"
200
+ mr={3}
201
+ onClick={onClose}
202
+ {...fields?.cancel}
203
+ >
204
+ {fields?.cancel?.children ?? 'Cancel'}
141
205
  </Button>
142
- <SubmitButton>{submitLabel}</SubmitButton>
206
+ <SubmitButton {...fields?.submit} />
143
207
  </ModalFooter>
144
208
  )}
145
209
  </>
@@ -147,9 +211,16 @@ export const FormDialog = forwardRef(
147
211
  </Form>
148
212
  </BaseModal>
149
213
  )
150
- }
151
- ) as <TFieldValues extends FieldValues>(
152
- props: FormDialogProps<TFieldValues> & {
153
- ref?: React.ForwardedRef<HTMLFormElement>
154
- }
155
- ) => React.ReactElement
214
+ }) as MergeDialogProps<TFormType>
215
+
216
+ Dialog.displayName = `${Form.displayName || Form.name}Dialog`
217
+
218
+ return Dialog
219
+ }
220
+
221
+ /**
222
+ * Can be used to quickly request information from people without leaving the current page.
223
+ *
224
+ * @see Docs https://saas-ui.dev/docs/components/overlay/form-dialog
225
+ */
226
+ export const FormDialog = createFormDialog(Form)
package/src/provider.tsx CHANGED
@@ -280,6 +280,8 @@ export function ModalsProvider({ children, modals }: ModalsProviderProps) {
280
280
  modal.scope
281
281
  )
282
282
  }
283
+
284
+ closeComplete(id)
283
285
  }
284
286
 
285
287
  const closeComplete = (id?: ModalId | null) => {