/
reactComponents.tsx
256 lines (236 loc) · 7.14 KB
/
reactComponents.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
import { ReactElement, PropsWithChildren } from "react";
/**
* The props type for {@link CardA}.
*/
export interface CardAProps {
/** The theme of the card. Defaults to `primary`. */
variant: "primary" | "secondary" | "success" | "danger" | "light" | "dark";
}
/**
* Renders a card around some content.
*
* ```tsx
* <CardA variant="secondary">
* <h5>My Title</h5>
* <p>My content</p>
* </CardA>
* ```
*
* The props type is defined as a separate interface **which must be exported!**
*
* ```
* export interface CardAProps {
* // ...
* }
*
* export function CardA({
* children,
* variant = "primary",
* }: PropsWithChildren<CardAProps>): ReactElement {
* // ...
* }
* ```
*
* This is our recommended way to define React components as it makes your code
* more readable. The minor drawback is you must click the `CardAProps` link to
* see the component's props.
*
* @category Component
*/
export function CardA({ children, variant = "primary" }: PropsWithChildren<CardAProps>): ReactElement {
return <div className={`card card-${variant}`}>{children}</div>;
}
/**
* Renders a card around some content.
*
* ```tsx
* <CardB variant="secondary">
* <h5>My Title</h5>
* <p>My content</p>
* </CardB>
* ```
*
* The props type is written directly in the function definition:
*
* ```
* export function CardB({
* children,
* variant = "primary",
* }: PropsWithChildren<{
* variant: "primary" | "secondary" | "success" | "danger" | "light" | "dark";
* }>): ReactElement {
* // ...
* }
* ```
*
* This can make the TypeDoc documentation a bit cleaner for very simple components,
* but it makes your code less readable.
*
* @category Component
*/
export function CardB({
children,
variant = "primary",
}: PropsWithChildren<{
/** The theme of the card. Defaults to `primary`. */
variant: "primary" | "secondary" | "success" | "danger" | "light" | "dark";
}>): ReactElement {
return <div className={`card card-${variant}`}>{children}</div>;
}
/** The props type of {@link EasyFormDialog | `EasyFormDialog`}. */
export interface EasyFormDialogProps {
/** The title of the dialog. Can be a JSX element. */
title: React.ReactNode;
/** The text of the submit button. */
submitButtonText: string;
/** The CSS class of the submit button. */
submitButtonClass?: string;
/** The text of the cancel button. Defaults to "Cancel". */
cancelButtonText?: string;
/**
* Allows you to disable the submit button even if `getSubmitEnabled()`
* would return true.
*
* This can be useful if you want to disable the submit button while a query
* is in progress.
*/
submitEnabled?: boolean;
/** A boolean indicating if the form is valid. */
formIsValid: boolean;
/** A boolean indicating if validation feedback is being shown. */
showValidation: boolean;
/** A callback that fires when the dialog is submitted. */
onShowValidationChange(showValidation: boolean): void;
/**
* A callback that fires after the `submit` function succeeds.
*
* If the `submit` function returned `responseData`, it is passed to your
* `onSuccess` function.
*
* Your `onSuccess` callback must return a promise. The submit button will
* continue showing a loading indicator until the promise resolves. This is
* to support refetching the data that was updated by the form submission.
*/
onSuccess(payload: unknown | undefined): Promise<void>;
/**
* A callback that fires when the dialog has completely closed. Your
* `onClose` callback should update call, for example,
* `setDialogVisible(false)` so that the `EasyFormDialog` is no longer
* rendered.
*/
onClose(): void;
/**
* A callback that fires when the form is submitted. You will typically
* perform an API call in your `submit` function.
*
* Your `submit` function can optionally return an object in the shape
*
* ```
* {
* shouldClose?: boolean
* responseData: unknown
* }
* ```
*
* Using `formData` is deprecated. Use controlled components instead.
*
* `formData` will be `{}` if the optional peer dependency `jquery` is not
* installed.
*/
onSubmit(formData: Record<string, string | boolean>):
| Promise<
| {
shouldClose?: boolean;
responseData: unknown;
}
| undefined
>
| Promise<void>;
/**
* An uncommonly-used callback that fires when the user clicks the cancel button.
*/
onCancel?(): void;
/**
* This prop accepts a ref object that holds a function of type `() =>
* void`. You can execute the function to programmatically close the dialog:
*
* ```
* closeRef.current()
* ```
*/
closeRef?: React.MutableRefObject<() => void>;
/** The CSS class added to the underlying Bootstrap modal. */
modalClass?: string;
/**
* Set to `false` to disable the default behavior of focusing the first
* input.
*/
focusFirst?: boolean;
/**
* Set to `false` to hide the modal footer, which contains the submit and
* cancel buttons.
*/
showFooter?: boolean;
}
/**
* An example of a complex React component.
*
* A wrapper around `ActionDialog` that removes a lot of the boilerplate needed
* for dialogs that contain a form.
*
* ```tsx
* interface ExampleProps {
* onSuccess(responseData: number): Promise<void>
* onClose(): void
* }
*
* export function Example({
* onSuccess,
* onClose,
* }: ExampleProps): ReactElement {
* const { onChildValidChange, allFieldsValid } = useFieldValidity()
* const [showValidation, setShowValidation] = useState(false)
* const vProps = { showValidation, onValidChange: onChildValidChange }
*
* const [myNumber, setMyNumber] = useState('')
*
* async function submit() {
* await api.product.performOperation()
*
* return {
* responseData: parseInt(myNumber),
* }
* }
*
* return (
* <EasyFormDialog
* title="Enter a Number"
* submitButtonText="Submit"
* formIsValid={allFieldsValid}
* showValidation={showValidation}
* onShowValidationChange={setShowValidation}
* onSubmit={submit}
* onSuccess={onSuccess}
* onClose={onClose}
* >
* <FormGroup label="My number">
* {(id) => (
* <ValidatedInput
* id={id}
* name="myNumber"
* validators={[Validators.required(), Validators.integer()]}
* value={myNumber}
* onChange={setMyNumber}
* {...vProps}
* />
* )}
* </FormGroup>
* </EasyFormDialog>
* )
* }
* ```
* @category Component
*/
export function EasyFormDialog(props: PropsWithChildren<EasyFormDialogProps>): ReactElement {
return <div />;
}