@oneblink/apps-react 9.0.0-beta.6 → 9.0.0-beta.7

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.
@@ -4,10 +4,10 @@ import { Dialog, DialogActions, DialogTitle, DialogContent, Button, Portal, } fr
4
4
  import useIsMounted from '../hooks/useIsMounted';
5
5
  import ErrorSnackbar from './ErrorSnackbar';
6
6
  export default function ConfirmDialog({ isOpen, onClose, children, onConfirm, title, confirmButtonText, confirmButtonIcon, cypress, TransitionProps, disabled, }) {
7
- const isMountedRef = useIsMounted();
8
- const isMounted = isMountedRef.current;
7
+ const isMounted = useIsMounted();
9
8
  const [isConfirming, setIsConfirming] = React.useState(false);
10
9
  const [error, setError] = React.useState(null);
10
+ // eslint-disable-next-line react-hooks/preserve-manual-memoization
11
11
  const handleConfirm = React.useCallback(async () => {
12
12
  setIsConfirming(true);
13
13
  setError(null);
@@ -19,7 +19,7 @@ export default function ConfirmDialog({ isOpen, onClose, children, onConfirm, ti
19
19
  catch (error) {
20
20
  newError = error;
21
21
  }
22
- if (isMounted && !abortController.signal.aborted) {
22
+ if (isMounted.current && !abortController.signal.aborted) {
23
23
  setIsConfirming(false);
24
24
  setError(newError);
25
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmDialog.js","sourceRoot":"","sources":["../../src/components/ConfirmDialog.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport {\n Dialog,\n DialogActions,\n DialogTitle,\n DialogContent,\n Button,\n Portal,\n DialogProps,\n} from '@mui/material'\nimport useIsMounted from '../hooks/useIsMounted'\nimport ErrorSnackbar from './ErrorSnackbar'\n\ntype Props = {\n isOpen: boolean\n onClose: () => void\n onConfirm: (abortSignal: AbortSignal) => unknown\n children: React.ReactNode\n title: string\n confirmButtonText: string\n confirmButtonIcon: React.ReactNode\n cypress?: {\n dialog?: string\n confirmButton?: string\n cancelButton?: string\n error?: string\n title?: string\n }\n TransitionProps?: NonNullable<DialogProps['slotProps']>['transition']\n disabled?: boolean\n}\n\nexport default function ConfirmDialog({\n isOpen,\n onClose,\n children,\n onConfirm,\n title,\n confirmButtonText,\n confirmButtonIcon,\n cypress,\n TransitionProps,\n disabled,\n}: Props) {\n const isMountedRef = useIsMounted()\n\n const isMounted = isMountedRef.current\n\n const [isConfirming, setIsConfirming] = React.useState(false)\n const [error, setError] = React.useState<Error | null>(null)\n\n const handleConfirm = React.useCallback(async () => {\n setIsConfirming(true)\n setError(null)\n let newError = null\n\n const abortController = new AbortController()\n try {\n await onConfirm(abortController.signal)\n } catch (error) {\n newError = error as Error\n }\n\n if (isMounted && !abortController.signal.aborted) {\n setIsConfirming(false)\n setError(newError)\n }\n }, [isMounted, onConfirm])\n\n return (\n <React.Fragment>\n <Dialog\n open={isOpen}\n maxWidth=\"sm\"\n fullWidth\n onClose={!isConfirming ? onClose : undefined}\n data-cypress={cypress?.dialog}\n slotProps={{\n transition: {\n onExiting: () => setError(null),\n ...(TransitionProps ? TransitionProps : {}),\n },\n }}\n >\n <DialogTitle data-cypress={cypress?.title}>{title}</DialogTitle>\n <DialogContent dividers>{children}</DialogContent>\n <DialogActions>\n <Button\n disabled={isConfirming}\n onClick={onClose}\n data-cypress={cypress?.cancelButton}\n >\n Cancel\n </Button>\n\n <Button\n variant=\"contained\"\n loading={isConfirming}\n autoFocus\n startIcon={confirmButtonIcon}\n loadingPosition=\"start\"\n onClick={handleConfirm}\n data-cypress={cypress?.confirmButton}\n disabled={disabled}\n >\n {confirmButtonText}\n </Button>\n </DialogActions>\n </Dialog>\n <Portal>\n <ErrorSnackbar open={!!error} onClose={setError}>\n <span data-cypress={cypress?.error}>{error?.message}</span>\n </ErrorSnackbar>\n </Portal>\n </React.Fragment>\n )\n}\n"]}
1
+ {"version":3,"file":"ConfirmDialog.js","sourceRoot":"","sources":["../../src/components/ConfirmDialog.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport {\n Dialog,\n DialogActions,\n DialogTitle,\n DialogContent,\n Button,\n Portal,\n DialogProps,\n} from '@mui/material'\nimport useIsMounted from '../hooks/useIsMounted'\nimport ErrorSnackbar from './ErrorSnackbar'\n\ntype Props = {\n isOpen: boolean\n onClose: () => void\n onConfirm: (abortSignal: AbortSignal) => unknown\n children: React.ReactNode\n title: string\n confirmButtonText: string\n confirmButtonIcon: React.ReactNode\n cypress?: {\n dialog?: string\n confirmButton?: string\n cancelButton?: string\n error?: string\n title?: string\n }\n TransitionProps?: NonNullable<DialogProps['slotProps']>['transition']\n disabled?: boolean\n}\n\nexport default function ConfirmDialog({\n isOpen,\n onClose,\n children,\n onConfirm,\n title,\n confirmButtonText,\n confirmButtonIcon,\n cypress,\n TransitionProps,\n disabled,\n}: Props) {\n const isMounted = useIsMounted()\n\n const [isConfirming, setIsConfirming] = React.useState(false)\n const [error, setError] = React.useState<Error | null>(null)\n\n // eslint-disable-next-line react-hooks/preserve-manual-memoization\n const handleConfirm = React.useCallback(async () => {\n setIsConfirming(true)\n setError(null)\n let newError = null\n\n const abortController = new AbortController()\n try {\n await onConfirm(abortController.signal)\n } catch (error) {\n newError = error as Error\n }\n\n if (isMounted.current && !abortController.signal.aborted) {\n setIsConfirming(false)\n setError(newError)\n }\n }, [isMounted, onConfirm])\n\n return (\n <React.Fragment>\n <Dialog\n open={isOpen}\n maxWidth=\"sm\"\n fullWidth\n onClose={!isConfirming ? onClose : undefined}\n data-cypress={cypress?.dialog}\n slotProps={{\n transition: {\n onExiting: () => setError(null),\n ...(TransitionProps ? TransitionProps : {}),\n },\n }}\n >\n <DialogTitle data-cypress={cypress?.title}>{title}</DialogTitle>\n <DialogContent dividers>{children}</DialogContent>\n <DialogActions>\n <Button\n disabled={isConfirming}\n onClick={onClose}\n data-cypress={cypress?.cancelButton}\n >\n Cancel\n </Button>\n\n <Button\n variant=\"contained\"\n loading={isConfirming}\n autoFocus\n startIcon={confirmButtonIcon}\n loadingPosition=\"start\"\n onClick={handleConfirm}\n data-cypress={cypress?.confirmButton}\n disabled={disabled}\n >\n {confirmButtonText}\n </Button>\n </DialogActions>\n </Dialog>\n <Portal>\n <ErrorSnackbar open={!!error} onClose={setError}>\n <span data-cypress={cypress?.error}>{error?.message}</span>\n </ErrorSnackbar>\n </Portal>\n </React.Fragment>\n )\n}\n"]}
@@ -9,9 +9,11 @@ import { formService } from '../apps';
9
9
  import { LookupNotificationContext } from '../hooks/useLookupNotification';
10
10
  import useElementAriaDescribedby from '../hooks/useElementAriaDescribedby';
11
11
  import FormElementValidationMessage from '../components/renderer/FormElementValidationMessage';
12
+ import useBooleanState from '../hooks/useBooleanState';
12
13
  function FormElementBSB({ id, formId, element, value, onChange, validationMessage, displayValidationMessage, isDirty, setIsDirty, autocompleteAttributes, }) {
13
14
  const ariaDescribedby = useElementAriaDescribedby(id, element);
14
15
  const [text, setText] = React.useState(typeof value === 'string' ? value : '');
16
+ const [hasFocus, setHasFocus, removeFocus] = useBooleanState(false);
15
17
  const isValidFormat = /\d{3}-\d{3}/.test(text);
16
18
  const [{ isLoading, errorMessage, bsbRecord }, setState] = React.useState({
17
19
  isLoading: false,
@@ -88,13 +90,15 @@ function FormElementBSB({ id, formId, element, value, onChange, validationMessag
88
90
  'no-addons-mobile': !hasCopyButton && !hasLookupButton,
89
91
  }), children: [_jsx("div", { className: clsx('control is-expanded', {
90
92
  'is-loading': isLoading,
91
- }), children: _jsx(InputMask, { mask: "xxx-xxx", replacement: { x: /\d/ }, showMask: true, type: "text", placeholder: element.placeholderValue, id: id, name: element.name, className: "input ob-input cypress-bsb-control", value: text, onChange: (e) => {
93
+ }), children: _jsx(InputMask, { mask: "xxx-xxx", replacement: { x: /\d/ }, showMask: hasFocus, type: "text", placeholder: element.placeholderValue, id: id, name: element.name, className: "input ob-input cypress-bsb-control", value: text, onChange: (e) => {
92
94
  setText(e.target.value);
93
- }, required: element.required, disabled: element.readOnly, onBlur: () => {
95
+ }, required: element.required, disabled: element.readOnly, onFocus: setHasFocus, onBlur: () => {
96
+ removeFocus();
94
97
  if (text === 'xxx-xxx') {
95
98
  onChange(element, {
96
99
  value: undefined,
97
100
  });
101
+ setText("");
98
102
  }
99
103
  setIsDirty();
100
104
  }, "aria-describedby": ariaDescribedby, autoComplete: autocompleteAttributes, "aria-required": element.required }) }), bsbRecord && (_jsx(BSBDisplay, { bsbRecord: bsbRecord, className: "ob-bsb__display-desktop" })), hasCopyButton && (_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 })] }), bsbRecord && (_jsx(BSBDisplay, { bsbRecord: bsbRecord, className: "ob-bsb__display-mobile" })), isDisplayingValidationMessage && (_jsx(FormElementValidationMessage, { message: errorMessage || validationMessage }))] }) }));
@@ -1 +1 @@
1
- {"version":3,"file":"FormElementBSB.js","sourceRoot":"","sources":["../../src/form-elements/FormElementBSB.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport { InputMask } from '@react-input/mask'\nimport clsx from 'clsx'\nimport CopyToClipboardButton from '../components/renderer/CopyToClipboardButton'\nimport LookupButton from '../components/renderer/LookupButton'\nimport { FormTypes, MiscTypes } from '@oneblink/types'\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport { FormElementValueChangeHandler, IsDirtyProps } from '../types/form'\nimport { formService } from '../apps'\nimport { LookupNotificationContext } from '../hooks/useLookupNotification'\nimport useElementAriaDescribedby from '../hooks/useElementAriaDescribedby'\nimport FormElementValidationMessage from '../components/renderer/FormElementValidationMessage'\n\ntype Props = {\n id: string\n formId: number\n element: FormTypes.BSBElement\n value: unknown\n onChange: FormElementValueChangeHandler<\n string | { isInvalid: boolean; isValidating: boolean }\n >\n displayValidationMessage: boolean\n validationMessage: string | undefined\n autocompleteAttributes?: string\n} & IsDirtyProps\n\nfunction FormElementBSB({\n id,\n formId,\n element,\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, setText] = React.useState(typeof value === 'string' ? value : '')\n const isValidFormat = /\\d{3}-\\d{3}/.test(text)\n\n const [{ isLoading, errorMessage, bsbRecord }, setState] = React.useState<{\n isLoading: boolean\n errorMessage: string | null\n bsbRecord: MiscTypes.BSBRecord | null\n }>({\n isLoading: false,\n errorMessage: null,\n bsbRecord: null,\n })\n\n React.useEffect(() => {\n if (bsbRecord) {\n onChange(element, {\n value: bsbRecord.bsb,\n })\n }\n }, [bsbRecord, element, onChange, value])\n\n React.useEffect(() => {\n if (text === '') {\n return\n }\n\n if (!isValidFormat) {\n setState({\n isLoading: false,\n errorMessage: null,\n bsbRecord: null,\n })\n return\n }\n\n setState({\n isLoading: true,\n errorMessage: null,\n bsbRecord: null,\n })\n\n const abortController = new AbortController()\n const getBSBRecord = async () => {\n onChange(element, {\n value: { isValidating: true, isInvalid: false },\n })\n try {\n const bsbRecord = await formService.getBSBRecord(\n formId,\n text,\n abortController.signal,\n )\n if (!abortController.signal.aborted) {\n setState({\n isLoading: false,\n errorMessage: null,\n bsbRecord,\n })\n }\n } catch (error) {\n console.warn('Error validating BSB number', error)\n if (!abortController.signal.aborted) {\n onChange(element, {\n value: { isInvalid: true, isValidating: false },\n })\n setState({\n isLoading: false,\n errorMessage: `The BSB number \"${text}\" does not exist`,\n bsbRecord: null,\n })\n }\n }\n }\n\n getBSBRecord()\n\n return () => {\n abortController.abort()\n }\n }, [formId, isValidFormat, text, onChange, element])\n\n const { isLookingUp } = React.useContext(LookupNotificationContext)\n const isDisplayingValidationMessage =\n (((isDirty || displayValidationMessage) &&\n !!validationMessage &&\n !isLoading) ||\n errorMessage) &&\n !isLookingUp\n\n const hasCopyButton = !!value && !!element.readOnly\n const hasLookupButton = element.isDataLookup || element.isElementLookup\n return (\n <div className=\"cypress-bsb-element\">\n <FormElementLabelContainer\n className=\"ob-bsb\"\n id={id}\n element={element}\n required={element.required}\n >\n <div\n className={clsx('field has-addons', {\n 'no-addons-mobile': !hasCopyButton && !hasLookupButton,\n })}\n >\n <div\n className={clsx('control is-expanded', {\n 'is-loading': isLoading,\n })}\n >\n <InputMask\n mask=\"xxx-xxx\"\n replacement={{ x: /\\d/ }}\n showMask\n type=\"text\"\n placeholder={element.placeholderValue}\n id={id}\n name={element.name}\n className=\"input ob-input cypress-bsb-control\"\n value={text}\n onChange={(e) => {\n setText(e.target.value)\n }}\n required={element.required}\n disabled={element.readOnly}\n onBlur={() => {\n if (text === 'xxx-xxx') {\n onChange(element, {\n value: undefined,\n })\n }\n setIsDirty()\n }}\n aria-describedby={ariaDescribedby}\n autoComplete={autocompleteAttributes}\n aria-required={element.required}\n />\n </div>\n {bsbRecord && (\n <BSBDisplay\n bsbRecord={bsbRecord}\n className=\"ob-bsb__display-desktop\"\n />\n )}\n {hasCopyButton && (\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 />\n </div>\n {bsbRecord && (\n <BSBDisplay\n bsbRecord={bsbRecord}\n className=\"ob-bsb__display-mobile\"\n />\n )}\n {isDisplayingValidationMessage && (\n <FormElementValidationMessage\n message={errorMessage || validationMessage}\n />\n )}\n </FormElementLabelContainer>\n </div>\n )\n}\n\nconst BSBDisplay = ({\n bsbRecord,\n className,\n}: {\n bsbRecord: MiscTypes.BSBRecord\n className: string\n}) => {\n return (\n <div className={`control ob-bsb__record-control ${className}`}>\n <a className=\"button is-static ob-bsb__record-button\">\n {bsbRecord.financialInstitutionMnemonic} - {bsbRecord.name}\n </a>\n </div>\n )\n}\nexport default React.memo(FormElementBSB)\n"]}
1
+ {"version":3,"file":"FormElementBSB.js","sourceRoot":"","sources":["../../src/form-elements/FormElementBSB.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport { InputMask } from '@react-input/mask'\nimport clsx from 'clsx'\nimport CopyToClipboardButton from '../components/renderer/CopyToClipboardButton'\nimport LookupButton from '../components/renderer/LookupButton'\nimport { FormTypes, MiscTypes } from '@oneblink/types'\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport { FormElementValueChangeHandler, IsDirtyProps } from '../types/form'\nimport { formService } from '../apps'\nimport { LookupNotificationContext } from '../hooks/useLookupNotification'\nimport useElementAriaDescribedby from '../hooks/useElementAriaDescribedby'\nimport FormElementValidationMessage from '../components/renderer/FormElementValidationMessage'\nimport useBooleanState from '../hooks/useBooleanState'\n\ntype Props = {\n id: string\n formId: number\n element: FormTypes.BSBElement\n value: unknown\n onChange: FormElementValueChangeHandler<\n string | { isInvalid: boolean; isValidating: boolean }\n >\n displayValidationMessage: boolean\n validationMessage: string | undefined\n autocompleteAttributes?: string\n} & IsDirtyProps\n\nfunction FormElementBSB({\n id,\n formId,\n element,\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, setText] = React.useState(typeof value === 'string' ? value : '')\n const [hasFocus, setHasFocus, removeFocus] = useBooleanState(false)\n const isValidFormat = /\\d{3}-\\d{3}/.test(text)\n\n const [{ isLoading, errorMessage, bsbRecord }, setState] = React.useState<{\n isLoading: boolean\n errorMessage: string | null\n bsbRecord: MiscTypes.BSBRecord | null\n }>({\n isLoading: false,\n errorMessage: null,\n bsbRecord: null,\n })\n\n React.useEffect(() => {\n if (bsbRecord) {\n onChange(element, {\n value: bsbRecord.bsb,\n })\n }\n }, [bsbRecord, element, onChange, value])\n\n React.useEffect(() => {\n if (text === '') {\n return\n }\n\n if (!isValidFormat) {\n setState({\n isLoading: false,\n errorMessage: null,\n bsbRecord: null,\n })\n return\n }\n\n setState({\n isLoading: true,\n errorMessage: null,\n bsbRecord: null,\n })\n\n const abortController = new AbortController()\n const getBSBRecord = async () => {\n onChange(element, {\n value: { isValidating: true, isInvalid: false },\n })\n try {\n const bsbRecord = await formService.getBSBRecord(\n formId,\n text,\n abortController.signal,\n )\n if (!abortController.signal.aborted) {\n setState({\n isLoading: false,\n errorMessage: null,\n bsbRecord,\n })\n }\n } catch (error) {\n console.warn('Error validating BSB number', error)\n if (!abortController.signal.aborted) {\n onChange(element, {\n value: { isInvalid: true, isValidating: false },\n })\n setState({\n isLoading: false,\n errorMessage: `The BSB number \"${text}\" does not exist`,\n bsbRecord: null,\n })\n }\n }\n }\n\n getBSBRecord()\n\n return () => {\n abortController.abort()\n }\n }, [formId, isValidFormat, text, onChange, element])\n\n const { isLookingUp } = React.useContext(LookupNotificationContext)\n const isDisplayingValidationMessage =\n (((isDirty || displayValidationMessage) &&\n !!validationMessage &&\n !isLoading) ||\n errorMessage) &&\n !isLookingUp\n\n const hasCopyButton = !!value && !!element.readOnly\n const hasLookupButton = element.isDataLookup || element.isElementLookup\n return (\n <div className=\"cypress-bsb-element\">\n <FormElementLabelContainer\n className=\"ob-bsb\"\n id={id}\n element={element}\n required={element.required}\n >\n <div\n className={clsx('field has-addons', {\n 'no-addons-mobile': !hasCopyButton && !hasLookupButton,\n })}\n >\n <div\n className={clsx('control is-expanded', {\n 'is-loading': isLoading,\n })}\n >\n <InputMask\n mask=\"xxx-xxx\"\n replacement={{ x: /\\d/ }}\n showMask={hasFocus}\n type=\"text\"\n placeholder={element.placeholderValue}\n id={id}\n name={element.name}\n className=\"input ob-input cypress-bsb-control\"\n value={text}\n onChange={(e) => {\n setText(e.target.value)\n }}\n required={element.required}\n disabled={element.readOnly}\n onFocus={setHasFocus}\n onBlur={() => {\n removeFocus()\n if (text === 'xxx-xxx') {\n onChange(element, {\n value: undefined,\n })\n setText(\"\")\n }\n setIsDirty()\n }}\n aria-describedby={ariaDescribedby}\n autoComplete={autocompleteAttributes}\n aria-required={element.required}\n />\n </div>\n {bsbRecord && (\n <BSBDisplay\n bsbRecord={bsbRecord}\n className=\"ob-bsb__display-desktop\"\n />\n )}\n {hasCopyButton && (\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 />\n </div>\n {bsbRecord && (\n <BSBDisplay\n bsbRecord={bsbRecord}\n className=\"ob-bsb__display-mobile\"\n />\n )}\n {isDisplayingValidationMessage && (\n <FormElementValidationMessage\n message={errorMessage || validationMessage}\n />\n )}\n </FormElementLabelContainer>\n </div>\n )\n}\n\nconst BSBDisplay = ({\n bsbRecord,\n className,\n}: {\n bsbRecord: MiscTypes.BSBRecord\n className: string\n}) => {\n return (\n <div className={`control ob-bsb__record-control ${className}`}>\n <a className=\"button is-static ob-bsb__record-button\">\n {bsbRecord.financialInstitutionMnemonic} - {bsbRecord.name}\n </a>\n </div>\n )\n}\nexport default React.memo(FormElementBSB)\n"]}
@@ -43,18 +43,19 @@ import useLoadDataEffect from './useLoadDataEffect';
43
43
  * @group Hooks
44
44
  */
45
45
  export default function useLoadDataState(onLoad) {
46
- const isMountedRef = useIsMounted();
47
- const isMounted = isMountedRef.current;
46
+ const isMounted = useIsMounted();
48
47
  const [state, setState] = React.useState({
49
48
  status: 'LOADING',
50
49
  });
51
- const handleLoad = React.useCallback(async (abortSignal) => {
50
+ const handleLoad = React.useCallback(
51
+ // eslint-disable-next-line react-hooks/preserve-manual-memoization
52
+ async (abortSignal) => {
52
53
  setState({
53
54
  status: 'LOADING',
54
55
  });
55
56
  try {
56
57
  const result = await onLoad(abortSignal);
57
- if (isMounted && !abortSignal.aborted) {
58
+ if (isMounted.current && !abortSignal.aborted) {
58
59
  setState({
59
60
  status: 'SUCCESS',
60
61
  result,
@@ -62,7 +63,7 @@ export default function useLoadDataState(onLoad) {
62
63
  }
63
64
  }
64
65
  catch (err) {
65
- if (isMounted && !abortSignal.aborted) {
66
+ if (isMounted.current && !abortSignal.aborted) {
66
67
  setState({
67
68
  status: 'ERROR',
68
69
  error: err,
@@ -1 +1 @@
1
- {"version":3,"file":"useLoadDataState.js","sourceRoot":"","sources":["../../src/hooks/useLoadDataState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,YAAY,MAAM,gBAAgB,CAAA;AACzC,OAAO,iBAAiB,MAAM,qBAAqB,CAAA;AAiBnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CACtC,MAAgD;IAMhD,MAAM,YAAY,GAAG,YAAY,EAAE,CAAA;IAEnC,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAA;IAEtC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAmB;QACzD,MAAM,EAAE,SAAS;KAClB,CAAC,CAAA;IAEF,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,CAClC,KAAK,EAAE,WAAwB,EAAE,EAAE;QACjC,QAAQ,CAAC;YACP,MAAM,EAAE,SAAS;SAClB,CAAC,CAAA;QACF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAA;YACxC,IAAI,SAAS,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;gBACtC,QAAQ,CAAC;oBACP,MAAM,EAAE,SAAS;oBACjB,MAAM;iBACP,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,SAAS,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;gBACtC,QAAQ,CAAC;oBACP,MAAM,EAAE,OAAO;oBACf,KAAK,EAAE,GAAY;iBACpB,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;IACH,CAAC,EACD,CAAC,SAAS,EAAE,MAAM,CAAC,CACpB,CAAA;IAED,MAAM,SAAS,GAA4C,KAAK,CAAC,WAAW,CAC1E,CAAC,MAAM,EAAE,EAAE;QACT,QAAQ,CAAC,CAAC,YAA8B,EAAE,EAAE;YAC1C,IAAI,YAAY,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBACtC,OAAO;oBACL,GAAG,YAAY;oBACf,MAAM,EACJ,OAAO,MAAM,KAAK,UAAU;wBAC1B,CAAC,CAAC,oFAAoF;4BACpF,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC;wBAC7B,CAAC,CAAC,MAAM;iBACb,CAAA;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,YAAY,CAAA;YACrB,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,EACD,EAAE,CACH,CAAA;IAED,MAAM,aAAa,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAA;IAEnD,OAAO,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,CAAC,CAAA;AAC1C,CAAC","sourcesContent":["import * as React from 'react'\nimport useIsMounted from './useIsMounted'\nimport useLoadDataEffect from './useLoadDataEffect'\n\nexport type LoadDataState<T> =\n | {\n status: 'SUCCESS'\n /** Your data. */\n result: T\n }\n | {\n status: 'ERROR'\n /** A JavaScript `Error` object. */\n error: Error\n }\n | {\n status: 'LOADING'\n }\n\n/**\n * This function is a react hook for managing the state involved with loading\n * data.\n *\n * ## Example\n *\n * ```js\n * import { useLoadDataState } from '@oneblink/apps-react'\n * const fetchData = async () => {\n * const response = await fetch(`https://some-website.com/api?data=data`)\n *\n * if (!response.ok) {\n * const text = await response.text()\n * throw new Error(text)\n * }\n *\n * return await response.json()\n * }\n *\n * const MyComponent = () => {\n * const [state, refresh, setResult] = useLoadDataState(fetchData)\n *\n * switch (state.status) {\n * case 'LOADING':\n * return <Loading />\n * case 'ERROR':\n * return <Error message={state.error} />\n * case 'SUCCESS':\n * // RENDER UI\n * }\n * }\n *\n * export default MyComponent\n * ```\n *\n * @typeParam T The type of the data returned by your `onLoad` function\n * @param onLoad The function that fetches your data. Should be a Promise that\n * returns your data\n * @returns\n * @group Hooks\n */\nexport default function useLoadDataState<T>(\n onLoad: (abortSignal: AbortSignal) => Promise<T>,\n): [\n state: LoadDataState<T>,\n handleRefresh: () => void,\n setResult: React.Dispatch<React.SetStateAction<T>>,\n] {\n const isMountedRef = useIsMounted()\n\n const isMounted = isMountedRef.current\n\n const [state, setState] = React.useState<LoadDataState<T>>({\n status: 'LOADING',\n })\n\n const handleLoad = React.useCallback(\n async (abortSignal: AbortSignal) => {\n setState({\n status: 'LOADING',\n })\n try {\n const result = await onLoad(abortSignal)\n if (isMounted && !abortSignal.aborted) {\n setState({\n status: 'SUCCESS',\n result,\n })\n }\n } catch (err) {\n if (isMounted && !abortSignal.aborted) {\n setState({\n status: 'ERROR',\n error: err as Error,\n })\n }\n }\n },\n [isMounted, onLoad],\n )\n\n const setResult: React.Dispatch<React.SetStateAction<T>> = React.useCallback(\n (setter) => {\n setState((currentState: LoadDataState<T>) => {\n if (currentState.status === 'SUCCESS') {\n return {\n ...currentState,\n result:\n typeof setter === 'function'\n ? // @ts-expect-error Typescript cannot tell between a generic type (T) and a function\n setter(currentState.result)\n : setter,\n }\n } else {\n return currentState\n }\n })\n },\n [],\n )\n\n const handleRefresh = useLoadDataEffect(handleLoad)\n\n return [state, handleRefresh, setResult]\n}\n"]}
1
+ {"version":3,"file":"useLoadDataState.js","sourceRoot":"","sources":["../../src/hooks/useLoadDataState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,YAAY,MAAM,gBAAgB,CAAA;AACzC,OAAO,iBAAiB,MAAM,qBAAqB,CAAA;AAiBnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CACtC,MAAgD;IAMhD,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAEhC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAmB;QACzD,MAAM,EAAE,SAAS;KAClB,CAAC,CAAA;IAEF,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW;IAClC,mEAAmE;IACnE,KAAK,EAAE,WAAwB,EAAE,EAAE;QACjC,QAAQ,CAAC;YACP,MAAM,EAAE,SAAS;SAClB,CAAC,CAAA;QACF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAA;YACxC,IAAI,SAAS,CAAC,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;gBAC9C,QAAQ,CAAC;oBACP,MAAM,EAAE,SAAS;oBACjB,MAAM;iBACP,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,SAAS,CAAC,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;gBAC9C,QAAQ,CAAC;oBACP,MAAM,EAAE,OAAO;oBACf,KAAK,EAAE,GAAY;iBACpB,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;IACH,CAAC,EACD,CAAC,SAAS,EAAE,MAAM,CAAC,CACpB,CAAA;IAED,MAAM,SAAS,GAA4C,KAAK,CAAC,WAAW,CAC1E,CAAC,MAAM,EAAE,EAAE;QACT,QAAQ,CAAC,CAAC,YAA8B,EAAE,EAAE;YAC1C,IAAI,YAAY,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBACtC,OAAO;oBACL,GAAG,YAAY;oBACf,MAAM,EACJ,OAAO,MAAM,KAAK,UAAU;wBAC1B,CAAC,CAAC,oFAAoF;4BACpF,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC;wBAC7B,CAAC,CAAC,MAAM;iBACb,CAAA;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,YAAY,CAAA;YACrB,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,EACD,EAAE,CACH,CAAA;IAED,MAAM,aAAa,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAA;IAEnD,OAAO,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,CAAC,CAAA;AAC1C,CAAC","sourcesContent":["import * as React from 'react'\nimport useIsMounted from './useIsMounted'\nimport useLoadDataEffect from './useLoadDataEffect'\n\nexport type LoadDataState<T> =\n | {\n status: 'SUCCESS'\n /** Your data. */\n result: T\n }\n | {\n status: 'ERROR'\n /** A JavaScript `Error` object. */\n error: Error\n }\n | {\n status: 'LOADING'\n }\n\n/**\n * This function is a react hook for managing the state involved with loading\n * data.\n *\n * ## Example\n *\n * ```js\n * import { useLoadDataState } from '@oneblink/apps-react'\n * const fetchData = async () => {\n * const response = await fetch(`https://some-website.com/api?data=data`)\n *\n * if (!response.ok) {\n * const text = await response.text()\n * throw new Error(text)\n * }\n *\n * return await response.json()\n * }\n *\n * const MyComponent = () => {\n * const [state, refresh, setResult] = useLoadDataState(fetchData)\n *\n * switch (state.status) {\n * case 'LOADING':\n * return <Loading />\n * case 'ERROR':\n * return <Error message={state.error} />\n * case 'SUCCESS':\n * // RENDER UI\n * }\n * }\n *\n * export default MyComponent\n * ```\n *\n * @typeParam T The type of the data returned by your `onLoad` function\n * @param onLoad The function that fetches your data. Should be a Promise that\n * returns your data\n * @returns\n * @group Hooks\n */\nexport default function useLoadDataState<T>(\n onLoad: (abortSignal: AbortSignal) => Promise<T>,\n): [\n state: LoadDataState<T>,\n handleRefresh: () => void,\n setResult: React.Dispatch<React.SetStateAction<T>>,\n] {\n const isMounted = useIsMounted()\n\n const [state, setState] = React.useState<LoadDataState<T>>({\n status: 'LOADING',\n })\n\n const handleLoad = React.useCallback(\n // eslint-disable-next-line react-hooks/preserve-manual-memoization\n async (abortSignal: AbortSignal) => {\n setState({\n status: 'LOADING',\n })\n try {\n const result = await onLoad(abortSignal)\n if (isMounted.current && !abortSignal.aborted) {\n setState({\n status: 'SUCCESS',\n result,\n })\n }\n } catch (err) {\n if (isMounted.current && !abortSignal.aborted) {\n setState({\n status: 'ERROR',\n error: err as Error,\n })\n }\n }\n },\n [isMounted, onLoad],\n )\n\n const setResult: React.Dispatch<React.SetStateAction<T>> = React.useCallback(\n (setter) => {\n setState((currentState: LoadDataState<T>) => {\n if (currentState.status === 'SUCCESS') {\n return {\n ...currentState,\n result:\n typeof setter === 'function'\n ? // @ts-expect-error Typescript cannot tell between a generic type (T) and a function\n setter(currentState.result)\n : setter,\n }\n } else {\n return currentState\n }\n })\n },\n [],\n )\n\n const handleRefresh = useLoadDataEffect(handleLoad)\n\n return [state, handleRefresh, setResult]\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@oneblink/apps-react",
3
3
  "description": "Helper functions for OneBlink apps in ReactJS.",
4
- "version": "9.0.0-beta.6",
4
+ "version": "9.0.0-beta.7",
5
5
  "author": "OneBlink <developers@oneblink.io> (https://oneblink.io)",
6
6
  "bugs": {
7
7
  "url": "https://github.com/oneblink/apps-react/issues"
@@ -59,7 +59,7 @@
59
59
  "@microsoft/eslint-plugin-sdl": "^1.1.0",
60
60
  "@mui/material": "^7.3.7",
61
61
  "@mui/x-date-pickers": "^8.24.0",
62
- "@oneblink/release-cli": "^3.4.0",
62
+ "@oneblink/release-cli": "^4.0.0-beta.2",
63
63
  "@oneblink/types": "github:oneblink/types",
64
64
  "@types/blueimp-load-image": "^5.16.6",
65
65
  "@types/color": "^3.0.6",