@lerx/promise-modal 0.8.0 → 0.8.2

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.
@@ -2,15 +2,14 @@ import type { Fn } from '../@aileron/declare';
2
2
  import type { Modal } from '../types';
3
3
  export declare class ModalManager {
4
4
  #private;
5
- static initialize(): boolean;
6
5
  static anchor(options?: {
7
6
  tag?: string;
8
7
  prefix?: string;
9
8
  root?: HTMLElement;
10
9
  }): HTMLElement;
10
+ static get anchored(): boolean;
11
11
  static get prerender(): Modal[];
12
12
  static set openHandler(handler: Fn<[Modal], void>);
13
- static get unanchored(): boolean;
14
13
  static defineStyleSheet(styleId: string, css: string): void;
15
14
  static applyStyleSheet(): void;
16
15
  static getHashedClassNames(styleId: string): string;
@@ -1,3 +1,4 @@
1
1
  import type { Color, Duration } from '../@aileron/declare';
2
+ export declare const DEFAULT_Z_INDEX: number;
2
3
  export declare const DEFAULT_ANIMATION_DURATION: Duration;
3
4
  export declare const DEFAULT_BACKDROP_COLOR: Color;
@@ -114,7 +114,7 @@ import type { BootstrapProviderHandle } from './type';
114
114
  * - All modals created within this provider share the same configuration
115
115
  * - The provider creates a portal for rendering modals outside the React tree
116
116
  */
117
- export declare const BootstrapProvider: import("react").ForwardRefExoticComponent<{
117
+ export declare const BootstrapProvider: import("react").NamedExoticComponent<{
118
118
  usePathname?: import("../../@aileron/declare").Fn<[], {
119
119
  pathname: string;
120
120
  }>;
@@ -1,2 +1,2 @@
1
- import type { ModalIdProps } from '../../types';
2
- export declare const Presenter: import("react").MemoExoticComponent<({ modalId }: ModalIdProps) => import("react/jsx-runtime").JSX.Element>;
1
+ import type { PresenterProps } from '../../types';
2
+ export declare const Presenter: import("react").MemoExoticComponent<({ modalId, getValue, increment }: PresenterProps) => import("react/jsx-runtime").JSX.Element>;
@@ -1,4 +1,5 @@
1
1
  import type { ComponentType, ReactNode } from 'react';
2
+ import type { Fn } from '../../@aileron/declare';
2
3
  import type { BackgroundComponent, FooterOptions, ForegroundComponent, ModalBackground, PromptContentProps, PromptFooterRender, PromptInputProps } from '../../types';
3
4
  interface PromptProps<InputValue, BackgroundValue = any> {
4
5
  group?: string;
@@ -6,8 +7,8 @@ interface PromptProps<InputValue, BackgroundValue = any> {
6
7
  subtitle?: ReactNode;
7
8
  content?: ReactNode | ComponentType<PromptContentProps>;
8
9
  defaultValue?: InputValue;
9
- Input: (props: PromptInputProps<InputValue>) => ReactNode;
10
- disabled?: (value: InputValue) => boolean;
10
+ Input: Fn<[props: PromptInputProps<InputValue>], ReactNode>;
11
+ disabled?: Fn<[value: InputValue], boolean>;
11
12
  returnOnCancel?: boolean;
12
13
  background?: ModalBackground<BackgroundValue>;
13
14
  footer?: PromptFooterRender<InputValue> | FooterOptions | false;
@@ -1,4 +1,5 @@
1
1
  import type { ComponentType, ReactNode } from 'react';
2
+ import type { Fn } from '../../../@aileron/declare';
2
3
  import type { FooterOptions, ManagedEntity, PromptContentProps, PromptFooterRender, PromptInputProps, PromptModal } from '../../../types';
3
4
  import { AbstractNode } from './AbstractNode';
4
5
  type PromptNodeProps<T, B> = PromptModal<T, B> & ManagedEntity;
@@ -7,8 +8,8 @@ export declare class PromptNode<T, B> extends AbstractNode<T, B> {
7
8
  readonly type: 'prompt';
8
9
  readonly content?: ReactNode | ComponentType<PromptContentProps>;
9
10
  readonly defaultValue: T | undefined;
10
- readonly Input: (props: PromptInputProps<T>) => ReactNode;
11
- readonly disabled?: (value: T) => boolean;
11
+ readonly Input: Fn<[props: PromptInputProps<T>], ReactNode>;
12
+ readonly disabled?: Fn<[value: T], boolean>;
12
13
  readonly returnOnCancel?: boolean;
13
14
  readonly footer?: PromptFooterRender<T> | FooterOptions | false;
14
15
  constructor({ id, group, initiator, type, title, subtitle, content, defaultValue, Input, disabled, returnOnCancel, footer, background, dimmed, manualDestroy, closeOnBackdropClick, resolve, ForegroundComponent, BackgroundComponent, }: PromptNodeProps<T, B>);
package/dist/index.cjs CHANGED
@@ -13,20 +13,13 @@ const array = require('@winglet/common-utils/array');
13
13
  const hoc = require('@winglet/react-utils/hoc');
14
14
  const filter = require('@winglet/common-utils/filter');
15
15
  const render = require('@winglet/react-utils/render');
16
- const console = require('@winglet/common-utils/console');
17
16
 
18
17
  class ModalManager {
19
- static #initialized = false;
20
- static initialize() {
21
- if (ModalManager.#initialized)
22
- return false;
23
- return (ModalManager.#initialized = true);
24
- }
25
18
  static #anchor = null;
26
19
  static #scope = `promise-modal-${lib.getRandomString(36)}`;
27
20
  static #hash = hash.polynomialHash(ModalManager.#scope);
28
21
  static anchor(options) {
29
- if (ModalManager.#anchor)
22
+ if (ModalManager.#anchor !== null)
30
23
  return ModalManager.#anchor;
31
24
  const { tag = 'div', prefix = 'promise-modal', root = document.body, } = options || {};
32
25
  const node = document.createElement(tag);
@@ -36,6 +29,9 @@ class ModalManager {
36
29
  ModalManager.#anchor = node;
37
30
  return node;
38
31
  }
32
+ static get anchored() {
33
+ return ModalManager.#anchor !== null;
34
+ }
39
35
  static #prerenderList = [];
40
36
  static get prerender() {
41
37
  return ModalManager.#prerenderList;
@@ -45,9 +41,6 @@ class ModalManager {
45
41
  ModalManager.#openHandler = handler;
46
42
  ModalManager.#prerenderList = [];
47
43
  }
48
- static get unanchored() {
49
- return !ModalManager.#anchor;
50
- }
51
44
  static #styleManager = styleManager.styleManagerFactory(ModalManager.#scope);
52
45
  static #styleSheetDefinition = new Map();
53
46
  static defineStyleSheet(styleId, css) {
@@ -61,7 +54,6 @@ class ModalManager {
61
54
  return `${styleId}-${ModalManager.#hash}`;
62
55
  }
63
56
  static reset() {
64
- ModalManager.#initialized = false;
65
57
  ModalManager.#anchor = null;
66
58
  ModalManager.#prerenderList = [];
67
59
  ModalManager.#openHandler = (modal) => ModalManager.#prerenderList.push(modal);
@@ -349,6 +341,7 @@ const nodeFactory = (modal) => {
349
341
  throw new Error(`Unknown modal: ${modal.type}`, { modal });
350
342
  };
351
343
 
344
+ const DEFAULT_Z_INDEX = 1000;
352
345
  const DEFAULT_ANIMATION_DURATION = '300ms';
353
346
  const DEFAULT_BACKDROP_COLOR = 'rgba(0, 0, 0, 0.5)';
354
347
 
@@ -420,6 +413,7 @@ const FallbackForegroundFrame = react.forwardRef(({ id, onChangeOrder, children
420
413
  const ConfigurationContext = react.createContext({});
421
414
 
422
415
  const DEFAULT_OPTIONS = {
416
+ zIndex: DEFAULT_Z_INDEX,
423
417
  duration: DEFAULT_ANIMATION_DURATION,
424
418
  backdrop: DEFAULT_BACKDROP_COLOR,
425
419
  closeOnBackdropClick: true,
@@ -811,21 +805,30 @@ const style$1 = `
811
805
  .${presenter} {
812
806
  position: fixed;
813
807
  inset: 0;
808
+ z-index: var(--z-index);
814
809
  pointer-events: none;
815
810
  overflow: hidden;
816
811
  `;
817
812
  ModalManager.defineStyleSheet('presenter', style$1);
818
813
 
819
- const { increment } = lib.counterFactory(1);
820
- const Presenter = react.memo(({ modalId }) => {
814
+ const Presenter = react.memo(({ modalId, getValue, increment }) => {
821
815
  const ref = react.useRef(null);
816
+ const options = useConfigurationOptions();
822
817
  const { modal } = useModal(modalId);
823
818
  useSubscribeModal(modal);
824
- const handleChangeOrder = hook.useHandle(() => {
825
- if (ref.current) {
826
- ref.current.style.zIndex = `${increment()}`;
827
- }
819
+ hook.useOnMountLayout(() => {
820
+ if (ref.current === null)
821
+ return;
822
+ ref.current.style.zIndex = '' + (options.zIndex + increment());
828
823
  });
824
+ const handleChangeOrder = react.useCallback(() => {
825
+ const element = ref.current;
826
+ if (element === null)
827
+ return;
828
+ if (element.style.zIndex === '' + (options.zIndex + getValue()))
829
+ return;
830
+ element.style.zIndex = '' + (options.zIndex + increment());
831
+ }, [getValue, increment, options.zIndex]);
829
832
  return (jsxRuntime.jsxs("div", { ref: ref, className: presenter, children: [jsxRuntime.jsx(BackgroundFrame, { modalId: modalId, onChangeOrder: handleChangeOrder }), jsxRuntime.jsx(ForegroundFrame, { modalId: modalId, onChangeOrder: handleChangeOrder })] }));
830
833
  });
831
834
 
@@ -838,11 +841,12 @@ const style = `
838
841
  position: fixed;
839
842
  inset: 0;
840
843
  pointer-events: none;
841
- z-index: 1000;
844
+ z-index: var(--z-index);
842
845
  transition: background-color ease-in-out;
843
846
  }`;
844
847
  ModalManager.defineStyleSheet('anchor', style);
845
848
 
849
+ const { getValue, increment, reset } = lib.counterFactory(0);
846
850
  const AnchorInner = () => {
847
851
  const [version, update] = hook.useVersion();
848
852
  const { modalIds, setUpdater } = useModalManagerContext();
@@ -851,10 +855,13 @@ const AnchorInner = () => {
851
855
  }, [setUpdater, update]);
852
856
  const options = useConfigurationOptions();
853
857
  const dimmed = useActiveModalCount(validateDimmable, version);
858
+ if (!dimmed)
859
+ reset();
854
860
  return (jsxRuntime.jsx("div", { className: anchor, style: {
861
+ '--z-index': options.zIndex,
855
862
  transitionDuration: options.duration,
856
863
  backgroundColor: dimmed ? options.backdrop : 'transparent',
857
- }, children: array.map(modalIds, (id) => (jsxRuntime.jsx(Presenter, { modalId: id }, id))) }));
864
+ }, children: array.map(modalIds, (id) => (jsxRuntime.jsx(Presenter, { modalId: id, getValue: getValue, increment: increment, reset: reset }, id))) }));
858
865
  };
859
866
  const validateDimmable = (modal) => modal?.visible && modal.dimmed;
860
867
  const Anchor = react.memo(hoc.withErrorBoundary(AnchorInner));
@@ -862,42 +869,33 @@ const Anchor = react.memo(hoc.withErrorBoundary(AnchorInner));
862
869
  const bootstrap = ({ ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, usePathname, options, context, anchor, }) => reactDom.createPortal(jsxRuntime.jsx(UserDefinedContextProvider, { context: context, children: jsxRuntime.jsx(ConfigurationContextProvider, { ForegroundComponent: ForegroundComponent, BackgroundComponent: BackgroundComponent, TitleComponent: TitleComponent, SubtitleComponent: SubtitleComponent, ContentComponent: ContentComponent, FooterComponent: FooterComponent, options: options, children: jsxRuntime.jsx(ModalManagerContextProvider, { usePathname: usePathname, children: jsxRuntime.jsx(Anchor, {}) }) }) }), anchor);
863
870
 
864
871
  const useInitialize = () => {
865
- const permitted = react.useRef(ModalManager.initialize());
866
- const anchorRef = react.useRef(null);
867
872
  const [, update] = hook.useVersion();
868
- const handleInitialize = react.useCallback((root) => {
869
- if (permitted.current) {
870
- anchorRef.current = ModalManager.anchor({ root });
871
- ModalManager.applyStyleSheet();
872
- update();
873
- }
874
- else
875
- console.printError('ModalProvider is already initialized', [
876
- 'ModalProvider can only be initialized once.',
877
- 'Nesting ModalProvider will be ignored...',
878
- ], {
879
- info: 'Something is wrong with the ModalProvider initialization...',
880
- });
881
- }, [update]);
882
- const handleReset = react.useCallback(() => {
883
- ModalManager.reset();
884
- }, []);
873
+ const anchorRef = react.useRef(null);
874
+ const handleInitialize = react.useRef((root) => {
875
+ if (ModalManager.anchored)
876
+ return;
877
+ anchorRef.current = ModalManager.anchor({ root });
878
+ ModalManager.applyStyleSheet();
879
+ update();
880
+ });
881
+ const handleReset = react.useRef(() => ModalManager.reset());
885
882
  return {
886
883
  anchorRef,
887
- handleInitialize,
888
- handleReset,
884
+ handleInitialize: handleInitialize.current,
885
+ handleReset: handleReset.current,
889
886
  };
890
887
  };
891
888
 
892
- const BootstrapProvider = react.forwardRef(({ usePathname: useExternalPathname, ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, context, children, }, handleRef) => {
889
+ const BootstrapProvider = react.memo(react.forwardRef(({ usePathname: useExternalPathname, ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, context, children, }, handleRef) => {
893
890
  const usePathname$1 = react.useMemo(() => useExternalPathname || usePathname, [useExternalPathname]);
894
891
  const { anchorRef, handleInitialize, handleReset } = useInitialize();
895
892
  react.useImperativeHandle(handleRef, () => ({
896
893
  initialize: handleInitialize,
897
894
  }), [handleInitialize]);
898
895
  hook.useOnMount(() => {
899
- if (handleRef === null)
900
- handleInitialize();
896
+ if (handleRef !== null)
897
+ return;
898
+ handleInitialize();
901
899
  return () => {
902
900
  if (anchorRef.current)
903
901
  anchorRef.current.remove();
@@ -917,7 +915,7 @@ const BootstrapProvider = react.forwardRef(({ usePathname: useExternalPathname,
917
915
  context,
918
916
  anchor: anchorRef.current,
919
917
  })] }));
920
- });
918
+ }));
921
919
 
922
920
  const useBootstrap = ({ usePathname: useExternalPathname, ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, context, mode = 'auto', } = {}) => {
923
921
  const usePathname$1 = react.useMemo(() => useExternalPathname || usePathname, [useExternalPathname]);
package/dist/index.mjs CHANGED
@@ -11,20 +11,13 @@ import { map } from '@winglet/common-utils/array';
11
11
  import { withErrorBoundary } from '@winglet/react-utils/hoc';
12
12
  import { isString, isFunction } from '@winglet/common-utils/filter';
13
13
  import { renderComponent } from '@winglet/react-utils/render';
14
- import { printError } from '@winglet/common-utils/console';
15
14
 
16
15
  class ModalManager {
17
- static #initialized = false;
18
- static initialize() {
19
- if (ModalManager.#initialized)
20
- return false;
21
- return (ModalManager.#initialized = true);
22
- }
23
16
  static #anchor = null;
24
17
  static #scope = `promise-modal-${getRandomString(36)}`;
25
18
  static #hash = polynomialHash(ModalManager.#scope);
26
19
  static anchor(options) {
27
- if (ModalManager.#anchor)
20
+ if (ModalManager.#anchor !== null)
28
21
  return ModalManager.#anchor;
29
22
  const { tag = 'div', prefix = 'promise-modal', root = document.body, } = options || {};
30
23
  const node = document.createElement(tag);
@@ -34,6 +27,9 @@ class ModalManager {
34
27
  ModalManager.#anchor = node;
35
28
  return node;
36
29
  }
30
+ static get anchored() {
31
+ return ModalManager.#anchor !== null;
32
+ }
37
33
  static #prerenderList = [];
38
34
  static get prerender() {
39
35
  return ModalManager.#prerenderList;
@@ -43,9 +39,6 @@ class ModalManager {
43
39
  ModalManager.#openHandler = handler;
44
40
  ModalManager.#prerenderList = [];
45
41
  }
46
- static get unanchored() {
47
- return !ModalManager.#anchor;
48
- }
49
42
  static #styleManager = styleManagerFactory(ModalManager.#scope);
50
43
  static #styleSheetDefinition = new Map();
51
44
  static defineStyleSheet(styleId, css) {
@@ -59,7 +52,6 @@ class ModalManager {
59
52
  return `${styleId}-${ModalManager.#hash}`;
60
53
  }
61
54
  static reset() {
62
- ModalManager.#initialized = false;
63
55
  ModalManager.#anchor = null;
64
56
  ModalManager.#prerenderList = [];
65
57
  ModalManager.#openHandler = (modal) => ModalManager.#prerenderList.push(modal);
@@ -347,6 +339,7 @@ const nodeFactory = (modal) => {
347
339
  throw new Error(`Unknown modal: ${modal.type}`, { modal });
348
340
  };
349
341
 
342
+ const DEFAULT_Z_INDEX = 1000;
350
343
  const DEFAULT_ANIMATION_DURATION = '300ms';
351
344
  const DEFAULT_BACKDROP_COLOR = 'rgba(0, 0, 0, 0.5)';
352
345
 
@@ -418,6 +411,7 @@ const FallbackForegroundFrame = forwardRef(({ id, onChangeOrder, children }, ref
418
411
  const ConfigurationContext = createContext({});
419
412
 
420
413
  const DEFAULT_OPTIONS = {
414
+ zIndex: DEFAULT_Z_INDEX,
421
415
  duration: DEFAULT_ANIMATION_DURATION,
422
416
  backdrop: DEFAULT_BACKDROP_COLOR,
423
417
  closeOnBackdropClick: true,
@@ -809,21 +803,30 @@ const style$1 = `
809
803
  .${presenter} {
810
804
  position: fixed;
811
805
  inset: 0;
806
+ z-index: var(--z-index);
812
807
  pointer-events: none;
813
808
  overflow: hidden;
814
809
  `;
815
810
  ModalManager.defineStyleSheet('presenter', style$1);
816
811
 
817
- const { increment } = counterFactory(1);
818
- const Presenter = memo(({ modalId }) => {
812
+ const Presenter = memo(({ modalId, getValue, increment }) => {
819
813
  const ref = useRef(null);
814
+ const options = useConfigurationOptions();
820
815
  const { modal } = useModal(modalId);
821
816
  useSubscribeModal(modal);
822
- const handleChangeOrder = useHandle(() => {
823
- if (ref.current) {
824
- ref.current.style.zIndex = `${increment()}`;
825
- }
817
+ useOnMountLayout(() => {
818
+ if (ref.current === null)
819
+ return;
820
+ ref.current.style.zIndex = '' + (options.zIndex + increment());
826
821
  });
822
+ const handleChangeOrder = useCallback(() => {
823
+ const element = ref.current;
824
+ if (element === null)
825
+ return;
826
+ if (element.style.zIndex === '' + (options.zIndex + getValue()))
827
+ return;
828
+ element.style.zIndex = '' + (options.zIndex + increment());
829
+ }, [getValue, increment, options.zIndex]);
827
830
  return (jsxs("div", { ref: ref, className: presenter, children: [jsx(BackgroundFrame, { modalId: modalId, onChangeOrder: handleChangeOrder }), jsx(ForegroundFrame, { modalId: modalId, onChangeOrder: handleChangeOrder })] }));
828
831
  });
829
832
 
@@ -836,11 +839,12 @@ const style = `
836
839
  position: fixed;
837
840
  inset: 0;
838
841
  pointer-events: none;
839
- z-index: 1000;
842
+ z-index: var(--z-index);
840
843
  transition: background-color ease-in-out;
841
844
  }`;
842
845
  ModalManager.defineStyleSheet('anchor', style);
843
846
 
847
+ const { getValue, increment, reset } = counterFactory(0);
844
848
  const AnchorInner = () => {
845
849
  const [version, update] = useVersion();
846
850
  const { modalIds, setUpdater } = useModalManagerContext();
@@ -849,10 +853,13 @@ const AnchorInner = () => {
849
853
  }, [setUpdater, update]);
850
854
  const options = useConfigurationOptions();
851
855
  const dimmed = useActiveModalCount(validateDimmable, version);
856
+ if (!dimmed)
857
+ reset();
852
858
  return (jsx("div", { className: anchor, style: {
859
+ '--z-index': options.zIndex,
853
860
  transitionDuration: options.duration,
854
861
  backgroundColor: dimmed ? options.backdrop : 'transparent',
855
- }, children: map(modalIds, (id) => (jsx(Presenter, { modalId: id }, id))) }));
862
+ }, children: map(modalIds, (id) => (jsx(Presenter, { modalId: id, getValue: getValue, increment: increment, reset: reset }, id))) }));
856
863
  };
857
864
  const validateDimmable = (modal) => modal?.visible && modal.dimmed;
858
865
  const Anchor = memo(withErrorBoundary(AnchorInner));
@@ -860,42 +867,33 @@ const Anchor = memo(withErrorBoundary(AnchorInner));
860
867
  const bootstrap = ({ ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, usePathname, options, context, anchor, }) => createPortal(jsx(UserDefinedContextProvider, { context: context, children: jsx(ConfigurationContextProvider, { ForegroundComponent: ForegroundComponent, BackgroundComponent: BackgroundComponent, TitleComponent: TitleComponent, SubtitleComponent: SubtitleComponent, ContentComponent: ContentComponent, FooterComponent: FooterComponent, options: options, children: jsx(ModalManagerContextProvider, { usePathname: usePathname, children: jsx(Anchor, {}) }) }) }), anchor);
861
868
 
862
869
  const useInitialize = () => {
863
- const permitted = useRef(ModalManager.initialize());
864
- const anchorRef = useRef(null);
865
870
  const [, update] = useVersion();
866
- const handleInitialize = useCallback((root) => {
867
- if (permitted.current) {
868
- anchorRef.current = ModalManager.anchor({ root });
869
- ModalManager.applyStyleSheet();
870
- update();
871
- }
872
- else
873
- printError('ModalProvider is already initialized', [
874
- 'ModalProvider can only be initialized once.',
875
- 'Nesting ModalProvider will be ignored...',
876
- ], {
877
- info: 'Something is wrong with the ModalProvider initialization...',
878
- });
879
- }, [update]);
880
- const handleReset = useCallback(() => {
881
- ModalManager.reset();
882
- }, []);
871
+ const anchorRef = useRef(null);
872
+ const handleInitialize = useRef((root) => {
873
+ if (ModalManager.anchored)
874
+ return;
875
+ anchorRef.current = ModalManager.anchor({ root });
876
+ ModalManager.applyStyleSheet();
877
+ update();
878
+ });
879
+ const handleReset = useRef(() => ModalManager.reset());
883
880
  return {
884
881
  anchorRef,
885
- handleInitialize,
886
- handleReset,
882
+ handleInitialize: handleInitialize.current,
883
+ handleReset: handleReset.current,
887
884
  };
888
885
  };
889
886
 
890
- const BootstrapProvider = forwardRef(({ usePathname: useExternalPathname, ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, context, children, }, handleRef) => {
887
+ const BootstrapProvider = memo(forwardRef(({ usePathname: useExternalPathname, ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, context, children, }, handleRef) => {
891
888
  const usePathname$1 = useMemo(() => useExternalPathname || usePathname, [useExternalPathname]);
892
889
  const { anchorRef, handleInitialize, handleReset } = useInitialize();
893
890
  useImperativeHandle(handleRef, () => ({
894
891
  initialize: handleInitialize,
895
892
  }), [handleInitialize]);
896
893
  useOnMount(() => {
897
- if (handleRef === null)
898
- handleInitialize();
894
+ if (handleRef !== null)
895
+ return;
896
+ handleInitialize();
899
897
  return () => {
900
898
  if (anchorRef.current)
901
899
  anchorRef.current.remove();
@@ -915,7 +913,7 @@ const BootstrapProvider = forwardRef(({ usePathname: useExternalPathname, Foregr
915
913
  context,
916
914
  anchor: anchorRef.current,
917
915
  })] }));
918
- });
916
+ }));
919
917
 
920
918
  const useBootstrap = ({ usePathname: useExternalPathname, ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, context, mode = 'auto', } = {}) => {
921
919
  const usePathname$1 = useMemo(() => useExternalPathname || usePathname, [useExternalPathname]);
@@ -1,10 +1,12 @@
1
1
  import type { ComponentType, ReactNode } from 'react';
2
- import type { Dictionary } from '../@aileron/declare';
2
+ import type { Dictionary, Fn } from '../@aileron/declare';
3
3
  import type { BaseModal, ContentComponentProps, FooterOptions } from './base';
4
- export type AlertFooterRender<Context extends Dictionary = object> = (props: {
5
- onConfirm: VoidFunction;
6
- context: Context;
7
- }) => ReactNode;
4
+ export type AlertFooterRender<Context extends Dictionary = object> = Fn<[
5
+ props: {
6
+ onConfirm: Fn;
7
+ context: Context;
8
+ }
9
+ ], ReactNode>;
8
10
  export type AlertContentProps<Context extends Dictionary = object> = Pick<ContentComponentProps<Context>, 'onConfirm'>;
9
11
  export interface AlertModal<B = any, Context extends Dictionary = object> extends BaseModal<void, B> {
10
12
  type: 'alert';
@@ -1,5 +1,5 @@
1
1
  import type { ComponentType, PropsWithChildren, ReactNode } from 'react';
2
- import type { Dictionary } from '../@aileron/declare';
2
+ import type { Dictionary, Fn } from '../@aileron/declare';
3
3
  import type { ModalBackground } from './background';
4
4
  import type { ModalFrameProps } from './modal';
5
5
  export interface BaseModal<T, B> {
@@ -10,15 +10,15 @@ export interface BaseModal<T, B> {
10
10
  dimmed?: boolean;
11
11
  manualDestroy?: boolean;
12
12
  closeOnBackdropClick?: boolean;
13
- resolve: (result: T | null) => void;
13
+ resolve: Fn<[result: T | null]>;
14
14
  ForegroundComponent?: ForegroundComponent;
15
15
  BackgroundComponent?: BackgroundComponent;
16
16
  }
17
17
  export type ForegroundComponent = ComponentType<PropsWithChildren<ModalFrameProps>>;
18
18
  export type BackgroundComponent = ComponentType<ModalFrameProps>;
19
19
  export interface ContentComponentProps<Context extends Dictionary = object> {
20
- onConfirm: VoidFunction;
21
- onCancel: VoidFunction;
20
+ onConfirm: Fn;
21
+ onCancel: Fn;
22
22
  context: Context;
23
23
  }
24
24
  export type WrapperComponentProps<Context extends Dictionary = object> = PropsWithChildren<{
@@ -36,7 +36,7 @@ export type FooterComponentProps<Context extends Dictionary = object> = {
36
36
  cancelLabel?: ReactNode;
37
37
  hideCancel?: boolean;
38
38
  disabled?: boolean;
39
- onConfirm: VoidFunction;
40
- onCancel?: VoidFunction;
39
+ onConfirm: Fn;
40
+ onCancel?: Fn;
41
41
  context: Context;
42
42
  };
@@ -1,11 +1,13 @@
1
1
  import type { ComponentType, ReactNode } from 'react';
2
- import type { Dictionary } from '../@aileron/declare';
2
+ import type { Dictionary, Fn } from '../@aileron/declare';
3
3
  import type { BaseModal, ContentComponentProps, FooterOptions } from './base';
4
- export type ConfirmFooterRender<Context extends Dictionary = object> = (props: {
5
- onConfirm: VoidFunction;
6
- onCancel: VoidFunction;
7
- context: Context;
8
- }) => ReactNode;
4
+ export type ConfirmFooterRender<Context extends Dictionary = object> = Fn<[
5
+ props: {
6
+ onConfirm: Fn;
7
+ onCancel: Fn;
8
+ context: Context;
9
+ }
10
+ ], ReactNode>;
9
11
  export type ConfirmContentProps<Context extends Dictionary = object> = ContentComponentProps<Context>;
10
12
  export interface ConfirmModal<B = any, Context extends Dictionary = object> extends BaseModal<boolean, B> {
11
13
  type: 'confirm';
@@ -19,29 +19,35 @@ export type ModalFrameProps<Context extends Dictionary = object, B = any> = {
19
19
  manualDestroy: boolean;
20
20
  closeOnBackdropClick: boolean;
21
21
  background?: ModalBackground<B>;
22
- onConfirm: () => void;
23
- onClose: () => void;
24
- onChange: (value: any) => void;
25
- onDestroy: () => void;
22
+ onConfirm: Fn;
23
+ onClose: Fn;
24
+ onChange: Fn<[value: any]>;
25
+ onDestroy: Fn;
26
26
  onChangeOrder: Fn;
27
27
  context: Context;
28
28
  };
29
- export interface ModalIdProps {
29
+ interface ModalIdProps {
30
30
  modalId: ModalNode['id'];
31
31
  }
32
+ export interface PresenterProps extends ModalIdProps {
33
+ getValue: Fn<[], number>;
34
+ increment: Fn<[], number>;
35
+ reset: Fn<[], number>;
36
+ }
32
37
  export interface ModalLayerProps extends ModalIdProps {
33
38
  onChangeOrder: Fn;
34
39
  }
35
40
  export interface ModalHandlersWithId {
36
- onConfirm: (modalId: ModalNode['id']) => void;
37
- onClose: (modalId: ModalNode['id']) => void;
38
- onChange: (modalId: ModalNode['id'], value: any) => void;
39
- onDestroy: (modalId: ModalNode['id']) => void;
41
+ onConfirm: Fn<[modalId: ModalNode['id']]>;
42
+ onClose: Fn<[modalId: ModalNode['id']]>;
43
+ onChange: Fn<[modalId: ModalNode['id'], value: any]>;
44
+ onDestroy: Fn<[modalId: ModalNode['id']]>;
40
45
  }
41
46
  export type ModalActions = {
42
47
  modal: ModalNode | undefined;
43
- onConfirm: () => void;
44
- onClose: () => void;
45
- onChange: (value: any) => void;
46
- onDestroy: () => void;
48
+ onConfirm: Fn;
49
+ onClose: Fn;
50
+ onChange: Fn<[value: any]>;
51
+ onDestroy: Fn;
47
52
  };
53
+ export {};
@@ -1,5 +1,7 @@
1
1
  import type { Color, Duration } from '../@aileron/declare';
2
2
  export interface ModalOptions {
3
+ /** Modal z-index */
4
+ zIndex?: number;
3
5
  /** Modal transition time(ms, s) */
4
6
  duration?: Duration;
5
7
  /** Modal backdrop color */
@@ -1,20 +1,22 @@
1
1
  import type { ComponentType, ReactNode } from 'react';
2
- import type { Dictionary, SetStateFn } from '../@aileron/declare';
2
+ import type { Dictionary, Fn, SetStateFn } from '../@aileron/declare';
3
3
  import type { BaseModal, ContentComponentProps, FooterOptions } from './base';
4
- export type PromptFooterRender<T, Context extends Dictionary = object> = (props: {
5
- value: T | undefined;
6
- onChange: SetStateFn<T | undefined>;
7
- onConfirm: VoidFunction;
8
- onCancel: VoidFunction;
9
- disabled: boolean;
10
- context: Context;
11
- }) => ReactNode;
4
+ export type PromptFooterRender<T, Context extends Dictionary = object> = Fn<[
5
+ props: {
6
+ value: T | undefined;
7
+ onChange: SetStateFn<T | undefined>;
8
+ onConfirm: Fn;
9
+ onCancel: Fn;
10
+ disabled: boolean;
11
+ context: Context;
12
+ }
13
+ ], ReactNode>;
12
14
  export interface PromptInputProps<T, Context extends Dictionary = object> {
13
15
  value?: T;
14
16
  defaultValue?: T;
15
17
  onChange: SetStateFn<T | undefined>;
16
- onConfirm: VoidFunction;
17
- onCancel: VoidFunction;
18
+ onConfirm: Fn;
19
+ onCancel: Fn;
18
20
  context: Context;
19
21
  }
20
22
  export type PromptContentProps<Context extends Dictionary = object> = ContentComponentProps<Context>;
@@ -22,8 +24,8 @@ export interface PromptModal<T = any, B = any, Context extends Dictionary = obje
22
24
  type: 'prompt';
23
25
  content?: ReactNode | ComponentType<PromptContentProps<Context>>;
24
26
  defaultValue?: T;
25
- Input: (props: PromptInputProps<T, Context>) => ReactNode;
26
- disabled?: (value: T | undefined) => boolean;
27
+ Input: Fn<[props: PromptInputProps<T, Context>], ReactNode>;
28
+ disabled?: Fn<[value: T | undefined], boolean>;
27
29
  returnOnCancel?: boolean;
28
30
  footer?: PromptFooterRender<T, Context> | FooterOptions | false;
29
31
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lerx/promise-modal",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "Universal React modal utility that can be used outside React components with promise-based results for alert, confirm, and prompt modals",
5
5
  "keywords": [
6
6
  "react",
@@ -64,7 +64,7 @@
64
64
  "version:patch": "yarn version patch"
65
65
  },
66
66
  "dependencies": {
67
- "@winglet/common-utils": "^0.8.0",
67
+ "@winglet/common-utils": "^0.8.1",
68
68
  "@winglet/react-utils": "^0.8.0",
69
69
  "@winglet/style-utils": "^0.8.0"
70
70
  },