quill-table-up 3.3.1 → 3.4.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.
@@ -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);cursor:pointer}.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{--check-color:#212121;--checked-color:#506eec;display:flex;align-items:center;margin-top:.25rem;cursor:pointer;font-size:.75rem;-webkit-user-select:none;-moz-user-select:none;user-select:none}.table-up-creator__checkbox input{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:1.125rem;height:1.125rem;border:.0625rem solid var(--check-color);border-radius:.3125rem;background-color:transparent;display:inline-block;position:relative;margin-right:.625rem;cursor:pointer}.table-up-creator__checkbox input:before{content:'';background-color:var(--checked-color);display:block;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%) scale(0);width:.625rem;height:.625rem;border-radius:.1875rem;transition:all .2s ease-in-out}.table-up-creator__checkbox input:checked:before{transform:translate(-50%,-50%) scale(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;display:block}.table-up-select-box__block{display:inline-flex;width:10rem;flex-wrap:wrap;align-items:center;justify-content:center}.table-up-select-box__item{display:inline-block;margin:.125rem;height:1rem;width:1rem;border:var(--select-box-border);cursor:pointer}.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{display:block;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{--check-color:#212121;--checked-color:#506eec;display:flex;align-items:center;margin-top:.25rem;cursor:pointer;font-size:.75rem;-webkit-user-select:none;-moz-user-select:none;user-select:none}.table-up-creator__checkbox input{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:1.125rem;height:1.125rem;border:.0625rem solid var(--check-color);border-radius:.3125rem;background-color:transparent;display:inline-block;position:relative;margin-right:.625rem;cursor:pointer}.table-up-creator__checkbox input:before{content:'';background-color:var(--checked-color);display:block;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%) scale(0);width:.625rem;height:.625rem;border-radius:.1875rem;transition:all .2s ease-in-out}.table-up-creator__checkbox input:checked:before{transform:translate(-50%,-50%) scale(1)}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "quill-table-up",
3
3
  "type": "module",
4
- "version": "3.3.1",
4
+ "version": "3.4.0",
5
5
  "packageManager": "pnpm@10.28.2",
6
6
  "description": "A table module for quill2.x",
7
7
  "author": "zzxming",
@@ -0,0 +1,50 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { TableUp } from '../../table-up';
3
+ import { createQuillWithTableModule } from './utils';
4
+
5
+ beforeEach(() => {
6
+ vi.useFakeTimers();
7
+ });
8
+ afterEach(() => {
9
+ vi.useRealTimers();
10
+ });
11
+
12
+ describe('TableUp - refreshUI', () => {
13
+ it('should call texts function with key and use returned text', async () => {
14
+ let locale = 'en';
15
+ const keyCalls: string[] = [];
16
+ const quill = createQuillWithTableModule('<p><br></p>', {
17
+ texts: (key) => {
18
+ keyCalls.push(key);
19
+ if (key === 'customBtnText') return locale === 'en' ? 'Custom' : '自定义';
20
+ if (key === 'fullCheckboxText') return locale === 'en' ? 'Insert full width table' : '插入满宽表格';
21
+ return '';
22
+ },
23
+ });
24
+
25
+ const tableModule = quill.getModule(TableUp.moduleName) as TableUp;
26
+ expect(tableModule.options.texts.customBtnText).toBe('Custom');
27
+ expect(tableModule.options.texts.fullCheckboxText).toBe('Insert full width table');
28
+ expect(keyCalls).toContain('customBtnText');
29
+ expect(keyCalls).toContain('fullCheckboxText');
30
+ locale = 'zh';
31
+ await tableModule.refreshUI();
32
+ expect(tableModule.options.texts.customBtnText).toBe('自定义');
33
+ expect(tableModule.options.texts.fullCheckboxText).toBe('插入满宽表格');
34
+ });
35
+
36
+ it('should bind this to TableUp instance when calling texts function', () => {
37
+ let boundThis: TableUp | undefined;
38
+ const quill = createQuillWithTableModule('<p><br></p>', {
39
+ texts(key) {
40
+ boundThis = this;
41
+ if (key === 'customBtnText') return 'Custom';
42
+ return '';
43
+ },
44
+ });
45
+
46
+ const tableModule = quill.getModule(TableUp.moduleName) as TableUp;
47
+ expect(tableModule.options.texts.customBtnText).toBe('Custom');
48
+ expect(boundThis).toBe(tableModule);
49
+ });
50
+ });
@@ -1,5 +1,5 @@
1
1
  import type { Op, Delta as TypeDelta, Range as TypeRange } from 'quill';
2
- import type { TableCaptionValue, TableColValue, TableUpOptions } from '../../utils';
2
+ import type { TableCaptionValue, TableColValue, TableUpOptionsInput } from '../../utils';
3
3
  import Quill from 'quill';
4
4
  import { expect, vi } from 'vitest';
5
5
  import { TableUp } from '../../table-up';
@@ -41,7 +41,7 @@ export function sortAttributes(element: HTMLElement) {
41
41
  }
42
42
  });
