quill-table-up 2.1.9 → 2.2.0

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 (79) hide show
  1. package/README.md +41 -34
  2. package/dist/index.css +1 -1
  3. package/dist/index.d.ts +53 -17
  4. package/dist/index.js +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.umd.js +1 -1
  7. package/dist/index.umd.js.map +1 -1
  8. package/package.json +16 -16
  9. package/src/__tests__/e2e/editor-page.ts +6 -0
  10. package/src/__tests__/e2e/table-blots.test.ts +52 -0
  11. package/src/__tests__/e2e/table-caption.test.ts +93 -0
  12. package/src/__tests__/e2e/table-hack.test.ts +43 -0
  13. package/src/__tests__/e2e/table-resize.test.ts +136 -5
  14. package/src/__tests__/e2e/table-selection.test.ts +7 -10
  15. package/src/__tests__/e2e/utils.ts +2 -2
  16. package/src/__tests__/unit/table-blots.test.ts +223 -0
  17. package/src/__tests__/unit/table-caption.test.ts +237 -0
  18. package/src/__tests__/unit/table-clipboard.test.ts +6 -6
  19. package/src/__tests__/unit/table-hack.test.ts +137 -63
  20. package/src/__tests__/unit/table-insert.test.ts +4 -4
  21. package/src/__tests__/unit/table-redo-undo.test.ts +252 -3
  22. package/src/__tests__/unit/utils.test.ts +2 -2
  23. package/src/__tests__/unit/utils.ts +44 -25
  24. package/src/__tests__/unit/vitest.d.ts +0 -1
  25. package/src/formats/index.ts +1 -0
  26. package/src/formats/overrides/scroll.ts +6 -0
  27. package/src/formats/table-caption-format.ts +115 -0
  28. package/src/formats/table-cell-format.ts +63 -33
  29. package/src/formats/table-cell-inner-format.ts +3 -3
  30. package/src/formats/table-col-format.ts +16 -12
  31. package/src/formats/table-colgroup-format.ts +2 -2
  32. package/src/formats/table-main-format.ts +0 -9
  33. package/src/formats/table-wrapper-format.ts +2 -2
  34. package/src/modules/table-clipboard.ts +21 -3
  35. package/src/modules/table-menu/constants.ts +18 -2
  36. package/src/modules/table-menu/table-menu-common.ts +0 -5
  37. package/src/modules/table-resize/table-resize-box.ts +74 -31
  38. package/src/modules/table-resize/table-resize-common.ts +8 -7
  39. package/src/modules/table-resize/table-resize-scale.ts +12 -5
  40. package/src/modules/table-scrollbar.ts +12 -7
  41. package/src/modules/table-selection.ts +16 -19
  42. package/src/style/color-picker.less +4 -2
  43. package/src/style/index.less +19 -0
  44. package/src/style/table-resize.less +16 -1
  45. package/src/svg/arrow-up-down.svg +11 -0
  46. package/src/svg/auto-full.svg +11 -1
  47. package/src/svg/background.svg +10 -1
  48. package/src/svg/border.svg +10 -1
  49. package/src/svg/color.svg +10 -1
  50. package/src/svg/copy.svg +8 -1
  51. package/src/svg/cut.svg +7 -1
  52. package/src/svg/insert-bottom.svg +6 -1
  53. package/src/svg/insert-left.svg +6 -1
  54. package/src/svg/insert-right.svg +6 -1
  55. package/src/svg/insert-top.svg +6 -1
  56. package/src/svg/merge-cell.svg +6 -1
  57. package/src/svg/remove-column.svg +6 -1
  58. package/src/svg/remove-row.svg +6 -1
  59. package/src/svg/remove-table.svg +6 -1
  60. package/src/svg/split-cell.svg +6 -1
  61. package/src/svg/table-head.svg +4 -0
  62. package/src/table-up.ts +149 -112
  63. package/src/utils/bem.ts +2 -2
  64. package/src/utils/blot-helper.ts +12 -0
  65. package/src/utils/color.ts +12 -12
  66. package/src/utils/components/button.ts +2 -2
  67. package/src/utils/components/color-picker.ts +2 -2
  68. package/src/utils/components/dialog.ts +2 -2
  69. package/src/utils/components/input.ts +2 -2
  70. package/src/utils/components/table/creator.ts +2 -2
  71. package/src/utils/components/table/select-box.ts +2 -2
  72. package/src/utils/components/tooltip.ts +2 -2
  73. package/src/utils/constants.ts +5 -3
  74. package/src/utils/position.ts +2 -2
  75. package/src/utils/resize-observer-helper.ts +2 -2
  76. package/src/utils/transformer.ts +5 -0
  77. package/src/utils/transition-event-helper.ts +2 -2
  78. package/src/utils/types.ts +5 -1
  79. package/src/utils/utils.ts +2 -2
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "quill-table-up",
3
3
  "type": "module",
