@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.
package/README.md CHANGED
@@ -22,7 +22,7 @@ npm i --save @kne/react-modal
22
22
 
23
23
  #### 主要特性
24
24
 
25
- - 声明式 / 命令式同一套 props 与 UI(Modal `useModal`;Drawer `useDrawer` + `DrawerContextHolder`;确认框 `useConfirmModal`)
25
+ - 声明式 / 命令式同一套 props 与 UI(Modal `useModal` + `ModalContextHolder`,多层就近 LayerHolder;Drawer `useDrawer` + `DrawerContextHolder`;确认框 `useConfirmModal`)
26
26
  - `footer` + `footerButtons`(`ButtonComponent` / `display` / `autoClose`)
27
27
  - title / footer 固定在滚动外,body 默认 SimpleBar
28
28
  - `--kne-modal-*` / `--kne-drawer-*` CSS 变量管理高度链
@@ -254,7 +254,7 @@ npm i --save @kne/react-modal
254
254
  - _ReactModal(@kne/current-lib_react-modal)[import * as _ReactModal from "@kne/react-modal"],(@kne/current-lib_react-modal/dist/index.css),antd(antd)
255
255
 
256
256
  ```jsx
257
- const { default: Modal, Drawer, DrawerContextHolder } = _ReactModal;
257
+ const { default: Modal, Drawer, DrawerContextHolder, ModalContextHolder } = _ReactModal;
258
258
  const { Button, Space, message, Typography, Radio, App } = antd;
259
259
  const { useState, useEffect } = React;
260
260
 
@@ -311,9 +311,7 @@ const BasicExample = () => {
311
311
  <Button type="primary" onClick={() => setOpen(true)}>
312
312
  保存评估备注
313
313
  </Button>
314
- <Text type="secondary">
315
- 最简受控弹层:切换 Modal / Drawer 对比同一套 props;异步 onConfirm 带 loading。
316
- </Text>
314
+ <Text type="secondary">最简受控弹层:切换 Modal / Drawer 对比同一套 props;异步 onConfirm 带 loading。</Text>
317
315
  {isDrawer ? (
318
316
  <Drawer {...overlayProps} size="default">
319
317
  {content}
@@ -327,6 +325,7 @@ const BasicExample = () => {
327
325
 
328
326
  render(
329
327
  <App>
328
+ <ModalContextHolder />
330
329
  <DrawerContextHolder />
331
330
  <BasicExample />
332
331
  </App>
@@ -339,7 +338,7 @@ render(
339
338
  - _ReactModal(@kne/current-lib_react-modal)[import * as _ReactModal from "@kne/react-modal"],(@kne/current-lib_react-modal/dist/index.css),antd(antd)
340
339
 
341
340
  ```jsx
342
- const { default: Modal, Drawer, DrawerContextHolder } = _ReactModal;
341
+ const { default: Modal, Drawer, DrawerContextHolder, ModalContextHolder } = _ReactModal;
343
342
  const { Button, Space, Radio, Tag, message, Typography, App } = antd;
344
343
  const { useState, useEffect } = React;
345
344
 
@@ -399,14 +398,8 @@ const FooterButtonsExample = () => {
399
398
  </Space>
400
399
  </div>
401
400
  <div className="demo-job-preview-body">
402
- <Paragraph style={{ marginTop: 0 }}>
403
- 负责招聘中台、候选人评估等 B 端产品的前端交付;要求熟悉 React、工程化与组件库协作。
404
- </Paragraph>
405
- <Paragraph style={{ marginBottom: 0 }}>
406
- {noPadding
407
- ? 'noPadding=true:预览卡片应贴齐内容区边缘。'
408
- : 'noPadding=false:预览卡片四周保留默认内边距。'}
409
- </Paragraph>
401
+ <Paragraph style={{ marginTop: 0 }}>负责招聘中台、候选人评估等 B 端产品的前端交付;要求熟悉 React、工程化与组件库协作。</Paragraph>
402
+ <Paragraph style={{ marginBottom: 0 }}>{noPadding ? 'noPadding=true:预览卡片应贴齐内容区边缘。' : 'noPadding=false:预览卡片四周保留默认内边距。'}</Paragraph>
410
403
  </div>
411
404
  </div>
412
405
  );
@@ -447,17 +440,14 @@ const FooterButtonsExample = () => {
447
440
  noPadding={String(noPadding)}
448
441
  </Button>
449
442
  </Space>
450
- {isDrawer ? (
451
- <Drawer {...overlayProps}>{content}</Drawer>
452
- ) : (
453
- <Modal {...overlayProps}>{content}</Modal>
454
- )}
443
+ {isDrawer ? <Drawer {...overlayProps}>{content}</Drawer> : <Modal {...overlayProps}>{content}</Modal>}
455
444
  </Space>
456
445
  );
457
446
  };
458
447
 
