quill-table-up 2.0.1 → 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 +5 -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
@@ -1 +1 @@
1
- .table-up-input__item{--input-height:2rem;--input-inner-height:calc(var(--input-height) - 0.125rem);--input-color-text:#606266;--input-color-boxshaow:#dcdfe6;--input-color-focus:#409eff;--input-color-error:#f56c6c;--input-boxshaow:0 0 0 0.0625rem var(--input-color-boxshaow) inset;--input-boxshaow-focus:0 0 0 0.0625rem var(--input-color-focus) inset;--input-boxshaow-error:0 0 0 0.0625rem var(--input-color-error) inset;display:flex;align-items:center}.table-up-input__item+.table-up-input__item{margin-top:1.125rem}.table-up-input__label{width:5rem;flex-shrink:0}.table-up-input__input{box-sizing:border-box;position:relative;display:flex;flex-wrap:wrap;width:100%;height:var(--input-height);line-height:var(--input-height);padding:.0625rem .5rem;border-radius:.25rem;box-shadow:var(--input-boxshaow);transition:box-shadow .2s linear}.table-up-input__input.focus{box-shadow:var(--input-boxshaow-focus)}.table-up-input__input input{width:100%;height:var(--input-inner-height);line-height:var(--input-inner-height);flex-grow:1;font-size:.875rem;color:var(--input-color-text);outline:0;border:0;padding:0}.table-up-input__input.error{box-shadow:var(--input-boxshaow-error)}.table-up-input__error-tip{position:absolute;top:100%;left:0;font-size:.75rem;color:var(--input-color-error);line-height:1rem}.ql-snow .table-up-select-box{--select-box-color-bg-hover:#f5f5f5;--select-box-color-bg-active:#e0f2fe;--select-box-custom-color-text:#0d0d0d;--select-box-custom-color-bg:transparent;--select-box-custom-color-bg-hover:#ebebeb}.table-up-select-box{--select-box-color-border:#e5e7eb;--select-box-border:0.0625rem solid var(--select-box-color-border);--select-box-color-active:#0ea5e9;--select-box-color-bg-hover:#f5f5f5;--select-box-color-bg-active:transparent;--select-box-custom-color-text:#f5f5f5;--select-box-custom-color-bg:transparent;--select-box-custom-color-bg-hover:#2c2c2c}.table-up-select-box__block{display:flex;width:10rem;flex-wrap:wrap;align-items:center;justify-content:center}.table-up-select-box__item{margin:.125rem;height:1rem;width:1rem;border:var(--select-box-border)}.table-up-select-box__item.active{border-color:var(--select-box-color-active);background-color:var(--select-box-color-bg-active)}.table-up-select-box__custom{padding:.5rem;color:var(--select-box-custom-color-text);background-color:var(--select-box-custom-color-bg);font-size:1rem;text-align:center;cursor:pointer}.table-up-select-box__custom:hover{background-color:var(--select-box-custom-color-bg-hover)}.table-up-table-creator{padding:1.5rem}.table-up-table-creator__input{display:flex;flex-direction:column;width:100%}.table-up-table-creator__control{margin-top:1rem;text-align:right}
1
+ .table-up-input__item{--input-height:2rem;--input-inner-height:calc(var(--input-height) - 0.125rem);--input-color-text:#606266;--input-color-boxshaow:#dcdfe6;--input-color-focus:#409eff;--input-color-error:#f56c6c;--input-boxshaow:0 0 0 0.0625rem var(--input-color-boxshaow) inset;--input-boxshaow-focus:0 0 0 0.0625rem var(--input-color-focus) inset;--input-boxshaow-error:0 0 0 0.0625rem var(--input-color-error) inset;display:flex;align-items:center}.table-up-input__item+.table-up-input__item{margin-top:1.125rem}.table-up-input__label{width:5rem;flex-shrink:0}.table-up-input__input{box-sizing:border-box;position:relative;display:flex;flex-wrap:wrap;width:100%;height:var(--input-height);line-height:var(--input-height);padding:.0625rem .5rem;border-radius:.25rem;box-shadow:var(--input-boxshaow);transition:box-shadow .2s linear}.table-up-input__input.focus{box-shadow:var(--input-boxshaow-focus)}.table-up-input__input input{width:100%;height:var(--input-inner-height);line-height:var(--input-inner-height);flex-grow:1;font-size:.875rem;color:var(--input-color-text);outline:0;border:0;padding:0}.table-up-input__input.error{box-shadow:var(--input-boxshaow-error)}.table-up-input__error-tip{position:absolute;top:100%;left:0;font-size:.75rem;color:var(--input-color-error);line-height:1rem}.ql-snow .table-up-select-box{--select-box-color-bg-hover:#f5f5f5;--select-box-color-bg-active:#e0f2fe;--select-box-custom-color-text:#0d0d0d;--select-box-custom-color-bg:transparent;--select-box-custom-color-bg-hover:#ebebeb}.table-up-select-box{--select-box-color-border:#e5e7eb;--select-box-border:0.0625rem solid var(--select-box-color-border);--select-box-color-active:#0ea5e9;--select-box-color-bg-hover:#f5f5f5;--select-box-color-bg-active:transparent;--select-box-custom-color-text:#f5f5f5;--select-box-custom-color-bg:transparent;--select-box-custom-color-bg-hover:#2c2c2c}.table-up-select-box__block{display:flex;width:10rem;flex-wrap:wrap;align-items:center;justify-content:center}.table-up-select-box__item{margin:.125rem;height:1rem;width:1rem;border:var(--select-box-border)}.table-up-select-box__item.active{border-color:var(--select-box-color-active);background-color:var(--select-box-color-bg-active)}.table-up-select-box__custom{padding:.5rem;color:var(--select-box-custom-color-text);background-color:var(--select-box-custom-color-bg);font-size:1rem;text-align:center;cursor:pointer}.table-up-select-box__custom:hover{background-color:var(--select-box-custom-color-bg-hover)}.table-up-creator{padding:1.5rem}.table-up-creator__input{display:flex;flex-direction:column;width:100%}.table-up-creator__control{margin-top:1rem;text-align:right}.table-up-creator__checkbox{--active-color:#506eec;--mark-bg-color:#fff;--mark-border-color:#212121;display:flex;align-items:center;margin-top:.25rem;position:relative;cursor:pointer;font-size:.75rem;-webkit-user-select:none;-moz-user-select:none;user-select:none}.table-up-creator__checkbox input{position:absolute;opacity:0;cursor:pointer;height:0;width:0}.table-up-creator__checkbox input:checked~.table-up-creator__mark{--mark-bg-color:var(--active-color);--mark-border-color:var(--active-color)}.table-up-creator__checkbox input:checked~.table-up-creator__mark:after{display:block}.table-up-creator__mark{position:relative;top:0;left:0;height:1.125rem;width:1.125rem;margin-right:.25rem;background:var(--mark-bg-color);border:.0625rem solid var(--mark-border-color);border-radius:.3125rem}.table-up-creator__mark::after{content:'';position:absolute;display:none;left:.3125rem;top:.125rem;width:.3125rem;height:.5625rem;border:solid #fff;border-width:0 .125rem .125rem 0;transform:rotate(45deg)}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "quill-table-up",
3
3
  "type": "module",
4
- "version": "2.0.1",
4
+ "version": "2.0.3",
5
5
  "packageManager": "pnpm@9.9.0",
6
6
  "description": "A table module for quill2.x",
7
7
  "author": "zzxming",
@@ -26,7 +26,8 @@
26
26
  "main": "./dist/index.js",
27
27
  "types": "./dist/index.d.ts",
28
28
  "files": [
29
- "dist"
29
+ "dist",
30
+ "src"
30
31
  ],
31
32
  "scripts": {
32
33
  "lint": "eslint . --cache",
@@ -43,7 +44,8 @@
43
44
  "quill": "^2.0.0"
44
45
  },
45
46
  "dependencies": {
46
- "@floating-ui/dom": "^1.6.12"
47
+ "@floating-ui/dom": "^1.6.12",
48
+ "@zzxming/eslint-config": "^0.3.5"
47
49
  },
48
50
  "devDependencies": {
49
51
  "@esbuild-kit/cjs-loader": "^2.4.4",
@@ -52,23 +54,17 @@
52
54
  "@rollup/plugin-terser": "^0.4.4",
53
55
  "@rollup/plugin-typescript": "^11.1.6",
54
56
  "@types/node": "^20.14.10",
55
- "@typescript-eslint/eslint-plugin": "^8.0.0",
56
- "@typescript-eslint/parser": "^8.0.0",
57
+ "@typescript-eslint/eslint-plugin": "^8.18.2",
58
+ "@typescript-eslint/parser": "^8.18.2",
57
59
  "@vitest/coverage-v8": "^2.0.5",
58
60
  "@vitest/ui": "^2.0.5",
59
- "@zzxming/eslint-config": "^0.3.4",
60
61
  "autoprefixer": "^10.4.19",
61
- "eslint": "^9.11.1",
62
- "eslint-merge-processors": "^0.1.0",
63
- "eslint-plugin-jsonc": "^2.16.0",
64
- "eslint-plugin-markdown": "^5.1.0",
65
- "eslint-plugin-yml": "^1.14.0",
62
+ "eslint": "^9.17.0",
66
63
  "gulp": "^4.0.0",
67
64
  "gulp-clean-css": "^4.3.0",
68
65
  "gulp-less": "^5.0.0",
69
66
  "gulp-postcss": "^10.0.0",
70
67
  "jsdom": "^25.0.0",
71
- "jsonc-eslint-parser": "^2.4.0",
72
68
  "parchment": "^3.0.0",
73
69
  "postcss-pxtorem": "^6.1.0",
74
70
  "resize-observer-polyfill": "^1.5.1",
@@ -76,7 +72,6 @@
76
72
  "rollup-plugin-dts": "^6.1.1",
77
73
  "rollup-plugin-svg-import": "^3.0.0",
78
74
  "typescript": "^5.5.3",
79
- "vitest": "^2.0.5",
80
- "yaml-eslint-parser": "^1.2.3"
75
+ "vitest": "^2.0.5"
81
76
  }
82
77
  }
@@ -0,0 +1,44 @@
1
+ import { expect, test } from '@playwright/test';
2
+ import { createTableBySelect } from './utils';
3
+
4
+ test.beforeEach(async ({ page }) => {
5
+ await page.goto('http://127.0.0.1:5500/docs/test.html');
6
+ page.locator('#editor1.ql-container.ql-snow');
7
+ });
8
+
9
+ test('custom selecor should work', async ({ page }) => {
10
+ await createTableBySelect(page, 'container1', 3, 3);
11
+
12
+ const isVisible = await page.locator('#editor1.ql-container .ql-table-wrapper').isVisible();
13
+ expect(isVisible).toBe(true);
14
+ const colCount = await page.locator('#editor1.ql-container .ql-table-wrapper col').count();
15
+ expect(colCount).toBe(3);
16
+ const rowCount = await page.locator('#editor1.ql-container .ql-table-wrapper tr').count();
17
+ expect(rowCount).toBe(3);
18
+ const cellCount = await page.locator('#editor1.ql-container .ql-table-wrapper td').count();
19
+ expect(cellCount).toBe(9);
20
+ });
21
+
22
+ test('custom button should work', async ({ page }) => {
23
+ await page.locator('#container1 .ql-toolbar .ql-table-up > .ql-picker-label').first().click();
24
+ await page.locator('#container1 .ql-toolbar .ql-table-up .ql-custom-select').getByText('Custom').click();
25
+
26
+ await page.locator('.table-up-dialog .table-up-button.confirm').click();
27
+ const rowInput = page.locator('.table-up-dialog .table-up-input__input').first();
28
+ expect(rowInput).toHaveClass(/error/);
29
+ const errorText = await page.locator('.table-up-dialog .table-up-input__input').first().locator('.table-up-input__error-tip').textContent();
30
+ expect(errorText).toBe('Please enter a positive integer');
31
+
32
+ await page.locator('.table-up-input__item').nth(0).locator('input').fill('3');
33
+ await page.locator('.table-up-input__item').nth(1).locator('input').fill('3');
34
+ await page.getByRole('button', { name: 'Confirm' }).click();
35
+
36
+ const isVisible = await page.locator('#editor1.ql-container .ql-table-wrapper').isVisible();
37
+ expect(isVisible).toBe(true);
38
+ const colCount = await page.locator('#editor1.ql-container .ql-table-wrapper col').count();
39
+ expect(colCount).toBe(3);
40
+ const rowCount = await page.locator('#editor1.ql-container .ql-table-wrapper tr').count();
41
+ expect(rowCount).toBe(3);
42
+ const cellCount = await page.locator('#editor1.ql-container .ql-table-wrapper td').count();
43
+ expect(cellCount).toBe(9);
44
+ });
@@ -0,0 +1,39 @@
1
+ import { expect, test } from '@playwright/test';
2
+ import { createTableBySelect } 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
+ test('test TableAlign', async ({ page }) => {
10
+ await createTableBySelect(page, 'container1', 3, 3);
11
+ const centerCell = page.locator('#editor1').getByRole('cell').nth(4);
12
+ await centerCell.click();
13
+ const cellBounding = (await centerCell.boundingBox())!;
14
+ expect(cellBounding).not.toBeNull();
15
+ await page.mouse.move(cellBounding.x, cellBounding.y);
16
+ const colBoundingBox = (await page.locator('#editor1 .table-up-resize-line__col').boundingBox())!;
17
+ expect(colBoundingBox).not.toBeNull();
18
+ await page.mouse.move(colBoundingBox.x + colBoundingBox.width / 2, colBoundingBox.y + colBoundingBox.height / 2);
19
+ await page.mouse.down();
20
+ await page.mouse.move(colBoundingBox.x + colBoundingBox.width / 2 - 200, colBoundingBox.y + colBoundingBox.height / 2);
21
+ await page.mouse.up();
22
+ await centerCell.click();
23
+
24
+ const isVisible = await page.locator('#editor1 .table-up-align.table-up-align--active').isVisible();
25
+ expect(isVisible).toBeTruthy();
26
+
27
+ const table = page.locator('#editor1 .ql-editor .ql-table');
28
+ await page.locator('#editor1 .table-up-align .table-up-align__item[data-align="center"]').click();
29
+ await expect(table).toHaveCSS('margin-left', `100px`);
30
+ await expect(table).toHaveCSS('margin-right', `100px`);
31
+
32
+ await page.locator('#editor1 .table-up-align .table-up-align__item[data-align="right"]').click();
33
+ await expect(table).toHaveCSS('margin-left', `200px`);
34
+ await expect(table).toHaveCSS('margin-right', '0px');
35
+
36
+ await page.locator('#editor1 .table-up-align .table-up-align__item[data-align="left"]').click();
37
+ await expect(table).toHaveCSS('margin-left', '0px');
38
+ await expect(table).toHaveCSS('margin-right', '200px');
39
+ });
@@ -0,0 +1,152 @@
1
+ import { expect, test } from '@playwright/test';
2
+ import { createTableBySelect } 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
+ test('test TableResizeLine fixed width', async ({ page }) => {
10
+ await createTableBySelect(page, 'container1', 3, 3);
11
+ const centerCell = page.locator('#editor1').getByRole('cell').nth(4);
12
+ await centerCell.click();
13
+ const cellBounding = (await centerCell.boundingBox())!;
14
+ expect(cellBounding).not.toBeNull();
15
+
16
+ // col
17
+ await page.mouse.move(cellBounding.x + 10, cellBounding.y + 10);
18
+ const colBoundingBox = (await page.locator('#editor1 .table-up-resize-line__col').boundingBox())!;
19
+ expect(colBoundingBox).not.toBeNull();
20
+ await page.mouse.move(colBoundingBox.x + colBoundingBox.width / 2, colBoundingBox.y + colBoundingBox.height / 2);
21
+ await page.mouse.down();
22
+ await page.mouse.move(colBoundingBox.x + colBoundingBox.width / 2 + 100, colBoundingBox.y + colBoundingBox.height / 2);
23
+ await page.mouse.up();
24
+ expect(page.locator('#editor1 .ql-table-wrapper col').nth(1)).toHaveAttribute('width', `${Math.floor(cellBounding.width) + 100}px`);
25
+ await page.mouse.move(cellBounding.x, cellBounding.y);
26
+
27
+ // row
28
+ await page.mouse.move(cellBounding.x + 10, cellBounding.y + 10);
29
+ const rowBoundingBox = (await page.locator('#editor1 .table-up-resize-line__row').boundingBox())!;
30
+ expect(rowBoundingBox).not.toBeNull();
31
+ await page.mouse.move(rowBoundingBox.x + rowBoundingBox.width / 2, rowBoundingBox.y + rowBoundingBox.height / 2);
32
+ await page.mouse.down();
33
+ await page.mouse.move(rowBoundingBox.x + rowBoundingBox.width / 2, rowBoundingBox.y + rowBoundingBox.height / 2 + 100);
34
+ await page.mouse.up();
35
+ const cells = await page.locator('#editor1 .ql-table-wrapper tr').nth(1).locator('td').all();
36
+ for (const cell of cells) {
37
+ await expect(cell).toHaveCSS('height', `${Math.floor(cellBounding.height) + 100}px`);
38
+ }
39
+ });
40
+
41
+ test('test TableResizeBox fixed width', async ({ page }) => {
42
+ await createTableBySelect(page, 'container2', 3, 3);
43
+ const centerCell = page.locator('#editor2').getByRole('cell').nth(4);
44
+ await centerCell.click();
45
+ const cellBounding = (await centerCell.boundingBox())!;
46
+ expect(cellBounding).not.toBeNull();
47
+
48
+ // col
49
+ const colBoundingBox = await page.locator('#editor2 .table-up-resize-box__col-separator').nth(1).boundingBox();
50
+ expect(colBoundingBox).not.toBeNull();
51
+ if (!colBoundingBox) {
52
+ throw new Error('colBoundingBox is null');
53
+ }
54
+ await page.mouse.move(colBoundingBox.x + colBoundingBox.width - 4, colBoundingBox.y + 4);
55
+ await page.mouse.down();
56
+ await page.mouse.move(colBoundingBox.x + colBoundingBox.width - 4 + 100, colBoundingBox.y + 4);
57
+ await page.mouse.up();
58
+ expect(page.locator('#editor2 .ql-table-wrapper col').nth(1)).toHaveAttribute('width', `${Math.floor(cellBounding.width - 4) + 100}px`);
59
+
60
+ // row
61
+ const rowBoundingBox = await page.locator('#editor2 .table-up-resize-box__row-separator').nth(1).boundingBox();
62
+ expect(rowBoundingBox).not.toBeNull();
63
+ if (!rowBoundingBox) {
64
+ throw new Error('rowBoundingBox is null');
65
+ }
66
+ await page.mouse.move(rowBoundingBox.x + 4, rowBoundingBox.y + rowBoundingBox.height - 4);
67
+ await page.mouse.down();
68
+ await page.mouse.move(rowBoundingBox.x + 4, rowBoundingBox.y + rowBoundingBox.height - 4 + 100);
69
+ await page.mouse.up();
70
+ const cells = await page.locator('#editor2 .ql-table-wrapper tr').nth(1).locator('td').all();
71
+ expect(cells.length).toEqual(3);
72
+ for (const cell of cells) {
73
+ await expect(cell).toHaveCSS('height', `${Math.floor(cellBounding.height - 4) + 100}px`);
74
+ }
75
+ });
76
+
77
+ test('test TableResizeLine full width', async ({ page }) => {
78
+ await createTableBySelect(page, 'container3', 4, 4);
79
+ const centerCell = page.locator('#editor3').getByRole('cell').nth(1);
80
+ await centerCell.click();
81
+ const cellBounding = (await centerCell.boundingBox())!;
82
+ const tableBounding = (await page.locator('#editor3 .ql-table').boundingBox())!;
83
+ expect(cellBounding).not.toBeNull();
84
+ expect(tableBounding).not.toBeNull();
85
+
86
+ await page.mouse.move(cellBounding.x + 10, cellBounding.y + 10);
87
+ const colBoundingBox = (await page.locator('#editor3 .table-up-resize-line__col').boundingBox())!;
88
+ expect(colBoundingBox).not.toBeNull();
89
+ await page.mouse.move(colBoundingBox.x + colBoundingBox.width / 2, colBoundingBox.y + colBoundingBox.height / 2);
90
+ await page.mouse.down();
91
+ await page.mouse.move(colBoundingBox.x + colBoundingBox.width / 2 + tableBounding.width * 0.05, colBoundingBox.y + colBoundingBox.height / 2);
92
+ await page.mouse.up();
93
+ const cols = page.locator('#editor3 .ql-table-wrapper col');
94
+ await expect(cols.nth(1)).toHaveAttribute('width', '30%');
95
+ await expect(cols.nth(2)).toHaveAttribute('width', '20%');
96
+ });
97
+
98
+ test('test TableResizeBox full width', async ({ page }) => {
99
+ await createTableBySelect(page, 'container4', 4, 4);
100
+ const centerCell = page.locator('#editor4').getByRole('cell').nth(1);
101
+ await centerCell.click();
102
+ const cellBounding = (await centerCell.boundingBox())!;
103
+ const tableBounding = (await page.locator('#editor4 .ql-table').boundingBox())!;
104
+ expect(cellBounding).not.toBeNull();
105
+ expect(tableBounding).not.toBeNull();
106
+
107
+ const colBoundingBox = (await page.locator('#editor4 .table-up-resize-box__col-separator').nth(1).boundingBox())!;
108
+ expect(colBoundingBox).not.toBeNull();
109
+ await page.mouse.move(colBoundingBox.x + colBoundingBox.width - 4, colBoundingBox.y + 4);
110
+ await page.mouse.down();
111
+ await page.mouse.move(colBoundingBox.x + colBoundingBox.width - 4 + tableBounding.width * 0.05, colBoundingBox.y);
112
+ await page.mouse.up();
113
+ const cols = page.locator('#editor4 .ql-table-wrapper col');
114
+ await expect(cols.nth(1)).toHaveAttribute('width', '30%');
115
+ await expect(cols.nth(2)).toHaveAttribute('width', '20%');
116
+ });
117
+
118
+ test('test TableResizeBox position', async ({ page }) => {
119
+ await createTableBySelect(page, 'container2', 3, 3);
120
+
121
+ const firstCell = page.locator('#editor2').getByRole('cell').nth(0);
122
+ await firstCell.click();
123
+ const firstCellBounding = (await firstCell.boundingBox())!;
124
+ expect(firstCellBounding).not.toBeNull();
125
+ const toolBounding = (await page.locator('#editor2 .table-up-toolbox .table-up-resize-box').boundingBox())!;
126
+ expect(toolBounding).not.toBeNull();
127
+ expect(firstCellBounding.x).toEqual(toolBounding.x);
128
+ expect(firstCellBounding.y).toEqual(toolBounding.y);
129
+ });
130
+
131
+ test('test TableResizeScale', async ({ page }) => {
132
+ await createTableBySelect(page, 'container1', 3, 3);
133
+ const centerCell = page.locator('#editor1').getByRole('cell').nth(4);
134
+ await centerCell.click();
135
+ const cellBounding = (await centerCell.boundingBox())!;
136
+ const scaleBtnBounding = (await page.locator('#editor1 .table-up-scale__block').boundingBox())!;
137
+ expect(cellBounding).not.toBeNull();
138
+ expect(scaleBtnBounding).not.toBeNull();
139
+ await page.mouse.move(scaleBtnBounding.x + scaleBtnBounding.width / 2, scaleBtnBounding.y + scaleBtnBounding.height / 2);
140
+ await page.mouse.down();
141
+ await page.mouse.move(scaleBtnBounding.x + scaleBtnBounding.width / 2 - 90, scaleBtnBounding.y + scaleBtnBounding.height / 2 + 90);
142
+ await page.mouse.up();
143
+ const cols = page.locator('#editor1 .ql-table-wrapper col');
144
+ for (const col of await cols.all()) {
145
+ await expect(col).toHaveAttribute('width', `${Math.floor(cellBounding.width - 30)}px`);
146
+ }
147
+
148
+ const cells = page.locator('#editor1 .ql-table-wrapper td');
149
+ for (const cell of await cells.all()) {
150
+ await expect(cell).toHaveCSS('height', `${Math.floor(cellBounding.height + 30)}px`);
151
+ }
152
+ });
@@ -0,0 +1,31 @@
1
+ import { expect, test } from '@playwright/test';
2
+ import { createTableBySelect } 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
+ test('test TableScrollbar', async ({ page }) => {
10
+ await createTableBySelect(page, 'container2', 3, 3);
11
+ const centerCell = page.locator('#editor2').getByRole('cell').nth(4);
12
+ await centerCell.click();
13
+ const cellBounding = (await centerCell.boundingBox())!;
14
+ expect(cellBounding).not.toBeNull();
15
+
16
+ await page.waitForTimeout(200);
17
+ expect(await page.locator('#editor2 .table-up-scrollbar.is-vertical').isVisible()).toBeFalsy();
18
+ expect(await page.locator('#editor2 .table-up-scrollbar.is-horizontal').isVisible()).toBeFalsy();
19
+
20
+ const colBoundingBox = (await page.locator('#editor2 .table-up-resize-box__col-separator').nth(1).boundingBox())!;
21
+ expect(colBoundingBox).not.toBeNull();
22
+ await page.mouse.move(colBoundingBox.x + colBoundingBox.width - 4, colBoundingBox.y + 4);
23
+ await page.mouse.down();
24
+ await page.mouse.move(colBoundingBox.x + colBoundingBox.width - 4 + 100, colBoundingBox.y + 4);
25
+ await page.mouse.up();
26
+
27
+ await page.mouse.move(cellBounding.x, cellBounding.y);
28
+ await page.waitForTimeout(200);
29
+ expect(await page.locator('#editor2 .table-up-scrollbar.is-vertical').isVisible()).toBeFalsy();
30
+ expect(await page.locator('#editor2 .table-up-scrollbar.is-horizontal').isVisible()).toBeTruthy();
31
+ });
@@ -0,0 +1,83 @@
1
+ import { expect, test } from '@playwright/test';
2
+ import { createTableBySelect } 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
+ test('test TableSelection horizontal', async ({ page }) => {
10
+ await createTableBySelect(page, 'container1', 5, 5);
11
+ const cell = page.locator('#editor1 .ql-editor .ql-table td').nth(0);
12
+ await cell.click();
13
+ const cellBounding = (await cell.boundingBox())!;
14
+ expect(cellBounding).not.toBeNull();
15
+
16
+ await cell.click();
17
+ const selectionLine = page.locator('#editor1 .table-up-selection__line');
18
+ await expect(selectionLine).toBeVisible();
19
+ await page.mouse.down();
20
+ await page.mouse.move(cellBounding.x + cellBounding.width * 3, cellBounding.y + cellBounding.height / 2);
21
+ await page.mouse.up();
22
+
23
+ await expect(selectionLine).toBeVisible();
24
+ expect(
25
+ Number.parseFloat(await selectionLine.evaluate(el => getComputedStyle(el).width)),
26
+ ).toBeCloseTo(cellBounding.width * 3, -1);
27
+ expect(
28
+ Number.parseFloat(await selectionLine.evaluate(el => getComputedStyle(el).height)),
29
+ ).toBeCloseTo(cellBounding.height, -1);
30
+
31
+ await page.locator('#editor1 .ql-editor .ql-table').click({ button: 'right' });
32
+ await page.locator('.table-up-menu.is-contextmenu .table-up-menu__item').filter({ hasText: 'Merge Cell' }).first().click();
33
+
34
+ await page.locator('#editor1 .ql-editor .ql-table td').nth(3).click();
35
+ await page.locator('#editor1 .ql-editor .ql-table td').nth(3).click();
36
+ await expect(selectionLine).toBeVisible();
37
+ await page.mouse.down();
38
+ await page.mouse.move(cellBounding.x + 10, cellBounding.y + 10);
39
+ await page.mouse.up();
40
+
41
+ const mergeCellBounding = (await page.locator('#editor1 .ql-editor .ql-table td').nth(0).boundingBox())!;
42
+ expect(mergeCellBounding).not.toBeNull();
43
+ expect(
44
+ Number.parseFloat(await selectionLine.evaluate(el => getComputedStyle(el).width)),
45
+ ).toBeCloseTo(mergeCellBounding.width, -1);
46
+ expect(
47
+ Number.parseFloat(await selectionLine.evaluate(el => getComputedStyle(el).height)),
48
+ ).toBeCloseTo(mergeCellBounding.height + cellBounding.height, -1);
49
+ });
50
+
51
+ test('test TableSelection vertical', async ({ page }) => {
52
+ await createTableBySelect(page, 'container1', 5, 5);
53
+ const cell = page.locator('#editor1 .ql-editor .ql-table td').nth(0);
54
+ const cellBounding = (await cell.boundingBox())!;
55
+ expect(cellBounding).not.toBeNull();
56
+ await cell.click();
57
+ await cell.click();
58
+ const selectionLine = page.locator('#editor1 .table-up-selection__line');
59
+ await expect(selectionLine).toBeVisible();
60
+
61
+ await page.locator('#editor1 .ql-editor .ql-table td').nth(0).click();
62
+ await page.locator('#editor1 .ql-editor .ql-table td').nth(0).click();
63
+ await expect(selectionLine).toBeVisible();
64
+ await page.mouse.down();
65
+ await page.mouse.move(cellBounding.x, cellBounding.y + cellBounding.height * 3);
66
+ await page.mouse.up();
67
+ await page.locator('#editor1 .ql-editor .ql-table').click({ button: 'right' });
68
+ await page.locator('.table-up-menu.is-contextmenu .table-up-menu__item').filter({ hasText: 'Merge Cell' }).first().click();
69
+
70
+ 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();
73
+ await page.mouse.down();
74
+ await page.mouse.move(cellBounding.x + cellBounding.width * 2 - 10, cellBounding.y + 10);
75
+ await page.mouse.up();
76
+
77
+ expect(
78
+ Number.parseFloat(await selectionLine.evaluate(el => getComputedStyle(el).width)),
79
+ ).toBeCloseTo(cellBounding.width * 2, -1);
80
+ expect(
81
+ Number.parseFloat(await selectionLine.evaluate(el => getComputedStyle(el).height)),
82
+ ).toBeCloseTo(cellBounding.height * 3, -1);
83
+ });
@@ -0,0 +1,6 @@
1
+ import type { Page } from '@playwright/test';
2
+
3
+ export const createTableBySelect = async (page: Page, container: string, row: number, col: number) => {
4
+ await page.locator(`#${container} .ql-toolbar .ql-table-up.ql-picker`).click();
5
+ await page.locator(`#${container} .ql-toolbar .ql-custom-select .table-up-select-box__item[data-row="${row}"][data-col="${col}"]`).click();
6
+ };