@lerx/promise-modal 0.7.0 → 0.8.1

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
  }>;
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,25 @@ 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);
814
+ const { getValue, increment } = lib.counterFactory(1);
820
815
  const Presenter = react.memo(({ modalId }) => {
821
816
  const ref = react.useRef(null);
817
+ const options = useConfigurationOptions();
822
818
  const { modal } = useModal(modalId);
823
819
  useSubscribeModal(modal);
824
- const handleChangeOrder = hook.useHandle(() => {
825
- if (ref.current) {
826
- ref.current.style.zIndex = `${increment()}`;
827
- }
828
- });
820
+ const handleChangeOrder = react.useCallback(() => {
821
+ if (ref.current === null)
822
+ return;
823
+ if (ref.current.style.zIndex === '' + options.zIndex + getValue())
824
+ return;
825
+ ref.current.style.zIndex = '' + options.zIndex + increment();
826
+ }, [options.zIndex]);
829
827
  return (jsxRuntime.jsxs("div", { ref: ref, className: presenter, children: [jsxRuntime.jsx(BackgroundFrame, { modalId: modalId, onChangeOrder: handleChangeOrder }), jsxRuntime.jsx(ForegroundFrame, { modalId: modalId, onChangeOrder: handleChangeOrder })] }));
830
828
  });
831
829
 
@@ -838,7 +836,7 @@ const style = `
838
836
  position: fixed;
839
837
  inset: 0;
840
838
  pointer-events: none;
841
- z-index: 1000;
839
+ z-index: var(--z-index);
842
840
  transition: background-color ease-in-out;
843
841
  }`;
844
842
  ModalManager.defineStyleSheet('anchor', style);
@@ -852,6 +850,7 @@ const AnchorInner = () => {
852
850
  const options = useConfigurationOptions();
853
851
  const dimmed = useActiveModalCount(validateDimmable, version);
854
852
  return (jsxRuntime.jsx("div", { className: anchor, style: {
853
+ '--z-index': options.zIndex,
855
854
  transitionDuration: options.duration,
856
855
  backgroundColor: dimmed ? options.backdrop : 'transparent',
857
856
  }, children: array.map(modalIds, (id) => (jsxRuntime.jsx(Presenter, { modalId: id }, id))) }));
@@ -862,42 +861,33 @@ const Anchor = react.memo(hoc.withErrorBoundary(AnchorInner));
862
861
  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
862
 
864
863
  const useInitialize = () => {
865
- const permitted = react.useRef(ModalManager.initialize());
866
- const anchorRef = react.useRef(null);
867
864
  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
- }, []);
865
+ const anchorRef = react.useRef(null);
866
+ const handleInitialize = react.useRef((root) => {
867
+ if (ModalManager.anchored)
868
+ return;
869
+ anchorRef.current = ModalManager.anchor({ root });
870
+ ModalManager.applyStyleSheet();
871
+ update();
872
+ });
873
+ const handleReset = react.useRef(() => ModalManager.reset());
885
874
  return {
886
875
  anchorRef,
887
- handleInitialize,
888
- handleReset,
876
+ handleInitialize: handleInitialize.current,
877
+ handleReset: handleReset.current,
889
878
  };
890
879
  };
891
880
 
892
- const BootstrapProvider = react.forwardRef(({ usePathname: useExternalPathname, ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, context, children, }, handleRef) => {
881
+ const BootstrapProvider = react.memo(react.forwardRef(({ usePathname: useExternalPathname, ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, context, children, }, handleRef) => {
893
882
  const usePathname$1 = react.useMemo(() => useExternalPathname || usePathname, [useExternalPathname]);
894
883
  const { anchorRef, handleInitialize, handleReset } = useInitialize();
895
884
  react.useImperativeHandle(handleRef, () => ({
896
885
  initialize: handleInitialize,
897
886
  }), [handleInitialize]);
898
887
  hook.useOnMount(() => {
899
- if (handleRef === null)
900
- handleInitialize();
888
+ if (handleRef !== null)
889
+ return;
890
+ handleInitialize();
901
891
  return () => {
902
892
  if (anchorRef.current)
903
893
  anchorRef.current.remove();
@@ -917,7 +907,7 @@ const BootstrapProvider = react.forwardRef(({ usePathname: useExternalPathname,
917
907
  context,
918
908
  anchor: anchorRef.current,
919
909
  })] }));
920
- });
910
+ }));
921
911
 
922
912
  const useBootstrap = ({ usePathname: useExternalPathname, ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, context, mode = 'auto', } = {}) => {
923
913
  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,25 @@ 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);
