@oneblink/apps-react 13.0.0-beta.1 → 13.0.0-beta.10

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.
Files changed (119) hide show
  1. package/dist/OneBlinkFormBase.d.ts +23 -3
  2. package/dist/OneBlinkFormBase.js +350 -193
  3. package/dist/OneBlinkFormBase.js.map +1 -1
  4. package/dist/OneBlinkReadOnlyForm.d.ts +17 -7
  5. package/dist/OneBlinkReadOnlyForm.js +24 -8
  6. package/dist/OneBlinkReadOnlyForm.js.map +1 -1
  7. package/dist/apps/approvals-service.d.ts +1 -0
  8. package/dist/apps/approvals-service.js.map +1 -1
  9. package/dist/apps/services/api/submissions.d.ts +3 -2
  10. package/dist/apps/services/api/submissions.js +3 -6
  11. package/dist/apps/services/api/submissions.js.map +1 -1
  12. package/dist/apps/submission-service.d.ts +11 -5
  13. package/dist/apps/submission-service.js +9 -4
  14. package/dist/apps/submission-service.js.map +1 -1
  15. package/dist/components/renderer/LookupButton.d.ts +1 -2
  16. package/dist/components/renderer/LookupButton.js +7 -6
  17. package/dist/components/renderer/LookupButton.js.map +1 -1
  18. package/dist/components/renderer/LookupNotification.js +31 -24
  19. package/dist/components/renderer/LookupNotification.js.map +1 -1
  20. package/dist/components/renderer/OneBlinkFormElements.d.ts +5 -7
  21. package/dist/components/renderer/OneBlinkFormElements.js +10 -35
  22. package/dist/components/renderer/OneBlinkFormElements.js.map +1 -1
  23. package/dist/components/renderer/PageFormElements.js +8 -3
  24. package/dist/components/renderer/PageFormElements.js.map +1 -1
  25. package/dist/components/renderer/ReverseGeocode.js +6 -11
  26. package/dist/components/renderer/ReverseGeocode.js.map +1 -1
  27. package/dist/form-elements/FormElementABN.js +1 -1
  28. package/dist/form-elements/FormElementABN.js.map +1 -1
  29. package/dist/form-elements/FormElementBSB.js +1 -1
  30. package/dist/form-elements/FormElementBSB.js.map +1 -1
  31. package/dist/form-elements/FormElementBarcodeScanner.js +1 -1
  32. package/dist/form-elements/FormElementBarcodeScanner.js.map +1 -1
  33. package/dist/form-elements/FormElementCalculation.js +1 -0
  34. package/dist/form-elements/FormElementCalculation.js.map +1 -1
  35. package/dist/form-elements/FormElementCheckBoxes.js +1 -1
  36. package/dist/form-elements/FormElementCheckBoxes.js.map +1 -1
  37. package/dist/form-elements/FormElementDate.js +1 -1
  38. package/dist/form-elements/FormElementDate.js.map +1 -1
  39. package/dist/form-elements/FormElementDateTime.js +1 -1
  40. package/dist/form-elements/FormElementDateTime.js.map +1 -1
  41. package/dist/form-elements/FormElementEmail.js +1 -1
  42. package/dist/form-elements/FormElementEmail.js.map +1 -1
  43. package/dist/form-elements/FormElementForm.d.ts +8 -9
  44. package/dist/form-elements/FormElementForm.js +4 -3
  45. package/dist/form-elements/FormElementForm.js.map +1 -1
  46. package/dist/form-elements/FormElementLookupButton.js +4 -3
  47. package/dist/form-elements/FormElementLookupButton.js.map +1 -1
  48. package/dist/form-elements/FormElementNumber.js +1 -1
  49. package/dist/form-elements/FormElementNumber.js.map +1 -1
  50. package/dist/form-elements/FormElementRepeatableSet.d.ts +4 -4
  51. package/dist/form-elements/FormElementRepeatableSet.js +6 -4
  52. package/dist/form-elements/FormElementRepeatableSet.js.map +1 -1
  53. package/dist/form-elements/FormElementSection.d.ts +3 -3
  54. package/dist/form-elements/FormElementSection.js +2 -2
  55. package/dist/form-elements/FormElementSection.js.map +1 -1
  56. package/dist/form-elements/FormElementSelect.js +1 -1
  57. package/dist/form-elements/FormElementSelect.js.map +1 -1
  58. package/dist/form-elements/FormElementSummary.js +2 -0
  59. package/dist/form-elements/FormElementSummary.js.map +1 -1
  60. package/dist/form-elements/FormElementTelephone.js +1 -1
  61. package/dist/form-elements/FormElementTelephone.js.map +1 -1
  62. package/dist/form-elements/FormElementText.js +1 -1
  63. package/dist/form-elements/FormElementText.js.map +1 -1
  64. package/dist/form-elements/FormElementTextarea.js +1 -1
  65. package/dist/form-elements/FormElementTextarea.js.map +1 -1
  66. package/dist/form-elements/FormElementTime.js +1 -1
  67. package/dist/form-elements/FormElementTime.js.map +1 -1
  68. package/dist/hooks/useAreLookupsDisallowed.d.ts +2 -0
  69. package/dist/hooks/useAreLookupsDisallowed.js +12 -0
  70. package/dist/hooks/useAreLookupsDisallowed.js.map +1 -0
  71. package/dist/hooks/useEditableFormElementIds.d.ts +3 -0
  72. package/dist/hooks/useEditableFormElementIds.js +6 -0
  73. package/dist/hooks/useEditableFormElementIds.js.map +1 -0
  74. package/dist/hooks/useFormElementOptions.js +2 -0
  75. package/dist/hooks/useFormElementOptions.js.map +1 -1
  76. package/dist/hooks/useFormIsDirty.d.ts +38 -0
  77. package/dist/hooks/useFormIsDirty.js +78 -0
  78. package/dist/hooks/useFormIsDirty.js.map +1 -0
  79. package/dist/hooks/useFormSubmissionAttempt.d.ts +88 -0
  80. package/dist/hooks/useFormSubmissionAttempt.js +103 -0
  81. package/dist/hooks/useFormSubmissionAttempt.js.map +1 -0
  82. package/dist/hooks/useFormSubmissionAutoSaveState.d.ts +2 -9
  83. package/dist/hooks/useFormSubmissionAutoSaveState.js +4 -2
  84. package/dist/hooks/useFormSubmissionAutoSaveState.js.map +1 -1
  85. package/dist/hooks/useFormValidation.d.ts +1 -1
  86. package/dist/hooks/useFormValidation.js +2 -1
  87. package/dist/hooks/useFormValidation.js.map +1 -1
  88. package/dist/hooks/useInjectPages.d.ts +2 -1
  89. package/dist/hooks/useInjectPages.js.map +1 -1
  90. package/dist/hooks/useIsFormElementReadOnly.d.ts +2 -0
  91. package/dist/hooks/useIsFormElementReadOnly.js +13 -0
  92. package/dist/hooks/useIsFormElementReadOnly.js.map +1 -0
  93. package/dist/hooks/useLookupNotification.d.ts +23 -2
  94. package/dist/hooks/useLookupNotification.js +2 -1
  95. package/dist/hooks/useLookupNotification.js.map +1 -1
  96. package/dist/hooks/useLookups.d.ts +3 -3
  97. package/dist/hooks/useLookups.js +7 -4
  98. package/dist/hooks/useLookups.js.map +1 -1
  99. package/dist/index.d.ts +2 -0
  100. package/dist/index.js +2 -0
  101. package/dist/index.js.map +1 -1
  102. package/dist/services/form-validation/extensions.d.ts +2 -1
  103. package/dist/services/form-validation/extensions.js +2 -1
  104. package/dist/services/form-validation/extensions.js.map +1 -1
  105. package/dist/services/form-validation/validateSubmission.d.ts +2 -1
  106. package/dist/services/form-validation/validateSubmission.js +14 -9
  107. package/dist/services/form-validation/validateSubmission.js.map +1 -1
  108. package/dist/types/form.d.ts +17 -3
  109. package/dist/types/form.js.map +1 -1
  110. package/dist/utils/read-only-form-elements.d.ts +37 -0
  111. package/dist/utils/read-only-form-elements.js +63 -0
  112. package/dist/utils/read-only-form-elements.js.map +1 -0
  113. package/package.json +4 -3
  114. package/dist/services/isElementReadOnlyForAudience.d.ts +0 -20
  115. package/dist/services/isElementReadOnlyForAudience.js +0 -46
  116. package/dist/services/isElementReadOnlyForAudience.js.map +0 -1
  117. package/dist/services/resolveFormElementReadOnly.d.ts +0 -10
  118. package/dist/services/resolveFormElementReadOnly.js +0 -17
  119. 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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","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 readOnly={readOnly}\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"]}
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, { readOnly: readOnly, isInputButton: true, value: value, validationMessage: validationMessage, lookupButtonConfig: element.lookupButton, overrideRequiredMessage: undefined })] }), isDisplayingValidationMessage && (_jsx(FormElementValidationMessage, { message: validationMessage }))] }) }));
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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","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 readOnly={readOnly}\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"]}
1
+ {"version":3,"file":"FormElementTime.js","sourceRoot":"","sources":["../../src/form-elements/FormElementTime.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAEhD,OAAO,qBAAqB,MAAM,8CAA8C,CAAA;AAChF,OAAO,YAAY,MAAM,qCAAqC,CAAA;AAE9D,OAAO,yBAAyB,MAAM,kDAAkD,CAAA;AAExF,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAA;AAC1E,OAAO,yBAAyB,MAAM,oCAAoC,CAAA;AAC1E,OAAO,sBAAsB,EAAE,EAC7B,iBAAiB,GAClB,MAAM,kDAAkD,CAAA;AACzD,OAAO,4BAA4B,MAAM,qDAAqD,CAAA;AAY9F,MAAM,UAAU,GAAG,mBAAmB,CAAC,iBAAiB,EAAE,CAAC,IAAI,CAAA;AAE/D,SAAS,eAAe,CAAC,EACvB,EAAE,EACF,OAAO,EACP,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,iBAAiB,EACjB,wBAAwB,EACxB,OAAO,EACP,UAAU,GACJ;IACN,MAAM,eAAe,GAAG,yBAAyB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;IAE9D,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,sBAAsB,CAAC;QAC3D,EAAE;QACF,KAAK,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;QACpD,OAAO,EAAE,SAAS;QAClB,OAAO,EAAE,SAAS;QAClB,eAAe;QACf,WAAW,EAAE,OAAO,CAAC,gBAAgB;QACrC,SAAS,EAAE,sBAAsB;QACjC,QAAQ,EAAE,QAAQ;QAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,MAAM,EAAE,UAAU;QAClB,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE;YACpB,QAAQ,CAAC,OAAO,EAAE;gBAChB,KAAK,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,WAAW,EAAE;aAC9B,CAAC,CAAA;QACJ,CAAC;KACF,CAAC,CAAA;IAEF,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACnC,qDAAqD;QACrD,6DAA6D;QAC7D,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,WAAW,CAAA;QACjD,OAAO,IAAI,CAAA;IACb,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;IAEjB,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,mBAAmB,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;IACxD,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAEX,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAA;IACnE,MAAM,6BAA6B,GACjC,CAAC,OAAO,IAAI,wBAAwB,CAAC,IAAI,CAAC,CAAC,iBAAiB,IAAI,CAAC,WAAW,CAAA;IAE9E,OAAO,CACL,cAAK,SAAS,EAAC,sBAAsB,YACnC,MAAC,yBAAyB,IACxB,SAAS,EAAC,SAAS,EACnB,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ,aAE1B,eAAK,SAAS,EAAC,kBAAkB,aAC/B,KAAC,UAAU,IACT,KAAK,EAAE,OAAO,CAAC,KAAK,EACpB,MAAM,EAAE,UAAU,KACd,SAAS,EACb,SAAS,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,GACzB,EACD,CAAC,QAAQ,IAAI,CACZ,KAAC,iBAAiB,IAChB,OAAO,EAAC,aAAa,EACrB,OAAO,EAAE,cAAc,EACvB,IAAI,EAAC,UAAU,GACf,CACH,EACA,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,IAAI,CACvB,cAAK,SAAS,EAAC,SAAS,YACtB,KAAC,qBAAqB,IACpB,SAAS,EAAC,oEAAoE,EAC9E,IAAI,EAAE,IAAI,GACV,GACE,CACP,EACD,KAAC,YAAY,IACX,aAAa,QACb,KAAK,EAAE,KAAK,EACZ,iBAAiB,EAAE,iBAAiB,EACpC,kBAAkB,EAAE,OAAO,CAAC,YAAY,EACxC,uBAAuB,EAAE,SAAS,GAClC,IACE,EAEL,6BAA6B,IAAI,CAChC,KAAC,4BAA4B,IAAC,OAAO,EAAE,iBAAiB,GAAI,CAC7D,IACyB,GACxB,CACP,CAAA;AACH,CAAC;AAED,eAAe,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA","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,2 @@
1
+ import { FormTypes } from '@oneblink/types';
2
+ export default function useAreLookupsDisallowed(element: FormTypes.FormElement | FormTypes.LookupFormElement): boolean;
@@ -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,3 @@
1
+ import * as React from 'react';
2
+ export declare const EditableFormElementIdsContext: React.Context<string[] | undefined>;
3
+ export default function useEditableFormElementIds(): string[] | undefined;
@@ -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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","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 })\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 })\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"]}
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,38 @@
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
+ * Registers this form’s unsaved-changes flag with the nearest
36
+ * {@link FormIsDirtyContextProvider}. Used internally by `OneBlinkFormBase`.
37
+ */
38
+ export declare function useRegisterFormIsDirty(formId: number, isDirty: boolean): void;
@@ -0,0 +1,78 @@
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
+ export function useMarkFormDirty() {
10
+ return React.useContext(FormMarkDirtyContext);
11
+ }
12
+ export function FormMarkDirtyContextProvider({ markDirty, children, }) {
13
+ return (_jsx(FormMarkDirtyContext.Provider, { value: markDirty, children: children }));
14
+ }
15
+ /**
16
+ * Optional context that lets a host (for example Approvals) read whether a
17
+ * rendered form has unsaved user edits. Derived writes (`isDerivedChange`) do
18
+ * not set this.
19
+ *
20
+ * Wrap both the form and the host action so they share one registry. Each form
21
+ * registers under its `formId`, so multiple forms under the same provider (for
22
+ * example an approval form in a dialog) keep independent flags. If nothing is
23
+ * registered for a form, {@link useFormIsDirty} is `false`.
24
+ *
25
+ * @param props
26
+ * @returns
27
+ * @group Components
28
+ */
29
+ export function FormIsDirtyContextProvider({ children, }) {
30
+ // Must be state, not a ref. Hosts reading this are siblings of the form, so
31
+ // they only re-render if the context value itself changes.
32
+ const [isDirtyByFormId, setIsDirtyByFormId] = React.useState(() => new Map());
33
+ const register = React.useCallback((formId, isDirty) => {
34
+ setIsDirtyByFormId((current) => {
35
+ if (current.get(formId) === isDirty) {
36
+ return current;
37
+ }
38
+ const next = new Map(current);
39
+ next.set(formId, isDirty);
40
+ return next;
41
+ });
42
+ return () => {
43
+ setIsDirtyByFormId((current) => {
44
+ if (!current.has(formId)) {
45
+ return current;
46
+ }
47
+ const next = new Map(current);
48
+ next.delete(formId);
49
+ return next;
50
+ });
51
+ };
52
+ }, []);
53
+ return (_jsx(RegisterFormIsDirtyContext.Provider, { value: register, children: _jsx(FormIsDirtyContext.Provider, { value: isDirtyByFormId, children: children }) }));
54
+ }
55
+ /**
56
+ * Whether the form with `formId` has unsaved user edits. Safe to call without a
57
+ * provider: returns `false`.
58
+ *
59
+ * @param formId
60
+ * The id of the form whose dirty flag to read.
61
+ * @returns
62
+ * @group Hooks
63
+ */
64
+ export function useFormIsDirty(formId) {
65
+ var _a;
66
+ return (_a = React.useContext(FormIsDirtyContext).get(formId)) !== null && _a !== void 0 ? _a : false;
67
+ }
68
+ /**
69
+ * Registers this form’s unsaved-changes flag with the nearest
70
+ * {@link FormIsDirtyContextProvider}. Used internally by `OneBlinkFormBase`.
71
+ */
72
+ export function useRegisterFormIsDirty(formId, isDirty) {
73
+ const register = React.useContext(RegisterFormIsDirtyContext);
74
+ React.useLayoutEffect(() => {
75
+ return register === null || register === void 0 ? void 0 : register(formId, isDirty);
76
+ }, [register, formId, isDirty]);
77
+ }
78
+ //# sourceMappingURL=useFormIsDirty.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFormIsDirty.js","sourceRoot":"","sources":["../../src/hooks/useFormIsDirty.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,MAAM,kBAAkB,GAAiC,IAAI,GAAG,EAAE,CAAA;AAElE,MAAM,kBAAkB,GACtB,KAAK,CAAC,aAAa,CAA+B,kBAAkB,CAAC,CAAA;AAEvE,0EAA0E;AAC1E,+BAA+B;AAC/B,MAAM,0BAA0B,GAAG,KAAK,CAAC,aAAa,CAEpD,SAAS,CAAC,CAAA;AAEZ,MAAM,oBAAoB,GAAG,KAAK,CAAC,aAAa,CAAa,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;AAEtE,MAAM,UAAU,gBAAgB;IAC9B,OAAO,KAAK,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAA;AAC/C,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,EAC3C,SAAS,EACT,QAAQ,GAIT;IACC,OAAO,CACL,KAAC,oBAAoB,CAAC,QAAQ,IAAC,KAAK,EAAE,SAAS,YAC5C,QAAQ,GACqB,CACjC,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,0BAA0B,CAAC,EACzC,QAAQ,GAGT;IACC,4EAA4E;IAC5E,2DAA2D;IAC3D,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,KAAK,CAAC,QAAQ,CAC1D,GAAG,EAAE,CAAC,IAAI,GAAG,EAAmB,CACjC,CAAA;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,MAAc,EAAE,OAAgB,EAAE,EAAE;QACtE,kBAAkB,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,OAAO,EAAE,CAAC;gBACpC,OAAO,OAAO,CAAA;YAChB,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAA;YAC7B,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;YACzB,OAAO,IAAI,CAAA;QACb,CAAC,CAAC,CAAA;QACF,OAAO,GAAG,EAAE;YACV,kBAAkB,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC7B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;oBACzB,OAAO,OAAO,CAAA;gBAChB,CAAC;gBACD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAA;gBAC7B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;gBACnB,OAAO,IAAI,CAAA;YACb,CAAC,CAAC,CAAA;QACJ,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,CACL,KAAC,0BAA0B,CAAC,QAAQ,IAAC,KAAK,EAAE,QAAQ,YAClD,KAAC,kBAAkB,CAAC,QAAQ,IAAC,KAAK,EAAE,eAAe,YAChD,QAAQ,GACmB,GACM,CACvC,CAAA;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc;;IAC3C,OAAO,MAAA,KAAK,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,mCAAI,KAAK,CAAA;AAClE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAc,EAAE,OAAgB;IACrE,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,0BAA0B,CAAC,CAAA;IAE7D,KAAK,CAAC,eAAe,CAAC,GAAG,EAAE;QACzB,OAAO,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAG,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AACjC,CAAC","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\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 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 <FormIsDirtyContext.Provider value={isDirtyByFormId}>\n {children}\n </FormIsDirtyContext.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 * 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"]}
@@ -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: React.Dispatch<React.SetStateAction<{
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
- throttledAutoSave(newFormSubmission.submission, newFormSubmission.lastElementUpdated, newFormSubmission.sectionState);
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]);