@trackunit/react-form-wizard 0.1.103 → 0.1.104
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/index.cjs.js
CHANGED
|
@@ -233,12 +233,12 @@ const cvaFormWizardComponentStepForm = cssClassVarianceUtilities.cvaMerge(["grid
|
|
|
233
233
|
* A wrapper component used by the FormWizard component to render each step.
|
|
234
234
|
* In most cases you should not be using this component directly, but rather use the FormWizard component.
|
|
235
235
|
*/
|
|
236
|
-
const FormWizardStepWrapper = ({ stepKey, onCancel, description, title, component,
|
|
236
|
+
const FormWizardStepWrapper = ({ stepKey, onCancel, description, title, component, nextStepPath, previousStepPath, lastStepPrimaryActionLabel, fullFormSchema, setFullFormState, fullFormState, stepForms, setStepForms, setStepStates, basePath, containerClassName, }) => {
|
|
237
237
|
const navigate = reactRouter.useNavigate();
|
|
238
238
|
const [isSubmitting, setIsSubmitting] = react.useState(false);
|
|
239
239
|
const [submitHandlerInternal, setSubmitHandlerInternal] = react.useState(null);
|
|
240
240
|
const form = reactHookForm.useForm({
|
|
241
|
-
resolver: zod.zodResolver(
|
|
241
|
+
resolver: zod.zodResolver(fullFormSchema.shape[stepKey]),
|
|
242
242
|
mode: "all",
|
|
243
243
|
defaultValues: fullFormState[stepKey],
|
|
244
244
|
});
|
|
@@ -280,6 +280,7 @@ const FormWizardStepWrapper = ({ stepKey, onCancel, description, title, componen
|
|
|
280
280
|
submitHandlerInternal === null || submitHandlerInternal === void 0 ? void 0 : submitHandlerInternal(fullFormState);
|
|
281
281
|
}
|
|
282
282
|
else if (nextStepPath) {
|
|
283
|
+
// eslint-disable-next-line local-rules/no-typescript-assertion
|
|
283
284
|
navigate({ to: basePath, params: { stepPath: nextStepPath } });
|
|
284
285
|
}
|
|
285
286
|
}, [basePath, fullFormState, isLastStep, navigate, nextStepPath, submitHandlerInternal]);
|
|
@@ -291,6 +292,7 @@ const FormWizardStepWrapper = ({ stepKey, onCancel, description, title, componen
|
|
|
291
292
|
yield (submitHandlerInternal === null || submitHandlerInternal === void 0 ? void 0 : submitHandlerInternal(Object.assign(Object.assign({}, fullFormState), { [stepKey]: data })));
|
|
292
293
|
}
|
|
293
294
|
else if (nextStepPath) {
|
|
295
|
+
// eslint-disable-next-line local-rules/no-typescript-assertion
|
|
294
296
|
navigate({ to: basePath, params: { stepPath: nextStepPath } });
|
|
295
297
|
}
|
|
296
298
|
})), [
|
|
@@ -304,7 +306,10 @@ const FormWizardStepWrapper = ({ stepKey, onCancel, description, title, componen
|
|
|
304
306
|
stepKey,
|
|
305
307
|
submitHandlerInternal,
|
|
306
308
|
]);
|
|
307
|
-
const handleSubmit = react.useMemo(() =>
|
|
309
|
+
const handleSubmit = react.useMemo(() => {
|
|
310
|
+
return isEmptyStep && form.formState.isValid ? emptyStepSubmitHandler : stepSubmitHandler;
|
|
311
|
+
}, [emptyStepSubmitHandler, form.formState.isValid, isEmptyStep, stepSubmitHandler]);
|
|
312
|
+
// TODO Replace with hoooooook
|
|
308
313
|
react.useEffect(() => {
|
|
309
314
|
// submit on cmd/ctrl + enter, always
|
|
310
315
|
const handleKeyDown = (event) => {
|
|
@@ -327,7 +332,8 @@ const FormWizardStepWrapper = ({ stepKey, onCancel, description, title, componen
|
|
|
327
332
|
setSubmitHandler: isLastStep ? setSubmitHandler : null,
|
|
328
333
|
}) })) }), jsxRuntime.jsx(FormWizardFooter, { stepForms,
|
|
329
334
|
onBack: previousStepPath
|
|
330
|
-
?
|
|
335
|
+
? // eslint-disable-next-line local-rules/no-typescript-assertion
|
|
336
|
+
() => navigate({ to: basePath, params: { stepPath: previousStepPath } })
|
|
331
337
|
: null,
|
|
332
338
|
primaryActionLabel: isLastStep ? lastStepPrimaryActionLabel : undefined,
|
|
333
339
|
onCancel: handleCancel,
|
|
@@ -349,7 +355,6 @@ const cvaStepContainer = cssClassVarianceUtilities.cvaMerge(["h-full", "grid", "
|
|
|
349
355
|
* Use the useFormWizard hook to generate the props for this component.
|
|
350
356
|
*/
|
|
351
357
|
const FormWizard = ({ lastStepPrimaryActionLabel, isEdit, steps, fullFormSchema, onCancel, className, dataTestId, basePath, }) => {
|
|
352
|
-
var _a;
|
|
353
358
|
const { stepPath, subStepPath } = reactRouter.useParams({ strict: false });
|
|
354
359
|
const [stepStates, setStepStates] = react.useState({});
|
|
355
360
|
const [stepForms, setStepForms] = react.useState({});
|
|
@@ -361,21 +366,33 @@ const FormWizard = ({ lastStepPrimaryActionLabel, isEdit, steps, fullFormSchema,
|
|
|
361
366
|
sharedUtils.objectFromEntries(sharedUtils.objectEntries(steps)
|
|
362
367
|
.filter(([_, { defaultValues }]) => defaultValues)
|
|
363
368
|
.map(([key, { defaultValues }]) => [key, defaultValues])));
|
|
364
|
-
const currentVisibleStepKey =
|
|
369
|
+
const currentVisibleStepKey = subStepPath ? `${stepPath}/${subStepPath}` : stepPath;
|
|
365
370
|
const currentVisibleStepIndex = sharedUtils.objectKeys(steps)
|
|
366
|
-
.filter(key => {
|
|
371
|
+
.filter(key => {
|
|
372
|
+
var _a;
|
|
373
|
+
const step = steps[key];
|
|
374
|
+
return hasShouldRenderProperty(step) ? (_a = step.shouldRender) === null || _a === void 0 ? void 0 : _a.call(step, fullFormState) : true;
|
|
375
|
+
})
|
|
367
376
|
.findIndex(key => key === currentVisibleStepKey);
|
|
377
|
+
/**
|
|
378
|
+
* Asserts that step has a shouldRender.
|
|
379
|
+
* Is a workaround because I can't for the life of me get it to look up the step by a correctly typed
|
|
380
|
+
* template literal key of TComponentStepDefinitions and infer that it has a shouldRender automatically.👎
|
|
381
|
+
*/
|
|
382
|
+
function hasShouldRenderProperty(obj) {
|
|
383
|
+
// TODO: remove this check if we can figure out a way to make TypeScript infer the type correctly
|
|
384
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, local-rules/no-typescript-assertion
|
|
385
|
+
return typeof obj.shouldRender === "function";
|
|
386
|
+
}
|
|
368
387
|
return (jsxRuntime.jsx("div", { className: cvaFormWizardContainer({ className }), "data-testid": dataTestId, children: jsxRuntime.jsxs("div", { className: cvaFormWizardLayout(), children: [jsxRuntime.jsx(FormWizardSidebar, { children: sharedUtils.objectEntries(steps)
|
|
369
|
-
.filter(([_, step]) => { var _a
|
|
370
|
-
.map(([key, {
|
|
388
|
+
.filter(([_, step]) => { var _a; return (hasShouldRenderProperty(step) ? (_a = step.shouldRender) === null || _a === void 0 ? void 0 : _a.call(step, fullFormState) : true); })
|
|
389
|
+
.map(([key, { title, sidebarDescription, defaultValues }], index) => {
|
|
371
390
|
const isPastStep = index < currentVisibleStepIndex;
|
|
372
391
|
const isFutureStep = index > currentVisibleStepIndex;
|
|
373
392
|
const isCurrentStep = key === currentVisibleStepKey;
|
|
374
393
|
const hasDefaultValue = defaultValues !== undefined;
|
|
375
|
-
const isSubStep =
|
|
376
|
-
const
|
|
377
|
-
.filter(([_, step]) => step.parent === undefined)
|
|
378
|
-
.map(([k]) => k);
|
|
394
|
+
const isSubStep = key.toString().includes("/");
|
|
395
|
+
const rootSteps = sharedUtils.objectKeys(steps).filter(k => !k.toString().includes("/"));
|
|
379
396
|
const previousStepKey = sharedUtils.objectKeys(steps)[index - 1];
|
|
380
397
|
const stepState = () => {
|
|
381
398
|
if (isCurrentStep) {
|
|
@@ -395,9 +412,10 @@ const FormWizard = ({ lastStepPrimaryActionLabel, isEdit, steps, fullFormSchema,
|
|
|
395
412
|
if (isFutureStep) {
|
|
396
413
|
return sharedUtils.objectKeys(steps)
|
|
397
414
|
.filter((stepKey, stepIndex) => {
|
|
398
|
-
var _a
|
|
399
|
-
|
|
400
|
-
|
|
415
|
+
var _a;
|
|
416
|
+
const step = steps[stepKey];
|
|
417
|
+
return stepIndex < index && hasShouldRenderProperty(step)
|
|
418
|
+
? (_a = step.shouldRender) === null || _a === void 0 ? void 0 : _a.call(step, fullFormState)
|
|
401
419
|
: true;
|
|
402
420
|
})
|
|
403
421
|
.every((pastStepKey) => stepStates[pastStepKey] === "valid")
|
|
@@ -408,7 +426,7 @@ const FormWizard = ({ lastStepPrimaryActionLabel, isEdit, steps, fullFormSchema,
|
|
|
408
426
|
};
|
|
409
427
|
return (jsxRuntime.jsx(FormWizardSidebarStep, { key: String(key),
|
|
410
428
|
state: stepState(),
|
|
411
|
-
stepNumber: isSubStep ? undefined :
|
|
429
|
+
stepNumber: isSubStep ? undefined : rootSteps.indexOf(key) + 1,
|
|
412
430
|
title,
|
|
413
431
|
onNavigate: () => {
|
|
414
432
|
previousStepKey &&
|
|
@@ -418,20 +436,19 @@ const FormWizard = ({ lastStepPrimaryActionLabel, isEdit, steps, fullFormSchema,
|
|
|
418
436
|
});
|
|
419
437
|
},
|
|
420
438
|
basePath,
|
|
421
|
-
path:
|
|
439
|
+
path: String(key),
|
|
422
440
|
subTitle: sidebarDescription,
|
|
423
441
|
isSubStep }));
|
|
424
442
|
}) }), jsxRuntime.jsx("div", { className: cvaStepContainer(), children: sharedUtils.objectEntries(steps)
|
|
425
|
-
.filter(([_, step]) => {
|
|
426
|
-
var _a, _b;
|
|
427
|
-
return (_b = (_a = step.shouldRender) === null || _a === void 0 ? void 0 : _a.call(step, fullFormState)) !== null && _b !== void 0 ? _b : true;
|
|
428
|
-
})
|
|
443
|
+
.filter(([_, step]) => { var _a; return (hasShouldRenderProperty(step) ? (_a = step.shouldRender) === null || _a === void 0 ? void 0 : _a.call(step, fullFormState) : true); })
|
|
429
444
|
.map(([stepKey, props], index) => {
|
|
430
445
|
var _a, _b, _c, _d;
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
446
|
+
const entriesOfRenderableSteps = sharedUtils.objectEntries(steps).filter(stepEntry => {
|
|
447
|
+
var _a;
|
|
448
|
+
const step = stepEntry[1];
|
|
449
|
+
return hasShouldRenderProperty(step) ? (_a = step.shouldRender) === null || _a === void 0 ? void 0 : _a.call(step, fullFormState) : true;
|
|
450
|
+
});
|
|
451
|
+
return currentVisibleStepKey === stepKey ? (jsxRuntime.jsx(FormWizardStepWrapper, Object.assign({}, props, { basePath,
|
|
435
452
|
stepKey: stepKey.toString(), // TODO: .toString() is a workaround
|
|
436
453
|
stepForms,
|
|
437
454
|
setStepForms,
|
|
@@ -441,8 +458,8 @@ const FormWizard = ({ lastStepPrimaryActionLabel, isEdit, steps, fullFormSchema,
|
|
|
441
458
|
setStepStates,
|
|
442
459
|
fullFormSchema,
|
|
443
460
|
lastStepPrimaryActionLabel,
|
|
444
|
-
nextStepPath: (_b = (_a =
|
|
445
|
-
previousStepPath: (_d = (_c =
|
|
461
|
+
nextStepPath: (_b = (_a = entriesOfRenderableSteps[index + 1]) === null || _a === void 0 ? void 0 : _a[0].toString()) !== null && _b !== void 0 ? _b : null,
|
|
462
|
+
previousStepPath: (_d = (_c = entriesOfRenderableSteps[index - 1]) === null || _c === void 0 ? void 0 : _c[0].toString()) !== null && _d !== void 0 ? _d : null }), stepKey.toString())) : null;
|
|
446
463
|
}) })] }) }));
|
|
447
464
|
};
|
|
448
465
|
|
package/index.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { registerTranslations, useNamespaceTranslation } from '@trackunit/i18n-library-translation';
|
|
3
3
|
import { Link, useNavigate, useParams } from '@tanstack/react-router';
|
|
4
|
-
import { objectKeys, objectFromEntries, objectEntries
|
|
4
|
+
import { objectKeys, objectFromEntries, objectEntries } from '@trackunit/shared-utils';
|
|
5
5
|
import { useState, useEffect, useCallback, useMemo } from 'react';
|
|
6
6
|
import { cvaMerge } from '@trackunit/css-class-variance-utilities';
|
|
7
7
|
import { Icon, Button, Heading } from '@trackunit/react-components';
|
|
@@ -229,12 +229,12 @@ const cvaFormWizardComponentStepForm = cvaMerge(["grid-rows-min-fr-min", "grid",
|
|
|
229
229
|
* A wrapper component used by the FormWizard component to render each step.
|
|
230
230
|
* In most cases you should not be using this component directly, but rather use the FormWizard component.
|
|
231
231
|
*/
|
|
232
|
-
const FormWizardStepWrapper = ({ stepKey, onCancel, description, title, component,
|
|
232
|
+
const FormWizardStepWrapper = ({ stepKey, onCancel, description, title, component, nextStepPath, previousStepPath, lastStepPrimaryActionLabel, fullFormSchema, setFullFormState, fullFormState, stepForms, setStepForms, setStepStates, basePath, containerClassName, }) => {
|
|
233
233
|
const navigate = useNavigate();
|
|
234
234
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
235
235
|
const [submitHandlerInternal, setSubmitHandlerInternal] = useState(null);
|
|
236
236
|
const form = useForm({
|
|
237
|
-
resolver: zodResolver(
|
|
237
|
+
resolver: zodResolver(fullFormSchema.shape[stepKey]),
|
|
238
238
|
mode: "all",
|
|
239
239
|
defaultValues: fullFormState[stepKey],
|
|
240
240
|
});
|
|
@@ -276,6 +276,7 @@ const FormWizardStepWrapper = ({ stepKey, onCancel, description, title, componen
|
|
|
276
276
|
submitHandlerInternal === null || submitHandlerInternal === void 0 ? void 0 : submitHandlerInternal(fullFormState);
|
|
277
277
|
}
|
|
278
278
|
else if (nextStepPath) {
|
|
279
|
+
// eslint-disable-next-line local-rules/no-typescript-assertion
|
|
279
280
|
navigate({ to: basePath, params: { stepPath: nextStepPath } });
|
|
280
281
|
}
|
|
281
282
|
}, [basePath, fullFormState, isLastStep, navigate, nextStepPath, submitHandlerInternal]);
|
|
@@ -287,6 +288,7 @@ const FormWizardStepWrapper = ({ stepKey, onCancel, description, title, componen
|
|
|
287
288
|
yield (submitHandlerInternal === null || submitHandlerInternal === void 0 ? void 0 : submitHandlerInternal(Object.assign(Object.assign({}, fullFormState), { [stepKey]: data })));
|
|
288
289
|
}
|
|
289
290
|
else if (nextStepPath) {
|
|
291
|
+
// eslint-disable-next-line local-rules/no-typescript-assertion
|
|
290
292
|
navigate({ to: basePath, params: { stepPath: nextStepPath } });
|
|
291
293
|
}
|
|
292
294
|
})), [
|
|
@@ -300,7 +302,10 @@ const FormWizardStepWrapper = ({ stepKey, onCancel, description, title, componen
|
|
|
300
302
|
stepKey,
|
|
301
303
|
submitHandlerInternal,
|
|
302
304
|
]);
|
|
303
|
-
const handleSubmit = useMemo(() =>
|
|
305
|
+
const handleSubmit = useMemo(() => {
|
|
306
|
+
return isEmptyStep && form.formState.isValid ? emptyStepSubmitHandler : stepSubmitHandler;
|
|
307
|
+
}, [emptyStepSubmitHandler, form.formState.isValid, isEmptyStep, stepSubmitHandler]);
|
|
308
|
+
// TODO Replace with hoooooook
|
|
304
309
|
useEffect(() => {
|
|
305
310
|
// submit on cmd/ctrl + enter, always
|
|
306
311
|
const handleKeyDown = (event) => {
|
|
@@ -323,7 +328,8 @@ const FormWizardStepWrapper = ({ stepKey, onCancel, description, title, componen
|
|
|
323
328
|
setSubmitHandler: isLastStep ? setSubmitHandler : null,
|
|
324
329
|
}) })) }), jsx(FormWizardFooter, { stepForms,
|
|
325
330
|
onBack: previousStepPath
|
|
326
|
-
?
|
|
331
|
+
? // eslint-disable-next-line local-rules/no-typescript-assertion
|
|
332
|
+
() => navigate({ to: basePath, params: { stepPath: previousStepPath } })
|
|
327
333
|
: null,
|
|
328
334
|
primaryActionLabel: isLastStep ? lastStepPrimaryActionLabel : undefined,
|
|
329
335
|
onCancel: handleCancel,
|
|
@@ -345,7 +351,6 @@ const cvaStepContainer = cvaMerge(["h-full", "grid", "bg-white", "overflow-hidde
|
|
|
345
351
|
* Use the useFormWizard hook to generate the props for this component.
|
|
346
352
|
*/
|
|
347
353
|
const FormWizard = ({ lastStepPrimaryActionLabel, isEdit, steps, fullFormSchema, onCancel, className, dataTestId, basePath, }) => {
|
|
348
|
-
var _a;
|
|
349
354
|
const { stepPath, subStepPath } = useParams({ strict: false });
|
|
350
355
|
const [stepStates, setStepStates] = useState({});
|
|
351
356
|
const [stepForms, setStepForms] = useState({});
|
|
@@ -357,21 +362,33 @@ const FormWizard = ({ lastStepPrimaryActionLabel, isEdit, steps, fullFormSchema,
|
|
|
357
362
|
objectFromEntries(objectEntries(steps)
|
|
358
363
|
.filter(([_, { defaultValues }]) => defaultValues)
|
|
359
364
|
.map(([key, { defaultValues }]) => [key, defaultValues])));
|
|
360
|
-
const currentVisibleStepKey =
|
|
365
|
+
const currentVisibleStepKey = subStepPath ? `${stepPath}/${subStepPath}` : stepPath;
|
|
361
366
|
const currentVisibleStepIndex = objectKeys(steps)
|
|
362
|
-
.filter(key => {
|
|
367
|
+
.filter(key => {
|
|
368
|
+
var _a;
|
|
369
|
+
const step = steps[key];
|
|
370
|
+
return hasShouldRenderProperty(step) ? (_a = step.shouldRender) === null || _a === void 0 ? void 0 : _a.call(step, fullFormState) : true;
|
|
371
|
+
})
|
|
363
372
|
.findIndex(key => key === currentVisibleStepKey);
|
|
373
|
+
/**
|
|
374
|
+
* Asserts that step has a shouldRender.
|
|
375
|
+
* Is a workaround because I can't for the life of me get it to look up the step by a correctly typed
|
|
376
|
+
* template literal key of TComponentStepDefinitions and infer that it has a shouldRender automatically.👎
|
|
377
|
+
*/
|
|
378
|
+
function hasShouldRenderProperty(obj) {
|
|
379
|
+
// TODO: remove this check if we can figure out a way to make TypeScript infer the type correctly
|
|
380
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, local-rules/no-typescript-assertion
|
|
381
|
+
return typeof obj.shouldRender === "function";
|
|
382
|
+
}
|
|
364
383
|
return (jsx("div", { className: cvaFormWizardContainer({ className }), "data-testid": dataTestId, children: jsxs("div", { className: cvaFormWizardLayout(), children: [jsx(FormWizardSidebar, { children: objectEntries(steps)
|
|
365
|
-
.filter(([_, step]) => { var _a
|
|
366
|
-
.map(([key, {
|
|
384
|
+
.filter(([_, step]) => { var _a; return (hasShouldRenderProperty(step) ? (_a = step.shouldRender) === null || _a === void 0 ? void 0 : _a.call(step, fullFormState) : true); })
|
|
385
|
+
.map(([key, { title, sidebarDescription, defaultValues }], index) => {
|
|
367
386
|
const isPastStep = index < currentVisibleStepIndex;
|
|
368
387
|
const isFutureStep = index > currentVisibleStepIndex;
|
|
369
388
|
const isCurrentStep = key === currentVisibleStepKey;
|
|
370
389
|
const hasDefaultValue = defaultValues !== undefined;
|
|
371
|
-
const isSubStep =
|
|
372
|
-
const
|
|
373
|
-
.filter(([_, step]) => step.parent === undefined)
|
|
374
|
-
.map(([k]) => k);
|
|
390
|
+
const isSubStep = key.toString().includes("/");
|
|
391
|
+
const rootSteps = objectKeys(steps).filter(k => !k.toString().includes("/"));
|
|
375
392
|
const previousStepKey = objectKeys(steps)[index - 1];
|
|
376
393
|
const stepState = () => {
|
|
377
394
|
if (isCurrentStep) {
|
|
@@ -391,9 +408,10 @@ const FormWizard = ({ lastStepPrimaryActionLabel, isEdit, steps, fullFormSchema,
|
|
|
391
408
|
if (isFutureStep) {
|
|
392
409
|
return objectKeys(steps)
|
|
393
410
|
.filter((stepKey, stepIndex) => {
|
|
394
|
-
var _a
|
|
395
|
-
|
|
396
|
-
|
|
411
|
+
var _a;
|
|
412
|
+
const step = steps[stepKey];
|
|
413
|
+
return stepIndex < index && hasShouldRenderProperty(step)
|
|
414
|
+
? (_a = step.shouldRender) === null || _a === void 0 ? void 0 : _a.call(step, fullFormState)
|
|
397
415
|
: true;
|
|
398
416
|
})
|
|
399
417
|
.every((pastStepKey) => stepStates[pastStepKey] === "valid")
|
|
@@ -404,7 +422,7 @@ const FormWizard = ({ lastStepPrimaryActionLabel, isEdit, steps, fullFormSchema,
|
|
|
404
422
|
};
|
|
405
423
|
return (jsx(FormWizardSidebarStep, { key: String(key),
|
|
406
424
|
state: stepState(),
|
|
407
|
-
stepNumber: isSubStep ? undefined :
|
|
425
|
+
stepNumber: isSubStep ? undefined : rootSteps.indexOf(key) + 1,
|
|
408
426
|
title,
|
|
409
427
|
onNavigate: () => {
|
|
410
428
|
previousStepKey &&
|
|
@@ -414,20 +432,19 @@ const FormWizard = ({ lastStepPrimaryActionLabel, isEdit, steps, fullFormSchema,
|
|
|
414
432
|
});
|
|
415
433
|
},
|
|
416
434
|
basePath,
|
|
417
|
-
path:
|
|
435
|
+
path: String(key),
|
|
418
436
|
subTitle: sidebarDescription,
|
|
419
437
|
isSubStep }));
|
|
420
438
|
}) }), jsx("div", { className: cvaStepContainer(), children: objectEntries(steps)
|
|
421
|
-
.filter(([_, step]) => {
|
|
422
|
-
var _a, _b;
|
|
423
|
-
return (_b = (_a = step.shouldRender) === null || _a === void 0 ? void 0 : _a.call(step, fullFormState)) !== null && _b !== void 0 ? _b : true;
|
|
424
|
-
})
|
|
439
|
+
.filter(([_, step]) => { var _a; return (hasShouldRenderProperty(step) ? (_a = step.shouldRender) === null || _a === void 0 ? void 0 : _a.call(step, fullFormState) : true); })
|
|
425
440
|
.map(([stepKey, props], index) => {
|
|
426
441
|
var _a, _b, _c, _d;
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
442
|
+
const entriesOfRenderableSteps = objectEntries(steps).filter(stepEntry => {
|
|
443
|
+
var _a;
|
|
444
|
+
const step = stepEntry[1];
|
|
445
|
+
return hasShouldRenderProperty(step) ? (_a = step.shouldRender) === null || _a === void 0 ? void 0 : _a.call(step, fullFormState) : true;
|
|
446
|
+
});
|
|
447
|
+
return currentVisibleStepKey === stepKey ? (jsx(FormWizardStepWrapper, Object.assign({}, props, { basePath,
|
|
431
448
|
stepKey: stepKey.toString(), // TODO: .toString() is a workaround
|
|
432
449
|
stepForms,
|
|
433
450
|
setStepForms,
|
|
@@ -437,8 +454,8 @@ const FormWizard = ({ lastStepPrimaryActionLabel, isEdit, steps, fullFormSchema,
|
|
|
437
454
|
setStepStates,
|
|
438
455
|
fullFormSchema,
|
|
439
456
|
lastStepPrimaryActionLabel,
|
|
440
|
-
nextStepPath: (_b = (_a =
|
|
441
|
-
previousStepPath: (_d = (_c =
|
|
457
|
+
nextStepPath: (_b = (_a = entriesOfRenderableSteps[index + 1]) === null || _a === void 0 ? void 0 : _a[0].toString()) !== null && _b !== void 0 ? _b : null,
|
|
458
|
+
previousStepPath: (_d = (_c = entriesOfRenderableSteps[index - 1]) === null || _c === void 0 ? void 0 : _c[0].toString()) !== null && _d !== void 0 ? _d : null }), stepKey.toString())) : null;
|
|
442
459
|
}) })] }) }));
|
|
443
460
|
};
|
|
444
461
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { UseFormReturn } from "react-hook-form";
|
|
3
3
|
import { AnyZodObject, z } from "zod";
|
|
4
|
-
import {
|
|
4
|
+
import { FromWizardComponentProps, StepDefinitions } from "./useFormWizard";
|
|
5
5
|
export type FormWizardStepFormReturnMap<TFullSchema extends AnyZodObject> = Partial<{
|
|
6
6
|
[TStepKey in keyof z.infer<TFullSchema>]: UseFormReturn<z.TypeOf<TFullSchema>[TStepKey]>;
|
|
7
7
|
}>;
|
|
@@ -9,4 +9,4 @@ export type FormWizardStepFormReturnMap<TFullSchema extends AnyZodObject> = Part
|
|
|
9
9
|
* The FormWizard component is used for forms in multiple steps.
|
|
10
10
|
* Use the useFormWizard hook to generate the props for this component.
|
|
11
11
|
*/
|
|
12
|
-
export declare const FormWizard: <TFullSchema extends AnyZodObject, TComponentStepDefinitions extends
|
|
12
|
+
export declare const FormWizard: <TFullSchema extends AnyZodObject, TComponentStepDefinitions extends StepDefinitions<TFullSchema>>({ lastStepPrimaryActionLabel, isEdit, steps, fullFormSchema, onCancel, className, dataTestId, basePath, }: FromWizardComponentProps<TFullSchema, TComponentStepDefinitions>) => JSX.Element;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { RegisteredRouter, RouteIds } from "@tanstack/react-router";
|
|
2
2
|
import { CommonProps } from "@trackunit/react-components";
|
|
3
|
+
import { MappedOmit } from "@trackunit/shared-utils";
|
|
3
4
|
import { ReactNode } from "react";
|
|
4
5
|
import { UseFormReturn } from "react-hook-form";
|
|
5
6
|
import { AnyZodObject, SomeZodObject, z } from "zod";
|
|
6
7
|
export type StepState = "active" | "done" | "invalid" | "disabled" | "ready";
|
|
7
8
|
export type StepDefinitions<TFullSchema extends AnyZodObject> = {
|
|
8
|
-
[
|
|
9
|
+
[KFullStepKey in keyof z.TypeOf<TFullSchema>]: KFullStepKey extends `${infer ParentStepKey}/${infer _SubStepKey}` ? ParentStepKey extends keyof z.TypeOf<TFullSchema> ? DefinedStep<z.TypeOf<TFullSchema>[KFullStepKey], z.TypeOf<TFullSchema>> & {
|
|
10
|
+
shouldRender?: (fullFormState: Partial<z.TypeOf<TFullSchema>>) => boolean;
|
|
11
|
+
} : never : DefinedStep<z.TypeOf<TFullSchema>[KFullStepKey], z.TypeOf<TFullSchema>>;
|
|
9
12
|
};
|
|
10
13
|
export type StepComponentPropsInner<TStepSchema extends TFullSchemaValue[keyof TFullSchemaValue], TFullSchemaValue extends z.TypeOf<AnyZodObject>> = {
|
|
11
14
|
form: UseFormReturn<TStepSchema>;
|
|
@@ -16,26 +19,17 @@ export interface SimpleStepProps {
|
|
|
16
19
|
title: string;
|
|
17
20
|
description: string | ReactNode;
|
|
18
21
|
sidebarDescription?: string;
|
|
19
|
-
path: string;
|
|
20
22
|
containerClassName?: string;
|
|
21
23
|
}
|
|
22
24
|
interface DefinedStep<TStepSchema extends TFullSchemaValue[keyof TFullSchemaValue], TFullSchemaValue extends z.TypeOf<AnyZodObject>> extends SimpleStepProps {
|
|
23
25
|
component: (props: StepComponentPropsInner<TStepSchema, TFullSchemaValue>) => React.ReactNode;
|
|
24
|
-
parent?: keyof TFullSchemaValue;
|
|
25
|
-
shouldRender?: (fullFormState: Partial<TFullSchemaValue>) => boolean;
|
|
26
26
|
defaultValues?: TStepSchema;
|
|
27
27
|
}
|
|
28
28
|
export type StepComponentProps<TFullSchemaHook extends () => AnyZodObject, TStepKey extends keyof z.TypeOf<ReturnType<TFullSchemaHook>>> = StepComponentPropsInner<z.TypeOf<ReturnType<TFullSchemaHook>>[TStepKey], z.TypeOf<ReturnType<TFullSchemaHook>>>;
|
|
29
|
-
export
|
|
30
|
-
[KStepKey in keyof z.TypeOf<TFullSchema>]: DefinedComponentStep<z.TypeOf<TFullSchema>[KStepKey], z.TypeOf<TFullSchema>>;
|
|
31
|
-
};
|
|
32
|
-
interface DefinedComponentStep<TStepSchema extends TFullSchemaValue[keyof TFullSchemaValue], TFullSchemaValue extends z.TypeOf<AnyZodObject>> extends DefinedStep<TStepSchema, TFullSchemaValue> {
|
|
33
|
-
formSchema: TStepSchema;
|
|
34
|
-
}
|
|
35
|
-
export interface FromWizardComponentProps<TFullSchema extends AnyZodObject, TComponentStepDefinitions extends ComponentStepDefinitions<TFullSchema>> extends Omit<UseFormWizardProps<TFullSchema, TComponentStepDefinitions>, "steps">, CommonProps {
|
|
29
|
+
export interface FromWizardComponentProps<TFullSchema extends AnyZodObject, TComponentStepDefinitions extends StepDefinitions<TFullSchema>> extends MappedOmit<UseFormWizardProps<TFullSchema, TComponentStepDefinitions>, "steps">, CommonProps {
|
|
36
30
|
steps: TComponentStepDefinitions;
|
|
37
31
|
}
|
|
38
|
-
export type StringWithStepKey<TPath> = TPath extends `${infer
|
|
32
|
+
export type StringWithStepKey<TPath> = TPath extends `${infer _Prefix}/$stepPath` ? TPath : never;
|
|
39
33
|
export interface UseFormWizardProps<TFullSchema extends SomeZodObject, TStepDefinitions extends StepDefinitions<TFullSchema>> {
|
|
40
34
|
fullFormSchema: TFullSchema;
|
|
41
35
|
lastStepPrimaryActionLabel: string;
|
|
@@ -47,5 +41,5 @@ export interface UseFormWizardProps<TFullSchema extends SomeZodObject, TStepDefi
|
|
|
47
41
|
/**
|
|
48
42
|
* A hook to generate the props for the FormWizard component.
|
|
49
43
|
*/
|
|
50
|
-
export declare const useFormWizard: <TStepDefinition extends StepDefinitions<TFullSchema>, TFullSchema extends AnyZodObject>(props: UseFormWizardProps<TFullSchema, TStepDefinition>) => FromWizardComponentProps<TFullSchema,
|
|
44
|
+
export declare const useFormWizard: <TStepDefinition extends StepDefinitions<TFullSchema>, TFullSchema extends AnyZodObject>(props: UseFormWizardProps<TFullSchema, TStepDefinition>) => FromWizardComponentProps<TFullSchema, StepDefinitions<TFullSchema>>;
|
|
51
45
|
export {};
|
|
@@ -3,7 +3,7 @@ import { Dispatch, ReactNode, SetStateAction } from "react";
|
|
|
3
3
|
import { DeepPartial, UseFormReturn } from "react-hook-form";
|
|
4
4
|
import { AnyZodObject, z } from "zod";
|
|
5
5
|
import { FormWizardStepFormReturnMap } from "../FormWizard/FormWizard";
|
|
6
|
-
import {
|
|
6
|
+
import { SimpleStepProps, StepComponentPropsInner, StepDefinitions, StringWithStepKey } from "../FormWizard/useFormWizard";
|
|
7
7
|
export type StepFormValidity = "valid" | "invalid";
|
|
8
8
|
export interface FormWizardStepWrapperProps<TStepKey extends keyof z.TypeOf<TFullSchema>, TFullSchema extends AnyZodObject> extends SimpleStepProps {
|
|
9
9
|
description: string | ReactNode;
|
|
@@ -16,8 +16,7 @@ export interface FormWizardStepWrapperProps<TStepKey extends keyof z.TypeOf<TFul
|
|
|
16
16
|
fullFormState: DeepPartial<z.TypeOf<TFullSchema>>;
|
|
17
17
|
setFullFormState: Dispatch<SetStateAction<DeepPartial<z.TypeOf<TFullSchema>>>>;
|
|
18
18
|
stepKey: TStepKey;
|
|
19
|
-
|
|
20
|
-
setStepStates: Dispatch<SetStateAction<Partial<Record<keyof ComponentStepDefinitions<TFullSchema>, StepFormValidity>>>>;
|
|
19
|
+
setStepStates: Dispatch<SetStateAction<Partial<Record<keyof StepDefinitions<TFullSchema>, StepFormValidity>>>>;
|
|
21
20
|
component: (props: StepComponentPropsInner<DeepPartial<z.TypeOf<TFullSchema>[TStepKey]>, z.TypeOf<TFullSchema>>) => ReactNode;
|
|
22
21
|
stepForms: FormWizardStepFormReturnMap<TFullSchema>;
|
|
23
22
|
setStepForms: Dispatch<SetStateAction<Partial<{
|
|
@@ -28,4 +27,4 @@ export interface FormWizardStepWrapperProps<TStepKey extends keyof z.TypeOf<TFul
|
|
|
28
27
|
* A wrapper component used by the FormWizard component to render each step.
|
|
29
28
|
* In most cases you should not be using this component directly, but rather use the FormWizard component.
|
|
30
29
|
*/
|
|
31
|
-
export declare const FormWizardStepWrapper: <TFullSchema extends AnyZodObject, TStepKey extends keyof z.TypeOf<TFullSchema>>({ stepKey, onCancel, description, title, component,
|
|
30
|
+
export declare const FormWizardStepWrapper: <TFullSchema extends AnyZodObject, TStepKey extends keyof z.TypeOf<TFullSchema>>({ stepKey, onCancel, description, title, component, nextStepPath, previousStepPath, lastStepPrimaryActionLabel, fullFormSchema, setFullFormState, fullFormState, stepForms, setStepForms, setStepStates, basePath, containerClassName, }: FormWizardStepWrapperProps<TStepKey, TFullSchema>) => JSX.Element;
|