@oneblink/apps-react 13.0.0-beta.1 → 13.0.0-beta.11
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/dist/OneBlinkFormBase.d.ts +23 -3
- package/dist/OneBlinkFormBase.js +351 -193
- package/dist/OneBlinkFormBase.js.map +1 -1
- package/dist/OneBlinkReadOnlyForm.d.ts +17 -7
- package/dist/OneBlinkReadOnlyForm.js +24 -8
- package/dist/OneBlinkReadOnlyForm.js.map +1 -1
- package/dist/apps/approvals-service.d.ts +2 -60
- package/dist/apps/approvals-service.js +1 -181
- package/dist/apps/approvals-service.js.map +1 -1
- package/dist/apps/services/api/submissions.d.ts +3 -2
- package/dist/apps/services/api/submissions.js +3 -6
- package/dist/apps/services/api/submissions.js.map +1 -1
- package/dist/apps/submission-service.d.ts +11 -5
- package/dist/apps/submission-service.js +9 -4
- package/dist/apps/submission-service.js.map +1 -1
- package/dist/components/renderer/LookupButton.d.ts +1 -2
- package/dist/components/renderer/LookupButton.js +7 -6
- package/dist/components/renderer/LookupButton.js.map +1 -1
- package/dist/components/renderer/LookupNotification.js +31 -24
- package/dist/components/renderer/LookupNotification.js.map +1 -1
- package/dist/components/renderer/OneBlinkFormElements.d.ts +5 -7
- package/dist/components/renderer/OneBlinkFormElements.js +10 -35
- package/dist/components/renderer/OneBlinkFormElements.js.map +1 -1
- package/dist/components/renderer/PageFormElements.js +8 -3
- package/dist/components/renderer/PageFormElements.js.map +1 -1
- package/dist/components/renderer/ReverseGeocode.js +6 -11
- package/dist/components/renderer/ReverseGeocode.js.map +1 -1
- package/dist/form-elements/FormElementABN.js +1 -1
- package/dist/form-elements/FormElementABN.js.map +1 -1
- package/dist/form-elements/FormElementBSB.js +1 -1
- package/dist/form-elements/FormElementBSB.js.map +1 -1
- package/dist/form-elements/FormElementBarcodeScanner.js +1 -1
- package/dist/form-elements/FormElementBarcodeScanner.js.map +1 -1
- package/dist/form-elements/FormElementCalculation.js +1 -0
- package/dist/form-elements/FormElementCalculation.js.map +1 -1
- package/dist/form-elements/FormElementCheckBoxes.js +1 -1
- package/dist/form-elements/FormElementCheckBoxes.js.map +1 -1
- package/dist/form-elements/FormElementDate.js +1 -1
- package/dist/form-elements/FormElementDate.js.map +1 -1
- package/dist/form-elements/FormElementDateTime.js +1 -1
- package/dist/form-elements/FormElementDateTime.js.map +1 -1
- package/dist/form-elements/FormElementEmail.js +1 -1
- package/dist/form-elements/FormElementEmail.js.map +1 -1
- package/dist/form-elements/FormElementForm.d.ts +8 -9
- package/dist/form-elements/FormElementForm.js +4 -3
- package/dist/form-elements/FormElementForm.js.map +1 -1
- package/dist/form-elements/FormElementLookupButton.js +4 -3
- package/dist/form-elements/FormElementLookupButton.js.map +1 -1
- package/dist/form-elements/FormElementNumber.js +1 -1
- package/dist/form-elements/FormElementNumber.js.map +1 -1
- package/dist/form-elements/FormElementRepeatableSet.d.ts +4 -4
- package/dist/form-elements/FormElementRepeatableSet.js +6 -4
- package/dist/form-elements/FormElementRepeatableSet.js.map +1 -1
- package/dist/form-elements/FormElementSection.d.ts +3 -3
- package/dist/form-elements/FormElementSection.js +2 -2
- package/dist/form-elements/FormElementSection.js.map +1 -1
- package/dist/form-elements/FormElementSelect.js +1 -1
- package/dist/form-elements/FormElementSelect.js.map +1 -1
- package/dist/form-elements/FormElementSummary.js +2 -0
- package/dist/form-elements/FormElementSummary.js.map +1 -1
- package/dist/form-elements/FormElementTelephone.js +1 -1
- package/dist/form-elements/FormElementTelephone.js.map +1 -1
- package/dist/form-elements/FormElementText.js +1 -1
- package/dist/form-elements/FormElementText.js.map +1 -1
- package/dist/form-elements/FormElementTextarea.js +1 -1
- package/dist/form-elements/FormElementTextarea.js.map +1 -1
- package/dist/form-elements/FormElementTime.js +1 -1
- package/dist/form-elements/FormElementTime.js.map +1 -1
- package/dist/hooks/useAreLookupsDisallowed.d.ts +2 -0
- package/dist/hooks/useAreLookupsDisallowed.js +12 -0
- package/dist/hooks/useAreLookupsDisallowed.js.map +1 -0
- package/dist/hooks/useEditableFormElementIds.d.ts +3 -0
- package/dist/hooks/useEditableFormElementIds.js +6 -0
- package/dist/hooks/useEditableFormElementIds.js.map +1 -0
- package/dist/hooks/useFormElementOptions.js +2 -0
- package/dist/hooks/useFormElementOptions.js.map +1 -1
- package/dist/hooks/useFormIsDirty.d.ts +56 -0
- package/dist/hooks/useFormIsDirty.js +121 -0
- package/dist/hooks/useFormIsDirty.js.map +1 -0
- package/dist/hooks/useFormSubmissionAttempt.d.ts +88 -0
- package/dist/hooks/useFormSubmissionAttempt.js +103 -0
- package/dist/hooks/useFormSubmissionAttempt.js.map +1 -0
- package/dist/hooks/useFormSubmissionAutoSaveState.d.ts +2 -9
- package/dist/hooks/useFormSubmissionAutoSaveState.js +4 -2
- package/dist/hooks/useFormSubmissionAutoSaveState.js.map +1 -1
- package/dist/hooks/useFormValidation.d.ts +1 -1
- package/dist/hooks/useFormValidation.js +2 -1
- package/dist/hooks/useFormValidation.js.map +1 -1
- package/dist/hooks/useInjectPages.d.ts +2 -1
- package/dist/hooks/useInjectPages.js.map +1 -1
- package/dist/hooks/useIsFormElementReadOnly.d.ts +2 -0
- package/dist/hooks/useIsFormElementReadOnly.js +13 -0
- package/dist/hooks/useIsFormElementReadOnly.js.map +1 -0
- package/dist/hooks/useLookupNotification.d.ts +23 -2
- package/dist/hooks/useLookupNotification.js +2 -1
- package/dist/hooks/useLookupNotification.js.map +1 -1
- package/dist/hooks/useLookups.d.ts +3 -3
- package/dist/hooks/useLookups.js +7 -4
- package/dist/hooks/useLookups.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/services/form-validation/extensions.d.ts +2 -1
- package/dist/services/form-validation/extensions.js +2 -1
- package/dist/services/form-validation/extensions.js.map +1 -1
- package/dist/services/form-validation/validateSubmission.d.ts +2 -1
- package/dist/services/form-validation/validateSubmission.js +14 -9
- package/dist/services/form-validation/validateSubmission.js.map +1 -1
- package/dist/services/getFlowInstanceNodesWithMeta.d.ts +70 -0
- package/dist/services/getFlowInstanceNodesWithMeta.js +247 -0
- package/dist/services/getFlowInstanceNodesWithMeta.js.map +1 -0
- package/dist/types/form.d.ts +17 -3
- package/dist/types/form.js.map +1 -1
- package/dist/utils/read-only-form-elements.d.ts +37 -0
- package/dist/utils/read-only-form-elements.js +63 -0
- package/dist/utils/read-only-form-elements.js.map +1 -0
- package/package.json +4 -3
- package/dist/services/isElementReadOnlyForAudience.d.ts +0 -20
- package/dist/services/isElementReadOnlyForAudience.js +0 -46
- package/dist/services/isElementReadOnlyForAudience.js.map +0 -1
- package/dist/services/resolveFormElementReadOnly.d.ts +0 -10
- package/dist/services/resolveFormElementReadOnly.js +0 -17
- package/dist/services/resolveFormElementReadOnly.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormElementTextarea.js","sourceRoot":"","sources":["../../src/form-elements/FormElementTextarea.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"FormElementTextarea.js","sourceRoot":"","sources":["../../src/form-elements/FormElementTextarea.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport clsx from 'clsx'\nimport { FormTypes } from '@oneblink/types'\nimport { TextareaAutosize, styled } from '@mui/material'\n\nimport CopyToClipboardButton from '../components/renderer/CopyToClipboardButton'\nimport LookupButton from '../components/renderer/LookupButton'\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport { FormElementValueChangeHandler, IsDirtyProps } from '../types/form'\nimport { LookupNotificationContext } from '../hooks/useLookupNotification'\nimport useElementAriaDescribedby from '../hooks/useElementAriaDescribedby'\nimport { ValidationIcon } from '../components/renderer/FormElementValidationMessage'\n\nconst StyledTextareaAutosize = styled(TextareaAutosize)(() => ({\n resize: 'vertical',\n}))\n\ntype Props = {\n id: string\n element: FormTypes.TextareaElement\n readOnly: boolean\n value: unknown\n onChange: FormElementValueChangeHandler<string>\n displayValidationMessage: boolean\n validationMessage: string | undefined\n autocompleteAttributes?: string\n} & IsDirtyProps\n\nfunction FormElementTextarea({\n id,\n element,\n readOnly,\n value,\n onChange,\n validationMessage,\n displayValidationMessage,\n isDirty,\n setIsDirty,\n autocompleteAttributes,\n}: Props) {\n const ariaDescribedby = useElementAriaDescribedby(id, element)\n const text = typeof value === 'string' ? value : ''\n const isDisplayingCopyButton = !!readOnly && !!value\n const isDisplayingLookupButton =\n !!element.isDataLookup || !!element.isElementLookup\n\n const { isLookingUp } = React.useContext(LookupNotificationContext)\n const isDisplayingValidationMessage =\n (isDirty || displayValidationMessage) && !!validationMessage && !isLookingUp\n\n return (\n <div className=\"cypress-textarea-element\">\n <FormElementLabelContainer\n className=\"ob-textarea\"\n id={id}\n element={element}\n required={element.required}\n >\n <div className=\"control\">\n <StyledTextareaAutosize\n placeholder={element.placeholderValue}\n id={id}\n name={element.name}\n className=\"input ob-input cypress-textarea-control\"\n value={text}\n onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>\n onChange(element, {\n value: e.target.value || undefined,\n })\n }\n required={element.required}\n disabled={readOnly}\n onBlur={setIsDirty}\n aria-describedby={ariaDescribedby}\n autoComplete={autocompleteAttributes}\n aria-required={element.required}\n minRows={4}\n />\n </div>\n\n {(isDisplayingValidationMessage || !!element.maxLength) && (\n <div className=\"has-margin-top-8\">\n <div className=\"is-flex is-justify-content-space-between\">\n {isDisplayingValidationMessage ? (\n <div\n role=\"alert\"\n className=\"has-text-danger ob-error__text cypress-validation-message\"\n >\n <ValidationIcon />\n {validationMessage}\n </div>\n ) : (\n <div />\n )}\n {!!element.maxLength && (\n <div\n className={clsx(\n 'ob-max-length__text cypress-max-length-message',\n {\n 'has-text-danger': text.length > element.maxLength,\n },\n )}\n >\n {text.length} / {element.maxLength}\n </div>\n )}\n </div>\n </div>\n )}\n\n {(isDisplayingLookupButton || isDisplayingCopyButton) && (\n <div className=\"buttons ob-buttons has-margin-top-8\">\n {isDisplayingCopyButton && (\n <CopyToClipboardButton\n className=\"button ob-button cypress-copy-to-clipboard-button\"\n text={text}\n />\n )}\n {isDisplayingLookupButton && (\n <LookupButton\n value={value}\n validationMessage={validationMessage}\n lookupButtonConfig={element.lookupButton}\n overrideRequiredMessage={undefined}\n />\n )}\n </div>\n )}\n </FormElementLabelContainer>\n </div>\n )\n}\n\nexport default React.memo(FormElementTextarea)\n"]}
|
|
@@ -43,7 +43,7 @@ function FormElementTime({ id, element, readOnly, value, onChange, validationMes
|
|
|
43
43
|
}, [value]);
|
|
44
44
|
const { isLookingUp } = React.useContext(LookupNotificationContext);
|
|
45
45
|
const isDisplayingValidationMessage = (isDirty || displayValidationMessage) && !!validationMessage && !isLookingUp;
|
|
46
|
-
return (_jsx("div", { className: "cypress-time-element", children: _jsxs(FormElementLabelContainer, { className: "ob-time", id: id, element: element, required: element.required, children: [_jsxs("div", { className: "field has-addons", children: [_jsx(TimePicker, { label: element.label, format: timeFormat, ...timeProps, timeSteps: { minutes: 1 } }), !readOnly && (_jsx(PickerInputButton, { tooltip: "Select time", onClick: openTimePicker, icon: "schedule" })), !!readOnly && !!text && (_jsx("div", { className: "control", children: _jsx(CopyToClipboardButton, { className: "button is-input-addon copy-button cypress-copy-to-clipboard-button", text: text }) })), _jsx(LookupButton, {
|
|
46
|
+
return (_jsx("div", { className: "cypress-time-element", children: _jsxs(FormElementLabelContainer, { className: "ob-time", id: id, element: element, required: element.required, children: [_jsxs("div", { className: "field has-addons", children: [_jsx(TimePicker, { label: element.label, format: timeFormat, ...timeProps, timeSteps: { minutes: 1 } }), !readOnly && (_jsx(PickerInputButton, { tooltip: "Select time", onClick: openTimePicker, icon: "schedule" })), !!readOnly && !!text && (_jsx("div", { className: "control", children: _jsx(CopyToClipboardButton, { className: "button is-input-addon copy-button cypress-copy-to-clipboard-button", text: text }) })), _jsx(LookupButton, { isInputButton: true, value: value, validationMessage: validationMessage, lookupButtonConfig: element.lookupButton, overrideRequiredMessage: undefined })] }), isDisplayingValidationMessage && (_jsx(FormElementValidationMessage, { message: validationMessage }))] }) }));
|
|
47
47
|
}
|
|
48
48
|
export default React.memo(FormElementTime);
|
|
49
49
|
//# sourceMappingURL=FormElementTime.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormElementTime.js","sourceRoot":"","sources":["../../src/form-elements/FormElementTime.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"FormElementTime.js","sourceRoot":"","sources":["../../src/form-elements/FormElementTime.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport { localisationService } from '../apps'\nimport { FormTypes } from '@oneblink/types'\nimport { TimePicker } from '@mui/x-date-pickers'\n\nimport CopyToClipboardButton from '../components/renderer/CopyToClipboardButton'\nimport LookupButton from '../components/renderer/LookupButton'\n\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport { FormElementValueChangeHandler, IsDirtyProps } from '../types/form'\nimport { LookupNotificationContext } from '../hooks/useLookupNotification'\nimport useElementAriaDescribedby from '../hooks/useElementAriaDescribedby'\nimport useFormDatePickerProps, {\n PickerInputButton,\n} from '../hooks/form-date-picker/useFormDatePickerProps'\nimport FormElementValidationMessage from '../components/renderer/FormElementValidationMessage'\n\ntype Props = {\n id: string\n element: FormTypes.TimeElement\n readOnly: boolean\n value: unknown | undefined\n onChange: FormElementValueChangeHandler<string>\n displayValidationMessage: boolean\n validationMessage: string | undefined\n} & IsDirtyProps\n\nconst timeFormat = localisationService.getDateFnsFormats().time\n\nfunction FormElementTime({\n id,\n element,\n readOnly,\n value,\n onChange,\n validationMessage,\n displayValidationMessage,\n isDirty,\n setIsDirty,\n}: Props) {\n const ariaDescribedby = useElementAriaDescribedby(id, element)\n\n const [commonProps, openTimePicker] = useFormDatePickerProps({\n id,\n value: typeof value === 'string' ? value : undefined,\n maxDate: undefined,\n minDate: undefined,\n ariaDescribedby,\n placeholder: element.placeholderValue,\n className: 'cypress-time-control',\n disabled: readOnly,\n required: element.required,\n onBlur: setIsDirty,\n onChange: (newDate) => {\n onChange(element, {\n value: newDate?.toISOString(),\n })\n },\n })\n\n const timeProps = React.useMemo(() => {\n // maxDate and minDate not applicable to a timepicker\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { maxDate, minDate, ...rest } = commonProps\n return rest\n }, [commonProps])\n\n const text = React.useMemo(() => {\n if (typeof value !== 'string') {\n return null\n }\n return localisationService.formatTime(new Date(value))\n }, [value])\n\n const { isLookingUp } = React.useContext(LookupNotificationContext)\n const isDisplayingValidationMessage =\n (isDirty || displayValidationMessage) && !!validationMessage && !isLookingUp\n\n return (\n <div className=\"cypress-time-element\">\n <FormElementLabelContainer\n className=\"ob-time\"\n id={id}\n element={element}\n required={element.required}\n >\n <div className=\"field has-addons\">\n <TimePicker\n label={element.label}\n format={timeFormat}\n {...timeProps}\n timeSteps={{ minutes: 1 }}\n />\n {!readOnly && (\n <PickerInputButton\n tooltip=\"Select time\"\n onClick={openTimePicker}\n icon=\"schedule\"\n />\n )}\n {!!readOnly && !!text && (\n <div className=\"control\">\n <CopyToClipboardButton\n className=\"button is-input-addon copy-button cypress-copy-to-clipboard-button\"\n text={text}\n />\n </div>\n )}\n <LookupButton\n isInputButton\n value={value}\n validationMessage={validationMessage}\n lookupButtonConfig={element.lookupButton}\n overrideRequiredMessage={undefined}\n />\n </div>\n\n {isDisplayingValidationMessage && (\n <FormElementValidationMessage message={validationMessage} />\n )}\n </FormElementLabelContainer>\n </div>\n )\n}\n\nexport default React.memo(FormElementTime)\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import useEditableFormElementIds from './useEditableFormElementIds';
|
|
2
|
+
import useFormIsReadOnly from './useFormIsReadOnly';
|
|
3
|
+
import { checkAreLookupsDisallowed } from '../utils/read-only-form-elements';
|
|
4
|
+
export default function useAreLookupsDisallowed(element) {
|
|
5
|
+
const isFormReadOnly = useFormIsReadOnly();
|
|
6
|
+
const editableFormElementIds = useEditableFormElementIds();
|
|
7
|
+
return checkAreLookupsDisallowed(element, {
|
|
8
|
+
isFormReadOnly,
|
|
9
|
+
editableFormElementIds,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=useAreLookupsDisallowed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAreLookupsDisallowed.js","sourceRoot":"","sources":["../../src/hooks/useAreLookupsDisallowed.ts"],"names":[],"mappings":"AACA,OAAO,yBAAyB,MAAM,6BAA6B,CAAA;AACnE,OAAO,iBAAiB,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAA;AAE5E,MAAM,CAAC,OAAO,UAAU,uBAAuB,CAC7C,OAA4D;IAE5D,MAAM,cAAc,GAAG,iBAAiB,EAAE,CAAA;IAC1C,MAAM,sBAAsB,GAAG,yBAAyB,EAAE,CAAA;IAE1D,OAAO,yBAAyB,CAAC,OAAO,EAAE;QACxC,cAAc;QACd,sBAAsB;KACvB,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { FormTypes } from '@oneblink/types'\r\nimport useEditableFormElementIds from './useEditableFormElementIds'\r\nimport useFormIsReadOnly from './useFormIsReadOnly'\r\nimport { checkAreLookupsDisallowed } from '../utils/read-only-form-elements'\r\n\r\nexport default function useAreLookupsDisallowed(\r\n element: FormTypes.FormElement | FormTypes.LookupFormElement,\r\n): boolean {\r\n const isFormReadOnly = useFormIsReadOnly()\r\n const editableFormElementIds = useEditableFormElementIds()\r\n\r\n return checkAreLookupsDisallowed(element, {\r\n isFormReadOnly,\r\n editableFormElementIds,\r\n })\r\n}\r\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export const EditableFormElementIdsContext = React.createContext(undefined);
|
|
3
|
+
export default function useEditableFormElementIds() {
|
|
4
|
+
return React.useContext(EditableFormElementIdsContext);
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=useEditableFormElementIds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEditableFormElementIds.js","sourceRoot":"","sources":["../../src/hooks/useEditableFormElementIds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,MAAM,CAAC,MAAM,6BAA6B,GAAG,KAAK,CAAC,aAAa,CAE9D,SAAS,CAAC,CAAA;AAEZ,MAAM,CAAC,OAAO,UAAU,yBAAyB;IAC/C,OAAO,KAAK,CAAC,UAAU,CAAC,6BAA6B,CAAC,CAAA;AACxD,CAAC","sourcesContent":["import * as React from 'react'\n\nexport const EditableFormElementIdsContext = React.createContext<\n string[] | undefined\n>(undefined)\n\nexport default function useEditableFormElementIds(): string[] | undefined {\n return React.useContext(EditableFormElementIdsContext)\n}\n"]}
|
|
@@ -63,6 +63,7 @@ export default function useFormElementOptions({ element, value, onChange, condit
|
|
|
63
63
|
!filteredOptions.some((option) => value === option.value)) {
|
|
64
64
|
onChange(element, {
|
|
65
65
|
value: undefined,
|
|
66
|
+
isDerivedChange: true,
|
|
66
67
|
});
|
|
67
68
|
return;
|
|
68
69
|
}
|
|
@@ -72,6 +73,7 @@ export default function useFormElementOptions({ element, value, onChange, condit
|
|
|
72
73
|
const newValueArray = newValue.length ? newValue : undefined;
|
|
73
74
|
onChange(element, {
|
|
74
75
|
value: newValueArray,
|
|
76
|
+
isDerivedChange: true,
|
|
75
77
|
});
|
|
76
78
|
}
|
|
77
79
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFormElementOptions.js","sourceRoot":"","sources":["../../src/hooks/useFormElementOptions.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"useFormElementOptions.js","sourceRoot":"","sources":["../../src/hooks/useFormElementOptions.ts"],"names":[],"mappings":"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","sourcesContent":["import { FormTypes } from '@oneblink/types'\nimport * as React from 'react'\nimport {\n FormElementValueChangeHandler,\n FormElementConditionallyShownElement,\n UpdateFormElementsHandler,\n} from '../types/form'\nimport { useLoadDynamicOptionsEffect } from './useDynamicOptionsLoaderState'\nimport useFormSubmissionModel from './useFormSubmissionModelContext'\nimport processInjectableOption from '../services/injectableOptions'\nimport useTaskContext from './useTaskContext'\nimport useUserProfileForInjectables from './useUserProfileForInjectables'\n\nexport default function useFormElementOptions<T>({\n element,\n value,\n onChange,\n conditionallyShownOptionsElement,\n onFilter,\n onUpdateFormElements,\n}: {\n element: FormTypes.FormElementWithOptions\n value: unknown | undefined\n onChange: FormElementValueChangeHandler<T>\n conditionallyShownOptionsElement:\n | FormElementConditionallyShownElement\n | undefined\n onFilter?: (choiceElementOption: FormTypes.ChoiceElementOption) => boolean\n onUpdateFormElements: UpdateFormElementsHandler\n}) {\n const taskContext = useTaskContext()\n const userProfileForInjectables = useUserProfileForInjectables()\n\n const { formSubmissionModel, elements, parent } = useFormSubmissionModel()\n const conditionallyShownOptions = conditionallyShownOptionsElement?.options\n //options that are shown due to conditional logic\n const shownOptions = React.useMemo<FormTypes.ChoiceElementOption[]>(() => {\n if (!element.options) {\n return []\n }\n if (!conditionallyShownOptions && !onFilter) {\n return element.options\n }\n return element.options.filter((option) => {\n return (\n !conditionallyShownOptions ||\n conditionallyShownOptions.some(({ id }) => id === option.id)\n )\n })\n }, [conditionallyShownOptions, element.options, onFilter])\n\n //\n const withInjectedOptions = React.useMemo(() => {\n return shownOptions.reduce<FormTypes.ChoiceElementOption[]>(\n (memo, option) => {\n const newOptions = processInjectableOption({\n option,\n submission: formSubmissionModel,\n formElements: elements,\n contextSubmission: parent?.formSubmissionModel || {},\n contextElements: parent?.elements || [],\n taskContext,\n userProfile: userProfileForInjectables,\n })\n memo.push(...newOptions)\n\n return memo\n },\n [],\n )\n }, [\n elements,\n formSubmissionModel,\n parent,\n shownOptions,\n taskContext,\n userProfileForInjectables,\n ])\n\n //options that are shown based on conditional logic, attributes, and user input\n const filteredOptions = React.useMemo<FormTypes.ChoiceElementOption[]>(() => {\n const reducedOptions = withInjectedOptions.filter(\n (option) => !onFilter || (onFilter(option) && !option.displayAlways),\n )\n if (element.type === 'autocomplete') {\n const alwaysShownOptions = withInjectedOptions.filter(\n (option) => option.displayAlways,\n )\n reducedOptions.push(...alwaysShownOptions)\n }\n return reducedOptions\n }, [withInjectedOptions, element.type, onFilter])\n\n React.useEffect(() => {\n if (\n !element.options ||\n conditionallyShownOptionsElement?.dependencyIsLoading\n ) {\n return\n }\n\n if (\n typeof value === 'string' &&\n !filteredOptions.some((option) => value === option.value)\n ) {\n onChange(element, {\n value: undefined,\n isDerivedChange: true,\n })\n return\n }\n\n if (Array.isArray(value)) {\n const newValue = value.filter((selectedValue) =>\n filteredOptions.some((option) => selectedValue === option.value),\n )\n if (newValue.length !== value.length) {\n const newValueArray = newValue.length ? newValue : undefined\n onChange(element, {\n value: newValueArray as T | undefined,\n isDerivedChange: true,\n })\n }\n }\n }, [\n element,\n onChange,\n value,\n conditionallyShownOptionsElement?.dependencyIsLoading,\n filteredOptions,\n ])\n\n useLoadDynamicOptionsEffect(element, onUpdateFormElements)\n\n return filteredOptions\n}\n"]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export declare function useMarkFormDirty(): () => void;
|
|
3
|
+
export declare function FormMarkDirtyContextProvider({ markDirty, children, }: {
|
|
4
|
+
markDirty: () => void;
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
/**
|
|
8
|
+
* Optional context that lets a host (for example Approvals) read whether a
|
|
9
|
+
* rendered form has unsaved user edits. Derived writes (`isDerivedChange`) do
|
|
10
|
+
* not set this.
|
|
11
|
+
*
|
|
12
|
+
* Wrap both the form and the host action so they share one registry. Each form
|
|
13
|
+
* registers under its `formId`, so multiple forms under the same provider (for
|
|
14
|
+
* example an approval form in a dialog) keep independent flags. If nothing is
|
|
15
|
+
* registered for a form, {@link useFormIsDirty} is `false`.
|
|
16
|
+
*
|
|
17
|
+
* @param props
|
|
18
|
+
* @returns
|
|
19
|
+
* @group Components
|
|
20
|
+
*/
|
|
21
|
+
export declare function FormIsDirtyContextProvider({ children, }: {
|
|
22
|
+
children: React.ReactNode;
|
|
23
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
/**
|
|
25
|
+
* Whether the form with `formId` has unsaved user edits. Safe to call without a
|
|
26
|
+
* provider: returns `false`.
|
|
27
|
+
*
|
|
28
|
+
* @param formId
|
|
29
|
+
* The id of the form whose dirty flag to read.
|
|
30
|
+
* @returns
|
|
31
|
+
* @group Hooks
|
|
32
|
+
*/
|
|
33
|
+
export declare function useFormIsDirty(formId: number): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Returns a callback that stops the form with `formId` prompting about unsaved
|
|
36
|
+
* changes when the host navigates away. Call it after the host action that
|
|
37
|
+
* discarded or persisted those edits has completed, immediately before
|
|
38
|
+
* navigating. Safe to call without a provider or for a form that is not
|
|
39
|
+
* rendered: nothing happens.
|
|
40
|
+
*
|
|
41
|
+
* @param formId
|
|
42
|
+
* The id of the form whose unsaved changes prompt to stop.
|
|
43
|
+
* @returns
|
|
44
|
+
* @group Hooks
|
|
45
|
+
*/
|
|
46
|
+
export declare function useAllowFormNavigation(formId: number): () => void;
|
|
47
|
+
/**
|
|
48
|
+
* Registers this form’s unsaved-changes flag with the nearest
|
|
49
|
+
* {@link FormIsDirtyContextProvider}. Used internally by `OneBlinkFormBase`.
|
|
50
|
+
*/
|
|
51
|
+
export declare function useRegisterFormIsDirty(formId: number, isDirty: boolean): void;
|
|
52
|
+
/**
|
|
53
|
+
* Registers the callback {@link useAllowFormNavigation} calls for this form.
|
|
54
|
+
* Used internally by `OneBlinkFormBase`.
|
|
55
|
+
*/
|
|
56
|
+
export declare function useRegisterAllowFormNavigation(formId: number, allowNavigation: () => void): void;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
const emptyDirtyByFormId = new Map();
|
|
4
|
+
const FormIsDirtyContext = React.createContext(emptyDirtyByFormId);
|
|
5
|
+
// Kept separate from the value so registering does not re-render the form
|
|
6
|
+
// every time the flag changes.
|
|
7
|
+
const RegisterFormIsDirtyContext = React.createContext(undefined);
|
|
8
|
+
const FormMarkDirtyContext = React.createContext(() => { });
|
|
9
|
+
const RegisterAllowFormNavigationContext = React.createContext(undefined);
|
|
10
|
+
const AllowFormNavigationContext = React.createContext(() => { });
|
|
11
|
+
export function useMarkFormDirty() {
|
|
12
|
+
return React.useContext(FormMarkDirtyContext);
|
|
13
|
+
}
|
|
14
|
+
export function FormMarkDirtyContextProvider({ markDirty, children, }) {
|
|
15
|
+
return (_jsx(FormMarkDirtyContext.Provider, { value: markDirty, children: children }));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Optional context that lets a host (for example Approvals) read whether a
|
|
19
|
+
* rendered form has unsaved user edits. Derived writes (`isDerivedChange`) do
|
|
20
|
+
* not set this.
|
|
21
|
+
*
|
|
22
|
+
* Wrap both the form and the host action so they share one registry. Each form
|
|
23
|
+
* registers under its `formId`, so multiple forms under the same provider (for
|
|
24
|
+
* example an approval form in a dialog) keep independent flags. If nothing is
|
|
25
|
+
* registered for a form, {@link useFormIsDirty} is `false`.
|
|
26
|
+
*
|
|
27
|
+
* @param props
|
|
28
|
+
* @returns
|
|
29
|
+
* @group Components
|
|
30
|
+
*/
|
|
31
|
+
export function FormIsDirtyContextProvider({ children, }) {
|
|
32
|
+
// Must be state, not a ref. Hosts reading this are siblings of the form, so
|
|
33
|
+
// they only re-render if the context value itself changes.
|
|
34
|
+
const [isDirtyByFormId, setIsDirtyByFormId] = React.useState(() => new Map());
|
|
35
|
+
// Kept in a ref, not state, so registering a form does not re-render hosts
|
|
36
|
+
// reading the dirty flags.
|
|
37
|
+
const allowNavigationByFormId = React.useRef(new Map()).current;
|
|
38
|
+
const registerAllowNavigation = React.useCallback((formId, allowNavigation) => {
|
|
39
|
+
allowNavigationByFormId.set(formId, allowNavigation);
|
|
40
|
+
return () => {
|
|
41
|
+
if (allowNavigationByFormId.get(formId) === allowNavigation) {
|
|
42
|
+
allowNavigationByFormId.delete(formId);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}, [allowNavigationByFormId]);
|
|
46
|
+
const allowNavigation = React.useCallback((formId) => {
|
|
47
|
+
var _a;
|
|
48
|
+
(_a = allowNavigationByFormId.get(formId)) === null || _a === void 0 ? void 0 : _a();
|
|
49
|
+
}, [allowNavigationByFormId]);
|
|
50
|
+
const register = React.useCallback((formId, isDirty) => {
|
|
51
|
+
setIsDirtyByFormId((current) => {
|
|
52
|
+
if (current.get(formId) === isDirty) {
|
|
53
|
+
return current;
|
|
54
|
+
}
|
|
55
|
+
const next = new Map(current);
|
|
56
|
+
next.set(formId, isDirty);
|
|
57
|
+
return next;
|
|
58
|
+
});
|
|
59
|
+
return () => {
|
|
60
|
+
setIsDirtyByFormId((current) => {
|
|
61
|
+
if (!current.has(formId)) {
|
|
62
|
+
return current;
|
|
63
|
+
}
|
|
64
|
+
const next = new Map(current);
|
|
65
|
+
next.delete(formId);
|
|
66
|
+
return next;
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
}, []);
|
|
70
|
+
return (_jsx(RegisterFormIsDirtyContext.Provider, { value: register, children: _jsx(RegisterAllowFormNavigationContext.Provider, { value: registerAllowNavigation, children: _jsx(AllowFormNavigationContext.Provider, { value: allowNavigation, children: _jsx(FormIsDirtyContext.Provider, { value: isDirtyByFormId, children: children }) }) }) }));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Whether the form with `formId` has unsaved user edits. Safe to call without a
|
|
74
|
+
* provider: returns `false`.
|
|
75
|
+
*
|
|
76
|
+
* @param formId
|
|
77
|
+
* The id of the form whose dirty flag to read.
|
|
78
|
+
* @returns
|
|
79
|
+
* @group Hooks
|
|
80
|
+
*/
|
|
81
|
+
export function useFormIsDirty(formId) {
|
|
82
|
+
var _a;
|
|
83
|
+
return (_a = React.useContext(FormIsDirtyContext).get(formId)) !== null && _a !== void 0 ? _a : false;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Returns a callback that stops the form with `formId` prompting about unsaved
|
|
87
|
+
* changes when the host navigates away. Call it after the host action that
|
|
88
|
+
* discarded or persisted those edits has completed, immediately before
|
|
89
|
+
* navigating. Safe to call without a provider or for a form that is not
|
|
90
|
+
* rendered: nothing happens.
|
|
91
|
+
*
|
|
92
|
+
* @param formId
|
|
93
|
+
* The id of the form whose unsaved changes prompt to stop.
|
|
94
|
+
* @returns
|
|
95
|
+
* @group Hooks
|
|
96
|
+
*/
|
|
97
|
+
export function useAllowFormNavigation(formId) {
|
|
98
|
+
const allowNavigation = React.useContext(AllowFormNavigationContext);
|
|
99
|
+
return React.useCallback(() => allowNavigation(formId), [allowNavigation, formId]);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Registers this form’s unsaved-changes flag with the nearest
|
|
103
|
+
* {@link FormIsDirtyContextProvider}. Used internally by `OneBlinkFormBase`.
|
|
104
|
+
*/
|
|
105
|
+
export function useRegisterFormIsDirty(formId, isDirty) {
|
|
106
|
+
const register = React.useContext(RegisterFormIsDirtyContext);
|
|
107
|
+
React.useLayoutEffect(() => {
|
|
108
|
+
return register === null || register === void 0 ? void 0 : register(formId, isDirty);
|
|
109
|
+
}, [register, formId, isDirty]);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Registers the callback {@link useAllowFormNavigation} calls for this form.
|
|
113
|
+
* Used internally by `OneBlinkFormBase`.
|
|
114
|
+
*/
|
|
115
|
+
export function useRegisterAllowFormNavigation(formId, allowNavigation) {
|
|
116
|
+
const register = React.useContext(RegisterAllowFormNavigationContext);
|
|
117
|
+
React.useLayoutEffect(() => {
|
|
118
|
+
return register === null || register === void 0 ? void 0 : register(formId, allowNavigation);
|
|
119
|
+
}, [register, formId, allowNavigation]);
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=useFormIsDirty.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFormIsDirty.js","sourceRoot":"","sources":["../../src/hooks/useFormIsDirty.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\n\nconst emptyDirtyByFormId: ReadonlyMap<number, boolean> = new Map()\n\nconst FormIsDirtyContext =\n React.createContext<ReadonlyMap<number, boolean>>(emptyDirtyByFormId)\n\n// Kept separate from the value so registering does not re-render the form\n// every time the flag changes.\nconst RegisterFormIsDirtyContext = React.createContext<\n ((formId: number, isDirty: boolean) => () => void) | undefined\n>(undefined)\n\nconst FormMarkDirtyContext = React.createContext<() => void>(() => {})\n\nconst RegisterAllowFormNavigationContext = React.createContext<\n ((formId: number, allowNavigation: () => void) => () => void) | undefined\n>(undefined)\n\nconst AllowFormNavigationContext = React.createContext<\n (formId: number) => void\n>(() => {})\n\nexport function useMarkFormDirty(): () => void {\n return React.useContext(FormMarkDirtyContext)\n}\n\nexport function FormMarkDirtyContextProvider({\n markDirty,\n children,\n}: {\n markDirty: () => void\n children: React.ReactNode\n}) {\n return (\n <FormMarkDirtyContext.Provider value={markDirty}>\n {children}\n </FormMarkDirtyContext.Provider>\n )\n}\n\n/**\n * Optional context that lets a host (for example Approvals) read whether a\n * rendered form has unsaved user edits. Derived writes (`isDerivedChange`) do\n * not set this.\n *\n * Wrap both the form and the host action so they share one registry. Each form\n * registers under its `formId`, so multiple forms under the same provider (for\n * example an approval form in a dialog) keep independent flags. If nothing is\n * registered for a form, {@link useFormIsDirty} is `false`.\n *\n * @param props\n * @returns\n * @group Components\n */\nexport function FormIsDirtyContextProvider({\n children,\n}: {\n children: React.ReactNode\n}) {\n // Must be state, not a ref. Hosts reading this are siblings of the form, so\n // they only re-render if the context value itself changes.\n const [isDirtyByFormId, setIsDirtyByFormId] = React.useState(\n () => new Map<number, boolean>(),\n )\n\n // Kept in a ref, not state, so registering a form does not re-render hosts\n // reading the dirty flags.\n const allowNavigationByFormId = React.useRef(\n new Map<number, () => void>(),\n ).current\n\n const registerAllowNavigation = React.useCallback(\n (formId: number, allowNavigation: () => void) => {\n allowNavigationByFormId.set(formId, allowNavigation)\n return () => {\n if (allowNavigationByFormId.get(formId) === allowNavigation) {\n allowNavigationByFormId.delete(formId)\n }\n }\n },\n [allowNavigationByFormId],\n )\n\n const allowNavigation = React.useCallback(\n (formId: number) => {\n allowNavigationByFormId.get(formId)?.()\n },\n [allowNavigationByFormId],\n )\n\n const register = React.useCallback((formId: number, isDirty: boolean) => {\n setIsDirtyByFormId((current) => {\n if (current.get(formId) === isDirty) {\n return current\n }\n const next = new Map(current)\n next.set(formId, isDirty)\n return next\n })\n return () => {\n setIsDirtyByFormId((current) => {\n if (!current.has(formId)) {\n return current\n }\n const next = new Map(current)\n next.delete(formId)\n return next\n })\n }\n }, [])\n\n return (\n <RegisterFormIsDirtyContext.Provider value={register}>\n <RegisterAllowFormNavigationContext.Provider\n value={registerAllowNavigation}\n >\n <AllowFormNavigationContext.Provider value={allowNavigation}>\n <FormIsDirtyContext.Provider value={isDirtyByFormId}>\n {children}\n </FormIsDirtyContext.Provider>\n </AllowFormNavigationContext.Provider>\n </RegisterAllowFormNavigationContext.Provider>\n </RegisterFormIsDirtyContext.Provider>\n )\n}\n\n/**\n * Whether the form with `formId` has unsaved user edits. Safe to call without a\n * provider: returns `false`.\n *\n * @param formId\n * The id of the form whose dirty flag to read.\n * @returns\n * @group Hooks\n */\nexport function useFormIsDirty(formId: number): boolean {\n return React.useContext(FormIsDirtyContext).get(formId) ?? false\n}\n\n/**\n * Returns a callback that stops the form with `formId` prompting about unsaved\n * changes when the host navigates away. Call it after the host action that\n * discarded or persisted those edits has completed, immediately before\n * navigating. Safe to call without a provider or for a form that is not\n * rendered: nothing happens.\n *\n * @param formId\n * The id of the form whose unsaved changes prompt to stop.\n * @returns\n * @group Hooks\n */\nexport function useAllowFormNavigation(formId: number): () => void {\n const allowNavigation = React.useContext(AllowFormNavigationContext)\n\n return React.useCallback(\n () => allowNavigation(formId),\n [allowNavigation, formId],\n )\n}\n\n/**\n * Registers this form’s unsaved-changes flag with the nearest\n * {@link FormIsDirtyContextProvider}. Used internally by `OneBlinkFormBase`.\n */\nexport function useRegisterFormIsDirty(formId: number, isDirty: boolean): void {\n const register = React.useContext(RegisterFormIsDirtyContext)\n\n React.useLayoutEffect(() => {\n return register?.(formId, isDirty)\n }, [register, formId, isDirty])\n}\n\n/**\n * Registers the callback {@link useAllowFormNavigation} calls for this form.\n * Used internally by `OneBlinkFormBase`.\n */\nexport function useRegisterAllowFormNavigation(\n formId: number,\n allowNavigation: () => void,\n): void {\n const register = React.useContext(RegisterAllowFormNavigationContext)\n\n React.useLayoutEffect(() => {\n return register?.(formId, allowNavigation)\n }, [register, formId, allowNavigation])\n}\n"]}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Call after the host has successfully persisted the edits (for example after
|
|
4
|
+
* an approval upload). This clears the unsaved-changes navigation guard.
|
|
5
|
+
*
|
|
6
|
+
* Do not call it until that work has finished: cancelling a confirmation dialog
|
|
7
|
+
* after a successful attempt must still prompt if the user navigates away.
|
|
8
|
+
*/
|
|
9
|
+
export type FormSubmissionAttemptAllowNavigation = () => void;
|
|
10
|
+
/**
|
|
11
|
+
* Runs the form’s existing submit-preparation path (validation, BSB checks,
|
|
12
|
+
* attachments, and the same error UI as a real submit).
|
|
13
|
+
*
|
|
14
|
+
* Resolves with {@link FormSubmissionAttemptAllowNavigation} when the host may
|
|
15
|
+
* continue (for example approve and upload an edit). Resolves `false` when
|
|
16
|
+
* preparation failed; field errors and toasts have already been shown. Does
|
|
17
|
+
* **not** call `onSubmit`, captcha, or analytics.
|
|
18
|
+
*/
|
|
19
|
+
export type FormSubmissionAttempt = () => Promise<false | FormSubmissionAttemptAllowNavigation>;
|
|
20
|
+
/**
|
|
21
|
+
* Optional context that lets a host (for example Approvals) trigger the
|
|
22
|
+
* rendered form’s submit-preparation path without duplicating it.
|
|
23
|
+
*
|
|
24
|
+
* Wrap both the form and the host action (Approve) so they share one registry.
|
|
25
|
+
* `OneBlinkFormBase` registers when `editableFormElementIds` is set. If nothing
|
|
26
|
+
* is registered, {@link useFormSubmissionAttempt} still resolves with a no-op
|
|
27
|
+
* {@link FormSubmissionAttemptAllowNavigation} so hosts without an editable form
|
|
28
|
+
* are unchanged.
|
|
29
|
+
*
|
|
30
|
+
* #### Example
|
|
31
|
+
*
|
|
32
|
+
* ```jsx
|
|
33
|
+
* import {
|
|
34
|
+
* FormSubmissionAttemptContextProvider,
|
|
35
|
+
* OneBlinkReadOnlyForm,
|
|
36
|
+
* useFormSubmissionAttempt,
|
|
37
|
+
* } from '@oneblink/apps-react'
|
|
38
|
+
*
|
|
39
|
+
* function ApproveButton() {
|
|
40
|
+
* const attemptFormSubmission = useFormSubmissionAttempt()
|
|
41
|
+
*
|
|
42
|
+
* const onClickApprove = async () => {
|
|
43
|
+
* const allowNavigation = await attemptFormSubmission()
|
|
44
|
+
* if (!allowNavigation) {
|
|
45
|
+
* return
|
|
46
|
+
* }
|
|
47
|
+
* // continue with the host action, then:
|
|
48
|
+
* allowNavigation()
|
|
49
|
+
* }
|
|
50
|
+
*
|
|
51
|
+
* return <button onClick={onClickApprove}>Approve</button>
|
|
52
|
+
* }
|
|
53
|
+
*
|
|
54
|
+
* function Approval() {
|
|
55
|
+
* return (
|
|
56
|
+
* <FormSubmissionAttemptContextProvider>
|
|
57
|
+
* <OneBlinkReadOnlyForm editableFormElementIds={['element-id']} />
|
|
58
|
+
* <ApproveButton />
|
|
59
|
+
* </FormSubmissionAttemptContextProvider>
|
|
60
|
+
* )
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @param props
|
|
65
|
+
* @returns
|
|
66
|
+
* @group Components
|
|
67
|
+
*/
|
|
68
|
+
export declare function FormSubmissionAttemptContextProvider({ children, }: {
|
|
69
|
+
/** The form and the host action that must share one submission attempt. */
|
|
70
|
+
children: React.ReactNode;
|
|
71
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
72
|
+
/**
|
|
73
|
+
* Returns the latest form submission attempt registered under a
|
|
74
|
+
* {@link FormSubmissionAttemptContextProvider}. Safe to call without a provider:
|
|
75
|
+
* preparation is skipped and the promise resolves with a no-op
|
|
76
|
+
* {@link FormSubmissionAttemptAllowNavigation}.
|
|
77
|
+
*
|
|
78
|
+
* @returns
|
|
79
|
+
* @group Hooks
|
|
80
|
+
*/
|
|
81
|
+
export declare function useFormSubmissionAttempt(): FormSubmissionAttempt;
|
|
82
|
+
/**
|
|
83
|
+
* Registers this form’s {@link FormSubmissionAttempt} with the nearest
|
|
84
|
+
* {@link FormSubmissionAttemptContextProvider}, if one exists. Used internally
|
|
85
|
+
* by `OneBlinkFormBase` when `editableFormElementIds` is provided. Pass
|
|
86
|
+
* `undefined` to skip registration (for example a fully read-only form).
|
|
87
|
+
*/
|
|
88
|
+
export declare function useRegisterFormSubmissionAttempt(attempt: FormSubmissionAttempt | undefined): void;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
const FormSubmissionAttemptContext = React.createContext(null);
|
|
4
|
+
/**
|
|
5
|
+
* Optional context that lets a host (for example Approvals) trigger the
|
|
6
|
+
* rendered form’s submit-preparation path without duplicating it.
|
|
7
|
+
*
|
|
8
|
+
* Wrap both the form and the host action (Approve) so they share one registry.
|
|
9
|
+
* `OneBlinkFormBase` registers when `editableFormElementIds` is set. If nothing
|
|
10
|
+
* is registered, {@link useFormSubmissionAttempt} still resolves with a no-op
|
|
11
|
+
* {@link FormSubmissionAttemptAllowNavigation} so hosts without an editable form
|
|
12
|
+
* are unchanged.
|
|
13
|
+
*
|
|
14
|
+
* #### Example
|
|
15
|
+
*
|
|
16
|
+
* ```jsx
|
|
17
|
+
* import {
|
|
18
|
+
* FormSubmissionAttemptContextProvider,
|
|
19
|
+
* OneBlinkReadOnlyForm,
|
|
20
|
+
* useFormSubmissionAttempt,
|
|
21
|
+
* } from '@oneblink/apps-react'
|
|
22
|
+
*
|
|
23
|
+
* function ApproveButton() {
|
|
24
|
+
* const attemptFormSubmission = useFormSubmissionAttempt()
|
|
25
|
+
*
|
|
26
|
+
* const onClickApprove = async () => {
|
|
27
|
+
* const allowNavigation = await attemptFormSubmission()
|
|
28
|
+
* if (!allowNavigation) {
|
|
29
|
+
* return
|
|
30
|
+
* }
|
|
31
|
+
* // continue with the host action, then:
|
|
32
|
+
* allowNavigation()
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* return <button onClick={onClickApprove}>Approve</button>
|
|
36
|
+
* }
|
|
37
|
+
*
|
|
38
|
+
* function Approval() {
|
|
39
|
+
* return (
|
|
40
|
+
* <FormSubmissionAttemptContextProvider>
|
|
41
|
+
* <OneBlinkReadOnlyForm editableFormElementIds={['element-id']} />
|
|
42
|
+
* <ApproveButton />
|
|
43
|
+
* </FormSubmissionAttemptContextProvider>
|
|
44
|
+
* )
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @param props
|
|
49
|
+
* @returns
|
|
50
|
+
* @group Components
|
|
51
|
+
*/
|
|
52
|
+
export function FormSubmissionAttemptContextProvider({ children, }) {
|
|
53
|
+
const attemptsRef = React.useRef([]);
|
|
54
|
+
const register = React.useCallback((attempt) => {
|
|
55
|
+
attemptsRef.current.push(attempt);
|
|
56
|
+
return () => {
|
|
57
|
+
attemptsRef.current = attemptsRef.current.filter((registeredAttempt) => registeredAttempt !== attempt);
|
|
58
|
+
};
|
|
59
|
+
}, []);
|
|
60
|
+
const attempt = React.useCallback(() => {
|
|
61
|
+
var _a, _b;
|
|
62
|
+
const registeredAttempts = attemptsRef.current;
|
|
63
|
+
return ((_b = (_a = registeredAttempts[registeredAttempts.length - 1]) === null || _a === void 0 ? void 0 : _a.call(registeredAttempts)) !== null && _b !== void 0 ? _b : Promise.resolve(noopAllowNavigation));
|
|
64
|
+
}, []);
|
|
65
|
+
const value = React.useMemo(() => ({
|
|
66
|
+
register,
|
|
67
|
+
attempt,
|
|
68
|
+
}), [attempt, register]);
|
|
69
|
+
return (_jsx(FormSubmissionAttemptContext.Provider, { value: value, children: children }));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Returns the latest form submission attempt registered under a
|
|
73
|
+
* {@link FormSubmissionAttemptContextProvider}. Safe to call without a provider:
|
|
74
|
+
* preparation is skipped and the promise resolves with a no-op
|
|
75
|
+
* {@link FormSubmissionAttemptAllowNavigation}.
|
|
76
|
+
*
|
|
77
|
+
* @returns
|
|
78
|
+
* @group Hooks
|
|
79
|
+
*/
|
|
80
|
+
export function useFormSubmissionAttempt() {
|
|
81
|
+
var _a;
|
|
82
|
+
const context = React.useContext(FormSubmissionAttemptContext);
|
|
83
|
+
return (_a = context === null || context === void 0 ? void 0 : context.attempt) !== null && _a !== void 0 ? _a : allowSubmissionAttempt;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Registers this form’s {@link FormSubmissionAttempt} with the nearest
|
|
87
|
+
* {@link FormSubmissionAttemptContextProvider}, if one exists. Used internally
|
|
88
|
+
* by `OneBlinkFormBase` when `editableFormElementIds` is provided. Pass
|
|
89
|
+
* `undefined` to skip registration (for example a fully read-only form).
|
|
90
|
+
*/
|
|
91
|
+
export function useRegisterFormSubmissionAttempt(attempt) {
|
|
92
|
+
const context = React.useContext(FormSubmissionAttemptContext);
|
|
93
|
+
React.useLayoutEffect(() => {
|
|
94
|
+
if (attempt) {
|
|
95
|
+
return context === null || context === void 0 ? void 0 : context.register(attempt);
|
|
96
|
+
}
|
|
97
|
+
}, [attempt, context]);
|
|
98
|
+
}
|
|
99
|
+
function noopAllowNavigation() { }
|
|
100
|
+
function allowSubmissionAttempt() {
|
|
101
|
+
return Promise.resolve(noopAllowNavigation);
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=useFormSubmissionAttempt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFormSubmissionAttempt.js","sourceRoot":"","sources":["../../src/hooks/useFormSubmissionAttempt.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA6B9B,MAAM,4BAA4B,GAChC,KAAK,CAAC,aAAa,CAA2C,IAAI,CAAC,CAAA;AAErE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,UAAU,oCAAoC,CAAC,EACnD,QAAQ,GAIT;IACC,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAA0B,EAAE,CAAC,CAAA;IAE7D,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,OAA8B,EAAE,EAAE;QACpE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACjC,OAAO,GAAG,EAAE;YACV,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,CAC9C,CAAC,iBAAiB,EAAE,EAAE,CAAC,iBAAiB,KAAK,OAAO,CACrD,CAAA;QACH,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,OAAO,GAAG,KAAK,CAAC,WAAW,CAAwB,GAAG,EAAE;;QAC5D,MAAM,kBAAkB,GAAG,WAAW,CAAC,OAAO,CAAA;QAC9C,OAAO,CACL,MAAA,MAAA,kBAAkB,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC,CAAC,kEAAI,mCACrD,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CACrC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CACzB,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ;QACR,OAAO;KACR,CAAC,EACF,CAAC,OAAO,EAAE,QAAQ,CAAC,CACpB,CAAA;IAED,OAAO,CACL,KAAC,4BAA4B,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAChD,QAAQ,GAC6B,CACzC,CAAA;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,wBAAwB;;IACtC,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,4BAA4B,CAAC,CAAA;IAC9D,OAAO,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO,mCAAI,sBAAsB,CAAA;AACnD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gCAAgC,CAC9C,OAA0C;IAE1C,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,4BAA4B,CAAC,CAAA;IAE9D,KAAK,CAAC,eAAe,CAAC,GAAG,EAAE;QACzB,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;QACnC,CAAC;IACH,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAA;AACxB,CAAC;AAED,SAAS,mBAAmB,KAAI,CAAC;AAEjC,SAAS,sBAAsB;IAC7B,OAAO,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAA;AAC7C,CAAC","sourcesContent":["import * as React from 'react'\n\n/**\n * Call after the host has successfully persisted the edits (for example after\n * an approval upload). This clears the unsaved-changes navigation guard.\n *\n * Do not call it until that work has finished: cancelling a confirmation dialog\n * after a successful attempt must still prompt if the user navigates away.\n */\nexport type FormSubmissionAttemptAllowNavigation = () => void\n\n/**\n * Runs the form’s existing submit-preparation path (validation, BSB checks,\n * attachments, and the same error UI as a real submit).\n *\n * Resolves with {@link FormSubmissionAttemptAllowNavigation} when the host may\n * continue (for example approve and upload an edit). Resolves `false` when\n * preparation failed; field errors and toasts have already been shown. Does\n * **not** call `onSubmit`, captcha, or analytics.\n */\nexport type FormSubmissionAttempt = () => Promise<\n false | FormSubmissionAttemptAllowNavigation\n>\n\ntype FormSubmissionAttemptContextValue = {\n register: (attempt: FormSubmissionAttempt) => () => void\n attempt: FormSubmissionAttempt\n}\n\nconst FormSubmissionAttemptContext =\n React.createContext<FormSubmissionAttemptContextValue | null>(null)\n\n/**\n * Optional context that lets a host (for example Approvals) trigger the\n * rendered form’s submit-preparation path without duplicating it.\n *\n * Wrap both the form and the host action (Approve) so they share one registry.\n * `OneBlinkFormBase` registers when `editableFormElementIds` is set. If nothing\n * is registered, {@link useFormSubmissionAttempt} still resolves with a no-op\n * {@link FormSubmissionAttemptAllowNavigation} so hosts without an editable form\n * are unchanged.\n *\n * #### Example\n *\n * ```jsx\n * import {\n * FormSubmissionAttemptContextProvider,\n * OneBlinkReadOnlyForm,\n * useFormSubmissionAttempt,\n * } from '@oneblink/apps-react'\n *\n * function ApproveButton() {\n * const attemptFormSubmission = useFormSubmissionAttempt()\n *\n * const onClickApprove = async () => {\n * const allowNavigation = await attemptFormSubmission()\n * if (!allowNavigation) {\n * return\n * }\n * // continue with the host action, then:\n * allowNavigation()\n * }\n *\n * return <button onClick={onClickApprove}>Approve</button>\n * }\n *\n * function Approval() {\n * return (\n * <FormSubmissionAttemptContextProvider>\n * <OneBlinkReadOnlyForm editableFormElementIds={['element-id']} />\n * <ApproveButton />\n * </FormSubmissionAttemptContextProvider>\n * )\n * }\n * ```\n *\n * @param props\n * @returns\n * @group Components\n */\nexport function FormSubmissionAttemptContextProvider({\n children,\n}: {\n /** The form and the host action that must share one submission attempt. */\n children: React.ReactNode\n}) {\n const attemptsRef = React.useRef<FormSubmissionAttempt[]>([])\n\n const register = React.useCallback((attempt: FormSubmissionAttempt) => {\n attemptsRef.current.push(attempt)\n return () => {\n attemptsRef.current = attemptsRef.current.filter(\n (registeredAttempt) => registeredAttempt !== attempt,\n )\n }\n }, [])\n\n const attempt = React.useCallback<FormSubmissionAttempt>(() => {\n const registeredAttempts = attemptsRef.current\n return (\n registeredAttempts[registeredAttempts.length - 1]?.() ??\n Promise.resolve(noopAllowNavigation)\n )\n }, [])\n\n const value = React.useMemo(\n () => ({\n register,\n attempt,\n }),\n [attempt, register],\n )\n\n return (\n <FormSubmissionAttemptContext.Provider value={value}>\n {children}\n </FormSubmissionAttemptContext.Provider>\n )\n}\n\n/**\n * Returns the latest form submission attempt registered under a\n * {@link FormSubmissionAttemptContextProvider}. Safe to call without a provider:\n * preparation is skipped and the promise resolves with a no-op\n * {@link FormSubmissionAttemptAllowNavigation}.\n *\n * @returns\n * @group Hooks\n */\nexport function useFormSubmissionAttempt(): FormSubmissionAttempt {\n const context = React.useContext(FormSubmissionAttemptContext)\n return context?.attempt ?? allowSubmissionAttempt\n}\n\n/**\n * Registers this form’s {@link FormSubmissionAttempt} with the nearest\n * {@link FormSubmissionAttemptContextProvider}, if one exists. Used internally\n * by `OneBlinkFormBase` when `editableFormElementIds` is provided. Pass\n * `undefined` to skip registration (for example a fully read-only form).\n */\nexport function useRegisterFormSubmissionAttempt(\n attempt: FormSubmissionAttempt | undefined,\n): void {\n const context = React.useContext(FormSubmissionAttemptContext)\n\n React.useLayoutEffect(() => {\n if (attempt) {\n return context?.register(attempt)\n }\n }, [attempt, context])\n}\n\nfunction noopAllowNavigation() {}\n\nfunction allowSubmissionAttempt(): Promise<FormSubmissionAttemptAllowNavigation> {\n return Promise.resolve(noopAllowNavigation)\n}\n"]}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
1
|
import { submissionService } from '../apps';
|
|
3
2
|
import { FormTypes, SubmissionTypes } from '@oneblink/types';
|
|
4
|
-
import { SectionState } from '../types/form';
|
|
3
|
+
import { SectionState, SetFormSubmission } from '../types/form';
|
|
5
4
|
/**
|
|
6
5
|
* Use this if you want to implement a controlled auto saving form. See
|
|
7
6
|
* {@link OneBlinkFormControlled} for a full example. If you do not need to
|
|
@@ -44,12 +43,6 @@ export default function useFormSubmissionAutoSaveState({ form, initialSubmission
|
|
|
44
43
|
handleCancel: () => void;
|
|
45
44
|
handleSaveDraft: ((newDraftSubmission: submissionService.NewDraftSubmission) => void) | undefined;
|
|
46
45
|
handleNavigateAway: () => void;
|
|
47
|
-
setFormSubmission:
|
|
48
|
-
definition: FormTypes.Form;
|
|
49
|
-
submission: SubmissionTypes.S3SubmissionData["submission"];
|
|
50
|
-
lastElementUpdated: FormTypes.FormElement | undefined;
|
|
51
|
-
executedLookups: import("../types/form").ExecutedLookups;
|
|
52
|
-
sectionState: SectionState | undefined;
|
|
53
|
-
}>>;
|
|
46
|
+
setFormSubmission: SetFormSubmission;
|
|
54
47
|
getCurrentSubmissionDuration: () => number;
|
|
55
48
|
};
|
|
@@ -158,12 +158,14 @@ export default function useFormSubmissionAutoSaveState({ form, initialSubmission
|
|
|
158
158
|
cancelAutoSave();
|
|
159
159
|
};
|
|
160
160
|
}, [cancelAutoSave]);
|
|
161
|
-
const setFormSubmissionAutoSave = React.useCallback((formSubmission) => {
|
|
161
|
+
const setFormSubmissionAutoSave = React.useCallback((formSubmission, options) => {
|
|
162
162
|
setFormSubmission((currentFormSubmission) => {
|
|
163
163
|
const newFormSubmission = typeof formSubmission === 'function'
|
|
164
164
|
? formSubmission(currentFormSubmission)
|
|
165
165
|
: formSubmission;
|
|
166
|
-
|
|
166
|
+
if (!(options === null || options === void 0 ? void 0 : options.isDerivedChange)) {
|
|
167
|
+
throttledAutoSave(newFormSubmission.submission, newFormSubmission.lastElementUpdated, newFormSubmission.sectionState);
|
|
168
|
+
}
|
|
167
169
|
return newFormSubmission;
|
|
168
170
|
});
|
|
169
171
|
}, [setFormSubmission, throttledAutoSave]);
|