459
448
  render(
460
449
  <App>
450
+ <ModalContextHolder />
461
451
  <DrawerContextHolder />
462
452
  <FooterButtonsExample />
463
453
  </App>
@@ -470,7 +460,7 @@ render(
470
460
  - _ReactModal(@kne/current-lib_react-modal)[import * as _ReactModal from "@kne/react-modal"],(@kne/current-lib_react-modal/dist/index.css),antd(antd)
471
461
 
472
462
  ```jsx
473
- const { useModal, useDrawer, DrawerContextHolder } = _ReactModal;
463
+ const { useModal, useDrawer, DrawerContextHolder, ModalContextHolder } = _ReactModal;
474
464
  const { Button, Space, message, Descriptions, Tag, Typography, Radio, App } = antd;
475
465
  const { useState } = React;
476
466
 
@@ -499,8 +489,7 @@ const CommandExample = () => {
499
489
  </Descriptions.Item>
500
490
  </Descriptions>
501
491
  <Paragraph type="secondary" style={{ marginBottom: 12 }}>
502
- 命令式 {isDrawer ? 'Drawer' : 'Modal'} 适用于列表页「快速查看」;children 为函数时可调用{' '}
503
- <Text code>close()</Text> 主动关闭。
492
+ 命令式 {isDrawer ? 'Drawer' : 'Modal'} 适用于列表页「快速查看」;children 为函数时可调用 <Text code>close()</Text> 主动关闭。
504
493
  </Paragraph>
505
494
  <Button size="small" onClick={() => close()}>
506
495
  关闭
@@ -531,15 +520,14 @@ const CommandExample = () => {
531
520
  <Button type="primary" onClick={openDetail}>
532
521
  从列表打开候选人快览
533
522
  </Button>
534
- <Text type="secondary">
535
- Drawer 模式需挂载 DrawerContextHolder;Modal 使用 antd App 内置 useModal。
536
- </Text>
523
+ <Text type="secondary">须挂载 ModalContextHolder(内容弹窗 useModal)与 DrawerContextHolder(useDrawer);确认框仍用 useConfirmModal。</Text>
537
524
  </Space>
538
525
  );
539
526
  };
540
527
 
541
528
  render(
542
529
  <App>
530
+ <ModalContextHolder />
543
531
  <DrawerContextHolder />
544
532
  <CommandExample />
545
533
  </App>
@@ -657,7 +645,7 @@ render(<BaseExample />);
657
645
  - _ReactModal(@kne/current-lib_react-modal)[import * as _ReactModal from "@kne/react-modal"],(@kne/current-lib_react-modal/dist/index.css),antd(antd)
658
646
 
659
647
  ```jsx
660
- const { default: Modal, Drawer, DrawerContextHolder } = _ReactModal;
648
+ const { default: Modal, Drawer, DrawerContextHolder, ModalContextHolder } = _ReactModal;
661
649
  const { Button, Space, Typography, Divider, Radio, App } = antd;
662
650
  const { useState, useEffect } = React;
663
651
 
@@ -666,24 +654,15 @@ const { Title, Paragraph, Text } = Typography;
666
654
  const EVAL_SECTIONS = [
667
655
  {
668
656
  title: '沟通表达',
669
- items: [
670
- '表达结构清晰,能准确复述业务目标与技术约束。',
671
- '对追问能够给出有层次的回答,而非堆砌名词。'
672
- ]
657
+ items: ['表达结构清晰,能准确复述业务目标与技术约束。', '对追问能够给出有层次的回答,而非堆砌名词。']
673
658
  },
674
659
  {
675
660
  title: '专业深度',
676
- items: [
677
- '熟悉 React 渲染机制,能说明列表虚拟化方案选型理由。',
678
- '了解前端监控与错误边界在生产环境的实践。'
679
- ]
661
+ items: ['熟悉 React 渲染机制,能说明列表虚拟化方案选型理由。', '了解前端监控与错误边界在生产环境的实践。']
680
662
  },
681
663
  {
682
664
  title: '项目复杂度',
683
- items: [
684
- '参与过多团队协同的中台项目,承担核心模块 Owner。',
685
- '能描述需求变更下的架构演进与风险控制。'
686
- ]
665
+ items: ['参与过多团队协同的中台项目,承担核心模块 Owner。', '能描述需求变更下的架构演进与风险控制。']
687
666
  },
688
667
  {
689
668
  title: '协作推进',
@@ -757,24 +736,10 @@ const LongContentExample = () => {
757
736
  </Button>
758
737
  <Button onClick={() => setOpenSelfScroll(true)}>自管滚动(bodyScroll=false)</Button>
759
738
  </Space>
760
- <Overlay
761
- title="陈思远 · 面试评估纪要"
762
- open={open}
763
- onClose={() => setOpen(false)}
764
- onConfirm={() => {}}
765
- confirmText="保存纪要"
766
- size={isDrawer ? 'default' : undefined}
767
- >
739
+ <Overlay title="陈思远 · 面试评估纪要" open={open} onClose={() => setOpen(false)} onConfirm={() => {}} confirmText="保存纪要" size={isDrawer ? 'default' : undefined}>
768
740
  <EvaluationContent />
769
741
  </Overlay>
770
- <Overlay
771
- title="自管滚动示例"
772
- open={openSelfScroll}
773
- onClose={() => setOpenSelfScroll(false)}
774
- bodyScroll={false}
775
- footer={null}
776
- size={isDrawer ? 'large' : undefined}
777
- >
742
+ <Overlay title="自管滚动示例" open={openSelfScroll} onClose={() => setOpenSelfScroll(false)} bodyScroll={false} footer={null} size={isDrawer ? 'large' : undefined}>
778
743
  <div
779
744
  style={{
780
745
  height: &#96;var(${contentHeightVar})&#96;,
@@ -798,6 +763,7 @@ const LongContentExample = () => {
798
763
 
799
764
  render(
800
765
  <App>
766
+ <ModalContextHolder />
801
767
  <DrawerContextHolder />
802
768
  <LongContentExample />
803
769
  </App>
@@ -810,7 +776,7 @@ render(
810
776
  - _ReactModal(@kne/current-lib_react-modal)[import * as _ReactModal from "@kne/react-modal"],(@kne/current-lib_react-modal/dist/index.css),antd(antd)
811
777
 
812
778
  ```jsx
813
- const { default: Modal, Drawer, DrawerContextHolder } = _ReactModal;
779
+ const { default: Modal, Drawer, DrawerContextHolder, ModalContextHolder } = _ReactModal;
814
780
  const { Button, Space, Switch, Tag, Descriptions, Radio, Typography, App } = antd;
815
781
  const { useState, useEffect } = React;
816
782
 
@@ -927,20 +893,14 @@ const HeightVarsExample = () => {
927
893
  />
928
894
  </Space>
929
895
  <Space wrap align="center">
930
- <Switch
931
- checked={customVars}
932
- onChange={setCustomVars}
933
- checkedChildren="自定义变量"
934
- unCheckedChildren="默认变量"
935
- />
896
+ <Switch checked={customVars} onChange={setCustomVars} checkedChildren="自定义变量" unCheckedChildren="默认变量" />
936
897
  <Button type="primary" onClick={() => setOpen(true)}>
937
898
  打开弹层对比高度
938
899
  </Button>
939
900
  <Tag color={customVars ? 'blue' : 'default'}>{customVars ? '已覆盖 CSS 变量' : '库内默认值'}</Tag>
940
901
  </Space>
941
902
  <div style={{ color: 'rgba(0,0,0,0.45)', maxWidth: 640 }}>
942
- 通过 <code>style</code> 覆盖 {chrome.varPrefix}-* 变量。Drawer 无 viewport-gutter;Modal 可加大 gutter
943
- 使 body 明显变矮。色块绑定 <code>{chrome.contentHeightVar}</code>。
903
+ 通过 <code>style</code> 覆盖 {chrome.varPrefix}-* 变量。Drawer 无 viewport-gutter;Modal 可加大 gutter 使 body 明显变矮。色块绑定 <code>{chrome.contentHeightVar}</code>。
944
904
  </div>
945
905
  <HeightProbe open={open} revision={revision} mode={mode} />
946
906
  <Overlay
@@ -965,9 +925,7 @@ const HeightVarsExample = () => {
965
925
  }}
966
926
  >
967
927
  <div style={{ padding: 12 }}>
968
- <p style={{ marginTop: 0, fontWeight: 600 }}>
969
- 色块 height = var({chrome.contentHeightVar})。切换「自定义/默认」与 Modal/Drawer 后重新打开对比。
970
- </p>
928
+ <p style={{ marginTop: 0, fontWeight: 600 }}>色块 height = var({chrome.contentHeightVar})。切换「自定义/默认」与 Modal/Drawer 后重新打开对比。</p>
971
929
  {fillLines.map(text => (
972
930
  <p key={text} style={{ margin: '4px 0' }}>
973
931
  {text}
@@ -982,6 +940,7 @@ const HeightVarsExample = () => {
982
940
 
983
941
  render(
984
942
  <App>
943
+ <ModalContextHolder />
985
944
  <DrawerContextHolder />
986
945
  <HeightVarsExample />
987
946
  </App>
@@ -994,7 +953,7 @@ render(
994
953
  - _ReactModal(@kne/current-lib_react-modal)[import * as _ReactModal from "@kne/react-modal"],(@kne/current-lib_react-modal/dist/index.css),antd(antd)
995
954
 
996
955
  ```jsx
997
- const { default: Modal, Drawer, DrawerContextHolder } = _ReactModal;
956
+ const { default: Modal, Drawer, DrawerContextHolder, ModalContextHolder } = _ReactModal;
998
957
  const { Button, Space, Switch, Radio, Tag, Descriptions, Typography, App } = antd;
999
958
  const { useState, useEffect } = React;
1000
959
 
@@ -1130,12 +1089,7 @@ const ChromeHeightExample = () => {
1130
1089
  <span>title</span>
1131
1090
  <Switch checked={hasTitle} onChange={setHasTitle} checkedChildren="有" unCheckedChildren="空" />
1132
1091
  <span>bodyScroll</span>
1133
- <Switch
1134
- checked={bodyScroll}
1135
- onChange={setBodyScroll}
1136
- checkedChildren="true"
1137
- unCheckedChildren="false"
1138
- />
1092
+ <Switch checked={bodyScroll} onChange={setBodyScroll} checkedChildren="true" unCheckedChildren="false" />
1139
1093
  </Space>
1140
1094
  <div>
1141
1095
  <div style={{ marginBottom: 8 }}>footer</div>
@@ -1185,9 +1139,7 @@ const ChromeHeightExample = () => {
1185
1139
  }}
1186
1140
  >
1187
1141
  <div style={{ padding: 12 }}>
1188
- <p style={{ marginTop: 0, fontWeight: 600 }}>
1189
- 滚动宿主 height: var({chrome.contentHeightVar})。footer=null 时 footer 变量应为 0。
1190
- </p>
1142
+ <p style={{ marginTop: 0, fontWeight: 600 }}>滚动宿主 height: var({chrome.contentHeightVar})。footer=null 时 footer 变量应为 0。</p>
1191
1143
  {lines.map(text => (
1192
1144
  <p key={text}>{text}</p>
1193
1145
  ))}
@@ -1217,6 +1169,7 @@ const ChromeHeightExample = () => {
1217
1169
 
1218
1170
  render(
1219
1171
  <App>
1172
+ <ModalContextHolder />
1220
1173
  <DrawerContextHolder />
1221
1174
  <ChromeHeightExample />
1222
1175
  </App>
@@ -1229,7 +1182,7 @@ render(
1229
1182
  - _ReactModal(@kne/current-lib_react-modal)[import * as _ReactModal from "@kne/react-modal"],(@kne/current-lib_react-modal/dist/index.css),antd(antd)
1230
1183
 
1231
1184
  ```jsx
1232
- const { default: Modal, useModal, DrawerContextHolder } = _ReactModal;
1185
+ const { default: Modal, useModal, DrawerContextHolder, ModalContextHolder } = _ReactModal;
1233
1186
  const { Button, Space, Radio, Typography, App } = antd;
1234
1187
  const { useState } = React;
1235
1188
 
@@ -1274,7 +1227,7 @@ const LimitedHeightExample = () => {
1274
1227
  size="small"
1275
1228
  options={[
1276
1229
  { label: '声明式 Modal', value: 'declarative' },
1277
- { label: 'useModal(info)', value: 'imperative' }
1230
+ { label: 'useModal(命令式)', value: 'imperative' }
1278
1231
  ]}
1279
1232
  onChange={e => setMode(e.target.value)}
1280
1233
  />
@@ -1294,9 +1247,7 @@ const LimitedHeightExample = () => {
1294
1247
  >
1295
1248
  打开高度受限弹窗
1296
1249
  </Button>
1297
- <Text type="secondary">
1298
- useModal 走 antd modal.info,已覆盖 <code>.ant-modal-confirm-paragraph</code> 的 12px 宽度扣减。
1299
- </Text>
1250
+ <Text type="secondary">useModal 走声明式 Modal(经 ModalContextHolder 就近 patch),与声明式同一套 chrome。</Text>
1300
1251
  {mode === 'declarative' ? (
1301
1252
  <Modal {...overlayProps} open={open}>
1302
1253
  {content}
@@ -1308,6 +1259,7 @@ const LimitedHeightExample = () => {
1308
1259
 
1309
1260
  render(
1310
1261
  <App>
1262
+ <ModalContextHolder />
1311
1263
  <DrawerContextHolder />
1312
1264
  <LimitedHeightExample />
1313
1265
  </App>
@@ -1320,30 +1272,8 @@ render(
1320
1272
  - _ReactModal(@kne/current-lib_react-modal)[import * as _ReactModal from "@kne/react-modal"],(@kne/current-lib_react-modal/dist/index.css),antd(antd)
1321
1273
 
1322
1274
  ```jsx
1323
- const {
1324
- default: Modal,
1325
- Drawer,
1326
- DrawerContextHolder,
1327
- TabsLayout,
1328
- ColumnsLayout,
1329
- ScrollRegion,
1330
- modalClassNames
1331
- } = _ReactModal;
1332
- const {
1333
- Button,
1334
- Space,
1335
- Splitter,
1336
- Input,
1337
- Avatar,
1338
- Tag,
1339
- Descriptions,
1340
- Progress,
1341
- Typography,
1342
- Divider,
1343
- App,
1344
- message,
1345
- Radio
1346
- } = antd;
1275
+ const { default: Modal, Drawer, DrawerContextHolder, ModalContextHolder, TabsLayout, ColumnsLayout, ScrollRegion, modalClassNames } = _ReactModal;
1276
+ const { Button, Space, Splitter, Input, Avatar, Tag, Descriptions, Progress, Typography, Divider, App, message, Radio } = antd;
1347
1277
  const { useState, useMemo, useEffect } = React;
1348
1278
 
1349
1279
  const { Text, Title, Paragraph } = Typography;
@@ -1500,26 +1430,15 @@ const SCORE_LABELS = {
1500
1430
  const CandidateList = ({ items, activeKey, onSelect, search, onSearchChange }) => (
1501
1431
  <>
1502
1432
  <div className="modal-scroll-region-sticky candidate-list-toolbar">
1503
- <Input
1504
- allowClear
1505
- placeholder="搜索姓名、岗位、城市…"
1506
- value={search}
1507
- onChange={e => onSearchChange(e.target.value)}
1508
- />
1433
+ <Input allowClear placeholder="搜索姓名、岗位、城市…" value={search} onChange={e => onSearchChange(e.target.value)} />
1509
1434
  <Text type="secondary">本批 {items.length} 人 · 点击切换右侧详情</Text>
1510
1435
  </div>
1511
1436
  {items.map(item => {
1512
1437
  const status = STATUS_MAP[item.status] || STATUS_MAP.pending;
1513
1438
  return (
1514
- <div
1515
- key={item.key}
1516
- className={&#96;candidate-list-item${item.key === activeKey ? ' is-active' : ''}&#96;}
1517
- onClick={() => onSelect(item.key)}
1518
- >
1439
+ <div key={item.key} className={&#96;candidate-list-item${item.key === activeKey ? ' is-active' : ''}&#96;} onClick={() => onSelect(item.key)}>
1519
1440
  <div className="candidate-list-item-main">
1520
- <Avatar style={{ backgroundColor: item.key === activeKey ? '#1677ff' : '#87d068' }}>
1521
- {item.name.slice(-2)}
1522
- </Avatar>
1441
+ <Avatar style={{ backgroundColor: item.key === activeKey ? '#1677ff' : '#87d068' }}>{item.name.slice(-2)}</Avatar>
1523
1442
  <div className="candidate-list-item-body">
1524
1443
  <div className="candidate-list-item-title">{item.name}</div>
1525
1444
  <div className="candidate-list-item-meta">
@@ -1541,8 +1460,7 @@ const CandidateDetail = ({ candidate }) => {
1541
1460
  return null;
1542
1461
  }
1543
1462
  const status = STATUS_MAP[candidate.status] || STATUS_MAP.pending;
1544
- const avgScore =
1545
- Object.values(candidate.scores).reduce((a, b) => a + b, 0) / Object.values(candidate.scores).length;
1463
+ const avgScore = Object.values(candidate.scores).reduce((a, b) => a + b, 0) / Object.values(candidate.scores).length;
1546
1464
 
1547
1465
  return (
1548
1466
  <div className="candidate-detail">
@@ -1560,9 +1478,7 @@ const CandidateDetail = ({ candidate }) => {
1560
1478
  </div>
1561
1479
  <div style={{ textAlign: 'right' }}>
1562
1480
  <Text type="secondary">综合</Text>
1563
- <div style={{ fontSize: 28, fontWeight: 600, color: '#1677ff', lineHeight: 1.2 }}>
1564
- {avgScore.toFixed(1)}
1565
- </div>
1481
+ <div style={{ fontSize: 28, fontWeight: 600, color: '#1677ff', lineHeight: 1.2 }}>{avgScore.toFixed(1)}</div>
1566
1482
  </div>
1567
1483
  </div>
1568
1484
 
@@ -1611,12 +1527,7 @@ const useCandidatePanel = () => {
1611
1527
  if (!q) {
1612
1528
  return ALL_CANDIDATES;
1613
1529
  }
1614
- return ALL_CANDIDATES.filter(
1615
- c =>
1616
- c.name.toLowerCase().includes(q) ||
1617
- c.role.toLowerCase().includes(q) ||
1618
- c.city.toLowerCase().includes(q)
1619
- );
1530
+ return ALL_CANDIDATES.filter(c => c.name.toLowerCase().includes(q) || c.role.toLowerCase().includes(q) || c.city.toLowerCase().includes(q));
1620
1531
  }, [search]);
1621
1532
 
1622
1533
  const current = filtered.find(item => item.key === active) || filtered[0];
@@ -1630,13 +1541,7 @@ const ColumnsPane = () => {
1630
1541
  return (
1631
1542
  <ColumnsLayout widths={['34%', '1fr']}>
1632
1543
  <ScrollRegion>
1633
- <CandidateList
1634
- items={filtered}
1635
- activeKey={current?.key}
1636
- onSelect={setActive}
1637
- search={search}
1638
- onSearchChange={setSearch}
1639
- />
1544
+ <CandidateList items={filtered} activeKey={current?.key} onSelect={setActive} search={search} onSearchChange={setSearch} />
1640
1545
  </ScrollRegion>
1641
1546
  <ScrollRegion inset>
1642
1547
  <CandidateDetail candidate={current} />
@@ -1651,22 +1556,10 @@ const SplitterPane = () => {
1651
1556
  return (
1652
1557
  <div style={{ height: '100%', display: 'flex', flexDirection: 'column', minHeight: 0 }}>
1653
1558
  <p className="demo-panel-hint">可拖拽中间分隔条调整列表宽度,左右列仍各自 SimpleBar 滚动。</p>
1654
- <Splitter
1655
- className={modalClassNames.splitter}
1656
- style={{ flex: 1, minHeight: 0 }}
1657
- defaultSize="34%"
1658
- min="240"
1659
- max="52%"
1660
- >
1559
+ <Splitter className={modalClassNames.splitter} style={{ flex: 1, minHeight: 0 }} defaultSize="34%" min="240" max="52%">
1661
1560
  <Splitter.Panel>
1662
1561
  <ScrollRegion>
1663
- <CandidateList
1664
- items={filtered}
1665
- activeKey={current?.key}
1666
- onSelect={setActive}
1667
- search={search}
1668
- onSearchChange={setSearch}
1669
- />
1562
+ <CandidateList items={filtered} activeKey={current?.key} onSelect={setActive} search={search} onSearchChange={setSearch} />
1670
1563
  </ScrollRegion>
1671
1564
  </Splitter.Panel>
1672
1565
  <Splitter.Panel>
@@ -1819,6 +1712,7 @@ const ExtendLayoutExample = () => {
1819
1712
 
1820
1713
  render(
1821
1714
  <App>
1715
+ <ModalContextHolder />
1822
1716
  <DrawerContextHolder />
1823
1717
  <ExtendLayoutExample />
1824
1718
  </App>
@@ -1831,7 +1725,7 @@ render(
1831
1725
  - _ReactModal(@kne/current-lib_react-modal)[import * as _ReactModal from "@kne/react-modal"],(@kne/current-lib_react-modal/dist/index.css),antd(antd)
1832
1726
 
1833
1727
  ```jsx
1834
- const { default: Modal, useModal, useDrawer, DrawerContextHolder } = _ReactModal;
1728
+ const { default: Modal, useModal, useDrawer, DrawerContextHolder, ModalContextHolder } = _ReactModal;
1835
1729
  const { Button, Space, Typography, Tag, message, Checkbox, Radio, App } = antd;
1836
1730
  const { useState, useEffect } = React;
1837
1731
  const { Text, Paragraph } = Typography;
@@ -1870,11 +1764,7 @@ const NestProbe = ({ open, isDrawer }) => {
1870
1764
  return <Text type="secondary">打开内层后显示挂载探针</Text>;
1871
1765
  }
1872
1766
 
1873
- return (
1874
- <Tag color={info.hoisted ? 'success' : 'error'}>
1875
- 内层 Modal {info.hoisted ? '已 hoist 到外层外侧' : '挂载异常'}
1876
- </Tag>
1877
- );
1767
+ return <Tag color={info.hoisted ? 'success' : 'error'}>内层 Modal {info.hoisted ? '已 hoist 到外层外侧' : '挂载异常'}</Tag>;
1878
1768
  };
1879
1769
 
1880
1770
  const ExportFieldPicker = ({ isDrawer }) => {
@@ -1884,8 +1774,7 @@ const ExportFieldPicker = ({ isDrawer }) => {
1884
1774
  return (
1885
1775
  <div>
1886
1776
  <Paragraph>
1887
- 已选择本批 <Text strong>8</Text> 位候选人。内层始终为声明式 Modal;外层当前为{' '}
1888
- <Text code>{isDrawer ? 'Drawer' : 'Modal'}</Text>。
1777
+ 已选择本批 <Text strong>8</Text> 位候选人。内层始终为声明式 Modal;外层当前为 <Text code>{isDrawer ? 'Drawer' : 'Modal'}</Text>。
1889
1778
  </Paragraph>
1890
1779
  <Space>
1891
1780
  <Button type="primary" onClick={() => setInnerOpen(true)}>
@@ -1907,12 +1796,7 @@ const ExportFieldPicker = ({ isDrawer }) => {
1907
1796
  }}
1908
1797
  confirmText="确认字段"
1909
1798
  >
1910
- <Checkbox.Group
1911
- style={{ display: 'flex', flexDirection: 'column', gap: 10 }}
1912
- options={EXPORT_FIELDS}
1913
- value={checked}
1914
- onChange={setChecked}
1915
- />
1799
+ <Checkbox.Group style={{ display: 'flex', flexDirection: 'column', gap: 10 }} options={EXPORT_FIELDS} value={checked} onChange={setChecked} />
1916
1800
  </Modal>
1917
1801
  </div>
1918
1802
  );
@@ -1961,6 +1845,7 @@ const NestedModalExample = () => {
1961
1845
 
1962
1846
  render(
1963
1847
  <App>
1848
+ <ModalContextHolder />
1964
1849
  <DrawerContextHolder />
1965
1850
  <NestedModalExample />
1966
1851
  </App>
@@ -1973,7 +1858,7 @@ render(
1973
1858
  - _ReactModal(@kne/current-lib_react-modal)[import * as _ReactModal from "@kne/react-modal"],(@kne/current-lib_react-modal/dist/index.css),_FormInfo(@kne/form-info)[import * as _FormInfo from "@kne/form-info"],(@kne/form-info/dist/index.css),antd(antd)
1974
1859
 
1975
1860
  ```jsx
1976
- const { createModalRender, createDrawerRender, DrawerContextHolder } = _ReactModal;
1861
+ const { createModalRender, createDrawerRender, DrawerContextHolder, ModalContextHolder } = _ReactModal;
1977
1862
  const { default: FormInfo, FormModal, Input, TextArea } = _FormInfo;
1978
1863
  const { Button, Space, Typography, App, message, Switch, Flex, Radio } = antd;
1979
1864
  const { useState, useMemo, useEffect } = React;
@@ -2009,11 +1894,7 @@ const SECTION_DEFS = [
2009
1894
  {
2010
1895
  key: 'experience',
2011
1896
  title: '经历与补充',
2012
- fields: Array.from({ length: 16 }, (_, i) => [
2013
- &#96;expField${i + 1}&#96;,
2014
- &#96;经历补充项 ${i + 1}&#96;,
2015
- i % 4 === 0 ? 'REQ' : ''
2016
- ])
1897
+ fields: Array.from({ length: 16 }, (_, i) => [&#96;expField${i + 1}&#96;, &#96;经历补充项 ${i + 1}&#96;, i % 4 === 0 ? 'REQ' : ''])
2017
1898
  }
2018
1899
  ];
2019
1900
 
@@ -2033,8 +1914,7 @@ const buildInitialData = () => {
2033
1914
  collabScore: '4',
2034
1915
  cultureScore: '5',
2035
1916
  overallScore: '4.5',
2036
- summary:
2037
- '沟通清晰,项目推进稳定。以下为加长评估说明,用于验证弹窗 body 在超长表单下的 SimpleBar 滚动:标题与底部按钮应固定,仅中间表单区域滚动。'.repeat(3)
1917
+ summary: '沟通清晰,项目推进稳定。以下为加长评估说明,用于验证弹窗 body 在超长表单下的 SimpleBar 滚动:标题与底部按钮应固定,仅中间表单区域滚动。'.repeat(3)
2038
1918
  };
2039
1919
  SECTION_DEFS[2].fields.forEach(([name], i) => {
2040
1920
  data[name] = &#96;补充说明内容 ${i + 1}:用于拉长表单高度。&#96;;
@@ -2063,20 +1943,8 @@ const LongFormFields = () => (
2063
1943
  gap={20}
2064
1944
  list={[
2065
1945
  <TextArea key="summary" name="summary" label="综合评语" rule="REQ" block />,
2066
- <TextArea
2067
- key="risk"
2068
- name="risk"
2069
- label="风险与待跟进"
2070
- block
2071
- placeholder="列出风险点、待确认事项等"
2072
- />,
2073
- <TextArea
2074
- key="plan"
2075
- name="plan"
2076
- label="入职 / 下轮计划"
2077
- block
2078
- placeholder="试用期目标、面试官建议等"
2079
- />
1946
+ <TextArea key="risk" name="risk" label="风险与待跟进" block placeholder="列出风险点、待确认事项等" />,
1947
+ <TextArea key="plan" name="plan" label="入职 / 下轮计划" block placeholder="试用期目标、面试官建议等" />
2080
1948
  ]}
2081
1949
  />
2082
1950
  {Array.from({ length: 8 }, (_, block) => (
@@ -2108,20 +1976,9 @@ const FormInfoModalExample = () => {
2108
1976
  }
2109
1977
  }, [mode]);
2110
1978
 
2111
- const renderModalBase = isDrawer
2112
- ? createDrawerRender({ placement: 'right', footerButtons: [], bodyScroll: true, size: 'large' })
2113
- : createModalRender({ footerButtons: [], bodyScroll: true, size: 'large' });
2114
-
2115
- const renderModal = ({
2116
- formProps,
2117
- saveText,
2118
- autoClose,
2119
- onCancel,
2120
- footer,
2121
- modalRender,
2122
- children,
2123
- ...props
2124
- }) =>
1979
+ const renderModalBase = isDrawer ? createDrawerRender({ placement: 'right', footerButtons: [], bodyScroll: true, size: 'large' }) : createModalRender({ footerButtons: [], bodyScroll: true, size: 'large' });
1980
+
1981
+ const renderModal = ({ formProps, saveText, autoClose, onCancel, footer, modalRender, children, ...props }) =>
2125
1982
  renderModalBase({
2126
1983
  ...props,
2127
1984
  bodyScroll,
@@ -2155,9 +2012,7 @@ const FormInfoModalExample = () => {
2155
2012
  <Switch checked={bodyScroll} onChange={setBodyScroll} checkedChildren="开" unCheckedChildren="关" />
2156
2013
  </Space>
2157
2014
  </Space>
2158
- <Text type="secondary">
2159
- createModalRender / createDrawerRender 注入默认 props;切换 Modal / Drawer 对比 form-info 宿主集成。
2160
- </Text>
2015
+ <Text type="secondary">createModalRender / createDrawerRender 注入默认 props;切换 Modal / Drawer 对比 form-info 宿主集成。</Text>
2161
2016
 
2162
2017
  <FormModal
2163
2018
  title={isDrawer ? '候选人深度评估(侧滑)' : '候选人深度评估(超长表单)'}
@@ -2183,6 +2038,7 @@ const FormInfoModalExample = () => {
2183
2038
 
2184
2039
  render(
2185
2040
  <App>
2041
+ <ModalContextHolder />
2186
2042
  <DrawerContextHolder />
2187
2043
  <FormInfoModalExample />
2188
2044
  </App>
@@ -2195,7 +2051,7 @@ render(
2195
2051
  - _ReactModal(@kne/current-lib_react-modal)[import * as _ReactModal from "@kne/react-modal"],(@kne/current-lib_react-modal/dist/index.css),_FormInfo(@kne/form-info)[import * as _FormInfo from "@kne/form-info"],(@kne/form-info/dist/index.css),antd(antd)
2196
2052
 
2197
2053
  ```jsx
2198
- const { createModalRender, createDrawerRender, modalClassNames, DrawerContextHolder } = _ReactModal;
2054
+ const { createModalRender, createDrawerRender, modalClassNames, DrawerContextHolder, ModalContextHolder } = _ReactModal;
2199
2055
  const { default: FormInfo, FormStepsModal, List, Input, TextArea } = _FormInfo;
2200
2056
  const { Button, Space, Typography, App, message, Flex, Radio } = antd;
2201
2057
  const { useState, useEffect } = React;
@@ -2217,25 +2073,17 @@ const renderStepsModalBase = isDrawer =>
2217
2073
  className: modalClassNames.stepsForm
2218
2074
  });
2219
2075
 
2220
- const renderStepsModal = isDrawer => ({
2221
- formProps,
2222
- saveText,
2223
- autoClose,
2224
- onCancel,
2225
- footer,
2226
- modalRender,
2227
- children,
2228
- className,
2229
- ...props
2230
- }) =>
2231
- renderStepsModalBase(isDrawer)({
2232
- ...props,
2233
- className,
2234
- onClose: onCancel,
2235
- footer: typeof footer === 'function' ? footer() : footer,
2236
- modalRender,
2237
- children
2238
- });
2076
+ const renderStepsModal =
2077
+ isDrawer =>
2078
+ ({ formProps, saveText, autoClose, onCancel, footer, modalRender, children, className, ...props }) =>
2079
+ renderStepsModalBase(isDrawer)({
2080
+ ...props,
2081
+ className,
2082
+ onClose: onCancel,
2083
+ footer: typeof footer === 'function' ? footer() : footer,
2084
+ modalRender,
2085
+ children
2086
+ });
2239
2087
 
2240
2088
  const STEP_DATA = {
2241
2089
  name: '李四',
@@ -2340,21 +2188,9 @@ const FormInfoStepsModalExample = () => {
2340
2188
  title="维度评分"
2341
2189
  column={2}
2342
2190
  gap={20}
2343
- list={[
2344
- <Input name="commScore" label="沟通表达" rule="REQ" />,
2345
- <Input name="techScore" label="专业深度" rule="REQ" />,
2346
- <Input name="projectScore" label="项目复杂度" rule="REQ" />
2347
- ]}
2348
- />
2349
- <FormInfo
2350
- bordered
2351
- title="评语"
2352
- column={1}
2353
- gap={20}
2354
- list={[
2355
- <TextArea name="summary" label="综合评语" rule="REQ" block rows={4} />
2356
- ]}
2191
+ list={[<Input name="commScore" label="沟通表达" rule="REQ" />, <Input name="techScore" label="专业深度" rule="REQ" />, <Input name="projectScore" label="项目复杂度" rule="REQ" />]}
2357
2192
  />
2193
+ <FormInfo bordered title="评语" column={1} gap={20} list={[<TextArea name="summary" label="综合评语" rule="REQ" block rows={4} />]} />
2358
2194
  </Flex>
2359
2195
  )
2360
2196
  },
@@ -2371,22 +2207,9 @@ const FormInfoStepsModalExample = () => {
2371
2207
  maxLength={5}
2372
2208
  addText="添加经历"
2373
2209
  itemTitle={({ index, data }) => data?.companyName || &#96;经历 ${index + 1}&#96;}
2374
- list={[
2375
- <Input name="companyName" label="公司" rule="REQ" />,
2376
- <Input name="role" label="职位" rule="REQ" />,
2377
- <Input name="years" label="年限" placeholder="例如 2年" />
2378
- ]}
2379
- />
2380
- <FormInfo
2381
- bordered
2382
- title="目标与风险"
2383
- column={1}
2384
- gap={20}
2385
- list={[
2386
- <TextArea name="objectives" label="培养目标" rule="REQ" block rows={4} />,
2387
- <TextArea name="risks" label="风险与跟进" block rows={3} />
2388
- ]}
2210
+ list={[<Input name="companyName" label="公司" rule="REQ" />, <Input name="role" label="职位" rule="REQ" />, <Input name="years" label="年限" placeholder="例如 2年" />]}
2389
2211
  />
2212
+ <FormInfo bordered title="目标与风险" column={1} gap={20} list={[<TextArea name="objectives" label="培养目标" rule="REQ" block rows={4} />, <TextArea name="risks" label="风险与跟进" block rows={3} />]} />
2390
2213
  </Flex>
2391
2214
  )
2392
2215
  }
@@ -2398,6 +2221,7 @@ const FormInfoStepsModalExample = () => {
2398
2221
 
2399
2222
  render(
2400
2223
  <App>
2224
+ <ModalContextHolder />
2401
2225
  <DrawerContextHolder />
2402
2226
  <FormInfoStepsModalExample />
2403
2227
  </App>
@@ -2413,52 +2237,54 @@ render(
2413
2237
 
2414
2238
  ##### 属性
2415
2239
 
2416
- | 属性 | 类型 | 默认值 | 描述 |
2417
- |------|------|--------|------|
2418
- | open | boolean | - | 是否显示 |
2419
- | onClose | function | - | 关闭回调;受控时由此改 `open` |
2420
- | title | ReactNode \| function | - | 标题;为 function 时入参含 `close` |
2421
- | children | ReactNode \| function | - | 内容;为 function 时入参含 `close` |
2422
- | onConfirm | function | - | 默认确认按钮;支持 Promise;返回 `false` 不关闭 |
2423
- | onCancel | function | - | 默认取消按钮;语义同 `onConfirm` |
2424
- | confirmText | ReactNode | - | 默认确认文案(默认 intl Confirm) |
2425
- | cancelText | ReactNode | - | 默认取消文案(默认 intl Cancel) |
2426
- | footer | ReactNode \| function \| null | - | 左侧 footer 插槽;与 `footerButtons` 均为「未设置」且 `footer === null` 时不渲染 footer |
2427
- | footerButtons | array \| function | - | 右侧按钮区,见下表;未传时为取消+确认 |
2428
- | size | `small` \| `default` \| `large` | `default` | 桌面宽度档位 |
2429
- | noPadding | boolean | false | 去掉 body 内边距。未传且 `bodyScroll={false}` 时默认视为 true;显式 `noPadding={false}` 可保留内边距 |
2430
- | maskClosable | boolean | false | 点击蒙层是否关闭 |
2431
- | closable | boolean | true | 是否显示右上角关闭 |
2432
- | bodyScroll | boolean | true | true 使用 SimpleBar;false 不挂 SimpleBar,内容自管滚动,且默认 noPadding(可用 `noPadding={false}` 覆盖) |
2433
- | mobileFullscreen | boolean | true | 移动端是否全屏 |
2434
- | getContainer | HTMLElement \| function | - | 挂载容器;嵌套时默认挂到外层 `.ant-modal-root` 外侧 |
2435
- | width / zIndex / className / afterClose / style / styles | - | - | 透传或覆盖 antd Modal |
2240
+ | 属性 | 类型 | 默认值 | 描述 |
2241
+ | -------------------------------------------------------- | ------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------- |
2242
+ | open | boolean | - | 是否显示 |
2243
+ | onClose | function | - | 关闭回调;受控时由此改 `open` |
2244
+ | title | ReactNode \| function | - | 标题;为 function 时入参含 `close` |
2245
+ | children | ReactNode \| function | - | 内容;为 function 时入参含 `close` |
2246
+ | onConfirm | function | - | 默认确认按钮;支持 Promise;返回 `false` 不关闭 |
2247
+ | onCancel | function | - | 默认取消按钮;语义同 `onConfirm` |
2248
+ | confirmText | ReactNode | - | 默认确认文案(默认 intl Confirm) |
2249
+ | cancelText | ReactNode | - | 默认取消文案(默认 intl Cancel) |
2250
+ | footer | ReactNode \| function \| null | - | 左侧 footer 插槽;与 `footerButtons` 均为「未设置」且 `footer === null` 时不渲染 footer |
2251
+ | footerButtons | array \| function | - | 右侧按钮区,见下表;未传时为取消+确认 |
2252
+ | size | `small` \| `default` \| `large` | `default` | 桌面宽度档位 |
2253
+ | noPadding | boolean | false | 去掉 body 内边距。未传且 `bodyScroll={false}` 时默认视为 true;显式 `noPadding={false}` 可保留内边距 |
2254
+ | maskClosable | boolean | false | 点击蒙层是否关闭 |
2255
+ | closable | boolean | true | 是否显示右上角关闭 |
2256
+ | bodyScroll | boolean | true | true 使用 SimpleBar;false 不挂 SimpleBar,内容自管滚动,且默认 noPadding(可用 `noPadding={false}` 覆盖) |
2257
+ | mobileFullscreen | boolean | true | 移动端是否全屏 |
2258
+ | getContainer | HTMLElement \| function | - | 挂载容器;嵌套时默认挂到外层 `.ant-modal-root` 外侧 |
2259
+ | width / zIndex / className / afterClose / style / styles | - | - | 透传或覆盖 antd Modal |
2436
2260
 
2437
2261
  其余未列出参数按 antd Modal 习惯透传。
2438
2262
 
2439
2263
  ##### footerButtons 项
2440
2264
 
2441
- | 属性 | 类型 | 默认值 | 描述 |
2442
- |------|------|--------|------|
2443
- | children | ReactNode | - | 按钮文案 |
2444
- | type | string | - | antd Button type |
2445
- | onClick | function | - | 可返回 Promise;末参为 `targetProps`(含 `close`);`autoClose` 且结果 `!== false` 时关闭 |
2446
- | autoClose | boolean | true | 点击后是否自动关闭 |
2447
- | display | boolean \| function | - | `false` 隐藏;function 返回值决定是否展示 |
2448
- | ButtonComponent | component | - | 自定义按钮;默认走 ButtonGroup 内 LoadingButton |
2449
- | ... | - | - | 其余透传 Button |
2265
+ | 属性 | 类型 | 默认值 | 描述 |
2266
+ | --------------- | ------------------- | ------ | ----------------------------------------------------------------------------------------- |
2267
+ | children | ReactNode | - | 按钮文案 |
2268
+ | type | string | - | antd Button type |
2269
+ | onClick | function | - | 可返回 Promise;末参为 `targetProps`(含 `close`);`autoClose` 且结果 `!== false` 时关闭 |
2270
+ | autoClose | boolean | true | 点击后是否自动关闭 |
2271
+ | display | boolean \| function | - | `false` 隐藏;function 返回值决定是否展示 |
2272
+ | ButtonComponent | component | - | 自定义按钮;默认走 ButtonGroup 内 LoadingButton |
2273
+ | ... | - | - | 其余透传 Button |
2450
2274
 
2451
2275
  - `footerButtons={[]}`:不渲染按钮列(可与左侧 `footer` 并存)。**移动端**此模式且 `footer` 有内容时(如 FormModal 自带 Submit/Cancel),按钮区会自动居中,与默认 `footerButtons` 行为一致。
2452
2276
  - `footer === null` 且未传 `footerButtons`:不渲染整个 footer 区
2453
2277
 
2454
2278
  #### useModal
2455
2279
 
2280
+ 命令式内容弹窗。须在 antd `App` 内挂载 **`<ModalContextHolder />`**(页面根层);弹窗内容树内另有 `ModalLayerProvider`,嵌套 `useModal` 会就近 patch,叠层交给 antd `ZIndexContext`。**不**再走 `App.modal.info` / ConfirmDialog。
2281
+
2456
2282
  命令式打开弹窗,参数同 Modal。需在 antd `App`(或 `App.useApp` 可用)上下文中使用。
2457
2283
 
2458
2284
  ##### 返回值
2459
2285
 
2460
- | 属性 | 类型 | 描述 |
2461
- |------|------|------|
2286
+ | 属性 | 类型 | 描述 |
2287
+ | ----- | -------- | --------------------------------------------------------- |
2462
2288
  | modal | function | 调用后弹出 Modal;返回 `{ close }`;默认 `zIndex` 为 1100 |
2463
2289
 
2464
2290
  #### useConfirmModal
@@ -2467,29 +2293,29 @@ render(
2467
2293
 
2468
2294
  ##### 参数
2469
2295
 
2470
- | 属性 | 类型 | 默认值 | 描述 |
2471
- |------|------|--------|------|
2472
- | type | `confirm` \| `info` \| `success` \| `warning` \| `error` | `confirm` | 调用 `modal[type]` |
2473
- | title | ReactNode | - | 标题 |
2474
- | message | ReactNode | - | 正文 |
2475
- | danger | boolean | false | 为 true 时展示语义图标,确认钮危险色 |
2476
- | confirmType | `info` \| `warning` \| `error` \| `success` | `info` | `type=confirm` 时图标语义 |
2477
- | icon | ReactNode | - | 自定义图标,覆盖默认 |
2478
- | onConfirm | function | - | 映射 antd `onOk` |
2479
- | onCancel | function | - | 映射 antd `onCancel` |
2480
- | confirmText | ReactNode | - | 映射 `okText` |
2481
- | cancelText | ReactNode | - | 映射 `cancelText` |
2482
- | onClose | function | - | 调用 `close()` 时触发 |
2483
- | maskClosable | boolean | false | 默认不可点蒙层关闭 |
2484
- | getContainer | HTMLElement \| function | - | 嵌套时挂到外层 modal 外侧 |
2485
- | afterClose / zIndex / wrapClassName | - | - | 透传;默认 `zIndex` 1100 |
2296
+ | 属性 | 类型 | 默认值 | 描述 |
2297
+ | ----------------------------------- | -------------------------------------------------------- | --------- | ------------------------------------ |
2298
+ | type | `confirm` \| `info` \| `success` \| `warning` \| `error` | `confirm` | 调用 `modal[type]` |
2299
+ | title | ReactNode | - | 标题 |
2300
+ | message | ReactNode | - | 正文 |
2301
+ | danger | boolean | false | 为 true 时展示语义图标,确认钮危险色 |
2302
+ | confirmType | `info` \| `warning` \| `error` \| `success` | `info` | `type=confirm` 时图标语义 |
2303
+ | icon | ReactNode | - | 自定义图标,覆盖默认 |
2304
+ | onConfirm | function | - | 映射 antd `onOk` |
2305
+ | onCancel | function | - | 映射 antd `onCancel` |
2306
+ | confirmText | ReactNode | - | 映射 `okText` |
2307
+ | cancelText | ReactNode | - | 映射 `cancelText` |
2308
+ | onClose | function | - | 调用 `close()` 时触发 |
2309
+ | maskClosable | boolean | false | 默认不可点蒙层关闭 |
2310
+ | getContainer | HTMLElement \| function | - | 嵌套时挂到外层 modal 外侧 |
2311
+ | afterClose / zIndex / wrapClassName | - | - | 透传;默认 `zIndex` 1100 |
2486
2312
 
2487
2313
  其余未列出参数按 antd Modal.confirm 习惯透传。
2488
2314
 
2489
2315
  ##### 返回值
2490
2316
 
2491
- | 属性 | 类型 | 描述 |
2492
- |------|------|------|
2317
+ | 属性 | 类型 | 描述 |
2318
+ | ------------ | -------- | ---------------------------------- |
2493
2319
  | confirmModal | function | 调用后弹出确认框;返回 `{ close }` |
2494
2320
 
2495
2321
  与 `useModal` 对比:专用于短文案确认 / 提示,桌面居中窄宽(约 400px),无 SimpleBar body。
@@ -2498,20 +2324,20 @@ render(
2498
2324
 
2499
2325
  挂在 `.modal` / `.modal-outer` 上,可业务覆盖。
2500
2326
 
2501
- | 变量 | 说明 |
2502
- |------|------|
2503
- | `--kne-modal-viewport-height` | 默认 `var(--kne-viewport-height, 100vh)` |
2504
- | `--kne-modal-viewport-width` | 默认 `var(--kne-viewport-width, 100vw)` |
2505
- | `--kne-modal-title-height` | 标题区高度贡献,默认 `48px`;无 title 为 `0` |
2506
- | `--kne-modal-footer-height` | footer 高度贡献,默认 `58px`;无 footer 为 `0` |
2507
- | `--kne-modal-viewport-gutter` | 桌面相对视口留白合计,默认 `120px`;移动全屏 `0` |
2508
- | `--kne-modal-body-padding-vertical` | body 上下 padding 合计,默认 `48px`;`noPadding` 为 `0` |
2509
- | `--kne-modal-body-padding-horizontal` | body 左右 padding 合计,默认 `48px`;`noPadding` 为 `0` |
2510
- | `--kne-modal-body-height` | body 容器高度(**不**扣 body padding) |
2511
- | `--kne-modal-content-height` | 内容高度;默认 `body-height − padding-vertical`。`bodyScroll={false}` 时在 `.modal-body` 内覆盖为 `100%`(相对 body 实高),供内部滚动容器使用 |
2512
- | `--kne-modal-body-min-height` / `--kne-modal-body-max-height` | body 容器 min/max |
2513
- | `--kne-modal-content-min-height` | content 侧 min |
2514
- | `--kne-modal-content-width` | 内容宽度契约(扣 horizontal padding) |
2327
+ | 变量 | 说明 |
2328
+ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
2329
+ | `--kne-modal-viewport-height` | 默认 `var(--kne-viewport-height, 100vh)` |
2330
+ | `--kne-modal-viewport-width` | 默认 `var(--kne-viewport-width, 100vw)` |
2331
+ | `--kne-modal-title-height` | 标题区高度贡献,默认 `48px`;无 title 为 `0` |
2332
+ | `--kne-modal-footer-height` | footer 高度贡献,默认 `58px`;无 footer 为 `0` |
2333
+ | `--kne-modal-viewport-gutter` | 桌面相对视口留白合计,默认 `80px`;移动全屏 `0` |
2334
+ | `--kne-modal-body-padding-vertical` | body 上下 padding 合计,默认 `48px`;`noPadding` 为 `0` |
2335
+ | `--kne-modal-body-padding-horizontal` | body 左右 padding 合计,默认 `48px`;`noPadding` 为 `0` |
2336
+ | `--kne-modal-body-height` | body **上限**高度公式(`100vh − title − footer − gutter`,**不**扣 body padding);`bodyScroll={false}` 时作为 body 实高 |
2337
+ | `--kne-modal-content-height` | 内容高度;默认 `body-height − padding-vertical`。`bodyScroll={false}` 时在 `.modal-body` 内覆盖为 `100%`(相对 body 实高),供内部滚动容器使用 |
2338
+ | `--kne-modal-body-min-height` / `--kne-modal-body-max-height` | body 容器 min/max。min 随 `size`:small 基准 300、default/large 基准 500,再扣 title/footer chrome;CSS 回退 small `252px` / 其它 `394px`。max 等于 `body-height`。桌面默认滚动:`height:auto`,不低于 min、不超过 max |
2339
+ | `--kne-modal-content-min-height` | content 侧 min(默认随 body-min − padding) |
2340
+ | `--kne-modal-content-width` | 内容宽度契约(扣 horizontal padding) |
2515
2341
 
2516
2342
  #### 布局组合(Modal / Drawer 共用)
2517
2343
 
@@ -2536,10 +2362,10 @@ Tabs / 分栏弹层须 **`bodyScroll={false}`**,此时默认 **noPadding**(
2536
2362
 
2537
2363
  ##### modalClassNames
2538
2364
 
2539
- | 常量 | 值 | 用途 |
2540
- |------|-----|------|
2365
+ | 常量 | 值 | 用途 |
2366
+ | ----------- | ------------------------ | ---------------------------------- |
2541
2367
  | `stepsForm` | `react-modal-steps-form` | 分步弹窗挂 `className`,去横向溢出 |
2542
- | `splitter` | `react-modal-splitter` | antd Splitter 在弹层内的高度链 |
2368
+ | `splitter` | `react-modal-splitter` | antd Splitter 在弹层内的高度链 |
2543
2369
 
2544
2370
  ##### createModalRender
2545
2371
 
@@ -2551,11 +2377,11 @@ createModalRender(modalDefaults) => (hostProps) => Modal
2551
2377
 
2552
2378
  推荐 `modalDefaults`:
2553
2379
 
2554
- | 场景 | modalDefaults |
2555
- |------|---------------|
2556
- | 子内容自带 Footer | `{ footerButtons: [] }` |
2557
- | 长内容 | `{ footerButtons: [], bodyScroll: true, size: 'large' }` |
2558
- | 分步弹窗 | `{ footerButtons: [], bodyScroll: true, size: 'default', className: modalClassNames.stepsForm }` |
2380
+ | 场景 | modalDefaults |
2381
+ | ----------------- | ------------------------------------------------------------------------------------------------ |
2382
+ | 子内容自带 Footer | `{ footerButtons: [] }` |
2383
+ | 长内容 | `{ footerButtons: [], bodyScroll: true, size: 'large' }` |
2384
+ | 分步弹窗 | `{ footerButtons: [], bodyScroll: true, size: 'default', className: modalClassNames.stepsForm }` |
2559
2385
 
2560
2386
  #### Drawer
2561
2387
 
@@ -2563,11 +2389,11 @@ createModalRender(modalDefaults) => (hostProps) => Modal
2563
2389
 
2564
2390
  ##### 属性(差异与补充)
2565
2391
 
2566
- | 属性 | 类型 | 默认值 | 描述 |
2567
- |------|------|--------|------|
2568
- | placement | `left` \| `right` \| `top` \| `bottom` | `right` | 滑出方向;`size` 映射 width(left/right)或 height(top/bottom) |
2569
- | size | `small` \| `default` \| `large` | `default` | 600 / 1000 / min(vw−64, 1500) px |
2570
- | 移动端 | - | 侧滑全宽 | left/right → 100vw;top/bottom → 100vh(非 Modal 式全屏居中) |
2392
+ | 属性 | 类型 | 默认值 | 描述 |
2393
+ | --------- | -------------------------------------- | --------- | ---------------------------------------------------------------- |
2394
+ | placement | `left` \| `right` \| `top` \| `bottom` | `right` | 滑出方向;`size` 映射 width(left/right)或 height(top/bottom) |
2395
+ | size | `small` \| `default` \| `large` | `default` | 600 / 1000 / min(vw−64, 1500) px |
2396
+ | 移动端 | - | 侧滑全宽 | left/right → 100vw;top/bottom → 100vh(非 Modal 式全屏居中) |
2571
2397
 
2572
2398
  其余 `open` / `onClose` / `title` / `children` / `footer` / `footerButtons` / `bodyScroll` / `noPadding` / `closable` / `maskClosable` / `getContainer` 等与 Modal 相同。
2573
2399
 
@@ -2590,4 +2416,3 @@ createDrawerRender(drawerDefaults) => (hostProps) => Drawer
2590
2416
  ```
2591
2417
 
2592
2418
  单参数合并渲染;宿主字段映射由 `renderModal` 回调内完成(同 `createModalRender`)。
2593
-