@kne/react-modal 0.1.11 → 0.1.12

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.
@@ -1,5 +1,5 @@
1
- import { useEffect, useRef, useState, useCallback, memo, forwardRef, useImperativeHandle, createRef, Children } from 'react';
2
- import { Modal as Modal$1, App, Button, Drawer as Drawer$1, Tabs } from 'antd';
1
+ import { useEffect, useState, useCallback, createContext, useContext, useMemo, useRef, createRef, forwardRef, useImperativeHandle, memo, Children } from 'react';
2
+ import { Modal as Modal$1, Button, Drawer as Drawer$1, App, Tabs } from 'antd';
3
3
  import { CloseOutlined, InfoCircleFilled, ExclamationCircleFilled, CloseCircleFilled, CheckCircleFilled } from '@ant-design/icons';
4
4
  import classnames from 'classnames';
5
5
  import { usePopupMount, useScrollElement, hoistOutOfModalRoot } from '@kne/responsive-utils';
@@ -51,7 +51,7 @@ const withLocale = createWithIntlProvider({
51
51
 
52
52
  var modalStyle = {"kne-responsive-boundary":"kne-react-modal_gh14z","kne-responsive-scroll":"kne-react-modal_Kfn6L","modal":"kne-react-modal_Bk7-B","small":"kne-react-modal_DZGD6","large":"kne-react-modal_9sz-n","modal-body-inner":"kne-react-modal_fFnva","is-mobile":"kne-react-modal_LtgJz","modal-container":"kne-react-modal_aEoZq","modal-antd-header":"kne-react-modal_54n8W","modal-antd-footer":"kne-react-modal_AJ9pV","modal-antd-body":"kne-react-modal_u2IjN","modal-outer":"kne-react-modal_kkILR","no-title":"kne-react-modal_8Iysr","no-footer":"kne-react-modal_VMxik","no-padding":"kne-react-modal_Fof-N","modal-title":"kne-react-modal_tG9MF","modal-body":"kne-react-modal_W-QFz","modal-footer":"kne-react-modal_meVfy","body-scroll-off":"kne-react-modal_l627I","is-embedded-footer":"kne-react-modal_17Eih","modal-footer-extra":"kne-react-modal_Fx8Z-","modal-footer-actions":"kne-react-modal_V3ZrX","modal-close":"kne-react-modal_-EK8N","modal-host":"kne-react-modal_eNb-h","modal-form-host":"kne-react-modal_Js8cf","modal-wrap":"kne-react-modal_3Sju5","modal-wrap-centered":"kne-react-modal_-qCIk","modal-wrap-fullscreen":"kne-react-modal_8lS2G","modal-mask-fullscreen":"kne-react-modal_XfLOC"};
53
53
 
54
- const _excluded$7 = ["ButtonComponent", "onClick", "autoClose", "display"];
54
+ const _excluded$8 = ["ButtonComponent", "onClick", "autoClose", "display"];
55
55
  const Footer = ({
56
56
  footer,
57
57
  footerButtons,
@@ -90,7 +90,7 @@ const Footer = ({
90
90
  onClick,
91
91
  autoClose = true
92
92
  } = _ref,
93
- props = _objectWithoutPropertiesLoose(_ref, _excluded$7);
93
+ props = _objectWithoutPropertiesLoose(_ref, _excluded$8);
94
94
  return _extends({}, props, {
95
95
  buttonComponent: ButtonComponent,
96
96
  onClick: async (...args) => {
@@ -173,11 +173,52 @@ const useLockParentScroll = (enabled, getScrollElement) => {
173
173
  }, [enabled, getScrollElement]);
174
174
  };
175
175
 
176
- const _excluded$6 = ["children", "footer", "footerButtons", "className", "size", "title", "onClose", "onConfirm", "confirmText", "onCancel", "cancelText", "closable", "noPadding", "bodyScroll", "isMobile", "mobileFullscreen", "fixedModeClass", "wrapClassName", "classNames", "styles", "style", "modalRender"],
177
- _excluded2$3 = ["width"],
178
- _excluded3$1 = ["size", "getContainer", "open", "mobileFullscreen", "bodyScroll"],
179
- _excluded4 = ["afterClose", "getContainer", "onClose", "onConfirm", "onCancel"],
180
- _excluded5 = ["children", "getContainer", "afterClose"];
176
+ const usePatchElement = () => {
177
+ const [elements, setElements] = useState([]);
178
+ const patchElement = useCallback(element => {
179
+ setElements(originElements => [...originElements, element]);
180
+ return () => {
181
+ setElements(originElements => originElements.filter(ele => ele !== element));
182
+ };
183
+ }, []);
184
+ return [elements, patchElement];
185
+ };
186
+
187
+ const ModalLayerContext = /*#__PURE__*/createContext(null);
188
+ const useModalLayer = () => useContext(ModalLayerContext);
189
+
190
+ /**
191
+ * 挂在 Modal 内容树内(antd ZIndexContext 之下),
192
+ * 使就近 useModal 打开的内层成为本层 React 子树,从而自动叠层。
193
+ */
194
+ const ModalLayerProvider = ({
195
+ children
196
+ }) => {
197
+ const [elements, patchElement] = usePatchElement();
198
+ const value = useMemo(() => ({
199
+ patchElement
200
+ }), [patchElement]);
201
+ return /*#__PURE__*/jsxs(ModalLayerContext.Provider, {
202
+ value: value,
203
+ children: [children, elements]
204
+ });
205
+ };
206
+
207
+ /** 根级命令式打开(页面首次弹层);不包 ModalLayerContext。 */
208
+ const rootModalPatchRef = {
209
+ current: null
210
+ };
211
+ const ModalContextHolder = () => {
212
+ const [elements, patchElement] = usePatchElement();
213
+ rootModalPatchRef.current = patchElement;
214
+ return /*#__PURE__*/jsx(Fragment, {
215
+ children: elements
216
+ });
217
+ };
218
+
219
+ const _excluded$7 = ["children", "footer", "footerButtons", "className", "size", "title", "onClose", "onConfirm", "confirmText", "onCancel", "cancelText", "closable", "noPadding", "bodyScroll", "isMobile", "mobileFullscreen", "fixedModeClass", "wrapClassName", "classNames", "styles", "style", "modalRender"],
220
+ _excluded2$4 = ["width"],
221
+ _excluded3$1 = ["size", "getContainer", "open", "mobileFullscreen", "bodyScroll"];
181
222
  const ModalLocaleRoot = withLocale(({
182
223
  children
183
224
  }) => children);
@@ -223,6 +264,7 @@ const resolveModalGetContainer = ({
223
264
  };
224
265
  };
225
266
  const sizeStyleVars$1 = (size, hasFooter) => {
267
+ // body 最低高度随 size:small 基准 300,default/large 基准 500(再扣 title/footer chrome)
226
268
  const minBase = size === 'small' ? 300 : 500;
227
269
  const chrome = 48 + (hasFooter ? 58 : 0);
228
270
  const minHeight = `${Math.max(0, minBase - chrome)}px`;
@@ -268,11 +310,15 @@ const ModalOuter = ({
268
310
  });
269
311
  const bodyClassName = classnames(modalStyle['modal-body'], 'modal-body');
270
312
  // 移动端全屏:body 用 flex 吃满 title/footer 之间剩余高度,footer 才能贴底;
271
- // 勿写死 --kne-modal-body-height(高度受限类会把该值压矮,footer 悬在中间)
313
+ // 桌面默认:height:auto + max-height,短内容不撑满;bodyScroll=false 仍写死满高供 Tabs/分栏
272
314
  const bodyStyle = isMobile ? {
273
315
  flex: '1 1 auto',
274
316
  minHeight: 0,
275
317
  height: 'auto'
318
+ } : bodyScroll !== false ? {
319
+ height: 'auto',
320
+ maxHeight: 'var(--kne-modal-body-max-height)',
321
+ minHeight: 'var(--kne-modal-body-min-height)'
276
322
  } : {
277
323
  height: 'var(--kne-modal-body-height)'
278
324
  };
@@ -302,10 +348,7 @@ const ModalOuter = ({
302
348
  children: bodyInner
303
349
  }) : /*#__PURE__*/jsx("div", {
304
350
  className: classnames(bodyClassName, modalStyle['body-scroll-off']),
305
- style: isMobile ? {
306
- flex: '1 1 auto',
307
- minHeight: 0
308
- } : undefined,
351
+ style: bodyStyle,
309
352
  children: bodyInner
310
353
  }), footer === null && footerButtons === undefined ? null : /*#__PURE__*/jsx(Footer, {
311
354
  footer: footer,
@@ -346,14 +389,14 @@ const computedCommonProps = _ref => {
346
389
  style: propsStyle,
347
390
  modalRender
348
391
  } = _ref,
349
- props = _objectWithoutPropertiesLoose(_ref, _excluded$6);
392
+ props = _objectWithoutPropertiesLoose(_ref, _excluded$7);
350
393
  const useMobileLayout = isMobile && mobileFullscreen !== false;
351
394
  const hasFooter = !(footer === null && footerButtons === undefined);
352
395
  const sizeVars = sizeStyleVars$1(size, hasFooter);
353
396
  const {
354
397
  width
355
398
  } = sizeVars,
356
- cssVars = _objectWithoutPropertiesLoose(sizeVars, _excluded2$3);
399
+ cssVars = _objectWithoutPropertiesLoose(sizeVars, _excluded2$4);
357
400
  const runChildren = options => {
358
401
  const opts = Object.assign({}, options, {
359
402
  close: onClose
@@ -428,8 +471,11 @@ const computedCommonProps = _ref => {
428
471
  overflow: 'hidden'
429
472
  } : null)
430
473
  }),
474
+ // LayerProvider 须在 antd Modal 内容树内(ZIndexContext 下),内层命令式才能自动 +100
431
475
  children: /*#__PURE__*/jsx(ModalLocaleRoot, {
432
- children: runChildren({})
476
+ children: /*#__PURE__*/jsx(ModalLayerProvider, {
477
+ children: runChildren({})
478
+ })
433
479
  })
434
480
  });
435
481
  };
@@ -480,77 +526,119 @@ const Modal = withLocale(_ref2 => {
480
526
  }))]
481
527
  });
482
528
  });
