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