@nokecy/qc-ui 1.1.83 → 1.1.85

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,15 +1,16 @@
1
- import React, { useEffect, useRef } from 'react';
1
+ import React, { useCallback, useEffect, useRef } from 'react';
2
2
 
3
3
  /**
4
4
  * 判断「焦点离开了这个单元格」的作用域,给懒挂载格「用完卸回纯文本」用。
5
5
  *
6
- * 用 React 合成的 onFocus/onBlur 而不是原生监听:合成事件会沿 React 树冒泡,
7
- * 穿过 portal。下拉面板、日期面板、选择对话框这类渲染到 body 上的弹层,焦点进去时
8
- * 对本格来说仍是「格内」,不会被误判成离开;弹层的挂载点是哪、有没有 antd 的类名都不用管。
6
+ * 用 React 合成的 onFocus/onBlur 判断焦点变化:合成事件会沿 React 树冒泡,穿过 portal。
7
+ * 下拉面板、日期面板、选择对话框这类渲染到 body 上的弹层,焦点进去时对本格仍是「格内」。
8
+ * 同时监听指针离开:点击到不可聚焦的文本格或页面空白不会触发 blur,需要按点击位置恢复展示态;
9
+ * portal 内的指针事件仍沿 React 树到达本作用域,不会被当作离开。
9
10
  *
10
- * 失焦不立刻判定,而是推到下一个任务再看:焦点从输入框换到格内别的元素(或弹层)时,
11
- * blur 之后紧跟着 focus,后者会作废这次判定。判定时若 document.activeElement 仍在格内
12
- * (窗口切走时输入框依旧是 activeElement),同样不算离开。
11
+ * 离开不立刻判定,而是推到下一个任务再看:焦点从输入框换到格内别的元素(或弹层)时,
12
+ * blur 之后紧跟着 focus,后者会作废这次判定。单纯 blur 时若 activeElement 仍在格内
13
+ * (如窗口切走),不算离开;指针明确点击到作用域外则按离开处理。
13
14
  *
14
15
  * 用 display: contents,不产生盒子,不改变单元格里原有的布局。
15
16
  *
@@ -21,34 +22,69 @@ export var CellFocusScope = function CellFocusScope(_ref) {
21
22
  children = _ref.children;
22
23
  var rootRef = useRef(null);
23
24
  var timerRef = useRef();
25
+ // 通过 React portal 渲染到 body 的弹层仍属于当前格;记录经过本作用域的指针事件,
26
+ // 避免日期/下拉弹层中的点击被 document 级离开检测误判。@author nokecy
27
+ var pointerEventsInScopeRef = useRef(new WeakSet());
28
+ var focusWithinRef = useRef(false);
24
29
  // 每次焦点回到格内、或卸载时递增;进行中的异步判定拿它判断自己是否已过期
25
30
  var generationRef = useRef(0);
26
31
  var onLeaveRef = useRef(onLeave);
27
32
  onLeaveRef.current = onLeave;
28
- var cancel = function cancel() {
33
+ var cancel = useCallback(function () {
29
34
  generationRef.current += 1;
30
35
  window.clearTimeout(timerRef.current);
31
- };
32
- useEffect(function () {
33
- return cancel;
34
36
  }, []);
35
- var handleBlur = function handleBlur() {
37
+ var scheduleLeave = useCallback(function () {
38
+ var pointerLeftScope = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
39
+ var hadFocus = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : focusWithinRef.current;
36
40
  cancel();
37
41
  var generation = generationRef.current;
38
42
  timerRef.current = window.setTimeout(function () {
39
43
  var _rootRef$current;
40
- if ((_rootRef$current = rootRef.current) !== null && _rootRef$current !== void 0 && _rootRef$current.contains(document.activeElement)) return;
44
+ // blur 后 activeElement 仍在本格通常是窗口切走或格内弹层切焦点,不算离开。
45
+ // 指针明确点到本格/其弹层之外时,即使目标不可聚焦导致 activeElement 没变,也应离开。
46
+ if (!pointerLeftScope && (_rootRef$current = rootRef.current) !== null && _rootRef$current !== void 0 && _rootRef$current.contains(document.activeElement)) return;
41
47
  onLeaveRef.current(function () {
42
48
  return generation !== generationRef.current;
43
- });
49
+ }, hadFocus);
44
50
  }, 0);
51
+ }, [cancel]);
52
+ var handleFocus = function handleFocus() {
53
+ focusWithinRef.current = true;
54
+ cancel();
45
55
  };
56
+ var handleBlur = function handleBlur() {
57
+ var hadFocus = focusWithinRef.current;
58
+ focusWithinRef.current = false;
59
+ scheduleLeave(false, hadFocus);
60
+ };
61
+ var handlePointerDownCapture = function handlePointerDownCapture(event) {
62
+ pointerEventsInScopeRef.current.add(event.nativeEvent);
63
+ };
64
+ useEffect(function () {
65
+ var handleDocumentPointerDown = function handleDocumentPointerDown(event) {
66
+ var root = rootRef.current;
67
+ if (!root) return;
68
+ var target = event.target;
69
+ // DOM 内点击以及 React portal 子树内点击都属于当前格的交互。
70
+ if (target instanceof Node && root.contains(target) || pointerEventsInScopeRef.current.has(event)) return;
71
+ // 新增行的必填空格也会预先挂载控件,但可能从未获得焦点;同样需要响应离开,
72
+ // 由 onLeave 根据 hadFocus 决定是否校验未触碰的空必填格。@author nokecy
73
+ scheduleLeave(true, focusWithinRef.current);
74
+ };
75
+ document.addEventListener('pointerdown', handleDocumentPointerDown);
76
+ return function () {
77
+ document.removeEventListener('pointerdown', handleDocumentPointerDown);
78
+ cancel();
79
+ };
80
+ }, [cancel, scheduleLeave]);
46
81
  return /*#__PURE__*/React.createElement("div", {
47
82
  ref: rootRef,
48
83
  style: {
49
84
  display: 'contents'
50
85
  },
51
- onFocus: cancel,
52
- onBlur: handleBlur
86
+ onFocus: handleFocus,
87
+ onBlur: handleBlur,
88
+ onPointerDownCapture: handlePointerDownCapture
53
89
  }, children);