483
- const useModal = () => {
484
- const {
485
- modal
486
- } = App.useApp();
529
+
530
+ const _excluded$6 = ["afterClose", "onClose", "onConfirm", "onCancel"],
531
+ _excluded2$3 = ["afterClose"];
532
+ let hookModalUuid = 0;
533
+ const HookModal = /*#__PURE__*/forwardRef(({
534
+ config,
535
+ afterClose: hookAfterClose
536
+ }, ref) => {
537
+ const [open, setOpen] = useState(true);
538
+ const [innerConfig, setInnerConfig] = useState(config);
539
+ const close = () => {
540
+ setOpen(false);
541
+ };
542
+ useImperativeHandle(ref, () => ({
543
+ destroy: close,
544
+ update: newConfig => {
545
+ setInnerConfig(origin => Object.assign({}, origin, typeof newConfig === 'function' ? newConfig(origin) : newConfig));
546
+ }
547
+ }));
487
548
  const {
488
- resolveMount,
489
- getPopupContainer
490
- } = usePopupMount(viewportPopupMountOptions$3);
549
+ afterClose: userAfterClose,
550
+ onClose: userOnClose,
551
+ onConfirm: userOnConfirm,
552
+ onCancel: userOnCancel
553
+ } = innerConfig,
554
+ restConfig = _objectWithoutPropertiesLoose(innerConfig, _excluded$6);
555
+ return /*#__PURE__*/jsx(Modal, _extends({}, restConfig, {
556
+ open: open,
557
+ onClose: () => {
558
+ userOnClose == null || userOnClose();
559
+ close();
560
+ },
561
+ onCancel: (...args) => {
562
+ userOnCancel == null || userOnCancel(...args);
563
+ close();
564
+ },
565
+ onConfirm: async (...args) => {
566
+ const res = await Promise.resolve(userOnConfirm == null ? void 0 : userOnConfirm(...args));
567
+ if (res !== false) {
568
+ close();
569
+ }
570
+ return res;
571
+ },
572
+ afterClose: (...args) => {
573
+ hookAfterClose == null || hookAfterClose(...args);
574
+ userAfterClose == null || userAfterClose(...args);
575
+ }
576
+ }));
577
+ });
578
+
579
+ /**
580
+ * 命令式内容弹窗:就近 patch 到 ModalLayerProvider(多层)或根 ModalContextHolder。
581
+ * 不走 App.modal.info / ConfirmDialog,层级交给 antd ZIndexContext。
582
+ */
583
+ const useModal = () => {
584
+ const layer = useContext(ModalLayerContext);
491
585
  const getScrollElement = useScrollElement();
492
- return props => {
493
- const anchor = typeof document !== 'undefined' ? document.activeElement : null;
494
- const {
495
- isMobile,
496
- fixedModeClass
497
- } = resolveMount(anchor);
498
- const unlock = lockParentScroll(getScrollElement);
586
+ const [actionQueue, setActionQueue] = useState([]);
587
+ useEffect(() => {
588
+ if (actionQueue.length) {
589
+ const cloneQueue = [...actionQueue];
590
+ cloneQueue.forEach(action => action());
591
+ setActionQueue([]);
592
+ }
593
+ }, [actionQueue]);
594
+ return useCallback(props => {
595
+ hookModalUuid += 1;
596
+ const modalRef = /*#__PURE__*/createRef();
499
597
  const api = {};
500
- const {
501
- afterClose: userAfterClose,
502
- getContainer: customGetContainer,
503
- onClose: userOnClose,
504
- onConfirm: userOnConfirm,
505
- onCancel: userOnCancel
506
- } = props,
507
- restProps = _objectWithoutPropertiesLoose(props, _excluded4);
508
- const closeModal = () => {
509
- api.close == null || api.close();
510
- };
511
- const _computedCommonProps = computedCommonProps(_extends({}, restProps, {
512
- isMobile,
513
- fixedModeClass,
514
- onClose: () => {
515
- userOnClose == null || userOnClose();
516
- closeModal();
517
- },
518
- onCancel: (...args) => {
519
- userOnCancel == null || userOnCancel(...args);
520
- closeModal();
521
- },
522
- onConfirm: async (...args) => {
523
- const res = await Promise.resolve(userOnConfirm == null ? void 0 : userOnConfirm(...args));
524
- if (res !== false) {
525
- closeModal();
598
+ let closeFunc;
599
+ let unlock = () => {};
600
+ const resolvePatch = () => (layer == null ? void 0 : layer.patchElement) || rootModalPatchRef.current;
601
+ const runOpen = () => {
602
+ const patch = resolvePatch();
603
+ if (typeof patch !== 'function') {
604
+ throw new Error('useModal requires <ModalContextHolder /> mounted inside <App> before calling useModal()');
605
+ }
606
+ unlock = lockParentScroll(getScrollElement);
607
+ const {
608
+ afterClose: userAfterClose
609
+ } = props,
610
+ restProps = _objectWithoutPropertiesLoose(props, _excluded2$3);
611
+ const modalEl = /*#__PURE__*/jsx(HookModal, {
612
+ ref: modalRef,
613
+ config: _extends({}, restProps, {
614
+ afterClose: (...args) => {
615
+ unlock();
616
+ userAfterClose == null || userAfterClose(...args);
526
617
  }
527
- return res;
528
- },
529
- afterClose: (...args) => {
530
- unlock();
531
- userAfterClose == null || userAfterClose(...args);
618
+ }),
619
+ afterClose: () => {
620
+ closeFunc && closeFunc();
532
621
  }
533
- })),
534
- {
535
- children,
536
- getContainer,
537
- afterClose
538
- } = _computedCommonProps,
539
- otherProps = _objectWithoutPropertiesLoose(_computedCommonProps, _excluded5);
540
- const {
541
- destroy
542
- } = modal.info(_extends({}, otherProps, {
543
- afterClose,
544
- content: children,
545
- getContainer: resolveModalGetContainer({
546
- customGetContainer: customGetContainer != null ? customGetContainer : getContainer,
547
- getPopupContainer,
548
- getHostNode: () => anchor
549
- })
550
- }));
551
- api.close = destroy;
622
+ }, `react-modal-${hookModalUuid}`);
623
+ closeFunc = patch(modalEl);
624
+ };
625
+ if (resolvePatch()) {
626
+ runOpen();
627
+ } else {
628
+ setActionQueue(prev => [...prev, runOpen]);
629
+ }
630
+ api.close = () => {
631
+ if (modalRef.current) {
632
+ modalRef.current.destroy();
633
+ } else {
634
+ setActionQueue(prev => [...prev, () => {
635
+ var _modalRef$current;
636
+ return (_modalRef$current = modalRef.current) == null ? void 0 : _modalRef$current.destroy();
637
+ }]);
638
+ }
639
+ };
552
640
  return api;
553
- };
641
+ }, [getScrollElement, layer]);
554
642
  };
555
643
 
556
644
  var style = {"kne-responsive-boundary":"kne-react-modal_qwqLr","kne-responsive-scroll":"kne-react-modal_vmry7","drawer":"kne-react-modal_cDsbq","small":"kne-react-modal_3QgK-","is-mobile":"kne-react-modal_FFf73","large":"kne-react-modal_8lell","drawer-body-inner":"kne-react-modal_xgX4D","drawer-antd-header":"kne-react-modal_3EUxr","drawer-antd-footer":"kne-react-modal_2G81L","drawer-antd-body":"kne-react-modal_eKVMu","drawer-outer":"kne-react-modal_P3Cw8","no-title":"kne-react-modal_upRot","no-footer":"kne-react-modal_j4sGu","no-padding":"kne-react-modal_pg37M","drawer-title":"kne-react-modal_-hw5V","drawer-body":"kne-react-modal_nJj7Y","body-scroll-off":"kne-react-modal_2Wh1H","modal-footer-extra":"kne-react-modal_M4hy9","drawer-close":"kne-react-modal_dVh38","drawer-host":"kne-react-modal_Nsxi9","drawer-host-render":"kne-react-modal_iGDWP","drawer-panel-host":"kne-react-modal_A0h-2","drawer-panel-body":"kne-react-modal_E4tcc","drawer-form-host":"kne-react-modal_vKkQW","drawer-wrapper-mobile":"kne-react-modal_vsxOs","drawer-wrapper-mobile-vertical":"kne-react-modal_HG8Vz","drawer-root-mobile":"kne-react-modal_G-qXe"};
@@ -884,17 +972,6 @@ const Drawer = withLocale(_ref2 => {
884
972
  });
885
973
  });