4
- "version": "2.1.9",
4
+ "version": "2.2.0",
5
5
  "packageManager": "pnpm@9.9.0",
6
6
  "description": "A table module for quill2.x",
7
7
  "author": "zzxming",
@@ -48,30 +48,30 @@
48
48
  },
49
49
  "devDependencies": {
50
50
  "@esbuild-kit/cjs-loader": "^2.4.4",
51
- "@playwright/test": "^1.50.1",
52
- "@rollup/plugin-node-resolve": "^15.3.1",
51
+ "@playwright/test": "^1.52.0",
52
+ "@rollup/plugin-node-resolve": "^16.0.1",
53
53
  "@rollup/plugin-terser": "^0.4.4",
54
54
  "@rollup/plugin-typescript": "^11.1.6",
55
- "@types/node": "^20.17.22",
56
- "@typescript-eslint/eslint-plugin": "^8.25.0",
57
- "@typescript-eslint/parser": "^8.25.0",
58
- "@vitest/coverage-v8": "^2.1.9",
59
- "@vitest/ui": "^2.1.9",
60
- "@zzxming/eslint-config": "^0.4.0",
61
- "autoprefixer": "^10.4.20",
62
- "eslint": "^9.21.0",
55
+ "@types/node": "^20.17.23",
56
+ "@typescript-eslint/eslint-plugin": "^8.31.1",
57
+ "@typescript-eslint/parser": "^8.31.1",
58
+ "@vitest/coverage-v8": "^3.1.2",
59
+ "@vitest/ui": "^3.1.2",
60
+ "@zzxming/eslint-config": "0.4.5",
61
+ "autoprefixer": "^10.4.21",
62
+ "eslint": "^9.25.0",
63
63
  "gulp": "^4.0.2",
64
64
  "gulp-clean-css": "^4.3.0",
65
65
  "gulp-less": "^5.0.0",
66
66
  "gulp-postcss": "^10.0.0",
67
- "jsdom": "^25.0.1",
67
+ "jsdom": "^26.1.0",
68
68
  "parchment": "^3.0.0",
69
69
  "postcss-pxtorem": "^6.1.0",
70
70
  "resize-observer-polyfill": "^1.5.1",
71
- "rollup": "^4.34.9",
72
- "rollup-plugin-dts": "^6.1.1",
71
+ "rollup": "^4.40.1",
72
+ "rollup-plugin-dts": "^6.2.1",
73
73
  "rollup-plugin-svg-import": "^3.0.0",
74
- "typescript": "^5.7.3",
75
- "vitest": "^2.1.9"
74
+ "typescript": "~5.7.3",
75
+ "vitest": "^3.1.2"
76
76
  }
77
77
  }
@@ -67,4 +67,10 @@ export class EditorPage {
67
67
  return window.quills[index].blur();
68
68
  }, { index: this.index });
69
69
  }
70
+
71
+ enable(enabled: boolean) {
72
+ return this.page.evaluate(({ index, enabled }) => {
73
+ return window.quills[index].enable(enabled);
74
+ }, { index: this.index, enabled });
75
+ }
70
76
  }
