]*>(.*?)<\/temporary>/gi, "")
+ .replace(/]*>(.*?)<\/td>/gi, ($1: string) => {
+ return getCopyTd($1);
+ });
+ }
+
+ getCorrectRow(prev: TableRow, maxColumns: number) {
+ let isCorrect = false;
+ while (prev && !isCorrect) {
+ const prevMaxColumns = this.getMaxColumns(prev.children);
+ if (maxColumns === prevMaxColumns) {
+ isCorrect = true;
+ return prev;
+ }
+ prev = prev.prev;
+ }
+ return prev;
+ }
+
+ getInsertRow(prev: TableRow, ref: TableRow | null, offset: number) {
+ const body = this.tbody();
+ if (body == null || body.children.head == null) return;
+ const id = tableId();
+ const row = this.scroll.create(TableRow.blotName) as TableRow;
+ const maxColumns = this.getMaxColumns(body.children.head.children);
+ const nextMaxColumns = this.getMaxColumns(prev.children);
+ if (nextMaxColumns === maxColumns) {
+ prev.children.forEach((child: TableCell) => {
+ const formats = { height: "24", "data-row": id };
+ const colspan = ~~child.domNode.getAttribute("colspan") || 1;
+ this.insertTableCell(colspan, formats, row);
+ });
+ return row;
+ } else {
+ const correctRow = this.getCorrectRow(prev.prev, maxColumns);
+ correctRow.children.forEach((child: TableCell) => {
+ const formats = { height: "24", "data-row": id };
+ const colspan = ~~child.domNode.getAttribute("colspan") || 1;
+ const rowspan = ~~child.domNode.getAttribute("rowspan") || 1;
+ if (rowspan > 1) {
+ if (offset > 0 && !ref) {
+ this.insertTableCell(colspan, formats, row);
+ } else {
+ const [formats] = getCellFormats(child);
+ child.replaceWith(child.statics.blotName, {
+ ...formats,
+ rowspan: rowspan + 1
+ });
+ }
+ } else {
+ this.insertTableCell(colspan, formats, row);
+ }
+ });
+ return row;
+ }
+ }
+
+ getMaxColumns(children: LinkedList) {
+ return children.reduce((num: number, child: TableCell) => {
+ const colspan = ~~child.domNode.getAttribute("colspan") || 1;
+ return (num += colspan);
+ }, 0);
+ }
+
+ insertColumn(position: number, isLast: boolean, w: number, offset: number) {
+ const colgroup = this.colgroup() as TableColgroup;
+ const body = this.tbody() as TableBody;
+ if (body == null || body.children.head == null) return;
+ const columnCells: [TableRow, string, TableCell | null, null][] = [];
+ const cols: [TableColgroup, TableCol | null][] = [];
+ let row = body.children.head;
+ while (row) {
+ if (isLast && offset > 0) {
+ const id = row.children.tail.domNode.getAttribute("data-row");
+ columnCells.push([row, id, null, null]);
+ } else {
+ this.setColumnCells(row, columnCells, { position, width: w });
+ }
+ row = row.next;
+ }
+ if (colgroup) {
+ if (isLast) {
+ cols.push([colgroup, null]);
+ } else {
+ let correctLeft = 0;
+ let correctRight = 0;
+ let col = colgroup.children.head;
+ while (col) {
+ const { left, width } = col.domNode.getBoundingClientRect();
+ correctLeft = correctLeft ? correctLeft : left;
+ correctRight = correctLeft + width;
+ if (Math.abs(correctLeft - position) <= DEVIATION) {
+ cols.push([colgroup, col]);
+ break;
+ } else if (Math.abs(correctRight - position) <= DEVIATION && !col.next) {
+ cols.push([colgroup, null]);
+ break;
+ }
+ correctLeft += width;
+ col = col.next;
+ }
+ }
+ }
+ for (const [row, id, ref] of columnCells) {
+ if (!row) {
+ this.setCellColspan(ref, 1);
+ } else {
+ this.insertColumnCell(row, id, ref);
+ }
+ }
+ for (const [colgroup, ref] of cols) {
+ this.insertCol(colgroup, ref);
+ }
+ }
+
+ insertCol(colgroup: TableColgroup, ref: TableCol | null) {
+ const col = this.scroll.create(TableCol.blotName, { width: `${CELL_DEFAULT_WIDTH}` });
+ colgroup.insertBefore(col, ref);
+ }
+
+ insertColumnCell(row: TableRow | null, id: string, ref: TableCell | null) {
+ const colgroup = this.colgroup();
+ const formats = colgroup ? { "data-row": id } : { "data-row": id, width: `${CELL_DEFAULT_WIDTH}` };
+ const cell = this.scroll.create(TableCell.blotName, formats) as TableCell;
+ const cellBlock = this.scroll.create(TableCellBlock.blotName, cellId()) as TableCellBlock;
+ cell.appendChild(cellBlock);
+ if (!row) {
+ const tbody = this.tbody();
+ row = this.scroll.create(TableRow.blotName) as TableRow;
+ tbody.insertBefore(row, null);
+ }
+ row.insertBefore(cell, ref);
+ cellBlock.optimize();
+ return cell;
+ }
+
+ insertRow(index: number, offset: number) {
+ const body = this.tbody() as TableBody;
+ if (body == null || body.children.head == null) return;
+ const ref = body.children.at(index);
+ const prev = ref ? ref : body.children.at(index - 1);
+ const correctRow = this.getInsertRow(prev, ref, offset);
+ body.insertBefore(correctRow, ref);
+ }
+
+ insertTableCell(colspan: number, formats: Props, row: TableRow) {
+ if (colspan > 1) {
+ Object.assign(formats, { colspan });
+ } else {
+ delete formats["colspan"];
+ }
+ const cell = this.scroll.create(TableCell.blotName, formats) as TableCell;
+ const cellBlock = this.scroll.create(TableCellBlock.blotName, cellId()) as TableCellBlock;
+ cell.appendChild(cellBlock);
+ row.appendChild(cell);
+ cellBlock.optimize();
+ }
+
+ optimize(context: unknown) {
+ super.optimize(context);
+ const temporaries = this.descendants(TableTemporary);
+ this.setClassName(temporaries);
+ if (temporaries.length > 1) {
+ temporaries.shift();
+ for (const temporary of temporaries) {
+ temporary.remove();
+ }
+ }
+ }
+
+ setCellColspan(cell: TableCell, offset: number) {
+ const blotName = cell.statics.blotName;
+ const formats = cell.formats()[blotName];
+ const colspan = (~~formats["colspan"] || 1) + offset;
+ if (colspan > 1) {
+ Object.assign(formats, { colspan });
+ } else {
+ delete formats["colspan"];
+ }
+ cell.replaceWith(blotName, formats);
+ }
+
+ setCellRowspan(parentElement: Element) {
+ while (parentElement) {
+ const children = parentElement.querySelectorAll("td[rowspan]");
+ if (children.length) {
+ for (const child of children) {
+ const cell = Quill.find(child) as TableCell;
+ const blotName = cell.statics.blotName;
+ const formats = cell.formats()[blotName];
+ const rowspan = (~~formats["rowspan"] || 1) - 1;
+ const childBlot = getCellChildBlot(cell);
+ if (rowspan > 1) {
+ Object.assign(formats, { rowspan });
+ } else {
+ delete formats["rowspan"];
+ }
+ childBlot.format(blotName, formats);
+ }
+ break;
+ }
+ parentElement = parentElement.previousElementSibling;
+ }
+ }
+
+ private setClassName(temporaries: TableTemporary[]) {
+ const defaultClassName = this.statics.defaultClassName;
+ const _temporary = temporaries[0];
+ const _className = this.domNode.getAttribute("class");
+ const getClassName = (className: string) => {
+ const classNames = (className || "").split(/\s+/);
+ if (!classNames.find(className => className === defaultClassName)) {
+ classNames.unshift(defaultClassName);
+ }
+ return classNames.join(" ").trim();
+ };
+ const setClass = (temporary: TableTemporary, _className: string) => {
+ const className = temporary.domNode.getAttribute("data-class");
+ if (className !== _className && _className != null) {
+ temporary.domNode.setAttribute("data-class", getClassName(_className));
+ }
+ if (!_className && !className) {
+ temporary.domNode.setAttribute("data-class", defaultClassName);
+ }
+ };
+ if (!_temporary) {
+ const container = this.prev;
+ if (!container) return;
+ // @ts-expect-error
+ const [cell] = container.descendant(TableCell);
+ // @ts-expect-error
+ const [temporary] = container.descendant(TableTemporary);
+ if (!cell && temporary) {
+ setClass(temporary, _className);
+ }
+ } else {
+ setClass(_temporary, _className);
+ }
+ }
+
+ private setColumnCells(
+ row: TableRow,
+ columnCells: [TableRow, Props | string, TableCell, TableCell][],
+ bounds: { position: number; width: number },
+ formats?: Props,
+ rowspan?: number,
+ prev?: TableCell
+ ) {
+ if (!row) return;
+ const { position, width } = bounds;
+ let ref = row.children.head;
+ while (ref) {
+ const { left, right } = ref.domNode.getBoundingClientRect();
+ const id: string = ref.domNode.getAttribute("data-row");
+ if (typeof formats === "object") {
+ Object.assign(formats, { rowspan, "data-row": id });
+ }
+ const props = formats || id;
+ if (Math.abs(left - position) <= DEVIATION) {
+ columnCells.push([row, props, ref, prev]);
+ break;
+ } else if (Math.abs(right - position) <= DEVIATION && !ref.next) {
+ columnCells.push([row, props, null, prev]);
+ break;
+ // rowspan > 1 (insertLeft, position + w is left)
+ } else if (Math.abs(left - position - width) <= DEVIATION) {
+ columnCells.push([row, props, ref, prev]);
+ break;
+ // rowspan > 1 (position between left and right, rowspan++)
+ } else if (position > left && position < right) {
+ columnCells.push([null, props, ref, prev]);
+ break;
+ }
+ ref = ref.next;
+ }
+ }
+
+ tbody() {
+ // @ts-expect-error
+ const [body] = this.descendant(TableBody);
+ return body || (this.findChild("table-body") as TableBody);
+ }
+
+ temporary() {
+ // @ts-expect-error
+ const [temporary] = this.descendant(TableTemporary);
+ return temporary;
+ }
+}
+
+TableContainer.allowedChildren = [TableBody, TableTemporary, TableColgroup];
+TableBody.requiredContainer = TableContainer;
+TableTemporary.requiredContainer = TableContainer;
+TableColgroup.requiredContainer = TableContainer;
+
+TableBody.allowedChildren = [TableRow];
+TableRow.requiredContainer = TableBody;
+
+TableColgroup.allowedChildren = [TableCol];
+TableCol.requiredContainer = TableColgroup;
+
+TableRow.allowedChildren = [TableCell];
+TableCell.requiredContainer = TableRow;
+
+TableCell.allowedChildren = [TableCellBlock, TableHeader, ListContainer];
+TableCellBlock.requiredContainer = TableCell;
+TableHeader.requiredContainer = TableCell;
+ListContainer.requiredContainer = TableCell;
+
+function cellId() {
+ const id = Math.random().toString(36).slice(2, 6);
+ return `cell-${id}`;
+}
+
+function tableId() {
+ const id = Math.random().toString(36).slice(2, 6);
+ return `row-${id}`;
+}
+
+export {
+ cellId,
+ TableBody,
+ TableCell,
+ TableCellBlock,
+ TableCol,
+ TableColgroup,
+ TableContainer,
+ tableId,
+ TableRow,
+ TableTemporary
+};
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/de_DE.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/de_DE.ts
new file mode 100644
index 0000000000..ca169b7921
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/de_DE.ts
@@ -0,0 +1,59 @@
+export default {
+ col: "Spalte",
+ insColL: "Spalte links einfügen",
+ insColR: "Spalte rechts einfügen",
+ delCol: "Spalte löschen",
+ row: "Zeile",
+ insRowAbv: "Zeile oberhalb einfügen",
+ insRowBlw: "Zeile unterhalb einfügen",
+ delRow: "Zeile löschen",
+ mCells: "Zellen verbinden",
+ sCell: "Zelle teilen",
+ tblProps: "Tabelleneingenschaften",
+ cellProps: "Zelleneigenschaften",
+ insParaOTbl: "Absatz außerhalb der Tabelle einfügen",
+ insB4: "Davor einfügen",
+ insAft: "Danach einfügen",
+ copyTable: "Tabelle kopieren",
+ delTable: "Tabelle löschen",
+ border: "Rahmen",
+ color: "Farbe",
+ width: "Breite",
+ background: "Schattierung",
+ dims: "Maße",
+ height: "Höhe",
+ padding: "Abstand",
+ tblCellTxtAlm: "Ausrichtung",
+ alCellTxtL: "Zellentext links ausrichten",
+ alCellTxtC: "Zellentext mittig ausrichten",
+ alCellTxtR: "Zellentext rechts ausrichten",
+ jusfCellTxt: "Zellentext Blocksatz",
+ alCellTxtT: "Zellentext oben ausrichten",
+ alCellTxtM: "Zellentext mittig ausrichten",
+ alCellTxtB: "Zellentext unten ausrichten",
+ dimsAlm: "Maße und Ausrichtung",
+ alTblL: "Tabelle links ausrichten",
+ tblC: "Tabelle mittig ausrichten",
+ alTblR: "Tabelle rechts ausrichten",
+ save: "Speichern",
+ cancel: "Abbrechen",
+ colorMsg: 'Die Farbe ist ungültig. Probiere "#FF0000", "rgb(255,0,0)" oder "red".',
+ dimsMsg: 'Der Wert ist ungültig. Probiere "10px", "2em" oder einfach "2".',
+ colorPicker: "Farbwähler",
+ removeColor: "Farbe entfernen",
+ black: "Schwarz",
+ dimGrey: "Dunkelgrau",
+ grey: "Grau",
+ lightGrey: "Hellgrau",
+ white: "Weiß",
+ red: "Rot",
+ orange: "Orange",
+ yellow: "Gelb",
+ lightGreen: "Hellgrün",
+ green: "Grün",
+ aquamarine: "Aquamarin",
+ turquoise: "Türkis",
+ lightBlue: "Hellblau",
+ blue: "Blau",
+ purple: "Lila"
+};
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/en_US.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/en_US.ts
new file mode 100644
index 0000000000..0f49a663dd
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/en_US.ts
@@ -0,0 +1,59 @@
+export default {
+ col: "Column",
+ insColL: "Insert column left",
+ insColR: "Insert column right",
+ delCol: "Delete column",
+ row: "Row",
+ insRowAbv: "Insert row above",
+ insRowBlw: "Insert row below",
+ delRow: "Delete row",
+ mCells: "Merge cells",
+ sCell: "Split cell",
+ tblProps: "Table properties",
+ cellProps: "Cell properties",
+ insParaOTbl: "Insert paragraph outside the table",
+ insB4: "Insert before",
+ insAft: "Insert after",
+ copyTable: "Copy table",
+ delTable: "Delete table",
+ border: "Border",
+ color: "Color",
+ width: "Width",
+ background: "Background",
+ dims: "Dimensions",
+ height: "Height",
+ padding: "Padding",
+ tblCellTxtAlm: "Table cell text alignment",
+ alCellTxtL: "Align cell text to the left",
+ alCellTxtC: "Align cell text to the center",
+ alCellTxtR: "Align cell text to the right",
+ jusfCellTxt: "Justify cell text",
+ alCellTxtT: "Align cell text to the top",
+ alCellTxtM: "Align cell text to the middle",
+ alCellTxtB: "Align cell text to the bottom",
+ dimsAlm: "Dimensions and alignment",
+ alTblL: "Align table to the left",
+ tblC: "Center table",
+ alTblR: "Align table to the right",
+ save: "Save",
+ cancel: "Cancel",
+ colorMsg: 'The color is invalid. Try "#FF0000" or "rgb(255,0,0)" or "red".',
+ dimsMsg: 'The value is invalid. Try "10px" or "2em" or simply "2".',
+ colorPicker: "Color picker",
+ removeColor: "Remove color",
+ black: "Black",
+ dimGrey: "Dim grey",
+ grey: "Grey",
+ lightGrey: "Light grey",
+ white: "White",
+ red: "Red",
+ orange: "Orange",
+ yellow: "Yellow",
+ lightGreen: "Light green",
+ green: "Green",
+ aquamarine: "Aquamarine",
+ turquoise: "Turquoise",
+ lightBlue: "Light blue",
+ blue: "Blue",
+ purple: "Purple"
+};
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/fr_FR.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/fr_FR.ts
new file mode 100644
index 0000000000..e021f72ce3
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/fr_FR.ts
@@ -0,0 +1,59 @@
+export default {
+ col: "Colonne",
+ insColL: "Insérer colonne à gauche",
+ insColR: "Insérer colonne à droite",
+ delCol: "Supprimer la colonne",
+ row: "Ligne",
+ insRowAbv: "Insérer ligne au-dessus",
+ insRowBlw: "Insérer ligne en dessous",
+ delRow: "Supprimer la ligne",
+ mCells: "Fusionner les cellules",
+ sCell: "Diviser la cellule",
+ tblProps: "Propriétés du tableau",
+ cellProps: "Propriétés de la cellule",
+ insParaOTbl: "Insérer paragraphe en dehors du tableau",
+ insB4: "Insérer avant",
+ insAft: "Insérer après",
+ copyTable: "Copier le tableau",
+ delTable: "Supprimer le tableau",
+ border: "Bordure",
+ color: "Couleur",
+ width: "Largeur",
+ background: "Arrière-plan",
+ dims: "Dimensions",
+ height: "Hauteur",
+ padding: "Marge intérieure",
+ tblCellTxtAlm: "Alignement du texte de la cellule du tableau",
+ alCellTxtL: "Aligner le texte de la cellule à gauche",
+ alCellTxtC: "Aligner le texte de la cellule au centre",
+ alCellTxtR: "Aligner le texte de la cellule à droite",
+ jusfCellTxt: "Justifier le texte de la cellule",
+ alCellTxtT: "Aligner le texte de la cellule en haut",
+ alCellTxtM: "Aligner le texte de la cellule au milieu",
+ alCellTxtB: "Aligner le texte de la cellule en bas",
+ dimsAlm: "Dimensions et alignement",
+ alTblL: "Aligner le tableau à gauche",
+ tblC: "Centrer le tableau",
+ alTblR: "Aligner le tableau à droite",
+ save: "Enregistrer",
+ cancel: "Annuler",
+ colorMsg: 'La couleur est invalide. Essayez "#FF0000" ou "rgb(255,0,0)" ou "rouge".',
+ dimsMsg: 'La valeur est invalide. Essayez "10px" ou "2em" ou simplement "2".',
+ colorPicker: "Sélecteur de couleur",
+ removeColor: "Supprimer la couleur",
+ black: "Noir",
+ dimGrey: "Gris foncé",
+ grey: "Gris",
+ lightGrey: "Gris clair",
+ white: "Blanc",
+ red: "Rouge",
+ orange: "Orange",
+ yellow: "Jaune",
+ lightGreen: "Vert clair",
+ green: "Vert",
+ aquamarine: "Aigue-marine",
+ turquoise: "Turquoise",
+ lightBlue: "Bleu clair",
+ blue: "Bleu",
+ purple: "Violet"
+};
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/index.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/index.ts
new file mode 100644
index 0000000000..9b0aa6b702
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/index.ts
@@ -0,0 +1,63 @@
+// @ts-nocheck
+import type { Props } from "../types";
+import de_DE from "./de_DE";
+import en_US from "./en_US";
+import fr_FR from "./fr_FR";
+import pl_PL from "./pl_PL";
+import ru_RU from "./ru_RU";
+import tr_TR from "./tr_TR";
+import zh_CN from "./zh_CN";
+
+interface Config {
+ [propName: string]: Props;
+}
+
+interface LanguageConfig {
+ name: string;
+ content: Props;
+}
+
+class Language {
+ config: Config;
+ language: string | LanguageConfig;
+ name: string;
+ constructor(language?: string | LanguageConfig) {
+ this.config = {
+ en_US,
+ zh_CN,
+ fr_FR,
+ pl_PL,
+ de_DE,
+ ru_RU,
+ tr_TR
+ };
+ this.init(language);
+ }
+
+ changeLanguage(name: string) {
+ this.name = name;
+ }
+
+ init(language: string | LanguageConfig) {
+ if (typeof language === "undefined" || typeof language === "string") {
+ this.changeLanguage(language || "en_US");
+ } else {
+ const { name, content } = language;
+ content && this.registry(name, content);
+ name && this.changeLanguage(name);
+ }
+ }
+
+ registry(name: string, content: Props) {
+ this.config = {
+ ...this.config,
+ [name]: content
+ };
+ }
+
+ useLanguage(name: string) {
+ return this.config[this.name][name];
+ }
+}
+
+export default Language;
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/pl_PL.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/pl_PL.ts
new file mode 100644
index 0000000000..599b15f630
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/pl_PL.ts
@@ -0,0 +1,59 @@
+export default {
+ col: "Kolumna",
+ insColL: "Wstaw kolumnę z lewej",
+ insColR: "Wstaw kolumnę z prawej",
+ delCol: "Usuń kolumnę",
+ row: "Wiersz",
+ insRowAbv: "Wstaw wiersz powyżej",
+ insRowBlw: "Wstaw wiersz poniżej",
+ delRow: "Usuń wiersz",
+ mCells: "Scal komórki",
+ sCell: "Podziel komórkę",
+ tblProps: "Właściwości tabeli",
+ cellProps: "Właściwości komórki",
+ insParaOTbl: "Wstaw akapit poza tabelą",
+ insB4: "Wstaw przed",
+ insAft: "Wstaw po",
+ copyTable: "Kopiuj tabelę",
+ delTable: "Usuń tabelę",
+ border: "Obramowanie",
+ color: "Kolor",
+ width: "Szerokość",
+ background: "Tło",
+ dims: "Wymiary",
+ height: "Wysokość",
+ padding: "Margines wewnętrzny",
+ tblCellTxtAlm: "Wyrównanie tekstu w komórce tabeli",
+ alCellTxtL: "Wyrównaj tekst w komórce do lewej",
+ alCellTxtC: "Wyrównaj tekst w komórce do środka",
+ alCellTxtR: "Wyrównaj tekst w komórce do prawej",
+ jusfCellTxt: "Wyjustuj tekst w komórce",
+ alCellTxtT: "Wyrównaj tekst w komórce do góry",
+ alCellTxtM: "Wyrównaj tekst w komórce do środka",
+ alCellTxtB: "Wyrównaj tekst w komórce do dołu",
+ dimsAlm: "Wymiary i wyrównanie",
+ alTblL: "Wyrównaj tabelę do lewej",
+ tblC: "Wyśrodkuj tabelę",
+ alTblR: "Wyrównaj tabelę do prawej",
+ save: "Zapisz",
+ cancel: "Anuluj",
+ colorMsg: 'Kolor jest nieprawidłowy. Spróbuj "#FF0000" lub "rgb(255,0,0)" lub "red".',
+ dimsMsg: 'Wartość jest nieprawidłowa. Spróbuj "10px" lub "2em" lub po prostu "2".',
+ colorPicker: "Wybór koloru",
+ removeColor: "Usuń kolor",
+ black: "Czarny",
+ dimGrey: "Przyciemniony szary",
+ grey: "Szary",
+ lightGrey: "Jasnoszary",
+ white: "Biały",
+ red: "Czerwony",
+ orange: "Pomarańczowy",
+ yellow: "Żółty",
+ lightGreen: "Jasnozielony",
+ green: "Zielony",
+ aquamarine: "Akwamaryna",
+ turquoise: "Turkusowy",
+ lightBlue: "Jasnoniebieski",
+ blue: "Niebieski",
+ purple: "Fioletowy"
+};
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/ru_RU.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/ru_RU.ts
new file mode 100644
index 0000000000..59c2308c4e
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/ru_RU.ts
@@ -0,0 +1,59 @@
+export default {
+ col: "Столбец",
+ insColL: "Вставить столбец слева",
+ insColR: "Вставить столбец справа",
+ delCol: "Удалить столбец",
+ row: "Строка",
+ insRowAbv: "Вставить строку сверху",
+ insRowBlw: "Вставить строку снизу",
+ delRow: "Удалить строку",
+ mCells: "Объединить ячейки",
+ sCell: "Разбить ячейку",
+ tblProps: "Свойства таблицы",
+ cellProps: "Свойства ячейки",
+ insParaOTbl: "Вставить абзац за пределами таблицы",
+ insB4: "Вставить абзац перед",
+ insAft: "Вставить абзац после",
+ copyTable: "Копировать таблицу",
+ delTable: "Удалить таблицу",
+ border: "Обводка",
+ color: "Цвет",
+ width: "Ширина",
+ background: "Фон",
+ dims: "Размеры",
+ height: "Высота",
+ padding: "Отступ",
+ tblCellTxtAlm: "Выравнивание текста в ячейке таблицы",
+ alCellTxtL: "Выровнять текст в ячейке по левому краю",
+ alCellTxtC: "Выровнять текст в ячейке по центру",
+ alCellTxtR: "Выровнять текст в ячейке по правому краю",
+ jusfCellTxt: "Выровнять текст в ячейке по ширине",
+ alCellTxtT: "Выровнять текст в ячейке по верху",
+ alCellTxtM: "Выровнять текст в ячейке по середине",
+ alCellTxtB: "Выровнять текст в ячейке по низу",
+ dimsAlm: "Размеры и выравнивание",
+ alTblL: "Выровнять таблицу по левому краю",
+ tblC: "Центрировать таблицу",
+ alTblR: "Выровнять таблицу по правому краю",
+ save: "Сохранить",
+ cancel: "Отменить",
+ colorMsg: 'Неверный цвет. Попробуйте "#FF0000", "rgb(255,0,0)" или "red".',
+ dimsMsg: 'Недопустимое значение. Попробуйте "10px", "2em" или просто "2".',
+ colorPicker: "Выбор цвета",
+ removeColor: "Удалить цвет",
+ black: "Черный",
+ dimGrey: "Темно-серый",
+ grey: "Серый",
+ lightGrey: "Светло-серый",
+ white: "Белый",
+ red: "Красный",
+ orange: "Оранжевый",
+ yellow: "Желтый",
+ lightGreen: "Светло-зеленый",
+ green: "Зеленый",
+ aquamarine: "Аквамарин",
+ turquoise: "Бирюзовый",
+ lightBlue: "Светло-голубой",
+ blue: "Синий",
+ purple: "Фиолетовый"
+};
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/tr_TR.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/tr_TR.ts
new file mode 100644
index 0000000000..71ede84bee
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/tr_TR.ts
@@ -0,0 +1,59 @@
+export default {
+ col: "Sütun",
+ insColL: "Sola sütun ekle",
+ insColR: "Sağa sütun ekle",
+ delCol: "Sütunu sil",
+ row: "Satır",
+ insRowAbv: "Üstüne satır ekle",
+ insRowBlw: "Altına satır ekle",
+ delRow: "Satırı sil",
+ mCells: "Hücreleri birleştir",
+ sCell: "Hücreyi böl",
+ tblProps: "Tablo özellikleri",
+ cellProps: "Hücre özellikleri",
+ insParaOTbl: "Tablo dışında paragraf ekle",
+ insB4: "Öncesine ekle",
+ insAft: "Sonrasına ekle",
+ copyTable: "Tabloyu kopyala",
+ delTable: "Tabloyu sil",
+ border: "Kenarlık",
+ color: "Renk",
+ width: "Genişlik",
+ background: "Arka plan",
+ dims: "Boyutlar",
+ height: "Yükseklik",
+ padding: "Dolgu",
+ tblCellTxtAlm: "Tablo hücresi metin hizalaması",
+ alCellTxtL: "Hücre metnini sola hizala",
+ alCellTxtC: "Hücre metnini ortaya hizala",
+ alCellTxtR: "Hücre metnini sağa hizala",
+ jusfCellTxt: "Hücre metnini yasla",
+ alCellTxtT: "Hücre metnini üste hizala",
+ alCellTxtM: "Hücre metnini ortaya hizala",
+ alCellTxtB: "Hücre metnini alta hizala",
+ dimsAlm: "Boyutlar ve hizalama",
+ alTblL: "Tabloyu sola hizala",
+ tblC: "Tabloyu ortala",
+ alTblR: "Tabloyu sağa hizala",
+ save: "Kaydet",
+ cancel: "İptal",
+ colorMsg: 'Renk geçersiz. "#FF0000", "rgb(255,0,0)" veya "red" deneyin.',
+ dimsMsg: 'Değer geçersiz. "10px", "2em" veya sadece "2" deneyin.',
+ colorPicker: "Renk seçici",
+ removeColor: "Rengi kaldır",
+ black: "Siyah",
+ dimGrey: "Koyu gri",
+ grey: "Gri",
+ lightGrey: "Açık gri",
+ white: "Beyaz",
+ red: "Kırmızı",
+ orange: "Turuncu",
+ yellow: "Sarı",
+ lightGreen: "Açık yeşil",
+ green: "Yeşil",
+ aquamarine: "Akuamarin",
+ turquoise: "Turkuaz",
+ lightBlue: "Açık mavi",
+ blue: "Mavi",
+ purple: "Mor"
+};
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/zh_CN.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/zh_CN.ts
new file mode 100644
index 0000000000..013a4dae93
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/zh_CN.ts
@@ -0,0 +1,59 @@
+export default {
+ col: "列",
+ insColL: "向左插入列",
+ insColR: "向右插入列",
+ delCol: "删除列",
+ row: "行",
+ insRowAbv: "在上面插入行",
+ insRowBlw: "在下面插入行",
+ delRow: "删除行",
+ mCells: "合并单元格",
+ sCell: "拆分单元格",
+ tblProps: "表格属性",
+ cellProps: "单元格属性",
+ insParaOTbl: "在表格外插入段落",
+ insB4: "在表格前面插入",
+ insAft: "在表格后面插入",
+ copyTable: "复制表格",
+ delTable: "删除表格",
+ border: "边框",
+ color: "颜色",
+ width: "宽度",
+ background: "背景",
+ dims: "尺寸",
+ height: "高度",
+ padding: "内边距",
+ tblCellTxtAlm: "单元格文本对齐方式",
+ alCellTxtL: "左对齐",
+ alCellTxtC: "水平居中对齐",
+ alCellTxtR: "右对齐",
+ jusfCellTxt: "两边对齐",
+ alCellTxtT: "顶端对齐",
+ alCellTxtM: "垂直居中对齐",
+ alCellTxtB: "底部对齐",
+ dimsAlm: "尺寸和对齐方式",
+ alTblL: "表格左对齐",
+ tblC: "表格居中",
+ alTblR: "表格右对齐",
+ save: "保存",
+ cancel: "取消",
+ colorMsg: '无效颜色,请使用 "#FF0000" 或者 "rgb(255,0,0)" 或者 "red"',
+ dimsMsg: '无效值, 请使用 "10px" 或者 "2em" 或者 "2"',
+ colorPicker: "颜色选择器",
+ removeColor: "删除颜色",
+ black: "黑色",
+ dimGrey: "暗灰色",
+ grey: "灰色",
+ lightGrey: "浅灰色",
+ white: "白色",
+ red: "红色",
+ orange: "橙色",
+ yellow: "黄色",
+ lightGreen: "浅绿色",
+ green: "绿色",
+ aquamarine: "海蓝色",
+ turquoise: "青绿色",
+ lightBlue: "浅蓝色",
+ blue: "蓝色",
+ purple: "紫色"
+};
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/modules/clipboard.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/modules/clipboard.ts
new file mode 100644
index 0000000000..2b255ed13a
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/modules/clipboard.ts
@@ -0,0 +1,58 @@
+import Quill from "quill";
+import Module from "quill/core/module";
+import QuillClipboard from "quill/modules/clipboard";
+import Delta from "quill-delta";
+import logger from "quill/core/logger.js";
+import type { Range, Props } from "../types";
+import { TableCellBlock, TableTemporary } from "../formats/table";
+
+const Clipboard = QuillClipboard as typeof Module;
+const debug = logger("quill:clipboard");
+
+class TableClipboard extends Clipboard {
+ // @ts-ignore
+ convert: (
+ {
+ html,
+ text
+ }: {
+ html?: string;
+ text?: string;
+ },
+ formats?: Record
+ ) => Delta;
+
+ onPaste(range: Range, { text, html }: { text?: string; html?: string }) {
+ const formats = this.quill.getFormat(range.index) as Props;
+ const pastedDelta = this.getTableDelta({ text, html }, formats);
+ debug.log("onPaste", pastedDelta, { text, html });
+ const delta = new Delta().retain(range.index).delete(range.length).concat(pastedDelta);
+ this.quill.updateContents(delta, Quill.sources.USER);
+ // range.length contributes to delta.length()
+ this.quill.setSelection(delta.length() - range.length, Quill.sources.SILENT);
+ this.quill.scrollSelectionIntoView();
+ }
+
+ private getTableDelta({ html, text }: { html?: string; text?: string }, formats: Props) {
+ const delta = this.convert({ text, html }, formats);
+ if (formats[TableCellBlock.blotName]) {
+ for (const op of delta.ops) {
+ // External copied tables or table contents copied within an editor.
+ // Subsequent version processing.
+ if (
+ op?.attributes &&
+ (op.attributes[TableTemporary.blotName] || op.attributes[TableCellBlock.blotName])
+ ) {
+ return new Delta();
+ }
+ // Process externally pasted lists or headers or text.
+ if (op?.attributes?.header || op?.attributes?.list || !op?.attributes?.[TableCellBlock.blotName]) {
+ op.attributes = { ...op.attributes, ...formats };
+ }
+ }
+ }
+ return delta;
+ }
+}
+
+export default TableClipboard;
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/modules/toolbar.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/modules/toolbar.ts
new file mode 100644
index 0000000000..ffb159d953
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/modules/toolbar.ts
@@ -0,0 +1,247 @@
+// @ts-nocheck
+import merge from "lodash.merge";
+import type { ContainerBlot } from "parchment";
+import { EmbedBlot } from "parchment";
+import type { Range } from "quill";
+import Quill from "quill";
+import Delta from "quill-delta";
+import QuillContainer from "quill/blots/container";
+import Module from "quill/core/module";
+import QuillToolbar from "quill/modules/toolbar";
+import TableHeader from "../formats/header";
+import type { CellSelection, QuillTableBetter, TableCell, TableCellAllowedChildren, TableCellChildren } from "../types";
+import { getCorrectCellBlot } from "../utils";
+
+const Container = QuillContainer as typeof ContainerBlot;
+const Toolbar = QuillToolbar as typeof Module;
+
+type Handler = (this: TableToolbar, value: any) => void;
+
+class TableToolbar extends Toolbar {
+ handlers: Record;
+ controls: [string, HTMLElement][];
+ update: (range: Range | null) => void;
+ container?: HTMLElement | null;
+
+ attach(input: HTMLElement) {
+ let format = Array.from(input.classList).find(className => {
+ return className.indexOf("ql-") === 0;
+ });
+ if (!format) return;
+ format = format.slice("ql-".length);
+ if (input.tagName === "BUTTON") {
+ input.setAttribute("type", "button");
+ }
+ if (this.handlers[format] == null && this.quill.scroll.query(format) == null) {
+ console.warn("ignoring attaching to nonexistent format", format, input);
+ return;
+ }
+ const eventName = input.tagName === "SELECT" ? "change" : "click";
+ input.addEventListener(eventName, e => {
+ const { cellSelection } = this.getTableBetter();
+ if (cellSelection?.selectedTds?.length > 1) {
+ this.cellSelectionAttach(input, format, e, cellSelection);
+ } else {
+ this.toolbarAttach(input, format, e);
+ }
+ });
+ this.controls.push([format, input]);
+ }
+
+ private cellSelectionAttach(
+ input: HTMLElement,
+ format: string,
+ e: Event | MouseEvent,
+ cellSelection: CellSelection
+ ) {
+ if (input.tagName === "SELECT") {
+ // @ts-ignore
+ if (input.selectedIndex < 0) return;
+ // @ts-ignore
+ const selected = input.options[input.selectedIndex];
+ const val = typeof selected?.value === "string" ? selected?.value : true;
+ const value = cellSelection.getCorrectValue(format, val);
+ cellSelection.setSelectedTdsFormat(format, value);
+ } else {
+ // @ts-ignore
+ const val = input?.value || true;
+ const value = cellSelection.getCorrectValue(format, val);
+ cellSelection.setSelectedTdsFormat(format, value);
+ e.preventDefault();
+ }
+ }
+
+ getTableBetter() {
+ return this.quill.getModule("table-better") as QuillTableBetter;
+ }
+
+ setTableFormat(range: Range, selectedTds: Element[], value: string, name: string, lines: TableCellChildren[]) {
+ let blot = null;
+ const { cellSelection, tableMenus } = this.getTableBetter();
+ const _isReplace = isReplace(range, selectedTds, lines);
+ for (const line of lines) {
+ const isReplace = getHeaderReplace(selectedTds, name, line, _isReplace);
+ blot = line.format(name, value, isReplace) as TableCellChildren;
+ }
+ if (selectedTds.length < 2) {
+ if (_isReplace || lines.length === 1) {
+ const cell = getCorrectCellBlot(blot);
+ Promise.resolve().then(() => {
+ if (cell && this.quill.root.contains(cell.domNode)) {
+ cellSelection.setSelected(cell.domNode, false);
+ } else {
+ cellSelection.setSelected(selectedTds[0], false);
+ }
+ });
+ } else {
+ cellSelection.setSelected(selectedTds[0], false);
+ }
+ this.quill.setSelection(range, Quill.sources.SILENT);
+ }
+ tableMenus.updateMenus();
+ return blot;
+ }
+
+ private toolbarAttach(input: HTMLElement, format: string, e: Event | MouseEvent) {
+ let value;
+ if (input.tagName === "SELECT") {
+ // @ts-expect-error
+ if (input.selectedIndex < 0) return;
+ // @ts-expect-error
+ const selected = input.options[input.selectedIndex];
+ if (selected.hasAttribute("selected")) {
+ value = false;
+ } else {
+ value = selected.value || false;
+ }
+ } else {
+ if (input.classList.contains("ql-active")) {
+ value = false;
+ } else {
+ // @ts-expect-error
+ value = input.value || !input.hasAttribute("value");
+ }
+ e.preventDefault();
+ }
+ this.quill.focus();
+ const [range] = this.quill.selection.getRange();
+ if (this.handlers[format] != null) {
+ this.handlers[format].call(this, value);
+ } else if (
+ // @ts-expect-error
+ this.quill.scroll.query(format).prototype instanceof EmbedBlot
+ ) {
+ value = prompt(`Enter ${format}`); // eslint-disable-line no-alert
+ if (!value) return;
+ this.quill.updateContents(
+ new Delta()
+ .retain(range.index)
+ .delete(range.length)
+ .insert({ [format]: value }),
+ Quill.sources.USER
+ );
+ } else {
+ this.quill.format(format, value, Quill.sources.USER);
+ }
+ this.update(range);
+ }
+}
+
+function containers(blot: TableCell, index = 0, length = Number.MAX_VALUE) {
+ const getContainers = (blot: TableCell | TableCellAllowedChildren, blotIndex: number, blotLength: number) => {
+ // @ts-ignore
+ let containers: Container[] = [];
+ let lengthLeft = blotLength;
+ blot.children.forEachAt(
+ blotIndex,
+ blotLength,
+ // @ts-ignore
+ (child, childIndex, childLength) => {
+ if (child instanceof Container) {
+ containers.push(child);
+ containers = containers.concat(getContainers(child, childIndex, lengthLeft));
+ }
+ lengthLeft -= childLength;
+ }
+ );
+ return containers;
+ };
+ return getContainers(blot, index, length);
+}
+
+function getHeaderReplace(selectedTds: Element[], name: string, line: TableCellChildren, _isReplace: boolean) {
+ if (selectedTds.length === 1 && name === "list" && line.statics.blotName === TableHeader.blotName) {
+ return true;
+ }
+ return _isReplace;
+}
+
+function getLength(blots: TableCellChildren[]): number {
+ return blots.reduce((sum, blot) => {
+ return (sum += blot.length());
+ }, 0);
+}
+
+function isReplace(range: Range, selectedTds: Element[], lines: TableCellChildren[]) {
+ if (selectedTds.length === 1) {
+ const cellBlot = Quill.find(selectedTds[0]) as TableCell;
+ const _containers = containers(cellBlot, range.index, range.length);
+ const length = getLength(_containers);
+ const _length = getLength(lines);
+ return length === _length;
+ }
+ return !!(selectedTds.length > 1);
+}
+
+function tablehandler(value: string, selectedTds: Element[], name: string, lines?: TableCellChildren[]) {
+ const range = this.quill.getSelection();
+ if (!lines) {
+ if (!range.length && selectedTds.length === 1) {
+ const [line] = this.quill.getLine(range.index);
+ lines = [line];
+ } else {
+ lines = this.quill.getLines(range);
+ }
+ }
+ return this.setTableFormat(range, selectedTds, value, name, lines);
+}
+
+TableToolbar.DEFAULTS = merge({}, Toolbar.DEFAULTS, {
+ handlers: {
+ header(value: string, lines?: TableCellChildren[]) {
+ const { cellSelection } = this.getTableBetter();
+ const selectedTds = cellSelection?.selectedTds;
+ if (selectedTds?.length) {
+ return tablehandler.call(this, value, selectedTds, "header", lines);
+ }
+ this.quill.format("header", value, Quill.sources.USER);
+ },
+ list(value: string, lines?: TableCellChildren[]) {
+ const { cellSelection } = this.getTableBetter();
+ const selectedTds = cellSelection?.selectedTds;
+ if (selectedTds?.length) {
+ if (selectedTds.length === 1) {
+ const range = this.quill.getSelection(true);
+ const formats = this.quill.getFormat(range);
+ value = cellSelection.getListCorrectValue("list", value, formats);
+ }
+ return tablehandler.call(this, value, selectedTds, "list", lines);
+ }
+
+ const range = this.quill.getSelection(true);
+ const formats = this.quill.getFormat(range);
+ if (value === "check") {
+ if (formats.list === "checked" || formats.list === "unchecked") {
+ this.quill.format("list", false, Quill.sources.USER);
+ } else {
+ this.quill.format("list", "unchecked", Quill.sources.USER);
+ }
+ } else {
+ this.quill.format("list", value, Quill.sources.USER);
+ }
+ },
+ "table-better"() {}
+ }
+});
+
+export default TableToolbar;
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/quill-table-better.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/quill-table-better.ts
new file mode 100644
index 0000000000..5d9891d804
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/quill-table-better.ts
@@ -0,0 +1,366 @@
+// @ts-nocheck
+import Quill from "quill";
+import Delta from "quill-delta";
+import Module from "quill/core/module";
+import type { EmitterSource, Range } from "quill";
+import type { BindingObject, Context, Props } from "./types";
+import {
+ cellId,
+ TableCellBlock,
+ TableCell,
+ TableRow,
+ TableBody,
+ TableTemporary,
+ TableContainer,
+ tableId,
+ TableCol,
+ TableColgroup
+} from "./formats/table";
+import TableHeader from "./formats/header";
+import { ListContainer } from "./formats/list";
+import { matchTable, matchTableCell, matchTableCol, matchTableTemporary } from "./utils/clipboard-matchers";
+import Language from "./language";
+import CellSelection from "./ui/cell-selection";
+import OperateLine from "./ui/operate-line";
+import TableMenus from "./ui/table-menus";
+import { CELL_DEFAULT_WIDTH } from "./config";
+import ToolbarTable, { TableSelect } from "./ui/toolbar-table";
+import { getCellId, getCorrectCellBlot } from "./utils";
+import TableToolbar from "./modules/toolbar";
+import TableClipboard from "./modules/clipboard";
+
+interface Options {
+ language?:
+ | string
+ | {
+ name: string;
+ content: Props;
+ };
+ menus?: string[];
+ toolbarButtons?: {
+ whiteList?: string[];
+ singleWhiteList?: string[];
+ };
+ toolbarTable?: boolean;
+}
+
+type Line = TableCellBlock | TableHeader | ListContainer;
+
+class Table extends Module {
+ language: Language;
+ cellSelection: CellSelection;
+ operateLine: OperateLine;
+ tableMenus: TableMenus;
+ tableSelect: TableSelect;
+ options: Options;
+
+ static keyboardBindings: { [propName: string]: BindingObject };
+
+ static register() {
+ Quill.register(TableCellBlock, true);
+ Quill.register(TableCell, true);
+ Quill.register(TableRow, true);
+ Quill.register(TableBody, true);
+ Quill.register(TableTemporary, true);
+ Quill.register(TableContainer, true);
+ Quill.register(TableCol, true);
+ Quill.register(TableColgroup, true);
+ Quill.register(
+ {
+ "modules/toolbar": TableToolbar,
+ "modules/clipboard": TableClipboard
+ },
+ true
+ );
+ }
+
+ constructor(quill: Quill, options: Options) {
+ super(quill, options);
+ quill.clipboard.addMatcher("td, th", matchTableCell);
+ quill.clipboard.addMatcher("tr", matchTable);
+ quill.clipboard.addMatcher("col", matchTableCol);
+ quill.clipboard.addMatcher("table", matchTableTemporary);
+ this.language = new Language(options?.language);
+ this.cellSelection = new CellSelection(quill, this);
+ this.operateLine = new OperateLine(quill, this);
+ this.tableMenus = new TableMenus(quill, this);
+ this.tableSelect = new TableSelect();
+ quill.root.addEventListener("keyup", this.handleKeyup.bind(this));
+ quill.root.addEventListener("mousedown", this.handleMousedown.bind(this));
+ quill.root.addEventListener("scroll", this.handleScroll.bind(this));
+ this.registerToolbarTable(options?.toolbarTable);
+ }
+
+ clearHistorySelected() {
+ const [table] = this.getTable();
+ if (!table) return;
+ const selectedTds: Element[] = Array.from(
+ table.domNode.querySelectorAll("td.ql-cell-focused, td.ql-cell-selected")
+ );
+ for (const td of selectedTds) {
+ td.classList && td.classList.remove("ql-cell-focused", "ql-cell-selected");
+ }
+ }
+
+ deleteTable() {
+ const [table] = this.getTable();
+ if (table == null) return;
+ const offset = table.offset();
+ table.remove();
+ this.hideTools();
+ this.quill.update(Quill.sources.USER);
+ this.quill.setSelection(offset, Quill.sources.SILENT);
+ }
+
+ deleteTableTemporary(source: EmitterSource = Quill.sources.API) {
+ const temporaries = this.quill.scroll.descendants(TableTemporary);
+ for (const temporary of temporaries) {
+ temporary.remove();
+ }
+ this.hideTools();
+ this.quill.update(source);
+ }
+
+ getTable(
+ range = this.quill.getSelection()
+ ): [null, null, null, -1] | [TableContainer, TableRow, TableCell, number] {
+ if (range == null) return [null, null, null, -1];
+ const [block, offset] = this.quill.getLine(range.index);
+ if (block == null || block.statics.blotName !== TableCellBlock.blotName) {
+ return [null, null, null, -1];
+ }
+ const cell = block.parent as TableCell;
+ const row = cell.parent as TableRow;
+ const table = row.parent.parent as TableContainer;
+ return [table, row, cell, offset];
+ }
+
+ handleKeyup(e: KeyboardEvent) {
+ this.cellSelection.handleKeyup(e);
+ if (e.ctrlKey && (e.key === "z" || e.key === "y")) {
+ this.hideTools();
+ this.clearHistorySelected();
+ }
+ this.updateMenus(e);
+ }
+
+ handleMousedown(e: MouseEvent) {
+ this.tableSelect?.hide(this.tableSelect.root);
+ const table = (e.target as Element).closest("table");
+ if (!table) return this.hideTools();
+ this.cellSelection.handleMousedown(e);
+ this.cellSelection.setDisabled(true);
+ }
+
+ handleScroll() {
+ this.hideTools();
+ this.tableMenus?.updateScroll(true);
+ }
+
+ hideTools() {
+ this.cellSelection?.clearSelected();
+ this.cellSelection?.setDisabled(false);
+ this.operateLine?.hideDragBlock();
+ this.operateLine?.hideDragTable();
+ this.operateLine?.hideLine();
+ this.tableMenus?.hideMenus();
+ this.tableMenus?.destroyTablePropertiesForm();
+ }
+
+ insertTable(rows: number, columns: number) {
+ const range = this.quill.getSelection(true);
+ if (range == null) return;
+ if (this.isTable(range)) return;
+ const style = `width: ${CELL_DEFAULT_WIDTH * columns}px`;
+ const formats = this.quill.getFormat(range.index - 1);
+ const [, offset] = this.quill.getLine(range.index);
+ const isExtra = !!formats[TableCellBlock.blotName] || offset !== 0;
+ const _offset = isExtra ? 2 : 1;
+ const extraDelta = isExtra ? new Delta().insert("\n") : new Delta();
+ const base = new Delta()
+ .retain(range.index)
+ .delete(range.length)
+ .concat(extraDelta)
+ .insert("\n", { [TableTemporary.blotName]: { style } });
+ const delta = new Array(rows).fill(0).reduce(memo => {
+ const id = tableId();
+ return new Array(columns).fill("\n").reduce((memo, text) => {
+ return memo.insert(text, {
+ [TableCellBlock.blotName]: cellId(),
+ [TableCell.blotName]: { "data-row": id, width: `${CELL_DEFAULT_WIDTH}` }
+ });
+ }, memo);
+ }, base);
+ this.quill.updateContents(delta, Quill.sources.USER);
+ this.quill.setSelection(range.index + _offset, Quill.sources.SILENT);
+ this.showTools();
+ }
+
+ // Inserting tables within tables is currently not supported
+ private isTable(range: Range) {
+ const formats = this.quill.getFormat(range.index);
+ return !!formats[TableCellBlock.blotName];
+ }
+
+ private registerToolbarTable(toolbarTable: boolean) {
+ if (!toolbarTable) return;
+ Quill.register({ "formats/table-better": ToolbarTable }, true);
+ const toolbar = this.quill.getModule("toolbar") as TableToolbar;
+ const button = toolbar.container.querySelector("button.ql-table-better");
+ if (!button || !this.tableSelect.root) return;
+ button.appendChild(this.tableSelect.root);
+ button.addEventListener("click", (e: MouseEvent) => {
+ this.tableSelect.handleClick(e, this.insertTable.bind(this));
+ });
+ this.quill.root.addEventListener("click", (e: MouseEvent) => {
+ const visible = e.composedPath().includes(button);
+ if (visible) return;
+ if (!this.tableSelect.root.classList.contains("ql-hidden")) {
+ this.tableSelect.hide(this.tableSelect.root);
+ }
+ });
+ }
+
+ showTools(force?: boolean) {
+ const [table, , cell] = this.getTable();
+ if (!table || !cell) return;
+ this.cellSelection.setDisabled(true);
+ this.cellSelection.setSelected(cell.domNode, force);
+ this.tableMenus.showMenus();
+ this.tableMenus.updateMenus(table.domNode);
+ this.tableMenus.updateTable(table.domNode);
+ }
+
+ private updateMenus(e: KeyboardEvent) {
+ if (!this.cellSelection.selectedTds.length) return;
+ if (e.key === "Enter" || (e.ctrlKey && e.key === "v")) {
+ this.tableMenus.updateMenus();
+ }
+ }
+}
+
+const keyboardBindings = {
+ "table-cell down": makeTableArrowHandler(false),
+ "table-cell up": makeTableArrowHandler(true),
+ "table-cell-block backspace": makeCellBlockHandler("Backspace"),
+ "table-cell-block delete": makeCellBlockHandler("Delete"),
+ "table-header backspace": makeTableHeaderHandler("Backspace"),
+ "table-header delete": makeTableHeaderHandler("Delete"),
+ "table-header enter": {
+ key: "Enter",
+ collapsed: true,
+ format: ["table-header"],
+ suffix: /^$/,
+ handler(range: Range, context: Context) {
+ const [line, offset] = this.quill.getLine(range.index);
+ const delta = new Delta()
+ .retain(range.index)
+ .insert("\n", context.format)
+ .retain(line.length() - offset - 1)
+ .retain(1, { header: null });
+ this.quill.updateContents(delta, Quill.sources.USER);
+ this.quill.setSelection(range.index + 1, Quill.sources.SILENT);
+ this.quill.scrollSelectionIntoView();
+ }
+ },
+ "table-list backspace": makeTableListHandler("Backspace"),
+ "table-list delete": makeTableListHandler("Delete"),
+ "table-list empty enter": {
+ key: "Enter",
+ collapsed: true,
+ format: ["table-list"],
+ empty: true,
+ handler(_range: Range, context: Context) {
+ const { line } = context;
+ const { cellId } = line.parent.formats()[line.parent.statics.blotName];
+ const blot = line.replaceWith(TableCellBlock.blotName, cellId) as TableCellBlock;
+ const tableModule = this.quill.getModule("table-better");
+ const cell = getCorrectCellBlot(blot);
+ cell && tableModule.cellSelection.setSelected(cell.domNode, false);
+ }
+ }
+};
+
+function makeCellBlockHandler(key: string) {
+ return {
+ key,
+ format: ["table-cell-block"],
+ collapsed: true,
+ handler(range: Range, context: Context) {
+ const [line] = this.quill.getLine(range.index);
+ const { offset, suffix } = context;
+ if (offset === 0 && !line.prev) return false;
+ const blotName = line.prev?.statics.blotName;
+ if (
+ offset === 0 &&
+ (blotName === ListContainer.blotName ||
+ blotName === TableCellBlock.blotName ||
+ blotName === TableHeader.blotName)
+ ) {
+ return removeLine.call(this, line, range);
+ }
+ // Delete isn't from the end
+ if (offset !== 0 && !suffix && key === "Delete") {
+ return false;
+ }
+ return true;
+ }
+ };
+}
+
+// Prevent table default up and down keyboard events.
+// Implemented by the makeTableArrowVerticalHandler function.
+function makeTableArrowHandler(up: boolean) {
+ return {
+ key: up ? "ArrowUp" : "ArrowDown",
+ collapsed: true,
+ format: ["table-cell"],
+ handler() {
+ return false;
+ }
+ };
+}
+
+function makeTableHeaderHandler(key: string) {
+ return {
+ key,
+ format: ["table-header"],
+ collapsed: true,
+ empty: true,
+ handler(range: Range, _context: Context) {
+ const [line] = this.quill.getLine(range.index);
+ if (line.prev) {
+ return removeLine.call(this, line, range);
+ } else {
+ const cellId = getCellId(line.formats()[line.statics.blotName]);
+ line.replaceWith(TableCellBlock.blotName, cellId);
+ }
+ }
+ };
+}
+
+function makeTableListHandler(key: string) {
+ return {
+ key,
+ format: ["table-list"],
+ collapsed: true,
+ empty: true,
+ handler(range: Range, _context: Context) {
+ const [line] = this.quill.getLine(range.index);
+ const cellId = getCellId(line.parent.formats()[line.parent.statics.blotName]);
+ line.replaceWith(TableCellBlock.blotName, cellId);
+ }
+ };
+}
+
+function removeLine(line: Line, range: Range) {
+ const tableModule = this.quill.getModule("table-better");
+ line.remove();
+ tableModule?.tableMenus.updateMenus();
+ this.quill.setSelection(range.index - 1, Quill.sources.SILENT);
+ return false;
+}
+
+Table.keyboardBindings = keyboardBindings;
+
+export default Table;
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/types.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/types.ts
new file mode 100644
index 0000000000..715219c1b6
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/types.ts
@@ -0,0 +1,85 @@
+import Quill from "quill";
+import TableHeader from "./formats/header";
+import TableList, { ListContainer } from "./formats/list";
+import { TableBody, TableCell, TableCellBlock, TableColgroup, TableContainer, TableRow } from "./formats/table";
+import QuillTableBetter from "./quill-table-better";
+import CellSelection from "./ui/cell-selection";
+import TableMenus from "./ui/table-menus";
+
+export interface CorrectBound {
+ left: number;
+ top: number;
+ right: number;
+ bottom: number;
+ width?: number;
+ height?: number;
+}
+
+export interface Props {
+ [propName: string]: string;
+}
+
+export interface Range {
+ index: number;
+ length: number;
+}
+
+export type InsertTableHandler = (rows: number, columns: number) => void;
+
+export type TableCellAllowedChildren = TableCellBlock | TableHeader | ListContainer;
+export type TableCellChildren = TableCellAllowedChildren | TableList;
+export type TableCellMap = Map;
+
+export type UseLanguageHandler = (name: string) => string;
+
+interface BindingObject extends Partial> {
+ key: number | string | string[];
+ shortKey?: boolean | null;
+ shiftKey?: boolean | null;
+ altKey?: boolean | null;
+ metaKey?: boolean | null;
+ ctrlKey?: boolean | null;
+ prefix?: RegExp;
+ suffix?: RegExp;
+ format?: Record | string[];
+ handler?: (
+ this: { quill: Quill },
+ range: Range,
+ // eslint-disable-next-line no-use-before-define
+ curContext: Context,
+ // eslint-disable-next-line no-use-before-define
+ binding: NormalizedBinding
+ ) => boolean | void;
+}
+
+interface Context {
+ collapsed: boolean;
+ empty: boolean;
+ offset: number;
+ prefix: string;
+ suffix: string;
+ format: Record;
+ event: KeyboardEvent;
+ line: TableCellChildren;
+}
+
+interface NormalizedBinding extends Omit {
+ key: string | number;
+}
+
+export type {
+ BindingObject,
+ CellSelection,
+ Context,
+ ListContainer,
+ QuillTableBetter,
+ TableBody,
+ TableCell,
+ TableCellBlock,
+ TableColgroup,
+ TableContainer,
+ TableHeader,
+ TableList,
+ TableMenus,
+ TableRow
+};
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/cell-selection.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/cell-selection.ts
new file mode 100644
index 0000000000..bfa8bd64a0
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/cell-selection.ts
@@ -0,0 +1,716 @@
+// @ts-nocheck
+import { BlockBlot, ContainerBlot, EmbedBlot } from "parchment";
+import Quill from "quill";
+import type { AttributeMap, Op } from "quill-delta";
+import Delta from "quill-delta";
+import { DEVIATION } from "../config";
+import { TableCell, TableCellBlock } from "../formats/table";
+import type {
+ Props,
+ QuillTableBetter,
+ TableBody,
+ TableCellAllowedChildren,
+ TableCellChildren,
+ TableContainer,
+ TableRow
+} from "../types";
+import { getComputeBounds, getComputeSelectedTds, getCopyTd, getCorrectBounds, getCorrectCellBlot } from "../utils";
+import { applyFormat } from "../utils/clipboard-matchers";
+
+const WHITE_LIST = [
+ "bold",
+ "italic",
+ "underline",
+ "strike",
+ "size",
+ "color",
+ "background",
+ "font",
+ "list",
+ "header",
+ "align",
+ "link",
+ "image"
+];
+
+// Only supports formatting for a single cell.
+const SINGLE_WHITE_LIST = ["link", "image"];
+
+function isLine(blot: unknown): blot is BlockBlot | EmbedBlot {
+ return blot instanceof BlockBlot || blot instanceof EmbedBlot;
+}
+
+class CellSelection {
+ quill: Quill;
+ selectedTds: Element[];
+ startTd: Element;
+ endTd: Element;
+ disabledList: Array;
+ singleList: Array;
+ tableBetter: QuillTableBetter;
+ constructor(quill: Quill, tableBetter: QuillTableBetter) {
+ this.quill = quill;
+ this.selectedTds = [];
+ this.startTd = null;
+ this.endTd = null;
+ this.disabledList = [];
+ this.singleList = [];
+ this.tableBetter = tableBetter;
+ this.quill.root.addEventListener("click", this.handleClick.bind(this));
+ this.initDocumentListener();
+ this.initWhiteList();
+ }
+
+ attach(input: HTMLElement) {
+ let format = Array.from(input.classList).find(className => {
+ return className.indexOf("ql-") === 0;
+ });
+ if (!format) return;
+ const [whiteList, singleWhiteList] = this.getButtonsWhiteList();
+ const correctDisabled = this.getCorrectDisabled(input, format);
+ format = format.slice("ql-".length);
+ if (!whiteList.includes(format)) {
+ this.disabledList.push(...correctDisabled);
+ }
+ if (singleWhiteList.includes(format)) {
+ this.singleList.push(...correctDisabled);
+ }
+ }
+
+ clearSelected() {
+ for (const td of this.selectedTds) {
+ td.classList && td.classList.remove("ql-cell-focused", "ql-cell-selected");
+ }
+ this.selectedTds = [];
+ this.startTd = null;
+ this.endTd = null;
+ }
+
+ exitTableFocus(block: TableCellChildren, up: boolean) {
+ const cell = getCorrectCellBlot(block);
+ const table = cell.table();
+ const offset = up ? -1 : table.length();
+ const index = table.offset(this.quill.scroll) + offset;
+ this.tableBetter.hideTools();
+ this.quill.setSelection(index, 0, Quill.sources.USER);
+ }
+
+ getButtonsWhiteList(): [string[], string[]] {
+ const { options = {} } = this.tableBetter;
+ const { toolbarButtons = {} } = options;
+ const { whiteList = WHITE_LIST, singleWhiteList = SINGLE_WHITE_LIST } = toolbarButtons;
+ return [whiteList, singleWhiteList];
+ }
+
+ getCopyColumns(container: Element) {
+ const tr = container.querySelector("tr");
+ const children = Array.from(tr.querySelectorAll("td"));
+ return children.reduce((sum: number, td: HTMLTableCellElement) => {
+ const colspan = ~~td.getAttribute("colspan") || 1;
+ return (sum += colspan);
+ }, 0);
+ }
+
+ getCopyData() {
+ const tableBlot = (Quill.find(this.selectedTds[0]) as TableCell).table();
+ const tableCells = tableBlot.descendants(TableCell);
+ if (tableCells.length === this.selectedTds.length) {
+ const html = tableBlot.getCopyTable();
+ const text = this.getText(html);
+ return { html, text };
+ }
+ let html = "";
+ const map: { [propName: string]: Element[] } = {};
+ for (const td of this.selectedTds) {
+ const rowId = td.getAttribute("data-row");
+ if (!map[rowId]) {
+ map[rowId] = [];
+ }
+ map[rowId].push(td);
+ }
+ for (const tds of Object.values(map)) {
+ let res = "";
+ for (const td of tds) {
+ res += getCopyTd(td.outerHTML);
+ }
+ res = `${res} `;
+ html += res;
+ }
+ html = ``;
+ const text = this.getText(html);
+ return { html, text };
+ }
+
+ getCorrectDisabled(input: HTMLElement, format: string) {
+ if (input.tagName !== "SELECT") return [input];
+ const parentElement = input.closest("span.ql-formats");
+ if (!parentElement) return [input];
+ const child = parentElement.querySelectorAll(`span.${format}.ql-picker`);
+ return [...child, input];
+ }
+
+ getCorrectRow(td: Element, key: string) {
+ const offset = key === "next" ? 0 : -1;
+ let rowspan = (~~td.getAttribute("rowspan") || 1) + offset || 1;
+ const cell = Quill.find(td) as TableCell;
+ let row = cell.parent;
+ while (row && rowspan) {
+ // @ts-expect-error
+ row = row[key];
+ rowspan--;
+ }
+ return row?.domNode;
+ }
+
+ getCorrectValue(format: string, value: boolean | string) {
+ for (const td of this.selectedTds) {
+ const blot = Quill.find(td) as TableCell;
+ const html = blot.html() || td.outerHTML;
+ const delta = this.quill.clipboard.convert({
+ html,
+ text: "\n"
+ });
+ for (const op of delta.ops) {
+ if (this.isContinue(op)) continue;
+ value = this.getListCorrectValue(format, value, op?.attributes);
+ const val = (op?.attributes && op?.attributes[format]) || false;
+ if (value != val) return value;
+ }
+ }
+ return !value;
+ }
+
+ getListCorrectValue(format: string, value: boolean | string, formats: AttributeMap = {}) {
+ if (format !== "list") return value;
+ if (value === "check") {
+ if (formats[format] === "checked" || formats[format] === "unchecked") {
+ return false;
+ } else {
+ return "unchecked";
+ }
+ }
+ return value;
+ }
+
+ getPasteComputeBounds(startTd: Element, rightTd: Element, row: TableRow) {
+ const startTdBounds = startTd.getBoundingClientRect();
+ const rightTdBounds = rightTd.getBoundingClientRect();
+ const rowBounds = row.domNode.getBoundingClientRect();
+ const containerBounds = this.quill.container.getBoundingClientRect();
+ const scrollLeft = this.quill.container.scrollLeft;
+ const scrollTop = this.quill.container.scrollTop;
+ const left = startTdBounds.left - containerBounds.left - scrollLeft;
+ const right = rightTdBounds.right - containerBounds.left - scrollLeft;
+ const top = startTdBounds.top - containerBounds.top - scrollTop;
+ const bottom = rowBounds.bottom - containerBounds.top - scrollTop;
+ return {
+ left,
+ right,
+ top,
+ bottom
+ };
+ }
+
+ getPasteInfo(td: Element, copyColumns: number, rowspan: number) {
+ let clospan = 0;
+ let cloTd = null;
+ let rowTd = null;
+ let row: Element = td.parentElement;
+ while (td) {
+ const colspan = ~~td.getAttribute("colspan") || 1;
+ clospan += colspan;
+ if (clospan >= copyColumns) {
+ clospan = copyColumns;
+ cloTd = td;
+ break;
+ }
+ td = td.nextElementSibling;
+ }
+ while (--rowspan) {
+ if (!row.nextElementSibling) {
+ rowTd = row.firstElementChild;
+ break;
+ }
+ row = row.nextElementSibling;
+ }
+ return [
+ { clospan: Math.abs(copyColumns - clospan), cloTd },
+ { rowspan, rowTd }
+ ];
+ }
+
+ getPasteLastRow(row: TableRow, len: number) {
+ while (--len && row) {
+ row = row.next;
+ }
+ return row;
+ }
+
+ getPasteTds(computeSelectedTds: Element[]) {
+ const map: { [propName: string]: Element[] } = {};
+ for (const td of computeSelectedTds) {
+ const id = td.getAttribute("data-row");
+ if (!map[id]) map[id] = [];
+ map[id].push(td);
+ }
+ return Object.values(map);
+ }
+
+ getText(html: string): string {
+ const delta: Delta = this.quill.clipboard.convert({ html });
+ return delta
+ .filter(op => typeof op.insert === "string")
+ .map(op => op.insert)
+ .join("");
+ }
+
+ handleClick(e: MouseEvent) {
+ if (e.detail < 3 || !this.selectedTds.length) return;
+ // Multiple clicks result in cell being selected
+ // Cell are deleted when deleting
+ const { index, length } = this.quill.getSelection(true);
+ this.quill.setSelection(index, length - 1, Quill.sources.SILENT);
+ this.quill.scrollSelectionIntoView();
+ }
+
+ handleDeleteKeyup(e: KeyboardEvent) {
+ if (this.selectedTds?.length < 2) return;
+ if (e.key === "Backspace" || e.key === "Delete") {
+ if (e.ctrlKey) {
+ this.tableBetter.tableMenus.deleteColumn(true);
+ this.tableBetter.tableMenus.deleteRow(true);
+ } else {
+ this.removeSelectedTdsContent();
+ }
+ }
+ }
+
+ handleKeyup(e: KeyboardEvent) {
+ switch (e.key) {
+ case "ArrowLeft":
+ case "ArrowRight":
+ this.makeTableArrowLevelHandler(e.key);
+ break;
+ case "ArrowUp":
+ case "ArrowDown":
+ this.makeTableArrowVerticalHandler(e.key);
+ break;
+ default:
+ break;
+ }
+ }
+
+ handleMousedown(e: MouseEvent) {
+ this.clearSelected();
+ const table = (e.target as Element).closest("table");
+ if (!table) return;
+ this.tableBetter.tableMenus.destroyTablePropertiesForm();
+ const startTd = (e.target as Element).closest("td");
+ this.startTd = startTd;
+ this.endTd = startTd;
+ this.selectedTds = [startTd];
+ startTd.classList.add("ql-cell-focused");
+
+ const handleMouseMove = (e: MouseEvent) => {
+ const endTd = (e.target as Element).closest("td");
+ if (!endTd) return;
+ const isEqualNode = startTd.isEqualNode(endTd);
+ if (isEqualNode) return;
+ this.clearSelected();
+ this.startTd = startTd;
+ this.endTd = endTd;
+ const startCorrectBounds = getCorrectBounds(startTd, this.quill.container);
+ const endCorrectBounds = getCorrectBounds(endTd, this.quill.container);
+ const computeBounds = getComputeBounds(startCorrectBounds, endCorrectBounds);
+ this.selectedTds = getComputeSelectedTds(computeBounds, table, this.quill.container);
+ for (const td of this.selectedTds) {
+ td.classList && td.classList.add("ql-cell-selected");
+ }
+ if (!isEqualNode) this.quill.blur();
+ };
+
+ const handleMouseup = (e: MouseEvent) => {
+ this.setSingleDisabled();
+ this.setCorrectPositionTds(this.startTd, this.endTd, this.selectedTds);
+ this.quill.root.removeEventListener("mousemove", handleMouseMove);
+ this.quill.root.removeEventListener("mouseup", handleMouseup);
+ };
+
+ this.quill.root.addEventListener("mousemove", handleMouseMove);
+ this.quill.root.addEventListener("mouseup", handleMouseup);
+ }
+
+ initDocumentListener() {
+ this.quill.root.addEventListener("copy", (e: ClipboardEvent) => this.onCaptureCopy(e, false));
+ this.quill.root.addEventListener("cut", (e: ClipboardEvent) => this.onCaptureCopy(e, true));
+ this.quill.root.addEventListener("keyup", this.handleDeleteKeyup.bind(this));
+ this.quill.root.addEventListener("paste", this.onCapturePaste.bind(this));
+ }
+
+ initWhiteList() {
+ const toolbar = this.quill.getModule("toolbar");
+ // @ts-expect-error
+ Array.from(toolbar.container.querySelectorAll("button, select")).forEach(input => {
+ // @ts-ignore
+ this.attach(input);
+ });
+ }
+
+ insertColumnCell(table: TableContainer, offset: number) {
+ const tbody = table.tbody() as TableBody;
+ if (!tbody) return;
+ tbody.children.forEach((row: TableRow) => {
+ const id = row.children.tail.domNode.getAttribute("data-row");
+ for (let i = 0; i < offset; i++) {
+ table.insertColumnCell(row, id, null);
+ }
+ });
+ }
+
+ insertRow(table: TableContainer, offset: number, td: Element) {
+ const index = (Quill.find(td) as TableCell).rowOffset();
+ while (offset--) {
+ table.insertRow(index + 1, 1);
+ }
+ }
+
+ insertWith(insert: string | Record) {
+ if (typeof insert !== "string") return false;
+ return insert.startsWith("\n") && insert.endsWith("\n");
+ }
+
+ isContinue(op: Op) {
+ if (
+ this.insertWith(op.insert) &&
+ (!op.attributes || op.attributes["table-list"] || op.attributes["table-header"])
+ ) {
+ return true;
+ }
+ return false;
+ }
+
+ lines(blot: TableCell) {
+ const getLines = (blot: TableCell | TableCellAllowedChildren) => {
+ let lines: (BlockBlot | EmbedBlot)[] = [];
+ blot.children.forEach((child: TableCellAllowedChildren) => {
+ if (child instanceof ContainerBlot) {
+ lines = lines.concat(getLines(child));
+ } else if (isLine(child)) {
+ lines.push(child);
+ }
+ });
+ return lines;
+ };
+ return getLines(blot);
+ }
+
+ makeTableArrowLevelHandler(key: string) {
+ const td = key === "ArrowLeft" ? this.startTd : this.endTd;
+ const range = this.quill.getSelection();
+ if (!range) return;
+ const [block] = this.quill.getLine(range.index);
+ // @ts-expect-error
+ const cell = getCorrectCellBlot(block);
+ if (!cell) return this.tableBetter.hideTools();
+ if (cell && (!td || !td.isEqualNode(cell.domNode))) {
+ this.setSelected(cell.domNode, false);
+ this.tableBetter.showTools(false);
+ }
+ }
+
+ makeTableArrowVerticalHandler(key: string) {
+ const up = key === "ArrowUp" ? true : false;
+ const range = this.quill.getSelection();
+ if (!range) return;
+ const [block, offset] = this.quill.getLine(range.index);
+ const _key = up ? "prev" : "next";
+ if (block[_key] && this.selectedTds.length) {
+ const index = block[_key].offset(this.quill.scroll) + Math.min(offset, block[_key].length() - 1);
+ this.quill.setSelection(index, 0, Quill.sources.USER);
+ } else {
+ if (!this.selectedTds.length) {
+ // @ts-expect-error
+ const cellBlot = getCorrectCellBlot(block);
+ if (!cellBlot) return;
+ this.tableArrowSelection(up, cellBlot);
+ this.tableBetter.showTools(false);
+ return;
+ }
+ const td = up ? this.startTd : this.endTd;
+ const cell = Quill.find(td) as TableCell;
+ const targetRow = cell.parent[_key];
+ const { left: _left, right: _right } = td.getBoundingClientRect();
+ if (targetRow) {
+ let cellBlot = null;
+ let row = targetRow;
+ while (row && !cellBlot) {
+ let ref = row.children.head;
+ while (ref) {
+ const { left, right } = ref.domNode.getBoundingClientRect();
+ if (Math.abs(left - _left) <= DEVIATION) {
+ cellBlot = ref;
+ break;
+ } else if (Math.abs(right - _right) <= DEVIATION) {
+ cellBlot = ref;
+ break;
+ }
+ ref = ref.next;
+ }
+ row = row[_key];
+ }
+ if (!cellBlot) {
+ // @ts-expect-error
+ this.exitTableFocus(block, up);
+ } else {
+ this.tableArrowSelection(up, cellBlot);
+ }
+ } else {
+ // @ts-expect-error
+ this.exitTableFocus(block, up);
+ }
+ }
+ }
+
+ onCaptureCopy(e: ClipboardEvent, isCut = false) {
+ if (this.selectedTds?.length < 2) return;
+ if (e.defaultPrevented) return;
+ e.preventDefault();
+ const { html, text } = this.getCopyData();
+ e.clipboardData?.setData("text/plain", text);
+ e.clipboardData?.setData("text/html", html);
+ if (isCut) this.removeSelectedTdsContent();
+ }
+
+ onCapturePaste(e: ClipboardEvent) {
+ if (!this.selectedTds?.length) return;
+ e.preventDefault();
+ const html = e.clipboardData?.getData("text/html");
+ const text = e.clipboardData?.getData("text/plain");
+ const container = this.quill.root.ownerDocument.createElement("div");
+ container.innerHTML = html;
+ const copyRows = Array.from(container.querySelectorAll("tr"));
+ if (!copyRows.length) return;
+ const cell = Quill.find(this.startTd) as TableCell;
+ const row = cell.row();
+ const table = cell.table();
+ this.quill.history.cutoff();
+ const copyColumns = this.getCopyColumns(container);
+ const [cloInfo, rowInfo] = this.getPasteInfo(this.startTd, copyColumns, copyRows.length);
+ const { clospan, cloTd } = cloInfo;
+ const { rowspan, rowTd } = rowInfo;
+ if (clospan) this.insertColumnCell(table, clospan);
+ if (rowspan) this.insertRow(table, rowspan, rowTd);
+ const rightTd = clospan ? row.children.tail.domNode : cloTd;
+ const pasteLastRow = this.getPasteLastRow(row, copyRows.length);
+ const computeBounds = this.getPasteComputeBounds(this.startTd, rightTd, pasteLastRow);
+ const pasteTds = this.getPasteTds(getComputeSelectedTds(computeBounds, table.domNode, this.quill.container));
+ const copyTds = copyRows.reduce((copyTds: HTMLElement[][], row: HTMLTableRowElement) => {
+ copyTds.push(Array.from(row.querySelectorAll("td")));
+ return copyTds;
+ }, []);
+ const selectedTds: HTMLElement[] = [];
+ while (copyTds.length) {
+ const copyTs = copyTds.shift();
+ const pasteTs = pasteTds.shift();
+ let prevPasteTd = null;
+ let cell: TableCell = null;
+ while (copyTs.length) {
+ const copyTd = copyTs.shift();
+ const pasteTd = pasteTs.shift();
+ if (!pasteTd) {
+ const id = prevPasteTd.getAttribute("data-row");
+ const ref = Quill.find(prevPasteTd) as TableCell;
+ cell = table.insertColumnCell(ref.parent, id, ref.next);
+ cell = this.pasteSelectedTd(cell.domNode, copyTd);
+ prevPasteTd = cell.domNode;
+ } else {
+ prevPasteTd = pasteTd;
+ cell = this.pasteSelectedTd(pasteTd, copyTd);
+ }
+ cell && selectedTds.push(cell.domNode);
+ }
+ while (pasteTs.length) {
+ const pasteTd = pasteTs.shift();
+ pasteTd.remove();
+ }
+ }
+ this.quill.blur();
+ this.setSelectedTds(selectedTds);
+ this.tableBetter.tableMenus.updateMenus();
+ this.quill.scrollSelectionIntoView();
+ }
+
+ pasteSelectedTd(selectedTd: Element, copyTd: Element) {
+ const id = selectedTd.getAttribute("data-row");
+ const copyFormats = TableCell.formats(copyTd);
+ Object.assign(copyFormats, { "data-row": id });
+ const cell = Quill.find(selectedTd) as TableCell;
+ const _cell = cell.replaceWith(cell.statics.blotName, copyFormats) as TableCell;
+ this.quill.setSelection(_cell.offset(this.quill.scroll) + _cell.length() - 1, 0, Quill.sources.USER);
+ const range = this.quill.getSelection(true);
+ const formats = this.quill.getFormat(range.index) as Props;
+ const html = copyTd.innerHTML;
+ const text = this.getText(html);
+ const pastedDelta = this.quill.clipboard.convert({ text, html });
+ const delta = new Delta().retain(range.index).delete(range.length).concat(applyFormat(pastedDelta, formats));
+ this.quill.updateContents(delta, Quill.sources.USER);
+ return _cell;
+ }
+
+ removeCursor() {
+ const range = this.quill.getSelection(true);
+ if (range && range.length === 0) {
+ // The attach function of the toolbar module generated extra cursor
+ // when clicked, which needs to be removed.
+ this.quill.selection.cursor.remove();
+ this.quill.blur();
+ }
+ }
+
+ removeSelectedTdContent(td: Element) {
+ const tdBlot = Quill.find(td) as TableCell;
+ let head = tdBlot.children.head as TableCellBlock;
+ const cellId = head.formats()[TableCellBlock.blotName];
+ const cellBlock = this.quill.scroll.create(TableCellBlock.blotName, cellId);
+ tdBlot.insertBefore(cellBlock, head);
+ while (head) {
+ head.remove();
+ head = head.next;
+ }
+ }
+
+ removeSelectedTdsContent() {
+ if (this.selectedTds.length < 2) return;
+ for (const td of this.selectedTds) {
+ this.removeSelectedTdContent(td);
+ }
+ this.tableBetter.tableMenus.updateMenus();
+ }
+
+ setCorrectPositionTds(startTd: Element, endTd: Element, selectedTds: Element[]) {
+ if (!startTd || !endTd || selectedTds.length < 2) return;
+ const firstTd = selectedTds[0];
+ const lastTd = selectedTds[selectedTds.length - 1];
+ const tds = [...new Set([startTd, endTd, firstTd, lastTd])];
+ tds.sort((prev: Element, next: Element) => {
+ const prevBounds = prev.getBoundingClientRect();
+ const nextBounds = next.getBoundingClientRect();
+ if (
+ (prevBounds.top <= nextBounds.top || prevBounds.bottom <= nextBounds.bottom) &&
+ (prevBounds.left <= nextBounds.left || prevBounds.right <= nextBounds.right)
+ ) {
+ return -1;
+ }
+ return 1;
+ });
+ this.startTd = tds[0];
+ this.endTd = tds[tds.length - 1];
+ }
+
+ setDisabled(disabled: boolean) {
+ for (const input of this.disabledList) {
+ if (disabled) {
+ input.classList.add("ql-table-button-disabled");
+ } else {
+ input.classList.remove("ql-table-button-disabled");
+ }
+ }
+ this.setSingleDisabled();
+ }
+
+ setSelected(target: Element, force: boolean = true) {
+ const cell = Quill.find(target) as TableCell;
+ this.clearSelected();
+ this.startTd = target;
+ this.endTd = target;
+ this.selectedTds = [target];
+ target.classList.add("ql-cell-focused");
+ force && this.quill.setSelection(cell.offset(this.quill.scroll) + cell.length() - 1, 0, Quill.sources.USER);
+ }
+
+ setSelectedTds(selectedTds: Element[]) {
+ this.clearSelected();
+ this.startTd = selectedTds[0];
+ this.endTd = selectedTds[selectedTds.length - 1];
+ this.selectedTds = selectedTds;
+ for (const td of this.selectedTds) {
+ td.classList && td.classList.add("ql-cell-selected");
+ }
+ }
+
+ setSelectedTdsFormat(format: string, value: boolean | string) {
+ const selectedTds = [];
+ const toolbar = this.quill.getModule("toolbar");
+ for (const td of this.selectedTds) {
+ // @ts-expect-error
+ if (toolbar.handlers[format] != null) {
+ const cellBlot = Quill.find(td) as TableCell;
+ const lines = this.lines(cellBlot);
+ // @ts-expect-error
+ const blot = toolbar.handlers[format].call(toolbar, value, lines);
+ blot && selectedTds.push(getCorrectCellBlot(blot).domNode);
+ } else {
+ const selection = window.getSelection();
+ selection.selectAllChildren(td);
+ this.quill.format(format, value, Quill.sources.USER);
+ selection.removeAllRanges();
+ }
+ }
+ this.quill.blur();
+ selectedTds.length && this.setSelectedTds(selectedTds);
+ }
+
+ setSingleDisabled() {
+ for (const input of this.singleList) {
+ if (this.selectedTds.length > 1) {
+ input.classList.add("ql-table-button-disabled");
+ } else {
+ input.classList.remove("ql-table-button-disabled");
+ }
+ }
+ }
+
+ tableArrowSelection(up: boolean, cellBlot: TableCell) {
+ const key = up ? "tail" : "head";
+ const offset = up ? cellBlot.children[key].length() - 1 : 0;
+ this.setSelected(cellBlot.domNode, false);
+ const index = cellBlot.children[key].offset(this.quill.scroll) + offset;
+ this.quill.setSelection(index, 0, Quill.sources.USER);
+ }
+
+ updateSelected(type: string) {
+ switch (type) {
+ case "column":
+ {
+ const target = this.endTd.nextElementSibling || this.startTd.previousElementSibling;
+ if (!target) return;
+ this.setSelected(target);
+ }
+ break;
+ case "row":
+ {
+ const row = this.getCorrectRow(this.endTd, "next") || this.getCorrectRow(this.startTd, "prev");
+ if (!row) return;
+ const startCorrectBounds = getCorrectBounds(this.startTd, this.quill.container);
+ let child = row.firstElementChild;
+ while (child) {
+ const childCorrectBounds = getCorrectBounds(child, this.quill.container);
+ if (
+ childCorrectBounds.left + DEVIATION >= startCorrectBounds.left ||
+ childCorrectBounds.right - DEVIATION >= startCorrectBounds.left
+ ) {
+ this.setSelected(child);
+ return;
+ }
+ child = child.nextElementSibling;
+ }
+ this.setSelected(row.firstElementChild);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+export default CellSelection;
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/operate-line.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/operate-line.ts
new file mode 100644
index 0000000000..1ef6a7191f
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/operate-line.ts
@@ -0,0 +1,443 @@
+// @ts-nocheck
+import Quill from "quill";
+import type { QuillTableBetter, TableCell, TableColgroup } from "../types";
+import { setElementAttribute, setElementProperty, updateTableWidth } from "../utils";
+
+interface Options {
+ tableNode: HTMLElement;
+ cellNode: HTMLElement;
+ mousePosition: {
+ clientX: number;
+ clientY: number;
+ };
+}
+
+const DRAG_BLOCK_HEIGHT = 8;
+const DRAG_BLOCK_WIDTH = 8;
+const LINE_CONTAINER_HEIGHT = 5;
+const LINE_CONTAINER_WIDTH = 5;
+
+class OperateLine {
+ quill: Quill;
+ options: Options | null;
+ drag: boolean;
+ line: HTMLElement | null;
+ dragBlock: HTMLElement | null;
+ dragTable: HTMLElement | null;
+ direction: string | null;
+ tableBetter: QuillTableBetter;
+ constructor(quill: Quill, tableBetter?: QuillTableBetter) {
+ this.quill = quill;
+ this.options = null;
+ this.drag = false;
+ this.line = null;
+ this.dragBlock = null;
+ this.dragTable = null;
+ this.direction = null; // 1.level 2.vertical
+ this.tableBetter = tableBetter;
+ this.quill.root.addEventListener("mousemove", this.handleMouseMove.bind(this));
+ }
+
+ createDragBlock() {
+ const dragBlock = this.quill.root.ownerDocument.createElement("div");
+ dragBlock.classList.add("ql-operate-block");
+ const { dragBlockProps } = this.getProperty(this.options);
+ setElementProperty(dragBlock, dragBlockProps);
+ this.dragBlock = dragBlock;
+ this.quill.container.appendChild(dragBlock);
+ this.updateCell(dragBlock);
+ }
+
+ createDragTable(table: Element) {
+ const dragTable = this.quill.root.ownerDocument.createElement("div");
+ const properties = this.getDragTableProperty(table);
+ dragTable.classList.add("ql-operate-drag-table");
+ setElementProperty(dragTable, properties);
+ this.dragTable = dragTable;
+ this.quill.container.appendChild(dragTable);
+ }
+
+ createOperateLine() {
+ const container = this.quill.root.ownerDocument.createElement("div");
+ const line = this.quill.root.ownerDocument.createElement("div");
+ container.classList.add("ql-operate-line-container");
+ const { containerProps, lineProps } = this.getProperty(this.options);
+ setElementProperty(container, containerProps);
+ setElementProperty(line, lineProps);
+ container.appendChild(line);
+ this.quill.container.appendChild(container);
+ this.line = container;
+ this.updateCell(container);
+ }
+
+ getCorrectCol(colgroup: TableColgroup, sum: number) {
+ let child = colgroup.children.head;
+ while (child && --sum) {
+ child = child.next;
+ }
+ return child;
+ }
+
+ getDragTableProperty(table: Element) {
+ const { left, top, width, height } = table.getBoundingClientRect();
+ const containerRect = this.quill.container.getBoundingClientRect();
+ return {
+ left: `${left - containerRect.left}px`,
+ top: `${top - containerRect.top}px`,
+ width: `${width}px`,
+ height: `${height}px`,
+ display: "block"
+ };
+ }
+
+ getLevelColSum(cell: Element) {
+ let previousNode = cell;
+ let sum = 0;
+ while (previousNode) {
+ const colspan = ~~previousNode.getAttribute("colspan") || 1;
+ sum += colspan;
+ // @ts-ignore
+ previousNode = previousNode.previousSibling;
+ }
+ return sum;
+ }
+
+ getMaxColNum(cell: Element) {
+ const cells = cell.parentElement.children;
+ let nums = 0;
+ for (const cell of cells) {
+ const colspan = ~~cell.getAttribute("colspan") || 1;
+ nums += colspan;
+ }
+ return nums;
+ }
+
+ getProperty(options: Options) {
+ const containerRect = this.quill.container.getBoundingClientRect();
+ const { tableNode, cellNode, mousePosition } = options;
+ const { clientX, clientY } = mousePosition;
+ const tableRect = tableNode.getBoundingClientRect();
+ const cellRect = cellNode.getBoundingClientRect();
+ const x = cellRect.left + cellRect.width;
+ const y = cellRect.top + cellRect.height;
+ const dragBlockProps = {
+ width: `${DRAG_BLOCK_WIDTH}px`,
+ height: `${DRAG_BLOCK_HEIGHT}px`,
+ top: `${tableRect.bottom - containerRect.top}px`,
+ left: `${tableRect.right - containerRect.left}px`,
+ display: tableRect.bottom > containerRect.bottom ? "none" : "block"
+ };
+ if (Math.abs(x - clientX) <= 5) {
+ this.direction = "level";
+ return {
+ dragBlockProps,
+ containerProps: {
+ width: `${LINE_CONTAINER_WIDTH}px`,
+ height: `${containerRect.height}px`,
+ top: "0",
+ left: `${x - containerRect.left - LINE_CONTAINER_WIDTH / 2}px`,
+ display: "flex",
+ cursor: "col-resize"
+ },
+ lineProps: {
+ width: "1px",
+ height: "100%"
+ }
+ };
+ } else if (Math.abs(y - clientY) <= 5) {
+ this.direction = "vertical";
+ return {
+ dragBlockProps,
+ containerProps: {
+ width: `${containerRect.width}px`,
+ height: `${LINE_CONTAINER_HEIGHT}px`,
+ top: `${y - containerRect.top - LINE_CONTAINER_HEIGHT / 2}px`,
+ left: "0",
+ display: "flex",
+ cursor: "row-resize"
+ },
+ lineProps: {
+ width: "100%",
+ height: "1px"
+ }
+ };
+ } else {
+ this.hideLine();
+ }
+ return { dragBlockProps };
+ }
+
+ getVerticalCells(cell: Element, rowspan: number) {
+ let row = cell.parentElement;
+ while (rowspan > 1 && row) {
+ // @ts-ignore
+ row = row.nextSibling;
+ rowspan--;
+ }
+ return row.children;
+ }
+
+ handleMouseMove(e: MouseEvent) {
+ const tableNode = (e.target as Element).closest("table");
+ const cellNode = (e.target as Element).closest("td");
+ const mousePosition = {
+ clientX: e.clientX,
+ clientY: e.clientY
+ };
+ if (!tableNode || !cellNode) {
+ if (this.line && !this.drag) {
+ this.hideLine();
+ this.hideDragBlock();
+ }
+ return;
+ }
+ const options = { tableNode, cellNode, mousePosition };
+ if (!this.line) {
+ this.options = options;
+ this.createOperateLine();
+ this.createDragBlock();
+ } else {
+ if (this.drag || !cellNode) return;
+ this.updateProperty(options);
+ }
+ }
+
+ hideDragBlock() {
+ this.dragBlock && setElementProperty(this.dragBlock, { display: "none" });
+ }
+
+ hideDragTable() {
+ this.dragTable && setElementProperty(this.dragTable, { display: "none" });
+ }
+
+ hideLine() {
+ this.line && setElementProperty(this.line, { display: "none" });
+ }
+
+ isLine(node: Element) {
+ return node.classList.contains("ql-operate-line-container");
+ }
+
+ setCellLevelRect(cell: Element, clientX: number) {
+ const { right } = cell.getBoundingClientRect();
+ const change = ~~(clientX - right);
+ const colSum = this.getLevelColSum(cell);
+ const quillCell = Quill.find(cell) as TableCell;
+ const tableBlot = quillCell?.table();
+ const colgroup = tableBlot.colgroup() as TableColgroup;
+ const bounds = tableBlot.domNode.getBoundingClientRect();
+ if (colgroup) {
+ const col = this.getCorrectCol(colgroup, colSum);
+ const nextCol = col.next;
+ const formats = col.formats()[col.statics.blotName];
+ col.domNode.setAttribute("width", `${parseFloat(formats["width"]) + change}`);
+ if (nextCol) {
+ const nextFormats = nextCol.formats()[nextCol.statics.blotName];
+ nextCol.domNode.setAttribute("width", `${parseFloat(nextFormats["width"]) - change}`);
+ }
+ } else {
+ const isLastCell = cell.nextElementSibling == null;
+ const rows = cell.parentElement.parentElement.children;
+ const preNodes: [Element, string][] = [];
+ for (const row of rows) {
+ const cells = row.children;
+ if (isLastCell) {
+ const cell = cells[cells.length - 1];
+ const { width } = cell.getBoundingClientRect();
+ preNodes.push([cell, `${~~(width + change)}`]);
+ continue;
+ }
+ let sum = 0;
+ for (const cell of cells) {
+ const colspan = ~~cell.getAttribute("colspan") || 1;
+ sum += colspan;
+ if (sum > colSum) break;
+ if (sum === colSum) {
+ const { width } = cell.getBoundingClientRect();
+ const nextCell = cell.nextElementSibling;
+ if (!nextCell) continue;
+ const { width: nextWidth } = nextCell.getBoundingClientRect();
+ preNodes.push([cell, `${~~(width + change)}`], [nextCell, `${~~(nextWidth - change)}`]);
+ }
+ }
+ }
+ for (const [node, width] of preNodes) {
+ setElementAttribute(node, { width });
+ setElementProperty(node as HTMLElement, { width: `${width}px` });
+ }
+ }
+ if (cell.nextElementSibling == null) {
+ updateTableWidth(tableBlot.domNode, bounds, change);
+ }
+ }
+
+ setCellRect(cell: Element, clientX: number, clientY: number) {
+ if (this.direction === "level") {
+ this.setCellLevelRect(cell, clientX);
+ } else if (this.direction === "vertical") {
+ this.setCellVerticalRect(cell, clientY);
+ }
+ }
+
+ setCellsRect(cell: Element, changeX: number, changeY: number) {
+ const rows = cell.parentElement.parentElement.children;
+ const maxColNum = this.getMaxColNum(cell);
+ const averageX = changeX / maxColNum;
+ const averageY = changeY / rows.length;
+ const preNodes: [Element, string, string][] = [];
+ const tableBlot = (Quill.find(cell) as TableCell).table();
+ const colgroup = tableBlot.colgroup() as TableColgroup;
+ const bounds = tableBlot.domNode.getBoundingClientRect();
+ for (const row of rows) {
+ const cells = row.children;
+ for (const cell of cells) {
+ const colspan = ~~cell.getAttribute("colspan") || 1;
+ const { width, height } = cell.getBoundingClientRect();
+ preNodes.push([cell, `${Math.ceil(width + averageX * colspan)}`, `${Math.ceil(height + averageY)}`]);
+ }
+ }
+ if (colgroup) {
+ let col = colgroup.children.head;
+ for (const [node, , height] of preNodes) {
+ setElementAttribute(node, { height });
+ setElementProperty(node as HTMLElement, { height: `${height}px` });
+ }
+ while (col) {
+ const { width } = col.domNode.getBoundingClientRect();
+ setElementAttribute(col.domNode, { width: `${Math.ceil(width + averageX)}` });
+ col = col.next;
+ }
+ } else {
+ for (const [node, width, height] of preNodes) {
+ setElementAttribute(node, { width, height });
+ setElementProperty(node as HTMLElement, {
+ width: `${width}px`,
+ height: `${height}px`
+ });
+ }
+ }
+ updateTableWidth(tableBlot.domNode, bounds, changeX);
+ }
+
+ setCellVerticalRect(cell: Element, clientY: number) {
+ const rowspan = ~~cell.getAttribute("rowspan") || 1;
+ const cells = rowspan > 1 ? this.getVerticalCells(cell, rowspan) : cell.parentElement.children;
+ for (const cell of cells) {
+ const { top } = cell.getBoundingClientRect();
+ const height = `${~~(clientY - top)}`;
+ setElementAttribute(cell, { height });
+ setElementProperty(cell as HTMLElement, { height: `${height}px` });
+ }
+ }
+
+ toggleLineChildClass(isAdd: boolean) {
+ const node = this.line.firstElementChild;
+ if (isAdd) {
+ node.classList.add("ql-operate-line");
+ } else {
+ node.classList.remove("ql-operate-line");
+ }
+ }
+
+ updateCell(node: Element) {
+ if (!node) return;
+ const isLine = this.isLine(node);
+ const handleDrag = (e: MouseEvent) => {
+ e.preventDefault();
+ if (this.drag) {
+ if (isLine) {
+ this.updateDragLine(e.clientX, e.clientY);
+ this.hideDragBlock();
+ } else {
+ this.updateDragBlock(e.clientX, e.clientY);
+ this.hideLine();
+ }
+ }
+ };
+
+ const handleMouseup = (e: MouseEvent) => {
+ e.preventDefault();
+ const { cellNode, tableNode } = this.options;
+ if (isLine) {
+ this.setCellRect(cellNode, e.clientX, e.clientY);
+ this.toggleLineChildClass(false);
+ } else {
+ const { right, bottom } = tableNode.getBoundingClientRect();
+ const changeX = e.clientX - right;
+ const changeY = e.clientY - bottom;
+ this.setCellsRect(cellNode, changeX, changeY);
+ this.dragBlock.classList.remove("ql-operate-block-move");
+ this.hideDragBlock();
+ this.hideDragTable();
+ }
+ this.drag = false;
+ window.document.removeEventListener("mousemove", handleDrag, false);
+ window.document.removeEventListener("mouseup", handleMouseup, false);
+ this.tableBetter.tableMenus.updateMenus(tableNode);
+ };
+
+ const handleMousedown = (e: MouseEvent) => {
+ e.preventDefault();
+ const { tableNode } = this.options;
+ if (isLine) {
+ this.toggleLineChildClass(true);
+ } else {
+ if (this.dragTable) {
+ const properties = this.getDragTableProperty(tableNode);
+ setElementProperty(this.dragTable, properties);
+ } else {
+ this.createDragTable(tableNode);
+ }
+ }
+ this.drag = true;
+ window.document.addEventListener("mousemove", handleDrag);
+ window.document.addEventListener("mouseup", handleMouseup);
+ };
+ node.addEventListener("mousedown", handleMousedown);
+ }
+
+ updateDragBlock(clientX: number, clientY: number) {
+ const containerRect = this.quill.container.getBoundingClientRect();
+ this.dragBlock.classList.add("ql-operate-block-move");
+ setElementProperty(this.dragBlock, {
+ top: `${~~(clientY - containerRect.top - DRAG_BLOCK_HEIGHT / 2)}px`,
+ left: `${~~(clientX - containerRect.left - DRAG_BLOCK_WIDTH / 2)}px`
+ });
+ this.updateDragTable(clientX, clientY);
+ }
+
+ updateDragLine(clientX: number, clientY: number) {
+ const containerRect = this.quill.container.getBoundingClientRect();
+ if (this.direction === "level") {
+ setElementProperty(this.line, {
+ left: `${~~(clientX - containerRect.left - LINE_CONTAINER_WIDTH / 2)}px`
+ });
+ } else if (this.direction === "vertical") {
+ setElementProperty(this.line, {
+ top: `${~~clientY - containerRect.top - LINE_CONTAINER_HEIGHT / 2}px`
+ });
+ }
+ }
+
+ updateDragTable(clientX: number, clientY: number) {
+ const { top, left } = this.dragTable.getBoundingClientRect();
+ const width = clientX - left;
+ const height = clientY - top;
+ setElementProperty(this.dragTable, {
+ width: `${width}px`,
+ height: `${height}px`,
+ display: "block"
+ });
+ }
+
+ updateProperty(options: Options) {
+ const { containerProps, lineProps, dragBlockProps } = this.getProperty(options);
+ if (!containerProps || !lineProps) return;
+ this.options = options;
+ setElementProperty(this.line, containerProps);
+ setElementProperty(this.line.firstChild as HTMLElement, lineProps);
+ setElementProperty(this.dragBlock, dragBlockProps);
+ }
+}
+
+export default OperateLine;
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/table-menus.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/table-menus.ts
new file mode 100644
index 0000000000..1fcd4622d8
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/table-menus.ts
@@ -0,0 +1,813 @@
+// @ts-nocheck
+import type { LinkedList } from "parchment";
+import Quill from "quill";
+import Delta from "quill-delta";
+import { CELL_DEFAULT_VALUES, CELL_DEFAULT_WIDTH, CELL_PROPERTIES, DEVIATION, TABLE_PROPERTIES } from "../config";
+import { TableCell, tableId } from "../formats/table";
+import type {
+ CorrectBound,
+ Props,
+ QuillTableBetter,
+ TableCellMap,
+ TableColgroup,
+ TableContainer,
+ TableRow,
+ UseLanguageHandler
+} from "../types";
+import {
+ createTooltip,
+ getAlign,
+ getCellFormats,
+ getComputeBounds,
+ getComputeSelectedCols,
+ getComputeSelectedTds,
+ getCorrectBounds,
+ getElementStyle,
+ setElementProperty,
+ updateTableWidth
+} from "../utils";
+import TablePropertiesForm from "./table-properties-form";
+
+interface Children {
+ [propName: string]: {
+ content: string;
+ handler: () => void;
+ };
+}
+
+interface MenusDefaults {
+ [propName: string]: {
+ content: string;
+ icon: string;
+ handler: (list: HTMLUListElement, tooltip: HTMLDivElement) => void;
+ children?: Children;
+ };
+}
+
+enum Alignment {
+ left = "margin-left",
+ right = "margin-right"
+}
+
+function getMenusConfig(useLanguage: UseLanguageHandler, menus?: string[]): MenusDefaults {
+ const DEFAULT: MenusDefaults = {
+ column: {
+ content: useLanguage("col"),
+ icon: "icons icon-Column",
+ handler(list: HTMLUListElement, tooltip: HTMLDivElement) {
+ this.toggleAttribute(list, tooltip);
+ },
+ children: {
+ left: {
+ content: useLanguage("insColL"),
+ handler() {
+ const { leftTd } = this.getSelectedTdsInfo();
+ const bounds = this.table.getBoundingClientRect();
+ this.insertColumn(leftTd, 0);
+ updateTableWidth(this.table, bounds, CELL_DEFAULT_WIDTH);
+ this.updateMenus();
+ }
+ },
+ right: {
+ content: useLanguage("insColR"),
+ handler() {
+ const { rightTd } = this.getSelectedTdsInfo();
+ const bounds = this.table.getBoundingClientRect();
+ this.insertColumn(rightTd, 1);
+ updateTableWidth(this.table, bounds, CELL_DEFAULT_WIDTH);
+ this.updateMenus();
+ }
+ },
+ delete: {
+ content: useLanguage("delCol"),
+ handler() {
+ this.deleteColumn();
+ }
+ }
+ }
+ },
+ row: {
+ content: useLanguage("row"),
+ icon: "icons icon-Row",
+ handler(list: HTMLUListElement, tooltip: HTMLDivElement) {
+ this.toggleAttribute(list, tooltip);
+ },
+ children: {
+ above: {
+ content: useLanguage("insRowAbv"),
+ handler() {
+ const { leftTd } = this.getSelectedTdsInfo();
+ this.insertRow(leftTd, 0);
+ this.updateMenus();
+ }
+ },
+ below: {
+ content: useLanguage("insRowBlw"),
+ handler() {
+ const { rightTd } = this.getSelectedTdsInfo();
+ this.insertRow(rightTd, 1);
+ this.updateMenus();
+ }
+ },
+ delete: {
+ content: useLanguage("delRow"),
+ handler() {
+ this.deleteRow();
+ }
+ }
+ }
+ },
+ merge: {
+ content: useLanguage("mCells"),
+ icon: "icons icon-Merge",
+ handler(list: HTMLUListElement, tooltip: HTMLDivElement) {
+ this.toggleAttribute(list, tooltip);
+ },
+ children: {
+ merge: {
+ content: useLanguage("mCells"),
+ handler() {
+ this.mergeCells();
+ this.updateMenus();
+ }
+ },
+ split: {
+ content: useLanguage("sCell"),
+ handler() {
+ this.splitCell();
+ this.updateMenus();
+ }
+ }
+ }
+ },
+ table: {
+ content: useLanguage("tblProps"),
+ icon: "icons icon-Table",
+ handler(list: HTMLUListElement, tooltip: HTMLDivElement) {
+ const attribute = {
+ ...getElementStyle(this.table, TABLE_PROPERTIES),
+ align: this.getTableAlignment(this.table)
+ };
+ this.toggleAttribute(list, tooltip);
+ this.tablePropertiesForm = new TablePropertiesForm(this, { attribute, type: "table" });
+ this.hideMenus();
+ }
+ },
+ cell: {
+ content: useLanguage("cellProps"),
+ icon: "icons icon-Cell",
+ handler(list: HTMLUListElement, tooltip: HTMLDivElement) {
+ const { selectedTds } = this.tableBetter.cellSelection;
+ const attribute =
+ selectedTds.length > 1
+ ? this.getSelectedTdsAttrs(selectedTds)
+ : this.getSelectedTdAttrs(selectedTds[0]);
+ this.toggleAttribute(list, tooltip);
+ this.tablePropertiesForm = new TablePropertiesForm(this, { attribute, type: "cell" });
+ this.hideMenus();
+ }
+ },
+ wrap: {
+ content: useLanguage("insParaOTbl"),
+ icon: "icons icon-Wrap",
+ handler(list: HTMLUListElement, tooltip: HTMLDivElement) {
+ this.toggleAttribute(list, tooltip);
+ },
+ children: {
+ before: {
+ content: useLanguage("insB4"),
+ handler() {
+ this.insertParagraph(-1);
+ }
+ },
+ after: {
+ content: useLanguage("insAft"),
+ handler() {
+ this.insertParagraph(1);
+ }
+ }
+ }
+ },
+ delete: {
+ content: useLanguage("delTable"),
+ icon: "icons icon-Delete",
+ handler() {
+ this.deleteTable();
+ }
+ }
+ };
+ const EXTRA: MenusDefaults = {
+ copy: {
+ content: useLanguage("copyTable"),
+ icon: "icons icon-Copy",
+ handler() {
+ this.copyTable();
+ }
+ }
+ };
+ if (menus?.length) {
+ return Object.values(menus).reduce((config: MenusDefaults, key: string) => {
+ config[key] = Object.assign({}, DEFAULT, EXTRA)[key];
+ return config;
+ }, {});
+ }
+ return DEFAULT;
+}
+
+class TableMenus {
+ quill: Quill;
+ table: HTMLElement | null;
+ root: HTMLElement;
+ prevList: HTMLUListElement | null;
+ prevTooltip: HTMLDivElement | null;
+ scroll: boolean;
+ tableBetter: QuillTableBetter;
+ tablePropertiesForm: TablePropertiesForm;
+ constructor(quill: Quill, tableBetter?: QuillTableBetter) {
+ this.quill = quill;
+ this.table = null;
+ this.prevList = null;
+ this.prevTooltip = null;
+ this.scroll = false;
+ this.tableBetter = tableBetter;
+ this.tablePropertiesForm = null;
+ this.quill.root.addEventListener("click", this.handleClick.bind(this));
+ this.root = this.createMenus();
+ }
+
+ async copyTable() {
+ if (!this.table) return;
+ const tableBlot = Quill.find(this.table) as TableContainer;
+ if (!tableBlot) return;
+ const html = "
" + tableBlot.getCopyTable();
+ const text = this.tableBetter.cellSelection.getText(html);
+ const clipboardItem = new ClipboardItem({
+ "text/html": new Blob([html], { type: "text/html" }),
+ "text/plain": new Blob([text], { type: "text/plain" })
+ });
+ try {
+ await navigator.clipboard.write([clipboardItem]);
+ const index = this.quill.getIndex(tableBlot);
+ const length = tableBlot.length();
+ this.quill.setSelection(index + length, Quill.sources.SILENT);
+ this.tableBetter.hideTools();
+ this.quill.scrollSelectionIntoView();
+ } catch (error) {
+ console.error("Failed to copy table:", error);
+ }
+ }
+
+ createList(children: Children) {
+ if (!children) return null;
+ const container = this.quill.root.ownerDocument.createElement("ul");
+ for (const [, child] of Object.entries(children)) {
+ const { content, handler } = child;
+ const list = this.quill.root.ownerDocument.createElement("li");
+ list.innerText = content;
+ list.addEventListener("click", handler.bind(this));
+ container.appendChild(list);
+ }
+ container.classList.add("ql-table-dropdown-list", "ql-hidden");
+ return container;
+ }
+
+ createMenu(left: string, right: string, isDropDown: boolean) {
+ const container = this.quill.root.ownerDocument.createElement("div");
+ container.classList.add("ql-table-dropdown");
+ const dropDown = this.quill.root.ownerDocument.createElement("span");
+ dropDown.classList.add("ql-table-tooltip-hover");
+ const classes = left.split(" ");
+ const icon = this.quill.root.ownerDocument.createElement("span");
+ icon.classList.add(...classes);
+ dropDown.appendChild(icon);
+ if (isDropDown) {
+ const classes = right.split(" ");
+ const dropDownIcon = this.quill.root.ownerDocument.createElement("span");
+ dropDownIcon.classList.add(...classes);
+ dropDown.appendChild(dropDownIcon);
+ }
+ container.appendChild(dropDown);
+ return container;
+ }
+
+ createMenus() {
+ const { language, options = {} } = this.tableBetter;
+ const { menus } = options;
+ const useLanguage = language.useLanguage.bind(language);
+ const container = this.quill.root.ownerDocument.createElement("div");
+ container.classList.add("ql-table-menus-container", "ql-hidden");
+ for (const [, val] of Object.entries(getMenusConfig(useLanguage, menus))) {
+ const { content, icon, children, handler } = val;
+ const list = this.createList(children);
+ const tooltip = createTooltip(content);
+ const menu = this.createMenu(icon, "icons icon-Arrow-down", !!children);
+ menu.appendChild(tooltip);
+ list && menu.appendChild(list);
+ container.appendChild(menu);
+ menu.addEventListener("click", handler.bind(this, list, tooltip));
+ }
+ this.quill.container.appendChild(container);
+ return container;
+ }
+
+ deleteColumn(isKeyboard: boolean = false) {
+ const { computeBounds, leftTd, rightTd } = this.getSelectedTdsInfo();
+ const bounds = this.table.getBoundingClientRect();
+ const deleteTds = getComputeSelectedTds(computeBounds, this.table, this.quill.container, "column");
+ const deleteCols = getComputeSelectedCols(computeBounds, this.table, this.quill.container);
+ const tableBlot = (Quill.find(leftTd) as TableCell).table();
+ const { changeTds, delTds } = this.getCorrectTds(deleteTds, computeBounds, leftTd, rightTd);
+ if (isKeyboard && delTds.length !== this.tableBetter.cellSelection.selectedTds.length) return;
+ this.tableBetter.cellSelection.updateSelected("column");
+ tableBlot.deleteColumn(changeTds, delTds, this.deleteTable.bind(this), deleteCols);
+ updateTableWidth(this.table, bounds, computeBounds.left - computeBounds.right);
+ this.updateMenus();
+ }
+
+ deleteRow(isKeyboard: boolean = false) {
+ const selectedTds = this.tableBetter.cellSelection.selectedTds;
+ const map: { [propName: string]: TableRow } = {};
+ for (const td of selectedTds) {
+ let rowspan = ~~td.getAttribute("rowspan") || 1;
+ let row = Quill.find(td.parentElement) as TableRow;
+ if (rowspan > 1) {
+ while (row && rowspan) {
+ const id = row.children.head.domNode.getAttribute("data-row");
+ if (!map[id]) map[id] = row;
+ row = row.next;
+ rowspan--;
+ }
+ } else {
+ const id = td.getAttribute("data-row");
+ if (!map[id]) map[id] = row;
+ }
+ }
+ const rows: TableRow[] = Object.values(map);
+ if (isKeyboard) {
+ const sum = rows.reduce((sum: number, row: TableRow) => {
+ return (sum += row.children.length);
+ }, 0);
+ if (sum !== selectedTds.length) return;
+ }
+ this.tableBetter.cellSelection.updateSelected("row");
+ const tableBlot = (Quill.find(selectedTds[0]) as TableCell).table();
+ tableBlot.deleteRow(rows, this.deleteTable.bind(this));
+ this.updateMenus();
+ }
+
+ deleteTable() {
+ const tableBlot = Quill.find(this.table) as TableContainer;
+ if (!tableBlot) return;
+ const offset = tableBlot.offset(this.quill.scroll);
+ tableBlot.remove();
+ this.tableBetter.hideTools();
+ this.quill.setSelection(offset - 1, 0, Quill.sources.USER);
+ }
+
+ destroyTablePropertiesForm() {
+ if (!this.tablePropertiesForm) return;
+ this.tablePropertiesForm.removePropertiesForm();
+ this.tablePropertiesForm = null;
+ }
+
+ getCellsOffset(computeBounds: CorrectBound, bounds: CorrectBound, leftColspan: number, rightColspan: number) {
+ const tableBlot = Quill.find(this.table) as TableContainer;
+ const cells = tableBlot.descendants(TableCell);
+ const _left = Math.max(bounds.left, computeBounds.left);
+ const _right = Math.min(bounds.right, computeBounds.right);
+ const map: TableCellMap = new Map();
+ const leftMap: TableCellMap = new Map();
+ const rightMap: TableCellMap = new Map();
+ for (const cell of cells) {
+ const { left, right } = getCorrectBounds(cell.domNode, this.quill.container);
+ if (left + DEVIATION >= _left && right <= _right + DEVIATION) {
+ this.setCellsMap(cell, map);
+ } else if (left + DEVIATION >= computeBounds.left && right <= bounds.left + DEVIATION) {
+ this.setCellsMap(cell, leftMap);
+ } else if (left + DEVIATION >= bounds.right && right <= computeBounds.right + DEVIATION) {
+ this.setCellsMap(cell, rightMap);
+ }
+ }
+ return (
+ this.getDiffOffset(map) ||
+ this.getDiffOffset(leftMap, leftColspan) + this.getDiffOffset(rightMap, rightColspan)
+ );
+ }
+
+ getColsOffset(colgroup: TableColgroup, computeBounds: CorrectBound, bounds: CorrectBound) {
+ let col = colgroup.children.head;
+ const _left = Math.max(bounds.left, computeBounds.left);
+ const _right = Math.min(bounds.right, computeBounds.right);
+ let colLeft = null;
+ let colRight = null;
+ let offset = 0;
+ while (col) {
+ const { width } = col.domNode.getBoundingClientRect();
+ if (!colLeft && !colRight) {
+ const colBounds = getCorrectBounds(col.domNode, this.quill.container);
+ colLeft = colBounds.left;
+ colRight = colLeft + width;
+ } else {
+ colLeft = colRight;
+ colRight += width;
+ }
+ if (colLeft > _right) break;
+ if (colLeft >= _left && colRight <= _right) {
+ offset--;
+ }
+ col = col.next;
+ }
+ return offset;
+ }
+
+ getCorrectBounds(table: HTMLElement): CorrectBound[] {
+ const bounds = this.quill.container.getBoundingClientRect();
+ const tableBounds = getCorrectBounds(table, this.quill.container);
+ return tableBounds.width >= bounds.width
+ ? [{ ...tableBounds, left: 0, right: bounds.width }, bounds]
+ : [tableBounds, bounds];
+ }
+
+ getCorrectTds(deleteTds: Element[], computeBounds: CorrectBound, leftTd: Element, rightTd: Element) {
+ const changeTds: [Element, number][] = [];
+ const delTds = [];
+ const colgroup = (Quill.find(leftTd) as TableCell).table().colgroup() as TableColgroup;
+ const leftColspan = ~~leftTd.getAttribute("colspan") || 1;
+ const rightColspan = ~~rightTd.getAttribute("colspan") || 1;
+ if (colgroup) {
+ for (const td of deleteTds) {
+ const bounds = getCorrectBounds(td, this.quill.container);
+ if (bounds.left + DEVIATION >= computeBounds.left && bounds.right <= computeBounds.right + DEVIATION) {
+ delTds.push(td);
+ } else {
+ const offset = this.getColsOffset(colgroup, computeBounds, bounds);
+ changeTds.push([td, offset]);
+ }
+ }
+ } else {
+ for (const td of deleteTds) {
+ const bounds = getCorrectBounds(td, this.quill.container);
+ if (bounds.left + DEVIATION >= computeBounds.left && bounds.right <= computeBounds.right + DEVIATION) {
+ delTds.push(td);
+ } else {
+ const offset = this.getCellsOffset(computeBounds, bounds, leftColspan, rightColspan);
+ changeTds.push([td, offset]);
+ }
+ }
+ }
+ return { changeTds, delTds };
+ }
+
+ getDiffOffset(map: TableCellMap, colspan?: number) {
+ let offset = 0;
+ const tds = this.getTdsFromMap(map);
+ if (tds.length) {
+ if (colspan) {
+ for (const td of tds) {
+ offset += ~~td.getAttribute("colspan") || 1;
+ }
+ offset -= colspan;
+ } else {
+ for (const td of tds) {
+ offset -= ~~td.getAttribute("colspan") || 1;
+ }
+ }
+ }
+ return offset;
+ }
+
+ getRefInfo(row: TableRow, right: number) {
+ let ref = null;
+ if (!row) return { id: tableId(), ref };
+ let td = row.children.head;
+ const id = td.domNode.getAttribute("data-row");
+ while (td) {
+ const { left } = td.domNode.getBoundingClientRect();
+ if (Math.abs(left - right) <= DEVIATION) {
+ return { id, ref: td };
+ // The nearest cell of a multi-row cell
+ } else if (Math.abs(left - right) >= DEVIATION && !ref) {
+ ref = td;
+ }
+ td = td.next;
+ }
+ return { id, ref };
+ }
+
+ getSelectedTdAttrs(td: HTMLElement) {
+ const cellBlot = Quill.find(td) as TableCell;
+ const align = getAlign(cellBlot);
+ const attr: Props = align
+ ? { ...getElementStyle(td, CELL_PROPERTIES), "text-align": align }
+ : getElementStyle(td, CELL_PROPERTIES);
+ return attr;
+ }
+
+ getSelectedTdsAttrs(selectedTds: HTMLElement[]) {
+ const map = new Map();
+ let attribute = null;
+ for (const td of selectedTds) {
+ const attr = this.getSelectedTdAttrs(td);
+ if (!attribute) {
+ attribute = attr;
+ continue;
+ }
+ for (const key of Object.keys(attribute)) {
+ if (map.has(key)) continue;
+ if (attr[key] !== attribute[key]) {
+ map.set(key, false);
+ }
+ }
+ }
+ for (const key of Object.keys(attribute)) {
+ if (map.has(key)) {
+ attribute[key] = CELL_DEFAULT_VALUES[key];
+ }
+ }
+ return attribute;
+ }
+
+ getSelectedTdsInfo() {
+ const { startTd, endTd } = this.tableBetter.cellSelection;
+ const startCorrectBounds = getCorrectBounds(startTd, this.quill.container);
+ const endCorrectBounds = getCorrectBounds(endTd, this.quill.container);
+ const computeBounds = getComputeBounds(startCorrectBounds, endCorrectBounds);
+ if (startCorrectBounds.left <= endCorrectBounds.left && startCorrectBounds.top <= endCorrectBounds.top) {
+ return {
+ computeBounds,
+ leftTd: startTd,
+ rightTd: endTd
+ };
+ }
+ return {
+ computeBounds,
+ leftTd: endTd,
+ rightTd: startTd
+ };
+ }
+
+ getTableAlignment(table: HTMLTableElement) {
+ const align = table.getAttribute("align");
+ if (!align) {
+ const { [Alignment.left]: left, [Alignment.right]: right } = getElementStyle(table, [
+ Alignment.left,
+ Alignment.right
+ ]);
+ if (left === "auto") {
+ if (right === "auto") return "center";
+ return "right";
+ }
+ return "left";
+ }
+ return align || "center";
+ }
+
+ getTdsFromMap(map: TableCellMap) {
+ return Object.values(Object.fromEntries(map)).reduce(
+ (tds: HTMLTableCellElement[], item: HTMLTableCellElement[]) => {
+ return tds.length > item.length ? tds : item;
+ },
+ []
+ );
+ }
+
+ handleClick(e: MouseEvent) {
+ const table = (e.target as Element).closest("table");
+ this.prevList && this.prevList.classList.add("ql-hidden");
+ this.prevTooltip && this.prevTooltip.classList.remove("ql-table-tooltip-hidden");
+ this.prevList = null;
+ this.prevTooltip = null;
+ if (!table && !this.tableBetter.cellSelection.selectedTds.length) {
+ this.hideMenus();
+ this.destroyTablePropertiesForm();
+ return;
+ } else {
+ if (this.tablePropertiesForm) return;
+ this.showMenus();
+ this.updateMenus(table);
+ if ((table && !table.isEqualNode(this.table)) || this.scroll) {
+ this.updateScroll(false);
+ }
+ this.table = table;
+ }
+ }
+
+ hideMenus() {
+ this.root.classList.add("ql-hidden");
+ }
+
+ insertColumn(td: HTMLTableColElement, offset: number) {
+ const { left, right, width } = td.getBoundingClientRect();
+ const tdBlot = Quill.find(td) as TableCell;
+ const tableBlot = tdBlot.table();
+ const isLast = td.parentElement.lastChild.isEqualNode(td);
+ const position = offset > 0 ? right : left;
+ tableBlot.insertColumn(position, isLast, width, offset);
+ this.quill.scrollSelectionIntoView();
+ }
+
+ insertParagraph(offset: number) {
+ const blot = Quill.find(this.table) as TableContainer;
+ const index = this.quill.getIndex(blot);
+ const length = offset > 0 ? blot.length() : 0;
+ const delta = new Delta().retain(index + length).insert("\n");
+ this.quill.updateContents(delta, Quill.sources.USER);
+ this.quill.setSelection(index + length, Quill.sources.SILENT);
+ this.tableBetter.hideTools();
+ this.quill.scrollSelectionIntoView();
+ }
+
+ insertRow(td: HTMLTableColElement, offset: number) {
+ const tdBlot = Quill.find(td) as TableCell;
+ const index = tdBlot.rowOffset();
+ const tableBlot = tdBlot.table();
+ if (offset > 0) {
+ const rowspan = ~~td.getAttribute("rowspan") || 1;
+ tableBlot.insertRow(index + offset + rowspan - 1, offset);
+ } else {
+ tableBlot.insertRow(index + offset, offset);
+ }
+ this.quill.scrollSelectionIntoView();
+ }
+
+ mergeCells() {
+ const { selectedTds } = this.tableBetter.cellSelection;
+ const { computeBounds, leftTd } = this.getSelectedTdsInfo();
+ const leftTdBlot = Quill.find(leftTd) as TableCell;
+ const [formats, cellId] = getCellFormats(leftTdBlot);
+ const head = leftTdBlot.children.head;
+ const tableBlot = leftTdBlot.table();
+ const rows = tableBlot.tbody().children as LinkedList;
+ const row = leftTdBlot.row();
+ const colspan = row.children.reduce((colspan: number, td: TableCell) => {
+ const tdCorrectBounds = getCorrectBounds(td.domNode, this.quill.container);
+ if (tdCorrectBounds.left >= computeBounds.left && tdCorrectBounds.right <= computeBounds.right) {
+ colspan += ~~td.domNode.getAttribute("colspan") || 1;
+ }
+ return colspan;
+ }, 0);
+ const rowspan = rows.reduce((rowspan: number, row: TableRow) => {
+ const rowCorrectBounds = getCorrectBounds(row.domNode, this.quill.container);
+ if (rowCorrectBounds.top >= computeBounds.top && rowCorrectBounds.bottom <= computeBounds.bottom) {
+ let minRowspan = Number.MAX_VALUE;
+ row.children.forEach((td: TableCell) => {
+ const rowspan = ~~td.domNode.getAttribute("rowspan") || 1;
+ minRowspan = Math.min(minRowspan, rowspan);
+ });
+ rowspan += minRowspan;
+ }
+ return rowspan;
+ }, 0);
+ let offset = 0;
+ for (const td of selectedTds) {
+ if (leftTd.isEqualNode(td)) continue;
+ const blot = Quill.find(td) as TableCell;
+ blot.moveChildren(leftTdBlot);
+ blot.remove();
+ if (!blot.parent?.children?.length) offset++;
+ }
+ if (offset) {
+ // Subtract the number of rows deleted by the merge
+ row.children.forEach((child: TableCell) => {
+ if (child.domNode.isEqualNode(leftTd)) return;
+ const rowspan = child.domNode.getAttribute("rowspan");
+ const [formats] = getCellFormats(child);
+ // @ts-expect-error
+ child.replaceWith(child.statics.blotName, { ...formats, rowspan: rowspan - offset });
+ });
+ }
+ leftTdBlot.setChildrenId(cellId);
+ // @ts-expect-error
+ head.format(leftTdBlot.statics.blotName, { ...formats, colspan, rowspan: rowspan - offset });
+ this.tableBetter.cellSelection.setSelected(head.parent.domNode);
+ this.quill.scrollSelectionIntoView();
+ }
+
+ setCellsMap(cell: TableCell, map: TableCellMap) {
+ const key: string = cell.domNode.getAttribute("data-row");
+ if (map.has(key)) {
+ map.set(key, [...map.get(key), cell.domNode]);
+ } else {
+ map.set(key, [cell.domNode]);
+ }
+ }
+
+ showMenus() {
+ this.root.classList.remove("ql-hidden");
+ }
+
+ splitCell() {
+ const { selectedTds } = this.tableBetter.cellSelection;
+ const { leftTd } = this.getSelectedTdsInfo();
+ const leftTdBlot = Quill.find(leftTd) as TableCell;
+ const head = leftTdBlot.children.head;
+ for (const td of selectedTds) {
+ const colspan = ~~td.getAttribute("colspan") || 1;
+ const rowspan = ~~td.getAttribute("rowspan") || 1;
+ if (colspan === 1 && rowspan === 1) continue;
+ const columnCells: [TableRow, string, TableCell | null][] = [];
+ const { width, right } = td.getBoundingClientRect();
+ const blot = Quill.find(td) as TableCell;
+ const tableBlot = blot.table();
+ const nextBlot = blot.next;
+ const rowBlot = blot.row();
+ if (rowspan > 1) {
+ if (colspan > 1) {
+ let nextRowBlot = rowBlot.next;
+ for (let i = 1; i < rowspan; i++) {
+ const { ref, id } = this.getRefInfo(nextRowBlot, right);
+ for (let j = 0; j < colspan; j++) {
+ columnCells.push([nextRowBlot, id, ref]);
+ }
+ nextRowBlot && (nextRowBlot = nextRowBlot.next);
+ }
+ } else {
+ let nextRowBlot = rowBlot.next;
+ for (let i = 1; i < rowspan; i++) {
+ const { ref, id } = this.getRefInfo(nextRowBlot, right);
+ columnCells.push([nextRowBlot, id, ref]);
+ nextRowBlot && (nextRowBlot = nextRowBlot.next);
+ }
+ }
+ }
+ if (colspan > 1) {
+ const id = td.getAttribute("data-row");
+ for (let i = 1; i < colspan; i++) {
+ columnCells.push([rowBlot, id, nextBlot]);
+ }
+ }
+ for (const [row, id, ref] of columnCells) {
+ tableBlot.insertColumnCell(row, id, ref);
+ }
+ const [formats] = getCellFormats(blot);
+ blot.replaceWith(blot.statics.blotName, {
+ ...formats,
+ width: ~~(width / colspan),
+ colspan: null,
+ rowspan: null
+ });
+ }
+ this.tableBetter.cellSelection.setSelected(head.parent.domNode);
+ this.quill.scrollSelectionIntoView();
+ }
+
+ toggleAttribute(list: HTMLUListElement, tooltip: HTMLDivElement) {
+ if (this.prevList && !this.prevList.isEqualNode(list)) {
+ this.prevList.classList.add("ql-hidden");
+ this.prevTooltip.classList.remove("ql-table-tooltip-hidden");
+ }
+ if (!list) return;
+ list.classList.toggle("ql-hidden");
+ tooltip.classList.toggle("ql-table-tooltip-hidden");
+ this.prevList = list;
+ this.prevTooltip = tooltip;
+ }
+
+ updateMenus(table: HTMLElement = this.table) {
+ if (!table) return;
+ requestAnimationFrame(() => {
+ this.root.classList.remove("ql-table-triangle-none");
+ const [tableBounds, containerBounds] = this.getCorrectBounds(table);
+ const { left, right, top, bottom } = tableBounds;
+ const { height, width } = this.root.getBoundingClientRect();
+ const toolbar = this.quill.getModule("toolbar");
+ // @ts-expect-error
+ const computedStyle = getComputedStyle(toolbar.container);
+ let correctTop = top - height - 10;
+ let correctLeft = (left + right - width) >> 1;
+ if (correctTop > -parseInt(computedStyle.paddingBottom)) {
+ this.root.classList.add("ql-table-triangle-up");
+ this.root.classList.remove("ql-table-triangle-down");
+ } else {
+ if (bottom > containerBounds.height) {
+ correctTop = containerBounds.height + 10;
+ } else {
+ correctTop = bottom + 10;
+ }
+ this.root.classList.add("ql-table-triangle-down");
+ this.root.classList.remove("ql-table-triangle-up");
+ }
+ if (correctLeft < containerBounds.left) {
+ correctLeft = 0;
+ this.root.classList.add("ql-table-triangle-none");
+ } else if (correctLeft + width > containerBounds.right) {
+ correctLeft = containerBounds.right - width;
+ this.root.classList.add("ql-table-triangle-none");
+ }
+ setElementProperty(this.root, {
+ left: `${correctLeft}px`,
+ top: `${correctTop}px`
+ });
+ });
+ }
+
+ updateScroll(scroll: boolean) {
+ this.scroll = scroll;
+ }
+
+ updateTable(table: HTMLElement) {
+ this.table = table;
+ }
+}
+
+export default TableMenus;
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/table-properties-form.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/table-properties-form.ts
new file mode 100644
index 0000000000..9a78337fd6
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/table-properties-form.ts
@@ -0,0 +1,610 @@
+import { computePosition, flip, offset, shift } from "@floating-ui/react";
+import Coloris from "@melloware/coloris";
+import "@melloware/coloris/dist/coloris.css";
+import Quill from "quill";
+import { getProperties } from "../config";
+import { ListContainer } from "../formats/list";
+import type { Props, TableCell, TableCellBlock, TableContainer, TableHeader, TableList, TableMenus } from "../types";
+import {
+ addDimensionsUnit,
+ createTooltip,
+ getClosestElement,
+ getComputeSelectedCols,
+ isDimensions,
+ setElementAttribute,
+ setElementProperty
+} from "../utils";
+
+interface Child {
+ category: string;
+ propertyName: string;
+ value?: string;
+ attribute?: Props;
+ options?: string[];
+ tooltip?: string;
+ menus?: Menus[];
+ valid?: (value?: string) => boolean;
+ message?: string;
+}
+
+interface Menus {
+ icon: string;
+ describe: string;
+ align: string;
+}
+
+interface Properties {
+ content: string;
+ children: Child[];
+}
+
+interface Options {
+ type: "table" | "cell";
+ attribute: Props;
+}
+
+interface ColorList {
+ value: string;
+ describe: string;
+}
+
+const ACTION_LIST = [
+ { icon: "icons icon-Save", label: "save" },
+ { icon: "icons icon-Close", label: "cancel" }
+];
+
+const COLOR_LIST: ColorList[] = [
+ { value: "#000000", describe: "black" },
+ { value: "#4d4d4d", describe: "dimGrey" },
+ { value: "#808080", describe: "grey" },
+ { value: "#e6e6e6", describe: "lightGrey" },
+ { value: "#ffffff", describe: "white" },
+ { value: "#ff0000", describe: "red" },
+ { value: "#ffa500", describe: "orange" },
+ { value: "#ffff00", describe: "yellow" },
+ { value: "#99e64d", describe: "lightGreen" },
+ { value: "#008000", describe: "green" },
+ { value: "#7fffd4", describe: "aquamarine" },
+ { value: "#40e0d0", describe: "turquoise" },
+ { value: "#4d99e6", describe: "lightBlue" },
+ { value: "#0000ff", describe: "blue" },
+ { value: "#800080", describe: "purple" }
+];
+
+class TablePropertiesForm {
+ tableMenus: TableMenus;
+ options: Options;
+ attrs: Props;
+ borderForm: HTMLElement[];
+ saveButton: HTMLButtonElement | null;
+ form: HTMLDivElement;
+ constructor(tableMenus: TableMenus, options: Options) {
+ this.tableMenus = tableMenus;
+ this.options = options;
+ this.attrs = { ...options.attribute };
+ this.borderForm = [];
+ this.saveButton = null;
+ this.form = this.createPropertiesForm(options);
+ }
+
+ checkBtnsAction(status: string) {
+ if (status === "save") {
+ this.saveAction(this.options.type);
+ }
+ this.removePropertiesForm();
+ this.tableMenus.showMenus();
+ this.tableMenus.updateMenus();
+ }
+
+ createActionBtns(listener: EventListener, showLabel: boolean) {
+ const useLanguage = this.getUseLanguage();
+ const ownerDocument = this.tableMenus.quill.root.ownerDocument;
+ const container = ownerDocument.createElement("div");
+ const fragment = ownerDocument.createDocumentFragment();
+ container.classList.add("properties-form-action-row");
+ for (const { icon, label } of ACTION_LIST) {
+ const button = ownerDocument.createElement("button");
+ const iconContainer = ownerDocument.createElement("span");
+ const iconClasses = icon.split(" ");
+ iconContainer.classList.add(...iconClasses);
+ button.appendChild(iconContainer);
+ setElementAttribute(button, { label });
+ if (showLabel) {
+ const labelContainer = ownerDocument.createElement("span");
+ labelContainer.innerText = useLanguage(label);
+ button.appendChild(labelContainer);
+ }
+ fragment.appendChild(button);
+ }
+ container.addEventListener("click", e => listener(e));
+ container.appendChild(fragment);
+ return container;
+ }
+
+ createCheckBtns(child: Child) {
+ const { menus, propertyName } = child;
+ const ownerDocument = this.tableMenus.quill.root.ownerDocument;
+ const container = ownerDocument.createElement("div");
+ const fragment = ownerDocument.createDocumentFragment();
+ for (const { icon, describe, align } of menus ?? []) {
+ const container = ownerDocument.createElement("span");
+ const iconContainer = ownerDocument.createElement("span");
+ const iconClasses = icon.split(" ");
+ iconContainer.classList.add(...iconClasses);
+ container.appendChild(iconContainer);
+ container.setAttribute("data-align", align);
+ container.classList.add("ql-table-tooltip-hover");
+ if (this.options.attribute[propertyName] === align) {
+ container.classList.add("ql-table-btns-checked");
+ }
+ const tooltip = createTooltip(describe);
+ container.appendChild(tooltip);
+ fragment.appendChild(container);
+ }
+ container.classList.add("ql-table-check-container");
+ container.appendChild(fragment);
+ container.addEventListener("click", e => {
+ const target: HTMLSpanElement | null = (e.target as HTMLElement).closest("span.ql-table-tooltip-hover");
+ const value = target?.getAttribute("data-align");
+ this.switchButton(container, target!);
+ this.setAttribute(propertyName, value ?? "");
+ });
+ return container;
+ }
+
+ createColorContainer(child: Child) {
+ const container = this.tableMenus.quill.root.ownerDocument.createElement("div");
+ container.classList.add("ql-table-color-container");
+ const input = this.createColorInput(child);
+ this.createColorPicker(child, input.querySelector("input"));
+ container.appendChild(input);
+ return container;
+ }
+
+ createColorInput(child: Child) {
+ const { attribute, value } = child;
+ const ownerDocument = this.tableMenus.quill.root.ownerDocument;
+ const placeholder = attribute?.placeholder ?? "";
+ const container = ownerDocument.createElement("div");
+ container.classList.add("label-field-view", "label-field-view-color");
+ const label = ownerDocument.createElement("label");
+ label.innerText = placeholder;
+ const input = ownerDocument.createElement("input");
+ setElementAttribute(input, attribute!);
+ input.classList.add("property-input");
+ input.value = value ?? "";
+
+ container.appendChild(input);
+ container.appendChild(label);
+ return container;
+ }
+
+ createColorPicker(child: Child, input: HTMLInputElement | null): void {
+ if (input) {
+ const { propertyName } = child;
+ Coloris.init();
+ Coloris({
+ // a11y: {},
+ el: input,
+ clearButton: true,
+ closeButton: true,
+ onChange: (color: string): void => {
+ this.setAttribute(propertyName, color);
+ },
+ swatches: COLOR_LIST.map(({ value }) => value),
+ theme: "polaroid"
+ });
+ }
+ }
+
+ createDropdown(value: string, category?: string) {
+ const ownerDocument = this.tableMenus.quill.root.ownerDocument;
+ const container = ownerDocument.createElement("div");
+ const dropIcon = ownerDocument.createElement("span");
+ const dropText = ownerDocument.createElement("span");
+ switch (category) {
+ case "dropdown":
+ dropIcon.classList.add("icons", "icon-Arrow-down", "ql-table-dropdown-icon");
+ break;
+ case "color":
+ break;
+ default:
+ break;
+ }
+ value && (dropText.innerText = value);
+ container.classList.add("ql-table-dropdown-properties");
+ dropText.classList.add("ql-table-dropdown-text");
+ container.appendChild(dropText);
+ container.appendChild(dropIcon);
+ return { dropdown: container, dropText };
+ }
+
+ createInput(child: Child) {
+ const { attribute, message, propertyName, valid, value } = child;
+ const ownerDocument = this.tableMenus.quill.root.ownerDocument;
+ const placeholder = attribute?.placeholder ?? "";
+ const container = ownerDocument.createElement("div");
+ const wrapper = ownerDocument.createElement("div");
+ const label = ownerDocument.createElement("label");
+ const input = ownerDocument.createElement("input");
+ const status = ownerDocument.createElement("div");
+ container.classList.add("label-field-view");
+ wrapper.classList.add("label-field-view-input-wrapper");
+ label.innerText = placeholder;
+ setElementAttribute(input, attribute!);
+ input.classList.add("property-input");
+ input.value = value ?? "";
+ input.addEventListener("input", e => {
+ const value = (e.target as HTMLInputElement).value;
+ valid && this.switchHidden(status, valid(value));
+ this.updateInputStatus(wrapper, !valid?.(value));
+ this.setAttribute(propertyName, value, container);
+ });
+ status.classList.add("label-field-view-status", "ql-hidden");
+ message && (status.innerText = message);
+ wrapper.appendChild(input);
+ wrapper.appendChild(label);
+ container.appendChild(wrapper);
+ valid && container.appendChild(status);
+ return container;
+ }
+
+ createList(child: Child, dropText?: HTMLSpanElement) {
+ const { options, propertyName } = child;
+ if (!options?.length) return null;
+ const ownerDocument = this.tableMenus.quill.root.ownerDocument;
+ const container = ownerDocument.createElement("ul");
+ for (const option of options) {
+ const list = ownerDocument.createElement("li");
+ list.innerText = option;
+ container.appendChild(list);
+ }
+ container.classList.add("ql-table-dropdown-list", "ql-hidden");
+ container.addEventListener("click", e => {
+ const value = (e.target as HTMLLIElement).innerText;
+ if (dropText) {
+ dropText.innerText = value;
+ }
+ this.toggleBorderDisabled(value);
+ this.setAttribute(propertyName, value);
+ });
+ return container;
+ }
+
+ createProperty(property: Properties) {
+ const { content, children } = property;
+ const ownerDocument = this.tableMenus.quill.root.ownerDocument;
+ const useLanguage = this.getUseLanguage();
+ const container = ownerDocument.createElement("div");
+ const label = ownerDocument.createElement("label");
+ label.innerText = content;
+ label.classList.add("ql-table-dropdown-label");
+ container.classList.add("properties-form-row");
+ if (children.length === 1) {
+ container.classList.add("properties-form-row-full");
+ }
+ container.appendChild(label);
+ for (const child of children) {
+ const node = this.createPropertyChild(child);
+ node && container.appendChild(node);
+ if (node && content === useLanguage("border")) {
+ this.borderForm.push(node);
+ }
+ }
+ return container;
+ }
+
+ createPropertyChild(child: Child) {
+ const { category, value } = child;
+ switch (category) {
+ case "dropdown":
+ const { dropdown, dropText } = this.createDropdown(value!, category);
+ const list = this.createList(child, dropText);
+ dropdown.appendChild(list!);
+ dropdown.addEventListener("click", () => {
+ this.toggleHidden(list!);
+ this.updateSelectedStatus(dropdown, dropText.innerText, "dropdown");
+ });
+ return dropdown;
+ case "color":
+ const colorContainer = this.createColorContainer(child);
+ return colorContainer;
+ case "menus":
+ const checkBtns = this.createCheckBtns(child);
+ return checkBtns;
+ case "input":
+ const input = this.createInput(child);
+ return input;
+ default:
+ break;
+ }
+ }
+
+ createPropertiesForm(options: Options) {
+ const useLanguage = this.getUseLanguage();
+ const { title, properties } = getProperties(options, useLanguage);
+ const ownerDocument = this.tableMenus.quill.root.ownerDocument;
+ const container = ownerDocument.createElement("div");
+ container.classList.add("ql-table-properties-form");
+ const header = ownerDocument.createElement("h2");
+ const actions = this.createActionBtns((e: MouseEvent) => {
+ const target = (e.target as HTMLElement).closest("button");
+ const label = target?.getAttribute("label") ?? "";
+ target && this.checkBtnsAction(label);
+ }, true);
+ header.innerText = title;
+ header.classList.add("properties-form-header");
+ container.appendChild(header);
+ for (const property of properties) {
+ const node = this.createProperty(property);
+ container.appendChild(node);
+ }
+ container.appendChild(actions);
+ this.setBorderDisabled();
+ this.tableMenus.quill.container.appendChild(container);
+ this.updatePropertiesForm(container, options.type);
+ this.setSaveButton(actions);
+ container.addEventListener("click", (e: MouseEvent) => {
+ const target = e.target as HTMLElement;
+ this.hiddenSelectList(target);
+ });
+ return container;
+ }
+
+ getCellStyle(td: Element, attrs: Props) {
+ const style = (td.getAttribute("style") || "")
+ .split(";")
+ .filter((value: string) => value.trim())
+ .reduce((style: Props, value: string) => {
+ const arr = value.split(":");
+ return { ...style, [arr[0].trim()]: arr[1].trim() };
+ }, {});
+ Object.assign(style, attrs);
+ return Object.keys(style).reduce((value: string, key: string) => {
+ return (value += `${key}: ${style[key]}; `);
+ }, "");
+ }
+
+ getColorClosest(container: HTMLElement) {
+ return getClosestElement(container, ".ql-table-color-container");
+ }
+
+ getDiffProperties() {
+ const change = this.attrs;
+ const old = this.options.attribute;
+ return Object.keys(change).reduce((attrs: Props, key) => {
+ if (change[key] !== old[key]) {
+ attrs[key] = isDimensions(key) ? addDimensionsUnit(change[key]) : change[key];
+ }
+ return attrs;
+ }, {});
+ }
+
+ getUseLanguage() {
+ const { language } = this.tableMenus.tableBetter;
+ const useLanguage = language.useLanguage.bind(language);
+ return useLanguage;
+ }
+
+ hiddenSelectList(element: HTMLElement) {
+ const listClassName = ".ql-table-dropdown-properties";
+ const colorClassName = ".color-picker";
+ const list = this.form.querySelectorAll(".ql-table-dropdown-list");
+ const colorPicker = this.form.querySelectorAll(".color-picker-select");
+ for (const node of [...Array.from(list), ...Array.from(colorPicker)]) {
+ if (
+ node.closest(listClassName)?.isEqualNode(element.closest(listClassName)) ||
+ node.closest(colorClassName)?.isEqualNode(element.closest(colorClassName))
+ ) {
+ continue;
+ }
+ node.classList.add("ql-hidden");
+ }
+ }
+
+ removePropertiesForm() {
+ this.form.remove();
+ this.borderForm = [];
+ }
+
+ saveAction(type: string) {
+ switch (type) {
+ case "table":
+ this.saveTableAction();
+ break;
+ default:
+ this.saveCellAction();
+ break;
+ }
+ }
+
+ saveCellAction() {
+ const { selectedTds } = this.tableMenus.tableBetter.cellSelection;
+ const { quill, table } = this.tableMenus;
+ const colgroup = (Quill.find(table as Node) as TableContainer).colgroup();
+ const attrs = this.getDiffProperties();
+ const width = parseFloat(attrs["width"]);
+ const align = attrs["text-align"];
+ align && delete attrs["text-align"];
+ const newSelectedTds = [];
+ if (colgroup && width) {
+ delete attrs["width"];
+ const { computeBounds } = this.tableMenus.getSelectedTdsInfo();
+ const cols = getComputeSelectedCols(computeBounds, table as Element, quill.container);
+ for (const col of cols) {
+ col.setAttribute("width", `${width}`);
+ }
+ }
+ for (const td of selectedTds) {
+ const tdBlot = Quill.find(td) as TableCell;
+ const blotName = tdBlot.statics.blotName;
+ const formats = tdBlot.formats()[blotName];
+ const style = this.getCellStyle(td, attrs);
+ if (align) {
+ const _align = align === "left" ? "" : align;
+ tdBlot.children.forEach((child: TableCellBlock | ListContainer | TableHeader) => {
+ if (child.statics.blotName === ListContainer.blotName) {
+ child.children.forEach((ch: TableList) => {
+ ch.format && ch.format("align", _align);
+ });
+ } else {
+ child.format("align", _align);
+ }
+ });
+ }
+ const parent = tdBlot.replaceWith(blotName, { ...formats, style }) as TableCell;
+ newSelectedTds.push(parent.domNode);
+ }
+ this.tableMenus.tableBetter.cellSelection.setSelectedTds(newSelectedTds);
+ }
+
+ saveTableAction() {
+ const { table, tableBetter } = this.tableMenus;
+ const temporary = (Quill.find(table as Node) as TableContainer).temporary()?.domNode;
+ const td = table?.querySelector("td");
+ const attrs = this.getDiffProperties();
+ const align = attrs["align"];
+ delete attrs["align"];
+ switch (align) {
+ case "center":
+ Object.assign(attrs, { margin: "0 auto" });
+ break;
+ case "left":
+ Object.assign(attrs, { margin: "" });
+ break;
+ case "right":
+ Object.assign(attrs, { "margin-left": "auto", "margin-right": "" });
+ break;
+ default:
+ break;
+ }
+ const element = temporary || table;
+ setElementProperty(element!, attrs);
+ tableBetter.cellSelection.setSelected(td as Element);
+ }
+
+ setAttribute(propertyName: string, value: string, container?: HTMLElement) {
+ this.attrs[propertyName] = value;
+ if (propertyName.includes("-color") && container) {
+ this.updateSelectColor(this.getColorClosest(container)!, value);
+ }
+ }
+
+ setBorderDisabled() {
+ const [borderContainer] = this.borderForm;
+ // @ts-ignore
+ const borderStyle = borderContainer.querySelector(".ql-table-dropdown-text").innerText;
+ this.toggleBorderDisabled(borderStyle);
+ }
+
+ setSaveButton(container: HTMLDivElement) {
+ const saveButton: HTMLButtonElement | null = container.querySelector('button[label="save"]');
+ this.saveButton = saveButton;
+ }
+
+ setSaveButtonDisabled(disabled: boolean) {
+ if (!this.saveButton) return;
+ if (disabled) {
+ this.saveButton.setAttribute("disabled", "true");
+ } else {
+ this.saveButton.removeAttribute("disabled");
+ }
+ }
+
+ switchButton(container: HTMLDivElement, target: HTMLSpanElement) {
+ const children = container.querySelectorAll("span.ql-table-tooltip-hover");
+ for (const child of Array.from(children)) {
+ child.classList.remove("ql-table-btns-checked");
+ }
+ target.classList.add("ql-table-btns-checked");
+ }
+
+ switchHidden(container: HTMLElement, valid: boolean) {
+ if (!valid) {
+ container.classList.remove("ql-hidden");
+ } else {
+ container.classList.add("ql-hidden");
+ }
+ }
+
+ toggleBorderDisabled(value: string) {
+ const [, colorContainer, widthContainer] = this.borderForm;
+ if (value === "none" || !value) {
+ this.attrs["border-color"] = "";
+ this.attrs["border-width"] = "";
+ this.updateSelectColor(colorContainer, "");
+ this.updateInputValue(widthContainer, "");
+ colorContainer.classList.add("ql-table-disabled");
+ widthContainer.classList.add("ql-table-disabled");
+ } else {
+ colorContainer.classList.remove("ql-table-disabled");
+ widthContainer.classList.remove("ql-table-disabled");
+ }
+ }
+
+ toggleHidden(container: HTMLElement) {
+ container.classList.toggle("ql-hidden");
+ }
+
+ updateInputValue(element: Element, value: string) {
+ const input: HTMLInputElement | null = element.querySelector(".property-input");
+ if (input) {
+ input.value = value;
+ }
+ }
+
+ updateInputStatus(container: HTMLElement, status: boolean, isColor?: boolean) {
+ const closestContainer = isColor
+ ? this.getColorClosest(container)
+ : getClosestElement(container, ".label-field-view");
+ const wrapper = closestContainer?.querySelector(".label-field-view-input-wrapper");
+ if (status) {
+ wrapper?.classList.add("label-field-view-error");
+ this.setSaveButtonDisabled(true);
+ } else {
+ wrapper?.classList.remove("label-field-view-error");
+ const wrappers = this.form.querySelectorAll(".label-field-view-error");
+ if (!wrappers.length) this.setSaveButtonDisabled(false);
+ }
+ }
+
+ updatePropertiesForm(container: HTMLElement, type: string) {
+ const target = type === "table" ? this.tableMenus.table! : this.tableMenus.getSelectedTdsInfo().leftTd;
+
+ computePosition(target, container, {
+ middleware: [offset(4), flip(), shift({ padding: 10 })],
+ placement: "bottom",
+ strategy: "fixed"
+ }).then(({ x, y }) => {
+ setElementProperty(container, {
+ left: `${x}px`,
+ top: `${y}px`
+ });
+ });
+ }
+
+ updateSelectColor(element: Element, value: string) {
+ const input: HTMLInputElement | null = element.querySelector(".property-input");
+
+ if (input) {
+ input.value = value;
+ }
+ }
+
+ updateSelectedStatus(container: HTMLDivElement, value: string, type: string) {
+ const selectors = type === "color" ? ".color-list" : ".ql-table-dropdown-list";
+ const list = container.querySelector(selectors);
+ if (!list) return;
+ const lists = Array.from(list.querySelectorAll("li"));
+ for (const list of lists) {
+ list.classList.remove(`ql-table-${type}-selected`);
+ }
+ const selected = lists.find(li => {
+ const data = type === "color" ? li.getAttribute("data-color") : li.innerText;
+ return data === value;
+ });
+ selected && selected.classList.add(`ql-table-${type}-selected`);
+ }
+}
+
+export default TablePropertiesForm;
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/toolbar-table.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/toolbar-table.ts
new file mode 100644
index 0000000000..2993dbf743
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/toolbar-table.ts
@@ -0,0 +1,123 @@
+// @ts-nocheck
+import type { InlineBlot } from "parchment";
+import QuillInline from "quill/blots/inline";
+import type { InsertTableHandler } from "../types";
+
+const Inline = QuillInline as typeof InlineBlot;
+const SUM = 10;
+
+class ToolbarTable extends Inline {}
+
+class TableSelect {
+ computeChildren: Element[];
+ root: HTMLDivElement;
+ constructor() {
+ this.computeChildren = [];
+ this.root = this.createContainer();
+ }
+
+ clearSelected(children: NodeListOf | Element[]) {
+ for (const child of children) {
+ child.classList && child.classList.remove("ql-cell-selected");
+ }
+ this.computeChildren = [];
+ this.root && this.setLabelContent(this.root.lastElementChild, null);
+ }
+
+ createContainer() {
+ const container = document.createElement("div");
+ const list = document.createElement("div");
+ const label = document.createElement("div");
+ const fragment = document.createDocumentFragment();
+ for (let row = 1; row <= SUM; row++) {
+ for (let column = 1; column <= SUM; column++) {
+ const child = document.createElement("span");
+ child.setAttribute("row", `${row}`);
+ child.setAttribute("column", `${column}`);
+ fragment.appendChild(child);
+ }
+ }
+ label.innerHTML = "0 × 0";
+ container.classList.add("ql-table-select-container", "ql-hidden");
+ list.classList.add("ql-table-select-list");
+ label.classList.add("ql-table-select-label");
+ list.appendChild(fragment);
+ container.appendChild(list);
+ container.appendChild(label);
+ container.addEventListener("mousemove", e => this.handleMouseMove(e, container));
+ return container;
+ }
+
+ getComputeChildren(children: HTMLCollection, e: MouseEvent): Element[] {
+ const computeChildren = [];
+ const { clientX, clientY } = e;
+ for (const child of children) {
+ const { left, top } = child.getBoundingClientRect();
+ if (clientX >= left && clientY >= top) {
+ computeChildren.push(child);
+ }
+ }
+ return computeChildren;
+ }
+
+ getSelectAttrs(element: Element) {
+ const row = ~~element.getAttribute("row");
+ const column = ~~element.getAttribute("column");
+ return [row, column];
+ }
+
+ handleClick(e: MouseEvent, insertTable: InsertTableHandler) {
+ this.toggle(this.root);
+ const span = (e.target as Element).closest("span[row]");
+ if (!span) {
+ // Click between two spans
+ const child = this.computeChildren[this.computeChildren.length - 1];
+ if (child) this.insertTable(child, insertTable);
+ return;
+ }
+ this.insertTable(span, insertTable);
+ }
+
+ handleMouseMove(e: MouseEvent, container: Element) {
+ const children = container.firstElementChild.children;
+ this.clearSelected(this.computeChildren);
+ const computeChildren = this.getComputeChildren(children, e);
+ for (const child of computeChildren) {
+ child.classList && child.classList.add("ql-cell-selected");
+ }
+ this.computeChildren = computeChildren;
+ this.setLabelContent(container.lastElementChild, computeChildren[computeChildren.length - 1]);
+ }
+
+ hide(element: Element) {
+ this.clearSelected(this.computeChildren);
+ element && element.classList.add("ql-hidden");
+ }
+
+ insertTable(child: Element, insertTable: InsertTableHandler) {
+ const [row, column] = this.getSelectAttrs(child);
+ insertTable(row, column);
+ this.hide(this.root);
+ }
+
+ setLabelContent(label: Element, child: Element) {
+ if (!child) {
+ label.innerHTML = "0 × 0";
+ } else {
+ const [row, column] = this.getSelectAttrs(child);
+ label.innerHTML = `${row} × ${column}`;
+ }
+ }
+
+ show(element: Element) {
+ this.clearSelected(this.computeChildren);
+ element && element.classList.remove("ql-hidden");
+ }
+
+ toggle(element: Element) {
+ this.clearSelected(this.computeChildren);
+ element && element.classList.toggle("ql-hidden");
+ }
+}
+
+export { ToolbarTable as default, TableSelect };
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/utils/clipboard-matchers.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/utils/clipboard-matchers.ts
new file mode 100644
index 0000000000..eb850f4049
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/utils/clipboard-matchers.ts
@@ -0,0 +1,90 @@
+// @ts-nocheck
+import merge from "lodash.merge";
+import Delta from "quill-delta";
+import { TableCell } from "../formats/table";
+import type { Props } from "../types";
+import { filterWordStyle } from "./";
+
+const TABLE_ATTRIBUTE = ["border", "cellspacing", "style", "class"];
+
+function applyFormat(delta: Delta, format: Props | string, value?: any): Delta {
+ if (typeof format === "object") {
+ return Object.keys(format).reduce((newDelta, key) => {
+ return applyFormat(newDelta, key, format[key]);
+ }, delta);
+ }
+ return delta.reduce((newDelta, op) => {
+ if (op.attributes && op.attributes[format]) {
+ return newDelta.push(op);
+ }
+ return newDelta.insert(op.insert, merge({}, { [format]: value }, op.attributes));
+ }, new Delta());
+}
+
+function matchTable(node: HTMLTableRowElement, delta: Delta) {
+ const table = (node.parentNode as HTMLElement).tagName === "TABLE" ? node.parentNode : node.parentNode.parentNode;
+ const rows = Array.from(table.querySelectorAll("tr"));
+ const row = rows.indexOf(node) + 1;
+ if (!node.innerHTML.replace(/\s/g, "")) return new Delta();
+ return applyFormat(delta, "table-cell", row);
+}
+
+function matchTableCell(node: HTMLTableCellElement, delta: Delta) {
+ const table =
+ (node.parentNode.parentNode as HTMLElement).tagName === "TABLE"
+ ? node.parentNode.parentNode
+ : node.parentNode.parentNode.parentNode;
+ const rows = Array.from(table.querySelectorAll("tr"));
+ const tagName = node.tagName;
+ const cells = Array.from(node.parentNode.querySelectorAll(tagName));
+ const row = node.getAttribute("data-row") || rows.indexOf(node.parentNode as HTMLTableRowElement) + 1;
+ const cellId = node?.firstElementChild?.getAttribute("data-cell") || cells.indexOf(node) + 1;
+ if (!delta.length()) delta.insert("\n", { "table-cell": { "data-row": row } });
+ delta.ops.forEach(op => {
+ if (op.attributes && op.attributes["table-cell"]) {
+ // @ts-ignore
+ op.attributes["table-cell"] = { ...op.attributes["table-cell"], "data-row": row };
+ }
+ });
+ return applyFormat(matchTableTh(node, delta, row), "table-cell-block", cellId);
+}
+
+function matchTableCol(node: HTMLElement, delta: Delta) {
+ let span = ~~node.getAttribute("span") || 1;
+ const width = node.getAttribute("width");
+ const newDelta = new Delta();
+ while (span > 1) {
+ newDelta.insert("\n", { "table-col": { width } });
+ span--;
+ }
+ return newDelta.concat(delta);
+}
+
+function matchTableTemporary(node: HTMLElement, delta: Delta) {
+ const formats = TABLE_ATTRIBUTE.reduce((formats: Props, attr) => {
+ if (node.hasAttribute(attr)) {
+ if (attr === "class") {
+ formats["data-class"] = node.getAttribute(attr);
+ } else {
+ formats[attr] = filterWordStyle(node.getAttribute(attr));
+ }
+ }
+ return formats;
+ }, {});
+ return new Delta().insert("\n", { "table-temporary": formats }).concat(delta);
+}
+
+function matchTableTh(node: HTMLTableCellElement, delta: Delta, row: string | number) {
+ const formats = TableCell.formats(node);
+ if (node.tagName === "TH") {
+ delta.ops.forEach(op => {
+ if (typeof op.insert === "string" && !op.insert.endsWith("\n")) {
+ op.insert += "\n";
+ }
+ });
+ return applyFormat(delta, "table-cell", { ...formats, "data-row": row });
+ }
+ return delta;
+}
+
+export { applyFormat, matchTable, matchTableCell, matchTableCol, matchTableTemporary };
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/utils/index.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/utils/index.ts
new file mode 100644
index 0000000000..e8010713ff
--- /dev/null
+++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/utils/index.ts
@@ -0,0 +1,383 @@
+// @ts-nocheck
+import Quill from "quill";
+import { COLORS, DEVIATION } from "../config";
+import TableHeader from "../formats/header";
+import TableList, { ListContainer } from "../formats/list";
+import { TableCell, TableCellBlock, TableCol } from "../formats/table";
+import type { CorrectBound, Props, TableCellChildren, TableContainer } from "../types";
+
+function addDimensionsUnit(value: string) {
+ if (!value) return value;
+ const unit = value.slice(-2); // 'px' or 'em'
+ if (unit !== "px" && unit !== "em") {
+ return value + "px";
+ }
+ return value;
+}
+
+function convertUnitToInteger(withUnit: string) {
+ if (typeof withUnit !== "string" || !withUnit) return withUnit;
+ const unit = withUnit.slice(-2); // 'px' or 'em'
+ const numberPart = withUnit.slice(0, -2);
+ const integerPart = Math.round(parseFloat(numberPart));
+ return `${integerPart}${unit}`;
+}
+
+function createTooltip(content: string) {
+ const element = document.createElement("div");
+ element.innerText = content;
+ element.classList.add("ql-table-tooltip", "ql-hidden");
+ return element;
+}
+
+function debounce(cb: Function, delay: number) {
+ let timer: NodeJS.Timeout = null;
+ return function () {
+ let context = this;
+ let args = arguments;
+ if (timer) clearTimeout(timer);
+ timer = setTimeout(function () {
+ cb.apply(context, args);
+ }, delay);
+ };
+}
+
+function filterWordStyle(s: string) {
+ return s.replace(/mso.*?;/g, "");
+}
+
+function getAlign(cellBlot: TableCell) {
+ const DEFAULT = "left";
+ let align = null;
+ const blocks = cellBlot.descendants(TableCellBlock);
+ const lists = cellBlot.descendants(TableList);
+ const headers = cellBlot.descendants(TableHeader);
+ function getChildAlign(child: TableCellChildren): string {
+ for (const name of child.domNode.classList) {
+ if (/ql-align-/.test(name)) {
+ return name.split("ql-align-")[1];
+ }
+ }
+ return DEFAULT;
+ }
+ function isSameValue(prev: string | null, cur: string) {
+ if (prev == null) return true;
+ return prev === cur;
+ }
+ for (const child of [...blocks, ...lists, ...headers]) {
+ const _align = getChildAlign(child);
+ if (isSameValue(align, _align)) {
+ align = _align;
+ } else {
+ return DEFAULT;
+ }
+ }
+ return align != null ? align : DEFAULT;
+}
+
+function getCellChildBlot(cellBlot: TableCell) {
+ // @ts-expect-error
+ const [block] = cellBlot.descendant(TableCellBlock);
+ // @ts-expect-error
+ const [list] = cellBlot.descendant(ListContainer);
+ // @ts-expect-error
+ const [header] = cellBlot.descendant(TableHeader);
+ return block || list || header;
+}
+
+function getCellFormats(cellBlot: TableCell): [Props, string] {
+ const formats = TableCell.formats(cellBlot.domNode);
+ const childBlot = getCellChildBlot(cellBlot);
+ if (!childBlot) {
+ const row = formats["data-row"].split("-")[1];
+ return [formats, `cell-${row}`];
+ } else {
+ const _formats = childBlot.formats()[childBlot.statics.blotName];
+ const cellId = getCellId(_formats);
+ return [formats, cellId];
+ }
+}
+
+function getCellId(formats: string | Props) {
+ return formats instanceof Object ? formats["cellId"] : formats;
+}
+
+function getClosestElement(element: HTMLElement, selector: string) {
+ return element.closest(selector);
+}
+
+function getComputeBounds(startCorrectBounds: CorrectBound, endCorrectBounds: CorrectBound) {
+ const left = Math.min(startCorrectBounds.left, endCorrectBounds.left);
+ const right = Math.max(startCorrectBounds.right, endCorrectBounds.right);
+ const top = Math.min(startCorrectBounds.top, endCorrectBounds.top);
+ const bottom = Math.max(startCorrectBounds.bottom, endCorrectBounds.bottom);
+ return { left, right, top, bottom };
+}
+
+function getComputeSelectedCols(computeBounds: CorrectBound, table: Element, container: Element) {
+ const tableParchment = Quill.find(table) as TableContainer;
+ const cols = tableParchment.descendants(TableCol);
+ let correctLeft = 0;
+ return cols.reduce((selectedCols: Element[], col: TableCol) => {
+ const { left, width } = getCorrectBounds(col.domNode, container);
+ correctLeft = correctLeft ? correctLeft : left;
+ if (correctLeft + DEVIATION >= computeBounds.left && correctLeft - DEVIATION + width <= computeBounds.right) {
+ selectedCols.push(col.domNode);
+ }
+ correctLeft += width;
+ return selectedCols;
+ }, []);
+}
+
+function getComputeSelectedTds(
+ computeBounds: CorrectBound,
+ table: Element,
+ container: Element,
+ type?: string
+): Element[] {
+ const tableParchment = Quill.find(table) as TableContainer;
+ const tableCells = tableParchment.descendants(TableCell);
+ return tableCells.reduce((selectedTds: Element[], tableCell: TableCell) => {
+ const { left, top, width, height } = getCorrectBounds(tableCell.domNode, container);
+ switch (type) {
+ case "column":
+ if (left + DEVIATION >= computeBounds.left && left - DEVIATION + width <= computeBounds.right) {
+ selectedTds.push(tableCell.domNode);
+ } else if (left + DEVIATION < computeBounds.right && computeBounds.right < left - DEVIATION + width) {
+ selectedTds.push(tableCell.domNode);
+ } else if (computeBounds.left > left + DEVIATION && computeBounds.left < left - DEVIATION + width) {
+ selectedTds.push(tableCell.domNode);
+ }
+ break;
+ case "row":
+ break;
+ default:
+ if (
+ left + DEVIATION >= computeBounds.left &&
+ left - DEVIATION + width <= computeBounds.right &&
+ top + DEVIATION >= computeBounds.top &&
+ top - DEVIATION + height <= computeBounds.bottom
+ ) {
+ selectedTds.push(tableCell.domNode);
+ }
+ break;
+ }
+ return selectedTds;
+ }, []);
+}
+
+function getCopyTd(html: string) {
+ return html
+ .replace(/data-[a-z]+="[^"]*"/g, "")
+ .replace(/class="[^"]*"/g, collapse => {
+ return collapse
+ .replace("ql-cell-selected", "")
+ .replace("ql-cell-focused", "")
+ .replace("ql-table-block", "");
+ })
+ .replace(/class="\s*"/g, "");
+}
+
+function getCorrectBounds(target: Element, container: Element) {
+ const targetBounds = target.getBoundingClientRect();
+ const containerBounds = container.getBoundingClientRect();
+ const left = targetBounds.left - containerBounds.left - container.scrollLeft;
+ const top = targetBounds.top - containerBounds.top - container.scrollTop;
+ const width = targetBounds.width;
+ const height = targetBounds.height;
+ return {
+ left,
+ top,
+ width,
+ height,
+ right: left + width,
+ bottom: top + height
+ };
+}
+
+function getCorrectCellBlot(blot: TableCell | TableCellChildren): TableCell | null {
+ while (blot) {
+ if (blot.statics.blotName === TableCell.blotName) {
+ // @ts-ignore
+ return blot;
+ }
+ // @ts-expect-error
+ blot = blot.parent;
+ }
+ return null;
+}
+
+function getElementStyle(node: HTMLElement, rules: string[]) {
+ const computedStyle = getComputedStyle(node);
+ const style = node.style;
+ return rules.reduce((styles: Props, rule: string) => {
+ styles[rule] = rgbToHex(style.getPropertyValue(rule) || computedStyle.getPropertyValue(rule));
+ return styles;
+ }, {});
+}
+
+function isDimensions(key: string) {
+ if (key.endsWith("width") || key.endsWith("height")) return true;
+ return false;
+}
+
+function isSimpleColor(color: string) {
+ for (const col of COLORS) {
+ if (col === color) return true;
+ }
+ return false;
+}
+
+function isValidColor(color: string) {
+ if (!color) return true;
+ const hexRegex = /^#([A-Fa-f0-9]{3,6})$/;
+ const rgbRegex = /^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/;
+ // const rgbaRegex = /^rgba\((\d{1,3}), (\d{1,3}), (\d{1,3}), (\d{1,3})\)$/;
+ if (hexRegex.test(color)) {
+ return true;
+ } else if (rgbRegex.test(color)) {
+ return true;
+ }
+ return isSimpleColor(color);
+}
+
+function isValidDimensions(value: string) {
+ if (!value) return true;
+ const unit = value.slice(-2); // 'px' or 'em'
+ if (unit !== "px" && unit !== "em") {
+ return !/[a-z]/.test(unit) && !isNaN(parseFloat(unit));
+ }
+ return true;
+}
+
+function removeElementProperty(node: HTMLElement, properties: string[]) {
+ for (const property of properties) {
+ node.style.removeProperty(property);
+ }
+}
+
+function rgbToHex(value: string) {
+ if (value.startsWith("rgba(")) return rgbaToHex(value);
+ if (!value.startsWith("rgb(")) return value;
+ value = value.replace(/^[^\d]+/, "").replace(/[^\d]+$/, "");
+ const hex = value
+ .split(",")
+ .map(component => `00${parseInt(component, 10).toString(16)}`.slice(-2))
+ .join("");
+ return `#${hex}`;
+}
+
+function rgbaToHex(value: string) {
+ value = value.replace(/^[^\d]+/, "").replace(/[^\d]+$/, "");
+ const r = Math.round(+value[0]);
+ const g = Math.round(+value[1]);
+ const b = Math.round(+value[2]);
+ const a = Math.round(+value[3] * 255)
+ .toString(16)
+ .toUpperCase()
+ .padStart(2, "0");
+ return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1) + a;
+}
+
+function setElementAttribute(node: Element, attributes: Props) {
+ for (const attribute in attributes) {
+ node.setAttribute(attribute, attributes[attribute]);
+ }
+}
+
+function setElementProperty(node: HTMLElement, properties: Props) {
+ const style = node.style;
+ if (!style) {
+ node.setAttribute("style", properties.toString());
+ return;
+ }
+ for (const propertyName in properties) {
+ style.setProperty(propertyName, properties[propertyName]);
+ }
+}
+
+function throttle(cb: Function, delay: number) {
+ let last = 0;
+ return function () {
+ let context = this;
+ let args = arguments;
+ let now = +new Date();
+ if (now - last >= delay) {
+ last = now;
+ cb.apply(context, args);
+ }
+ };
+}
+
+function throttleStrong(cb: Function, delay: number) {
+ let last = 0,
+ timer: NodeJS.Timeout = null;
+ return function () {
+ let context = this;
+ let args = arguments;
+ let now = +new Date();
+ if (now - last < delay) {
+ clearTimeout(timer);
+ timer = setTimeout(function () {
+ last = now;
+ cb.apply(context, args);
+ }, delay);
+ } else {
+ last = now;
+ cb.apply(context, args);
+ }
+ };
+}
+
+function updateTableWidth(table: HTMLElement, tableBounds: CorrectBound, change: number) {
+ const tableBlot = Quill.find(table) as TableContainer;
+ if (!tableBlot) return;
+ const colgroup = tableBlot.colgroup();
+ const temporary = tableBlot.temporary();
+ if (colgroup) {
+ let _width = 0;
+ const cols = colgroup.domNode.querySelectorAll("col");
+ for (const col of cols) {
+ const width = ~~col.getAttribute("width");
+ _width += width;
+ }
+ setElementProperty(temporary.domNode, {
+ width: `${_width}px`
+ });
+ } else {
+ setElementProperty(temporary.domNode, {
+ width: `${~~(tableBounds.width + change)}px`
+ });
+ }
+}
+
+export {
+ addDimensionsUnit,
+ convertUnitToInteger,
+ createTooltip,
+ debounce,
+ filterWordStyle,
+ getAlign,
+ getCellChildBlot,
+ getCellFormats,
+ getCellId,
+ getClosestElement,
+ getComputeBounds,
+ getComputeSelectedCols,
+ getComputeSelectedTds,
+ getCopyTd,
+ getCorrectBounds,
+ getCorrectCellBlot,
+ getElementStyle,
+ isDimensions,
+ isValidColor,
+ isValidDimensions,
+ removeElementProperty,
+ rgbaToHex,
+ rgbToHex,
+ setElementAttribute,
+ setElementProperty,
+ throttle,
+ throttleStrong,
+ updateTableWidth
+};
diff --git a/packages/pluggableWidgets/rich-text-web/typings/RichTextProps.d.ts b/packages/pluggableWidgets/rich-text-web/typings/RichTextProps.d.ts
index 4bf3a7e2aa..0380ae4691 100644
--- a/packages/pluggableWidgets/rich-text-web/typings/RichTextProps.d.ts
+++ b/packages/pluggableWidgets/rich-text-web/typings/RichTextProps.d.ts
@@ -25,7 +25,7 @@ export type OnChangeTypeEnum = "onLeave" | "onDataChange";
export type ToolbarConfigEnum = "basic" | "advanced";
-export type CtItemTypeEnum = "separator" | "undo" | "redo" | "bold" | "italic" | "underline" | "strike" | "superScript" | "subScript" | "orderedList" | "bulletList" | "lowerAlphaList" | "checkList" | "minIndent" | "plusIndent" | "direction" | "link" | "image" | "video" | "formula" | "blockquote" | "code" | "codeBlock" | "viewCode" | "align" | "centerAlign" | "rightAlign" | "font" | "size" | "color" | "background" | "header" | "fullscreen" | "clean";
+export type CtItemTypeEnum = "separator" | "undo" | "redo" | "bold" | "italic" | "underline" | "strike" | "superScript" | "subScript" | "orderedList" | "bulletList" | "lowerAlphaList" | "checkList" | "minIndent" | "plusIndent" | "direction" | "link" | "image" | "video" | "formula" | "blockquote" | "code" | "codeBlock" | "viewCode" | "align" | "centerAlign" | "rightAlign" | "font" | "size" | "color" | "background" | "header" | "fullscreen" | "clean" | "tableBetter";
export interface AdvancedConfigType {
ctItemType: CtItemTypeEnum;
@@ -72,6 +72,7 @@ export interface RichTextContainerProps {
header: boolean;
view: boolean;
remove: boolean;
+ tableBetter: boolean;
advancedConfig: AdvancedConfigType[];
}
@@ -112,5 +113,6 @@ export interface RichTextPreviewProps {
header: boolean;
view: boolean;
remove: boolean;
+ tableBetter: boolean;
advancedConfig: AdvancedConfigPreviewType[];
}
diff --git a/packages/pluggableWidgets/rich-text-web/typings/declare-svg.ts b/packages/pluggableWidgets/rich-text-web/typings/declare-svg.ts
index 1bed3c6deb..e65f2cb5a6 100644
--- a/packages/pluggableWidgets/rich-text-web/typings/declare-svg.ts
+++ b/packages/pluggableWidgets/rich-text-web/typings/declare-svg.ts
@@ -3,4 +3,4 @@ declare module "*.svg" {
export = content;
}
-declare module '*.css';
\ No newline at end of file
+declare module '*.css';
diff --git a/packages/pluggableWidgets/rich-text-web/typings/global.d.ts b/packages/pluggableWidgets/rich-text-web/typings/global.d.ts
index bced5234c8..b0eef7f609 100644
--- a/packages/pluggableWidgets/rich-text-web/typings/global.d.ts
+++ b/packages/pluggableWidgets/rich-text-web/typings/global.d.ts
@@ -7,3 +7,5 @@ declare global {
mx: MXGlobalObject;
}
}
+
+declare module "lodash.merge";
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1e4ec2e412..37c6311295 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1995,6 +1995,9 @@ importers:
'@floating-ui/react':
specifier: ^0.26.27
version: 0.26.27(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
+ '@melloware/coloris':
+ specifier: ^0.24.0
+ version: 0.24.0
classnames:
specifier: ^2.2.6
version: 2.3.2
@@ -2007,6 +2010,9 @@ importers:
linkifyjs:
specifier: ^4.1.3
version: 4.1.3
+ lodash.merge:
+ specifier: ^4.6.2
+ version: 4.6.2
parchment:
specifier: ^3.0.0
version: 3.0.0
@@ -2411,40 +2417,40 @@ importers:
dependencies:
'@eslint/js':
specifier: ^9.23.0
- version: 9.23.0
+ version: 9.24.0
'@mendix/prettier-config-web-widgets':
specifier: workspace:*
version: link:../prettier-config-web-widgets
eslint:
specifier: ^9.23.0
- version: 9.23.0(jiti@2.4.2)
+ version: 9.24.0(jiti@2.4.2)
eslint-plugin-cypress:
specifier: ^4.2.0
- version: 4.2.0(eslint@9.23.0(jiti@2.4.2))
+ version: 4.2.1(eslint@9.24.0(jiti@2.4.2))
eslint-plugin-jest:
specifier: ^28.11.0
- version: 28.11.0(@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.23.0(jiti@2.4.2))(jest@29.7.0(@types/node@22.14.0))(typescript@5.8.2)
+ version: 28.11.0(@typescript-eslint/eslint-plugin@8.30.1(@typescript-eslint/parser@8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.24.0(jiti@2.4.2))(jest@29.7.0(@types/node@22.14.0))(typescript@5.8.2)
eslint-plugin-package-json:
specifier: ^0.29.0
- version: 0.29.0(@types/estree@1.0.6)(eslint@9.23.0(jiti@2.4.2))(jsonc-eslint-parser@2.4.0)
+ version: 0.29.1(@types/estree@1.0.6)(eslint@9.24.0(jiti@2.4.2))(jsonc-eslint-parser@2.4.0)
eslint-plugin-prettier:
specifier: ^5.2.6
- version: 5.2.6(@types/eslint@9.6.1)(eslint-config-prettier@10.1.1(eslint@9.23.0(jiti@2.4.2)))(eslint@9.23.0(jiti@2.4.2))(prettier@3.5.3)
+ version: 5.2.6(@types/eslint@9.6.1)(eslint-config-prettier@8.10.0(eslint@9.24.0(jiti@2.4.2)))(eslint@9.24.0(jiti@2.4.2))(prettier@3.5.3)
eslint-plugin-promise:
specifier: ^7.2.1
- version: 7.2.1(eslint@9.23.0(jiti@2.4.2))
+ version: 7.2.1(eslint@9.24.0(jiti@2.4.2))
eslint-plugin-react:
specifier: ~7.37.5
- version: 7.37.5(eslint@9.23.0(jiti@2.4.2))
+ version: 7.37.5(eslint@9.24.0(jiti@2.4.2))
eslint-plugin-react-hooks:
specifier: ^5.2.0
- version: 5.2.0(eslint@9.23.0(jiti@2.4.2))
+ version: 5.2.0(eslint@9.24.0(jiti@2.4.2))
globals:
specifier: ^16.0.0
version: 16.0.0
typescript-eslint:
specifier: ^8.29.0
- version: 8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
+ version: 8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)
packages/shared/prettier-config-web-widgets:
dependencies:
@@ -2456,7 +2462,7 @@ importers:
version: 3.4.1(prettier@3.5.3)
eslint:
specifier: ^9.23.0
- version: 9.23.0(jiti@2.4.2)
+ version: 9.24.0(jiti@2.4.2)
globals:
specifier: ^16.0.0
version: 16.0.0
@@ -3719,18 +3725,10 @@ packages:
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
- '@eslint-community/regexpp@4.11.1':
- resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==}
- engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
-
'@eslint-community/regexpp@4.12.1':
resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
- '@eslint/config-array@0.19.2':
- resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
'@eslint/config-array@0.20.0':
resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -3755,10 +3753,6 @@ packages:
resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/js@9.23.0':
- resolution: {integrity: sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
'@eslint/js@9.24.0':
resolution: {integrity: sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -4023,73 +4017,76 @@ packages:
resolution: {integrity: sha512-5ueL4UDitzVtceQ8J4kY+Px3WK+eZTsmGwha3MBKHKqiHvKrjWWwBCIl1K8BuJSc5OFh83uI8IFNoFvQxX2uUw==}
hasBin: true
+ '@melloware/coloris@0.24.0':
+ resolution: {integrity: sha512-9RGKHqZJsUSsxb/0xaBCK5OKywobiK/xRtV8f4KQDmviqmVfkMLR3kK4DRuTTLSFdSOqkV0OQ/Niitu+rlXXYw==}
+
'@mendix/pluggable-widgets-tools@10.18.2':
resolution: {integrity: sha512-6AT45Ob3WiGEBiIAlqbYowJjRi3zyACgc5uH20oKlrSX9lJ3y60SH9zApXlP6esINBApD59L+EjW5brpz3EJjA==}
engines: {node: '>=20'}
hasBin: true
- '@napi-rs/canvas-android-arm64@0.1.68':
- resolution: {integrity: sha512-h1KcSR4LKLfRfzeBH65xMxbWOGa1OtMFQbCMVlxPCkN1Zr+2gK+70pXO5ktojIYcUrP6KDcOwoc8clho5ccM/w==}
+ '@napi-rs/canvas-android-arm64@0.1.69':
+ resolution: {integrity: sha512-4icWTByY8zPvM9SelfQKf3I6kwXw0aI5drBOVrwfER5kjwXJd78FPSDSZkxDHjvIo9Q86ljl18Yr963ehA4sHQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [android]
- '@napi-rs/canvas-darwin-arm64@0.1.68':
- resolution: {integrity: sha512-/VURlrAD4gDoxW1GT/b0nP3fRz/fhxmHI/xznTq2FTwkQLPOlLkDLCvTmQ7v6LtGKdc2Ed6rvYpRan+JXThInQ==}
+ '@napi-rs/canvas-darwin-arm64@0.1.69':
+ resolution: {integrity: sha512-HOanhhYlHdukA+unjelT4Dg3ta7e820x87/AG2dKUMsUzH19jaeZs9bcYjzEy2vYi/dFWKz7cSv2yaIOudB8Yg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
- '@napi-rs/canvas-darwin-x64@0.1.68':
- resolution: {integrity: sha512-tEpvGR6vCLTo1Tx9wmDnoOKROpw57wiCWwCpDOuVlj/7rqEJOUYr9ixW4aRJgmeGBrZHgevI0EURys2ER6whmg==}
+ '@napi-rs/canvas-darwin-x64@0.1.69':
+ resolution: {integrity: sha512-SIp7WfhxAPnSVK9bkFfJp+84rbATCIq9jMUzDwpCLhQ+v+OqtXe4pggX1oeV+62/HK6BT1t18qRmJfyqwJ9f3g==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
- '@napi-rs/canvas-linux-arm-gnueabihf@0.1.68':
- resolution: {integrity: sha512-U9xbJsumPOiAYeAFZMlHf62b9dGs2HJ6Q5xt7xTB0uEyPeurwhgYBWGgabdsEidyj38YuzI/c3LGBbSQB3vagw==}
+ '@napi-rs/canvas-linux-arm-gnueabihf@0.1.69':
+ resolution: {integrity: sha512-Ls+KujCp6TGpkuMVFvrlx+CxtL+casdkrprFjqIuOAnB30Mct6bCEr+I83Tu29s3nNq4EzIGjdmA3fFAZG/Dtw==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
- '@napi-rs/canvas-linux-arm64-gnu@0.1.68':
- resolution: {integrity: sha512-KFkn8wEm3mPnWD4l8+OUUkxylSJuN5q9PnJRZJgv15RtCA1bgxIwTkBhI/+xuyVMcHqON9sXq7cDkEJtHm35dg==}
+ '@napi-rs/canvas-linux-arm64-gnu@0.1.69':
+ resolution: {integrity: sha512-m8VcGmeSBNRbHZBd1srvdM1aq/ScS2y8KqGqmCCEgJlytYK4jdULzAo2K/BPKE1v3xvn8oUPZDLI/NBJbJkEoA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
- '@napi-rs/canvas-linux-arm64-musl@0.1.68':
- resolution: {integrity: sha512-IQzts91rCdOALXBWQxLZRCEDrfFTGDtNRJMNu+2SKZ1uT8cmPQkPwVk5rycvFpvgAcmiFiOSCp1aRrlfU8KPpQ==}
+ '@napi-rs/canvas-linux-arm64-musl@0.1.69':
+ resolution: {integrity: sha512-a3xjNRIeK2m2ZORGv2moBvv3vbkaFZG1QKMeiEv/BKij+rkztuEhTJGMar+buICFgS0fLgphXXsKNkUSJb7eRQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
- '@napi-rs/canvas-linux-riscv64-gnu@0.1.68':
- resolution: {integrity: sha512-e9AS5UttoIKqXSmBzKZdd3NErSVyOEYzJfNOCGtafGk1//gibTwQXGlSXmAKuErqMp09pyk9aqQRSYzm1AQfBw==}
+ '@napi-rs/canvas-linux-riscv64-gnu@0.1.69':
+ resolution: {integrity: sha512-pClUoJF5wdC9AvD0mc15G9JffL1Q85nuH1rLSQPRkGmGmQOtRjw5E9xNbanz7oFUiPbjH7xcAXUjVAcf7tdgPQ==}
engines: {node: '>= 10'}
cpu: [riscv64]
os: [linux]
- '@napi-rs/canvas-linux-x64-gnu@0.1.68':
- resolution: {integrity: sha512-Pa/I36VE3j57I3Obhrr+J48KGFfkZk2cJN/2NmW/vCgmoF7kCP6aTVq5n+cGdGWLd/cN9CJ9JvNwEoMRDghu0g==}
+ '@napi-rs/canvas-linux-x64-gnu@0.1.69':
+ resolution: {integrity: sha512-96X3bFAmzemfw84Ts6Jg/omL86uuynvK06MWGR/mp3JYNumY9RXofA14eF/kJIYelbYFWXcwpbcBR71lJ6G/YQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
- '@napi-rs/canvas-linux-x64-musl@0.1.68':
- resolution: {integrity: sha512-9c6rkc5195wNxuUHJdf4/mmnq433OQey9TNvQ9LspJazvHbfSkTij8wtKjASVQsJyPDva4fkWOeV/OQ7cLw0GQ==}
+ '@napi-rs/canvas-linux-x64-musl@0.1.69':
+ resolution: {integrity: sha512-2QTsEFO72Kwkj53W9hc5y1FAUvdGx0V+pjJB+9oQF6Ys9+y989GyPIl5wZDzeh8nIJW6koZZ1eFa8pD+pA5BFQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
- '@napi-rs/canvas-win32-x64-msvc@0.1.68':
- resolution: {integrity: sha512-Fc5Dez23u0FoSATurT6/w1oMytiRnKWEinHivdMvXpge6nG4YvhrASrtqMk8dGJMVQpHr8QJYF45rOrx2YU2Aw==}
+ '@napi-rs/canvas-win32-x64-msvc@0.1.69':
+ resolution: {integrity: sha512-Q4YA8kVnKarApBVLu7F8icGlIfSll5Glswo5hY6gPS4Is2dCI8+ig9OeDM8RlwYevUIxKq8lZBypN8Q1iLAQ7w==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
- '@napi-rs/canvas@0.1.68':
- resolution: {integrity: sha512-LQESrePLEBLvhuFkXx9jjBXRC2ClYsO5mqQ1m/puth5z9SOuM3N/B3vDuqnC3RJFktDktyK9khGvo7dTkqO9uQ==}
+ '@napi-rs/canvas@0.1.69':
+ resolution: {integrity: sha512-ydvNeJMRm+l3T14yCoUKqjYQiEdXDq1isznI93LEBGYssXKfSaLNLHOkeM4z9Fnw9Pkt2EKOCAtW9cS4b00Zcg==}
engines: {node: '>= 10'}
'@nodelib/fs.scandir@2.1.5':
@@ -4108,8 +4105,8 @@ packages:
resolution: {integrity: sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
- '@pkgr/core@0.2.0':
- resolution: {integrity: sha512-vsJDAkYR6qCPu+ioGScGiMYR7LvZYIXh/dlQeviqoTWNCVfKTLYD/LkNWH4Mxsv2a5vpIRc77FN5DnmK1eBggQ==}
+ '@pkgr/core@0.2.4':
+ resolution: {integrity: sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
'@playwright/test@1.51.1':
@@ -4847,8 +4844,8 @@ packages:
typescript:
optional: true
- '@typescript-eslint/eslint-plugin@8.29.0':
- resolution: {integrity: sha512-PAIpk/U7NIS6H7TEtN45SPGLQaHNgB7wSjsQV/8+KYokAb2T/gloOA/Bee2yd4/yKVhPKe5LlaUGhAZk5zmSaQ==}
+ '@typescript-eslint/eslint-plugin@8.30.1':
+ resolution: {integrity: sha512-v+VWphxMjn+1t48/jO4t950D6KR8JaJuNXzi33Ve6P8sEmPr5k6CEXjdGwT6+LodVnEa91EQCtwjWNUCPweo+Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
@@ -4871,8 +4868,8 @@ packages:
typescript:
optional: true
- '@typescript-eslint/parser@8.29.0':
- resolution: {integrity: sha512-8C0+jlNJOwQso2GapCVWWfW/rzaq7Lbme+vGUFKE31djwNncIpgXD7Cd4weEsDdkoZDjH0lwwr3QDQFuyrMg9g==}
+ '@typescript-eslint/parser@8.30.1':
+ resolution: {integrity: sha512-H+vqmWwT5xoNrXqWs/fesmssOW70gxFlgcMlYcBaWNPIEWDgLa4W9nkSPmhuOgLnXq9QYgkZ31fhDyLhleCsAg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -4890,8 +4887,8 @@ packages:
resolution: {integrity: sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==}
engines: {node: ^16.0.0 || >=18.0.0}
- '@typescript-eslint/scope-manager@8.29.0':
- resolution: {integrity: sha512-aO1PVsq7Gm+tcghabUpzEnVSFMCU4/nYIgC2GOatJcllvWfnhrgW0ZEbnTxm36QsikmCN1K/6ZgM7fok2I7xNw==}
+ '@typescript-eslint/scope-manager@8.30.1':
+ resolution: {integrity: sha512-+C0B6ChFXZkuaNDl73FJxRYT0G7ufVPOSQkqkpM/U198wUwUFOtgo1k/QzFh1KjpBitaK7R1tgjVz6o9HmsRPg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/type-utils@5.62.0':
@@ -4904,8 +4901,8 @@ packages:
typescript:
optional: true
- '@typescript-eslint/type-utils@8.29.0':
- resolution: {integrity: sha512-ahaWQ42JAOx+NKEf5++WC/ua17q5l+j1GFrbbpVKzFL/tKVc0aYY8rVSYUpUvt2hUP1YBr7mwXzx+E/DfUWI9Q==}
+ '@typescript-eslint/type-utils@8.30.1':
+ resolution: {integrity: sha512-64uBF76bfQiJyHgZISC7vcNz3adqQKIccVoKubyQcOnNcdJBvYOILV1v22Qhsw3tw3VQu5ll8ND6hycgAR5fEA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -4923,8 +4920,8 @@ packages:
resolution: {integrity: sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==}
engines: {node: ^16.0.0 || >=18.0.0}
- '@typescript-eslint/types@8.29.0':
- resolution: {integrity: sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg==}
+ '@typescript-eslint/types@8.30.1':
+ resolution: {integrity: sha512-81KawPfkuulyWo5QdyG/LOKbspyyiW+p4vpn4bYO7DM/hZImlVnFwrpCTnmNMOt8CvLRr5ojI9nU1Ekpw4RcEw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@4.33.0':
@@ -4954,8 +4951,8 @@ packages:
typescript:
optional: true
- '@typescript-eslint/typescript-estree@8.29.0':
- resolution: {integrity: sha512-yOfen3jE9ISZR/hHpU/bmNvTtBW1NjRbkSFdZOksL1N+ybPEE7UVGMwqvS6CP022Rp00Sb0tdiIkhSCe6NI8ow==}
+ '@typescript-eslint/typescript-estree@8.30.1':
+ resolution: {integrity: sha512-kQQnxymiUy9tTb1F2uep9W6aBiYODgq5EMSk6Nxh4Z+BDUoYUSa029ISs5zTzKBFnexQEh71KqwjKnRz58lusQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <5.9.0'
@@ -4972,8 +4969,8 @@ packages:
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
- '@typescript-eslint/utils@8.29.0':
- resolution: {integrity: sha512-gX/A0Mz9Bskm8avSWFcK0gP7cZpbY4AIo6B0hWYFCaIsz750oaiWR4Jr2CI+PQhfW1CpcQr9OlfPS+kMFegjXA==}
+ '@typescript-eslint/utils@8.30.1':
+ resolution: {integrity: sha512-T/8q4R9En2tcEsWPQgB5BQ0XJVOtfARcUvOa8yJP3fh9M/mXraLxZrkCfGb6ChrO/V3W+Xbd04RacUEqk1CFEQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -4991,8 +4988,8 @@ packages:
resolution: {integrity: sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==}
engines: {node: ^16.0.0 || >=18.0.0}
- '@typescript-eslint/visitor-keys@8.29.0':
- resolution: {integrity: sha512-Sne/pVz8ryR03NFK21VpN88dZ2FdQXOlq3VIklbrTYEt8yXtRFr9tvUhqvCeKjqYk5FSim37sHbooT6vzBTZcg==}
+ '@typescript-eslint/visitor-keys@8.30.1':
+ resolution: {integrity: sha512-aEhgas7aJ6vZnNFC7K4/vMGDGyOiqWcYZPpIWrTKuTAlsvDNKy2GFDqh9smL+iq069ZvR0YzEeq0B8NJlLzjFA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@uiw/codemirror-extensions-basic-setup@4.22.2':
@@ -5149,7 +5146,6 @@ packages:
abab@2.0.6:
resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
- deprecated: Use your platform's native atob() and btoa() methods instead
abort-controller@3.0.0:
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
@@ -5331,10 +5327,6 @@ packages:
array-ify@1.0.0:
resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==}
- array-includes@3.1.7:
- resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==}
- engines: {node: '>= 0.4'}
-
array-includes@3.1.8:
resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==}
engines: {node: '>= 0.4'}
@@ -5372,10 +5364,6 @@ packages:
resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==}
engines: {node: '>= 0.4'}
- array.prototype.flatmap@1.3.2:
- resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==}
- engines: {node: '>= 0.4'}
-
array.prototype.flatmap@1.3.3:
resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==}
engines: {node: '>= 0.4'}
@@ -5943,7 +5931,6 @@ packages:
core-js@2.6.12:
resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==}
- deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
core-js@3.33.2:
resolution: {integrity: sha512-XeBzWI6QL3nJQiHmdzbAOiMYqjrb7hwU7A39Qhvd/POSa/t9E1AeZyEZx3fNvp/vtM8zXwhoL0FsiS0hD0pruQ==}
@@ -6419,7 +6406,6 @@ packages:
domexception@4.0.0:
resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==}
engines: {node: '>=12'}
- deprecated: Use your platform's native DOMException instead
domhandler@3.3.0:
resolution: {integrity: sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==}
@@ -6686,12 +6672,6 @@ packages:
engines: {node: '>=6.0'}
hasBin: true
- eslint-config-prettier@10.1.1:
- resolution: {integrity: sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw==}
- hasBin: true
- peerDependencies:
- eslint: '>=7.0.0'
-
eslint-config-prettier@8.10.0:
resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==}
hasBin: true
@@ -6708,8 +6688,8 @@ packages:
'@types/estree':
optional: true
- eslint-plugin-cypress@4.2.0:
- resolution: {integrity: sha512-v5cyt0VYb1tEEODBJSE44PocYOwQsckyexJhCs7LtdD3FGO6D2GjnZB2s2Sts4RcxdxECTWX01nObOZRs26bQw==}
+ eslint-plugin-cypress@4.2.1:
+ resolution: {integrity: sha512-WNhKkQPqXcbDL7pxGnNYBVLlAIOk6eHdFGQFRELsba871guZZe8zZe50GAjBXSZKcvUWbzCUopM+8ArlngdyGQ==}
peerDependencies:
eslint: '>=9'
@@ -6736,8 +6716,8 @@ packages:
jest:
optional: true
- eslint-plugin-package-json@0.29.0:
- resolution: {integrity: sha512-S2YjWLMb+vaI0QbvkSrM6F2lEulaehGWEgHAXSoJI0F2eDw4udp5gtdFyKMLP2GSrfJB5cnKPnSJiOO5RGuaKg==}
+ eslint-plugin-package-json@0.29.1:
+ resolution: {integrity: sha512-4Jn1YO0JJyqs2W7Tt9I0QahQ0sPc2G5hLcWBUxkTdVF84Rdn+bVm9NY/XbjVJOlujkgZAK8Hi8irv+Mx4aTqaw==}
engines: {node: '>=18'}
peerDependencies:
eslint: '>=8.0.0'
@@ -6848,16 +6828,6 @@ packages:
deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
hasBin: true
- eslint@9.23.0:
- resolution: {integrity: sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- hasBin: true
- peerDependencies:
- jiti: '*'
- peerDependenciesMeta:
- jiti:
- optional: true
-
eslint@9.24.0:
resolution: {integrity: sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -7288,16 +7258,13 @@ packages:
glob@7.2.0:
resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==}
- deprecated: Glob versions prior to v9 are no longer supported
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
- deprecated: Glob versions prior to v9 are no longer supported
glob@8.1.0:
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
engines: {node: '>=12'}
- deprecated: Glob versions prior to v9 are no longer supported
glob@9.3.5:
resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==}
@@ -7566,10 +7533,6 @@ packages:
resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==}
engines: {node: '>= 4'}
- ignore@5.2.4:
- resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
- engines: {node: '>= 4'}
-
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@@ -7623,7 +7586,6 @@ packages:
inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
- deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@@ -8431,11 +8393,9 @@ packages:
lodash.get@4.4.2:
resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
- deprecated: This package is deprecated. Use the optional chaining (?.) operator instead.
lodash.isequal@4.5.0:
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
- deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
@@ -9010,18 +8970,10 @@ packages:
resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
engines: {node: '>= 0.4'}
- object.entries@1.1.7:
- resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==}
- engines: {node: '>= 0.4'}
-
object.entries@1.1.9:
resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==}
engines: {node: '>= 0.4'}
- object.fromentries@2.0.7:
- resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==}
- engines: {node: '>= 0.4'}
-
object.fromentries@2.0.8:
resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==}
engines: {node: '>= 0.4'}
@@ -9029,10 +8981,6 @@ packages:
object.hasown@1.1.3:
resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==}
- object.values@1.1.7:
- resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==}
- engines: {node: '>= 0.4'}
-
object.values@1.2.1:
resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
engines: {node: '>= 0.4'}
@@ -10537,7 +10485,6 @@ packages:
stable@0.1.8:
resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==}
- deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility'
stack-trace@0.0.9:
resolution: {integrity: sha512-vjUc6sfgtgY0dxCdnc40mK6Oftjo9+2K8H/NG81TMhgL392FtiPA9tn9RLyTxXmTLPJPjF3VyzFp6bsWFLisMQ==}
@@ -10588,9 +10535,6 @@ packages:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
- string.prototype.matchall@4.0.10:
- resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==}
-
string.prototype.matchall@4.0.12:
resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==}
engines: {node: '>= 0.4'}
@@ -10738,8 +10682,8 @@ packages:
symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
- synckit@0.11.2:
- resolution: {integrity: sha512-1IUffI8zZ8qUMB3NUJIjk0RpLroG/8NkQDAWH1NbB2iJ0/5pn3M8rxfNzMz4GH9OnYaGYn31LEDSXJp/qIlxgA==}
+ synckit@0.11.4:
+ resolution: {integrity: sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ==}
engines: {node: ^14.18.0 || >=16.0.0}
synckit@0.9.2:
@@ -11060,8 +11004,8 @@ packages:
typedarray@0.0.6:
resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
- typescript-eslint@8.29.0:
- resolution: {integrity: sha512-ep9rVd9B4kQsZ7ZnWCVxUE/xDLUUUsRzE0poAeNu+4CkFErLfuvPt/qtm2EpnSyfvsR0S6QzDFSrPCFBwf64fg==}
+ typescript-eslint@8.30.1:
+ resolution: {integrity: sha512-D7lC0kcehVH7Mb26MRQi64LMyRJsj3dToJxM1+JVTl53DQSV5/7oUGWQLcKl1C1KnoVHxMMU2FNQMffr7F3Row==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -11927,7 +11871,7 @@ snapshots:
'@babel/helper-validator-identifier': 7.25.9
chalk: 2.4.2
js-tokens: 4.0.0
- picocolors: 1.1.0
+ picocolors: 1.1.1
'@babel/parser@7.22.5':
dependencies:
@@ -13486,28 +13430,13 @@ snapshots:
eslint: 7.32.0
eslint-visitor-keys: 3.4.3
- '@eslint-community/eslint-utils@4.4.0(eslint@9.23.0(jiti@2.4.2))':
- dependencies:
- eslint: 9.23.0(jiti@2.4.2)
- eslint-visitor-keys: 3.4.3
-
'@eslint-community/eslint-utils@4.4.0(eslint@9.24.0(jiti@2.4.2))':
dependencies:
eslint: 9.24.0(jiti@2.4.2)
eslint-visitor-keys: 3.4.3
- '@eslint-community/regexpp@4.11.1': {}
-
'@eslint-community/regexpp@4.12.1': {}
- '@eslint/config-array@0.19.2':
- dependencies:
- '@eslint/object-schema': 2.1.6
- debug: 4.3.7
- minimatch: 3.1.2
- transitivePeerDependencies:
- - supports-color
-
'@eslint/config-array@0.20.0':
dependencies:
'@eslint/object-schema': 2.1.6
@@ -13554,8 +13483,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@eslint/js@9.23.0': {}
-
'@eslint/js@9.24.0': {}
'@eslint/object-schema@2.1.6': {}
@@ -14004,6 +13931,8 @@ snapshots:
sort-object: 3.0.3
tinyqueue: 3.0.0
+ '@melloware/coloris@0.24.0': {}
+
'@mendix/pluggable-widgets-tools@10.18.2(@jest/transform@29.7.0)(@jest/types@29.6.3)(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/babel__core@7.20.3)(@types/node@22.14.0)(picomatch@4.0.2)(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.21.0)(@babel/preset-env@7.26.9(@babel/core@7.21.0))(@types/react@18.2.36)(react@18.2.0)(typescript@5.1.6))(react@18.2.0)(tslib@2.8.1)':
dependencies:
'@babel/core': 7.26.10
@@ -14056,7 +13985,7 @@ snapshots:
identity-obj-proxy: 3.0.0
jasmine: 3.99.0
jasmine-core: 3.99.1
- jest: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.14.0)(typescript@5.8.2))
+ jest: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.14.0)(typescript@5.1.6))
jest-environment-jsdom: 29.7.0
jest-jasmine2: 29.7.0
jest-junit: 13.2.0
@@ -14078,13 +14007,13 @@ snapshots:
rollup-plugin-command: 1.1.3
rollup-plugin-license: 3.6.0(picomatch@4.0.2)(rollup@3.29.5)
rollup-plugin-livereload: 2.0.5
- rollup-plugin-postcss: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.14.0)(typescript@5.8.2))
+ rollup-plugin-postcss: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.14.0)(typescript@5.1.6))
rollup-plugin-re: 1.0.7
sass: 1.58.3
semver: 7.7.1
shelljs: 0.8.5
shx: 0.3.4
- ts-jest: 29.2.6(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.14.0)(typescript@5.8.2)))(typescript@5.8.2)
+ ts-jest: 29.2.6(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.14.0)(typescript@5.1.6)))(typescript@5.8.2)
ts-node: 10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.14.0)(typescript@5.8.2)
typescript: 5.8.2
xml2js: 0.6.2
@@ -14322,48 +14251,48 @@ snapshots:
- tslib
- utf-8-validate
- '@napi-rs/canvas-android-arm64@0.1.68':
+ '@napi-rs/canvas-android-arm64@0.1.69':
optional: true
- '@napi-rs/canvas-darwin-arm64@0.1.68':
+ '@napi-rs/canvas-darwin-arm64@0.1.69':
optional: true
- '@napi-rs/canvas-darwin-x64@0.1.68':
+ '@napi-rs/canvas-darwin-x64@0.1.69':
optional: true
- '@napi-rs/canvas-linux-arm-gnueabihf@0.1.68':
+ '@napi-rs/canvas-linux-arm-gnueabihf@0.1.69':
optional: true
- '@napi-rs/canvas-linux-arm64-gnu@0.1.68':
+ '@napi-rs/canvas-linux-arm64-gnu@0.1.69':
optional: true
- '@napi-rs/canvas-linux-arm64-musl@0.1.68':
+ '@napi-rs/canvas-linux-arm64-musl@0.1.69':
optional: true
- '@napi-rs/canvas-linux-riscv64-gnu@0.1.68':
+ '@napi-rs/canvas-linux-riscv64-gnu@0.1.69':
optional: true
- '@napi-rs/canvas-linux-x64-gnu@0.1.68':
+ '@napi-rs/canvas-linux-x64-gnu@0.1.69':
optional: true
- '@napi-rs/canvas-linux-x64-musl@0.1.68':
+ '@napi-rs/canvas-linux-x64-musl@0.1.69':
optional: true
- '@napi-rs/canvas-win32-x64-msvc@0.1.68':
+ '@napi-rs/canvas-win32-x64-msvc@0.1.69':
optional: true
- '@napi-rs/canvas@0.1.68':
+ '@napi-rs/canvas@0.1.69':
optionalDependencies:
- '@napi-rs/canvas-android-arm64': 0.1.68
- '@napi-rs/canvas-darwin-arm64': 0.1.68
- '@napi-rs/canvas-darwin-x64': 0.1.68
- '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.68
- '@napi-rs/canvas-linux-arm64-gnu': 0.1.68
- '@napi-rs/canvas-linux-arm64-musl': 0.1.68
- '@napi-rs/canvas-linux-riscv64-gnu': 0.1.68
- '@napi-rs/canvas-linux-x64-gnu': 0.1.68
- '@napi-rs/canvas-linux-x64-musl': 0.1.68
- '@napi-rs/canvas-win32-x64-msvc': 0.1.68
+ '@napi-rs/canvas-android-arm64': 0.1.69
+ '@napi-rs/canvas-darwin-arm64': 0.1.69
+ '@napi-rs/canvas-darwin-x64': 0.1.69
+ '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.69
+ '@napi-rs/canvas-linux-arm64-gnu': 0.1.69
+ '@napi-rs/canvas-linux-arm64-musl': 0.1.69
+ '@napi-rs/canvas-linux-riscv64-gnu': 0.1.69
+ '@napi-rs/canvas-linux-x64-gnu': 0.1.69
+ '@napi-rs/canvas-linux-x64-musl': 0.1.69
+ '@napi-rs/canvas-win32-x64-msvc': 0.1.69
optional: true
'@nodelib/fs.scandir@2.1.5':
@@ -14380,7 +14309,7 @@ snapshots:
'@pkgr/core@0.1.2': {}
- '@pkgr/core@0.2.0': {}
+ '@pkgr/core@0.2.4': {}
'@playwright/test@1.51.1':
dependencies:
@@ -15536,7 +15465,7 @@ snapshots:
'@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.2))(eslint@7.32.0)(typescript@5.8.2)':
dependencies:
- '@eslint-community/regexpp': 4.11.1
+ '@eslint-community/regexpp': 4.12.1
'@typescript-eslint/parser': 5.62.0(eslint@7.32.0)(typescript@5.8.2)
'@typescript-eslint/scope-manager': 5.62.0
'@typescript-eslint/type-utils': 5.62.0(eslint@7.32.0)(typescript@5.8.2)
@@ -15553,15 +15482,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)':
+ '@typescript-eslint/eslint-plugin@8.30.1(@typescript-eslint/parser@8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)':
dependencies:
'@eslint-community/regexpp': 4.12.1
- '@typescript-eslint/parser': 8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
- '@typescript-eslint/scope-manager': 8.29.0
- '@typescript-eslint/type-utils': 8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
- '@typescript-eslint/utils': 8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
- '@typescript-eslint/visitor-keys': 8.29.0
- eslint: 9.23.0(jiti@2.4.2)
+ '@typescript-eslint/parser': 8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)
+ '@typescript-eslint/scope-manager': 8.30.1
+ '@typescript-eslint/type-utils': 8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)
+ '@typescript-eslint/utils': 8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)
+ '@typescript-eslint/visitor-keys': 8.30.1
+ eslint: 9.24.0(jiti@2.4.2)
graphemer: 1.4.0
ignore: 5.3.2
natural-compare: 1.4.0
@@ -15595,14 +15524,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)':
+ '@typescript-eslint/parser@8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)':
dependencies:
- '@typescript-eslint/scope-manager': 8.29.0
- '@typescript-eslint/types': 8.29.0
- '@typescript-eslint/typescript-estree': 8.29.0(typescript@5.8.2)
- '@typescript-eslint/visitor-keys': 8.29.0
+ '@typescript-eslint/scope-manager': 8.30.1
+ '@typescript-eslint/types': 8.30.1
+ '@typescript-eslint/typescript-estree': 8.30.1(typescript@5.8.2)
+ '@typescript-eslint/visitor-keys': 8.30.1
debug: 4.3.7
- eslint: 9.23.0(jiti@2.4.2)
+ eslint: 9.24.0(jiti@2.4.2)
typescript: 5.8.2
transitivePeerDependencies:
- supports-color
@@ -15622,10 +15551,10 @@ snapshots:
'@typescript-eslint/types': 6.13.2
'@typescript-eslint/visitor-keys': 6.13.2
- '@typescript-eslint/scope-manager@8.29.0':
+ '@typescript-eslint/scope-manager@8.30.1':
dependencies:
- '@typescript-eslint/types': 8.29.0
- '@typescript-eslint/visitor-keys': 8.29.0
+ '@typescript-eslint/types': 8.30.1
+ '@typescript-eslint/visitor-keys': 8.30.1
'@typescript-eslint/type-utils@5.62.0(eslint@7.32.0)(typescript@5.8.2)':
dependencies:
@@ -15639,12 +15568,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/type-utils@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)':
+ '@typescript-eslint/type-utils@8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)':
dependencies:
- '@typescript-eslint/typescript-estree': 8.29.0(typescript@5.8.2)
- '@typescript-eslint/utils': 8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
+ '@typescript-eslint/typescript-estree': 8.30.1(typescript@5.8.2)
+ '@typescript-eslint/utils': 8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)
debug: 4.3.7
- eslint: 9.23.0(jiti@2.4.2)
+ eslint: 9.24.0(jiti@2.4.2)
ts-api-utils: 2.1.0(typescript@5.8.2)
typescript: 5.8.2
transitivePeerDependencies:
@@ -15656,7 +15585,7 @@ snapshots:
'@typescript-eslint/types@6.13.2': {}
- '@typescript-eslint/types@8.29.0': {}
+ '@typescript-eslint/types@8.30.1': {}
'@typescript-eslint/typescript-estree@4.33.0(typescript@5.8.2)':
dependencies:
@@ -15700,10 +15629,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/typescript-estree@8.29.0(typescript@5.8.2)':
+ '@typescript-eslint/typescript-estree@8.30.1(typescript@5.8.2)':
dependencies:
- '@typescript-eslint/types': 8.29.0
- '@typescript-eslint/visitor-keys': 8.29.0
+ '@typescript-eslint/types': 8.30.1
+ '@typescript-eslint/visitor-keys': 8.30.1
debug: 4.3.7
fast-glob: 3.3.2
is-glob: 4.0.3
@@ -15729,27 +15658,27 @@ snapshots:
- supports-color
- typescript
- '@typescript-eslint/utils@6.13.2(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)':
+ '@typescript-eslint/utils@6.13.2(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)':
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@9.23.0(jiti@2.4.2))
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.24.0(jiti@2.4.2))
'@types/json-schema': 7.0.15
'@types/semver': 7.5.4
'@typescript-eslint/scope-manager': 6.13.2
'@typescript-eslint/types': 6.13.2
'@typescript-eslint/typescript-estree': 6.13.2(typescript@5.8.2)
- eslint: 9.23.0(jiti@2.4.2)
+ eslint: 9.24.0(jiti@2.4.2)
semver: 7.7.1
transitivePeerDependencies:
- supports-color
- typescript
- '@typescript-eslint/utils@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)':
+ '@typescript-eslint/utils@8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)':
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@9.23.0(jiti@2.4.2))
- '@typescript-eslint/scope-manager': 8.29.0
- '@typescript-eslint/types': 8.29.0
- '@typescript-eslint/typescript-estree': 8.29.0(typescript@5.8.2)
- eslint: 9.23.0(jiti@2.4.2)
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.24.0(jiti@2.4.2))
+ '@typescript-eslint/scope-manager': 8.30.1
+ '@typescript-eslint/types': 8.30.1
+ '@typescript-eslint/typescript-estree': 8.30.1(typescript@5.8.2)
+ eslint: 9.24.0(jiti@2.4.2)
typescript: 5.8.2
transitivePeerDependencies:
- supports-color
@@ -15769,9 +15698,9 @@ snapshots:
'@typescript-eslint/types': 6.13.2
eslint-visitor-keys: 3.4.3
- '@typescript-eslint/visitor-keys@8.29.0':
+ '@typescript-eslint/visitor-keys@8.30.1':
dependencies:
- '@typescript-eslint/types': 8.29.0
+ '@typescript-eslint/types': 8.30.1
eslint-visitor-keys: 4.2.0
'@uiw/codemirror-extensions-basic-setup@4.22.2(@codemirror/autocomplete@6.16.2(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2)(@lezer/common@1.2.2))(@codemirror/commands@6.6.0)(@codemirror/language@6.10.2)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/view@6.34.2)':
@@ -16153,14 +16082,6 @@ snapshots:
array-ify@1.0.0: {}
- array-includes@3.1.7:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.3
- get-intrinsic: 1.2.4
- is-string: 1.0.7
-
array-includes@3.1.8:
dependencies:
call-bind: 1.0.7
@@ -16188,11 +16109,11 @@ snapshots:
array.prototype.filter@1.0.3:
dependencies:
- call-bind: 1.0.7
+ call-bind: 1.0.8
define-properties: 1.2.1
- es-abstract: 1.23.3
+ es-abstract: 1.23.9
es-array-method-boxes-properly: 1.0.0
- is-string: 1.0.7
+ is-string: 1.1.1
array.prototype.findlast@1.2.5:
dependencies:
@@ -16210,13 +16131,6 @@ snapshots:
es-abstract: 1.23.3
es-shim-unscopables: 1.0.2
- array.prototype.flatmap@1.3.2:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.3
- es-shim-unscopables: 1.0.2
-
array.prototype.flatmap@1.3.3:
dependencies:
call-bind: 1.0.8
@@ -17712,25 +17626,25 @@ snapshots:
array.prototype.flat: 1.3.2
cheerio: 1.0.0-rc.10
enzyme-shallow-equal: 1.0.5
- function.prototype.name: 1.1.6
+ function.prototype.name: 1.1.8
has: 1.0.4
html-element-map: 1.3.1
- is-boolean-object: 1.1.2
+ is-boolean-object: 1.2.2
is-callable: 1.2.7
- is-number-object: 1.0.7
- is-regex: 1.1.4
- is-string: 1.0.7
+ is-number-object: 1.1.1
+ is-regex: 1.2.1
+ is-string: 1.1.1
is-subset: 0.1.1
lodash.escape: 4.0.1
lodash.isequal: 4.5.0
- object-inspect: 1.13.1
+ object-inspect: 1.13.4
object-is: 1.1.5
- object.assign: 4.1.5
- object.entries: 1.1.7
- object.values: 1.1.7
+ object.assign: 4.1.7
+ object.entries: 1.1.9
+ object.values: 1.2.1
raf: 3.4.1
rst-selector-parser: 2.2.3
- string.prototype.trim: 1.2.9
+ string.prototype.trim: 1.2.10
errno@0.1.8:
dependencies:
@@ -17984,24 +17898,24 @@ snapshots:
optionalDependencies:
source-map: 0.6.1
- eslint-config-prettier@10.1.1(eslint@9.23.0(jiti@2.4.2)):
- dependencies:
- eslint: 9.23.0(jiti@2.4.2)
- optional: true
-
eslint-config-prettier@8.10.0(eslint@7.32.0):
dependencies:
eslint: 7.32.0
- eslint-fix-utils@0.2.1(@types/estree@1.0.6)(eslint@9.23.0(jiti@2.4.2)):
+ eslint-config-prettier@8.10.0(eslint@9.24.0(jiti@2.4.2)):
dependencies:
- eslint: 9.23.0(jiti@2.4.2)
+ eslint: 9.24.0(jiti@2.4.2)
+ optional: true
+
+ eslint-fix-utils@0.2.1(@types/estree@1.0.6)(eslint@9.24.0(jiti@2.4.2)):
+ dependencies:
+ eslint: 9.24.0(jiti@2.4.2)
optionalDependencies:
'@types/estree': 1.0.6
- eslint-plugin-cypress@4.2.0(eslint@9.23.0(jiti@2.4.2)):
+ eslint-plugin-cypress@4.2.1(eslint@9.24.0(jiti@2.4.2)):
dependencies:
- eslint: 9.23.0(jiti@2.4.2)
+ eslint: 9.24.0(jiti@2.4.2)
globals: 15.15.0
eslint-plugin-jest@24.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.2))(eslint@7.32.0)(typescript@5.8.2))(eslint@7.32.0)(typescript@5.8.2):
@@ -18014,24 +17928,24 @@ snapshots:
- supports-color
- typescript
- eslint-plugin-jest@28.11.0(@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.23.0(jiti@2.4.2))(jest@29.7.0(@types/node@22.14.0))(typescript@5.8.2):
+ eslint-plugin-jest@28.11.0(@typescript-eslint/eslint-plugin@8.30.1(@typescript-eslint/parser@8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.24.0(jiti@2.4.2))(jest@29.7.0(@types/node@22.14.0))(typescript@5.8.2):
dependencies:
- '@typescript-eslint/utils': 6.13.2(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
- eslint: 9.23.0(jiti@2.4.2)
+ '@typescript-eslint/utils': 6.13.2(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)
+ eslint: 9.24.0(jiti@2.4.2)
optionalDependencies:
- '@typescript-eslint/eslint-plugin': 8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
+ '@typescript-eslint/eslint-plugin': 8.30.1(@typescript-eslint/parser@8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)
jest: 29.7.0(@types/node@22.14.0)
transitivePeerDependencies:
- supports-color
- typescript
- eslint-plugin-package-json@0.29.0(@types/estree@1.0.6)(eslint@9.23.0(jiti@2.4.2))(jsonc-eslint-parser@2.4.0):
+ eslint-plugin-package-json@0.29.1(@types/estree@1.0.6)(eslint@9.24.0(jiti@2.4.2))(jsonc-eslint-parser@2.4.0):
dependencies:
'@altano/repository-tools': 0.1.1
detect-indent: 6.1.0
detect-newline: 3.1.0
- eslint: 9.23.0(jiti@2.4.2)
- eslint-fix-utils: 0.2.1(@types/estree@1.0.6)(eslint@9.23.0(jiti@2.4.2))
+ eslint: 9.24.0(jiti@2.4.2)
+ eslint-fix-utils: 0.2.1(@types/estree@1.0.6)(eslint@9.24.0(jiti@2.4.2))
jsonc-eslint-parser: 2.4.0
package-json-validator: 0.10.1
semver: 7.7.1
@@ -18054,50 +17968,50 @@ snapshots:
optionalDependencies:
eslint-config-prettier: 8.10.0(eslint@7.32.0)
- eslint-plugin-prettier@5.2.6(@types/eslint@9.6.1)(eslint-config-prettier@10.1.1(eslint@9.23.0(jiti@2.4.2)))(eslint@9.23.0(jiti@2.4.2))(prettier@3.5.3):
+ eslint-plugin-prettier@5.2.6(@types/eslint@9.6.1)(eslint-config-prettier@8.10.0(eslint@9.24.0(jiti@2.4.2)))(eslint@9.24.0(jiti@2.4.2))(prettier@3.5.3):
dependencies:
- eslint: 9.23.0(jiti@2.4.2)
+ eslint: 9.24.0(jiti@2.4.2)
prettier: 3.5.3
prettier-linter-helpers: 1.0.0
- synckit: 0.11.2
+ synckit: 0.11.4
optionalDependencies:
'@types/eslint': 9.6.1
- eslint-config-prettier: 10.1.1(eslint@9.23.0(jiti@2.4.2))
+ eslint-config-prettier: 8.10.0(eslint@9.24.0(jiti@2.4.2))
eslint-plugin-promise@4.3.1: {}
- eslint-plugin-promise@7.2.1(eslint@9.23.0(jiti@2.4.2)):
+ eslint-plugin-promise@7.2.1(eslint@9.24.0(jiti@2.4.2)):
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@9.23.0(jiti@2.4.2))
- eslint: 9.23.0(jiti@2.4.2)
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.24.0(jiti@2.4.2))
+ eslint: 9.24.0(jiti@2.4.2)
eslint-plugin-react-hooks@4.6.0(eslint@7.32.0):
dependencies:
eslint: 7.32.0
- eslint-plugin-react-hooks@5.2.0(eslint@9.23.0(jiti@2.4.2)):
+ eslint-plugin-react-hooks@5.2.0(eslint@9.24.0(jiti@2.4.2)):
dependencies:
- eslint: 9.23.0(jiti@2.4.2)
+ eslint: 9.24.0(jiti@2.4.2)
eslint-plugin-react@7.28.0(eslint@7.32.0):
dependencies:
- array-includes: 3.1.7
- array.prototype.flatmap: 1.3.2
+ array-includes: 3.1.8
+ array.prototype.flatmap: 1.3.3
doctrine: 2.1.0
eslint: 7.32.0
estraverse: 5.3.0
jsx-ast-utils: 3.3.5
minimatch: 3.1.2
- object.entries: 1.1.7
- object.fromentries: 2.0.7
+ object.entries: 1.1.9
+ object.fromentries: 2.0.8
object.hasown: 1.1.3
- object.values: 1.1.7
+ object.values: 1.2.1
prop-types: 15.8.1
resolve: 2.0.0-next.5
semver: 6.3.1
- string.prototype.matchall: 4.0.10
+ string.prototype.matchall: 4.0.12
- eslint-plugin-react@7.37.5(eslint@9.23.0(jiti@2.4.2)):
+ eslint-plugin-react@7.37.5(eslint@9.24.0(jiti@2.4.2)):
dependencies:
array-includes: 3.1.8
array.prototype.findlast: 1.2.5
@@ -18105,7 +18019,7 @@ snapshots:
array.prototype.tosorted: 1.1.4
doctrine: 2.1.0
es-iterator-helpers: 1.2.1
- eslint: 9.23.0(jiti@2.4.2)
+ eslint: 9.24.0(jiti@2.4.2)
estraverse: 5.3.0
hasown: 2.0.2
jsx-ast-utils: 3.3.5
@@ -18153,7 +18067,7 @@ snapshots:
'@humanwhocodes/config-array': 0.5.0
ajv: 6.12.6
chalk: 4.1.2
- cross-spawn: 7.0.3
+ cross-spawn: 7.0.6
debug: 4.3.7
doctrine: 3.0.0
enquirer: 2.4.1
@@ -18191,48 +18105,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint@9.23.0(jiti@2.4.2):
- dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@9.23.0(jiti@2.4.2))
- '@eslint-community/regexpp': 4.12.1
- '@eslint/config-array': 0.19.2
- '@eslint/config-helpers': 0.2.1
- '@eslint/core': 0.12.0
- '@eslint/eslintrc': 3.3.1
- '@eslint/js': 9.23.0
- '@eslint/plugin-kit': 0.2.8
- '@humanfs/node': 0.16.6
- '@humanwhocodes/module-importer': 1.0.1
- '@humanwhocodes/retry': 0.4.2
- '@types/estree': 1.0.6
- '@types/json-schema': 7.0.15
- ajv: 6.12.6
- chalk: 4.1.2
- cross-spawn: 7.0.6
- debug: 4.3.7
- escape-string-regexp: 4.0.0
- eslint-scope: 8.3.0
- eslint-visitor-keys: 4.2.0
- espree: 10.3.0
- esquery: 1.6.0
- esutils: 2.0.3
- fast-deep-equal: 3.1.3
- file-entry-cache: 8.0.0
- find-up: 5.0.0
- glob-parent: 6.0.2
- ignore: 5.3.2
- imurmurhash: 0.1.4
- is-glob: 4.0.3
- json-stable-stringify-without-jsonify: 1.0.1
- lodash.merge: 4.6.2
- minimatch: 3.1.2
- natural-compare: 1.4.0
- optionator: 0.9.4
- optionalDependencies:
- jiti: 2.4.2
- transitivePeerDependencies:
- - supports-color
-
eslint@9.24.0(jiti@2.4.2):
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@9.24.0(jiti@2.4.2))
@@ -18838,7 +18710,7 @@ snapshots:
dependencies:
dir-glob: 3.0.1
fast-glob: 3.2.12
- ignore: 5.2.4
+ ignore: 5.3.2
merge2: 1.4.1
slash: 4.0.0
@@ -19011,7 +18883,7 @@ snapshots:
html-element-map@1.3.1:
dependencies:
array.prototype.filter: 1.0.3
- call-bind: 1.0.7
+ call-bind: 1.0.8
html-encoding-sniffer@3.0.0:
dependencies:
@@ -19090,8 +18962,6 @@ snapshots:
ignore@4.0.6: {}
- ignore@5.2.4: {}
-
ignore@5.3.2: {}
ignore@7.0.3: {}
@@ -19920,7 +19790,7 @@ snapshots:
jest-snapshot@29.7.0:
dependencies:
'@babel/core': 7.26.10
- '@babel/generator': 7.26.9
+ '@babel/generator': 7.26.10
'@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.10)
'@babel/plugin-syntax-typescript': 7.25.7(@babel/core@7.26.10)
'@babel/types': 7.26.10
@@ -21064,16 +20934,10 @@ snapshots:
call-bind: 1.0.8
call-bound: 1.0.4
define-properties: 1.2.1
- es-object-atoms: 1.0.0
+ es-object-atoms: 1.1.1
has-symbols: 1.1.0
object-keys: 1.1.1
- object.entries@1.1.7:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.3
-
object.entries@1.1.9:
dependencies:
call-bind: 1.0.8
@@ -21081,12 +20945,6 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.1.1
- object.fromentries@2.0.7:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.3
-
object.fromentries@2.0.8:
dependencies:
call-bind: 1.0.7
@@ -21097,13 +20955,7 @@ snapshots:
object.hasown@1.1.3:
dependencies:
define-properties: 1.2.1
- es-abstract: 1.23.3
-
- object.values@1.1.7:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.3
+ es-abstract: 1.23.9
object.values@1.2.1:
dependencies:
@@ -21306,7 +21158,7 @@ snapshots:
pdfjs-dist@5.1.91:
optionalDependencies:
- '@napi-rs/canvas': 0.1.68
+ '@napi-rs/canvas': 0.1.69
peggy@1.2.0: {}
@@ -21867,7 +21719,7 @@ snapshots:
postcss@8.4.21:
dependencies:
nanoid: 3.3.6
- picocolors: 1.0.0
+ picocolors: 1.1.0
source-map-js: 1.0.2
postcss@8.4.31:
@@ -22921,7 +22773,7 @@ snapshots:
dependencies:
call-bind: 1.0.7
es-errors: 1.3.0
- is-regex: 1.1.4
+ is-regex: 1.2.1
safe-regex-test@1.1.0:
dependencies:
@@ -23344,18 +23196,6 @@ snapshots:
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
- string.prototype.matchall@4.0.10:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.3
- get-intrinsic: 1.2.4
- has-symbols: 1.0.3
- internal-slot: 1.0.7
- regexp.prototype.flags: 1.5.2
- set-function-name: 2.0.1
- side-channel: 1.0.4
-
string.prototype.matchall@4.0.12:
dependencies:
call-bind: 1.0.8
@@ -23384,7 +23224,7 @@ snapshots:
define-data-property: 1.1.4
define-properties: 1.2.1
es-abstract: 1.23.9
- es-object-atoms: 1.0.0
+ es-object-atoms: 1.1.1
has-property-descriptors: 1.0.2
string.prototype.trim@1.2.9:
@@ -23409,7 +23249,7 @@ snapshots:
string.prototype.trimstart@1.0.8:
dependencies:
- call-bind: 1.0.7
+ call-bind: 1.0.8
define-properties: 1.2.1
es-object-atoms: 1.0.0
@@ -23533,9 +23373,9 @@ snapshots:
symbol-tree@3.2.4: {}
- synckit@0.11.2:
+ synckit@0.11.4:
dependencies:
- '@pkgr/core': 0.2.0
+ '@pkgr/core': 0.2.4
tslib: 2.8.1
synckit@0.9.2:
@@ -23928,12 +23768,12 @@ snapshots:
typedarray@0.0.6: {}
- typescript-eslint@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2):
+ typescript-eslint@8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2):
dependencies:
- '@typescript-eslint/eslint-plugin': 8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
- '@typescript-eslint/parser': 8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
- '@typescript-eslint/utils': 8.29.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
- eslint: 9.23.0(jiti@2.4.2)
+ '@typescript-eslint/eslint-plugin': 8.30.1(@typescript-eslint/parser@8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)
+ '@typescript-eslint/parser': 8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)
+ '@typescript-eslint/utils': 8.30.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.2)
+ eslint: 9.24.0(jiti@2.4.2)
typescript: 5.8.2
transitivePeerDependencies:
- supports-color
|