886
974
 
887
- const usePatchElement = () => {
888
- const [elements, setElements] = useState([]);
889
- const patchElement = useCallback(element => {
890
- setElements(originElements => [...originElements, element]);
891
- return () => {
892
- setElements(originElements => originElements.filter(ele => ele !== element));
893
- };
894
- }, []);
895
- return [elements, patchElement];
896
- };
897
-
898
975
  const _excluded$4 = ["getContainer", "afterClose"],
899
976
  _excluded2$1 = ["afterClose", "getContainer"];
900
977
  const VIEWPORT_EXAMPLE_SELECTORS$1 = ['.example-driver-device-scroll'];
@@ -1212,41 +1289,46 @@ const mapConfirmProps = (props, {
1212
1289
  icon,
1213
1290
  isMobile
1214
1291
  });
1292
+
1293
+ // Confirm 走 antd ConfirmDialog:未传 zIndex 时用 static 顶层,适合真确认框盖住内容弹窗
1294
+ const config = _extends({}, otherProps, {
1295
+ okText: confirmText != null ? confirmText : otherProps.okText,
1296
+ cancelText: cancelText != null ? cancelText : otherProps.cancelText,
1297
+ onOk: onConfirm != null ? onConfirm : otherProps.onOk,
1298
+ onCancel: onCancel != null ? onCancel : otherProps.onCancel,
1299
+ getContainer: resolveModalGetContainer({
1300
+ customGetContainer,
1301
+ getPopupContainer,
1302
+ getHostNode: () => anchor
1303
+ }),
1304
+ centered: true,
1305
+ afterClose: (...args) => {
1306
+ unlock();
1307
+ userAfterClose && userAfterClose(...args);
1308
+ afterClose && afterClose(...args);
1309
+ },
1310
+ icon: null,
1311
+ classNames: {
1312
+ mask: classnames(isMobile && modalStyle['modal-mask-fullscreen'], isMobile && fixedModeClass, (_otherProps$className = otherProps.classNames) == null ? void 0 : _otherProps$className.mask)
1313
+ },
1314
+ wrapClassName: classnames(modalStyle['modal-wrap'], modalStyle['modal-wrap-centered'], confirmStyle['confirm-modal-wrap'], wrapClassName, {
1315
+ [confirmStyle['is-danger']]: danger,
1316
+ [confirmStyle['is-mobile']]: isMobile,
1317
+ [fixedModeClass]: isMobile
1318
+ }),
1319
+ title: confirmTitle ? /*#__PURE__*/jsx(ConfirmLocaleRoot, {
1320
+ children: confirmTitle
1321
+ }) : null,
1322
+ content: /*#__PURE__*/jsx(ConfirmLocaleRoot, {
1323
+ children: content
1324
+ })
1325
+ });
1326
+ if (zIndex !== undefined) {
1327
+ config.zIndex = zIndex;
1328
+ }
1215
1329
  return {
1216
1330
  modalMethod: type,
1217
- config: _extends({}, otherProps, {
1218
- zIndex: zIndex != null ? zIndex : 1100,
1219
- okText: confirmText != null ? confirmText : otherProps.okText,
1220
- cancelText: cancelText != null ? cancelText : otherProps.cancelText,
1221
- onOk: onConfirm != null ? onConfirm : otherProps.onOk,
1222
- onCancel: onCancel != null ? onCancel : otherProps.onCancel,
1223
- getContainer: resolveModalGetContainer({
1224
- customGetContainer,
1225
- getPopupContainer,
1226
- getHostNode: () => anchor
1227
- }),
1228
- centered: true,
1229
- afterClose: (...args) => {
1230
- unlock();
1231
- userAfterClose && userAfterClose(...args);
1232
- afterClose && afterClose(...args);
1233
- },
1234
- icon: null,
1235
- classNames: {
1236
- mask: classnames(isMobile && modalStyle['modal-mask-fullscreen'], isMobile && fixedModeClass, (_otherProps$className = otherProps.classNames) == null ? void 0 : _otherProps$className.mask)
1237
- },
1238
- wrapClassName: classnames(modalStyle['modal-wrap'], modalStyle['modal-wrap-centered'], confirmStyle['confirm-modal-wrap'], wrapClassName, {
1239
- [confirmStyle['is-danger']]: danger,
1240
- [confirmStyle['is-mobile']]: isMobile,
1241
- [fixedModeClass]: isMobile
1242
- }),
1243
- title: confirmTitle ? /*#__PURE__*/jsx(ConfirmLocaleRoot, {
1244
- children: confirmTitle
1245
- }) : null,
1246
- content: /*#__PURE__*/jsx(ConfirmLocaleRoot, {
1247
- children: content
1248
- })
1249
- })
1331
+ config
1250
1332
  };
1251
1333
  };
1252
1334
  const useConfirmModal = () => {
@@ -1369,5 +1451,5 @@ const modalClassNames = {
1369
1451
  splitter: 'react-modal-splitter'
1370
1452
  };
1371
1453
 
1372
- export { ColumnsLayout, Drawer, DrawerContextHolder, ScrollRegion, TabsLayout, createDrawerRender, createModalRender, Modal as default, modalClassNames, useConfirmModal, useDrawer, useModal };
1454
+ export { ColumnsLayout, Drawer, DrawerContextHolder, ModalContextHolder, ModalLayerContext, ScrollRegion, TabsLayout, createDrawerRender, createModalRender, Modal as default, modalClassNames, useConfirmModal, useDrawer, useModal, useModalLayer };
1373
1455
  //# sourceMappingURL=index.modern.js.map