@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.
Files changed (123) hide show
  1. package/dist/OneBlinkFormBase.d.ts +23 -3
  2. package/dist/OneBlinkFormBase.js +351 -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 +2 -60
  8. package/dist/apps/approvals-service.js +1 -181
  9. package/dist/apps/approvals-service.js.map +1 -1
  10. package/dist/apps/services/api/submissions.d.ts +3 -2
  11. package/dist/apps/services/api/submissions.js +3 -6
  12. package/dist/apps/services/api/submissions.js.map +1 -1
  13. package/dist/apps/submission-service.d.ts +11 -5
  14. package/dist/apps/submission-service.js +9 -4
  15. package/dist/apps/submission-service.js.map +1 -1
  16. package/dist/components/renderer/LookupButton.d.ts +1 -2
  17. package/dist/components/renderer/LookupButton.js +7 -6
  18. package/dist/components/renderer/LookupButton.js.map +1 -1
  19. package/dist/components/renderer/LookupNotification.js +31 -24
  20. package/dist/components/renderer/LookupNotification.js.map +1 -1
  21. package/dist/components/renderer/OneBlinkFormElements.d.ts +5 -7
  22. package/dist/components/renderer/OneBlinkFormElements.js +10 -35
  23. package/dist/components/renderer/OneBlinkFormElements.js.map +1 -1
  24. package/dist/components/renderer/PageFormElements.js +8 -3
  25. package/dist/components/renderer/PageFormElements.js.map +1 -1
  26. package/dist/components/renderer/ReverseGeocode.js +6 -11
  27. package/dist/components/renderer/ReverseGeocode.js.map +1 -1
  28. package/dist/form-elements/FormElementABN.js +1 -1
  29. package/dist/form-elements/FormElementABN.js.map +1 -1
  30. package/dist/form-elements/FormElementBSB.js +1 -1
  31. package/dist/form-elements/FormElementBSB.js.map +1 -1
  32. package/dist/form-elements/FormElementBarcodeScanner.js +1 -1
  33. package/dist/form-elements/FormElementBarcodeScanner.js.map +1 -1
  34. package/dist/form-elements/FormElementCalculation.js +1 -0
  35. package/dist/form-elements/FormElementCalculation.js.map +1 -1
  36. package/dist/form-elements/FormElementCheckBoxes.js +1 -1
  37. package/dist/form-elements/FormElementCheckBoxes.js.map +1 -1
  38. package/dist/form-elements/FormElementDate.js +1 -1
  39. package/dist/form-elements/FormElementDate.js.map +1 -1
  40. package/dist/form-elements/FormElementDateTime.js +1 -1
  41. package/dist/form-elements/FormElementDateTime.js.map +1 -1
  42. package/dist/form-elements/FormElementEmail.js +1 -1
  43. package/dist/form-elements/FormElementEmail.js.map +1 -1
  44. package/dist/form-elements/FormElementForm.d.ts +8 -9
  45. package/dist/form-elements/FormElementForm.js +4 -3
  46. package/dist/form-elements/FormElementForm.js.map +1 -1
  47. package/dist/form-elements/FormElementLookupButton.js +4 -3
  48. package/dist/form-elements/FormElementLookupButton.js.map +1 -1
  49. package/dist/form-elements/FormElementNumber.js +1 -1
  50. package/dist/form-elements/FormElementNumber.js.map +1 -1
  51. package/dist/form-elements/FormElementRepeatableSet.d.ts +4 -4
  52. package/dist/form-elements/FormElementRepeatableSet.js +6 -4
  53. package/dist/form-elements/FormElementRepeatableSet.js.map +1 -1
  54. package/dist/form-elements/FormElementSection.d.ts +3 -3
  55. package/dist/form-elements/FormElementSection.js +2 -2
  56. package/dist/form-elements/FormElementSection.js.map +1 -1
  57. package/dist/form-elements/FormElementSelect.js +1 -1
  58. package/dist/form-elements/FormElementSelect.js.map +1 -1
  59. package/dist/form-elements/FormElementSummary.js +2 -0
  60. package/dist/form-elements/FormElementSummary.js.map +1 -1
  61. package/dist/form-elements/FormElementTelephone.js +1 -1
  62. package/dist/form-elements/FormElementTelephone.js.map +1 -1
  63. package/dist/form-elements/FormElementText.js +1 -1
  64. package/dist/form-elements/FormElementText.js.map +1 -1
  65. package/dist/form-elements/FormElementTextarea.js +1 -1
  66. package/dist/form-elements/FormElementTextarea.js.map +1 -1
  67. package/dist/form-elements/FormElementTime.js +1 -1
  68. package/dist/form-elements/FormElementTime.js.map +1 -1
  69. package/dist/hooks/useAreLookupsDisallowed.d.ts +2 -0
  70. package/dist/hooks/useAreLookupsDisallowed.js +12 -0
  71. package/dist/hooks/useAreLookupsDisallowed.js.map +1 -0
  72. package/dist/hooks/useEditableFormElementIds.d.ts +3 -0
  73. package/dist/hooks/useEditableFormElementIds.js +6 -0
  74. package/dist/hooks/useEditableFormElementIds.js.map +1 -0
  75. package/dist/hooks/useFormElementOptions.js +2 -0
  76. package/dist/hooks/useFormElementOptions.js.map +1 -1
  77. package/dist/hooks/useFormIsDirty.d.ts +56 -0
  78. package/dist/hooks/useFormIsDirty.js +121 -0
  79. package/dist/hooks/useFormIsDirty.js.map +1 -0
  80. package/dist/hooks/useFormSubmissionAttempt.d.ts +88 -0
  81. package/dist/hooks/useFormSubmissionAttempt.js +103 -0
  82. package/dist/hooks/useFormSubmissionAttempt.js.map +1 -0
  83. package/dist/hooks/useFormSubmissionAutoSaveState.d.ts +2 -9
  84. package/dist/hooks/useFormSubmissionAutoSaveState.js +4 -2
  85. package/dist/hooks/useFormSubmissionAutoSaveState.js.map +1 -1
  86. package/dist/hooks/useFormValidation.d.ts +1 -1
  87. package/dist/hooks/useFormValidation.js +2 -1
  88. package/dist/hooks/useFormValidation.js.map +1 -1
  89. package/dist/hooks/useInjectPages.d.ts +2 -1
  90. package/dist/hooks/useInjectPages.js.map +1 -1
  91. package/dist/hooks/useIsFormElementReadOnly.d.ts +2 -0
  92. package/dist/hooks/useIsFormElementReadOnly.js +13 -0
  93. package/dist/hooks/useIsFormElementReadOnly.js.map +1 -0
  94. package/dist/hooks/useLookupNotification.d.ts +23 -2
  95. package/dist/hooks/useLookupNotification.js +2 -1
  96. package/dist/hooks/useLookupNotification.js.map +1 -1
  97. package/dist/hooks/useLookups.d.ts +3 -3
  98. package/dist/hooks/useLookups.js +7 -4
  99. package/dist/hooks/useLookups.js.map +1 -1
  100. package/dist/index.d.ts +2 -0
  101. package/dist/index.js +2 -0
  102. package/dist/index.js.map +1 -1
  103. package/dist/services/form-validation/extensions.d.ts +2 -1
  104. package/dist/services/form-validation/extensions.js +2 -1
  105. package/dist/services/form-validation/extensions.js.map +1 -1
  106. package/dist/services/form-validation/validateSubmission.d.ts +2 -1
  107. package/dist/services/form-validation/validateSubmission.js +14 -9
  108. package/dist/services/form-validation/validateSubmission.js.map +1 -1
  109. package/dist/services/getFlowInstanceNodesWithMeta.d.ts +70 -0
  110. package/dist/services/getFlowInstanceNodesWithMeta.js +247 -0
  111. package/dist/services/getFlowInstanceNodesWithMeta.js.map +1 -0
  112. package/dist/types/form.d.ts +17 -3
  113. package/dist/types/form.js.map +1 -1
  114. package/dist/utils/read-only-form-elements.d.ts +37 -0
  115. package/dist/utils/read-only-form-elements.js +63 -0
  116. package/dist/utils/read-only-form-elements.js.map +1 -0
  117. package/package.json +4 -3
  118. package/dist/services/isElementReadOnlyForAudience.d.ts +0 -20
  119. package/dist/services/isElementReadOnlyForAudience.js +0 -46
  120. package/dist/services/isElementReadOnlyForAudience.js.map +0 -1
  121. package/dist/services/resolveFormElementReadOnly.d.ts +0 -10
  122. package/dist/services/resolveFormElementReadOnly.js +0 -17
  123. 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":";AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAExD,OAAO,qBAAqB,MAAM,8CAA8C,CAAA;AAChF,OAAO,YAAY,MAAM,qCAAqC,CAAA;AAC9D,OAAO,yBAAyB,MAAM,kDAAkD,CAAA;AAExF,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAA;AAC1E,OAAO,yBAAyB,MAAM,oCAAoC,CAAA;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,qDAAqD,CAAA;AAEpF,MAAM,sBAAsB,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7D,MAAM,EAAE,UAAU;CACnB,CAAC,CAAC,CAAA;AAaH,SAAS,mBAAmB,CAAC,EAC3B,EAAE,EACF,OAAO,EACP,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,iBAAiB,EACjB,wBAAwB,EACxB,OAAO,EACP,UAAU,EACV,sBAAsB,GAChB;IACN,MAAM,eAAe,GAAG,yBAAyB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;IAC9D,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;IACnD,MAAM,sBAAsB,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAA;IACpD,MAAM,wBAAwB,GAC5B,CAAC,CAAC,OAAO,CAAC,YAAY,IAAI,CAAC,CAAC,OAAO,CAAC,eAAe,CAAA;IAErD,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,0BAA0B,YACvC,MAAC,yBAAyB,IACxB,SAAS,EAAC,aAAa,EACvB,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ,aAE1B,cAAK,SAAS,EAAC,SAAS,YACtB,KAAC,sBAAsB,IACrB,WAAW,EAAE,OAAO,CAAC,gBAAgB,EACrC,EAAE,EAAE,EAAE,EACN,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,SAAS,EAAC,yCAAyC,EACnD,KAAK,EAAE,IAAI,EACX,QAAQ,EAAE,CAAC,CAAyC,EAAE,EAAE,CACtD,QAAQ,CAAC,OAAO,EAAE;4BAChB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,SAAS;yBACnC,CAAC,EAEJ,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAC1B,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,UAAU,sBACA,eAAe,EACjC,YAAY,EAAE,sBAAsB,mBACrB,OAAO,CAAC,QAAQ,EAC/B,OAAO,EAAE,CAAC,GACV,GACE,EAEL,CAAC,6BAA6B,IAAI,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CACzD,cAAK,SAAS,EAAC,kBAAkB,YAC/B,eAAK,SAAS,EAAC,0CAA0C,aACtD,6BAA6B,CAAC,CAAC,CAAC,CAC/B,eACE,IAAI,EAAC,OAAO,EACZ,SAAS,EAAC,2DAA2D,aAErE,KAAC,cAAc,KAAG,EACjB,iBAAiB,IACd,CACP,CAAC,CAAC,CAAC,CACF,eAAO,CACR,EACA,CAAC,CAAC,OAAO,CAAC,SAAS,IAAI,CACtB,eACE,SAAS,EAAE,IAAI,CACb,gDAAgD,EAChD;oCACE,iBAAiB,EAAE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS;iCACnD,CACF,aAEA,IAAI,CAAC,MAAM,SAAK,OAAO,CAAC,SAAS,IAC9B,CACP,IACG,GACF,CACP,EAEA,CAAC,wBAAwB,IAAI,sBAAsB,CAAC,IAAI,CACvD,eAAK,SAAS,EAAC,qCAAqC,aACjD,sBAAsB,IAAI,CACzB,KAAC,qBAAqB,IACpB,SAAS,EAAC,mDAAmD,EAC7D,IAAI,EAAE,IAAI,GACV,CACH,EACA,wBAAwB,IAAI,CAC3B,KAAC,YAAY,IACX,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,KAAK,EACZ,iBAAiB,EAAE,iBAAiB,EACpC,kBAAkB,EAAE,OAAO,CAAC,YAAY,EACxC,uBAAuB,EAAE,SAAS,GAClC,CACH,IACG,CACP,IACyB,GACxB,CACP,CAAA;AACH,CAAC;AAED,eAAe,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA","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":";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,QAAQ,EAAE,QAAQ,EAClB,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 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":"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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,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,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: 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]);