54
90
  };
@@ -1,10 +1,10 @@
1
- function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
1
  function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
3
2
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4
3
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
5
4
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
5
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
7
6
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
8
8
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
9
9
  function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
10
10
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
@@ -34,7 +34,6 @@ import { useGridSchemes } from "../ag-grid-plus";
34
34
 
35
35
  //@ts-ignore
36
36
  var ArrayTableInner = observer(function (props) {
37
- var _addition$props;
38
37
  var height = props.height,
39
38
  gridKey = props.gridKey;
40
39
  var arrayTableTheme = useArrayTableTheme(true);
@@ -310,21 +309,39 @@ var ArrayTableInner = observer(function (props) {
310
309
  style: {
311
310
  marginBottom: 5
312
311
  }
313
- }, addition ? /*#__PURE__*/React.createElement(ArrayAddBtn, _extends({
314
- title: "新增",
315
- onAdd: function onAdd() {
316
- setIsAdd(true);
317
- }
318
- }, addition.props, {
319
- // 框架关键属性钉在 spread 之后:不可被 addition.props 覆盖;
320
- // defaultValue 合并自定义字段但始终携带 _id/_isNew 标记。@author nokecy
321
- arrayField: field,
322
- schema: schema,
323
- defaultValue: _objectSpread({
324
- _id: uniqueId(),
325
- _isNew: true
326
- }, ((_addition$props = addition.props) === null || _addition$props === void 0 ? void 0 : _addition$props.defaultValue) || {})
327
- })) : null, actions.map(function (column, key) {
312
+ }, addition ? function (_addition$props, _additionSchema$xCom, _ref, _additionProps$title, _additionProps$method) {
313
+ // addition 是 RecursionField 元素;业务配置在其 schema.x-component-props 中,
314
+ // 不能从 React 元素的 props 直接读取,否则默认值和标题会丢失。@author nokecy
315
+ var additionSchema = (_addition$props = addition.props) === null || _addition$props === void 0 ? void 0 : _addition$props.schema;
316
+ var additionProps = (_additionSchema$xCom = additionSchema === null || additionSchema === void 0 ? void 0 : additionSchema['x-component-props']) !== null && _additionSchema$xCom !== void 0 ? _additionSchema$xCom : {};
317
+ var configuredDefaults = additionProps.defaultValue;
318
+ var rowDefaults = configuredDefaults && _typeof(configuredDefaults) === 'object' && !Array.isArray(configuredDefaults) ? configuredDefaults : {};
319
+ return /*#__PURE__*/React.createElement(ArrayAddBtn, _extends({}, additionProps, {
320
+ title: (_ref = (_additionProps$title = additionProps.title) !== null && _additionProps$title !== void 0 ? _additionProps$title : additionSchema === null || additionSchema === void 0 ? void 0 : additionSchema.title) !== null && _ref !== void 0 ? _ref : '新增'
321
+ // 新增行总是回到数组顺序,避免当前列排序把空白新行插到旧明细前面。
322
+ ,
323
+ onAdd: function onAdd(index) {
324
+ var _apiRef$current;
325
+ setIsAdd(true);
326
+ (_apiRef$current = apiRef.current) === null || _apiRef$current === void 0 || _apiRef$current.applyColumnState({
327
+ defaultState: {
328
+ sort: null,
329
+ sortIndex: null
330
+ }
331
+ });
332
+ if (typeof additionProps.onAdd === 'function') additionProps.onAdd(index);
333
+ }
334
+ // 框架属性在业务配置之后设置;新行默认追加到明细末尾。@author nokecy
335
+ ,
336
+ method: (_additionProps$method = additionProps.method) !== null && _additionProps$method !== void 0 ? _additionProps$method : 'push',
337
+ arrayField: field,
338
+ schema: schema,
339
+ defaultValue: _objectSpread({
340
+ _id: uniqueId(),
341
+ _isNew: true
342
+ }, rowDefaults)
343
+ }));
344
+ }() : null, actions.map(function (column, key) {
328
345
  return /*#__PURE__*/React.createElement(RecursionField, {
329
346
  schema: column.schema,
330
347
  name: key,
@@ -389,8 +406,8 @@ var ArrayTableInner = observer(function (props) {
389
406
  });
390
407
  }
391
408
  if (isAdd) {
392
- var _apiRef$current;
393
- (_apiRef$current = apiRef.current) === null || _apiRef$current === void 0 || _apiRef$current.ensureIndexVisible(dataSource.length - 1, "bottom");
409
+ var _apiRef$current2;
410
+ (_apiRef$current2 = apiRef.current) === null || _apiRef$current2 === void 0 || _apiRef$current2.ensureIndexVisible(dataSource.length - 1, "bottom");
394
411
  setIsAdd(false);
395
412
  }
396
413
  },
@@ -412,9 +429,9 @@ var ArrayTableInner = observer(function (props) {
412
429
  ' <span data-ref="eSortAsc" class="ag-header-icon ag-sort-ascending-icon"></span>' + ' <span data-ref="eSortDesc" class="ag-header-icon ag-sort-descending-icon"></span>' + ' <span data-ref="eSortNone" class="ag-header-icon ag-sort-none-icon"></span>' + " </div>" + "</div>"
413
430
  }
414
431
  },
415
- getRowId: function getRowId(_ref) {
432
+ getRowId: function getRowId(_ref2) {
416
433
  var _data$_id;
417
- var data = _ref.data;
434
+ var data = _ref2.data;
418
435
  var id = (_data$_id = data === null || data === void 0 ? void 0 : data._id) !== null && _data$_id !== void 0 ? _data$_id : data === null || data === void 0 ? void 0 : data.id;
419
436
  if (id != null) return String(id);
420
437
  // 既无 _id 也无 id 的外部数据:按对象引用从 WeakMap 取/分配稳定 id。
@@ -6,7 +6,8 @@ var containsIndexComponent = function containsIndexComponent(schema) {
6
6
  var _schema$properties;
7
7
  if (!schema) return false;
8
8
  var component = schema['x-component'];
9
- if (typeof component === 'string' && /(?:^|\.)Index$/.test(component)) return true;
9
+ // ArrayTable.Index / ArrayBase.Index,以及业务常用的 ArrayTableIndex(还会把行号写进数据字段)
10
+ if (typeof component === 'string' && /(?:^|\.)(?:Array(?:Table)?)?Index$/.test(component)) return true;
10
11
  return Object.values((_schema$properties = schema.properties) !== null && _schema$properties !== void 0 ? _schema$properties : {}).some(containsIndexComponent);
11
12
  };
12
13
 
@@ -376,52 +376,60 @@ var LazyAgField = function LazyAgField(params) {
376
376
  // 内层字段名:Column key 与它可能不一致(设计器形态),取值/找字段节点都按它
377
377
  var dataKey = (_fieldSchema$name = fieldSchema === null || fieldSchema === void 0 ? void 0 : fieldSchema.name) !== null && _fieldSchema$name !== void 0 ? _fieldSchema$name : colDef === null || colDef === void 0 ? void 0 : colDef.field;
378
378
 
379
- /** 焦点离开本格:校验通过才卸回懒挂载文本。isStale 为真说明校验期间焦点又回来了或格子已销毁 */
379
+ /** 离开本格:校验通过才卸回懒挂载文本。未触碰的空必填格保留控件等待填写。@author nokecy */
380
380
  var handleLeave = /*#__PURE__*/function () {
381
- var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(isStale) {
381
+ var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(isStale, hadFocus) {
382
382
  var _field$value$indexOf3, _field$value3, _field$value3$indexOf, _field$form;
383
- var index, cellField;
383
+ var currentValue, index, cellField;
384
384
  return _regeneratorRuntime().wrap(function _callee$(_context) {
385
385
  while (1) switch (_context.prev = _context.next) {
386
386
  case 0:
387
+ currentValue = dataKey != null ? readByFieldPath(record, dataKey) : value; // 新增行的必填空格会预先挂载以参与提交校验;若用户从未进入该格,不在点击页面其他位置时
388
+ // 主动触发校验,但已带值的格子仍可恢复静默文本态。@author nokecy
389
+ if (!(required && isBlank(currentValue) && !hadFocus)) {
390
+ _context.next = 3;
391
+ break;
392
+ }
393
+ return _context.abrupt("return");
394
+ case 3:
387
395
  index = (_field$value$indexOf3 = field === null || field === void 0 || (_field$value3 = field.value) === null || _field$value3 === void 0 || (_field$value3$indexOf = _field$value3.indexOf) === null || _field$value3$indexOf === void 0 ? void 0 : _field$value3$indexOf.call(_field$value3, record)) !== null && _field$value$indexOf3 !== void 0 ? _field$value$indexOf3 : -1; // 字段节点按数据路径找(不含 void 容器);从没挂载过就没有节点,无需校验
388
396
  cellField = index >= 0 && dataKey ? (_field$form = field.form) === null || _field$form === void 0 ? void 0 : _field$form.query(field.path.concat(index).concat(dataKey)).take() : undefined;
389
397
  if (!cellField) {
390
- _context.next = 11;
398
+ _context.next = 14;
391
399
  break;
392
400
  }
393
- _context.prev = 3;
394
- _context.next = 6;
401
+ _context.prev = 6;
402
+ _context.next = 9;
395
403
  return cellField.validate();
396
- case 6:
397
- _context.next = 11;
404
+ case 9:
405
+ _context.next = 14;
398
406
  break;
399
- case 8:
400
- _context.prev = 8;
401
- _context.t0 = _context["catch"](3);
402
- return _context.abrupt("return");
403
407
  case 11:
408
+ _context.prev = 11;
409
+ _context.t0 = _context["catch"](6);
410
+ return _context.abrupt("return");
411
+ case 14:
404
412
  if (!isStale()) {
405
- _context.next = 13;
413
+ _context.next = 16;
406
414
  break;
407
415
  }
408
416
  return _context.abrupt("return");
409
- case 13:
417
+ case 16:
410
418
  if (!(required && isBlank(dataKey != null ? readByFieldPath(record, dataKey) : undefined))) {
411
- _context.next = 15;
419
+ _context.next = 18;
412
420
  break;
413
421
  }
414
422
  return _context.abrupt("return");
415
- case 15:
423
+ case 18:
416
424
  activeCells.delete(key);
417
425
  rerender();
418
- case 17:
426
+ case 20:
419
427
  case "end":
420
428
  return _context.stop();
421
429
  }
422
- }, _callee, null, [[3, 8]]);
430
+ }, _callee, null, [[6, 11]]);
423
431
  }));
424
- return function handleLeave(_x) {
432
+ return function handleLeave(_x, _x2) {
425
433
  return _ref5.apply(this, arguments);
426
434
  };
427
435
  }();
@@ -794,7 +802,6 @@ var useAddition = function useAddition() {
794
802
  }, null);
795
803
  };
796
804
  export { isColumnComponent, useArrayTableSources, useArrayTableActions, buildArrayTableColumns, useAddition, LazyAgField, LazyReadOnlyText };
797
-
798
805
  /** 简单字段名(非路径、非解构),默认值回填只处理这一种 */
799
806
  var SIMPLE_FIELD_NAME = /^[A-Za-z_$][\w$]*$/;
800
807
  /**
@@ -7,8 +7,9 @@
7
7
  display: inline-flex;
8
8
  align-items: center;
9
9
  justify-content: center;
10
- width: 100%;
11
- height: 100%;
10
+ width: 24px;
11
+ height: 24px;
12
+ font-size: 16px;
12
13
  cursor: pointer;
13
14
  pointer-events: auto;
14
15
  color: var(--qc-dialog-select-trigger-color, rgba(0, 0, 0, 0.45));
@@ -19,18 +20,24 @@
19
20
  }
20
21
  }
21
22
 
23
+ // 为放大后的入口预留文本空间,避免选中值与图标重叠。
24
+ &.ant-select-single:not(.ant-select-allow-clear) .ant-select-selection-item,
25
+ &.ant-select-single:not(.ant-select-allow-clear) .ant-select-selection-placeholder {
26
+ padding-inline-end: 24px;
27
+ }
28
+
22
29
  // 悬停时 antd 会把后缀淡出、换成清除图标;这里让入口始终可见,清除图标左移一格并排。
23
30
  &.ant-select.ant-select:hover .ant-select-arrow:not(:last-child) {
24
31
  opacity: 1;
25
32
  }
26
33
 
27
34
  &.ant-select-allow-clear .ant-select-clear {
28
- inset-inline-end: 31px;
35
+ inset-inline-end: 37px;
29
36
  }
30
37
 
31
38
  &.ant-select-allow-clear .ant-select-selection-item,
32
39
  &.ant-select-allow-clear .ant-select-selection-placeholder {
33
- padding-inline-end: 36px;
40
+ padding-inline-end: 42px;
34
41
  }
35
42
 
36
43
  &.ant-select-multiple .ant-select-selector {
@@ -39,24 +39,31 @@ var DraggableModal = function DraggableModal(props) {
39
39
  _useState6 = _slicedToArray(_useState5, 2),
40
40
  isResizing = _useState6[0],
41
41
  setIsResizing = _useState6[1];
42
- var _useState7 = useState(''),
43
- _useState8 = _slicedToArray(_useState7, 2),
44
- resizeDirection = _useState8[0],
45
- setResizeDirection = _useState8[1];
46
- var _useState9 = useState({
42
+ var _useState7 = useState({
47
43
  width: 0,
48
44
  height: 0
49
45
  }),
50
- _useState10 = _slicedToArray(_useState9, 2),
51
- modalSize = _useState10[0],
52
- setModalSize = _useState10[1];
53
- var _useState11 = useState({
46
+ _useState8 = _slicedToArray(_useState7, 2),
47
+ modalSize = _useState8[0],
48
+ setModalSize = _useState8[1];
49
+ var _useState9 = useState({
54
50
  x: 0,
55
51
  y: 0
56
52
  }),
53
+ _useState10 = _slicedToArray(_useState9, 2),
54
+ modalPosition = _useState10[0],
55
+ setModalPosition = _useState10[1];
56
+ var _useState11 = useState(false),
57
57
  _useState12 = _slicedToArray(_useState11, 2),
58
- modalPosition = _useState12[0],
59
- setModalPosition = _useState12[1];
58
+ hasResized = _useState12[0],
59
+ setHasResized = _useState12[1];
60
+ var _useState13 = useState({
61
+ x: 0,
62
+ y: 0
63
+ }),
64
+ _useState14 = _slicedToArray(_useState13, 2),
65
+ dragPosition = _useState14[0],
66
+ setDragPosition = _useState14[1];
60
67
 
61
68
  // 解构 props,分离出 wrapClassName 和 open
62
69
  var propsWrapClassName = props.wrapClassName,
@@ -80,6 +87,25 @@ var DraggableModal = function DraggableModal(props) {
80
87
  if (timer !== undefined) clearTimeout(timer);
81
88
  };
82
89
  }, [open]);
90
+
91
+ // 每次关闭后还原弹窗定位;下次打开仍按调用方传入的默认尺寸居中显示。@author nokecy
92
+ useEffect(function () {
93
+ if (open) return;
94
+ setIsResizing(false);
95
+ setHasResized(false);
96
+ setModalSize({
97
+ width: 0,
98
+ height: 0
99
+ });
100
+ setModalPosition({
101
+ x: 0,
102
+ y: 0
103
+ });
104
+ setDragPosition({
105
+ x: 0,
106
+ y: 0
107
+ });
108
+ }, [open]);
83
109
  var _onStart = function onStart(_event, uiData) {
84
110
  var _draggleRef$current;
85
111
  var _window$document$docu = window.document.documentElement,
@@ -117,7 +143,12 @@ var DraggableModal = function DraggableModal(props) {
117
143
  x: rect.left,
118
144
  y: rect.top
119
145
  });
120
- setResizeDirection(direction);
146
+ setHasResized(true);
147
+ // 将当前视觉位置作为新定位基点,避免弹窗自身和 react-draggable 位移重复叠加。@author nokecy
148
+ setDragPosition({
149
+ x: 0,
150
+ y: 0
151
+ });
121
152
  setIsResizing(true);
122
153
  var startX = e.clientX;
123
154
  var startY = e.clientY;
@@ -130,30 +161,28 @@ var DraggableModal = function DraggableModal(props) {
130
161
  var deltaY = moveEvent.clientY - startY;
131
162
  var newWidth = startWidth;
132
163
  var newHeight = startHeight;
133
- var newLeft = startLeft;
134
- var newTop = startTop;
135
164
 
136
165
  // 根据方向计算新尺寸
137
166
  if (direction.includes('e')) {
138
- newWidth = Math.max(400, startWidth + deltaX);
167
+ newWidth = startWidth + deltaX;
139
168
  }
140
169
  if (direction.includes('w')) {
141
- newWidth = Math.max(400, startWidth - deltaX);
142
- newLeft = startLeft + (startWidth - newWidth);
170
+ newWidth = startWidth - deltaX;
143
171
  }
144
172
  if (direction.includes('s')) {
145
- newHeight = Math.max(300, startHeight + deltaY);
173
+ newHeight = startHeight + deltaY;
146
174
  }
147
175
  if (direction.includes('n')) {
148
- newHeight = Math.max(300, startHeight - deltaY);
149
- newTop = startTop + (startHeight - newHeight);
176
+ newHeight = startHeight - deltaY;
150
177
  }
151
178
 
152
- // 限制最大尺寸
179
+ // 限制最小与最大尺寸,再按固定边计算另一侧位置,确保拖哪条边就移动哪条边。@author nokecy
153
180
  var maxWidth = window.innerWidth * 0.95;
154
181
  var maxHeight = window.innerHeight * 0.95;
155
- newWidth = Math.min(newWidth, maxWidth);
156
- newHeight = Math.min(newHeight, maxHeight);
182
+ newWidth = Math.min(Math.max(400, newWidth), maxWidth);
183
+ newHeight = Math.min(Math.max(300, newHeight), maxHeight);
184
+ var newLeft = direction.includes('w') ? startLeft + startWidth - newWidth : startLeft;
185
+ var newTop = direction.includes('n') ? startTop + startHeight - newHeight : startTop;
157
186
 
158
187
  // 直接更新DOM以实现实时效果
159
188
  modal.style.width = "".concat(newWidth, "px");
@@ -182,7 +211,6 @@ var DraggableModal = function DraggableModal(props) {
182
211
  };
183
212
  var handleMouseUp = function handleMouseUp() {
184
213
  setIsResizing(false);
185
- setResizeDirection('');
186
214
  document.removeEventListener('mousemove', handleMouseMove);
187
215
  document.removeEventListener('mouseup', handleMouseUp);
188
216
 
@@ -197,7 +225,8 @@ var DraggableModal = function DraggableModal(props) {
197
225
 
198
226
  // 合并类名
199
227
  var resizingClass = isResizing ? 'modal-wrap-resizing' : '';
200
- var mergedWrapClassName = [propsWrapClassName, resizingClass].filter(Boolean).join(' ');
228
+ var resizedClass = hasResized ? 'modal-wrap-resized' : '';
229
+ var mergedWrapClassName = [propsWrapClassName, resizingClass, resizedClass].filter(Boolean).join(' ');
201
230
  return /*#__PURE__*/React.createElement(Modal, _extends({
202
231
  maskClosable: false,
203
232
  width: width,
@@ -223,18 +252,27 @@ var DraggableModal = function DraggableModal(props) {
223
252
  }, props.title),
224
253
  modalRender: function modalRender(modal) {
225
254
  return /*#__PURE__*/React.createElement(Draggable, {
226
- disabled: disabled,
255
+ disabled: disabled || isResizing,
227
256
  bounds: bounds,
257
+ position: dragPosition,
228
258
  nodeRef: draggleRef,
229
259
  onStart: function onStart(event, uiData) {
230
260
  return _onStart(event, uiData);
231
261
  },
262
+ onDrag: function onDrag(_event, uiData) {
263
+ return setDragPosition({
264
+ x: uiData.x,
265
+ y: uiData.y
266
+ });
267
+ },
232
268
  cancel: ".resize-handle"
233
269
  }, /*#__PURE__*/React.createElement("div", {
234
270
  ref: draggleRef,
235
- style: isResizing && modalSize.width > 0 ? {
236
- position: 'relative',
237
- height: '100%',
271
+ style: hasResized && modalSize.width > 0 ? {
272
+ position: 'fixed',
273
+ left: modalPosition.x,
274
+ top: modalPosition.y,
275
+ height: "".concat(modalSize.height, "px"),
238
276
  width: "".concat(modalSize.width, "px"),
239
277
  '--modal-width': "".concat(modalSize.width, "px"),
240
278
  '--modal-height': "".concat(modalSize.height, "px")
@@ -1,6 +1,11 @@
1
1
  :global {
2
- .modal-wrap-resizing {
2
+ .modal-wrap-resizing,
3
+ .modal-wrap-resized {
3
4
  .ant-modal {
5
+ position: absolute;
6
+ left: 0 !important;
7
+ top: 0 !important;
8
+ margin: 0 !important;
4
9
  width: var(--modal-width) !important;
5
10
  transition: none;
6
11
  }