@canvas-components/react-maintop-pattern 0.0.0-stage → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,3623 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var React = require('react');
6
+ var reactComponents = require('@canvas-components/react-components');
7
+ var ahooks = require('ahooks');
8
+ var jsxRuntime = require('react/jsx-runtime');
9
+ var maintopPattern = require('@canvas-components/maintop-pattern');
10
+ var reactListTable = require('@canvas-components/react-list-table');
11
+
12
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
+
14
+ var React__default = /*#__PURE__*/_interopDefault(React);
15
+
16
+ // src/components/drawing-board.tsx
17
+
18
+ // src/styles.ts
19
+ var STYLES = {
20
+ rulerWrapper: {
21
+ borderRadius: "4px",
22
+ overflow: "hidden",
23
+ backgroundColor: "#fff",
24
+ height: "650px",
25
+ flex: 1,
26
+ minWidth: 0,
27
+ position: "relative",
28
+ cursor: "grab",
29
+ // overscrollBehavior: 'contain' as const,
30
+ userSelect: "none"
31
+ },
32
+ boardWrapper: {
33
+ width: "100%",
34
+ overflow: "hidden"
35
+ },
36
+ gridContainer: {
37
+ flex: 1,
38
+ minWidth: 0
39
+ },
40
+ gridHeader: {
41
+ display: "flex",
42
+ flexDirection: "row",
43
+ alignItems: "flex-start",
44
+ width: "100%",
45
+ minWidth: 0
46
+ },
47
+ canvas: {
48
+ display: "block"
49
+ }};
50
+ var ICON_PATHS = {
51
+ aim: [
52
+ "M952 474H829.8C812.5 327.6 696.4 211.5 550 194.2V72c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v122.2C327.6 211.5 211.5 327.6 194.2 474H72c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h122.2C211.5 696.4 327.6 812.5 474 829.8V952c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V829.8C696.4 812.5 812.5 696.4 829.8 550H952c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8zM512 756c-134.8 0-244-109.2-244-244s109.2-244 244-244 244 109.2 244 244-109.2 244-244 244z",
53
+ "M512 392c-32.1 0-62.1 12.4-84.8 35.2-22.7 22.7-35.2 52.7-35.2 84.8s12.5 62.1 35.2 84.8C449.9 619.4 480 632 512 632s62.1-12.5 84.8-35.2C619.4 574.1 632 544 632 512s-12.5-62.1-35.2-84.8A118.57 118.57 0 00512 392z"
54
+ ],
55
+ arrowsAlt: [
56
+ "M855 160.1l-189.2 23.5c-6.6.8-9.3 8.8-4.7 13.5l54.7 54.7-153.5 153.5a8.03 8.03 0 000 11.3l45.1 45.1c3.1 3.1 8.2 3.1 11.3 0l153.6-153.6 54.7 54.7a7.94 7.94 0 0013.5-4.7L863.9 169a7.9 7.9 0 00-8.9-8.9zM416.6 562.3a8.03 8.03 0 00-11.3 0L251.8 715.9l-54.7-54.7a7.94 7.94 0 00-13.5 4.7L160.1 855c-.6 5.2 3.7 9.5 8.9 8.9l189.2-23.5c6.6-.8 9.3-8.8 4.7-13.5l-54.7-54.7 153.6-153.6c3.1-3.1 3.1-8.2 0-11.3l-45.2-45z"
57
+ ],
58
+ borderInner: [
59
+ "M872 476H548V144h-72v332H152c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h324v332h72V548h324c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0-166h-56c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 498h-56c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0-664h-56c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 498h-56c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM650 216h56c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm56 592h-56c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm-332 0h-56c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm-56-592h56c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-166 0h56c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm56 592h-56c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm-56-426h56c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm56 260h-56c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8z"
60
+ ],
61
+ clear: [
62
+ "M899.1 869.6l-53-305.6H864c14.4 0 26-11.6 26-26V346c0-14.4-11.6-26-26-26H618V138c0-14.4-11.6-26-26-26H432c-14.4 0-26 11.6-26 26v182H160c-14.4 0-26 11.6-26 26v192c0 14.4 11.6 26 26 26h17.9l-53 305.6a25.95 25.95 0 0025.6 30.4h723c1.5 0 3-.1 4.4-.4a25.88 25.88 0 0021.2-30zM204 390h272V182h72v208h272v104H204V390zm468 440V674c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v156H416V674c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v156H202.8l45.1-260H776l45.1 260H672z"
63
+ ],
64
+ closeCircle: [
65
+ "M512 64c247.4 0 448 200.6 448 448S759.4 960 512 960 64 759.4 64 512 264.6 64 512 64zm0 76c-205.4 0-372 166.6-372 372s166.6 372 372 372 372-166.6 372-372-166.6-372-372-372zm128.01 198.83c.03 0 .05.01.09.06l45.02 45.01a.2.2 0 01.05.09.12.12 0 010 .07c0 .02-.01.04-.05.08L557.25 512l127.87 127.86a.27.27 0 01.05.06v.02a.12.12 0 010 .07c0 .03-.01.05-.05.09l-45.02 45.02a.2.2 0 01-.09.05.12.12 0 01-.07 0c-.02 0-.04-.01-.08-.05L512 557.25 384.14 685.12c-.04.04-.06.05-.08.05a.12.12 0 01-.07 0c-.03 0-.05-.01-.09-.05l-45.02-45.02a.2.2 0 01-.05-.09.12.12 0 010-.07c0-.02.01-.04.06-.08L466.75 512 338.88 384.14a.27.27 0 01-.05-.06l-.01-.02a.12.12 0 010-.07c0-.03.01-.05.05-.09l45.02-45.02a.2.2 0 01.09-.05.12.12 0 01.07 0c.02 0 .04.01.08.06L512 466.75l127.86-127.86c.04-.05.06-.06.08-.06a.12.12 0 01.07 0z"
66
+ ],
67
+ closeSquare: [
68
+ "M880 112c17.7 0 32 14.3 32 32v736c0 17.7-14.3 32-32 32H144c-17.7 0-32-14.3-32-32V144c0-17.7 14.3-32 32-32zm-40 72H184v656h656V184zM640.01 338.83c.03 0 .05.01.09.06l45.02 45.01a.2.2 0 01.05.09.12.12 0 010 .07c0 .02-.01.04-.05.08L557.25 512l127.87 127.86a.27.27 0 01.05.06v.02a.12.12 0 010 .07c0 .03-.01.05-.05.09l-45.02 45.02a.2.2 0 01-.09.05.12.12 0 01-.07 0c-.02 0-.04-.01-.08-.05L512 557.25 384.14 685.12c-.04.04-.06.05-.08.05a.12.12 0 01-.07 0c-.03 0-.05-.01-.09-.05l-45.02-45.02a.2.2 0 01-.05-.09.12.12 0 010-.07c0-.02.01-.04.06-.08L466.75 512 338.88 384.14a.27.27 0 01-.05-.06l-.01-.02a.12.12 0 010-.07c0-.03.01-.05.05-.09l45.02-45.02a.2.2 0 01.09-.05.12.12 0 01.07 0c.02 0 .04.01.08.06L512 466.75l127.86-127.86c.04-.05.06-.06.08-.06a.12.12 0 01.07 0z"
69
+ ],
70
+ copy: [
71
+ "M832 64H296c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h496v688c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V96c0-17.7-14.3-32-32-32zM704 192H192c-17.7 0-32 14.3-32 32v530.7c0 8.5 3.4 16.6 9.4 22.6l173.3 173.3c2.2 2.2 4.7 4 7.4 5.5v1.9h4.2c3.5 1.3 7.2 2 11 2H704c17.7 0 32-14.3 32-32V224c0-17.7-14.3-32-32-32zM350 856.2L263.9 770H350v86.2zM664 888H414V746c0-22.1-17.9-40-40-40H232V264h432v624z"
72
+ ],
73
+ delete: [
74
+ "M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"
75
+ ],
76
+ diff: [
77
+ "M476 399.1c0-3.9-3.1-7.1-7-7.1h-42c-3.8 0-7 3.2-7 7.1V484h-84.5c-4.1 0-7.5 3.1-7.5 7v42c0 3.8 3.4 7 7.5 7H420v84.9c0 3.9 3.2 7.1 7 7.1h42c3.9 0 7-3.2 7-7.1V540h84.5c4.1 0 7.5-3.2 7.5-7v-42c0-3.9-3.4-7-7.5-7H476v-84.9zM560.5 704h-225c-4.1 0-7.5 3.2-7.5 7v42c0 3.8 3.4 7 7.5 7h225c4.1 0 7.5-3.2 7.5-7v-42c0-3.8-3.4-7-7.5-7zm-7.1-502.6c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v704c0 17.7 14.3 32 32 32h512c17.7 0 32-14.3 32-32V397.3c0-8.5-3.4-16.6-9.4-22.6L553.4 201.4zM664 888H232V264h282.2L664 413.8V888zm190.2-581.4L611.3 72.9c-6-5.7-13.9-8.9-22.2-8.9H296c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h277l219 210.6V824c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V329.6c0-8.7-3.5-17-9.8-23z"
78
+ ],
79
+ edit: [
80
+ "M257.7 752c2 0 4-.2 6-.5L431.9 722c2-.4 3.9-1.3 5.3-2.8l423.9-423.9a9.96 9.96 0 000-14.1L694.9 114.9c-1.9-1.9-4.4-2.9-7.1-2.9s-5.2 1-7.1 2.9L256.8 538.8c-1.5 1.5-2.4 3.3-2.8 5.3l-29.5 168.2a33.5 33.5 0 009.4 29.8c6.6 6.4 14.9 9.9 23.8 9.9zm67.4-174.4L687.8 215l73.3 73.3-362.7 362.6-88.9 15.7 15.6-89zM880 836H144c-17.7 0-32 14.3-32 32v36c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-36c0-17.7-14.3-32-32-32z"
81
+ ],
82
+ eye: [
83
+ "M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"
84
+ ],
85
+ history: [
86
+ "M536.1 273H488c-4.4 0-8 3.6-8 8v275.3c0 2.6 1.2 5 3.3 6.5l165.3 120.7c3.6 2.6 8.6 1.9 11.2-1.7l28.6-39c2.7-3.7 1.9-8.7-1.7-11.2L544.1 528.5V281c0-4.4-3.6-8-8-8zm219.8 75.2l156.8 38.3c5 1.2 9.9-2.6 9.9-7.7l.8-161.5c0-6.7-7.7-10.5-12.9-6.3L752.9 334.1a8 8 0 003 14.1zm167.7 301.1l-56.7-19.5a8 8 0 00-10.1 4.8c-1.9 5.1-3.9 10.1-6 15.1-17.8 42.1-43.3 80-75.9 112.5a353 353 0 01-112.5 75.9 352.18 352.18 0 01-137.7 27.8c-47.8 0-94.1-9.3-137.7-27.8a353 353 0 01-112.5-75.9c-32.5-32.5-58-70.4-75.9-112.5A353.44 353.44 0 01171 512c0-47.8 9.3-94.2 27.8-137.8 17.8-42.1 43.3-80 75.9-112.5a353 353 0 01112.5-75.9C430.6 167.3 477 158 524.8 158s94.1 9.3 137.7 27.8A353 353 0 01775 261.7c10.2 10.3 19.8 21 28.6 32.3l59.8-46.8C784.7 146.6 662.2 81.9 524.6 82 285 82.1 92.6 276.7 95 516.4 97.4 751.9 288.9 942 524.8 942c185.5 0 343.5-117.6 403.7-282.3 1.5-4.2-.7-8.9-4.9-10.4z"
87
+ ],
88
+ mergeCells: [
89
+ "M482.2 508.4L331.3 389c-3-2.4-7.3-.2-7.3 3.6V478H184V184h204v128c0 2.2 1.8 4 4 4h60c2.2 0 4-1.8 4-4V144c0-15.5-12.5-28-28-28H144c-15.5 0-28 12.5-28 28v736c0 15.5 12.5 28 28 28h284c15.5 0 28-12.5 28-28V712c0-2.2-1.8-4-4-4h-60c-2.2 0-4 1.8-4 4v128H184V546h140v85.4c0 3.8 4.4 6 7.3 3.6l150.9-119.4a4.5 4.5 0 000-7.2zM880 116H596c-15.5 0-28 12.5-28 28v168c0 2.2 1.8 4 4 4h60c2.2 0 4-1.8 4-4V184h204v294H700v-85.4c0-3.8-4.3-6-7.3-3.6l-151 119.4a4.52 4.52 0 000 7.1l151 119.5c2.9 2.3 7.3.2 7.3-3.6V546h140v294H636V712c0-2.2-1.8-4-4-4h-60c-2.2 0-4 1.8-4 4v168c0 15.5 12.5 28 28 28h284c15.5 0 28-12.5 28-28V144c0-15.5-12.5-28-28-28z"
90
+ ],
91
+ plusCircle: [
92
+ "M696 480H544V328c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v152H328c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h152v152c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V544h152c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8z",
93
+ "M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
94
+ ],
95
+ redo: [
96
+ "M758.2 839.1C851.8 765.9 912 651.9 912 523.9 912 303 733.5 124.3 512.6 124 291.4 123.7 112 302.8 112 523.9c0 125.2 57.5 236.9 147.6 310.2 3.5 2.8 8.6 2.2 11.4-1.3l39.4-50.5c2.7-3.4 2.1-8.3-1.2-11.1-8.1-6.6-15.9-13.7-23.4-21.2a318.64 318.64 0 01-68.6-101.7C200.4 609 192 567.1 192 523.9s8.4-85.1 25.1-124.5c16.1-38.1 39.2-72.3 68.6-101.7 29.4-29.4 63.6-52.5 101.7-68.6C426.9 212.4 468.8 204 512 204s85.1 8.4 124.5 25.1c38.1 16.1 72.3 39.2 101.7 68.6 29.4 29.4 52.5 63.6 68.6 101.7 16.7 39.4 25.1 81.3 25.1 124.5s-8.4 85.1-25.1 124.5a318.64 318.64 0 01-68.6 101.7c-9.3 9.3-19.1 18-29.3 26L668.2 724a8 8 0 00-14.1 3l-39.6 162.2c-1.2 5 2.6 9.9 7.7 9.9l167 .8c6.7 0 10.5-7.7 6.3-12.9l-37.3-47.9z"
97
+ ],
98
+ scissor: [
99
+ "M567.1 512l318.5-319.3c5-5 1.5-13.7-5.6-13.7h-90.5c-2.1 0-4.2.8-5.6 2.3l-273.3 274-90.2-90.5c12.5-22.1 19.7-47.6 19.7-74.8 0-83.9-68.1-152-152-152s-152 68.1-152 152 68.1 152 152 152c27.7 0 53.6-7.4 75.9-20.3l90 90.3-90.1 90.3A151.04 151.04 0 00288 582c-83.9 0-152 68.1-152 152s68.1 152 152 152 152-68.1 152-152c0-27.2-7.2-52.7-19.7-74.8l90.2-90.5 273.3 274c1.5 1.5 3.5 2.3 5.6 2.3H880c7.1 0 10.7-8.6 5.6-13.7L567.1 512zM288 370c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80zm0 444c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z"
100
+ ],
101
+ select: [
102
+ "M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h360c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H184V184h656v320c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V144c0-17.7-14.3-32-32-32zM653.3 599.4l52.2-52.2a8.01 8.01 0 00-4.7-13.6l-179.4-21c-5.1-.6-9.5 3.7-8.9 8.9l21 179.4c.8 6.6 8.9 9.4 13.6 4.7l52.4-52.4 256.2 256.2c3.1 3.1 8.2 3.1 11.3 0l42.4-42.4c3.1-3.1 3.1-8.2 0-11.3L653.3 599.4z"
103
+ ],
104
+ shrink: [
105
+ "M881.7 187.4l-45.1-45.1a8.03 8.03 0 00-11.3 0L667.8 299.9l-54.7-54.7a7.94 7.94 0 00-13.5 4.7L576.1 439c-.6 5.2 3.7 9.5 8.9 8.9l189.2-23.5c6.6-.8 9.3-8.8 4.7-13.5l-54.7-54.7 157.6-157.6c3-3 3-8.1-.1-11.2zM439 576.1l-189.2 23.5c-6.6.8-9.3 8.9-4.7 13.5l54.7 54.7-157.5 157.5a8.03 8.03 0 000 11.3l45.1 45.1c3.1 3.1 8.2 3.1 11.3 0l157.6-157.6 54.7 54.7a7.94 7.94 0 0013.5-4.7L447.9 585a7.9 7.9 0 00-8.9-8.9z"
106
+ ],
107
+ undo: [
108
+ "M511.4 124C290.5 124.3 112 303 112 523.9c0 128 60.2 242 153.8 315.2l-37.5 48c-4.1 5.3-.3 13 6.3 12.9l167-.8c5.2 0 9-4.9 7.7-9.9L369.8 727a8 8 0 00-14.1-3L315 776.1c-10.2-8-20-16.7-29.3-26a318.64 318.64 0 01-68.6-101.7C200.4 609 192 567.1 192 523.9s8.4-85.1 25.1-124.5c16.1-38.1 39.2-72.3 68.6-101.7 29.4-29.4 63.6-52.5 101.7-68.6C426.9 212.4 468.8 204 512 204s85.1 8.4 124.5 25.1c38.1 16.1 72.3 39.2 101.7 68.6 29.4 29.4 52.5 63.6 68.6 101.7 16.7 39.4 25.1 81.3 25.1 124.5s-8.4 85.1-25.1 124.5a318.64 318.64 0 01-68.6 101.7c-7.5 7.5-15.3 14.5-23.4 21.2a7.93 7.93 0 00-1.2 11.1l39.4 50.5c2.8 3.5 7.9 4.1 11.4 1.3C854.5 760.8 912 649.1 912 523.9c0-221.1-179.4-400.2-400.6-399.9z"
109
+ ]
110
+ };
111
+ function PatternIcon({
112
+ name,
113
+ style
114
+ }) {
115
+ return /* @__PURE__ */ jsxRuntime.jsx(
116
+ "span",
117
+ {
118
+ "aria-hidden": "true",
119
+ style: {
120
+ display: "inline-flex",
121
+ width: 16,
122
+ height: 16,
123
+ alignItems: "center",
124
+ justifyContent: "center",
125
+ fontSize: 14,
126
+ lineHeight: 1,
127
+ ...style
128
+ },
129
+ children: /* @__PURE__ */ jsxRuntime.jsx(
130
+ "svg",
131
+ {
132
+ viewBox: "64 64 896 896",
133
+ focusable: "false",
134
+ width: "1em",
135
+ height: "1em",
136
+ fill: "currentColor",
137
+ fillRule: name === "closeCircle" || name === "closeSquare" ? "evenodd" : void 0,
138
+ children: ICON_PATHS[name].map((path) => /* @__PURE__ */ jsxRuntime.jsx("path", { d: path }, path))
139
+ }
140
+ )
141
+ }
142
+ );
143
+ }
144
+ var createPatternIcon = (name) => function MaintopPatternIcon(props) {
145
+ return /* @__PURE__ */ jsxRuntime.jsx(PatternIcon, { ...props, name });
146
+ };
147
+ var AimOutlined = createPatternIcon("aim");
148
+ var ArrowsAltOutlined = createPatternIcon("arrowsAlt");
149
+ var BorderInnerOutlined = createPatternIcon("borderInner");
150
+ var ClearOutlined = createPatternIcon("clear");
151
+ var CloseCircleOutlined = createPatternIcon("closeCircle");
152
+ var CloseSquareOutlined = createPatternIcon("closeSquare");
153
+ var CopyOutlined = createPatternIcon("copy");
154
+ var DeleteOutlined = createPatternIcon("delete");
155
+ var DiffOutlined = createPatternIcon("diff");
156
+ var EditOutlined = createPatternIcon("edit");
157
+ var EyeOutlined = createPatternIcon("eye");
158
+ var HistoryOutlined = createPatternIcon("history");
159
+ var MergeCellsOutlined = createPatternIcon("mergeCells");
160
+ var PlusCircleOutlined = createPatternIcon("plusCircle");
161
+ var RedoOutlined = createPatternIcon("redo");
162
+ var ScissorOutlined = createPatternIcon("scissor");
163
+ var SelectOutlined = createPatternIcon("select");
164
+ var ShrinkOutlined = createPatternIcon("shrink");
165
+ var UndoOutlined = createPatternIcon("undo");
166
+ var Toolbar = React__default.default.memo(
167
+ ({ items, isExpanded, height = 650 }) => {
168
+ return /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactFlex, { vertical: true, justify: "space-between", style: { height }, children: items.map((item) => {
169
+ const isLoopToggle = item.text === "\u6536\u8D77\u5FAA\u73AF" || item.text === "\u5C55\u5F00\u5FAA\u73AF";
170
+ const isDisabled = isExpanded ? !isLoopToggle : item.disabled;
171
+ return /* @__PURE__ */ jsxRuntime.jsx(
172
+ reactComponents.ReactTooltip,
173
+ {
174
+ title: item.text,
175
+ destroyTooltipOnHide: true,
176
+ placement: "right",
177
+ children: /* @__PURE__ */ jsxRuntime.jsx(
178
+ reactComponents.ReactButton,
179
+ {
180
+ icon: item.icon,
181
+ onClick: item.onClick,
182
+ disabled: isDisabled,
183
+ size: "small"
184
+ }
185
+ )
186
+ },
187
+ item.text
188
+ );
189
+ }) });
190
+ }
191
+ );
192
+ var toolbar_default = Toolbar;
193
+ var SCROLLBAR_THICKNESS = 12;
194
+ function getRangeLevel(current, items, preferLargerOutside) {
195
+ return items.filter((other) => {
196
+ if (other.id === current.id) return false;
197
+ const hasIntersection = !(other.endPos < current.startPos || other.startPos > current.endPos);
198
+ if (!hasIntersection) return false;
199
+ const otherWidth = other.endPos - other.startPos;
200
+ const selfWidth = current.endPos - current.startPos;
201
+ if (otherWidth < selfWidth) return !preferLargerOutside;
202
+ if (otherWidth > selfWidth) return preferLargerOutside;
203
+ return other.id < current.id;
204
+ }).length;
205
+ }
206
+ function getMaxRangeLevel(items, preferLargerOutside) {
207
+ if (items.length === 0) return -1;
208
+ return Math.max(
209
+ ...items.map((item) => getRangeLevel(item, items, preferLargerOutside))
210
+ );
211
+ }
212
+ function createTextMeasurer() {
213
+ const canvas = document.createElement("canvas");
214
+ const ctx = canvas.getContext("2d");
215
+ return (text, font) => {
216
+ if (!ctx) {
217
+ return text.length * 10;
218
+ }
219
+ ctx.font = font;
220
+ return ctx.measureText(text).width;
221
+ };
222
+ }
223
+ function estimateExportRightMargin(params) {
224
+ const {
225
+ baseRightMargin,
226
+ step,
227
+ loops = [],
228
+ memos = [],
229
+ printMode = false,
230
+ loopFontSize = 10
231
+ } = params;
232
+ const measureText = createTextMeasurer();
233
+ const safePadding = Math.max(Math.ceil(step / 2), 8);
234
+ let required = baseRightMargin + safePadding;
235
+ const yLoops = loops.filter((loop) => loop.type === "y");
236
+ if (yLoops.length > 0) {
237
+ const maxLevel = getMaxRangeLevel(yLoops, false);
238
+ const maxLabelWidth = Math.max(
239
+ ...yLoops.map(
240
+ (loop, index) => measureText(
241
+ printMode ? `${loop.count}\u6B21` : `${loop.count}\u6B21[${index + 1}]`,
242
+ `${loopFontSize}px sans-serif`
243
+ )
244
+ ),
245
+ 0
246
+ );
247
+ required = Math.max(
248
+ required,
249
+ 5 + Math.max(0, maxLevel) * 30 + 6 + loopFontSize + maxLabelWidth / 2 + 20
250
+ );
251
+ if (printMode) {
252
+ required = Math.max(
253
+ required,
254
+ 11 + measureText("9999", `${loopFontSize}px sans-serif`) + 12
255
+ );
256
+ }
257
+ }
258
+ const yMemos = memos.filter((memo2) => memo2.type === "y");
259
+ if (yMemos.length > 0) {
260
+ const maxLoopLevel = getMaxRangeLevel(yLoops, false);
261
+ const loopOccupiedWidth = maxLoopLevel >= 0 ? (maxLoopLevel + 1) * 30 + 20 : 0;
262
+ const maxMemoLevel = getMaxRangeLevel(yMemos, false);
263
+ const maxMemoWidth = Math.max(
264
+ ...yMemos.map((memo2) => measureText(memo2.content, "10px sans-serif")),
265
+ 0
266
+ );
267
+ required = Math.max(
268
+ required,
269
+ 15 + loopOccupiedWidth + Math.max(0, maxMemoLevel) * 30 + maxMemoWidth + 20
270
+ );
271
+ }
272
+ return Math.ceil(required);
273
+ }
274
+ function buildSvgScene(props, forceExpanded) {
275
+ const vScaleSize = props.verticalScaleSize ?? props.horizontalScaleSize ?? 20;
276
+ const thickness = props.thickness ?? 60;
277
+ const step = props.step ?? 10;
278
+ const padding = props.padding ?? 0;
279
+ const topPadding = props.topPadding ?? 0;
280
+ const rightMargin = props.canvasRightMargin ?? 50;
281
+ const topMargin = props.canvasTopMargin ?? 0;
282
+ const isExpandedToUse = forceExpanded !== void 0 ? forceExpanded : props.isExpanded ?? false;
283
+ let exportMarks = props.gridMarks;
284
+ if (isExpandedToUse && !props.isExpanded) {
285
+ let tempMarks = { ...props.gridMarks };
286
+ const loopsConfig = props.loops ?? [];
287
+ const rowLoops = loopsConfig.filter((l) => l.type === "y");
288
+ const colLoops = loopsConfig.filter((l) => l.type === "x");
289
+ rowLoops.sort((a, b) => b.startPos - a.startPos).forEach((loop) => {
290
+ tempMarks = maintopPattern.GridModel.duplicateRows(
291
+ tempMarks,
292
+ loop.startPos,
293
+ loop.endPos,
294
+ loop.startPos,
295
+ loop.count,
296
+ 999999
297
+ );
298
+ });
299
+ colLoops.sort((a, b) => b.startPos - a.startPos).forEach((loop) => {
300
+ tempMarks = maintopPattern.GridModel.duplicateCols(
301
+ tempMarks,
302
+ loop.startPos,
303
+ loop.endPos,
304
+ loop.startPos,
305
+ loop.count,
306
+ 999999
307
+ );
308
+ });
309
+ exportMarks = tempMarks;
310
+ }
311
+ let maxX = -1;
312
+ let maxY = -1;
313
+ Object.keys(exportMarks).forEach((key) => {
314
+ const [x, y] = key.split(",").map(Number);
315
+ maxX = Math.max(maxX, x);
316
+ maxY = Math.max(maxY, y);
317
+ });
318
+ if (!isExpandedToUse) {
319
+ (props.loops ?? []).forEach((loop) => {
320
+ if (loop.type === "x") {
321
+ maxX = Math.max(maxX, loop.endPos);
322
+ } else {
323
+ maxY = Math.max(maxY, loop.endPos);
324
+ }
325
+ });
326
+ (props.memos ?? []).forEach((memo2) => {
327
+ if (memo2.type === "x") {
328
+ maxX = Math.max(maxX, memo2.endPos);
329
+ } else {
330
+ maxY = Math.max(maxY, memo2.endPos);
331
+ }
332
+ });
333
+ }
334
+ const exportHScale = props.printMode ? props.horizontalScaleSize ?? 20 : maxX === -1 ? props.horizontalScaleSize ?? 20 : maxX + 1;
335
+ const exportVScale = props.printMode ? props.verticalScaleSize ?? props.horizontalScaleSize ?? 20 : maxY === -1 ? vScaleSize : maxY + 1;
336
+ const exportRightMargin = estimateExportRightMargin({
337
+ baseRightMargin: rightMargin,
338
+ step,
339
+ loops: props.loops ?? [],
340
+ memos: props.memos ?? [],
341
+ printMode: props.printMode,
342
+ loopFontSize: props.loopFontSize
343
+ });
344
+ const fullWidth = thickness + exportHScale * step + padding + exportRightMargin;
345
+ const fullHeight = thickness + exportVScale * step + padding + topPadding + topMargin;
346
+ return {
347
+ width: fullWidth,
348
+ height: fullHeight,
349
+ options: {
350
+ width: fullWidth,
351
+ height: fullHeight,
352
+ scrollLeft: 0,
353
+ scrollTop: 0,
354
+ horizontalScaleSize: exportHScale,
355
+ verticalScaleSize: exportVScale,
356
+ thickness,
357
+ step,
358
+ minorTickInterval: props.midTickInterval ?? 5,
359
+ majorTickInterval: props.majorTickInterval ?? 10,
360
+ padding,
361
+ topPadding,
362
+ gridMarks: exportMarks,
363
+ hoverX: null,
364
+ hoverY: null,
365
+ hoveredGridCoord: null,
366
+ isSelecting: false,
367
+ selectionStart: null,
368
+ selectionCurrent: null,
369
+ rightMargin: exportRightMargin,
370
+ topMargin,
371
+ showCursor: false,
372
+ loops: props.loops ?? [],
373
+ memos: props.memos ?? [],
374
+ isExpanded: isExpandedToUse,
375
+ midTickFontSize: props.midTickFontSize,
376
+ majorTickFontSize: props.majorTickFontSize,
377
+ loopFontSize: props.loopFontSize,
378
+ printMode: props.printMode,
379
+ markPointFontSize: props.markPointFontSize,
380
+ loopWingOffset: props.loopWingOffset,
381
+ minorTickLength: props.midTickLength,
382
+ majorTickLength: props.majorTickLength,
383
+ smallTickLength: props.smallTickLength,
384
+ showSmallTickText: props.showSmallTickText,
385
+ smallTickFontSize: props.smallTickFontSize,
386
+ hoverEffectColor: props.hoverEffectColor,
387
+ markSelectColor: props.markSelectColor,
388
+ markCheckedColor: props.markCheckedColor,
389
+ markPointColor: props.markPointColor,
390
+ cursorColor: props.cursorColor,
391
+ mainGridColor: props.mainGridColor,
392
+ minorTickColor: props.minorTickColor,
393
+ rulerBgColor: props.rulerBgColor,
394
+ rulerTextColor: props.rulerTextColor,
395
+ rulerTickColor: props.rulerTickColor,
396
+ rulerBorderColor: props.rulerBorderColor,
397
+ loopIndicatorColor: props.loopIndicatorColor,
398
+ loopTextColor: props.loopTextColor,
399
+ loopTickExtension: props.loopTickExtension,
400
+ showLoopArrow: props.showLoopArrow,
401
+ loopArrowSize: props.loopArrowSize,
402
+ showInnerLoopEndpoints: props.showInnerLoopEndpoints
403
+ }
404
+ };
405
+ }
406
+ var Grid = React.forwardRef((props, ref) => {
407
+ const {
408
+ width,
409
+ height,
410
+ scrollLeft,
411
+ scrollTop: rawScrollTop,
412
+ showScrollbar = true,
413
+ scrollbarTotalWidth,
414
+ scrollbarTotalHeight,
415
+ horizontalScaleSize = 50,
416
+ verticalScaleSize = 50,
417
+ thickness = 40,
418
+ step = 10,
419
+ midTickInterval = 5,
420
+ majorTickInterval = 10,
421
+ padding = 20,
422
+ topPadding = 0,
423
+ gridMarks,
424
+ canvasRightMargin = 0,
425
+ canvasTopMargin = 0,
426
+ readonly = false,
427
+ showCursor = true,
428
+ loops = [],
429
+ memos = [],
430
+ isExpanded = false,
431
+ loopFontSize,
432
+ midTickLength,
433
+ majorTickLength,
434
+ smallTickLength,
435
+ showSmallTickText,
436
+ smallTickFontSize,
437
+ hoverEffectColor,
438
+ markSelectColor,
439
+ markCheckedColor,
440
+ markPointColor,
441
+ majorTickFontSize,
442
+ midTickFontSize,
443
+ markPointFontSize,
444
+ printMode = false,
445
+ loopWingOffset,
446
+ loopIndicatorColor,
447
+ loopTextColor,
448
+ cursorColor,
449
+ mainGridColor,
450
+ minorTickColor,
451
+ rulerBgColor,
452
+ rulerTextColor,
453
+ rulerTickColor,
454
+ rulerBorderColor,
455
+ loopTickExtension,
456
+ showLoopArrow,
457
+ loopArrowSize,
458
+ showInnerLoopEndpoints,
459
+ onGirdClick
460
+ } = props;
461
+ const svgScene = React.useMemo(() => {
462
+ if (!printMode) return null;
463
+ const scene = buildSvgScene(props);
464
+ const result = maintopPattern.exportDrawingBoardSvg(scene.options);
465
+ return {
466
+ ...scene,
467
+ svg: result.svg
468
+ };
469
+ }, [props, printMode]);
470
+ const logicalTotalHeight = thickness + (verticalScaleSize || horizontalScaleSize) * step + padding + topPadding;
471
+ const contentHeight = Math.max(
472
+ height - (showScrollbar ? SCROLLBAR_THICKNESS : 0),
473
+ 0
474
+ );
475
+ const calculatedScrollTop = logicalTotalHeight < contentHeight ? logicalTotalHeight - contentHeight : rawScrollTop;
476
+ const canvasRef = React.useRef(null);
477
+ const rendererRef = React.useRef(null);
478
+ const hoverState = React.useRef({
479
+ x: null,
480
+ y: null,
481
+ coord: null
482
+ });
483
+ const selectionState = React.useRef({
484
+ isSelecting: false,
485
+ start: null,
486
+ current: null
487
+ });
488
+ const clickStartPos = React.useRef({ x: 0, y: 0 });
489
+ const scrollbarDragRef = React.useRef(null);
490
+ const scrollbarInteractionRef = React.useRef(false);
491
+ const propsRef = React.useRef(props);
492
+ React.useEffect(() => {
493
+ propsRef.current = props;
494
+ }, [props]);
495
+ const getScrollbarLayouts = React.useCallback(() => {
496
+ const p = propsRef.current;
497
+ if (p.printMode || !p.showScrollbar) {
498
+ return { horizontal: null, vertical: null };
499
+ }
500
+ return {
501
+ horizontal: maintopPattern.computeCanvasScrollbarLayout({
502
+ orientation: "horizontal",
503
+ totalSize: p.scrollbarTotalWidth ?? p.width,
504
+ viewportSize: p.width,
505
+ scrollPos: p.scrollLeft,
506
+ thickness: SCROLLBAR_THICKNESS
507
+ }),
508
+ vertical: maintopPattern.computeCanvasScrollbarLayout({
509
+ orientation: "vertical",
510
+ totalSize: p.scrollbarTotalHeight ?? p.height,
511
+ viewportSize: Math.max(
512
+ p.height - SCROLLBAR_THICKNESS - (p.canvasTopMargin ?? 0),
513
+ 0
514
+ ),
515
+ scrollPos: p.scrollTop,
516
+ thickness: SCROLLBAR_THICKNESS
517
+ })
518
+ };
519
+ }, []);
520
+ const [isSpacePressed, setIsSpacePressed] = React.useState(false);
521
+ ahooks.useEventListener("keydown", (e) => {
522
+ if (e.code === "Space" && !e.repeat) {
523
+ setIsSpacePressed(true);
524
+ }
525
+ });
526
+ ahooks.useEventListener("keyup", (e) => {
527
+ if (e.code === "Space") {
528
+ setIsSpacePressed(false);
529
+ }
530
+ });
531
+ const renderRafRef = React.useRef(null);
532
+ const requestRender = React.useCallback(() => {
533
+ if (renderRafRef.current) return;
534
+ renderRafRef.current = requestAnimationFrame(() => {
535
+ renderRafRef.current = null;
536
+ if (!rendererRef.current) return;
537
+ const p = propsRef.current;
538
+ const vScaleSize = p.verticalScaleSize ?? p.horizontalScaleSize ?? 20;
539
+ rendererRef.current.render({
540
+ width: p.width,
541
+ height: p.height,
542
+ bottomInset: p.showScrollbar ? SCROLLBAR_THICKNESS : 0,
543
+ scrollLeft: p.scrollLeft,
544
+ scrollTop: calculatedScrollTop,
545
+ horizontalScaleSize: p.horizontalScaleSize ?? 20,
546
+ verticalScaleSize: vScaleSize,
547
+ thickness: p.thickness ?? 60,
548
+ step: p.step ?? 10,
549
+ minorTickInterval: p.midTickInterval ?? 5,
550
+ majorTickInterval: p.majorTickInterval ?? 10,
551
+ padding: p.padding ?? 40,
552
+ topPadding: p.topPadding ?? 40,
553
+ gridMarks: p.gridMarks,
554
+ hoverX: hoverState.current.x,
555
+ hoverY: hoverState.current.y,
556
+ hoveredGridCoord: hoverState.current.coord,
557
+ isSelecting: selectionState.current.isSelecting,
558
+ selectionStart: selectionState.current.start,
559
+ selectionCurrent: selectionState.current.current,
560
+ rightMargin: p.canvasRightMargin ?? 50,
561
+ topMargin: p.canvasTopMargin ?? 0,
562
+ showCursor: p.showCursor ?? true,
563
+ loops: p.loops ?? [],
564
+ memos: p.memos ?? [],
565
+ isExpanded: p.isExpanded ?? false,
566
+ midTickFontSize: p.midTickFontSize,
567
+ majorTickFontSize: p.majorTickFontSize,
568
+ loopFontSize: p.loopFontSize,
569
+ printMode: p.printMode,
570
+ markPointFontSize: p.markPointFontSize,
571
+ loopWingOffset: p.loopWingOffset,
572
+ minorTickLength: p.midTickLength,
573
+ majorTickLength: p.majorTickLength,
574
+ smallTickLength: p.smallTickLength,
575
+ showSmallTickText: p.showSmallTickText,
576
+ smallTickFontSize: p.smallTickFontSize,
577
+ hoverEffectColor: p.hoverEffectColor,
578
+ markSelectColor: p.markSelectColor,
579
+ markCheckedColor: p.markCheckedColor,
580
+ markPointColor: p.markPointColor,
581
+ cursorColor: p.cursorColor,
582
+ mainGridColor: p.mainGridColor,
583
+ minorTickColor: p.minorTickColor,
584
+ rulerBgColor: p.rulerBgColor,
585
+ rulerTextColor: p.rulerTextColor,
586
+ rulerTickColor: p.rulerTickColor,
587
+ rulerBorderColor: p.rulerBorderColor,
588
+ loopIndicatorColor: p.loopIndicatorColor,
589
+ loopTextColor: p.loopTextColor,
590
+ loopTickExtension: p.loopTickExtension,
591
+ showLoopArrow: p.showLoopArrow,
592
+ loopArrowSize: p.loopArrowSize,
593
+ showInnerLoopEndpoints: p.showInnerLoopEndpoints
594
+ });
595
+ const canvas = canvasRef.current;
596
+ const context = canvas?.getContext("2d");
597
+ if (context) {
598
+ const layouts = getScrollbarLayouts();
599
+ maintopPattern.drawCanvasScrollbars(
600
+ context,
601
+ [
602
+ ...layouts.horizontal ? [
603
+ {
604
+ layout: layouts.horizontal,
605
+ offsetY: p.height - SCROLLBAR_THICKNESS
606
+ }
607
+ ] : [],
608
+ ...layouts.vertical ? [
609
+ {
610
+ layout: layouts.vertical,
611
+ offsetX: p.width - SCROLLBAR_THICKNESS
612
+ }
613
+ ] : []
614
+ ],
615
+ {},
616
+ false
617
+ );
618
+ }
619
+ });
620
+ }, [calculatedScrollTop, getScrollbarLayouts]);
621
+ React.useEffect(() => {
622
+ return () => {
623
+ if (renderRafRef.current) {
624
+ cancelAnimationFrame(renderRafRef.current);
625
+ renderRafRef.current = null;
626
+ }
627
+ };
628
+ }, []);
629
+ const getGridFromCoord = (clientX, clientY) => {
630
+ const rect = canvasRef.current?.getBoundingClientRect();
631
+ if (!rect) return null;
632
+ const p = propsRef.current;
633
+ const vScaleSize = p.verticalScaleSize ?? p.horizontalScaleSize ?? 20;
634
+ const s = p.step ?? 10;
635
+ const pad = p.padding ?? 40;
636
+ const topPad = p.topPadding ?? 40;
637
+ const thick = p.thickness ?? 60;
638
+ const lTotalHeight = thick + vScaleSize * s + pad + topPad;
639
+ const renderHeight = Math.max(
640
+ p.height - (p.showScrollbar ? SCROLLBAR_THICKNESS : 0),
641
+ 0
642
+ );
643
+ const effectiveScrollTop = lTotalHeight < renderHeight ? lTotalHeight - renderHeight : p.scrollTop;
644
+ const pixelX = clientX - rect.left;
645
+ const pixelY = clientY - rect.top;
646
+ if (p.showScrollbar && pixelY >= renderHeight) return null;
647
+ const x = pixelX + p.scrollLeft - thick - pad;
648
+ const colIndex = Math.floor(x / s);
649
+ const yVal = vScaleSize * s + topPad - (pixelY + effectiveScrollTop - (p.canvasTopMargin ?? 0));
650
+ const rowIndex = Math.floor(yVal / s);
651
+ const hScale = p.horizontalScaleSize ?? 20;
652
+ if (colIndex >= 0 && colIndex < hScale && rowIndex >= 0 && rowIndex < vScaleSize) {
653
+ return { x: colIndex, y: rowIndex };
654
+ }
655
+ return null;
656
+ };
657
+ const autoScrollRaf = React.useRef(null);
658
+ const autoScrollSpeed = React.useRef({ x: 0, y: 0 });
659
+ const AUTO_SCROLL_SPEED = 10;
660
+ const stopAutoScroll = () => {
661
+ if (autoScrollRaf.current) {
662
+ cancelAnimationFrame(autoScrollRaf.current);
663
+ autoScrollRaf.current = null;
664
+ }
665
+ };
666
+ const performAutoScroll = () => {
667
+ const { x, y } = autoScrollSpeed.current;
668
+ if (x === 0 && y === 0) {
669
+ stopAutoScroll();
670
+ return;
671
+ }
672
+ if (propsRef.current.onScrollRequest) {
673
+ propsRef.current.onScrollRequest(x, y);
674
+ }
675
+ autoScrollRaf.current = requestAnimationFrame(performAutoScroll);
676
+ };
677
+ React.useEffect(() => {
678
+ return () => stopAutoScroll();
679
+ }, []);
680
+ const { run: checkMaxGrid } = ahooks.useDebounceFn(
681
+ (marks) => {
682
+ const onMaxGridChange = propsRef.current.onMaxGridChange;
683
+ if (!onMaxGridChange) return;
684
+ const keys = Object.keys(marks);
685
+ if (keys.length === 0) {
686
+ onMaxGridChange(null);
687
+ return;
688
+ }
689
+ let maxX = -1;
690
+ let maxY = -1;
691
+ for (const key of keys) {
692
+ const commaIndex = key.indexOf(",");
693
+ const x = parseInt(key.slice(0, commaIndex), 10);
694
+ const y = parseInt(key.slice(commaIndex + 1), 10);
695
+ if (x > maxX) maxX = x;
696
+ if (y > maxY) maxY = y;
697
+ }
698
+ if (maxX !== -1 && maxY !== -1) {
699
+ onMaxGridChange({ x: maxX + 1, y: maxY + 1 });
700
+ } else {
701
+ onMaxGridChange(null);
702
+ }
703
+ },
704
+ { wait: 300 }
705
+ );
706
+ React.useEffect(() => {
707
+ checkMaxGrid(gridMarks);
708
+ }, [gridMarks, checkMaxGrid]);
709
+ const lastMousePos = React.useRef(null);
710
+ React.useEffect(() => {
711
+ if (selectionState.current.isSelecting && selectionState.current.start && lastMousePos.current) {
712
+ const coord = getGridFromCoord(
713
+ lastMousePos.current.x,
714
+ lastMousePos.current.y
715
+ );
716
+ if (coord) {
717
+ selectionState.current.current = coord;
718
+ }
719
+ }
720
+ requestRender();
721
+ }, [
722
+ width,
723
+ height,
724
+ scrollLeft,
725
+ rawScrollTop,
726
+ // 内部衍生逻辑处理了严格相等性检查
727
+ showScrollbar,
728
+ scrollbarTotalWidth,
729
+ scrollbarTotalHeight,
730
+ horizontalScaleSize,
731
+ verticalScaleSize,
732
+ thickness,
733
+ step,
734
+ midTickInterval,
735
+ majorTickInterval,
736
+ padding,
737
+ topPadding,
738
+ gridMarks,
739
+ canvasRightMargin,
740
+ canvasTopMargin,
741
+ readonly,
742
+ showCursor,
743
+ loops,
744
+ memos,
745
+ isExpanded,
746
+ isExpanded,
747
+ requestRender,
748
+ loopFontSize,
749
+ midTickLength,
750
+ majorTickLength,
751
+ smallTickLength,
752
+ showSmallTickText,
753
+ smallTickFontSize,
754
+ hoverEffectColor,
755
+ markSelectColor,
756
+ markCheckedColor,
757
+ markPointColor,
758
+ cursorColor,
759
+ mainGridColor,
760
+ minorTickColor,
761
+ rulerBgColor,
762
+ rulerTextColor,
763
+ rulerTickColor,
764
+ rulerBorderColor,
765
+ loopTickExtension,
766
+ showLoopArrow,
767
+ loopArrowSize,
768
+ showInnerLoopEndpoints,
769
+ majorTickFontSize,
770
+ midTickFontSize,
771
+ markPointFontSize,
772
+ loopWingOffset,
773
+ loopIndicatorColor,
774
+ loopTextColor
775
+ ]);
776
+ React.useEffect(() => {
777
+ if (canvasRef.current && !rendererRef.current) {
778
+ rendererRef.current = new maintopPattern.RulerRenderer(canvasRef.current);
779
+ requestRender();
780
+ }
781
+ }, [requestRender]);
782
+ const getScrollbarHit = (clientX, clientY) => {
783
+ const rect = canvasRef.current?.getBoundingClientRect();
784
+ if (!rect) return null;
785
+ const x = clientX - rect.left;
786
+ const y = clientY - rect.top;
787
+ const layouts = getScrollbarLayouts();
788
+ if (layouts.vertical && x >= propsRef.current.width - SCROLLBAR_THICKNESS) {
789
+ const part = maintopPattern.hitTestCanvasScrollbar(
790
+ layouts.vertical,
791
+ x - (propsRef.current.width - SCROLLBAR_THICKNESS),
792
+ y
793
+ );
794
+ if (part) {
795
+ return {
796
+ orientation: "vertical",
797
+ layout: layouts.vertical,
798
+ part,
799
+ pointer: y
800
+ };
801
+ }
802
+ }
803
+ if (layouts.horizontal && y >= propsRef.current.height - SCROLLBAR_THICKNESS) {
804
+ const part = maintopPattern.hitTestCanvasScrollbar(
805
+ layouts.horizontal,
806
+ x,
807
+ y - (propsRef.current.height - SCROLLBAR_THICKNESS)
808
+ );
809
+ if (part) {
810
+ return {
811
+ orientation: "horizontal",
812
+ layout: layouts.horizontal,
813
+ part,
814
+ pointer: x
815
+ };
816
+ }
817
+ }
818
+ return null;
819
+ };
820
+ const handleMouseMove = (e) => {
821
+ const scrollbarDrag = scrollbarDragRef.current;
822
+ if (scrollbarDrag) {
823
+ const rect2 = canvasRef.current?.getBoundingClientRect();
824
+ if (!rect2) return;
825
+ const pointer = scrollbarDrag.orientation === "horizontal" ? e.clientX - rect2.left : e.clientY - rect2.top;
826
+ const nextPosition = maintopPattern.resolveCanvasScrollbarDragPosition(
827
+ scrollbarDrag.layout,
828
+ scrollbarDrag.startScroll,
829
+ pointer - scrollbarDrag.startPointer
830
+ );
831
+ if (scrollbarDrag.orientation === "horizontal") {
832
+ propsRef.current.onHorizontalScroll?.(nextPosition);
833
+ } else {
834
+ propsRef.current.onVerticalScroll?.(nextPosition);
835
+ }
836
+ e.stopPropagation();
837
+ return;
838
+ }
839
+ const rect = canvasRef.current?.getBoundingClientRect();
840
+ if (rect) {
841
+ const newHoverX = e.clientX - rect.left;
842
+ const newHoverY = e.clientY - rect.top;
843
+ hoverState.current.x = newHoverX;
844
+ hoverState.current.y = newHoverY;
845
+ lastMousePos.current = { x: e.clientX, y: e.clientY };
846
+ const coord = getGridFromCoord(e.clientX, e.clientY);
847
+ const oldCoord = hoverState.current.coord;
848
+ let coordChanged = false;
849
+ if (coord?.x !== oldCoord?.x || coord?.y !== oldCoord?.y) {
850
+ hoverState.current.coord = coord;
851
+ coordChanged = true;
852
+ } else if (!coord && oldCoord) {
853
+ hoverState.current.coord = null;
854
+ coordChanged = true;
855
+ }
856
+ if (coordChanged && propsRef.current.onHoverGridChange) {
857
+ propsRef.current.onHoverGridChange(coord ?? null);
858
+ }
859
+ } else {
860
+ hoverState.current.x = null;
861
+ hoverState.current.y = null;
862
+ }
863
+ if (selectionState.current.isSelecting && selectionState.current.start) {
864
+ const coord = getGridFromCoord(e.clientX, e.clientY);
865
+ if (coord) {
866
+ selectionState.current.current = coord;
867
+ }
868
+ if (rect) {
869
+ const margin = 20;
870
+ let sx = 0;
871
+ let sy = 0;
872
+ if (e.clientX < rect.left + margin) sx = -AUTO_SCROLL_SPEED;
873
+ else if (e.clientX > rect.right - margin) sx = AUTO_SCROLL_SPEED;
874
+ if (e.clientY < rect.top + margin) sy = -AUTO_SCROLL_SPEED;
875
+ else if (e.clientY > rect.bottom - margin - (propsRef.current.showScrollbar ? SCROLLBAR_THICKNESS : 0))
876
+ sy = AUTO_SCROLL_SPEED;
877
+ if (sx !== 0 || sy !== 0) {
878
+ autoScrollSpeed.current = { x: sx, y: sy };
879
+ if (!autoScrollRaf.current) {
880
+ performAutoScroll();
881
+ }
882
+ } else {
883
+ stopAutoScroll();
884
+ }
885
+ }
886
+ }
887
+ requestRender();
888
+ };
889
+ const handleCanvasMouseDown = (e) => {
890
+ const scrollbarHit = getScrollbarHit(e.clientX, e.clientY);
891
+ if (e.button === 0 && scrollbarHit) {
892
+ const p = propsRef.current;
893
+ const scrollPos = scrollbarHit.orientation === "horizontal" ? p.scrollLeft : p.scrollTop;
894
+ const viewportSize = scrollbarHit.orientation === "horizontal" ? p.width : Math.max(
895
+ p.height - SCROLLBAR_THICKNESS - (p.canvasTopMargin ?? 0),
896
+ 0
897
+ );
898
+ const onScroll = scrollbarHit.orientation === "horizontal" ? p.onHorizontalScroll : p.onVerticalScroll;
899
+ const pageSize = Math.max(viewportSize * 0.9, 1);
900
+ scrollbarInteractionRef.current = true;
901
+ clickStartPos.current = { x: e.clientX, y: e.clientY };
902
+ e.preventDefault();
903
+ e.stopPropagation();
904
+ if (scrollbarHit.part === "thumb") {
905
+ scrollbarDragRef.current = {
906
+ orientation: scrollbarHit.orientation,
907
+ layout: scrollbarHit.layout,
908
+ startPointer: scrollbarHit.pointer,
909
+ startScroll: scrollPos
910
+ };
911
+ } else if (scrollbarHit.part === "decrease") {
912
+ onScroll?.(Math.max(scrollPos - Math.max(viewportSize * 0.1, 1), 0));
913
+ } else if (scrollbarHit.part === "increase") {
914
+ onScroll?.(
915
+ Math.min(
916
+ scrollPos + Math.max(viewportSize * 0.1, 1),
917
+ scrollbarHit.layout.maxScroll
918
+ )
919
+ );
920
+ } else if (scrollbarHit.part === "track-before") {
921
+ onScroll?.(Math.max(scrollPos - pageSize, 0));
922
+ } else if (scrollbarHit.part === "track-after") {
923
+ onScroll?.(
924
+ Math.min(scrollPos + pageSize, scrollbarHit.layout.maxScroll)
925
+ );
926
+ }
927
+ return;
928
+ }
929
+ if (propsRef.current.readonly) return;
930
+ if (e.button === 0 && !isSpacePressed) {
931
+ const coord = getGridFromCoord(e.clientX, e.clientY);
932
+ if (coord) {
933
+ e.stopPropagation();
934
+ selectionState.current.isSelecting = true;
935
+ selectionState.current.start = coord;
936
+ selectionState.current.current = coord;
937
+ requestRender();
938
+ }
939
+ }
940
+ clickStartPos.current = { x: e.clientX, y: e.clientY };
941
+ };
942
+ ahooks.useEventListener("mouseup", () => {
943
+ scrollbarDragRef.current = null;
944
+ const { isSelecting, start, current } = selectionState.current;
945
+ if (isSelecting && start && current) {
946
+ const x1 = Math.min(start.x, current.x);
947
+ const x2 = Math.max(start.x, current.x);
948
+ const y1 = Math.min(start.y, current.y);
949
+ const y2 = Math.max(start.y, current.y);
950
+ if (x1 === x2 && y1 === y2) ; else {
951
+ propsRef.current.onGridMarksChange(
952
+ (prev) => maintopPattern.GridModel.markRange(prev, x1, y1, x2, y2, 1)
953
+ );
954
+ }
955
+ selectionState.current.isSelecting = false;
956
+ selectionState.current.start = null;
957
+ selectionState.current.current = null;
958
+ stopAutoScroll();
959
+ requestRender();
960
+ } else if (isSelecting) {
961
+ selectionState.current.isSelecting = false;
962
+ selectionState.current.start = null;
963
+ selectionState.current.current = null;
964
+ stopAutoScroll();
965
+ requestRender();
966
+ }
967
+ });
968
+ const handleCanvasClick = (e) => {
969
+ if (scrollbarInteractionRef.current) {
970
+ scrollbarInteractionRef.current = false;
971
+ return;
972
+ }
973
+ if (propsRef.current.readonly) return;
974
+ const dist = Math.hypot(
975
+ e.clientX - clickStartPos.current.x,
976
+ e.clientY - clickStartPos.current.y
977
+ );
978
+ if (dist > 5) return;
979
+ const coord = getGridFromCoord(e.clientX, e.clientY);
980
+ if (coord) {
981
+ propsRef.current.onGridMarksChange(
982
+ (prev) => maintopPattern.GridModel.toggleCell(
983
+ prev,
984
+ coord.x,
985
+ coord.y,
986
+ propsRef.current.isClickModeEnabled
987
+ )
988
+ );
989
+ }
990
+ };
991
+ const handleMouseLeave = () => {
992
+ hoverState.current.x = null;
993
+ hoverState.current.y = null;
994
+ requestRender();
995
+ };
996
+ React.useImperativeHandle(ref, () => ({
997
+ toDataURL: (type = "image/png", quality, forceExpanded) => {
998
+ const p = propsRef.current;
999
+ const vScaleSize = p.verticalScaleSize ?? p.horizontalScaleSize ?? 20;
1000
+ const thickness2 = p.thickness ?? 60;
1001
+ const step2 = p.step ?? 10;
1002
+ const padding2 = p.padding ?? 0;
1003
+ const topPadding2 = p.topPadding ?? 0;
1004
+ const rightMargin = p.canvasRightMargin ?? 50;
1005
+ const topMargin = p.canvasTopMargin ?? 0;
1006
+ const isExpandedToUse = forceExpanded !== void 0 ? forceExpanded : p.isExpanded ?? false;
1007
+ let exportMarks = p.gridMarks;
1008
+ if (isExpandedToUse && !p.isExpanded) {
1009
+ let tempMarks = { ...p.gridMarks };
1010
+ const loopsConfig = p.loops ?? [];
1011
+ const rowLoops = loopsConfig.filter((l) => l.type === "y");
1012
+ const colLoops = loopsConfig.filter((l) => l.type === "x");
1013
+ rowLoops.sort((a, b) => b.startPos - a.startPos).forEach((loop) => {
1014
+ tempMarks = maintopPattern.GridModel.duplicateRows(
1015
+ tempMarks,
1016
+ loop.startPos,
1017
+ loop.endPos,
1018
+ loop.startPos,
1019
+ // 插入位置
1020
+ loop.count,
1021
+ 999999
1022
+ // 导出时不限制上限
1023
+ );
1024
+ });
1025
+ colLoops.sort((a, b) => b.startPos - a.startPos).forEach((loop) => {
1026
+ tempMarks = maintopPattern.GridModel.duplicateCols(
1027
+ tempMarks,
1028
+ loop.startPos,
1029
+ loop.endPos,
1030
+ loop.startPos,
1031
+ // 插入位置
1032
+ loop.count,
1033
+ 999999
1034
+ // 导出时不限制上限
1035
+ );
1036
+ });
1037
+ exportMarks = tempMarks;
1038
+ }
1039
+ let maxX = -1;
1040
+ let maxY = -1;
1041
+ Object.keys(exportMarks).forEach((key) => {
1042
+ const [x, y] = key.split(",").map(Number);
1043
+ maxX = Math.max(maxX, x);
1044
+ maxY = Math.max(maxY, y);
1045
+ });
1046
+ if (!isExpandedToUse) {
1047
+ (p.loops ?? []).forEach((loop) => {
1048
+ if (loop.type === "x") {
1049
+ maxX = Math.max(maxX, loop.endPos);
1050
+ } else {
1051
+ maxY = Math.max(maxY, loop.endPos);
1052
+ }
1053
+ });
1054
+ (p.memos ?? []).forEach((memo2) => {
1055
+ if (memo2.type === "x") {
1056
+ maxX = Math.max(maxX, memo2.endPos);
1057
+ } else {
1058
+ maxY = Math.max(maxY, memo2.endPos);
1059
+ }
1060
+ });
1061
+ }
1062
+ const exportHScale = maxX === -1 ? p.horizontalScaleSize ?? 20 : maxX + 1;
1063
+ const exportVScale = maxY === -1 ? vScaleSize : maxY + 1;
1064
+ const exportRightMargin = estimateExportRightMargin({
1065
+ baseRightMargin: rightMargin,
1066
+ step: step2,
1067
+ loops: p.loops ?? [],
1068
+ memos: p.memos ?? [],
1069
+ printMode: p.printMode,
1070
+ loopFontSize: p.loopFontSize
1071
+ });
1072
+ const exportDpr = p.printMode ? 4 : 2;
1073
+ let fullWidth = thickness2 + exportHScale * step2 + padding2 + exportRightMargin;
1074
+ let fullHeight = thickness2 + exportVScale * step2 + padding2 + topPadding2 + topMargin;
1075
+ const MAX_CANVAS_SIZE = 16e3;
1076
+ if (fullHeight > MAX_CANVAS_SIZE || fullWidth > MAX_CANVAS_SIZE) {
1077
+ console.warn("Canvas size exceeds limit, image will be truncated.");
1078
+ fullWidth = Math.min(fullWidth, MAX_CANVAS_SIZE);
1079
+ fullHeight = Math.min(fullHeight, MAX_CANVAS_SIZE);
1080
+ }
1081
+ const offscreenCanvas = document.createElement("canvas");
1082
+ const offscreenRenderer = new maintopPattern.RulerRenderer(offscreenCanvas);
1083
+ offscreenRenderer.render({
1084
+ width: fullWidth,
1085
+ height: fullHeight,
1086
+ scrollLeft: 0,
1087
+ scrollTop: 0,
1088
+ horizontalScaleSize: exportHScale,
1089
+ verticalScaleSize: exportVScale,
1090
+ thickness: thickness2,
1091
+ step: step2,
1092
+ minorTickInterval: p.midTickInterval ?? 5,
1093
+ majorTickInterval: p.majorTickInterval ?? 10,
1094
+ padding: padding2,
1095
+ topPadding: topPadding2,
1096
+ gridMarks: exportMarks,
1097
+ hoverX: null,
1098
+ hoverY: null,
1099
+ hoveredGridCoord: null,
1100
+ isSelecting: false,
1101
+ selectionStart: null,
1102
+ selectionCurrent: null,
1103
+ rightMargin: exportRightMargin,
1104
+ topMargin,
1105
+ showCursor: false,
1106
+ loops: p.loops ?? [],
1107
+ memos: p.memos ?? [],
1108
+ isExpanded: isExpandedToUse,
1109
+ dpr: exportDpr,
1110
+ midTickFontSize: p.midTickFontSize,
1111
+ majorTickFontSize: p.majorTickFontSize,
1112
+ loopFontSize: p.loopFontSize,
1113
+ printMode: p.printMode,
1114
+ markPointFontSize: p.markPointFontSize,
1115
+ loopWingOffset: p.loopWingOffset,
1116
+ minorTickLength: p.midTickLength,
1117
+ majorTickLength: p.majorTickLength,
1118
+ smallTickLength: p.smallTickLength,
1119
+ showSmallTickText: p.showSmallTickText,
1120
+ smallTickFontSize: p.smallTickFontSize,
1121
+ hoverEffectColor: p.hoverEffectColor,
1122
+ markSelectColor: p.markSelectColor,
1123
+ markCheckedColor: p.markCheckedColor,
1124
+ markPointColor: p.markPointColor,
1125
+ cursorColor: p.cursorColor,
1126
+ mainGridColor: p.mainGridColor,
1127
+ minorTickColor: p.minorTickColor,
1128
+ rulerBgColor: p.rulerBgColor,
1129
+ rulerTextColor: p.rulerTextColor,
1130
+ rulerTickColor: p.rulerTickColor,
1131
+ rulerBorderColor: p.rulerBorderColor,
1132
+ loopIndicatorColor: p.loopIndicatorColor,
1133
+ loopTextColor: p.loopTextColor,
1134
+ loopTickExtension: p.loopTickExtension,
1135
+ showLoopArrow: p.showLoopArrow,
1136
+ loopArrowSize: p.loopArrowSize,
1137
+ showInnerLoopEndpoints: p.showInnerLoopEndpoints
1138
+ });
1139
+ return {
1140
+ url: offscreenCanvas.toDataURL(type, quality),
1141
+ width: offscreenCanvas.width,
1142
+ height: offscreenCanvas.height,
1143
+ dpi: exportDpr * 96
1144
+ };
1145
+ },
1146
+ toSVG: (forceExpanded) => {
1147
+ const p = propsRef.current;
1148
+ const scene = buildSvgScene(p, forceExpanded);
1149
+ const { svg, width: width2, height: height2 } = maintopPattern.exportDrawingBoardSvg(scene.options);
1150
+ return {
1151
+ svg,
1152
+ url: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`,
1153
+ width: width2,
1154
+ height: height2
1155
+ };
1156
+ }
1157
+ }));
1158
+ if (printMode && svgScene) {
1159
+ return /* @__PURE__ */ jsxRuntime.jsx(
1160
+ "div",
1161
+ {
1162
+ style: {
1163
+ width: svgScene.width,
1164
+ height: svgScene.height,
1165
+ lineHeight: 0,
1166
+ flex: "0 0 auto"
1167
+ },
1168
+ dangerouslySetInnerHTML: { __html: svgScene.svg }
1169
+ }
1170
+ );
1171
+ }
1172
+ return /* @__PURE__ */ jsxRuntime.jsx(
1173
+ "canvas",
1174
+ {
1175
+ ref: canvasRef,
1176
+ style: {
1177
+ ...STYLES.canvas,
1178
+ cursor: isSpacePressed ? "grab" : "crosshair",
1179
+ width,
1180
+ height
1181
+ },
1182
+ onMouseMove: handleMouseMove,
1183
+ onMouseDown: handleCanvasMouseDown,
1184
+ onClick: handleCanvasClick,
1185
+ onMouseLeave: handleMouseLeave,
1186
+ onClickCapture: () => {
1187
+ if (!scrollbarInteractionRef.current) onGirdClick?.();
1188
+ }
1189
+ }
1190
+ );
1191
+ });
1192
+ var grid_default = React__default.default.memo(Grid);
1193
+
1194
+ // src/components/wheel-scroll.ts
1195
+ var WHEEL_DELTA_MODE_PIXEL = 0;
1196
+ var WHEEL_DELTA_MODE_LINE = 1;
1197
+ var WHEEL_DELTA_MODE_PAGE = 2;
1198
+ function normalizeWheelDeltaToPixels(options) {
1199
+ const delta = Number.isFinite(options.delta) ? options.delta : 0;
1200
+ if (options.deltaMode === WHEEL_DELTA_MODE_LINE) {
1201
+ return delta * Math.max(options.lineHeight, 1);
1202
+ }
1203
+ if (options.deltaMode === WHEEL_DELTA_MODE_PAGE) {
1204
+ return delta * Math.max(options.pageSize, 1);
1205
+ }
1206
+ return delta;
1207
+ }
1208
+ function softenWheelDeltaPixels(options) {
1209
+ const { delta, deltaMode } = options;
1210
+ if (delta === 0) return 0;
1211
+ const absoluteDelta = Math.abs(delta);
1212
+ const lineHeight = Math.max(options.lineHeight, 1);
1213
+ if (deltaMode === WHEEL_DELTA_MODE_PIXEL && absoluteDelta >= 80 && absoluteDelta <= 160) {
1214
+ return delta * 0.42;
1215
+ }
1216
+ if (deltaMode === WHEEL_DELTA_MODE_LINE) {
1217
+ const maxStep = Math.max(lineHeight * 0.75, 24);
1218
+ if (absoluteDelta <= maxStep) return delta * 0.72;
1219
+ return Math.sign(delta) * (maxStep + (absoluteDelta - maxStep) * 0.35);
1220
+ }
1221
+ const softThreshold = Math.max(lineHeight * 1.25, 48);
1222
+ if (absoluteDelta <= softThreshold) return delta;
1223
+ return Math.sign(delta) * (softThreshold + (absoluteDelta - softThreshold) * 0.4);
1224
+ }
1225
+ function resolveWheelScrollDelta({
1226
+ deltaX,
1227
+ deltaY,
1228
+ deltaMode,
1229
+ shiftKey,
1230
+ lineHeight,
1231
+ pageWidth,
1232
+ pageHeight
1233
+ }) {
1234
+ const left = softenWheelDeltaPixels({
1235
+ delta: normalizeWheelDeltaToPixels({
1236
+ delta: deltaX,
1237
+ deltaMode,
1238
+ lineHeight,
1239
+ pageSize: pageWidth
1240
+ }),
1241
+ deltaMode,
1242
+ lineHeight
1243
+ });
1244
+ const top = softenWheelDeltaPixels({
1245
+ delta: normalizeWheelDeltaToPixels({
1246
+ delta: deltaY,
1247
+ deltaMode,
1248
+ lineHeight,
1249
+ pageSize: pageHeight
1250
+ }),
1251
+ deltaMode,
1252
+ lineHeight
1253
+ });
1254
+ return shiftKey ? { left: left + top, top: 0 } : { left, top };
1255
+ }
1256
+ function shouldApplyWheelDeltaImmediately(options) {
1257
+ return options.deltaMode === WHEEL_DELTA_MODE_PIXEL && Math.abs(options.deltaX) < 40 && Math.abs(options.deltaY) < 40;
1258
+ }
1259
+ function advanceWheelScrollSmoothing(options) {
1260
+ const timeConstant = Math.max(options.timeConstantMs ?? 92, 1);
1261
+ const deltaMs = Math.max(Math.min(options.deltaMs, 64), 0);
1262
+ const alpha = 1 - Math.exp(-deltaMs / timeConstant);
1263
+ const next = {
1264
+ left: options.current.left + (options.target.left - options.current.left) * alpha,
1265
+ top: options.current.top + (options.target.top - options.current.top) * alpha
1266
+ };
1267
+ const done = Math.abs(options.target.left - next.left) < 0.35 && Math.abs(options.target.top - next.top) < 0.35;
1268
+ return {
1269
+ next: done ? options.target : next,
1270
+ done
1271
+ };
1272
+ }
1273
+ var columns = [
1274
+ { title: "\u5E8F\u53F7", dataIndex: "id", key: "id", width: 80 },
1275
+ { title: "\u65F6\u95F4", dataIndex: "time", key: "time", width: 120 },
1276
+ { title: "\u64CD\u4F5C\u5185\u5BB9", dataIndex: "content", key: "content" }
1277
+ ];
1278
+ function HistoryModal({ open, onCancel, onClear, logs }) {
1279
+ return /* @__PURE__ */ jsxRuntime.jsx(
1280
+ reactComponents.ReactModal,
1281
+ {
1282
+ title: "\u64CD\u4F5C\u5386\u53F2",
1283
+ open,
1284
+ onCancel,
1285
+ footer: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1286
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactButton, { onClick: onClear, danger: true, children: "\u6E05\u7A7A\u5386\u53F2" }),
1287
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactButton, { type: "primary", onClick: onCancel, children: "\u5173\u95ED" })
1288
+ ] }),
1289
+ width: 600,
1290
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1291
+ reactListTable.ReactListTable,
1292
+ {
1293
+ dataSource: logs,
1294
+ columns,
1295
+ rowKey: "id",
1296
+ height: 400,
1297
+ scroll: { y: 400 },
1298
+ rowHeight: 32,
1299
+ toolbar: false
1300
+ }
1301
+ )
1302
+ }
1303
+ );
1304
+ }
1305
+ var history_modal_default = React.memo(HistoryModal);
1306
+ var BatchCopyModal = ({
1307
+ open,
1308
+ onCancel,
1309
+ onOk
1310
+ }) => {
1311
+ const [duplicateForm] = reactComponents.ReactForm.useForm();
1312
+ const duplicateType = reactComponents.ReactForm.useWatch("type", duplicateForm);
1313
+ const handleOk = () => {
1314
+ duplicateForm.validateFields().then((values) => {
1315
+ onOk(values);
1316
+ }).catch((info) => {
1317
+ console.log("Validate Failed:", info);
1318
+ });
1319
+ };
1320
+ const afterOpenChange = (visible) => {
1321
+ if (visible) {
1322
+ duplicateForm.resetFields();
1323
+ }
1324
+ };
1325
+ return /* @__PURE__ */ jsxRuntime.jsx(
1326
+ reactComponents.ReactModal,
1327
+ {
1328
+ title: "\u590D\u5236\u7ECF\u7EAC",
1329
+ open,
1330
+ onOk: handleOk,
1331
+ onCancel,
1332
+ afterOpenChange,
1333
+ width: 400,
1334
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1335
+ reactComponents.ReactForm,
1336
+ {
1337
+ form: duplicateForm,
1338
+ layout: "vertical",
1339
+ initialValues: {
1340
+ type: "y",
1341
+ count: 1,
1342
+ startPos: 1,
1343
+ endPos: 1,
1344
+ insertPos: 1
1345
+ },
1346
+ children: [
1347
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u7C7B\u578B", name: "type", children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.ReactRadio.Group, { children: [
1348
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "y", children: "\u7EAC" }),
1349
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "x", children: "\u7ECF" })
1350
+ ] }) }),
1351
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.ReactRow, { gutter: 16, children: [
1352
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactCol, { span: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
1353
+ reactComponents.ReactForm.Item,
1354
+ {
1355
+ label: duplicateType === "y" ? "\u63D2\u5165\u884C" : "\u63D2\u5165\u5217",
1356
+ name: "insertPos",
1357
+ rules: [{ required: true, message: "\u8BF7\u8F93\u5165\u63D2\u5165\u4F4D\u7F6E" }],
1358
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactInputNumber, { min: 1, style: { width: "100%" } })
1359
+ }
1360
+ ) }),
1361
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactCol, { span: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
1362
+ reactComponents.ReactForm.Item,
1363
+ {
1364
+ label: "\u590D\u5236\u6B21\u6570",
1365
+ name: "count",
1366
+ rules: [{ required: true, message: "\u8BF7\u8F93\u5165\u6B21\u6570" }],
1367
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactInputNumber, { min: 1, style: { width: "100%" } })
1368
+ }
1369
+ ) })
1370
+ ] }),
1371
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.ReactRow, { gutter: 16, children: [
1372
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactCol, { span: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
1373
+ reactComponents.ReactForm.Item,
1374
+ {
1375
+ label: duplicateType === "y" ? "\u5F00\u59CB\u884C" : "\u5F00\u59CB\u5217",
1376
+ name: "startPos",
1377
+ rules: [{ required: true, message: "\u8BF7\u8F93\u5165\u5F00\u59CB\u4F4D\u7F6E" }],
1378
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactInputNumber, { min: 1, style: { width: "100%" } })
1379
+ }
1380
+ ) }),
1381
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactCol, { span: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
1382
+ reactComponents.ReactForm.Item,
1383
+ {
1384
+ label: duplicateType === "y" ? "\u7ED3\u675F\u884C" : "\u7ED3\u675F\u5217",
1385
+ name: "endPos",
1386
+ dependencies: ["startPos"],
1387
+ rules: [
1388
+ { required: true, message: "\u8BF7\u8F93\u5165\u7ED3\u675F\u4F4D\u7F6E" },
1389
+ ({ getFieldValue }) => ({
1390
+ validator(_, value) {
1391
+ const start = getFieldValue("startPos");
1392
+ if (typeof start === "number" && typeof value === "number" && value < start) {
1393
+ return Promise.reject(
1394
+ new Error("\u7ED3\u675F\u4F4D\u7F6E\u4E0D\u80FD\u5C0F\u4E8E\u5F00\u59CB\u4F4D\u7F6E")
1395
+ );
1396
+ }
1397
+ return Promise.resolve();
1398
+ }
1399
+ })
1400
+ ],
1401
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactInputNumber, { min: 1, style: { width: "100%" } })
1402
+ }
1403
+ ) })
1404
+ ] })
1405
+ ]
1406
+ }
1407
+ )
1408
+ }
1409
+ );
1410
+ };
1411
+ var batch_copy_modal_default = BatchCopyModal;
1412
+ var CreateLoopModal = ({
1413
+ open,
1414
+ onCancel,
1415
+ onSubmit,
1416
+ verticalScaleSize,
1417
+ horizontalScaleSize
1418
+ }) => {
1419
+ const [form] = reactComponents.ReactForm.useForm();
1420
+ const type = reactComponents.ReactForm.useWatch("type", form);
1421
+ const handleOk = () => {
1422
+ form.validateFields().then((values) => {
1423
+ onSubmit(values);
1424
+ }).catch((info) => {
1425
+ console.log("Validate Failed:", info);
1426
+ });
1427
+ };
1428
+ const afterOpenChange = (visible) => {
1429
+ if (visible) {
1430
+ form.resetFields();
1431
+ }
1432
+ };
1433
+ return /* @__PURE__ */ jsxRuntime.jsx(
1434
+ reactComponents.ReactModal,
1435
+ {
1436
+ title: "\u65B0\u5EFA\u5FAA\u73AF",
1437
+ open,
1438
+ onOk: handleOk,
1439
+ onCancel,
1440
+ afterOpenChange,
1441
+ width: 400,
1442
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1443
+ reactComponents.ReactForm,
1444
+ {
1445
+ form,
1446
+ layout: "vertical",
1447
+ initialValues: { type: "y", count: 2, startPos: 1, endPos: 1 },
1448
+ children: [
1449
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u7C7B\u578B", name: "type", children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.ReactRadio.Group, { children: [
1450
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "y", children: "\u7EAC" }),
1451
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "x", children: "\u7ECF" })
1452
+ ] }) }),
1453
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.ReactRow, { gutter: 16, children: [
1454
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactCol, { span: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
1455
+ reactComponents.ReactForm.Item,
1456
+ {
1457
+ label: type === "y" ? "\u5F00\u59CB\u884C" : "\u5F00\u59CB\u5217",
1458
+ name: "startPos",
1459
+ rules: [{ required: true, message: "\u8BF7\u8F93\u5165\u5F00\u59CB\u4F4D\u7F6E" }],
1460
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1461
+ reactComponents.ReactInputNumber,
1462
+ {
1463
+ min: 1,
1464
+ max: type === "y" ? verticalScaleSize : horizontalScaleSize,
1465
+ style: { width: "100%" }
1466
+ }
1467
+ )
1468
+ }
1469
+ ) }),
1470
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactCol, { span: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
1471
+ reactComponents.ReactForm.Item,
1472
+ {
1473
+ label: type === "y" ? "\u7ED3\u675F\u884C" : "\u7ED3\u675F\u5217",
1474
+ name: "endPos",
1475
+ dependencies: ["startPos"],
1476
+ rules: [
1477
+ { required: true, message: "\u8BF7\u8F93\u5165\u7ED3\u675F\u4F4D\u7F6E" },
1478
+ ({ getFieldValue }) => ({
1479
+ validator(_, value) {
1480
+ const start = getFieldValue("startPos");
1481
+ const max = type === "y" ? verticalScaleSize : horizontalScaleSize;
1482
+ if (typeof start === "number" && typeof value === "number" && value < start) {
1483
+ return Promise.reject(
1484
+ new Error("\u7ED3\u675F\u4F4D\u7F6E\u4E0D\u80FD\u5C0F\u4E8E\u5F00\u59CB\u4F4D\u7F6E")
1485
+ );
1486
+ }
1487
+ if (typeof value === "number" && value > max) {
1488
+ return Promise.reject(
1489
+ new Error(`\u7ED3\u675F\u4F4D\u7F6E\u4E0D\u80FD\u5927\u4E8E ${max}`)
1490
+ );
1491
+ }
1492
+ return Promise.resolve();
1493
+ }
1494
+ })
1495
+ ],
1496
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1497
+ reactComponents.ReactInputNumber,
1498
+ {
1499
+ min: 1,
1500
+ max: type === "y" ? verticalScaleSize : horizontalScaleSize,
1501
+ style: { width: "100%" }
1502
+ }
1503
+ )
1504
+ }
1505
+ ) })
1506
+ ] }),
1507
+ /* @__PURE__ */ jsxRuntime.jsx(
1508
+ reactComponents.ReactForm.Item,
1509
+ {
1510
+ label: "\u5FAA\u73AF\u6B21\u6570",
1511
+ name: "count",
1512
+ rules: [
1513
+ { required: true, message: "\u8BF7\u8F93\u5165\u6B21\u6570" },
1514
+ { type: "number", min: 2, message: "\u5FAA\u73AF\u6B21\u6570\u4E0D\u80FD\u5C0F\u4E8E 2" },
1515
+ { type: "integer", message: "\u5FAA\u73AF\u6B21\u6570\u5FC5\u987B\u662F\u6574\u6570" }
1516
+ ],
1517
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactInputNumber, { min: 2, style: { width: "100%" } })
1518
+ }
1519
+ )
1520
+ ]
1521
+ }
1522
+ )
1523
+ }
1524
+ );
1525
+ };
1526
+ var create_loop_modal_default = CreateLoopModal;
1527
+ var EditLoopModal = ({
1528
+ open,
1529
+ onCancel,
1530
+ onSubmit,
1531
+ loops,
1532
+ loopsInSelection,
1533
+ verticalScaleSize,
1534
+ horizontalScaleSize
1535
+ }) => {
1536
+ const [form] = reactComponents.ReactForm.useForm();
1537
+ const type = reactComponents.ReactForm.useWatch("type", form);
1538
+ const handleOk = () => {
1539
+ form.validateFields().then((values) => {
1540
+ onSubmit(values);
1541
+ }).catch((info) => {
1542
+ console.log("Validate Failed:", info);
1543
+ });
1544
+ };
1545
+ const handleLoopSelect = (val) => {
1546
+ const loop = loops.find((l) => l.id === val);
1547
+ if (loop) {
1548
+ form.setFieldsValue({
1549
+ startPos: loop.startPos + 1,
1550
+ endPos: loop.endPos + 1,
1551
+ count: loop.count
1552
+ });
1553
+ }
1554
+ };
1555
+ const afterOpenChange = (visible) => {
1556
+ if (visible) {
1557
+ form.resetFields();
1558
+ const preferredLoops = loopsInSelection.length > 0 ? loopsInSelection : loops;
1559
+ const yLoops = preferredLoops.filter((l) => l.type === "y");
1560
+ const xLoops = preferredLoops.filter((l) => l.type === "x");
1561
+ let targetType = "y";
1562
+ if (yLoops.length === 0 && xLoops.length > 0) {
1563
+ targetType = "x";
1564
+ }
1565
+ form.setFieldsValue({
1566
+ type: targetType,
1567
+ count: 2
1568
+ });
1569
+ }
1570
+ };
1571
+ return /* @__PURE__ */ jsxRuntime.jsx(
1572
+ reactComponents.ReactModal,
1573
+ {
1574
+ title: "\u7F16\u8F91\u5FAA\u73AF",
1575
+ open,
1576
+ onOk: handleOk,
1577
+ onCancel,
1578
+ afterOpenChange,
1579
+ width: 400,
1580
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.ReactForm, { form, layout: "vertical", children: [
1581
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u7C7B\u578B", name: "type", initialValue: "y", children: /* @__PURE__ */ jsxRuntime.jsxs(
1582
+ reactComponents.ReactRadio.Group,
1583
+ {
1584
+ onChange: () => {
1585
+ form.setFieldsValue({
1586
+ loopId: void 0,
1587
+ startPos: void 0,
1588
+ endPos: void 0,
1589
+ count: void 0
1590
+ });
1591
+ },
1592
+ children: [
1593
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "y", children: "\u7EAC" }),
1594
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "x", children: "\u7ECF" })
1595
+ ]
1596
+ }
1597
+ ) }),
1598
+ /* @__PURE__ */ jsxRuntime.jsx(
1599
+ reactComponents.ReactForm.Item,
1600
+ {
1601
+ label: "\u5FAA\u73AF\u5E8F\u53F7",
1602
+ name: "loopId",
1603
+ rules: [{ required: true, message: "\u8BF7\u9009\u62E9\u5FAA\u73AF" }],
1604
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1605
+ reactComponents.ReactSelect,
1606
+ {
1607
+ placeholder: "\u8BF7\u9009\u62E9\u5FAA\u73AF\u5E8F\u53F7",
1608
+ onChange: handleLoopSelect,
1609
+ options: loops.filter((loop) => loop.type === type).map((loop) => ({
1610
+ value: loop.id,
1611
+ label: `\u5E8F\u53F7 ${loops.findIndex((item) => item.id === loop.id) + 1} (\u8303\u56F4 ${loop.startPos + 1}-${loop.endPos + 1})`
1612
+ }))
1613
+ }
1614
+ )
1615
+ }
1616
+ ),
1617
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.ReactRow, { gutter: 16, children: [
1618
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactCol, { span: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
1619
+ reactComponents.ReactForm.Item,
1620
+ {
1621
+ label: type === "y" ? "\u5F00\u59CB\u884C" : "\u5F00\u59CB\u5217",
1622
+ name: "startPos",
1623
+ rules: [{ required: true, message: "\u8BF7\u8F93\u5165\u5F00\u59CB\u4F4D\u7F6E" }],
1624
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1625
+ reactComponents.ReactInputNumber,
1626
+ {
1627
+ min: 1,
1628
+ max: type === "y" ? verticalScaleSize : horizontalScaleSize,
1629
+ style: { width: "100%" }
1630
+ }
1631
+ )
1632
+ }
1633
+ ) }),
1634
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactCol, { span: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
1635
+ reactComponents.ReactForm.Item,
1636
+ {
1637
+ label: type === "y" ? "\u7ED3\u675F\u884C" : "\u7ED3\u675F\u5217",
1638
+ name: "endPos",
1639
+ dependencies: ["startPos"],
1640
+ rules: [
1641
+ { required: true, message: "\u8BF7\u8F93\u5165\u7ED3\u675F\u4F4D\u7F6E" },
1642
+ ({ getFieldValue }) => ({
1643
+ validator(_, value) {
1644
+ const start = getFieldValue("startPos");
1645
+ const max = type === "y" ? verticalScaleSize : horizontalScaleSize;
1646
+ if (typeof start === "number" && typeof value === "number" && value < start) {
1647
+ return Promise.reject(
1648
+ new Error("\u7ED3\u675F\u4F4D\u7F6E\u4E0D\u80FD\u5C0F\u4E8E\u5F00\u59CB\u4F4D\u7F6E")
1649
+ );
1650
+ }
1651
+ if (typeof value === "number" && value > max) {
1652
+ return Promise.reject(
1653
+ new Error(`\u7ED3\u675F\u4F4D\u7F6E\u4E0D\u80FD\u5927\u4E8E ${max}`)
1654
+ );
1655
+ }
1656
+ return Promise.resolve();
1657
+ }
1658
+ })
1659
+ ],
1660
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1661
+ reactComponents.ReactInputNumber,
1662
+ {
1663
+ min: 1,
1664
+ max: type === "y" ? verticalScaleSize : horizontalScaleSize,
1665
+ style: { width: "100%" }
1666
+ }
1667
+ )
1668
+ }
1669
+ ) })
1670
+ ] }),
1671
+ /* @__PURE__ */ jsxRuntime.jsx(
1672
+ reactComponents.ReactForm.Item,
1673
+ {
1674
+ label: "\u5FAA\u73AF\u6B21\u6570",
1675
+ name: "count",
1676
+ rules: [
1677
+ { required: true, message: "\u8BF7\u8F93\u5165\u6B21\u6570" },
1678
+ { type: "number", min: 2, message: "\u5FAA\u73AF\u6B21\u6570\u4E0D\u80FD\u5C0F\u4E8E 2" },
1679
+ { type: "integer", message: "\u5FAA\u73AF\u6B21\u6570\u5FC5\u987B\u662F\u6574\u6570" }
1680
+ ],
1681
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactInputNumber, { min: 2, style: { width: "100%" } })
1682
+ }
1683
+ )
1684
+ ] })
1685
+ }
1686
+ );
1687
+ };
1688
+ var edit_loop_modal_default = EditLoopModal;
1689
+ var DeleteLoopModal = ({
1690
+ open,
1691
+ onCancel,
1692
+ onSubmit,
1693
+ loops,
1694
+ loopsInSelection
1695
+ }) => {
1696
+ const [form] = reactComponents.ReactForm.useForm();
1697
+ const type = reactComponents.ReactForm.useWatch("type", form);
1698
+ const handleOk = () => {
1699
+ form.validateFields().then((values) => {
1700
+ onSubmit(values);
1701
+ }).catch((info) => {
1702
+ console.log("Validate Failed:", info);
1703
+ });
1704
+ };
1705
+ const afterOpenChange = (visible) => {
1706
+ if (visible) {
1707
+ form.resetFields();
1708
+ const preferredLoops = loopsInSelection.length > 0 ? loopsInSelection : loops;
1709
+ const yLoops = preferredLoops.filter((l) => l.type === "y");
1710
+ const xLoops = preferredLoops.filter((l) => l.type === "x");
1711
+ let targetType = "y";
1712
+ if (yLoops.length === 0 && xLoops.length > 0) {
1713
+ targetType = "x";
1714
+ }
1715
+ form.setFieldsValue({ type: targetType });
1716
+ }
1717
+ };
1718
+ return /* @__PURE__ */ jsxRuntime.jsx(
1719
+ reactComponents.ReactModal,
1720
+ {
1721
+ title: "\u5220\u9664\u5FAA\u73AF",
1722
+ open,
1723
+ onOk: handleOk,
1724
+ onCancel,
1725
+ afterOpenChange,
1726
+ width: 400,
1727
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.ReactForm, { form, layout: "vertical", children: [
1728
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u7C7B\u578B", name: "type", initialValue: "y", children: /* @__PURE__ */ jsxRuntime.jsxs(
1729
+ reactComponents.ReactRadio.Group,
1730
+ {
1731
+ onChange: () => {
1732
+ form.setFieldsValue({ loopId: void 0 });
1733
+ },
1734
+ children: [
1735
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "y", children: "\u7EAC" }),
1736
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "x", children: "\u7ECF" })
1737
+ ]
1738
+ }
1739
+ ) }),
1740
+ /* @__PURE__ */ jsxRuntime.jsx(
1741
+ reactComponents.ReactForm.Item,
1742
+ {
1743
+ label: "\u5FAA\u73AF\u5E8F\u53F7",
1744
+ name: "loopId",
1745
+ rules: [{ required: true, message: "\u8BF7\u9009\u62E9\u8981\u5220\u9664\u7684\u5FAA\u73AF" }],
1746
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1747
+ reactComponents.ReactSelect,
1748
+ {
1749
+ placeholder: "\u8BF7\u9009\u62E9\u5FAA\u73AF\u5E8F\u53F7",
1750
+ options: loops.filter((loop) => loop.type === type).map((loop) => ({
1751
+ value: loop.id,
1752
+ label: `\u5E8F\u53F7 ${loops.findIndex((item) => item.id === loop.id) + 1} (\u8303\u56F4 ${loop.startPos + 1}-${loop.endPos + 1})`
1753
+ }))
1754
+ }
1755
+ )
1756
+ }
1757
+ )
1758
+ ] })
1759
+ }
1760
+ );
1761
+ };
1762
+ var delete_loop_modal_default = DeleteLoopModal;
1763
+ var InsertJingWeiModal = ({
1764
+ open,
1765
+ onCancel,
1766
+ onOk,
1767
+ verticalScaleSize,
1768
+ horizontalScaleSize
1769
+ }) => {
1770
+ const [form] = reactComponents.ReactForm.useForm();
1771
+ const type = reactComponents.ReactForm.useWatch("type", form) || "y";
1772
+ const handleOk = () => {
1773
+ form.validateFields().then((values) => {
1774
+ onOk(values);
1775
+ }).catch((info) => {
1776
+ console.log("Validate Failed:", info);
1777
+ });
1778
+ };
1779
+ const afterOpenChange = (visible) => {
1780
+ if (visible) {
1781
+ form.resetFields();
1782
+ }
1783
+ };
1784
+ return /* @__PURE__ */ jsxRuntime.jsx(
1785
+ reactComponents.ReactModal,
1786
+ {
1787
+ title: "\u63D2\u5165\u7ECF\u7EAC",
1788
+ open,
1789
+ onOk: handleOk,
1790
+ onCancel,
1791
+ afterOpenChange,
1792
+ width: 400,
1793
+ destroyOnClose: true,
1794
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1795
+ reactComponents.ReactForm,
1796
+ {
1797
+ form,
1798
+ layout: "vertical",
1799
+ initialValues: { type: "y", count: 1 },
1800
+ children: [
1801
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u7C7B\u578B", name: "type", children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.ReactRadio.Group, { children: [
1802
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "y", children: "\u7EAC" }),
1803
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "x", children: "\u7ECF" })
1804
+ ] }) }),
1805
+ /* @__PURE__ */ jsxRuntime.jsx(
1806
+ reactComponents.ReactForm.Item,
1807
+ {
1808
+ label: "\u63D2\u5165\u4F4D\u7F6E",
1809
+ name: "insertPos",
1810
+ rules: [{ required: true, message: "\u8BF7\u8F93\u5165\u63D2\u5165\u4F4D\u7F6E" }],
1811
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1812
+ reactComponents.ReactInputNumber,
1813
+ {
1814
+ min: 1,
1815
+ max: type === "y" ? verticalScaleSize : horizontalScaleSize,
1816
+ style: { width: "100%" },
1817
+ placeholder: "\u63D2\u5165\u8D77\u59CB\u70B9"
1818
+ }
1819
+ )
1820
+ }
1821
+ ),
1822
+ /* @__PURE__ */ jsxRuntime.jsx(
1823
+ reactComponents.ReactForm.Item,
1824
+ {
1825
+ label: "\u63D2\u5165\u6570\u91CF",
1826
+ name: "count",
1827
+ rules: [{ required: true, message: "\u8BF7\u8F93\u5165\u63D2\u5165\u6570\u91CF" }],
1828
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactInputNumber, { min: 1, style: { width: "100%" } })
1829
+ }
1830
+ )
1831
+ ]
1832
+ }
1833
+ )
1834
+ }
1835
+ );
1836
+ };
1837
+ var insert_jing_wei_modal_default = InsertJingWeiModal;
1838
+ var DeleteJingWeiModal = ({
1839
+ open,
1840
+ onCancel,
1841
+ onOk,
1842
+ verticalScaleSize,
1843
+ horizontalScaleSize
1844
+ }) => {
1845
+ const [form] = reactComponents.ReactForm.useForm();
1846
+ const type = reactComponents.ReactForm.useWatch("type", form) || "y";
1847
+ const handleOk = () => {
1848
+ form.validateFields().then((values) => {
1849
+ onOk(values);
1850
+ }).catch((info) => {
1851
+ console.log("Validate Failed:", info);
1852
+ });
1853
+ };
1854
+ const afterOpenChange = (visible) => {
1855
+ if (visible) {
1856
+ form.resetFields();
1857
+ }
1858
+ };
1859
+ return /* @__PURE__ */ jsxRuntime.jsx(
1860
+ reactComponents.ReactModal,
1861
+ {
1862
+ title: "\u5220\u9664\u7ECF\u7EAC",
1863
+ open,
1864
+ onOk: handleOk,
1865
+ onCancel,
1866
+ afterOpenChange,
1867
+ width: 400,
1868
+ destroyOnClose: true,
1869
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1870
+ reactComponents.ReactForm,
1871
+ {
1872
+ form,
1873
+ layout: "vertical",
1874
+ initialValues: { type: "y", startPos: 1, endPos: 1 },
1875
+ children: [
1876
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u7C7B\u578B", name: "type", children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.ReactRadio.Group, { children: [
1877
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "y", children: "\u7EAC" }),
1878
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "x", children: "\u7ECF" })
1879
+ ] }) }),
1880
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.ReactRow, { gutter: 16, children: [
1881
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactCol, { span: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
1882
+ reactComponents.ReactForm.Item,
1883
+ {
1884
+ label: type === "y" ? "\u5F00\u59CB\u884C" : "\u5F00\u59CB\u5217",
1885
+ name: "startPos",
1886
+ rules: [{ required: true, message: "\u8BF7\u8F93\u5165\u5F00\u59CB\u4F4D\u7F6E" }],
1887
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1888
+ reactComponents.ReactInputNumber,
1889
+ {
1890
+ min: 1,
1891
+ max: type === "y" ? verticalScaleSize : horizontalScaleSize,
1892
+ style: { width: "100%" },
1893
+ placeholder: "\u5F00\u59CB\u4F4D\u7F6E"
1894
+ }
1895
+ )
1896
+ }
1897
+ ) }),
1898
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactCol, { span: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
1899
+ reactComponents.ReactForm.Item,
1900
+ {
1901
+ label: type === "y" ? "\u7ED3\u675F\u884C" : "\u7ED3\u675F\u5217",
1902
+ name: "endPos",
1903
+ dependencies: ["startPos"],
1904
+ rules: [
1905
+ { required: true, message: "\u8BF7\u8F93\u5165\u7ED3\u675F\u4F4D\u7F6E" },
1906
+ ({ getFieldValue }) => ({
1907
+ validator(_, value) {
1908
+ const start = getFieldValue("startPos");
1909
+ if (typeof start === "number" && typeof value === "number" && value < start) {
1910
+ return Promise.reject(
1911
+ new Error("\u7ED3\u675F\u4F4D\u7F6E\u4E0D\u80FD\u5C0F\u4E8E\u5F00\u59CB\u4F4D\u7F6E")
1912
+ );
1913
+ }
1914
+ return Promise.resolve();
1915
+ }
1916
+ })
1917
+ ],
1918
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1919
+ reactComponents.ReactInputNumber,
1920
+ {
1921
+ min: 1,
1922
+ max: type === "y" ? verticalScaleSize : horizontalScaleSize,
1923
+ style: { width: "100%" },
1924
+ placeholder: "\u7ED3\u675F\u4F4D\u7F6E"
1925
+ }
1926
+ )
1927
+ }
1928
+ ) })
1929
+ ] })
1930
+ ]
1931
+ }
1932
+ )
1933
+ }
1934
+ );
1935
+ };
1936
+ var delete_jing_wei_modal_default = DeleteJingWeiModal;
1937
+ var CreateMemoModal = ({
1938
+ open,
1939
+ onCancel,
1940
+ onSubmit,
1941
+ verticalScaleSize,
1942
+ horizontalScaleSize
1943
+ }) => {
1944
+ const [form] = reactComponents.ReactForm.useForm();
1945
+ const type = reactComponents.ReactForm.useWatch("type", form);
1946
+ const handleOk = () => {
1947
+ form.validateFields().then((values) => {
1948
+ onSubmit(values);
1949
+ }).catch((info) => {
1950
+ console.log("Validate Failed:", info);
1951
+ });
1952
+ };
1953
+ const afterOpenChange = (visible) => {
1954
+ if (visible) {
1955
+ form.resetFields();
1956
+ }
1957
+ };
1958
+ return /* @__PURE__ */ jsxRuntime.jsx(
1959
+ reactComponents.ReactModal,
1960
+ {
1961
+ title: "\u65B0\u5EFA\u5907\u6CE8",
1962
+ open,
1963
+ onOk: handleOk,
1964
+ onCancel,
1965
+ afterOpenChange,
1966
+ width: 400,
1967
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1968
+ reactComponents.ReactForm,
1969
+ {
1970
+ form,
1971
+ layout: "vertical",
1972
+ initialValues: { type: "y", startPos: 1, endPos: 1 },
1973
+ children: [
1974
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u7C7B\u578B", name: "type", children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.ReactRadio.Group, { children: [
1975
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "y", children: "\u7EAC" }),
1976
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "x", children: "\u7ECF" })
1977
+ ] }) }),
1978
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.ReactRow, { gutter: 16, children: [
1979
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactCol, { span: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
1980
+ reactComponents.ReactForm.Item,
1981
+ {
1982
+ label: type === "y" ? "\u5F00\u59CB\u884C" : "\u5F00\u59CB\u5217",
1983
+ name: "startPos",
1984
+ rules: [{ required: true, message: "\u8BF7\u8F93\u5165\u5F00\u59CB\u4F4D\u7F6E" }],
1985
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1986
+ reactComponents.ReactInputNumber,
1987
+ {
1988
+ min: 1,
1989
+ max: type === "y" ? verticalScaleSize : horizontalScaleSize,
1990
+ style: { width: "100%" }
1991
+ }
1992
+ )
1993
+ }
1994
+ ) }),
1995
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactCol, { span: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
1996
+ reactComponents.ReactForm.Item,
1997
+ {
1998
+ label: type === "y" ? "\u7ED3\u675F\u884C" : "\u7ED3\u675F\u5217",
1999
+ name: "endPos",
2000
+ dependencies: ["startPos"],
2001
+ rules: [
2002
+ { required: true, message: "\u8BF7\u8F93\u5165\u7ED3\u675F\u4F4D\u7F6E" },
2003
+ ({ getFieldValue }) => ({
2004
+ validator(_, value) {
2005
+ const start = getFieldValue("startPos");
2006
+ const max = type === "y" ? verticalScaleSize : horizontalScaleSize;
2007
+ if (typeof start === "number" && typeof value === "number" && value < start) {
2008
+ return Promise.reject(
2009
+ new Error("\u7ED3\u675F\u4F4D\u7F6E\u4E0D\u80FD\u5C0F\u4E8E\u5F00\u59CB\u4F4D\u7F6E")
2010
+ );
2011
+ }
2012
+ if (typeof value === "number" && value > max) {
2013
+ return Promise.reject(
2014
+ new Error(`\u7ED3\u675F\u4F4D\u7F6E\u4E0D\u80FD\u5927\u4E8E ${max}`)
2015
+ );
2016
+ }
2017
+ return Promise.resolve();
2018
+ }
2019
+ })
2020
+ ],
2021
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2022
+ reactComponents.ReactInputNumber,
2023
+ {
2024
+ min: 1,
2025
+ max: type === "y" ? verticalScaleSize : horizontalScaleSize,
2026
+ style: { width: "100%" }
2027
+ }
2028
+ )
2029
+ }
2030
+ ) })
2031
+ ] }),
2032
+ /* @__PURE__ */ jsxRuntime.jsx(
2033
+ reactComponents.ReactForm.Item,
2034
+ {
2035
+ label: "\u5907\u6CE8\u5185\u5BB9",
2036
+ name: "content",
2037
+ rules: [{ required: true, message: "\u8BF7\u8F93\u5165\u5907\u6CE8\u5185\u5BB9" }],
2038
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactTextArea, { rows: 3, placeholder: "\u8BF7\u8F93\u5165\u5907\u6CE8..." })
2039
+ }
2040
+ )
2041
+ ]
2042
+ }
2043
+ )
2044
+ }
2045
+ );
2046
+ };
2047
+ var create_memo_modal_default = CreateMemoModal;
2048
+ var DeleteMemoModal = ({
2049
+ open,
2050
+ onCancel,
2051
+ onSubmit,
2052
+ memosInSelection
2053
+ }) => {
2054
+ const [form] = reactComponents.ReactForm.useForm();
2055
+ const type = reactComponents.ReactForm.useWatch("type", form);
2056
+ const handleOk = () => {
2057
+ form.validateFields().then((values) => {
2058
+ onSubmit(values);
2059
+ }).catch((info) => {
2060
+ console.log("Validate Failed:", info);
2061
+ });
2062
+ };
2063
+ const afterOpenChange = (visible) => {
2064
+ if (visible) {
2065
+ form.resetFields();
2066
+ const yMemos = memosInSelection.filter((m) => m.type === "y");
2067
+ const xMemos = memosInSelection.filter((m) => m.type === "x");
2068
+ let targetType = "y";
2069
+ if (yMemos.length === 0 && xMemos.length > 0) {
2070
+ targetType = "x";
2071
+ }
2072
+ form.setFieldsValue({ type: targetType });
2073
+ }
2074
+ };
2075
+ return /* @__PURE__ */ jsxRuntime.jsx(
2076
+ reactComponents.ReactModal,
2077
+ {
2078
+ title: "\u5220\u9664\u5907\u6CE8",
2079
+ open,
2080
+ onOk: handleOk,
2081
+ onCancel,
2082
+ afterOpenChange,
2083
+ width: 400,
2084
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.ReactForm, { form, layout: "vertical", children: [
2085
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u7C7B\u578B", name: "type", initialValue: "y", children: /* @__PURE__ */ jsxRuntime.jsxs(
2086
+ reactComponents.ReactRadio.Group,
2087
+ {
2088
+ onChange: () => {
2089
+ form.setFieldsValue({ memoId: void 0 });
2090
+ },
2091
+ children: [
2092
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "y", children: "\u7EAC" }),
2093
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "x", children: "\u7ECF" })
2094
+ ]
2095
+ }
2096
+ ) }),
2097
+ /* @__PURE__ */ jsxRuntime.jsx(
2098
+ reactComponents.ReactForm.Item,
2099
+ {
2100
+ label: "\u5907\u6CE8",
2101
+ name: "memoId",
2102
+ rules: [{ required: true, message: "\u8BF7\u9009\u62E9\u8981\u5220\u9664\u7684\u5907\u6CE8" }],
2103
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2104
+ reactComponents.ReactSelect,
2105
+ {
2106
+ placeholder: "\u8BF7\u9009\u62E9\u5907\u6CE8",
2107
+ options: memosInSelection.filter((memo2) => memo2.type === type).map((memo2) => ({
2108
+ value: memo2.id,
2109
+ label: `\u8303\u56F4 ${memo2.startPos + 1}-${memo2.endPos + 1}: ${memo2.content.length > 10 ? `${memo2.content.slice(0, 10)}...` : memo2.content}`
2110
+ }))
2111
+ }
2112
+ )
2113
+ }
2114
+ )
2115
+ ] })
2116
+ }
2117
+ );
2118
+ };
2119
+ var delete_memo_modal_default = DeleteMemoModal;
2120
+ var SCROLLBAR_THICKNESS2 = 12;
2121
+ var DrawingBoard = React.forwardRef(
2122
+ ({
2123
+ horizontalScaleSize,
2124
+ verticalScaleSize = horizontalScaleSize,
2125
+ step,
2126
+ rightPadding,
2127
+ topPadding,
2128
+ thickness,
2129
+ canvasRightMargin,
2130
+ canvasTopMargin,
2131
+ defaultRight,
2132
+ defaultBottom,
2133
+ majorInterval,
2134
+ midInterval,
2135
+ onHoverGridChange,
2136
+ onMaxGridChange,
2137
+ onMaxGridExpandedChange,
2138
+ readonly = false,
2139
+ showCursor = true,
2140
+ width = "100%",
2141
+ height = 650,
2142
+ showScrollbar = true,
2143
+ midTickFontSize,
2144
+ majorTickFontSize,
2145
+ loopFontSize,
2146
+ printMode = false,
2147
+ markPointFontSize,
2148
+ loopWingOffset,
2149
+ midTickLength,
2150
+ majorTickLength,
2151
+ smallTickLength,
2152
+ showSmallTickText,
2153
+ smallTickFontSize,
2154
+ hoverEffectColor,
2155
+ markSelectColor,
2156
+ markCheckedColor,
2157
+ markPointColor,
2158
+ cursorColor,
2159
+ mainGridColor,
2160
+ minorTickColor,
2161
+ rulerBgColor,
2162
+ rulerTextColor,
2163
+ rulerTickColor,
2164
+ rulerBorderColor,
2165
+ loopIndicatorColor,
2166
+ loopTextColor,
2167
+ loopTickExtension,
2168
+ showLoopArrow = true,
2169
+ loopArrowSize,
2170
+ showInnerLoopEndpoints,
2171
+ onGirdClick
2172
+ }, ref) => {
2173
+ const viewportRef = React.useRef(null);
2174
+ const gridRef = React.useRef(null);
2175
+ const size = ahooks.useSize(viewportRef);
2176
+ const viewportWidth = size?.width || 0;
2177
+ const viewportHeight = size?.height || 0;
2178
+ const hasInitialScrolledY = React.useRef(false);
2179
+ React.useEffect(() => {
2180
+ hasInitialScrolledY.current = false;
2181
+ }, [defaultBottom]);
2182
+ const [scrollLeft, setScrollLeft] = React.useState(0);
2183
+ const [scrollTop, setScrollTop] = React.useState(0);
2184
+ const scrollPositionRef = React.useRef({ left: 0, top: 0 });
2185
+ const wheelScrollTargetRef = React.useRef(null);
2186
+ const wheelScrollFrameRef = React.useRef(null);
2187
+ const wheelScrollLastTimeRef = React.useRef(0);
2188
+ React.useEffect(() => {
2189
+ scrollPositionRef.current = { left: scrollLeft, top: scrollTop };
2190
+ }, [scrollLeft, scrollTop]);
2191
+ const stopWheelScrollSmoothing = React.useCallback(() => {
2192
+ if (wheelScrollFrameRef.current !== null) {
2193
+ cancelAnimationFrame(wheelScrollFrameRef.current);
2194
+ wheelScrollFrameRef.current = null;
2195
+ }
2196
+ wheelScrollTargetRef.current = null;
2197
+ wheelScrollLastTimeRef.current = 0;
2198
+ }, []);
2199
+ const applyWheelScrollPosition = React.useCallback(
2200
+ (position) => {
2201
+ scrollPositionRef.current = position;
2202
+ setScrollLeft(position.left);
2203
+ setScrollTop(position.top);
2204
+ },
2205
+ []
2206
+ );
2207
+ const advanceWheelScroll = React.useCallback(
2208
+ function advance(timestamp) {
2209
+ wheelScrollFrameRef.current = null;
2210
+ const target = wheelScrollTargetRef.current;
2211
+ if (!target) return;
2212
+ const deltaMs = Math.max(timestamp - wheelScrollLastTimeRef.current, 0);
2213
+ wheelScrollLastTimeRef.current = timestamp;
2214
+ const result = advanceWheelScrollSmoothing({
2215
+ current: scrollPositionRef.current,
2216
+ target,
2217
+ deltaMs
2218
+ });
2219
+ applyWheelScrollPosition(result.next);
2220
+ if (result.done) {
2221
+ wheelScrollTargetRef.current = null;
2222
+ wheelScrollLastTimeRef.current = 0;
2223
+ return;
2224
+ }
2225
+ wheelScrollFrameRef.current = requestAnimationFrame(advance);
2226
+ },
2227
+ [applyWheelScrollPosition]
2228
+ );
2229
+ const startWheelScrollSmoothing = React.useCallback(
2230
+ (target) => {
2231
+ wheelScrollTargetRef.current = target;
2232
+ if (wheelScrollFrameRef.current !== null) return;
2233
+ wheelScrollLastTimeRef.current = performance.now();
2234
+ wheelScrollFrameRef.current = requestAnimationFrame(advanceWheelScroll);
2235
+ },
2236
+ [advanceWheelScroll]
2237
+ );
2238
+ React.useEffect(
2239
+ () => () => {
2240
+ stopWheelScrollSmoothing();
2241
+ },
2242
+ [stopWheelScrollSmoothing]
2243
+ );
2244
+ const {
2245
+ value: gridMarks = {},
2246
+ setValue: setGridMarksRaw,
2247
+ back,
2248
+ forward,
2249
+ reset,
2250
+ backLength,
2251
+ forwardLength
2252
+ } = ahooks.useHistoryTravel({});
2253
+ const gridMarksRef = React.useRef(gridMarks);
2254
+ React.useEffect(() => {
2255
+ gridMarksRef.current = gridMarks;
2256
+ }, [gridMarks]);
2257
+ const setGridMarks = React.useCallback(
2258
+ (valOrFn) => {
2259
+ if (typeof valOrFn === "function") {
2260
+ setGridMarksRaw(valOrFn(gridMarksRef.current));
2261
+ } else {
2262
+ setGridMarksRaw(valOrFn);
2263
+ }
2264
+ },
2265
+ [setGridMarksRaw]
2266
+ );
2267
+ const canUndo = backLength > 0;
2268
+ const canRedo = forwardLength > 0;
2269
+ const onUndo = back;
2270
+ const onRedo = forward;
2271
+ const [clipboard, setClipboard] = React.useState(null);
2272
+ const [copyModalOpen, setCopyModalOpen] = React.useState(false);
2273
+ const [loopModalOpen, setLoopModalOpen] = React.useState(false);
2274
+ const [editLoopModalOpen, setEditLoopModalOpen] = React.useState(false);
2275
+ const [deleteLoopModalOpen, setDeleteLoopModalOpen] = React.useState(false);
2276
+ const [insertModalOpen, setInsertModalOpen] = React.useState(false);
2277
+ const [deleteJingWeiModalOpen, setDeleteJingWeiModalOpen] = React.useState(false);
2278
+ const [memos, setMemos] = React.useState([]);
2279
+ const [memoModalOpen, setMemoModalOpen] = React.useState(false);
2280
+ const [deleteMemoModalOpen, setDeleteMemoModalOpen] = React.useState(false);
2281
+ const [loops, setLoops] = React.useState([]);
2282
+ const orderedLoops = React.useMemo(() => {
2283
+ const rowLoops = loops.filter((l) => l.type === "y");
2284
+ const colLoops = loops.filter((l) => l.type === "x");
2285
+ const sortFn = (a, b) => b.endPos - b.startPos - (a.endPos - a.startPos);
2286
+ return [...rowLoops.sort(sortFn), ...colLoops.sort(sortFn)];
2287
+ }, [loops]);
2288
+ const [isExpanded, setIsExpanded] = React.useState(false);
2289
+ const [baseMarks, setBaseMarks] = React.useState(null);
2290
+ const [isClickModeEnabled, setIsClickModeEnabled] = React.useState(true);
2291
+ const [historyLogs, setHistoryLogs] = React.useState([]);
2292
+ const [isHistoryModalOpen, setIsHistoryModalOpen] = React.useState(false);
2293
+ const addLog = React.useCallback((content) => {
2294
+ const now = /* @__PURE__ */ new Date();
2295
+ const timeStr = now.toLocaleTimeString();
2296
+ setHistoryLogs((prev) => [
2297
+ {
2298
+ id: prev.length + 1,
2299
+ time: timeStr,
2300
+ content
2301
+ },
2302
+ ...prev
2303
+ ]);
2304
+ }, []);
2305
+ const clearLogs = React.useCallback(() => {
2306
+ setHistoryLogs([]);
2307
+ }, []);
2308
+ const contentBounds = React.useMemo(() => {
2309
+ let maxX = -1;
2310
+ let maxY = -1;
2311
+ Object.keys(gridMarks).forEach((key) => {
2312
+ const [x, y] = key.split(",").map(Number);
2313
+ maxX = Math.max(maxX, x);
2314
+ maxY = Math.max(maxY, y);
2315
+ });
2316
+ if (!isExpanded) {
2317
+ loops.forEach((loop) => {
2318
+ if (loop.type === "x") {
2319
+ maxX = Math.max(maxX, loop.endPos);
2320
+ } else {
2321
+ maxY = Math.max(maxY, loop.endPos);
2322
+ }
2323
+ });
2324
+ memos.forEach((memo2) => {
2325
+ if (memo2.type === "x") {
2326
+ maxX = Math.max(maxX, memo2.endPos);
2327
+ } else {
2328
+ maxY = Math.max(maxY, memo2.endPos);
2329
+ }
2330
+ });
2331
+ }
2332
+ return { maxX, maxY };
2333
+ }, [gridMarks, loops, memos, isExpanded]);
2334
+ React.useEffect(() => {
2335
+ if (!onMaxGridExpandedChange) return;
2336
+ const { maxX, maxY } = contentBounds;
2337
+ let baseX = maxX;
2338
+ let baseY = maxY;
2339
+ if (baseX < 0) {
2340
+ baseX = (horizontalScaleSize || 0) - 1;
2341
+ }
2342
+ if (baseY < 0) {
2343
+ baseY = (verticalScaleSize || 0) - 1;
2344
+ }
2345
+ const yLoops = loops.filter((l) => l.type === "y");
2346
+ const xLoops = loops.filter((l) => l.type === "x");
2347
+ const getExpandedPos = (targetPos, curLoops) => {
2348
+ let cur = targetPos;
2349
+ const sortedLoops = [...curLoops].sort((a, b) => {
2350
+ const sizeA = a.endPos - a.startPos;
2351
+ const sizeB = b.endPos - b.startPos;
2352
+ if (sizeA !== sizeB) return sizeA - sizeB;
2353
+ return a.startPos - b.startPos;
2354
+ });
2355
+ const workingLoops = sortedLoops.map((l) => ({ ...l }));
2356
+ for (let i = 0; i < workingLoops.length; i++) {
2357
+ const loop = workingLoops[i];
2358
+ const loopLen = loop.endPos - loop.startPos + 1;
2359
+ const expands = loopLen * (loop.count - 1);
2360
+ if (cur > loop.endPos) {
2361
+ cur += expands;
2362
+ } else if (cur >= loop.startPos && cur <= loop.endPos) {
2363
+ const insideOffset = cur - loop.startPos;
2364
+ cur = loop.startPos + insideOffset + expands;
2365
+ }
2366
+ const insertAt = loop.endPos + 1;
2367
+ for (let j = i + 1; j < workingLoops.length; j++) {
2368
+ const other = workingLoops[j];
2369
+ if (insertAt <= other.startPos) {
2370
+ other.startPos += expands;
2371
+ other.endPos += expands;
2372
+ } else if (other.startPos < insertAt && insertAt <= other.endPos + 1) {
2373
+ other.endPos += expands;
2374
+ }
2375
+ }
2376
+ }
2377
+ return cur;
2378
+ };
2379
+ const maxRow = isExpanded ? baseY + 1 : baseY >= 0 ? getExpandedPos(baseY, yLoops) + 1 : 0;
2380
+ const maxCol = isExpanded ? baseX + 1 : baseX >= 0 ? getExpandedPos(baseX, xLoops) + 1 : 0;
2381
+ if (loops.length === 0) {
2382
+ onMaxGridExpandedChange(null);
2383
+ } else {
2384
+ onMaxGridExpandedChange({ x: maxCol, y: maxRow });
2385
+ }
2386
+ }, [
2387
+ contentBounds,
2388
+ loops,
2389
+ isExpanded,
2390
+ horizontalScaleSize,
2391
+ verticalScaleSize,
2392
+ onMaxGridExpandedChange
2393
+ ]);
2394
+ const displayHorizontalScaleSize = React.useMemo(() => {
2395
+ if (!printMode) return horizontalScaleSize;
2396
+ const { maxX } = contentBounds;
2397
+ if (maxX === -1) return horizontalScaleSize;
2398
+ return Math.min(horizontalScaleSize, maxX + 1);
2399
+ }, [printMode, horizontalScaleSize, contentBounds]);
2400
+ const displayVerticalScaleSize = React.useMemo(() => {
2401
+ if (!printMode) return verticalScaleSize;
2402
+ const { maxY } = contentBounds;
2403
+ if (maxY === -1) return verticalScaleSize;
2404
+ return Math.min(verticalScaleSize, maxY + 1);
2405
+ }, [printMode, verticalScaleSize, contentBounds]);
2406
+ const totalWidth = React.useMemo(
2407
+ () => thickness + displayHorizontalScaleSize * step + rightPadding,
2408
+ [thickness, displayHorizontalScaleSize, step, rightPadding]
2409
+ );
2410
+ const totalHeight = React.useMemo(
2411
+ () => thickness + displayVerticalScaleSize * step + topPadding,
2412
+ [thickness, displayVerticalScaleSize, step, topPadding]
2413
+ );
2414
+ const computedWidth = React.useMemo(() => {
2415
+ if (!printMode) return width;
2416
+ return width;
2417
+ }, [printMode, width, totalWidth, canvasRightMargin]);
2418
+ const computedHeight = React.useMemo(() => {
2419
+ if (!printMode) return height;
2420
+ return height;
2421
+ }, [printMode, height, totalHeight, canvasTopMargin]);
2422
+ const printModeBottomPending = React.useRef(false);
2423
+ React.useEffect(() => {
2424
+ printModeBottomPending.current = true;
2425
+ }, [printMode]);
2426
+ React.useEffect(() => {
2427
+ stopWheelScrollSmoothing();
2428
+ const handle = requestAnimationFrame(() => {
2429
+ if (viewportWidth > 0) {
2430
+ const maxScrollX = Math.max(
2431
+ 0,
2432
+ totalWidth - (viewportWidth - canvasRightMargin)
2433
+ );
2434
+ setScrollLeft((previous) => {
2435
+ const next = defaultRight ? maxScrollX : Math.min(previous, maxScrollX);
2436
+ scrollPositionRef.current.left = next;
2437
+ return next;
2438
+ });
2439
+ } else {
2440
+ scrollPositionRef.current.left = 0;
2441
+ setScrollLeft(0);
2442
+ }
2443
+ if (viewportHeight > 0) {
2444
+ const maxScrollY = Math.max(
2445
+ 0,
2446
+ totalHeight - (viewportHeight - canvasTopMargin - (showScrollbar ? SCROLLBAR_THICKNESS2 : 0))
2447
+ );
2448
+ setScrollTop((previous) => {
2449
+ let next = Math.min(previous, maxScrollY);
2450
+ if (printModeBottomPending.current) {
2451
+ next = maxScrollY;
2452
+ printModeBottomPending.current = false;
2453
+ } else if (defaultBottom && !hasInitialScrolledY.current && maxScrollY > 0) {
2454
+ next = maxScrollY;
2455
+ hasInitialScrolledY.current = true;
2456
+ }
2457
+ scrollPositionRef.current.top = next;
2458
+ return next;
2459
+ });
2460
+ } else {
2461
+ scrollPositionRef.current.top = 0;
2462
+ setScrollTop(0);
2463
+ }
2464
+ });
2465
+ return () => cancelAnimationFrame(handle);
2466
+ }, [
2467
+ totalWidth,
2468
+ totalHeight,
2469
+ viewportWidth,
2470
+ viewportHeight,
2471
+ defaultBottom,
2472
+ defaultRight,
2473
+ canvasRightMargin,
2474
+ canvasTopMargin,
2475
+ printMode,
2476
+ showScrollbar,
2477
+ stopWheelScrollSmoothing
2478
+ ]);
2479
+ const isContentDragging = React.useRef(false);
2480
+ const contentStartPos = React.useRef({ x: 0, y: 0 });
2481
+ const contentStartScroll = React.useRef({ left: 0, top: 0 });
2482
+ const autoScrollRaf = React.useRef(null);
2483
+ const autoScrollSpeed = React.useRef({ x: 0, y: 0 });
2484
+ const AUTO_SCROLL_SPEED = 10;
2485
+ const stopAutoScroll = () => {
2486
+ if (autoScrollRaf.current) {
2487
+ cancelAnimationFrame(autoScrollRaf.current);
2488
+ autoScrollRaf.current = null;
2489
+ }
2490
+ };
2491
+ const performAutoScroll = () => {
2492
+ const { x: speedX, y: speedY } = autoScrollSpeed.current;
2493
+ if (speedX === 0 && speedY === 0) {
2494
+ stopAutoScroll();
2495
+ return;
2496
+ }
2497
+ setScrollLeft((prev) => {
2498
+ const maxScrollX = Math.max(
2499
+ 0,
2500
+ totalWidth - (viewportWidth - canvasRightMargin)
2501
+ );
2502
+ const next = Math.min(Math.max(prev + speedX, 0), maxScrollX);
2503
+ if (next !== prev) {
2504
+ contentStartScroll.current.left += speedX;
2505
+ }
2506
+ return next;
2507
+ });
2508
+ setScrollTop((prev) => {
2509
+ const maxScrollY = Math.max(
2510
+ 0,
2511
+ totalHeight - (viewportHeight - canvasTopMargin - (showScrollbar ? SCROLLBAR_THICKNESS2 : 0))
2512
+ );
2513
+ const next = Math.min(Math.max(prev + speedY, 0), maxScrollY);
2514
+ if (next !== prev) {
2515
+ contentStartScroll.current.top += speedY;
2516
+ }
2517
+ return next;
2518
+ });
2519
+ autoScrollRaf.current = requestAnimationFrame(performAutoScroll);
2520
+ };
2521
+ const handleContentMouseDown = (e) => {
2522
+ stopWheelScrollSmoothing();
2523
+ isContentDragging.current = true;
2524
+ contentStartPos.current = { x: e.clientX, y: e.clientY };
2525
+ contentStartScroll.current = { left: scrollLeft, top: scrollTop };
2526
+ };
2527
+ ahooks.useEventListener("mousemove", (e) => {
2528
+ if (!isContentDragging.current) return;
2529
+ const deltaX = e.clientX - contentStartPos.current.x;
2530
+ const deltaY = e.clientY - contentStartPos.current.y;
2531
+ const maxScrollX = Math.max(
2532
+ 0,
2533
+ totalWidth - (viewportWidth - canvasRightMargin)
2534
+ );
2535
+ const maxScrollY = Math.max(
2536
+ 0,
2537
+ totalHeight - (viewportHeight - canvasTopMargin - (showScrollbar ? SCROLLBAR_THICKNESS2 : 0))
2538
+ );
2539
+ const newScrollLeft = contentStartScroll.current.left - deltaX;
2540
+ const newScrollTop = contentStartScroll.current.top + deltaY;
2541
+ if (viewportRef.current) {
2542
+ const rect = viewportRef.current.getBoundingClientRect();
2543
+ const margin = 0;
2544
+ let sx = 0;
2545
+ let sy = 0;
2546
+ if (e.clientY < rect.top - margin) sy = -AUTO_SCROLL_SPEED;
2547
+ else if (e.clientY > rect.bottom + margin) sy = AUTO_SCROLL_SPEED;
2548
+ if (e.clientX < rect.left - margin) sx = -AUTO_SCROLL_SPEED;
2549
+ else if (e.clientX > rect.right + margin) sx = AUTO_SCROLL_SPEED;
2550
+ if (sx !== 0 || sy !== 0) {
2551
+ autoScrollSpeed.current = { x: sx, y: sy };
2552
+ if (!autoScrollRaf.current) {
2553
+ autoScrollRaf.current = requestAnimationFrame(performAutoScroll);
2554
+ }
2555
+ } else {
2556
+ stopAutoScroll();
2557
+ }
2558
+ }
2559
+ setScrollLeft(Math.min(Math.max(newScrollLeft, 0), maxScrollX));
2560
+ setScrollTop(Math.min(Math.max(newScrollTop, 0), maxScrollY));
2561
+ });
2562
+ ahooks.useEventListener("mouseup", () => {
2563
+ if (isContentDragging.current) {
2564
+ isContentDragging.current = false;
2565
+ stopAutoScroll();
2566
+ }
2567
+ });
2568
+ ahooks.useEventListener(
2569
+ "wheel",
2570
+ (e) => {
2571
+ const maxScrollX = Math.max(
2572
+ 0,
2573
+ totalWidth - (viewportWidth - canvasRightMargin)
2574
+ );
2575
+ const maxScrollY = Math.max(
2576
+ 0,
2577
+ totalHeight - (viewportHeight - canvasTopMargin - (showScrollbar ? SCROLLBAR_THICKNESS2 : 0))
2578
+ );
2579
+ const delta = resolveWheelScrollDelta({
2580
+ deltaX: e.deltaX,
2581
+ deltaY: e.deltaY,
2582
+ deltaMode: e.deltaMode,
2583
+ shiftKey: e.shiftKey,
2584
+ lineHeight: step,
2585
+ pageWidth: Math.max(viewportWidth - canvasRightMargin, step),
2586
+ pageHeight: Math.max(
2587
+ viewportHeight - canvasTopMargin - (showScrollbar ? SCROLLBAR_THICKNESS2 : 0),
2588
+ step
2589
+ )
2590
+ });
2591
+ const canScrollX = maxScrollX > 0 && delta.left !== 0;
2592
+ const canScrollY = maxScrollY > 0 && delta.top !== 0;
2593
+ if (!canScrollX && !canScrollY) return;
2594
+ e.preventDefault();
2595
+ e.stopPropagation();
2596
+ const basePosition = wheelScrollTargetRef.current ?? scrollPositionRef.current;
2597
+ const nextTarget = {
2598
+ left: canScrollX ? Math.min(Math.max(basePosition.left + delta.left, 0), maxScrollX) : basePosition.left,
2599
+ top: canScrollY ? Math.min(Math.max(basePosition.top + delta.top, 0), maxScrollY) : basePosition.top
2600
+ };
2601
+ if (shouldApplyWheelDeltaImmediately({
2602
+ deltaX: e.deltaX,
2603
+ deltaY: e.deltaY,
2604
+ deltaMode: e.deltaMode
2605
+ })) {
2606
+ stopWheelScrollSmoothing();
2607
+ applyWheelScrollPosition(nextTarget);
2608
+ return;
2609
+ }
2610
+ startWheelScrollSmoothing(nextTarget);
2611
+ },
2612
+ { target: viewportRef, passive: false }
2613
+ );
2614
+ const handleSelectAll = React.useCallback(() => {
2615
+ setGridMarks((prev) => maintopPattern.GridModel.selectAll(prev));
2616
+ addLog("\u5168\u9009");
2617
+ }, [setGridMarks, addLog]);
2618
+ const handleClearSelect = React.useCallback(() => {
2619
+ setGridMarks((prev) => maintopPattern.GridModel.deleteSelectionContent(prev));
2620
+ addLog("\u6E05\u9664\u9009\u533A\u5185\u5BB9");
2621
+ }, [setGridMarks, addLog]);
2622
+ const handleClearAll = React.useCallback(() => {
2623
+ setGridMarks(maintopPattern.GridModel.clearAll());
2624
+ addLog("\u5168\u90E8\u6E05\u9664");
2625
+ }, [setGridMarks, addLog]);
2626
+ const handleShowBack = React.useCallback(() => {
2627
+ setGridMarks((prev) => maintopPattern.GridModel.showBack(prev));
2628
+ addLog("\u663E\u793A\u53CD\u9762");
2629
+ }, [setGridMarks, addLog]);
2630
+ const handleOpenHistory = React.useCallback(() => {
2631
+ setIsHistoryModalOpen(true);
2632
+ }, []);
2633
+ const handleUndoClick = React.useCallback(() => {
2634
+ if (canUndo) {
2635
+ onUndo();
2636
+ addLog("\u64A4\u9500");
2637
+ }
2638
+ }, [canUndo, onUndo, addLog]);
2639
+ const handleRedoClick = React.useCallback(() => {
2640
+ if (canRedo) {
2641
+ onRedo();
2642
+ addLog("\u91CD\u505A");
2643
+ }
2644
+ }, [canRedo, onRedo, addLog]);
2645
+ const onScrollRequest = React.useCallback(
2646
+ (dx, dy) => {
2647
+ const maxScrollX = Math.max(
2648
+ 0,
2649
+ totalWidth - (viewportWidth - canvasRightMargin)
2650
+ );
2651
+ const maxScrollY = Math.max(
2652
+ 0,
2653
+ totalHeight - (viewportHeight - canvasTopMargin - (showScrollbar ? SCROLLBAR_THICKNESS2 : 0))
2654
+ );
2655
+ setScrollLeft((prev) => Math.min(Math.max(prev + dx, 0), maxScrollX));
2656
+ setScrollTop((prev) => Math.min(Math.max(prev + dy, 0), maxScrollY));
2657
+ },
2658
+ [
2659
+ totalWidth,
2660
+ totalHeight,
2661
+ viewportWidth,
2662
+ viewportHeight,
2663
+ canvasRightMargin,
2664
+ canvasTopMargin,
2665
+ showScrollbar
2666
+ ]
2667
+ );
2668
+ const handleCopy = React.useCallback(() => {
2669
+ const cp = maintopPattern.GridModel.copy(gridMarks);
2670
+ if (cp) {
2671
+ setClipboard(cp);
2672
+ addLog("\u590D\u5236");
2673
+ }
2674
+ }, [gridMarks, addLog]);
2675
+ const handleCut = React.useCallback(() => {
2676
+ const res = maintopPattern.GridModel.cut(gridMarks);
2677
+ if (res) {
2678
+ setGridMarks(res.nextMarks);
2679
+ setClipboard(res.clipboard);
2680
+ addLog("\u526A\u5207");
2681
+ }
2682
+ }, [gridMarks, setGridMarks, addLog]);
2683
+ const handlePaste = React.useCallback(() => {
2684
+ if (clipboard) {
2685
+ setGridMarks(
2686
+ (prev) => maintopPattern.GridModel.paste(
2687
+ prev,
2688
+ clipboard,
2689
+ horizontalScaleSize,
2690
+ verticalScaleSize
2691
+ )
2692
+ );
2693
+ addLog("\u7C98\u8D34");
2694
+ }
2695
+ }, [
2696
+ clipboard,
2697
+ horizontalScaleSize,
2698
+ verticalScaleSize,
2699
+ setGridMarks,
2700
+ addLog
2701
+ ]);
2702
+ const handleDuplicateSubmit = React.useCallback(
2703
+ (values) => {
2704
+ const { insertPos, startPos, endPos, count, type } = values;
2705
+ const s = startPos - 1;
2706
+ const e = endPos - 1;
2707
+ const at = insertPos - 1;
2708
+ if (type === "y") {
2709
+ setGridMarks(
2710
+ (prev) => maintopPattern.GridModel.duplicateRows(prev, s, e, at, count, verticalScaleSize)
2711
+ );
2712
+ } else {
2713
+ setGridMarks(
2714
+ (prev) => maintopPattern.GridModel.duplicateCols(prev, s, e, at, count, horizontalScaleSize)
2715
+ );
2716
+ }
2717
+ addLog(
2718
+ `\u590D\u5236${type === "y" ? "\u7EAC" : "\u7ECF"} (${startPos}-${endPos} -> \u63D2\u5165\u81F3:${insertPos} \u6B21\u6570:${count})`
2719
+ );
2720
+ setCopyModalOpen(false);
2721
+ },
2722
+ [verticalScaleSize, horizontalScaleSize, setGridMarks, addLog]
2723
+ );
2724
+ const handleInsertSubmit = React.useCallback(
2725
+ (values) => {
2726
+ const { insertPos, count, type } = values;
2727
+ const s = insertPos - 1;
2728
+ const blockSize = 1;
2729
+ if (type === "y") {
2730
+ setGridMarks(
2731
+ (prev) => maintopPattern.GridModel.insertBlankRows(
2732
+ prev,
2733
+ s,
2734
+ blockSize,
2735
+ count,
2736
+ verticalScaleSize
2737
+ )
2738
+ );
2739
+ } else {
2740
+ setGridMarks(
2741
+ (prev) => maintopPattern.GridModel.insertBlankCols(
2742
+ prev,
2743
+ s,
2744
+ blockSize,
2745
+ count,
2746
+ horizontalScaleSize
2747
+ )
2748
+ );
2749
+ }
2750
+ addLog(
2751
+ `\u63D2\u5165\u7A7A\u767D${type === "y" ? "\u7EAC" : "\u7ECF"} (\u4F4D\u7F6E:${insertPos} \u6570\u91CF:${count})`
2752
+ );
2753
+ setInsertModalOpen(false);
2754
+ },
2755
+ [verticalScaleSize, horizontalScaleSize, setGridMarks, addLog]
2756
+ );
2757
+ const handleDeleteJingWeiSubmit = React.useCallback(
2758
+ (values) => {
2759
+ const { startPos, endPos, type } = values;
2760
+ const s = startPos - 1;
2761
+ const e = endPos - 1;
2762
+ const shiftAmount = e - s + 1;
2763
+ if (type === "y") {
2764
+ setGridMarks((prev) => maintopPattern.GridModel.deleteRows(prev, s, e));
2765
+ } else {
2766
+ setGridMarks((prev) => maintopPattern.GridModel.deleteCols(prev, s, e));
2767
+ }
2768
+ setLoops((prev) => {
2769
+ return prev.map((loop) => {
2770
+ if (loop.type !== type) return loop;
2771
+ let newStart = loop.startPos;
2772
+ let newEnd = loop.endPos;
2773
+ if (loop.startPos >= s && loop.startPos <= e) {
2774
+ newStart = s;
2775
+ } else if (loop.startPos > e) {
2776
+ newStart = loop.startPos - shiftAmount;
2777
+ }
2778
+ if (loop.endPos >= s && loop.endPos <= e) {
2779
+ newEnd = s - 1;
2780
+ } else if (loop.endPos > e) {
2781
+ newEnd = loop.endPos - shiftAmount;
2782
+ }
2783
+ if (newStart > newEnd) return null;
2784
+ return { ...loop, startPos: newStart, endPos: newEnd };
2785
+ }).filter(Boolean);
2786
+ });
2787
+ setMemos((prev) => {
2788
+ return prev.map((memo2) => {
2789
+ if (memo2.type !== type) return memo2;
2790
+ let newStart = memo2.startPos;
2791
+ let newEnd = memo2.endPos;
2792
+ if (memo2.startPos >= s && memo2.startPos <= e) {
2793
+ newStart = s;
2794
+ } else if (memo2.startPos > e) {
2795
+ newStart = memo2.startPos - shiftAmount;
2796
+ }
2797
+ if (memo2.endPos >= s && memo2.endPos <= e) {
2798
+ newEnd = s - 1;
2799
+ } else if (memo2.endPos > e) {
2800
+ newEnd = memo2.endPos - shiftAmount;
2801
+ }
2802
+ if (newStart > newEnd) return null;
2803
+ return { ...memo2, startPos: newStart, endPos: newEnd };
2804
+ }).filter(Boolean);
2805
+ });
2806
+ addLog(
2807
+ `\u5220\u9664${type === "y" ? "\u7EAC" : "\u7ECF"} (\u4F4D\u7F6E:${startPos}-${endPos})`
2808
+ );
2809
+ setDeleteJingWeiModalOpen(false);
2810
+ },
2811
+ [
2812
+ verticalScaleSize,
2813
+ horizontalScaleSize,
2814
+ setGridMarks,
2815
+ setLoops,
2816
+ setMemos,
2817
+ addLog
2818
+ ]
2819
+ );
2820
+ const handleLoopSubmit = React.useCallback(
2821
+ (values) => {
2822
+ const { startPos, endPos, count, type } = values;
2823
+ const s = startPos - 1;
2824
+ const e = endPos - 1;
2825
+ const hasPartialOverlap = loops.some((loop) => {
2826
+ if (loop.type !== type) return false;
2827
+ const s1 = loop.startPos;
2828
+ const e1 = loop.endPos;
2829
+ const s2 = s;
2830
+ const e2 = e;
2831
+ const hasIntersection = !(e2 < s1 || s2 > e1);
2832
+ if (!hasIntersection) return false;
2833
+ const isNested = s2 >= s1 && e2 <= e1 || s1 >= s2 && e1 <= e2;
2834
+ return !isNested;
2835
+ });
2836
+ if (hasPartialOverlap) {
2837
+ reactComponents.reactMessage.error("\u6240\u9009\u8303\u56F4\u4E0E\u73B0\u6709\u5FAA\u73AF\u5B58\u5728\u975E\u6CD5\u4EA4\u53C9\uFF0C\u8BF7\u91CD\u65B0\u9009\u62E9");
2838
+ return;
2839
+ }
2840
+ const newLoop = {
2841
+ id: Date.now().toString(),
2842
+ type,
2843
+ startPos: s,
2844
+ endPos: e,
2845
+ count
2846
+ };
2847
+ setLoops((prev) => [...prev, newLoop]);
2848
+ addLog(
2849
+ `\u6DFB\u52A0\u5FAA\u73AF (${type === "y" ? "\u7EAC" : "\u7ECF"} ${startPos}-${endPos} x${count})`
2850
+ );
2851
+ setLoopModalOpen(false);
2852
+ },
2853
+ [loops, addLog]
2854
+ );
2855
+ const handleEditLoopSubmit = React.useCallback(
2856
+ (values) => {
2857
+ const { loopId, startPos, endPos, count, type } = values;
2858
+ const s = startPos - 1;
2859
+ const e = endPos - 1;
2860
+ const hasPartialOverlap = loops.some((loop) => {
2861
+ if (loop.id === loopId) return false;
2862
+ if (loop.type !== type) return false;
2863
+ const s1 = loop.startPos;
2864
+ const e1 = loop.endPos;
2865
+ const s2 = s;
2866
+ const e2 = e;
2867
+ const hasIntersection = !(e2 < s1 || s2 > e1);
2868
+ if (!hasIntersection) return false;
2869
+ const isNested = s2 >= s1 && e2 <= e1 || s1 >= s2 && e1 <= e2;
2870
+ return !isNested;
2871
+ });
2872
+ if (hasPartialOverlap) {
2873
+ reactComponents.reactMessage.error("\u4FEE\u6539\u540E\u7684\u8303\u56F4\u4E0E\u73B0\u6709\u5FAA\u73AF\u5B58\u5728\u975E\u6CD5\u4EA4\u53C9\uFF0C\u8BF7\u91CD\u65B0\u9009\u62E9");
2874
+ return;
2875
+ }
2876
+ setLoops(
2877
+ (prev) => prev.map((loop) => {
2878
+ if (loop.id === loopId) {
2879
+ return {
2880
+ ...loop,
2881
+ startPos: s,
2882
+ endPos: e,
2883
+ count
2884
+ };
2885
+ }
2886
+ return loop;
2887
+ })
2888
+ );
2889
+ addLog(
2890
+ `\u7F16\u8F91\u5FAA\u73AF (${type === "y" ? "\u7EAC" : "\u7ECF"} ${startPos}-${endPos} x${count})`
2891
+ );
2892
+ setEditLoopModalOpen(false);
2893
+ },
2894
+ [loops, addLog]
2895
+ );
2896
+ const selectionBounds = React.useMemo(
2897
+ () => maintopPattern.GridModel.getSelectionBounds(gridMarks),
2898
+ [gridMarks]
2899
+ );
2900
+ const loopsInSelection = React.useMemo(() => {
2901
+ if (!selectionBounds) return [];
2902
+ const { minX, maxX, minY, maxY } = selectionBounds;
2903
+ return loops.map((l, idx) => ({ ...l, globalIndex: idx + 1 })).filter((loop) => {
2904
+ if (loop.type === "y") {
2905
+ return !(maxY < loop.startPos || minY > loop.endPos);
2906
+ } else {
2907
+ return !(maxX < loop.startPos || minX > loop.endPos);
2908
+ }
2909
+ });
2910
+ }, [selectionBounds, loops]);
2911
+ const memosInSelection = React.useMemo(() => {
2912
+ if (!selectionBounds) return [];
2913
+ const { minX, maxX, minY, maxY } = selectionBounds;
2914
+ return memos.map((m, idx) => ({ ...m, globalIndex: idx + 1 })).filter((memo2) => {
2915
+ if (memo2.type === "y") {
2916
+ return !(maxY < memo2.startPos || minY > memo2.endPos);
2917
+ } else {
2918
+ return !(maxX < memo2.startPos || minX > memo2.endPos);
2919
+ }
2920
+ });
2921
+ }, [selectionBounds, memos]);
2922
+ const handleOpenEditLoop = React.useCallback(() => {
2923
+ setEditLoopModalOpen(true);
2924
+ }, []);
2925
+ const handleOpenDeleteLoop = React.useCallback(() => {
2926
+ setDeleteLoopModalOpen(true);
2927
+ }, []);
2928
+ const handleDeleteLoopSubmit = React.useCallback(
2929
+ (values) => {
2930
+ const { loopId } = values;
2931
+ setLoops((prev) => prev.filter((loop) => loop.id !== loopId));
2932
+ addLog("\u5220\u9664\u5FAA\u73AF");
2933
+ setDeleteLoopModalOpen(false);
2934
+ },
2935
+ [addLog]
2936
+ );
2937
+ const handleMemoSubmit = React.useCallback(
2938
+ (values) => {
2939
+ const { startPos, endPos, content, type } = values;
2940
+ const s = startPos - 1;
2941
+ const e = endPos - 1;
2942
+ memos.some((m) => {
2943
+ if (m.type !== type) return false;
2944
+ return !(e < m.startPos || s > m.endPos);
2945
+ });
2946
+ const newMemo = {
2947
+ id: Date.now().toString(),
2948
+ type,
2949
+ startPos: s,
2950
+ endPos: e,
2951
+ content
2952
+ };
2953
+ setMemos((prev) => [...prev, newMemo]);
2954
+ addLog(
2955
+ `\u65B0\u5EFA\u5907\u6CE8 (${type === "y" ? "\u7EAC" : "\u7ECF"} ${startPos}-${endPos})`
2956
+ );
2957
+ setMemoModalOpen(false);
2958
+ },
2959
+ [memos, addLog]
2960
+ );
2961
+ const handleOpenDeleteMemo = React.useCallback(() => {
2962
+ setDeleteMemoModalOpen(true);
2963
+ }, []);
2964
+ const handleDeleteMemoSubmit = React.useCallback(
2965
+ (values) => {
2966
+ const { memoId } = values;
2967
+ setMemos((prev) => prev.filter((m) => m.id !== memoId));
2968
+ addLog("\u5220\u9664\u5907\u6CE8");
2969
+ setDeleteMemoModalOpen(false);
2970
+ },
2971
+ [addLog]
2972
+ );
2973
+ const getBeforeOpenPattern = () => {
2974
+ if (isExpanded && baseMarks) {
2975
+ return maintopPattern.GridModel.binaryToPatternDesignString(baseMarks, loops);
2976
+ }
2977
+ return maintopPattern.GridModel.binaryToPatternDesignString(gridMarks, loops);
2978
+ };
2979
+ const getAfterOpenPattern = () => {
2980
+ if (isExpanded) {
2981
+ return maintopPattern.GridModel.binaryToPatternDesignString(gridMarks);
2982
+ }
2983
+ if (loops.length > 0) {
2984
+ let tempMarks = { ...gridMarks };
2985
+ const rowLoops = loops.filter((l) => l.type === "y").map((l) => ({ ...l })).sort((a, b) => a.endPos - a.startPos - (b.endPos - b.startPos));
2986
+ for (let i = 0; i < rowLoops.length; i++) {
2987
+ const current = rowLoops[i];
2988
+ tempMarks = maintopPattern.GridModel.createLoopRows(
2989
+ tempMarks,
2990
+ current.startPos,
2991
+ current.endPos,
2992
+ current.count,
2993
+ verticalScaleSize
2994
+ );
2995
+ const height2 = current.endPos - current.startPos + 1;
2996
+ const totalShift = height2 * (current.count - 1);
2997
+ const insertAt = current.endPos + 1;
2998
+ for (let j = i + 1; j < rowLoops.length; j++) {
2999
+ const other = rowLoops[j];
3000
+ if (insertAt <= other.startPos) {
3001
+ other.startPos += totalShift;
3002
+ other.endPos += totalShift;
3003
+ } else if (other.startPos < insertAt && insertAt <= other.endPos + 1) {
3004
+ other.endPos += totalShift;
3005
+ }
3006
+ }
3007
+ }
3008
+ const colLoops = loops.filter((l) => l.type === "x").map((l) => ({ ...l })).sort((a, b) => a.endPos - a.startPos - (b.endPos - b.startPos));
3009
+ for (let i = 0; i < colLoops.length; i++) {
3010
+ const current = colLoops[i];
3011
+ tempMarks = maintopPattern.GridModel.createLoopCols(
3012
+ tempMarks,
3013
+ current.startPos,
3014
+ current.endPos,
3015
+ current.count,
3016
+ horizontalScaleSize
3017
+ );
3018
+ const width2 = current.endPos - current.startPos + 1;
3019
+ const totalShift = width2 * (current.count - 1);
3020
+ const insertAt = current.endPos + 1;
3021
+ for (let j = i + 1; j < colLoops.length; j++) {
3022
+ const other = colLoops[j];
3023
+ if (insertAt <= other.startPos) {
3024
+ other.startPos += totalShift;
3025
+ other.endPos += totalShift;
3026
+ } else if (other.startPos < insertAt && insertAt <= other.endPos + 1) {
3027
+ other.endPos += totalShift;
3028
+ }
3029
+ }
3030
+ }
3031
+ return maintopPattern.GridModel.binaryToPatternDesignString(tempMarks);
3032
+ }
3033
+ return maintopPattern.GridModel.binaryToPatternDesignString(gridMarks);
3034
+ };
3035
+ const loadPattern = (patternString, parseLoops = false) => {
3036
+ if (!patternString) return;
3037
+ try {
3038
+ const {
3039
+ point,
3040
+ row,
3041
+ column,
3042
+ loops: parsedLoops
3043
+ } = maintopPattern.GridModel.parsePatternDesignString(patternString);
3044
+ const marks = { ...point };
3045
+ const loadedLoops = [];
3046
+ if (parsedLoops && parsedLoops.length > 0) {
3047
+ loadedLoops.push(...parsedLoops);
3048
+ }
3049
+ let curRows = row;
3050
+ let curCols = column;
3051
+ if (parseLoops && loadedLoops.length === 0) {
3052
+ const rowLoop = maintopPattern.GridModel.detectRowLoop(marks, curRows, curCols);
3053
+ if (rowLoop) {
3054
+ loadedLoops.push({
3055
+ id: Date.now().toString() + "-row",
3056
+ ...rowLoop
3057
+ });
3058
+ curRows = rowLoop.endPos + 1;
3059
+ Object.keys(marks).forEach((key) => {
3060
+ const [, y] = key.split(",").map(Number);
3061
+ if (y >= curRows) {
3062
+ delete marks[key];
3063
+ }
3064
+ });
3065
+ }
3066
+ const colLoop = maintopPattern.GridModel.detectColLoop(marks, curRows, curCols);
3067
+ if (colLoop) {
3068
+ loadedLoops.push({
3069
+ id: Date.now().toString() + "-col",
3070
+ ...colLoop
3071
+ });
3072
+ curCols = colLoop.endPos + 1;
3073
+ Object.keys(marks).forEach((key) => {
3074
+ const [x] = key.split(",").map(Number);
3075
+ if (x >= curCols) {
3076
+ delete marks[key];
3077
+ }
3078
+ });
3079
+ }
3080
+ }
3081
+ reset(marks);
3082
+ setLoops(loadedLoops);
3083
+ setMemos([]);
3084
+ setHistoryLogs([]);
3085
+ setBaseMarks(null);
3086
+ setIsExpanded(false);
3087
+ addLog("\u52A0\u8F7D\u6392\u7248");
3088
+ } catch (e) {
3089
+ console.error("Failed to load pattern:", e);
3090
+ reactComponents.reactMessage.error("\u6392\u7248\u89E3\u6790\u5931\u8D25");
3091
+ }
3092
+ };
3093
+ React.useImperativeHandle(ref, () => ({
3094
+ getBeforeOpenPattern,
3095
+ getAfterOpenPattern,
3096
+ loadPattern,
3097
+ exportImage: (type, quality, forceExpanded) => {
3098
+ return gridRef.current?.toDataURL(type, quality, forceExpanded) || {
3099
+ url: "",
3100
+ width: 0,
3101
+ height: 0,
3102
+ dpi: 0
3103
+ };
3104
+ },
3105
+ exportSvg: (forceExpanded) => {
3106
+ return gridRef.current?.toSVG(forceExpanded) || {
3107
+ svg: "",
3108
+ url: "",
3109
+ width: 0,
3110
+ height: 0
3111
+ };
3112
+ },
3113
+ getMemos: () => {
3114
+ return memos;
3115
+ },
3116
+ loadMemos: (memos2) => {
3117
+ setMemos(memos2);
3118
+ addLog("\u52A0\u8F7D\u5907\u6CE8");
3119
+ },
3120
+ getLoops: () => {
3121
+ return loops;
3122
+ },
3123
+ loadLoops: (newLoops) => {
3124
+ setLoops(newLoops);
3125
+ addLog("\u52A0\u8F7D\u5FAA\u73AF");
3126
+ },
3127
+ getPatternInfo: () => {
3128
+ return {
3129
+ beforeOpenPattern: getBeforeOpenPattern(),
3130
+ pattern: getAfterOpenPattern(),
3131
+ loops: [...loops],
3132
+ memos: [...memos],
3133
+ historyLogs: [...historyLogs]
3134
+ };
3135
+ },
3136
+ loadPatternInfo: ({ loops: loops2, memos: memos2, beforeOpenPattern }) => {
3137
+ loadPattern(beforeOpenPattern, false);
3138
+ setLoops(loops2);
3139
+ setMemos(memos2);
3140
+ },
3141
+ loadPatterInfo: ({ loops: loops2, memos: memos2, beforeOpenPattern }) => {
3142
+ loadPattern(beforeOpenPattern, false);
3143
+ setLoops(loops2);
3144
+ setMemos(memos2);
3145
+ }
3146
+ }));
3147
+ const handleExpandLoops = React.useCallback(() => {
3148
+ if (loops.length === 0) return;
3149
+ setBaseMarks(gridMarks);
3150
+ let currentMarks = { ...gridMarks };
3151
+ const rowLoops = loops.filter((l) => l.type === "y").map((l) => ({ ...l })).sort((a, b) => a.endPos - a.startPos - (b.endPos - b.startPos));
3152
+ for (let i = 0; i < rowLoops.length; i++) {
3153
+ const current = rowLoops[i];
3154
+ currentMarks = maintopPattern.GridModel.createLoopRows(
3155
+ currentMarks,
3156
+ current.startPos,
3157
+ current.endPos,
3158
+ current.count,
3159
+ verticalScaleSize
3160
+ );
3161
+ const height2 = current.endPos - current.startPos + 1;
3162
+ const totalShift = height2 * (current.count - 1);
3163
+ const insertAt = current.endPos + 1;
3164
+ for (let j = i + 1; j < rowLoops.length; j++) {
3165
+ const other = rowLoops[j];
3166
+ if (insertAt <= other.startPos) {
3167
+ other.startPos += totalShift;
3168
+ other.endPos += totalShift;
3169
+ } else if (other.startPos < insertAt && insertAt <= other.endPos + 1) {
3170
+ other.endPos += totalShift;
3171
+ }
3172
+ }
3173
+ }
3174
+ const colLoops = loops.filter((l) => l.type === "x").map((l) => ({ ...l })).sort((a, b) => a.endPos - a.startPos - (b.endPos - b.startPos));
3175
+ for (let i = 0; i < colLoops.length; i++) {
3176
+ const current = colLoops[i];
3177
+ currentMarks = maintopPattern.GridModel.createLoopCols(
3178
+ currentMarks,
3179
+ current.startPos,
3180
+ current.endPos,
3181
+ current.count,
3182
+ horizontalScaleSize
3183
+ );
3184
+ const width2 = current.endPos - current.startPos + 1;
3185
+ const totalShift = width2 * (current.count - 1);
3186
+ const insertAt = current.endPos + 1;
3187
+ for (let j = i + 1; j < colLoops.length; j++) {
3188
+ const other = colLoops[j];
3189
+ if (insertAt <= other.startPos) {
3190
+ other.startPos += totalShift;
3191
+ other.endPos += totalShift;
3192
+ } else if (other.startPos < insertAt && insertAt <= other.endPos + 1) {
3193
+ other.endPos += totalShift;
3194
+ }
3195
+ }
3196
+ }
3197
+ setGridMarks(currentMarks);
3198
+ setIsExpanded(true);
3199
+ addLog("\u5C55\u5F00\u5FAA\u73AF");
3200
+ }, [
3201
+ loops,
3202
+ gridMarks,
3203
+ verticalScaleSize,
3204
+ horizontalScaleSize,
3205
+ setGridMarks,
3206
+ addLog
3207
+ ]);
3208
+ const handleShrinkLoops = React.useCallback(() => {
3209
+ if (baseMarks) {
3210
+ setGridMarks(baseMarks);
3211
+ setBaseMarks(null);
3212
+ }
3213
+ setIsExpanded(false);
3214
+ addLog("\u6536\u8D77\u5FAA\u73AF");
3215
+ }, [baseMarks, setGridMarks, addLog]);
3216
+ const handleSelectMode = React.useCallback(() => {
3217
+ setIsClickModeEnabled(!isClickModeEnabled);
3218
+ addLog(isClickModeEnabled ? "\u5355\u51FB\u6A21\u5F0F" : "\u53CC\u51FB\u6A21\u5F0F");
3219
+ }, [isClickModeEnabled, setIsClickModeEnabled, addLog]);
3220
+ const menuItems = React.useMemo(
3221
+ () => [
3222
+ {
3223
+ text: isClickModeEnabled ? "\u5355\u51FB\u6A21\u5F0F" : "\u53CC\u51FB\u6A21\u5F0F",
3224
+ icon: /* @__PURE__ */ jsxRuntime.jsx(
3225
+ AimOutlined,
3226
+ {
3227
+ style: { color: isClickModeEnabled ? "#1890FF" : "#000" }
3228
+ }
3229
+ ),
3230
+ onClick: handleSelectMode
3231
+ },
3232
+ {
3233
+ text: "\u5168\u9009",
3234
+ icon: /* @__PURE__ */ jsxRuntime.jsx(SelectOutlined, {}),
3235
+ onClick: handleSelectAll
3236
+ },
3237
+ {
3238
+ text: "\u6E05\u9664\u9009\u62E9",
3239
+ icon: /* @__PURE__ */ jsxRuntime.jsx(CloseSquareOutlined, {}),
3240
+ onClick: handleClearSelect
3241
+ },
3242
+ {
3243
+ text: "\u5168\u90E8\u6E05\u9664",
3244
+ icon: /* @__PURE__ */ jsxRuntime.jsx(ClearOutlined, {}),
3245
+ onClick: handleClearAll
3246
+ },
3247
+ {
3248
+ text: "\u663E\u793A\u53CD\u9762",
3249
+ icon: /* @__PURE__ */ jsxRuntime.jsx(EyeOutlined, {}),
3250
+ onClick: handleShowBack
3251
+ },
3252
+ { text: "\u526A\u5207", icon: /* @__PURE__ */ jsxRuntime.jsx(ScissorOutlined, {}), onClick: handleCut },
3253
+ { text: "\u590D\u5236", icon: /* @__PURE__ */ jsxRuntime.jsx(CopyOutlined, {}), onClick: handleCopy },
3254
+ {
3255
+ text: "\u7C98\u8D34",
3256
+ icon: /* @__PURE__ */ jsxRuntime.jsx(DiffOutlined, {}),
3257
+ onClick: handlePaste,
3258
+ disabled: !clipboard
3259
+ },
3260
+ {
3261
+ text: "\u590D\u5236\u7ECF\u7EAC",
3262
+ icon: /* @__PURE__ */ jsxRuntime.jsx(MergeCellsOutlined, {}),
3263
+ onClick: () => setCopyModalOpen(true)
3264
+ },
3265
+ {
3266
+ text: "\u63D2\u5165\u7ECF\u7EAC",
3267
+ icon: /* @__PURE__ */ jsxRuntime.jsx(BorderInnerOutlined, {}),
3268
+ onClick: () => setInsertModalOpen(true)
3269
+ },
3270
+ {
3271
+ text: "\u5220\u9664\u7ECF\u7EAC",
3272
+ icon: /* @__PURE__ */ jsxRuntime.jsx(DeleteOutlined, {}),
3273
+ onClick: () => setDeleteJingWeiModalOpen(true)
3274
+ },
3275
+ {
3276
+ text: "\u64A4\u9500",
3277
+ icon: /* @__PURE__ */ jsxRuntime.jsx(UndoOutlined, {}),
3278
+ onClick: handleUndoClick,
3279
+ disabled: !canUndo
3280
+ },
3281
+ {
3282
+ text: "\u91CD\u505A",
3283
+ icon: /* @__PURE__ */ jsxRuntime.jsx(RedoOutlined, {}),
3284
+ onClick: handleRedoClick,
3285
+ disabled: !canRedo
3286
+ },
3287
+ {
3288
+ text: "\u5386\u53F2",
3289
+ icon: /* @__PURE__ */ jsxRuntime.jsx(HistoryOutlined, {}),
3290
+ onClick: handleOpenHistory
3291
+ },
3292
+ {
3293
+ text: "\u65B0\u5EFA\u5FAA\u73AF",
3294
+ icon: /* @__PURE__ */ jsxRuntime.jsx(PlusCircleOutlined, {}),
3295
+ onClick: () => setLoopModalOpen(true)
3296
+ },
3297
+ {
3298
+ text: "\u7F16\u8F91\u5FAA\u73AF",
3299
+ icon: /* @__PURE__ */ jsxRuntime.jsx(EditOutlined, {}),
3300
+ onClick: handleOpenEditLoop
3301
+ },
3302
+ {
3303
+ text: "\u5220\u9664\u5FAA\u73AF",
3304
+ icon: /* @__PURE__ */ jsxRuntime.jsx(CloseCircleOutlined, {}),
3305
+ onClick: handleOpenDeleteLoop
3306
+ },
3307
+ {
3308
+ text: isExpanded ? "\u6536\u8D77\u5FAA\u73AF" : "\u5C55\u5F00\u5FAA\u73AF",
3309
+ icon: isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(ShrinkOutlined, {}) : /* @__PURE__ */ jsxRuntime.jsx(ArrowsAltOutlined, {}),
3310
+ onClick: isExpanded ? handleShrinkLoops : handleExpandLoops,
3311
+ disabled: !isExpanded && loops.length === 0
3312
+ }
3313
+ // {
3314
+ // text: '新建备注',
3315
+ // icon: <PlusOutlined />,
3316
+ // onClick: () => setMemoModalOpen(true),
3317
+ // },
3318
+ // {
3319
+ // text: '删除备注',
3320
+ // icon: <CloseOutlined />,
3321
+ // disabled: memosInSelection.length === 0,
3322
+ // onClick: handleOpenDeleteMemo,
3323
+ // },
3324
+ ],
3325
+ [
3326
+ handleSelectAll,
3327
+ handleClearSelect,
3328
+ handleClearAll,
3329
+ handleShowBack,
3330
+ handleCut,
3331
+ handleCopy,
3332
+ handlePaste,
3333
+ clipboard,
3334
+ canUndo,
3335
+ handleUndoClick,
3336
+ canRedo,
3337
+ handleRedoClick,
3338
+ handleOpenHistory,
3339
+ loopsInSelection.length,
3340
+ handleOpenEditLoop,
3341
+ handleOpenDeleteLoop,
3342
+ isExpanded,
3343
+ handleShrinkLoops,
3344
+ handleExpandLoops,
3345
+ loops.length,
3346
+ memosInSelection.length,
3347
+ handleOpenDeleteMemo,
3348
+ isClickModeEnabled,
3349
+ handleSelectMode
3350
+ ]
3351
+ );
3352
+ const onGridMarksChange = React.useCallback(
3353
+ (newMarksOrFn) => {
3354
+ setGridMarks(newMarksOrFn);
3355
+ addLog("\u7ED8\u5236/\u7F16\u8F91");
3356
+ },
3357
+ [addLog, setGridMarks]
3358
+ );
3359
+ const hasContentInPrintArea = React.useMemo(() => {
3360
+ if (!printMode) return true;
3361
+ let has = false;
3362
+ Object.keys(gridMarks).forEach((key) => {
3363
+ const [x, y] = key.split(",").map(Number);
3364
+ if (x < horizontalScaleSize && y < verticalScaleSize) {
3365
+ has = true;
3366
+ }
3367
+ });
3368
+ loops.forEach((loop) => {
3369
+ if (loop.type === "x" && loop.startPos < horizontalScaleSize)
3370
+ has = true;
3371
+ if (loop.type === "y" && loop.startPos < verticalScaleSize) has = true;
3372
+ });
3373
+ memos.forEach((memo2) => {
3374
+ if (memo2.type === "x" && memo2.startPos < horizontalScaleSize)
3375
+ has = true;
3376
+ if (memo2.type === "y" && memo2.startPos < verticalScaleSize) has = true;
3377
+ });
3378
+ return has;
3379
+ }, [
3380
+ printMode,
3381
+ gridMarks,
3382
+ loops,
3383
+ memos,
3384
+ horizontalScaleSize,
3385
+ verticalScaleSize
3386
+ ]);
3387
+ React.useEffect(() => {
3388
+ if (printMode && !hasContentInPrintArea && onMaxGridChange) {
3389
+ const keys = Object.keys(gridMarks);
3390
+ if (keys.length === 0) {
3391
+ onMaxGridChange(null);
3392
+ return;
3393
+ }
3394
+ let maxX = -1;
3395
+ let maxY = -1;
3396
+ for (const key of keys) {
3397
+ const commaIndex = key.indexOf(",");
3398
+ const x = parseInt(key.slice(0, commaIndex), 10);
3399
+ const y = parseInt(key.slice(commaIndex + 1), 10);
3400
+ if (x > maxX) maxX = x;
3401
+ if (y > maxY) maxY = y;
3402
+ }
3403
+ if (maxX !== -1 && maxY !== -1) {
3404
+ onMaxGridChange({ x: maxX + 1, y: maxY + 1 });
3405
+ } else {
3406
+ onMaxGridChange(null);
3407
+ }
3408
+ }
3409
+ }, [printMode, hasContentInPrintArea, gridMarks, onMaxGridChange]);
3410
+ if (printMode && !hasContentInPrintArea) {
3411
+ return null;
3412
+ }
3413
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3414
+ reactComponents.ReactFlex,
3415
+ {
3416
+ gap: 12,
3417
+ style: {
3418
+ ...STYLES.boardWrapper,
3419
+ width: computedWidth,
3420
+ height: computedHeight
3421
+ },
3422
+ children: [
3423
+ !readonly && !printMode && /* @__PURE__ */ jsxRuntime.jsx(toolbar_default, { items: menuItems, isExpanded, height }),
3424
+ /* @__PURE__ */ jsxRuntime.jsx(
3425
+ "div",
3426
+ {
3427
+ style: {
3428
+ ...STYLES.gridContainer,
3429
+ display: "flex",
3430
+ flexDirection: "column",
3431
+ height: "100%"
3432
+ },
3433
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...STYLES.gridHeader, flex: 1, minHeight: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(
3434
+ "div",
3435
+ {
3436
+ style: {
3437
+ display: "flex",
3438
+ flexDirection: "column",
3439
+ flex: 1,
3440
+ minWidth: 0,
3441
+ height: "100%"
3442
+ },
3443
+ children: /* @__PURE__ */ jsxRuntime.jsx(
3444
+ "div",
3445
+ {
3446
+ ref: viewportRef,
3447
+ onMouseDown: handleContentMouseDown,
3448
+ style: {
3449
+ ...STYLES.rulerWrapper,
3450
+ flex: 1,
3451
+ height: "unset"
3452
+ // 由 flex 决定高度
3453
+ },
3454
+ children: viewportWidth > 0 && viewportHeight > 0 && /* @__PURE__ */ jsxRuntime.jsx(
3455
+ grid_default,
3456
+ {
3457
+ ref: gridRef,
3458
+ width: viewportWidth,
3459
+ height: viewportHeight,
3460
+ scrollLeft,
3461
+ scrollTop,
3462
+ showScrollbar,
3463
+ scrollbarTotalWidth: totalWidth + canvasRightMargin,
3464
+ scrollbarTotalHeight: totalHeight,
3465
+ onHorizontalScroll: setScrollLeft,
3466
+ onVerticalScroll: setScrollTop,
3467
+ horizontalScaleSize: displayHorizontalScaleSize,
3468
+ verticalScaleSize: displayVerticalScaleSize,
3469
+ thickness,
3470
+ step,
3471
+ majorTickInterval: majorInterval,
3472
+ midTickInterval: midInterval,
3473
+ padding: 0,
3474
+ topPadding,
3475
+ onScrollRequest,
3476
+ onHoverGridChange,
3477
+ gridMarks,
3478
+ onGridMarksChange,
3479
+ canvasRightMargin,
3480
+ canvasTopMargin,
3481
+ readonly,
3482
+ showCursor,
3483
+ loops: orderedLoops,
3484
+ memos,
3485
+ isExpanded,
3486
+ isClickModeEnabled,
3487
+ midTickFontSize,
3488
+ majorTickFontSize,
3489
+ loopFontSize,
3490
+ onMaxGridChange,
3491
+ printMode,
3492
+ markPointFontSize,
3493
+ loopWingOffset,
3494
+ midTickLength,
3495
+ majorTickLength,
3496
+ smallTickLength,
3497
+ showSmallTickText,
3498
+ smallTickFontSize,
3499
+ hoverEffectColor,
3500
+ markSelectColor,
3501
+ markCheckedColor,
3502
+ markPointColor,
3503
+ cursorColor,
3504
+ mainGridColor,
3505
+ minorTickColor,
3506
+ rulerBgColor,
3507
+ rulerTextColor,
3508
+ rulerTickColor,
3509
+ rulerBorderColor,
3510
+ loopIndicatorColor,
3511
+ loopTextColor,
3512
+ loopTickExtension,
3513
+ showLoopArrow,
3514
+ loopArrowSize,
3515
+ showInnerLoopEndpoints,
3516
+ onGirdClick
3517
+ }
3518
+ )
3519
+ }
3520
+ )
3521
+ }
3522
+ ) })
3523
+ }
3524
+ ),
3525
+ /* @__PURE__ */ jsxRuntime.jsx(
3526
+ history_modal_default,
3527
+ {
3528
+ open: isHistoryModalOpen,
3529
+ onCancel: () => setIsHistoryModalOpen(false),
3530
+ onClear: clearLogs,
3531
+ logs: historyLogs
3532
+ }
3533
+ ),
3534
+ /* @__PURE__ */ jsxRuntime.jsx(
3535
+ batch_copy_modal_default,
3536
+ {
3537
+ open: copyModalOpen,
3538
+ onCancel: () => setCopyModalOpen(false),
3539
+ onOk: handleDuplicateSubmit
3540
+ }
3541
+ ),
3542
+ /* @__PURE__ */ jsxRuntime.jsx(
3543
+ insert_jing_wei_modal_default,
3544
+ {
3545
+ open: insertModalOpen,
3546
+ onCancel: () => setInsertModalOpen(false),
3547
+ onOk: handleInsertSubmit,
3548
+ verticalScaleSize,
3549
+ horizontalScaleSize
3550
+ }
3551
+ ),
3552
+ /* @__PURE__ */ jsxRuntime.jsx(
3553
+ delete_jing_wei_modal_default,
3554
+ {
3555
+ open: deleteJingWeiModalOpen,
3556
+ onCancel: () => setDeleteJingWeiModalOpen(false),
3557
+ onOk: handleDeleteJingWeiSubmit,
3558
+ verticalScaleSize,
3559
+ horizontalScaleSize
3560
+ }
3561
+ ),
3562
+ /* @__PURE__ */ jsxRuntime.jsx(
3563
+ create_loop_modal_default,
3564
+ {
3565
+ open: loopModalOpen,
3566
+ onCancel: () => setLoopModalOpen(false),
3567
+ onSubmit: handleLoopSubmit,
3568
+ verticalScaleSize,
3569
+ horizontalScaleSize
3570
+ }
3571
+ ),
3572
+ /* @__PURE__ */ jsxRuntime.jsx(
3573
+ edit_loop_modal_default,
3574
+ {
3575
+ open: editLoopModalOpen,
3576
+ onCancel: () => setEditLoopModalOpen(false),
3577
+ onSubmit: handleEditLoopSubmit,
3578
+ loops,
3579
+ loopsInSelection,
3580
+ verticalScaleSize,
3581
+ horizontalScaleSize
3582
+ }
3583
+ ),
3584
+ /* @__PURE__ */ jsxRuntime.jsx(
3585
+ delete_loop_modal_default,
3586
+ {
3587
+ open: deleteLoopModalOpen,
3588
+ onCancel: () => setDeleteLoopModalOpen(false),
3589
+ onSubmit: handleDeleteLoopSubmit,
3590
+ loops,
3591
+ loopsInSelection
3592
+ }
3593
+ ),
3594
+ /* @__PURE__ */ jsxRuntime.jsx(
3595
+ create_memo_modal_default,
3596
+ {
3597
+ open: memoModalOpen,
3598
+ onCancel: () => setMemoModalOpen(false),
3599
+ onSubmit: handleMemoSubmit,
3600
+ verticalScaleSize,
3601
+ horizontalScaleSize
3602
+ }
3603
+ ),
3604
+ /* @__PURE__ */ jsxRuntime.jsx(
3605
+ delete_memo_modal_default,
3606
+ {
3607
+ open: deleteMemoModalOpen,
3608
+ onCancel: () => setDeleteMemoModalOpen(false),
3609
+ onSubmit: handleDeleteMemoSubmit,
3610
+ memosInSelection
3611
+ }
3612
+ )
3613
+ ]
3614
+ }
3615
+ );
3616
+ }
3617
+ );
3618
+ var drawing_board_default = DrawingBoard;
3619
+
3620
+ exports.DrawingBoard = drawing_board_default;
3621
+ exports.MaintopPatternGrid = grid_default;
3622
+ exports.ReactMaintopPattern = drawing_board_default;
3623
+ exports.default = drawing_board_default;