812
+ const { getValue, increment } = counterFactory(1);
818
813
  const Presenter = memo(({ modalId }) => {
819
814
  const ref = useRef(null);
815
+ const options = useConfigurationOptions();
820
816
  const { modal } = useModal(modalId);
821
817
  useSubscribeModal(modal);
822
- const handleChangeOrder = useHandle(() => {
823
- if (ref.current) {
824
- ref.current.style.zIndex = `${increment()}`;
825
- }
826
- });
818
+ const handleChangeOrder = useCallback(() => {
819
+ if (ref.current === null)
820
+ return;
821
+ if (ref.current.style.zIndex === '' + options.zIndex + getValue())
822
+ return;
823
+ ref.current.style.zIndex = '' + options.zIndex + increment();
824
+ }, [options.zIndex]);
827
825
  return (jsxs("div", { ref: ref, className: presenter, children: [jsx(BackgroundFrame, { modalId: modalId, onChangeOrder: handleChangeOrder }), jsx(ForegroundFrame, { modalId: modalId, onChangeOrder: handleChangeOrder })] }));
828
826
  });
829
827
 
@@ -836,7 +834,7 @@ const style = `
836
834
  position: fixed;
837
835
  inset: 0;
838
836
  pointer-events: none;
839
- z-index: 1000;
837
+ z-index: var(--z-index);
840
838
  transition: background-color ease-in-out;
841
839
  }`;
842
840
  ModalManager.defineStyleSheet('anchor', style);
@@ -850,6 +848,7 @@ const AnchorInner = () => {
850
848
  const options = useConfigurationOptions();
851
849
  const dimmed = useActiveModalCount(validateDimmable, version);
852
850
  return (jsx("div", { className: anchor, style: {
851
+ '--z-index': options.zIndex,
853
852
  transitionDuration: options.duration,
854
853
  backgroundColor: dimmed ? options.backdrop : 'transparent',
855
854
  }, children: map(modalIds, (id) => (jsx(Presenter, { modalId: id }, id))) }));
@@ -860,42 +859,33 @@ const Anchor = memo(withErrorBoundary(AnchorInner));
860
859
  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
860
 
862
861
  const useInitialize = () => {
863
- const permitted = useRef(ModalManager.initialize());
864
- const anchorRef = useRef(null);
865
862
  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
- }, []);
863
+ const anchorRef = useRef(null);
864
+ const handleInitialize = useRef((root) => {
865
+ if (ModalManager.anchored)
866
+ return;
867
+ anchorRef.current = ModalManager.anchor({ root });
868
+ ModalManager.applyStyleSheet();
869
+ update();
870
+ });
871
+ const handleReset = useRef(() => ModalManager.reset());
883
872
  return {
884
873
  anchorRef,
885
- handleInitialize,
886
- handleReset,
874
+ handleInitialize: handleInitialize.current,
875
+ handleReset: handleReset.current,
887
876
  };
888
877
  };
889
878
 
890
- const BootstrapProvider = forwardRef(({ usePathname: useExternalPathname, ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, context, children, }, handleRef) => {
879
+ const BootstrapProvider = memo(forwardRef(({ usePathname: useExternalPathname, ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, context, children, }, handleRef) => {
891
880
  const usePathname$1 = useMemo(() => useExternalPathname || usePathname, [useExternalPathname]);
892
881
  const { anchorRef, handleInitialize, handleReset } = useInitialize();
893
882
  useImperativeHandle(handleRef, () => ({
894
883
  initialize: handleInitialize,
895
884
  }), [handleInitialize]);
896
885
  useOnMount(() => {
897
- if (handleRef === null)
898
- handleInitialize();
886
+ if (handleRef !== null)
887
+ return;
888
+ handleInitialize();
899
889
  return () => {
900
890
  if (anchorRef.current)
901
891
  anchorRef.current.remove();
@@ -915,7 +905,7 @@ const BootstrapProvider = forwardRef(({ usePathname: useExternalPathname, Foregr
915
905
  context,
916
906
  anchor: anchorRef.current,
917
907
  })] }));
918
- });
908
+ }));
919
909
 
920
910
  const useBootstrap = ({ usePathname: useExternalPathname, ForegroundComponent, BackgroundComponent, TitleComponent, SubtitleComponent, ContentComponent, FooterComponent, options, context, mode = 'auto', } = {}) => {
921
911
  const usePathname$1 = useMemo(() => useExternalPathname || usePathname, [useExternalPathname]);
@@ -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 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lerx/promise-modal",
3
- "version": "0.7.0",
3
+ "version": "0.8.1",
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,9 +64,9 @@
64
64
  "version:patch": "yarn version patch"
65
65
  },
66
66
  "dependencies": {
67
- "@winglet/common-utils": "^0.7.0",
68
- "@winglet/react-utils": "^0.7.0",
69
- "@winglet/style-utils": "^0.7.0"
67
+ "@winglet/common-utils": "^0.8.1",
68
+ "@winglet/react-utils": "^0.8.0",
69
+ "@winglet/style-utils": "^0.8.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/react": "^19.0.0",