quill-table-up 2.0.2 → 2.0.3

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.
Files changed (99) hide show
  1. package/dist/index.d.ts +3 -0
  2. package/dist/index.js +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.umd.js +1 -1
  5. package/dist/index.umd.js.map +1 -1
  6. package/dist/table-creator.css +1 -1
  7. package/package.json +9 -14
  8. package/src/__tests__/e2e/custom-creator.test.ts +44 -0
  9. package/src/__tests__/e2e/table-align.test.ts +39 -0
  10. package/src/__tests__/e2e/table-resize.test.ts +152 -0
  11. package/src/__tests__/e2e/table-scrollbar.test.ts +31 -0
  12. package/src/__tests__/e2e/table-selection.test.ts +83 -0
  13. package/src/__tests__/e2e/utils.ts +6 -0
  14. package/src/__tests__/unit/table-insert-blot.test.ts +464 -0
  15. package/src/__tests__/unit/table-insert-remove-merge.test.ts +1270 -0
  16. package/src/__tests__/unit/table-redo-undo.test.ts +909 -0
  17. package/src/__tests__/unit/utils.test-d.ts +49 -0
  18. package/src/__tests__/unit/utils.test.ts +715 -0
  19. package/src/__tests__/unit/utils.ts +216 -0
  20. package/src/__tests__/unit/vitest.d.ts +12 -0
  21. package/src/formats/container-format.ts +52 -0
  22. package/src/formats/index.ts +10 -0
  23. package/src/formats/overrides/block.ts +93 -0
  24. package/src/formats/overrides/blockquote.ts +8 -0
  25. package/src/formats/overrides/code.ts +8 -0
  26. package/src/formats/overrides/header.ts +8 -0
  27. package/src/formats/overrides/index.ts +6 -0
  28. package/src/formats/overrides/list.ts +10 -0
  29. package/src/formats/overrides/scroll.ts +51 -0
  30. package/src/formats/table-body-format.ts +92 -0
  31. package/src/formats/table-cell-format.ts +139 -0
  32. package/src/formats/table-cell-inner-format.ts +251 -0
  33. package/src/formats/table-col-format.ts +174 -0
  34. package/src/formats/table-colgroup-format.ts +133 -0
  35. package/src/formats/table-main-format.ts +143 -0
  36. package/src/formats/table-row-format.ts +147 -0
  37. package/src/formats/table-wrapper-format.ts +55 -0
  38. package/src/formats/utils.ts +3 -0
  39. package/src/index.ts +1157 -0
  40. package/src/modules/index.ts +5 -0
  41. package/src/modules/table-align.ts +116 -0
  42. package/src/modules/table-menu/constants.ts +140 -0
  43. package/src/modules/table-menu/index.ts +3 -0
  44. package/src/modules/table-menu/table-menu-common.ts +249 -0
  45. package/src/modules/table-menu/table-menu-contextmenu.ts +94 -0
  46. package/src/modules/table-menu/table-menu-select.ts +28 -0
  47. package/src/modules/table-resize/index.ts +5 -0
  48. package/src/modules/table-resize/table-resize-box.ts +293 -0
  49. package/src/modules/table-resize/table-resize-common.ts +343 -0
  50. package/src/modules/table-resize/table-resize-line.ts +163 -0
  51. package/src/modules/table-resize/table-resize-scale.ts +154 -0
  52. package/src/modules/table-resize/utils.ts +3 -0
  53. package/src/modules/table-scrollbar.ts +255 -0
  54. package/src/modules/table-selection.ts +262 -0
  55. package/src/style/button.less +45 -0
  56. package/src/style/color-picker.less +134 -0
  57. package/src/style/dialog.less +53 -0
  58. package/src/style/functions.less +9 -0
  59. package/src/style/index.less +89 -0
  60. package/src/style/input.less +64 -0
  61. package/src/style/select-box.less +51 -0
  62. package/src/style/table-creator.less +68 -0
  63. package/src/style/table-menu.less +122 -0
  64. package/src/style/table-resize-scale.less +31 -0
  65. package/src/style/table-resize.less +183 -0
  66. package/src/style/table-scrollbar.less +49 -0
  67. package/src/style/table-selection.less +15 -0
  68. package/src/style/tooltip.less +19 -0
  69. package/src/style/variables.less +1 -0
  70. package/src/svg/background.svg +1 -0
  71. package/src/svg/border.svg +1 -0
  72. package/src/svg/color.svg +1 -0
  73. package/src/svg/insert-bottom.svg +1 -0
  74. package/src/svg/insert-left.svg +1 -0
  75. package/src/svg/insert-right.svg +1 -0
  76. package/src/svg/insert-top.svg +1 -0
  77. package/src/svg/merge-cell.svg +1 -0
  78. package/src/svg/remove-column.svg +1 -0
  79. package/src/svg/remove-row.svg +1 -0
  80. package/src/svg/remove-table.svg +1 -0
  81. package/src/svg/split-cell.svg +1 -0
  82. package/src/types.d.ts +4 -0
  83. package/src/utils/bem.ts +23 -0
  84. package/src/utils/color.ts +109 -0
  85. package/src/utils/components/button.ts +22 -0
  86. package/src/utils/components/color-picker.ts +236 -0
  87. package/src/utils/components/dialog.ts +41 -0
  88. package/src/utils/components/index.ts +6 -0
  89. package/src/utils/components/input.ts +74 -0
  90. package/src/utils/components/table/creator.ts +86 -0
  91. package/src/utils/components/table/index.ts +2 -0
  92. package/src/utils/components/table/select-box.ts +83 -0
  93. package/src/utils/components/tooltip.ts +186 -0
  94. package/src/utils/constants.ts +99 -0
  95. package/src/utils/index.ts +7 -0
  96. package/src/utils/is.ts +6 -0
  97. package/src/utils/position.ts +21 -0
  98. package/src/utils/types.ts +131 -0
  99. package/src/utils/utils.ts +139 -0