@@ -0,0 +1,52 @@
1
+ import { expect, test } from '@playwright/test';
2
+ import { extendTest } from './utils';
3
+
4
+ test.beforeEach(async ({ page }) => {
5
+ await page.goto('http://127.0.0.1:5500/docs/test.html');
6
+ page.locator('.ql-container.ql-snow');
7
+ });
8
+
9
+ extendTest('test table full width switch redo and undo', async ({ page, editorPage }) => {
10
+ editorPage.index = 0;
11
+ await editorPage.setContents([
12
+ { insert: '\n' },
13
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
14
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
15
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
16
+ { insert: { 'table-up-col': { tableId: '1', colId: '4', full: false, width: 100 } } },
17
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
18
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
19
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
20
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
21
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
22
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
23
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
24
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
25
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
26
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
27
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
28
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
29
+ { insert: '\n' },
30
+ ]);
31
+ await page.waitForTimeout(1000);
32
+
33
+ const cell = page.locator('#editor1 .ql-editor .ql-table td').nth(0);
34
+ await cell.click();
35
+ await cell.click({ button: 'right' });
36
+ await page.locator('.table-up-menu.is-contextmenu .table-up-menu__item').filter({ hasText: 'Switch table width' }).first().click();
37
+ expect(await page.locator('#editor1 .ql-editor .ql-table[data-full="true"]').count()).toBe(1);
38
+ expect(await page.locator('#editor1 .ql-editor .ql-table colgroup[data-full="true"]').count()).toBe(1);
39
+ expect(await page.locator('#editor1 .ql-editor .ql-table col[data-full="true"]').count()).toBe(4);
40
+ await page.waitForTimeout(1000);
41
+
42
+ await page.keyboard.press('Control+z');
43
+ expect(await page.locator('#editor1 .ql-editor .ql-table[data-full="true"]').count()).toBe(0);
44
+ expect(await page.locator('#editor1 .ql-editor .ql-table colgroup[data-full="true"]').count()).toBe(0);
45
+ expect(await page.locator('#editor1 .ql-editor .ql-table col[width="100px"]').count()).toBe(4);
46
+ await page.waitForTimeout(1000);
47
+
48
+ await page.keyboard.press('Control+Shift+z');
49
+ expect(await page.locator('#editor1 .ql-editor .ql-table[data-full="true"]').count()).toBe(1);
50
+ expect(await page.locator('#editor1 .ql-editor .ql-table colgroup[data-full="true"]').count()).toBe(1);
51
+ expect(await page.locator('#editor1 .ql-editor .ql-table col[data-full="true"]').count()).toBe(4);
52
+ });
@@ -0,0 +1,93 @@
1
+ import { expect, test } from '@playwright/test';
2
+ import { extendTest } from './utils';
3
+
4
+ test.beforeEach(async ({ page }) => {
5
+ await page.goto('http://127.0.0.1:5500/docs/test.html');
6
+ page.locator('.ql-container.ql-snow');
7
+ });
8
+
9
+ extendTest('text tableCaption insert', async ({ page, editorPage }) => {
10
+ editorPage.index = 0;
11
+ await editorPage.setContents([
12
+ { insert: '\n' },
13
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
14
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
15
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
16
+ { insert: { 'table-up-col': { tableId: '1', colId: '4', full: false, width: 100 } } },
17
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
18
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
19
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
20
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
21
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
22
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
23
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
24
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
25
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
26
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
27
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
28
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
29
+ { insert: '\n' },
30
+ ]);
31
+ await page.waitForTimeout(1000);
32
+
33
+ const cell = page.locator('#editor1 .ql-editor .ql-table td').nth(0);
34
+ await cell.click();
35
+ await expect(page.locator('#container1 .table-up-toolbox .table-up-selection .table-up-selection__line')).toBeVisible();
36
+ await cell.click({ button: 'right' });
37
+ await page.locator('.table-up-menu.is-contextmenu .table-up-menu__item').filter({ hasText: 'Insert table caption' }).first().click();
38
+
39
+ const caption = page.locator('#container1 .ql-table caption');
40
+ const tbody = page.locator('#container1 .ql-table tbody');
41
+ await expect(caption).toBeVisible();
42
+ expect(await caption.textContent()).toContain('Table Caption');
43
+ const captionBox = (await caption.boundingBox())!;
44
+ const tbodyBox = (await tbody.boundingBox())!;
45
+ expect(captionBox).not.toBeNull();
46
+ expect(tbodyBox).not.toBeNull();
47
+ expect(captionBox.y).toBeLessThan(tbodyBox.y);
48
+ });
49
+
50
+ extendTest('tableCaption side switch', async ({ page, editorPage }) => {
51
+ editorPage.index = 0;
52
+ await editorPage.setContents([
53
+ { insert: '\nTable Caption' },
54
+ { attributes: { 'table-up-caption': { tableId: '1', side: 'top' } }, insert: '\n' },
55
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
56
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
57
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
58
+ { insert: '1' },
59
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
60
+ { insert: '2' },
61
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
62
+ { insert: '3' },
63
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
64
+ { insert: '4' },
65
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
66
+ { insert: '5' },
67
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
68
+ { insert: '6' },
69
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
70
+ { insert: '7' },
71
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
72
+ { insert: '8' },
73
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
74
+ { insert: '9' },
75
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
76
+ { insert: '\n' },
77
+ ]);
78
+
79
+ const captionUINode = page.locator('#container1 .ql-table caption .ql-ui');
80
+ expect(captionUINode).not.toBeNull();
81
+
82
+ const caption = page.locator('#container1 .ql-table caption');
83
+ const boundingBox = (await caption.boundingBox())!;
84
+ expect(caption).not.toBeNull();
85
+ await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2);
86
+ await expect(captionUINode).toBeVisible();
87
+ await page.mouse.move(0, 0);
88
+ await expect(captionUINode).not.toBeVisible();
89
+
90
+ editorPage.enable(false);
91
+ await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2);
92
+ await expect(captionUINode).not.toBeVisible();
93
+ });
@@ -106,3 +106,46 @@ extendTest('toolbar item handler should trigger source USER', async ({ page, edi
106
106
  const result = await textChangePromise;
107
107
  expect(result).toBe('user');
108
108
  });
109
+
110
+ extendTest('getSemanticHTML should not effect editable when manual copy or cut', async ({ page, editorPage }) => {
111
+ editorPage.index = 0;
112
+ await editorPage.setContents([
113
+ { insert: '\nTable Caption' },
114
+ { attributes: { 'table-up-caption': { tableId: '1', side: 'top' } }, insert: '\n' },
115
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
116
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
117
+ { insert: '1' },
118
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
119
+ { insert: '2' },
120
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
121
+ { insert: '3' },
122
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
123
+ { insert: '4' },
124
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
125
+ { insert: '\n' },
126
+ ]);
127
+ const tableCaption = page.locator('#container1 .ql-table .ql-table-caption');
128
+ const td = page.locator('#container1 .ql-table td .ql-table-cell-inner').nth(0);
129
+ await expect(tableCaption).toHaveAttribute('contenteditable', 'true');
130
+ await expect(td).toHaveAttribute('contenteditable', 'true');
131
+
132
+ await editorPage.setSelection(2, 4);
133
+ await page.keyboard.press('Control+C');
134
+ await expect(tableCaption).toHaveAttribute('contenteditable', 'true');
135
+ await expect(tableCaption).toContainText('Table Caption');
136
+
137
+ await editorPage.setSelection(2, 4);
138
+ await page.keyboard.press('Control+X');
139
+ await expect(tableCaption).toHaveAttribute('contenteditable', 'true');
140
+ await expect(tableCaption).toContainText('T Caption');
141
+
142
+ await editorPage.setSelection(14, 1);
143
+ await page.keyboard.press('Control+C');
144
+ await expect(td).toHaveAttribute('contenteditable', 'true');
145
+ await expect(td).toContainText('1');
146
+
147
+ await editorPage.setSelection(14, 1);
148
+ await page.keyboard.press('Control+X');
149
+ await expect(td).toHaveAttribute('contenteditable', 'true');
150
+ await expect(td).toContainText('');
151
+ });
@@ -83,12 +83,12 @@ test('test TableResizeLine full width', async ({ page }) => {
83
83
  expect(cellBounding).not.toBeNull();
84
84
  expect(tableBounding).not.toBeNull();
85
85
 
86
- await page.mouse.move(cellBounding.x + 10, cellBounding.y + 10);
86
+ await page.mouse.move(cellBounding.x + cellBounding.width / 2, cellBounding.y + cellBounding.height / 2);
87
87
  const colBoundingBox = (await page.locator('#editor3 .table-up-resize-line__col').boundingBox())!;
88
88
  expect(colBoundingBox).not.toBeNull();
89
- await page.mouse.move(colBoundingBox.x + colBoundingBox.width / 2, colBoundingBox.y + colBoundingBox.height / 2);
89
+ await page.mouse.move(colBoundingBox.x + colBoundingBox.width / 2, colBoundingBox.y + cellBounding.height / 2);
90
90
  await page.mouse.down();
91
- await page.mouse.move(colBoundingBox.x + colBoundingBox.width / 2 + tableBounding.width * 0.05, colBoundingBox.y + colBoundingBox.height / 2);
91
+ await page.mouse.move(colBoundingBox.x + colBoundingBox.width / 2 + tableBounding.width * 0.05, colBoundingBox.y + cellBounding.height / 2);
92
92
  await page.mouse.up();
93
93
  const cols = page.locator('#editor3 .ql-table-wrapper col');
94
94
  await expect(cols.nth(1)).toHaveAttribute('width', '30%');
@@ -162,19 +162,150 @@ extendTest('test TableResizeBox and TableResizeScale should update when text cha
162
162
  const boxTop = await page.locator('#container2 .table-up-resize-box').evaluate((element) => {
163
163
  return Number.parseFloat(window.getComputedStyle(element).top);
164
164
  });
165
+ const scaleTop = await scale.evaluate((element) => {
166
+ return Number.parseFloat(window.getComputedStyle(element).top);
167
+ });
165
168
  await expect(scale).toBeVisible();
166
169
  await expect(page.locator('#container2 .table-up-resize-box .table-up-resize-box__corner')).toBeVisible();
167
170
 
168
171
  await editorPage.updateContents([{ insert: '12345\n12345\n12345' }], 'user');
172
+ await page.evaluate(() => {
173
+ window.scrollTo(0, 0);
174
+ });
169
175
 
170
176
  await expect(scale).toBeVisible();
171
177
  await expect(page.locator('#container2 .table-up-resize-box .table-up-resize-box__corner')).toBeVisible();
172
- const scaleTop = await scale.evaluate((element) => {
178
+ const newScaleTop = await scale.evaluate((element) => {
173
179
  return Number.parseFloat(window.getComputedStyle(element).top);
174
180
  });
175
- expect(scaleTop).toBeCloseTo(lineBound.height * 3, 4);
181
+ expect(newScaleTop).toBeCloseTo(scaleTop + lineBound.height * 2, 4);
176
182
  const newBoxTop = await page.locator('#container2 .table-up-resize-box').evaluate((element) => {
177
183
  return Number.parseFloat(window.getComputedStyle(element).top);
178
184
  });
179
185
  expect(newBoxTop).toBeCloseTo(boxTop + lineBound.height * 2, 4);
180
186
  });
187
+
188
+ extendTest('test TableResizeScale should hide when table width switch full', async ({ page }) => {
189
+ await createTableBySelect(page, 'container1', 3, 3);
190
+
191
+ const cell = page.locator('#editor1 .ql-editor .ql-table td').nth(0);
192
+ await cell.click();
193
+ await expect(page.locator('#container1 .table-up-scale')).toBeVisible();
194
+
195
+ await cell.click({ button: 'right' });
196
+ await page.locator('.table-up-menu.is-contextmenu .table-up-menu__item').filter({ hasText: 'Switch table width' }).first().click();
197
+ await expect(page.locator('#container1 .table-up-scale')).not.toBeVisible();
198
+ });
199
+
200
+ extendTest('test TableResizeBox head click and shift click (column)', async ({ page }) => {
201
+ await createTableBySelect(page, 'container2', 3, 3);
202
+
203
+ const firstCell = page.locator('#editor2').getByRole('cell').nth(0);
204
+ await firstCell.click();
205
+ expect(page.locator('#editor2 .table-up-resize-box .table-up-resize-box__corner')).toBeVisible();
206
+
207
+ await page.locator('#editor2 .table-up-resize-box__col-header').nth(0).click();
208
+ const selection = page.locator('#editor2 .table-up-selection .table-up-selection__line');
209
+ const selectionBounding = (await selection.boundingBox())!;
210
+ expect(selectionBounding).not.toBeNull();
211
+
212
+ const tableBounding = (await page.locator('#editor2 .ql-table').boundingBox())!;
213
+ expect(tableBounding).not.toBeNull();
214
+ // minus beacuse `border-collapse: collapse;`
215
+ expect(selectionBounding.height).toBe(tableBounding.height - 1);
216
+
217
+ await page.keyboard.down('Shift');
218
+ await page.locator('#editor2 .table-up-resize-box__col-header').nth(2).click();
219
+
220
+ const selectionBounding2 = (await selection.boundingBox())!;
221
+ expect(selectionBounding2).not.toBeNull();
222
+ expect(selectionBounding2.height).toBe(tableBounding.height - 1);
223
+ expect(selectionBounding2.width).toBe(tableBounding.width - 1);
224
+ });
225
+
226
+ extendTest('test TableResizeBox head click and shift click (row)', async ({ page }) => {
227
+ await createTableBySelect(page, 'container2', 3, 3);
228
+
229
+ const firstCell = page.locator('#editor2').getByRole('cell').nth(0);
230
+ await firstCell.click();
231
+ expect(page.locator('#editor2 .table-up-resize-box .table-up-resize-box__corner')).toBeVisible();
232
+
233
+ await page.locator('#editor2 .table-up-resize-box__row-header').nth(0).click();
234
+ const selection = page.locator('#editor2 .table-up-selection .table-up-selection__line');
235
+ const selectionBounding = (await selection.boundingBox())!;
236
+ expect(selectionBounding).not.toBeNull();
237
+
238
+ const tableBounding = (await page.locator('#editor2 .ql-table').boundingBox())!;
239
+ expect(tableBounding).not.toBeNull();
240
+ // minus beacuse `border-collapse: collapse;`
241
+ expect(selectionBounding.width).toBe(tableBounding.width - 1);
242
+
243
+ await page.keyboard.down('Shift');
244
+ await page.locator('#editor2 .table-up-resize-box__row-header').nth(2).click();
245
+
246
+ const selectionBounding2 = (await selection.boundingBox())!;
247
+ expect(selectionBounding2).not.toBeNull();
248
+ expect(selectionBounding2.height).toBe(tableBounding.height - 1);
249
+ expect(selectionBounding2.width).toBe(tableBounding.width - 1);
250
+ });
251
+
252
+ extendTest('test TableResizeBox head click and shift click (row mixin column)', async ({ page }) => {
253
+ await createTableBySelect(page, 'container2', 3, 3);
254
+ const firstCell = page.locator('#editor2').getByRole('cell').nth(0);
255
+ await firstCell.click();
256
+ expect(page.locator('#editor2 .table-up-resize-box .table-up-resize-box__corner')).toBeVisible();
257
+
258
+ await page.locator('#editor2 .table-up-resize-box__row-header').nth(1).click();
259
+ await page.keyboard.down('Shift');
260
+ await page.locator('#editor2 .table-up-resize-box__col-header').nth(1).click();
261
+
262
+ const selectionBounding = (await page.locator('#editor2 .table-up-selection .table-up-selection__line').boundingBox())!;
263
+ expect(selectionBounding).not.toBeNull();
264
+ const cellBounding = (await page.locator('#editor2 .ql-editor .ql-table td').nth(0).boundingBox())!;
265
+ expect(cellBounding).not.toBeNull();
266
+ expect(selectionBounding.height).toBe(cellBounding.height * 2);
267
+ expect(selectionBounding.width).toBe(cellBounding.width * 2);
268
+ });
269
+
270
+ extendTest('test TableResizeBox head click and shift click (scroll table wrapper)', async ({ page, editorPage }) => {
271
+ editorPage.index = 1;
272
+ editorPage.setContents([
273
+ { insert: '\n' },
274
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 500 } } },
275
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 500 } } },
276
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 500 } } },
277
+ { insert: { 'table-up-col': { tableId: '1', colId: '4', full: false, width: 500 } } },
278
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
279
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
280
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
281
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
282
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
283
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
284
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
285
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
286
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
287
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
288
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
289
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
290
+ { insert: '\n' },
291
+ ]);
292
+
293
+ const firstCell = page.locator('#editor2').getByRole('cell').nth(0);
294
+ await firstCell.click();
295
+ expect(page.locator('#editor2 .table-up-resize-box .table-up-resize-box__corner')).toBeVisible();
296
+ await page.locator('#editor2 .ql-table-wrapper').evaluate((el) => {
297
+ el.scrollLeft = el.scrollWidth;
298
+ });
299
+
300
+ await page.locator('#editor2 .table-up-resize-box__col-header').nth(2).click();
301
+ await page.locator('#editor2 .ql-table-wrapper').evaluate((el) => {
302
+ el.scrollLeft = 0;
303
+ });
304
+ await page.keyboard.down('Shift');
305
+ await page.locator('#editor2 .table-up-resize-box__col-header').nth(0).click();
306
+
307
+ const selectionBounding = (await page.locator('#editor2 .table-up-selection .table-up-selection__line').boundingBox())!;
308
+ const cellBounding = (await page.locator('#editor2 .ql-editor .ql-table td').nth(0).boundingBox())!;
309
+ expect(cellBounding).not.toBeNull();
310
+ expect(selectionBounding.width).toBe(cellBounding.width * 3);
311
+ });
@@ -54,31 +54,28 @@ test('test TableSelection vertical', async ({ page }) => {
54
54
  const cellBounding = (await cell.boundingBox())!;
55
55
  expect(cellBounding).not.toBeNull();
56
56
  await cell.click();
57
- await cell.click();
58
- const selectionLine = page.locator('#editor1 .table-up-selection__line');
59
- await expect(selectionLine).toBeVisible();
57
+ await expect(page.locator('#editor1 .table-up-selection__line')).toBeVisible();
60
58
 
61
59
  await page.locator('#editor1 .ql-editor .ql-table td').nth(0).click();
62
60
  await page.locator('#editor1 .ql-editor .ql-table td').nth(0).click();
63
- await expect(selectionLine).toBeVisible();
61
+ await expect(page.locator('#editor1 .table-up-selection__line')).toBeVisible();
64
62
  await page.mouse.down();
65
- await page.mouse.move(cellBounding.x, cellBounding.y + cellBounding.height * 3);
63
+ await page.mouse.move(cellBounding.x + cellBounding.width * 0.5, cellBounding.y + cellBounding.height * 3);
66
64
  await page.mouse.up();
67
65
  await cell.click({ button: 'right' });
68
66
  await page.locator('.table-up-menu.is-contextmenu .table-up-menu__item').filter({ hasText: 'Merge Cell' }).first().click();
69
67
 
70
68
  await page.locator('#editor1 .ql-editor .ql-table td').nth(0).click();
71
- await page.locator('#editor1 .ql-editor .ql-table td').nth(0).click();
72
- await expect(selectionLine).toBeVisible();
69
+ await expect(page.locator('#editor1 .table-up-selection__line')).toBeVisible();
73
70
  await page.mouse.down();
74
- await page.mouse.move(cellBounding.x + cellBounding.width * 2 - 10, cellBounding.y + 10);
71
+ await page.mouse.move(cellBounding.x + cellBounding.width * 1.5, cellBounding.y + cellBounding.height * 0.5);
75
72
  await page.mouse.up();
76
73
 
77
74
  expect(
78
- Number.parseFloat(await selectionLine.evaluate(el => getComputedStyle(el).width)),
75
+ Number.parseFloat(await page.locator('#editor1 .table-up-selection__line').evaluate(el => getComputedStyle(el).width)),
79
76
  ).toBeCloseTo(cellBounding.width * 2, -1);
80
77
  expect(
81
- Number.parseFloat(await selectionLine.evaluate(el => getComputedStyle(el).height)),
78
+ Number.parseFloat(await page.locator('#editor1 .table-up-selection__line').evaluate(el => getComputedStyle(el).height)),
82
79
  ).toBeCloseTo(cellBounding.height * 3, -1);
83
80
  });
84
81
 
@@ -2,10 +2,10 @@ import type { Page } from '@playwright/test';
2
2
  import { test } from '@playwright/test';
3
3
  import { EditorPage } from './editor-page';
4
4
 
5
- export const createTableBySelect = async (page: Page, container: string, row: number, col: number) => {
5
+ export async function createTableBySelect(page: Page, container: string, row: number, col: number) {
6
6
  await page.locator(`#${container} .ql-toolbar .ql-table-up.ql-picker`).click();
7
7
  await page.locator(`#${container} .ql-toolbar .ql-custom-select .table-up-select-box__item[data-row="${row}"][data-col="${col}"]`).click();
8
- };
8
+ }
9
9
 
10
10
  export const extendTest = test.extend<{
11
11
  editorPage: EditorPage;