43
43
  }
44
- export function createQuillWithTableModule(html: string, tableOptions: Partial<TableUpOptions> = {}, moduleOptions = {}, quillOptions = {}, register = {}) {
44
+ export function createQuillWithTableModule(html: string, tableOptions: TableUpOptionsInput = {}, moduleOptions = {}, quillOptions = {}, register = {}) {
45
45
  Quill.register({
46
46
  [`modules/${TableUp.moduleName}`]: TableUp,
47
47
  ...register,
@@ -1 +1 @@
1
- {"version":"4.0.18","results":[]}
1
+ {"version":"4.0.18","results":[[":__tests__/unit/utils.test-d.ts",{"duration":0,"failed":false}],[":__tests__/unit/table-insert.test.ts",{"duration":18173.0784,"failed":false}],[":__tests__/unit/table-clipboard.test.ts",{"duration":22002.459899999998,"failed":false}],[":__tests__/unit/table-blots.test.ts",{"duration":10285.912399999997,"failed":false}],[":__tests__/unit/table-cell-merge.test.ts",{"duration":12967.189000000002,"failed":false}],[":__tests__/unit/utils.test.ts",{"duration":3874.055199999999,"failed":false}],[":__tests__/unit/table-hack.test.ts",{"duration":9750.4833,"failed":false}],[":__tests__/unit/table-redo-undo.test.ts",{"duration":32718.328999999998,"failed":false}],[":__tests__/unit/table-caption.test.ts",{"duration":3572.148699999998,"failed":false}],[":__tests__/unit/table-remove.test.ts",{"duration":6382.709699999998,"failed":false}],[":__tests__/unit/table-contenteditable.test.ts",{"duration":1995.755299999999,"failed":false}]]}
@@ -20,14 +20,17 @@
20
20
  .setCssVar(select-box-custom-color-bg, transparent);
21
21
  .setCssVar(select-box-custom-color-bg-hover, rgb(44, 44, 44));
22
22
 
23
+ display: block;
24
+
23
25
  &__block {
24
- display: flex;
26
+ display: inline-flex;
25
27
  width: 160px;
26
28
  flex-wrap: wrap;
27
29
  align-items: center;
28
30
  justify-content: center;
29
31
  }
30
32
  &__item {
33
+ display: inline-block;
31
34
  margin: 2px;
32
35
  height: 16px;
33
36
  width: 16px;
@@ -39,6 +42,7 @@
39
42
  }
40
43
  }
41
44
  &__custom {
45
+ display: block;
42
46
  padding: 8px;
43
47
  color: .getCssVar(select-box-custom-color-text) [];
44
48
  background-color: .getCssVar(select-box-custom-color-bg) [];
package/src/table-up.ts CHANGED
@@ -5,7 +5,7 @@ import type { Context } from 'quill/modules/keyboard';
5
5
  import type TypeKeyboard from 'quill/modules/keyboard';
6
6
  import type TypeToolbar from 'quill/modules/toolbar';
7
7
  import type { TableSelection } from './modules';
8
- import type { Constructor, QuillTheme, QuillThemePicker, TableBodyTag, TableCellValue, TableConstantsData, TableTextOptions, TableUpOptions } from './utils';
8
+ import type { Constructor, QuillTheme, QuillThemePicker, TableBodyTag, TableCellValue, TableConstantsData, TableTextOptions, TableTextOptionsInput, TableUpOptions, TableUpOptionsInput } from './utils';
9
9
  import Quill from 'quill';
10
10
  import { BlockEmbedOverride, BlockOverride, ContainerFormat, ScrollOverride, TableBodyFormat, TableCaptionFormat, TableCellFormat, TableCellInnerFormat, TableColFormat, TableColgroupFormat, TableFootFormat, TableHeadFormat, TableMainFormat, TableRowFormat, TableWrapperFormat } from './formats';
11
11
  import { TableClipboard } from './modules';
@@ -277,6 +277,7 @@ export class TableUp {
277
277
 
278
278
  quill: Quill;
279
279
  options: TableUpOptions;
280
+ textOptionsInput: TableTextOptionsInput | undefined;
280
281
  toolBox: HTMLDivElement;
281
282
  fixTableByLisenter = debounce(this.balanceTables, 100);
282
283
  selector?: HTMLElement;
@@ -288,33 +289,28 @@ export class TableUp {
288
289
  return this.constructor;
289
290
  }
290
291
 
291
- constructor(quill: Quill, options: Partial<TableUpOptions>) {
292
+ constructor(quill: Quill, options: TableUpOptionsInput) {
292
293
  this.quill = quill;
294
+ this.textOptionsInput = options?.texts;
293
295
  this.options = this.resolveOptions(options || {});
294
296
  this.toolBox = this.initialContainer();
295
297
 
296
- const toolbar = this.quill.getModule('toolbar') as TypeToolbar;
297
- if (toolbar && (this.quill.theme as QuillTheme).pickers) {
298
- const [, select] = (toolbar.controls as [string, HTMLElement][] || []).find(([name]) => name === this.statics.toolName) || [];
299
- if (select?.tagName.toLocaleLowerCase() === 'select') {
300
- const picker = (this.quill.theme as QuillTheme).pickers.find(picker => picker.select === select);
301
- if (picker) {
302
- picker.label.innerHTML = this.options.icon;
303
- this.buildCustomSelect(this.options.customSelect, picker);
304
- picker.label.addEventListener('mousedown', () => {
305
- if (!this.selector || !picker) return;
306
- const selectRect = this.selector.getBoundingClientRect();
307
- const { leftLimited } = limitDomInViewPort(selectRect);
308
- if (leftLimited) {
309
- const labelRect = picker.label.getBoundingClientRect();
310
- Object.assign(picker.options.style, { transform: `translateX(calc(-100% + ${labelRect.width}px))` });
311
- }
312
- else {
313
- Object.assign(picker.options.style, { transform: undefined });
314
- }
315
- });
298
+ const picker = this.getToolbarPicker();
299
+ if (picker) {
300
+ picker.label.innerHTML = this.options.icon;
301
+ this.buildCustomSelect(this.options.customSelect, picker);
302
+ picker.label.addEventListener('mousedown', () => {
303
+ if (!this.selector) return;
304
+ const selectRect = this.selector.getBoundingClientRect();
305
+ const { leftLimited } = limitDomInViewPort(selectRect);
306
+ if (leftLimited) {
307
+ const labelRect = picker.label.getBoundingClientRect();
308
+ Object.assign(picker.options.style, { transform: `translateX(calc(-100% + ${labelRect.width}px))` });
316
309
  }
317
- }
310
+ else {
311
+ Object.assign(picker.options.style, { transform: undefined });
312
+ }
313
+ });
318
314
  }
319
315
 
320
316
  const keyboard = this.quill.getModule('keyboard') as TypeKeyboard;
@@ -367,20 +363,29 @@ export class TableUp {
367
363
  }
368
364
  }
369
365
 
370
- resolveOptions(options: Partial<TableUpOptions>): TableUpOptions {
366
+ getToolbarPicker() {
367
+ const toolbar = this.quill.getModule('toolbar') as TypeToolbar;
368
+ if (!toolbar || !(this.quill.theme as QuillTheme).pickers) return;
369
+ const [, select] = (toolbar.controls as [string, HTMLElement][] || []).find(([name]) => name === this.statics.toolName) || [];
370
+ if (select?.tagName.toLocaleLowerCase() !== 'select') return;
371
+ return (this.quill.theme as QuillTheme).pickers.find(picker => picker.select === select);
372
+ }
373
+
374
+ resolveOptions(options: TableUpOptionsInput): TableUpOptions {
375
+ const { texts, ...rest } = options;
371
376
  return Object.assign({
372
377
  customBtn: false,
373
- texts: this.resolveTexts(options.texts || {}),
378
+ texts: this.resolveTexts(texts),
374
379
  full: false,
375
380
  fullSwitch: true,
376
381
  icon: icons.table,
377
382
  autoMergeCell: true,
378
383
  modules: [],
379
- } as TableUpOptions, options);
384
+ } as TableUpOptions, rest);
380
385
  }
381
386
 
382
- resolveTexts(options: Partial<TableTextOptions>) {
383
- return Object.assign({
387
+ resolveTexts(options?: TableTextOptionsInput) {
388
+ const defaults: TableTextOptions = {
384
389
  fullCheckboxText: 'Insert full width table',
385
390
  customBtnText: 'Custom',
386
391
  confirmText: 'Confirm',
@@ -405,7 +410,35 @@ export class TableUp {
405
410
  DeleteTable: 'Delete table',
406
411
  BackgroundColor: 'Set background color',
407
412
  BorderColor: 'Set border color',
408
- }, options);
413
+ };
414
+ if (isFunction(options)) {
415
+ const textGetter = options;
416
+ const tableModule = this;
417
+ return new Proxy(defaults, {
418
+ get(target, key: string | symbol) {
419
+ if (typeof key !== 'string') return Reflect.get(target, key);
420
+ const value = textGetter.call(tableModule, key);
421
+ return isString(value) ? value : (target as Record<string, string>)[key];
422
+ },
423
+ });
424
+ }
425
+ return Object.assign(defaults, options);
426
+ }
427
+
428
+ async refreshUI() {
429
+ this.options.texts = this.resolveTexts(this.textOptionsInput);
430
+
431
+ const picker = this.getToolbarPicker();
432
+ if (picker) {
433
+ picker.label.innerHTML = this.options.icon;
434
+ await this.buildCustomSelect(this.options.customSelect, picker);
435
+ }
436
+
437
+ for (const module of Object.values(this.modules)) {
438
+ if (module && typeof (module as any).hide === 'function') {
439
+ (module as any).hide();
440
+ }
441
+ }
409
442
  }
410
443
 
411
444
  initModules() {
@@ -655,7 +688,7 @@ export class TableUp {
655
688
 
656
689
  async buildCustomSelect(customSelect: ((module: TableUp, picker: QuillThemePicker) => HTMLElement | Promise<HTMLElement>) | undefined, picker: QuillThemePicker) {
657
690
  if (!customSelect || !isFunction(customSelect)) return;
658
- const dom = document.createElement('div');
691
+ const dom = document.createElement('span');
659
692
  dom.classList.add('ql-custom-select');
660
693
  this.selector = await customSelect(this, picker);
661
694
  dom.appendChild(this.selector);
@@ -11,14 +11,14 @@ interface TableSelectOptions {
11
11
  }
12
12
  export function createSelectBox(options: Partial<TableSelectOptions> = {}) {
13
13
  const bem = createBEM('select-box');
14
- const selectDom = document.createElement('div');
14
+ const selectDom = document.createElement('span');
15
15
  selectDom.classList.add(bem.b());
16
16
 
17
- const selectBlock = document.createElement('div');
17
+ const selectBlock = document.createElement('span');
18
18
  selectBlock.classList.add(bem.be('block'));
19
19
  for (let r = 0; r < (options.row || 8); r++) {
20
20
  for (let c = 0; c < (options.col || 8); c++) {
21
- const selectItem = document.createElement('div');
21
+ const selectItem = document.createElement('span');
22
22
  selectItem.classList.add(bem.be('item'));
23
23
  selectItem.dataset.row = String(r + 1);
24
24
  selectItem.dataset.col = String(c + 1);
@@ -62,7 +62,7 @@ export function createSelectBox(options: Partial<TableSelectOptions> = {}) {
62
62
 
63
63
  if (options.customBtn) {
64
64
  const texts = options.texts || {};
65
- const selectCustom = document.createElement('div');
65
+ const selectCustom = document.createElement('span');
66
66
  selectCustom.classList.add(bem.be('custom'));
67
67
  selectCustom.textContent = texts.customBtnText || 'Custom';
68
68
  selectCustom.addEventListener('click', async () => {
@@ -57,6 +57,7 @@ export interface TableTextOptions extends TableCreatorTextOptions, TableMenuText
57
57
  transparent: string;
58
58
  perWidthInsufficient: string;
59
59
  }
60
+ export type TableTextOptionsInput = Partial<TableTextOptions> | ((this: TableUp, key: string) => string);
60
61
  export interface TableUpExtraModule extends Constructor<any, [TableUp, Quill, any]> {
61
62
  moduleName: string;
62
63
  }
@@ -74,6 +75,9 @@ export interface TableUpOptions {
74
75
  autoMergeCell: boolean;
75
76
  modules: TableUpModule[];
76
77
  }
78
+ export interface TableUpOptionsInput extends Partial<Omit<TableUpOptions, 'texts'>> {
79
+ texts?: TableTextOptionsInput;
80
+ }
77
81
  export interface TableColValue {
78
82
  tableId: string;
79
83
  colId: string;