@@ -0,0 +1,236 @@
1
+ import type { HSB } from '../color';
2
+ import { createBEM } from '../bem';
3
+ import { HEXtoRGB, HSBtoHEX, HSBtoRGB, RGBtoHEX, RGBtoHSB, validateHSB } from '../color';
4
+
5
+ interface ColorPickerOptions {
6
+ color: string;
7
+ onChange: (color: string) => void;
8
+ };
9
+ export const createColorPicker = (options: Partial<ColorPickerOptions> = {}) => {
10
+ const contentWidth = 230;
11
+ const contentHeight = 150;
12
+ const handleSizeSec = 10;
13
+
14
+ let hsbValue: HSB = RGBtoHSB(HEXtoRGB(options.color || '#ff0000'));
15
+ const bem = createBEM('color-picker');
16
+ const root = document.createElement('div');
17
+ root.classList.add(bem.b());
18
+
19
+ const content = document.createElement('div');
20
+ content.classList.add(bem.be('content'));
21
+
22
+ const colorSelector = document.createElement('div');
23
+ colorSelector.classList.add(bem.be('selector'));
24
+
25
+ const colorBackground = document.createElement('div');
26
+ colorBackground.classList.add(bem.be('background'));
27
+ colorSelector.appendChild(colorBackground);
28
+
29
+ const colorHandle = document.createElement('div');
30
+ colorHandle.classList.add(bem.be('background-handle'));
31
+ colorBackground.appendChild(colorHandle);
32
+
33
+ const colorAlpha = document.createElement('div');
34
+ colorAlpha.classList.add(bem.be('alpha'));
35
+
36
+ const alphaBg = document.createElement('div');
37
+ alphaBg.classList.add(bem.be('alpha-bg'));
38
+
39
+ const alphaHandle = document.createElement('div');
40
+ alphaHandle.classList.add(bem.be('alpha-handle'));
41
+
42
+ colorAlpha.appendChild(alphaBg);
43
+ colorAlpha.appendChild(alphaHandle);
44
+
45
+ const colorHue = document.createElement('div');
46
+ colorHue.classList.add(bem.be('hue'));
47
+
48
+ const colorHueHandle = document.createElement('div');
49
+ colorHueHandle.classList.add(bem.be('hue-handle'));
50
+ colorHue.appendChild(colorHueHandle);
51
+
52
+ const action = document.createElement('div');
53
+ action.classList.add(bem.be('action'));
54
+
55
+ const [colorRInput, colorGInput, colorBInput, colorAInput] = (['r', 'g', 'b', 'a'] as const).map((key) => {
56
+ const item = document.createElement('div');
57
+ item.classList.add(bem.be('action-item'), key);
58
+
59
+ const label = document.createElement('label');
60
+ label.textContent = key.toUpperCase();
61
+
62
+ const colorInput = document.createElement('input');
63
+ colorInput.classList.add(bem.be('input'));
64
+
65
+ colorInput.addEventListener('input', () => {
66
+ colorInput.value = colorInput.value.replaceAll(/[^0-9]/g, '');
67
+ });
68
+ colorInput.addEventListener('change', () => {
69
+ let value = Math.round(Number(colorInput.value));
70
+ if (key === 'a') {
71
+ value = value / 100;
72
+ }
73
+ const result = validateHSB(RGBtoHSB(Object.assign({}, HSBtoRGB(hsbValue), { [key]: value })));
74
+ updateValue(result);
75
+ updateUI();
76
+ });
77
+
78
+ item.appendChild(label);
79
+ item.appendChild(colorInput);
80
+ action.appendChild(item);
81
+
82
+ return colorInput;
83
+ });
84
+
85
+ content.appendChild(colorHue);
86
+ content.appendChild(colorSelector);
87
+ content.appendChild(colorAlpha);
88
+ root.appendChild(content);
89
+ root.appendChild(action);
90
+
91
+ let colorDragging = false;
92
+ let hueDragging = false;
93
+ let alphaDragging = false;
94
+
95
+ function updateInput() {
96
+ const hex = HSBtoHEX(hsbValue);
97
+ for (const [i, input] of [colorRInput, colorGInput, colorBInput].entries()) {
98
+ input.value = String(Number.parseInt(hex[i * 2] + hex[i * 2 + 1], 16));
99
+ }
100
+ colorAInput.value = String((hsbValue.a * 100).toFixed(0));
101
+ }
102
+ function updateColorHandle() {
103
+ Object.assign(colorHandle.style, {
104
+ left: `${Math.floor((contentWidth * hsbValue.s) / 100)}px`,
105
+ top: `${Math.floor((contentHeight * (100 - hsbValue.b)) / 100)}px`,
106
+ });
107
+ }
108
+ function updateColorSelector() {
109
+ colorSelector.style.backgroundColor = `#${RGBtoHEX(HSBtoRGB({
110
+ h: hsbValue.h,
111
+ s: 100,
112
+ b: 100,
113
+ a: 1,
114
+ }))}`;
115
+ }
116
+ function updateHue() {
117
+ colorHueHandle.style.top = `${Math.floor(contentHeight - (contentHeight * hsbValue.h) / 360)}px`;
118
+ }
119
+ function updateAlphaHandle() {
120
+ alphaHandle.style.left = `${hsbValue.a * 100}%`;
121
+ }
122
+ function updateAlphaBg() {
123
+ const { r, g, b } = HSBtoRGB(hsbValue);
124
+ alphaBg.style.background = `linear-gradient(to right, rgba(${r}, ${g}, ${b}, 0) 0%, rgba(${r}, ${g}, ${b}, 1) 100%)`;
125
+ }
126
+ function updateUI() {
127
+ updateColorHandle();
128
+ updateColorSelector();
129
+ updateHue();
130
+ updateAlphaHandle();
131
+ updateAlphaBg();
132
+ updateInput();
133
+ }
134
+ function updateValue(value: Partial<HSB>) {
135
+ hsbValue = validateHSB(Object.assign({}, hsbValue, value));
136
+
137
+ updateInput();
138
+
139
+ if (options.onChange) {
140
+ options.onChange(`#${HSBtoHEX(hsbValue)}`);
141
+ }
142
+ }
143
+
144
+ function pickColor(event: MouseEvent) {
145
+ const rect = colorSelector.getBoundingClientRect();
146
+ const top = rect.top + (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0);
147
+ const left = rect.left + document.body.scrollLeft;
148
+ const saturation = Math.floor((100 * Math.max(0, Math.min(contentWidth, event.pageX - left))) / contentWidth);
149
+ const brightness = Math.floor((100 * (contentHeight - Math.max(0, Math.min(contentHeight, event.pageY - top)))) / contentHeight);
150
+
151
+ updateValue({
152
+ s: saturation,
153
+ b: brightness,
154
+ });
155
+ updateUI();
156
+ }
157
+ function pickHue(event: MouseEvent) {
158
+ const top = colorHue.getBoundingClientRect().top + (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0);
159
+
160
+ updateValue({
161
+ h: Math.floor((360 * (contentHeight - Math.max(0, Math.min(contentHeight, event.pageY - top)))) / contentHeight),
162
+ });
163
+ updateUI();
164
+ }
165
+ function pickAlpha(event: MouseEvent) {
166
+ const { pageX } = event;
167
+ const rect = colorAlpha.getBoundingClientRect();
168
+ let left = pageX - rect.left;
169
+ left = Math.max(handleSizeSec / 2, left);
170
+ left = Math.min(left, rect.width - handleSizeSec / 2);
171
+
172
+ updateValue({
173
+ a: Math.round(((left - 10 / 2) / (rect.width - 10)) * 100) / 100,
174
+ });
175
+ updateUI();
176
+ }
177
+
178
+ function onDrag(event: MouseEvent) {
179
+ if (colorDragging) {
180
+ event.preventDefault();
181
+ pickColor(event);
182
+ }
183
+
184
+ if (hueDragging) {
185
+ event.preventDefault();
186
+ pickHue(event);
187
+ }
188
+
189
+ if (alphaDragging) {
190
+ event.preventDefault();
191
+ pickAlpha(event);
192
+ }
193
+ }
194
+
195
+ function onColorSelectorDragEnd() {
196
+ document.removeEventListener('mousemove', onDrag);
197
+ document.removeEventListener('mouseup', onColorSelectorDragEnd);
198
+ colorDragging = false;
199
+ }
200
+ function onColorSelectorMousedown(e: MouseEvent) {
201
+ document.addEventListener('mousemove', onDrag);
202
+ document.addEventListener('mouseup', onColorSelectorDragEnd);
203
+ colorDragging = true;
204
+ pickColor(e);
205
+ }
206
+ colorSelector.addEventListener('mousedown', onColorSelectorMousedown);
207
+
208
+ function onColorHueDragEnd() {
209
+ document.removeEventListener('mousemove', onDrag);
210
+ document.removeEventListener('mouseup', onColorHueDragEnd);
211
+ hueDragging = false;
212
+ }
213
+ function onColorHueMousedown(event: MouseEvent) {
214
+ document.addEventListener('mousemove', onDrag);
215
+ document.addEventListener('mouseup', onColorHueDragEnd);
216
+ hueDragging = true;
217
+ pickHue(event);
218
+ }
219
+ colorHue.addEventListener('mousedown', onColorHueMousedown);
220
+
221
+ function onColorAlphaDragEnd() {
222
+ document.removeEventListener('mousemove', onDrag);
223
+ document.removeEventListener('mouseup', onColorAlphaDragEnd);
224
+ alphaDragging = false;
225
+ }
226
+ function onColorAlphaMousedown(event: MouseEvent) {
227
+ document.addEventListener('mousemove', onDrag);
228
+ document.addEventListener('mouseup', onColorAlphaDragEnd);
229
+ alphaDragging = true;
230
+ pickAlpha(event);
231
+ }
232
+ colorAlpha.addEventListener('mousedown', onColorAlphaMousedown);
233
+
234
+ updateUI();
235
+ return root;
236
+ };
@@ -0,0 +1,41 @@
1
+ import { createBEM } from '../bem';
2
+
3
+ interface DialogOptions {
4
+ child?: HTMLElement;
5
+ target?: HTMLElement;
6
+ beforeClose?: () => void;
7
+ }
8
+ let zindex = 8000;
9
+ export const createDialog = ({ child, target = document.body, beforeClose = () => {} }: DialogOptions = {}) => {
10
+ const bem = createBEM('dialog');
11
+ const appendTo = target;
12
+ const dialog = document.createElement('div');
13
+ dialog.classList.add(bem.b());
14
+ dialog.style.zIndex = String(zindex);
15
+ const overlay = document.createElement('div');
16
+ overlay.classList.add(bem.be('overlay'));
17
+ dialog.appendChild(overlay);
18
+ if (child) {
19
+ const content = document.createElement('div');
20
+ content.classList.add(bem.be('content'));
21
+ content.appendChild(child);
22
+ overlay.appendChild(content);
23
+ content.addEventListener('click', (e) => {
24
+ e.stopPropagation();
25
+ });
26
+ }
27
+
28
+ const originOverflow = getComputedStyle(appendTo).overflow;
29
+ appendTo.style.overflow = 'hidden';
30
+
31
+ appendTo.appendChild(dialog);
32
+ const close = () => {
33
+ beforeClose();
34
+ dialog.remove();
35
+ appendTo.style.overflow = originOverflow;
36
+ };
37
+ dialog.addEventListener('click', close);
38
+ zindex += 1;
39
+
40
+ return { dialog, close };
41
+ };
@@ -0,0 +1,6 @@
1
+ export * from './button';
2
+ export * from './color-picker';
3
+ export * from './dialog';
4
+ export * from './input';
5
+ export * from './table';
6
+ export * from './tooltip';
@@ -0,0 +1,74 @@
1
+ import { createBEM } from '../bem';
2
+
3
+ interface InputOptions {
4
+ type?: string;
5
+ value?: string;
6
+ max?: number;
7
+ min?: number;
8
+ [key: string]: any;
9
+ };
10
+ export const createInputItem = (label: string, options: InputOptions) => {
11
+ const bem = createBEM('input');
12
+ options.type || (options.type = 'text');
13
+ options.value || (options.value = '');
14
+
15
+ const inputItem = document.createElement('div');
16
+ inputItem.classList.add(bem.be('item'));
17
+
18
+ if (label) {
19
+ const inputLabel = document.createElement('span');
20
+ inputLabel.classList.add(bem.be('label'));
21
+ inputLabel.textContent = label;
22
+ inputItem.appendChild(inputLabel);
23
+ }
24
+
25
+ const inputInput = document.createElement('div');
26
+ inputInput.classList.add(bem.be('input'));
27
+ const input = document.createElement('input');
28
+ for (const key in options) {
29
+ input.setAttribute(key, options[key]);
30
+ }
31
+ if (options.max || options.min) {
32
+ input.addEventListener('blur', () => {
33
+ if (options.max && options.max <= Number(input.value)) {
34
+ input.value = String(options.max);
35
+ }
36
+ if (options.min && options.min >= Number(input.value)) {
37
+ input.value = String(options.min);
38
+ }
39
+ });
40
+ }
41
+
42
+ inputInput.appendChild(input);
43
+ inputItem.appendChild(inputInput);
44
+
45
+ input.addEventListener('focus', () => {
46
+ inputInput.classList.add('focus');
47
+ });
48
+ input.addEventListener('blur', () => {
49
+ inputInput.classList.remove('focus');
50
+ });
51
+
52
+ const errorTip = (msg: string) => {
53
+ let errorTip: HTMLElement;
54
+ if (inputInput.classList.contains('error')) {
55
+ errorTip = inputInput.querySelector(`.${bem.be('error-tip')}`)!;
56
+ }
57
+ else {
58
+ errorTip = document.createElement('span');
59
+ errorTip.classList.add(bem.be('error-tip'));
60
+ inputInput.appendChild(errorTip);
61
+ }
62
+
63
+ errorTip.textContent = msg;
64
+ inputInput.classList.add('error');
65
+
66
+ const removeError = () => {
67
+ inputInput.classList.remove('error');
68
+ errorTip.remove();
69
+ };
70
+ return { removeError };
71
+ };
72
+
73
+ return { item: inputItem, input, errorTip };
74
+ };
@@ -0,0 +1,86 @@
1
+ import type { TableCreatorTextOptions } from '../../types';
2
+ import { createBEM } from '../../bem';
3
+ import { createButton } from '../button';
4
+ import { createDialog } from '../dialog';
5
+ import { createInputItem } from '../input';
6
+
7
+ interface TableCreatorOptions extends Omit<TableCreatorTextOptions, 'customBtnText'> {
8
+ row: number;
9
+ col: number;
10
+ }
11
+ export const showTableCreator = async (options: Partial<TableCreatorOptions> = {}) => {
12
+ const bem = createBEM('creator');
13
+ const box = document.createElement('div');
14
+ box.classList.add(bem.b());
15
+ const inputContent = document.createElement('div');
16
+ inputContent.classList.add(bem.be('input'));
17
+
18
+ const {
19
+ item: rowItem,
20
+ input: rowInput,
21
+ errorTip: rowErrorTip,
22
+ } = createInputItem(options.rowText || 'Row', { type: 'number', value: String(options.row || ''), max: 99 });
23
+ const {
24
+ item: colItem,
25
+ input: colInput,
26
+ errorTip: colErrorTip,
27
+ } = createInputItem(options.colText || 'Column', { type: 'number', value: String(options.col || ''), max: 99 });
28
+
29
+ inputContent.appendChild(rowItem);
30
+ inputContent.appendChild(colItem);
31
+ box.appendChild(inputContent);
32
+
33
+ const control = document.createElement('div');
34
+ control.classList.add(bem.be('control'));
35
+
36
+ const confirmBtn = createButton({ type: 'confirm', content: options.confirmText || 'Confirm' });
37
+ const cancelBtn = createButton({ type: 'default', content: options.cancelText || 'Cancel' });
38
+
39
+ control.appendChild(confirmBtn);
40
+ control.appendChild(cancelBtn);
41
+ box.appendChild(control);
42
+
43
+ const validateInput = (row: number = Number(rowInput.value), col: number = Number(colInput.value)) => {
44
+ if (Number.isNaN(row) || row <= 0) {
45
+ rowErrorTip(options.notPositiveNumberError || 'Please enter a positive integer');
46
+ return;
47
+ }
48
+ if (Number.isNaN(col) || col <= 0) {
49
+ colErrorTip(options.notPositiveNumberError || 'Please enter a positive integer');
50
+ return;
51
+ }
52
+ return { row, col };
53
+ };
54
+ const keyboardClose = (e: KeyboardEvent) => {
55
+ if (e.key === 'Escape') {
56
+ close();
57
+ document.removeEventListener('keydown', keyboardClose);
58
+ }
59
+ };
60
+
61
+ return new Promise<{ row: number; col: number }>((resolve, reject) => {
62
+ const { close } = createDialog({ child: box, beforeClose: reject });
63
+ rowInput.focus();
64
+
65
+ for (const input of [rowInput, colInput]) {
66
+ input.addEventListener('keydown', (e) => {
67
+ if (e.key === 'Enter') {
68
+ const result = validateInput();
69
+ if (result) {
70
+ resolve(result);
71
+ close();
72
+ }
73
+ }
74
+ });
75
+ }
76
+ confirmBtn.addEventListener('click', async () => {
77
+ const result = validateInput();
78
+ if (result) {
79
+ resolve(result);
80
+ close();
81
+ }
82
+ });
83
+ document.addEventListener('keydown', keyboardClose);
84
+ cancelBtn.addEventListener('click', close);
85
+ });
86
+ };
@@ -0,0 +1,2 @@
1
+ export * from './creator';
2
+ export * from './select-box';
@@ -0,0 +1,83 @@
1
+ import type { TableCreatorTextOptions } from '../../types';
2
+ import { createBEM } from '../../bem';
3
+ import { showTableCreator } from './creator';
4
+
5
+ interface TableSelectOptions {
6
+ row: number;
7
+ col: number;
8
+ onSelect: (row: number, col: number) => void;
9
+ customBtn: boolean;
10
+ texts: Partial<TableCreatorTextOptions>;
11
+ }
12
+ export const createSelectBox = (options: Partial<TableSelectOptions> = {}) => {
13
+ const bem = createBEM('select-box');
14
+ const selectDom = document.createElement('div');
15
+ selectDom.classList.add(bem.b());
16
+
17
+ const selectBlock = document.createElement('div');
18
+ selectBlock.classList.add(bem.be('block'));
19
+ for (let r = 0; r < (options.row || 8); r++) {
20
+ for (let c = 0; c < (options.col || 8); c++) {
21
+ const selectItem = document.createElement('div');
22
+ selectItem.classList.add(bem.be('item'));
23
+ selectItem.dataset.row = String(r + 1);
24
+ selectItem.dataset.col = String(c + 1);
25
+ selectBlock.appendChild(selectItem);
26
+ }
27
+ }
28
+ const updateSelectBlockItems = () => {
29
+ const { row, col } = selectDom.dataset;
30
+ for (const item of Array.from(selectBlock.querySelectorAll('.active'))) {
31
+ item.classList.remove('active');
32
+ }
33
+ if (!row || !col) return;
34
+ const childs = Array.from(selectBlock.children) as HTMLElement[];
35
+ for (let i = 0; i < childs.length; i++) {
36
+ const { row: childRow, col: childCol } = childs[i].dataset;
37
+ if (childRow! > row && childCol! > col) {
38
+ return;
39
+ }
40
+ if (childRow! <= row && childCol! <= col) {
41
+ childs[i].classList.add('active');
42
+ }
43
+ else {
44
+ childs[i].classList.remove('active');
45
+ }
46
+ }
47
+ };
48
+ selectBlock.addEventListener('mousemove', (e) => {
49
+ if (!e.target) return;
50
+ const { row, col } = (e.target as HTMLElement).dataset;
51
+ if (!row || !col) return;
52
+ selectDom.dataset.row = row;
53
+ selectDom.dataset.col = col;
54
+ updateSelectBlockItems();
55
+ });
56
+ selectBlock.addEventListener('mouseleave', () => {
57
+ selectDom.removeAttribute('data-row');
58
+ selectDom.removeAttribute('data-col');
59
+ updateSelectBlockItems();
60
+ });
61
+ selectBlock.addEventListener('click', () => {
62
+ const { row, col } = selectDom.dataset;
63
+ if (!row || !col) return;
64
+ options.onSelect && options.onSelect(Number(row), Number(col));
65
+ });
66
+ selectDom.appendChild(selectBlock);
67
+
68
+ if (options.customBtn) {
69
+ const texts = options.texts || {};
70
+ const selectCustom = document.createElement('div');
71
+ selectCustom.classList.add(bem.be('custom'));
72
+ selectCustom.textContent = texts.customBtnText || 'Custom';
73
+ selectCustom.addEventListener('click', async () => {
74
+ const res = await showTableCreator(texts);
75
+ if (res) {
76
+ options.onSelect && options.onSelect(res.row, res.col);
77
+ }
78
+ });
79
+ selectDom.appendChild(selectCustom);
80
+ }
81
+
82
+ return selectDom;
83
+ };