From 860abacd840e961e30e9a955f311b38715ebf780 Mon Sep 17 00:00:00 2001 From: gjulivan Date: Tue, 18 Feb 2025 15:29:06 +0100 Subject: [PATCH 01/28] chore: add better table --- .../rich-text-web/src/components/Editor.tsx | 11 +- .../src/utils/customPluginRegisters.ts | 8 + .../assets/css/quill-table-better.scss | 546 ++++++++++++ .../assets/icon/align-bottom.svg | 1 + .../assets/icon/align-center.svg | 1 + .../assets/icon/align-justify.svg | 1 + .../assets/icon/align-left.svg | 1 + .../assets/icon/align-middle.svg | 1 + .../assets/icon/align-right.svg | 1 + .../assets/icon/align-top.svg | 1 + .../quill-table-better/assets/icon/cell.svg | 1 + .../quill-table-better/assets/icon/check.png | Bin 0 -> 209 bytes .../quill-table-better/assets/icon/check.svg | 1 + .../quill-table-better/assets/icon/close.svg | 1 + .../quill-table-better/assets/icon/column.svg | 1 + .../quill-table-better/assets/icon/copy.svg | 1 + .../quill-table-better/assets/icon/delete.svg | 1 + .../quill-table-better/assets/icon/down.svg | 1 + .../quill-table-better/assets/icon/erase.svg | 1 + .../quill-table-better/assets/icon/merge.svg | 1 + .../assets/icon/palette.svg | 1 + .../quill-table-better/assets/icon/row.svg | 1 + .../quill-table-better/assets/icon/save.svg | 1 + .../quill-table-better/assets/icon/table.svg | 1 + .../quill-table-better/assets/icon/wrap.svg | 1 + .../quill-table-better/config/index.ts | 438 ++++++++++ .../quill-table-better/formats/header.ts | 74 ++ .../quill-table-better/formats/list.ts | 150 ++++ .../quill-table-better/formats/table.ts | 744 ++++++++++++++++ .../quill-table-better/language/de_DE.ts | 59 ++ .../quill-table-better/language/en_US.ts | 59 ++ .../quill-table-better/language/fr_FR.ts | 59 ++ .../quill-table-better/language/index.ts | 61 ++ .../quill-table-better/language/pl_PL.ts | 59 ++ .../quill-table-better/language/ru_RU.ts | 59 ++ .../quill-table-better/language/tr_TR.ts | 59 ++ .../quill-table-better/language/zh_CN.ts | 59 ++ .../quill-table-better/modules/clipboard.ts | 43 + .../quill-table-better/modules/toolbar.ts | 225 +++++ .../quill-table-better/quill-table-better.ts | 416 +++++++++ .../utils/formats/quill-table-better/types.ts | 17 + .../quill-table-better/ui/cell-selection.ts | 704 +++++++++++++++ .../quill-table-better/ui/operate-line.ts | 437 ++++++++++ .../quill-table-better/ui/table-menus.ts | 807 ++++++++++++++++++ .../ui/table-properties-form.ts | 735 ++++++++++++++++ .../quill-table-better/ui/toolbar-table.ts | 123 +++ .../utils/clipboard-matchers.ts | 88 ++ .../formats/quill-table-better/utils/index.ts | 378 ++++++++ .../rich-text-web/src/utils/formats/table.ts | 81 ++ .../rich-text-web/typings/declare-svg.ts | 2 + 50 files changed, 6521 insertions(+), 1 deletion(-) create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/css/quill-table-better.scss create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-bottom.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-center.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-justify.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-left.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-middle.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-right.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-top.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/cell.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/check.png create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/check.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/close.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/column.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/copy.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/delete.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/down.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/erase.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/merge.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/palette.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/row.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/save.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/table.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/wrap.svg create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/config/index.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/header.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/list.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/de_DE.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/en_US.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/fr_FR.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/index.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/pl_PL.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/ru_RU.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/tr_TR.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/zh_CN.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/modules/clipboard.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/modules/toolbar.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/quill-table-better.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/types.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/cell-selection.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/operate-line.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/table-menus.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/table-properties-form.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/toolbar-table.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/utils/clipboard-matchers.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/utils/index.ts create mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/table.ts diff --git a/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx b/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx index 0cfc3a68c3..9ca522d496 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx @@ -11,6 +11,8 @@ import { useLayoutEffect, useRef } from "react"; +import QuillTableBetter from "../utils/formats/quill-table-better/quill-table-better"; +import "../utils/formats/quill-table-better/assets/css/quill-table-better.scss"; import "../utils/customPluginRegisters"; import MxQuill from "../utils/MxQuill"; import { @@ -90,6 +92,12 @@ const Editor = forwardRef((props: EditorProps, ref: MutableRefObject label { + position: absolute; + left: 0; + top: -50%; + transform: translateY(50%) scale(0.75); + color: #999; + background: $color-white; + display: none; + } + } + &-status { + @extend .ql-table-tooltip-error; + max-width: 160px; + width: max-content; + } + &-error { + & > input { + &:focus { + box-shadow: 0 0 0 3px #ff401f4d !important; + } + border-color: $tooltip-color-error !important; + animation: ql-table-input-shake 0.3s ease both; + } + & > label { + color: $tooltip-color-error; + } + } +} +.ql-table-dropdown, +.ql-table-dropdown-properties { + display: flex; + height: 100%; + align-items: center; + position: relative; + padding: 0 4px; + &:hover { + background: $hover-background; + } + &-text { + flex: 1; + height: 100%; + margin-right: 7px; + display: flex; + align-items: center; + } + &-list { + position: absolute; + left: 0; + bottom: 0; + transform: translateY(100%); + margin: 0; + padding: 0; + width: 170px; + z-index: 10; + @extend .ql-table-border-shadow; + li { + list-style: none; + line-height: 30px; + padding-left: 10px; + &:hover { + background-color: $hover-background; + } + } + } + &-label { + width: 100%; + min-width: 100%; + line-height: 24px; + font-weight: bold; + margin-bottom: 6px; + display: block; + } +} +.ql-table-tooltip-hover { + display: flex; + position: relative; + &:hover .ql-table-tooltip { + display: block; + } + &:hover + .ql-table-tooltip { + display: block; + } +} +.ql-table-tooltip { + @include qlTableTooltip($tooltip-color-simple); + &-error { + @include qlTableTooltip($tooltip-color-error); + white-space: pre-wrap; + z-index: 9; + } +} +.ql-table-dropdown-properties { + width: 80px; + height: 30px; + border: $border; + box-sizing: border-box; + &:hover { + background: none; + } +} +.ql-table-properties-form { + width: 320px; + position: absolute; + left: 50%; + padding-bottom: 8px; + background: $color-white; + z-index: 1; + @include boxShadow($color-ccced1); + .properties-form-header { + height: 40px; + line-height: 40px; + padding: 0 12px; + border-bottom: $border; + margin: 0; + box-sizing: border-box; + color: #333; + font-size: 14px; + } + .properties-form-row { + display: flex; + flex-wrap: wrap; + padding: 8px 12px; + justify-content: space-between; + .ql-table-check-container { + display: flex; + border: $border; + align-items: center; + & .ql-table-tooltip-hover { + padding: 6px 10px; + cursor: pointer; + &:hover { + background: $hover-background; + } + } + .ql-table-btns-checked { + background: #f0f7ff; + & > svg path { + stroke: #2977ff; + } + } + } + } + .properties-form-row-full { + .ql-table-color-container { + width: 100%; + .property-input { + width: 100%; + } + } + } + .property-input { + @extend .ql-table-input; + } + .properties-form-action-row { + display: flex; + justify-content: space-around; + padding: 0 12px; + & > button { + background: $color-white; + outline: none; + border: none; + height: 30px; + cursor: pointer; + @extend .ql-table-center; + flex: 1; + & > span { + margin: 0 2px; + display: flex; + } + &:hover { + background: $hover-background; + } + &[disabled] { + background-color: transparent; + } + } + } + .ql-table-color-selected { + @extend .ql-table-selected; + background-position: center; + } + .ql-table-dropdown-selected { + @extend .ql-table-selected; + background-position: calc(100% - 10px) center; + } +} +.ql-table-color-container { + border: $border; + height: 30px; + box-sizing: border-box; + display: flex; + .label-field-view-color { + flex: 1; + .property-input { + @extend .ql-table-input; + border: 1px solid transparent; + height: 100%; + } + } + .color-picker { + width: 30px; + border-left: $border; + box-sizing: border-box; + position: relative; + @extend .ql-table-center; + .color-button { + width: 20px; + height: 20px; + border: $border; + box-sizing: border-box; + cursor: pointer; + position: relative; + } + .color-unselected { + position: relative; + &::after { + content: ""; + position: absolute; + width: 1px; + height: 26px; + background: red; + transform-origin: 50%; + transform: rotate(45deg); + left: 50%; + top: -4px; + } + } + .color-picker-select { + position: absolute; + right: 0; + bottom: 0; + width: 156px; + transform: translateY(100%); + background: $color-white; + z-index: 10; + @include boxShadow($color-ccced1); + .erase-container { + display: flex; + height: 30px; + align-items: center; + padding: 0 12px; + &:hover { + background: #f0f0f0; + } + cursor: pointer; + & > button { + border: none; + outline: none; + background: inherit; + height: 100%; + cursor: pointer; + } + } + & > .erase-container { + @extend .ql-table-input-focus; + margin-bottom: 4px; + } + .color-list { + display: flex; + flex-wrap: wrap; + padding: 0 12px; + margin: 0; + justify-content: space-between; + & > li { + list-style: none; + width: 24px; + height: 24px; + margin: 2px 0; + position: relative; + cursor: pointer; + &[data-color="#ffffff"] { + border: $border; + box-sizing: border-box; + } + } + } + } + .color-picker-palette { + width: 100%; + height: 100%; + position: absolute; + left: 0; + top: 0; + z-index: 1; + background: $color-white; + .color-picker-wrap { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + .iro-container { + flex: 1; + @extend .ql-table-center; + } + } + } + } +} +.ql-table-disabled { + background: #f2f2f2; + pointer-events: none; +} +.ql-table-button-disabled { + background: #f2f2f2 !important; + pointer-events: none; + svg { + .ql-fill { + fill: #999 !important; + } + .ql-stroke { + stroke: #999 !important; + } + } +} +button.ql-table-better { + position: relative; +} +.ql-table-select-container { + flex-direction: column; + width: 190px; + padding: 2px; + position: absolute; + top: 24px; + z-index: 10; + box-sizing: border-box; + @extend .ql-table-center; + @extend .ql-table-border-shadow; + .ql-table-select-list { + flex-wrap: wrap; + @extend .ql-table-center; + } + .ql-table-select-label { + width: 100%; + line-height: 16px; + text-align: center; + color: #222f3eb3; + margin-top: 2px; + } + span { + width: 16px; + height: 16px; + border: 1px solid black; + box-sizing: border-box; + margin: 1px; + } +} +ol.table-list-container { + counter-reset: list-0; // reset counter +} + +// animation +@keyframes ql-table-input-shake { + 20% { + transform: translateX(-2px); + } + 40% { + transform: translateX(2px); + } + 60% { + transform: translateX(-1px); + } + 80% { + transform: translateX(1px); + } +} diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-bottom.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-bottom.svg new file mode 100644 index 0000000000..7e737480b5 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-bottom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-center.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-center.svg new file mode 100644 index 0000000000..6a426961d7 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-center.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-justify.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-justify.svg new file mode 100644 index 0000000000..8637538344 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-justify.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-left.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-left.svg new file mode 100644 index 0000000000..c8ea2cc80a --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-middle.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-middle.svg new file mode 100644 index 0000000000..9391870571 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-middle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-right.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-right.svg new file mode 100644 index 0000000000..afe490c057 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-top.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-top.svg new file mode 100644 index 0000000000..4fa387f23c --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/align-top.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/cell.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/cell.svg new file mode 100644 index 0000000000..d864ce5874 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/cell.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/check.png b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/check.png new file mode 100644 index 0000000000000000000000000000000000000000..812b34da0f29366f34ef24486484125c53173e23 GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!aez;VE08t<10^LT2m?YI8XCg6 z1_lPk#>PMq2xCUxR2`r;!IB`qV1~aHtRG79veTd4+GM`o(p2~F9PTKfq>ZPGV~E7% zh{q1!^Q$*=N|?Km_-tko-k|@P>M;gWBO2B c6!1uvq1u6wU3baODxf(Gp00i_>zopr0N0^Bp#T5? literal 0 HcmV?d00001 diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/check.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/check.svg new file mode 100644 index 0000000000..933eaf5b2c --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/close.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/close.svg new file mode 100644 index 0000000000..9fea1a1b7d --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/column.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/column.svg new file mode 100644 index 0000000000..4e3967d5b7 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/column.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/copy.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/copy.svg new file mode 100644 index 0000000000..980f7c165a --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/copy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/delete.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/delete.svg new file mode 100644 index 0000000000..8f4f092b5d --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/delete.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/down.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/down.svg new file mode 100644 index 0000000000..6f40a8852d --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/erase.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/erase.svg new file mode 100644 index 0000000000..bebdfb4942 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/erase.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/merge.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/merge.svg new file mode 100644 index 0000000000..b943191d11 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/merge.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/palette.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/palette.svg new file mode 100644 index 0000000000..5f96a02278 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/palette.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/row.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/row.svg new file mode 100644 index 0000000000..004946f0e2 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/row.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/save.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/save.svg new file mode 100644 index 0000000000..ee5b978491 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/table.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/table.svg new file mode 100644 index 0000000000..aa29e69b16 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/wrap.svg b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/wrap.svg new file mode 100644 index 0000000000..3c01d22b2b --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/icon/wrap.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/config/index.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/config/index.ts new file mode 100644 index 0000000000..c277223e95 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/config/index.ts @@ -0,0 +1,438 @@ +import alignBottomIcon from "../assets/icon/align-bottom.svg"; +import alignCenterIcon from "../assets/icon/align-center.svg"; +import alignLeftIcon from "../assets/icon/align-left.svg"; +import alignMiddleIcon from "../assets/icon/align-middle.svg"; +import alignJustifyIcon from "../assets/icon/align-justify.svg"; +import alignRightIcon from "../assets/icon/align-right.svg"; +import alignTopIcon from "../assets/icon/align-top.svg"; +import { convertUnitToInteger, isValidColor, isValidDimensions } from "../utils"; + +interface Options { + type: string; + attribute: Props; +} + +const CELL_ATTRIBUTE = ["data-row", "width", "height", "colspan", "rowspan", "style"]; + +const CELL_DEFAULT_VALUES: Props = { + "border-style": "none", + "border-color": "", + "border-width": "", + "background-color": "", + width: "", + height: "", + padding: "", + "text-align": "left", + "vertical-align": "middle" +}; + +const CELL_DEFAULT_WIDTH = 72; + +const CELL_PROPERTIES = [ + "border-style", + "border-color", + "border-width", + "background-color", + "width", + "height", + "padding", + "text-align", + "vertical-align" +]; + +const COLORS = [ + "aliceblue", + "antiquewhite", + "aqua", + "aquamarine", + "azure", + "beige", + "bisque", + "black", + "blanchedalmond", + "blue", + "blueviolet", + "brown", + "burlywood", + "cadetblue", + "chartreuse", + "chocolate", + "coral", + "cornflowerblue", + "cornsilk", + "crimson", + "currentcolor", + "currentcolor", + "cyan", + "darkblue", + "darkcyan", + "darkgoldenrod", + "darkgray", + "darkgreen", + "darkgrey", + "darkkhaki", + "darkmagenta", + "darkolivegreen", + "darkorange", + "darkorchid", + "darkred", + "darksalmon", + "darkseagreen", + "darkslateblue", + "darkslategray", + "darkslategrey", + "darkturquoise", + "darkviolet", + "deeppink", + "deepskyblue", + "dimgray", + "dimgrey", + "dodgerblue", + "firebrick", + "floralwhite", + "forestgreen", + "fuchsia", + "gainsboro", + "ghostwhite", + "gold", + "goldenrod", + "gray", + "green", + "greenyellow", + "grey", + "honeydew", + "hotpink", + "indianred", + "indigo", + "ivory", + "khaki", + "lavender", + "lavenderblush", + "lawngreen", + "lemonchiffon", + "lightblue", + "lightcoral", + "lightcyan", + "lightgoldenrodyellow", + "lightgray", + "lightgreen", + "lightgrey", + "lightpink", + "lightsalmon", + "lightseagreen", + "lightskyblue", + "lightslategray", + "lightslategrey", + "lightsteelblue", + "lightyellow", + "lime", + "limegreen", + "linen", + "magenta", + "maroon", + "mediumaquamarine", + "mediumblue", + "mediumorchid", + "mediumpurple", + "mediumseagreen", + "mediumslateblue", + "mediumspringgreen", + "mediumturquoise", + "mediumvioletred", + "midnightblue", + "mintcream", + "mistyrose", + "moccasin", + "navajowhite", + "navy", + "oldlace", + "olive", + "olivedrab", + "orange", + "orangered", + "orchid", + "palegoldenrod", + "palegreen", + "paleturquoise", + "palevioletred", + "papayawhip", + "peachpuff", + "peru", + "pink", + "plum", + "powderblue", + "purple", + "rebeccapurple", + "red", + "rosybrown", + "royalblue", + "saddlebrown", + "salmon", + "sandybrown", + "seagreen", + "seashell", + "sienna", + "silver", + "skyblue", + "slateblue", + "slategray", + "slategrey", + "snow", + "springgreen", + "steelblue", + "tan", + "teal", + "thistle", + "tomato", + "transparent", + "turquoise", + "violet", + "wheat", + "white", + "whitesmoke", + "yellow", + "yellowgreen" +]; + +const DEVIATION = 2; + +const TABLE_PROPERTIES = [ + "border-style", + "border-color", + "border-width", + "background-color", + "width", + "height", + "align" +]; + +function getCellProperties(attribute: Props, useLanguage: _useLanguage) { + return { + title: useLanguage("cellProps"), + properties: [ + { + content: useLanguage("border"), + children: [ + { + category: "dropdown", + propertyName: "border-style", + value: attribute["border-style"], + options: ["dashed", "dotted", "double", "groove", "inset", "none", "outset", "ridge", "solid"] + }, + { + category: "color", + propertyName: "border-color", + value: attribute["border-color"], + attribute: { + type: "text", + placeholder: useLanguage("color") + }, + valid: isValidColor, + message: useLanguage("colorMsg") + }, + { + category: "input", + propertyName: "border-width", + value: convertUnitToInteger(attribute["border-width"]), + attribute: { + type: "text", + placeholder: useLanguage("width") + }, + valid: isValidDimensions, + message: useLanguage("dimsMsg") + } + ] + }, + { + content: useLanguage("background"), + children: [ + { + category: "color", + propertyName: "background-color", + value: attribute["background-color"], + attribute: { + type: "text", + placeholder: useLanguage("color") + }, + valid: isValidColor, + message: useLanguage("colorMsg") + } + ] + }, + { + content: useLanguage("dims"), + children: [ + { + category: "input", + propertyName: "width", + value: convertUnitToInteger(attribute["width"]), + attribute: { + type: "text", + placeholder: useLanguage("width") + }, + valid: isValidDimensions, + message: useLanguage("dimsMsg") + }, + { + category: "input", + propertyName: "height", + value: convertUnitToInteger(attribute["height"]), + attribute: { + type: "text", + placeholder: useLanguage("height") + }, + valid: isValidDimensions, + message: useLanguage("dimsMsg") + }, + { + category: "input", + propertyName: "padding", + value: convertUnitToInteger(attribute["padding"]), + attribute: { + type: "text", + placeholder: useLanguage("padding") + }, + valid: isValidDimensions, + message: useLanguage("dimsMsg") + } + ] + }, + { + content: useLanguage("tblCellTxtAlm"), + children: [ + { + category: "menus", + propertyName: "text-align", + value: attribute["text-align"], + menus: [ + { icon: alignLeftIcon, describe: useLanguage("alCellTxtL"), align: "left" }, + { icon: alignCenterIcon, describe: useLanguage("alCellTxtC"), align: "center" }, + { icon: alignRightIcon, describe: useLanguage("alCellTxtR"), align: "right" }, + { icon: alignJustifyIcon, describe: useLanguage("jusfCellTxt"), align: "justify" } + ] + }, + { + category: "menus", + propertyName: "vertical-align", + value: attribute["vertical-align"], + menus: [ + { icon: alignTopIcon, describe: useLanguage("alCellTxtT"), align: "top" }, + { icon: alignMiddleIcon, describe: useLanguage("alCellTxtM"), align: "middle" }, + { icon: alignBottomIcon, describe: useLanguage("alCellTxtB"), align: "bottom" } + ] + } + ] + } + ] + }; +} + +function getTableProperties(attribute: Props, useLanguage: _useLanguage) { + return { + title: useLanguage("tblProps"), + properties: [ + { + content: useLanguage("border"), + children: [ + { + category: "dropdown", + propertyName: "border-style", + value: attribute["border-style"], + options: ["dashed", "dotted", "double", "groove", "inset", "none", "outset", "ridge", "solid"] + }, + { + category: "color", + propertyName: "border-color", + value: attribute["border-color"], + attribute: { + type: "text", + placeholder: useLanguage("color") + }, + valid: isValidColor, + message: useLanguage("colorMsg") + }, + { + category: "input", + propertyName: "border-width", + value: convertUnitToInteger(attribute["border-width"]), + attribute: { + type: "text", + placeholder: useLanguage("width") + }, + valid: isValidDimensions, + message: useLanguage("dimsMsg") + } + ] + }, + { + content: useLanguage("background"), + children: [ + { + category: "color", + propertyName: "background-color", + value: attribute["background-color"], + attribute: { + type: "text", + placeholder: useLanguage("color") + }, + valid: isValidColor, + message: useLanguage("colorMsg") + } + ] + }, + { + content: useLanguage("dimsAlm"), + children: [ + { + category: "input", + propertyName: "width", + value: convertUnitToInteger(attribute["width"]), + attribute: { + type: "text", + placeholder: useLanguage("width") + }, + valid: isValidDimensions, + message: useLanguage("dimsMsg") + }, + { + category: "input", + propertyName: "height", + value: convertUnitToInteger(attribute["height"]), + attribute: { + type: "text", + placeholder: useLanguage("height") + }, + valid: isValidDimensions, + message: useLanguage("dimsMsg") + }, + { + category: "menus", + propertyName: "align", + value: attribute["align"], + menus: [ + { icon: alignLeftIcon, describe: useLanguage("alTblL"), align: "left" }, + { icon: alignCenterIcon, describe: useLanguage("tblC"), align: "center" }, + { icon: alignRightIcon, describe: useLanguage("alTblR"), align: "right" } + ] + } + ] + } + ] + }; +} + +function getProperties({ type, attribute }: Options, useLanguage: _useLanguage) { + if (type === "table") return getTableProperties(attribute, useLanguage); + return getCellProperties(attribute, useLanguage); +} + +export { + CELL_ATTRIBUTE, + CELL_DEFAULT_VALUES, + CELL_DEFAULT_WIDTH, + CELL_PROPERTIES, + COLORS, + DEVIATION, + TABLE_PROPERTIES, + getProperties +}; diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/header.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/header.ts new file mode 100644 index 0000000000..6089d2c46b --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/header.ts @@ -0,0 +1,74 @@ +import Quill from "quill"; +import { type Props, type Range } from "../types"; +import { TableCellBlock, TableCell } from "./table"; +import { ListContainer } from "./list"; +import { getCellFormats, getCorrectCellBlot } from "../utils"; +import Header from "quill/formats/header"; + +class TableHeader extends Header { + static blotName = "table-header"; + static className = "ql-table-header"; + + static create(formats: Props) { + const { cellId, value } = formats; + const node = super.create(value); + node.setAttribute("data-cell", cellId); + return node; + } + + format(name: string, value: string, isReplace?: boolean) { + if (name === "header") { + const _value = this.statics.formats(this.domNode).value; + const cellId = this.domNode.getAttribute("data-cell"); + if (_value == value || !value) { + this.replaceWith(TableCellBlock.blotName, cellId); + } else { + super.format("table-header", { cellId, value }); + } + } else if (name === "list") { + const [formats, cellId] = this.getCellFormats(this.parent); + if (isReplace) { + this.wrap(ListContainer.blotName, { ...formats, cellId }); + } else { + this.wrap(TableCell.blotName, formats); + } + return this.replaceWith("table-list", value); + } else if (name === TableCell.blotName) { + return this.wrap(name, value); + } else if (name === this.statics.blotName && !value) { + const cellId = this.domNode.getAttribute("data-cell"); + this.replaceWith(TableCellBlock.blotName, cellId); + } else { + super.format(name, value); + } + } + + static formats(domNode: HTMLElement) { + const cellId = domNode.getAttribute("data-cell"); + const value = this.tagName.indexOf(domNode.tagName) + 1; + return { cellId, value }; + } + + formats() { + const formats = this.attributes.values(); + const format = this.statics.formats(this.domNode, this.scroll); + if (format != null) { + formats[this.statics.blotName] = format; + } + return formats; + } + + getCellFormats(parent: TableCell) { + const cellBlot = getCorrectCellBlot(parent); + return getCellFormats(cellBlot); + } +} + +Quill.register( + { + "formats/table-header": TableHeader + }, + true +); + +export default TableHeader; diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/list.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/list.ts new file mode 100644 index 0000000000..ae4390593b --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/list.ts @@ -0,0 +1,150 @@ +import Quill from "quill"; +import { type Props, type Range } from "../types"; +import { TableCell, TableCellBlock } from "./table"; +import { getCellFormats, getCorrectCellBlot } from "../utils"; +import { CELL_ATTRIBUTE } from "../config"; +import Container from "quill/blots/container"; +import List from "quill/formats/list"; +const DEFAULT_ATTRIBUTE = ["colspan", "rowspan"]; + +class ListContainer extends Container { + static create(value: Props) { + const node = super.create(); + for (const key of DEFAULT_ATTRIBUTE) { + if (value[key] == "1") delete value[key]; + } + const keys = Object.keys(value); + for (const key of keys) { + if (key === "data-row") { + node.setAttribute(key, value[key]); + } else if (key === "cellId") { + node.setAttribute("data-cell", value[key]); + } else { + node.setAttribute(`data-${key}`, value[key]); + } + } + return node; + } + + format(name: string, value: string | Props) { + return this.wrap(name, value); + } + + static formats(domNode: HTMLElement) { + const formats = CELL_ATTRIBUTE.reduce((formats: Props, attr) => { + const name = attr.includes("data") ? attr : `data-${attr}`; + if (domNode.hasAttribute(name)) { + formats[attr] = domNode.getAttribute(name); + } + return formats; + }, {}); + formats["cellId"] = domNode.getAttribute("data-cell"); + for (const key of DEFAULT_ATTRIBUTE) { + if (!formats[key]) formats[key] = "1"; + } + return formats; + } + + formats() { + const formats = this.statics.formats(this.domNode, this.scroll); + return { [this.statics.blotName]: formats }; + } +} +ListContainer.blotName = "table-list-container"; +ListContainer.className = "table-list-container"; +ListContainer.tagName = "OL"; + +class TableList extends List { + format(name: string, value: string | Props, isReplace?: boolean) { + const list = this.formats()[this.statics.blotName]; + if (name === "list") { + const [formats, cellId] = this.getCellFormats(this.parent); + if (!value || value === list) { + this.setReplace(isReplace, formats); + return this.replaceWith(TableCellBlock.blotName, cellId); + } else if (value !== list) { + return this.replaceWith(this.statics.blotName, value); + } + } else if (name === ListContainer.blotName) { + if (typeof value === "string") { + value = { cellId: value }; + } + const [formats, cellId] = this.getCorrectCellFormats(value); + this.wrap(TableCell.blotName, formats); + this.wrap(name, { ...formats, cellId }); + } else if (name === "header") { + const [formats, cellId] = this.getCellFormats(this.parent); + this.setReplace(isReplace, formats); + return this.replaceWith("table-header", { cellId, value }); + } else if (name === TableCell.blotName) { + const listContainer = this.getListContainer(this.parent); + if (!listContainer) return; + const formats = listContainer.formats()[listContainer.statics.blotName]; + this.wrap(name, value); + // @ts-ignore + this.wrap(ListContainer.blotName, { ...formats, ...value }); + } else if (name === this.statics.blotName && !value) { + const [, cellId] = this.getCellFormats(this.parent); + this.replaceWith(TableCellBlock.blotName, cellId); + } else { + super.format(name, value); + } + } + + getCellFormats(parent: TableCell) { + const cellBlot = getCorrectCellBlot(parent); + return getCellFormats(cellBlot); + } + + getCorrectCellFormats(value: Props): [Props, string] { + const cellBlot = getCorrectCellBlot(this.parent); + if (!cellBlot) { + const cellId = value["cellId"]; + const formats = { ...value }; + delete formats["cellId"]; + return [formats, cellId]; + } else { + const [formats, cellId] = getCellFormats(cellBlot); + const _formats = { ...formats, ...value }; + const _cellId = _formats["cellId"] || cellId; + delete _formats["cellId"]; + return [_formats, _cellId]; + } + } + + private getListContainer(blot: ListContainer) { + while (blot) { + if (blot.statics.blotName === ListContainer.blotName) { + return blot; + } + blot = blot.parent; + } + return null; + } + + static register() { + Quill.register(ListContainer); + } + + setReplace(isReplace: boolean, formats: Props) { + if (isReplace) { + this.parent.replaceWith(TableCell.blotName, formats); + } else { + this.wrap(TableCell.blotName, formats); + } + } +} +TableList.blotName = "table-list"; +TableList.className = "table-list"; + +Quill.register( + { + "formats/table-list": TableList + }, + true +); + +ListContainer.allowedChildren = [TableList]; +TableList.requiredContainer = ListContainer; + +export { ListContainer, TableList as default }; diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts new file mode 100644 index 0000000000..540fb57a5b --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts @@ -0,0 +1,744 @@ +import Quill from "quill"; +import Block from "quill/blots/block"; +import Break from "quill/blots/break"; +import Container from "quill/blots/container"; +import { type Props, type Range } from "../types"; +import { filterWordStyle, getCellChildBlot, getCellFormats, getCellId, getCopyTd, getCorrectCellBlot } from "../utils"; +import TableHeader from "./header"; +import { ListContainer } from "./list"; +import { CELL_ATTRIBUTE, CELL_DEFAULT_WIDTH, DEVIATION } from "../config"; + +// const Block = Quill.import('blots/block'); +// const Break = Quill.import('blots/break'); +// const Container = Quill.import('blots/container'); + +const TABLE_ATTRIBUTE = ["border", "cellspacing", "style", "data-class"]; +const STYLE_RULES = ["color", "border", "width", "height"]; +const COL_ATTRIBUTE = ["width"]; + +class TableCellBlock extends Block { + static create(value: string) { + const node = super.create(); + if (value) { + node.setAttribute("data-cell", value); + } else { + node.setAttribute("data-cell", cellId()); + } + return node; + } + + format(name: string, value: string | Props) { + const cellId = this.formats()[this.statics.blotName]; + if (name === TableCell.blotName && value) { + this.wrap(TableRow.blotName); + return this.wrap(name, value); + } else if (name === TableContainer.blotName) { + this.wrap(name, value); + } else if (name === "header") { + return this.replaceWith("table-header", { cellId, value }); + } else if (name === "table-header" && value) { + this.wrapTableCell(this.parent); + return this.replaceWith(name, value); + } else if (name === "list" || (name === "table-list" && value)) { + const formats = this.getCellFormats(this.parent); + this.wrap(ListContainer.blotName, { ...formats, cellId }); + return this.replaceWith("table-list", value); + } else { + super.format(name, value); + } + } + + formats() { + const formats = this.attributes.values(); + const format = this.domNode.getAttribute("data-cell"); + if (format != null) { + formats[this.statics.blotName] = format; + } + return formats; + } + + getCellFormats(parent: TableCell) { + const cellBlot = getCorrectCellBlot(parent); + if (!cellBlot) return {}; + const [formats] = getCellFormats(cellBlot); + return formats; + } + + wrapTableCell(parent: TableCell) { + const cellBlot = getCorrectCellBlot(parent); + if (!cellBlot) return; + const [formats] = getCellFormats(cellBlot); + this.wrap(TableCell.blotName, formats); + } +} +TableCellBlock.blotName = "table-cell-block"; +TableCellBlock.className = "ql-table-block"; +TableCellBlock.tagName = "P"; + +class TableCell extends Container { + checkMerge() { + if (super.checkMerge() && this.next.children.head != null && this.next.children.head.formats) { + const thisHead = this.children.head.formats()[this.children.head.statics.blotName]; + const thisTail = this.children.tail.formats()[this.children.tail.statics.blotName]; + const nextHead = this.next.children.head.formats()[this.next.children.head.statics.blotName]; + const nextTail = this.next.children.tail.formats()[this.next.children.tail.statics.blotName]; + const _thisHead = getCellId(thisHead); + const _thisTail = getCellId(thisTail); + const _nextHead = getCellId(nextHead); + const _nextTail = getCellId(nextTail); + return _thisHead === _thisTail && _thisHead === _nextHead && _thisHead === _nextTail; + } + return false; + } + + static create(value: Props) { + const node = super.create(); + const keys = Object.keys(value); + for (const key of keys) { + value[key] && node.setAttribute(key, value[key]); + } + return node; + } + + static formats(domNode: Element) { + const rowspan = this.getEmptyRowspan(domNode); + const formats = CELL_ATTRIBUTE.reduce((formats: Props, attr) => { + if (domNode.hasAttribute(attr)) { + if (attr === "rowspan" && rowspan) { + formats[attr] = `${~~domNode.getAttribute(attr) - rowspan}`; + } else { + formats[attr] = filterWordStyle(domNode.getAttribute(attr)); + } + } + return formats; + }, {}); + if (this.hasColgroup(domNode)) { + delete formats["width"]; + if (formats["style"]) { + formats["style"] = formats["style"].replace(/width.*?;/g, ""); + } + } + return formats; + } + + formats() { + const formats = this.statics.formats(this.domNode, this.scroll); + return { [this.statics.blotName]: formats }; + } + + static getEmptyRowspan(domNode: Element) { + let nextNode = domNode.parentElement.nextElementSibling; + let rowspan = 0; + while (nextNode && nextNode.tagName === "TR" && !nextNode.innerHTML.replace(/\s/g, "")) { + rowspan++; + nextNode = nextNode.nextElementSibling; + } + return rowspan; + } + + static hasColgroup(domNode: Element) { + while (domNode && domNode.tagName !== "TBODY") { + domNode = domNode.parentElement; + } + while (domNode) { + if (domNode.tagName === "COLGROUP") { + return true; + } + domNode = domNode.previousElementSibling; + } + return false; + } + + html() { + const reg = /<(ol)[^>]*>]* data-list="bullet">(?:.*?)<\/li><\/(ol)>/gi; + return this.domNode.outerHTML.replace(reg, (match: string, $1: string, $2: string) => { + return match.replace($1, "ul").replace($2, "ul"); + }); + } + + row() { + return this.parent; + } + + rowOffset() { + if (this.row()) { + return this.row().rowOffset(); + } + return -1; + } + + setChildrenId(cellId: string) { + this.children.forEach((child: TableCellBlock | ListContainer | TableHeader) => { + child.domNode.setAttribute("data-cell", cellId); + }); + } + + table() { + let cur = this.parent; + while (cur != null && cur.statics.blotName !== "table-container") { + cur = cur.parent; + } + return cur; + } + + optimize(...args: unknown[]) { + super.optimize(...args); + this.children.forEach((child: TableCellBlock | TableHeader | ListContainer) => { + if (child.next == null) return; + const childFormats = getCellId(child.formats()[child.statics.blotName]); + const nextFormats = getCellId(child.next.formats()[child.next.statics.blotName]); + if (childFormats !== nextFormats) { + const next = this.splitAfter(child); + if (next) next.optimize(); + // We might be able to merge with prev now + if (this.prev) this.prev.optimize(); + } + }); + } +} +TableCell.blotName = "table-cell"; +TableCell.tagName = "TD"; + +class TableRow extends Container { + checkMerge() { + if (super.checkMerge() && this.next.children.head != null && this.next.children.head.formats) { + const thisHead = this.children.head.formats()[this.children.head.statics.blotName]; + const thisTail = this.children.tail.formats()[this.children.tail.statics.blotName]; + const nextHead = this.next.children.head.formats()[this.next.children.head.statics.blotName]; + const nextTail = this.next.children.tail.formats()[this.next.children.tail.statics.blotName]; + return ( + thisHead["data-row"] === thisTail["data-row"] && + thisHead["data-row"] === nextHead["data-row"] && + thisHead["data-row"] === nextTail["data-row"] + ); + } + return false; + } + + rowOffset() { + if (this.parent) { + return this.parent.children.indexOf(this); + } + return -1; + } +} +TableRow.blotName = "table-row"; +TableRow.tagName = "TR"; + +class TableBody extends Container {} +TableBody.blotName = "table-body"; +TableBody.tagName = "TBODY"; + +class TableTemporary extends Block { + static create(value: Props) { + const node = super.create(); + const keys = Object.keys(value); + for (const key of keys) { + node.setAttribute(key, value[key]); + } + return node; + } + + static formats(domNode: Element) { + return TABLE_ATTRIBUTE.reduce((formats: Props, attr) => { + if (domNode.hasAttribute(attr)) { + formats[attr] = domNode.getAttribute(attr); + } + return formats; + }, {}); + } + + formats() { + const formats = this.statics.formats(this.domNode, this.scroll); + return { [this.statics.blotName]: formats }; + } + + optimize(...args: unknown[]) { + if (this.statics.requiredContainer && this.parent instanceof this.statics.requiredContainer) { + const formats = this.formats()[this.statics.blotName]; + for (const key of TABLE_ATTRIBUTE) { + if (formats[key]) { + if (key === "data-class") { + this.parent.domNode.setAttribute("class", formats[key]); + } else { + this.parent.domNode.setAttribute(key, formats[key]); + } + } else { + this.parent.domNode.removeAttribute(key); + } + } + } + super.optimize(...args); + } +} +TableTemporary.blotName = "table-temporary"; +TableTemporary.className = "ql-table-temporary"; +TableTemporary.tagName = "temporary"; + +class TableCol extends Block { + static create(value: Props) { + const node = super.create(); + const keys = Object.keys(value); + for (const key of keys) { + node.setAttribute(key, value[key]); + } + return node; + } + + static formats(domNode: Element) { + return COL_ATTRIBUTE.reduce((formats: Props, attr) => { + if (domNode.hasAttribute(attr)) { + formats[attr] = domNode.getAttribute(attr); + } + return formats; + }, {}); + } + + formats() { + const formats = this.statics.formats(this.domNode, this.scroll); + return { [this.statics.blotName]: formats }; + } + + html() { + return this.domNode.outerHTML; + } +} +TableCol.blotName = "table-col"; +TableCol.tagName = "COL"; + +class TableColgroup extends Container {} +TableColgroup.blotName = "table-colgroup"; +TableColgroup.tagName = "COLGROUP"; + +class TableContainer extends Container { + colgroup() { + const [colgroup] = this.descendant(TableColgroup); + return colgroup || this.findChild("table-colgroup"); + } + + deleteColumn(changeTds: [Element, number][], delTds: Element[], deleteTable: () => void, cols: Element[] = []) { + const body = this.tbody(); + const tableCells = this.descendants(TableCell); + if (body == null || body.children.head == null) return; + if (delTds.length === tableCells.length) { + deleteTable(); + } else { + for (const [td, offset] of changeTds) { + this.setCellColspan(Quill.find(td), offset); + } + for (const td of [...delTds, ...cols]) { + if (td.parentElement.children.length === 1) { + this.setCellRowspan(td.parentElement.previousElementSibling); + } + td.remove(); + } + } + } + + deleteRow(rows: TableRow[], deleteTable: () => void) { + const body = this.tbody(); + if (body == null || body.children.head == null) return; + if (rows.length === body.children.length) { + deleteTable(); + } else { + const weakMap: WeakMap = new WeakMap(); + const columnCells: [TableRow, Props, TableCell | null, TableCell | null][] = []; + const keys: TableCell[] = []; + const maxColumns = this.getMaxColumns(body.children.head.children); + for (const row of rows) { + const prev = this.getCorrectRow(row, maxColumns); + prev && + prev.children.forEach((child: TableCell) => { + const rowspan = ~~child.domNode.getAttribute("rowspan") || 1; + if (rowspan > 1) { + const blotName = child.statics.blotName; + const [formats] = getCellFormats(child); + if (rows.includes(child.parent)) { + const next = child.parent?.next; + if (weakMap.has(child)) { + const { rowspan } = weakMap.get(child); + weakMap.set(child, { next, rowspan: rowspan - 1 }); + } else { + weakMap.set(child, { next, rowspan: rowspan - 1 }); + keys.push(child); + } + } else { + child.replaceWith(blotName, { ...formats, rowspan: rowspan - 1 }); + } + } + }); + } + for (const prev of keys) { + const [formats] = getCellFormats(prev); + const { right: position, width } = prev.domNode.getBoundingClientRect(); + const { next, rowspan } = weakMap.get(prev); + this.setColumnCells(next, columnCells, { position, width }, formats, rowspan, prev); + } + for (const [row, formats, ref, prev] of columnCells) { + const cell: TableCell = this.scroll.create(TableCell.blotName, formats); + prev.moveChildren(cell); + const _cellId = cellId(); + cell.setChildrenId(_cellId); + row.insertBefore(cell, ref); + prev.remove(); + } + for (const row of rows) { + row.remove(); + } + } + } + + deleteTable() { + this.remove(); + } + + findChild(blotName: string) { + let child = this.children.head; + while (child) { + if (child.statics.blotName === blotName) { + return child; + } + child = child.next; + } + return null; + } + + getCopyTable() { + return this.domNode.outerHTML + .replace(/]*>(.*?)<\/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); + 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: TableCell[]) { + 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(); + const body = this.tbody(); + 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); + const cellBlock = this.scroll.create(TableCellBlock.blotName, cellId()); + cell.appendChild(cellBlock); + if (!row) { + const tbody = this.tbody(); + row = this.scroll.create(TableRow.blotName); + tbody.insertBefore(row, null); + } + row.insertBefore(cell, ref); + cellBlock.optimize(); + return cell; + } + + insertRow(index: number, offset: number) { + const body = this.tbody(); + 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); + const cellBlock = this.scroll.create(TableCellBlock.blotName, cellId()); + cell.appendChild(cellBlock); + row.appendChild(cell); + cellBlock.optimize(); + } + + optimize(...args: unknown[]) { + super.optimize(...args); + 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); + 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, value: string) => { + temporary.domNode.setAttribute("data-class", value); + }; + if (!_temporary) { + const container = this.prev; + if (!container) return; + const [cell] = container.descendant(TableCell); + const [temporary] = container.descendant(TableTemporary); + if (!cell && temporary) { + const className = temporary.domNode.getAttribute("data-class"); + if (className !== _className && _className != null) { + setClass(temporary, getClassName(_className)); + } + if (!_className && !className) { + setClass(temporary, defaultClassName); + } + } + } else { + const className = _temporary.domNode.getAttribute("data-class"); + if (className !== _className && _className != null) { + setClass(_temporary, getClassName(_className)); + } + if (!_className && !className) { + setClass(_temporary, defaultClassName); + } + } + } + + 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() { + const [body] = this.descendant(TableBody); + return body || this.findChild("table-body"); + } + + temporary() { + const [temporary] = this.descendant(TableTemporary); + return temporary; + } +} +TableContainer.blotName = "table-container"; +// TableContainer.className = 'ql-table-better'; +TableContainer.defaultClassName = "ql-table-better"; +TableContainer.tagName = "TABLE"; + +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, + TableCellBlock, + TableCell, + TableRow, + TableBody, + TableTemporary, + TableContainer, + tableId, + TableCol, + TableColgroup +}; 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..4e052bf371 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/language/index.ts @@ -0,0 +1,61 @@ +import en_US from "./en_US"; +import zh_CN from "./zh_CN"; +import fr_FR from "./fr_FR"; +import pl_PL from "./pl_PL"; +import de_DE from "./de_DE"; +import ru_RU from "./ru_RU"; +import tr_TR from "./tr_TR"; + +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..fa3630caa0 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/modules/clipboard.ts @@ -0,0 +1,43 @@ +import Quill from "quill"; +import Delta from "quill-delta"; +import logger from "quill/core/logger.js"; +import { TableCellBlock, TableTemporary } from "../formats/table"; + +const Clipboard = Quill.import("modules/clipboard"); +const debug = logger("quill:clipboard"); + +class TableClipboard extends Clipboard { + onPaste(range: Range, { text, html }: { text?: string; html?: string }) { + const formats = this.quill.getFormat(range.index); + 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..28b2b995e5 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/modules/toolbar.ts @@ -0,0 +1,225 @@ +import Quill from "quill"; +import Delta from "quill-delta"; +import merge from "lodash.merge"; +import { EmbedBlot } from "parchment"; +import { getCorrectCellBlot } from "../utils"; +import { TableCell } from "../formats/table"; +import TableHeader from "../formats/header"; +import Container from "quill/blots/container"; +import Toolbar from "quill/modules/toolbar"; + +class TableToolbar extends Toolbar { + 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: any) { + 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") || {}; + } + + setTableFormat(range: Range, selectedTds: Element[], value: string, name: string, lines: any[]) { + 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); + } + 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 (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, 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: TableHeader, _isReplace: boolean) { + if (selectedTds.length === 1 && name === "list" && line.statics.blotName === TableHeader.blotName) { + return true; + } + return _isReplace; +} + +function getLength(blots: any[]): number { + return blots.reduce((sum, blot) => { + return (sum += blot.length()); + }, 0); +} + +function isReplace(range: Range, selectedTds: Element[], lines: any[]) { + if (selectedTds.length === 1) { + const cellBlot = Quill.find(selectedTds[0]); + 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?: any[]) { + 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?: any[]) { + 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?: any[]) { + 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..9e48d13c49 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/quill-table-better.ts @@ -0,0 +1,416 @@ +import Quill from "quill"; +import Delta from "quill-delta"; +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"; +import { type Props, type Range } from "./types"; +interface Context { + [propName: string]: any; +} + +interface Options { + language?: + | string + | { + name: string; + content: Props; + }; + menus?: string[]; + toolbarButtons?: { + whiteList?: string[]; + singleWhiteList?: string[]; + }; + toolbarTable?: boolean; +} + +type Line = TableCellBlock | TableHeader | ListContainer; + +const Module = Quill.import("core/module"); + +class Table extends Module { + language: Language; + cellSelection: CellSelection; + operateLine: OperateLine; + tableMenus: TableMenus; + tableSelect: TableSelect; + static keyboardBindings: { + "table-cell down": { key: string; collapsed: boolean; format: string[]; handler(): boolean }; + "table-cell up": { key: string; collapsed: boolean; format: string[]; handler(): boolean }; + "table-cell-block backspace": { + key: string; + format: string[]; + collapsed: boolean; + handler(range: Range, context: Context): any; + }; + "table-cell-block delete": { + key: string; + format: string[]; + collapsed: boolean; + handler(range: Range, context: Context): any; + }; + "table-header backspace": { + key: string; + format: string[]; + collapsed: boolean; + empty: boolean; + handler(range: Range, context: Context): any; + }; + "table-header delete": { + key: string; + format: string[]; + collapsed: boolean; + empty: boolean; + handler(range: Range, context: Context): any; + }; + "table-header enter": { + key: string; + collapsed: boolean; + format: string[]; + suffix: RegExp; + handler(range: Range, context: Context): void; + }; + "table-list backspace": { + key: string; + format: string[]; + collapsed: boolean; + empty: boolean; + handler(range: Range, context: Context): void; + }; + "table-list delete": { + key: string; + format: string[]; + collapsed: boolean; + empty: boolean; + handler(range: Range, context: Context): void; + }; + "table-list empty enter": { + key: string; + collapsed: boolean; + format: string[]; + empty: boolean; + handler(range: Range, context: Context): void; + }; + }; + + 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, true); + Quill.register("modules/clipboard", TableClipboard, true); + } + + constructor(quill: any, 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: string = 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()) { + 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; + const row = cell.parent; + const table = row.parent.parent; + 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"); + 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)); + }); + document.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); + } + }); + } + + private 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); + 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..361f6631b8 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/types.ts @@ -0,0 +1,17 @@ +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; +} 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..30202a03db --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/cell-selection.ts @@ -0,0 +1,704 @@ +import Quill from "quill"; +import Delta from "quill-delta"; +import type { Op } from "quill-delta"; +import { getComputeBounds, getComputeSelectedTds, getCopyTd, getCorrectBounds, getCorrectCellBlot } from "../utils"; +import { applyFormat } from "../utils/clipboard-matchers"; +import type { AllowedChildren } from "../utils"; +import { TableCellBlock, TableCell, TableRow, TableContainer } from "../formats/table"; +import { DEVIATION } from "../config"; + +const Block = Quill.import("blots/block"); +const { BlockEmbed } = Quill.import("blots/block"); +const Container = Quill.import("blots/container"); + +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"]; + +// @ts-ignore +function isLine(blot: unknown): blot is Block | BlockEmbed { + return blot instanceof Block || blot instanceof BlockEmbed; +} + +class CellSelection { + quill: any; + selectedTds: Element[]; + startTd: Element; + endTd: Element; + disabledList: Array; + singleList: Array; + tableBetter: any; + constructor(quill: any, tableBetter: any) { + 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: AllowedChildren, 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]).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 = `${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: TableCell = Quill.find(td); + let row = cell.parent; + while (row && rowspan) { + row = row[key]; + rowspan--; + } + return row?.domNode; + } + + getCorrectValue(format: string, value: boolean | string) { + for (const td of this.selectedTds) { + const blot = Quill.find(td); + 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: any = {}) { + 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): any { + 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() { + document.addEventListener("copy", (e: ClipboardEvent) => this.onCaptureCopy(e, false)); + document.addEventListener("cut", (e: ClipboardEvent) => this.onCaptureCopy(e, true)); + document.addEventListener("keyup", this.handleDeleteKeyup.bind(this)); + document.addEventListener("paste", this.onCapturePaste.bind(this)); + } + + initWhiteList() { + const toolbar = this.quill.getModule("toolbar"); + Array.from(toolbar.container.querySelectorAll("button, select")).forEach(input => { + // @ts-ignore + this.attach(input); + }); + } + + insertColumnCell(table: TableContainer, offset: number) { + const tbody = table.tbody(); + 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).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) => { + // @ts-ignore + let lines: (Block | BlockEmbed)[] = []; + blot.children.forEach((child: any) => { + if (child instanceof Container) { + 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); + 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) { + 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); + 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) { + this.exitTableFocus(block, up); + } else { + this.tableArrowSelection(up, cellBlot); + } + } else { + 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 = document.createElement("div"); + container.innerHTML = html; + const copyRows = Array.from(container.querySelectorAll("tr")); + if (!copyRows.length) return; + const cell = Quill.find(this.startTd); + 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: HTMLTableCellElement[][], row: HTMLTableRowElement) => { + copyTds.push(Array.from(row.querySelectorAll("td"))); + return copyTds; + }, []); + const selectedTds: HTMLTableCellElement[] = []; + 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); + 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); + const _cell = cell.replaceWith(cell.statics.blotName, copyFormats); + 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); + 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); + let head = tdBlot.children.head; + 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); + 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) { + if (toolbar.handlers[format] != null) { + const cellBlot = Quill.find(td); + const lines = this.lines(cellBlot); + 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..eec8a7bb1d --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/operate-line.ts @@ -0,0 +1,437 @@ +import Quill from "quill"; +import { setElementProperty, setElementAttribute, updateTableWidth } from "../utils"; +import { TableColgroup } from "../formats/table"; + +interface Options { + tableNode: Element; + cellNode: Element; + 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: any; + options: Options | null; + drag: boolean; + line: HTMLElement | null; + dragBlock: HTMLElement | null; + dragTable: HTMLElement | null; + direction: string | null; + tableBetter: any; + constructor(quill: any, tableBetter?: any) { + 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 = document.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 = document.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 = document.createElement("div"); + const line = document.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 tableBlot = Quill.find(cell).table(); + const colgroup = tableBlot.colgroup(); + 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).table(); + const colgroup = tableBlot.colgroup(); + 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; + document.removeEventListener("mousemove", handleDrag, false); + 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; + document.addEventListener("mousemove", handleDrag); + 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..663053bdab --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/table-menus.ts @@ -0,0 +1,807 @@ +import Quill from "quill"; +import Delta from "quill-delta"; +import { + createTooltip, + getAlign, + getCellFormats, + getCorrectBounds, + getComputeBounds, + getComputeSelectedCols, + getComputeSelectedTds, + setElementProperty, + getElementStyle, + updateTableWidth +} from "../utils"; +import columnIcon from "../assets/icon/column.svg"; +import rowIcon from "../assets/icon/row.svg"; +import mergeIcon from "../assets/icon/merge.svg"; +import tableIcon from "../assets/icon/table.svg"; +import cellIcon from "../assets/icon/cell.svg"; +import wrapIcon from "../assets/icon/wrap.svg"; +import downIcon from "../assets/icon/down.svg"; +import deleteIcon from "../assets/icon/delete.svg"; +import copyIcon from "../assets/icon/copy.svg"; +import { TableCell, TableCol, TableRow, tableId } from "../formats/table"; +import TablePropertiesForm from "./table-properties-form"; +import { CELL_DEFAULT_VALUES, CELL_DEFAULT_WIDTH, CELL_PROPERTIES, DEVIATION, TABLE_PROPERTIES } from "../config"; + +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: _useLanguage, menus?: string[]): MenusDefaults { + const DEFAULT: MenusDefaults = { + column: { + content: useLanguage("col"), + icon: columnIcon, + 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: rowIcon, + 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: mergeIcon, + 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: tableIcon, + 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: cellIcon, + 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: wrapIcon, + 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: deleteIcon, + handler() { + this.deleteTable(); + } + } + }; + const EXTRA: MenusDefaults = { + copy: { + content: useLanguage("copyTable"), + icon: copyIcon, + 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: any; + table: HTMLTableElement | null; + root: HTMLElement; + prevList: HTMLUListElement | null; + prevTooltip: HTMLDivElement | null; + scroll: boolean; + tableBetter: any; + tablePropertiesForm: any; + constructor(quill: any, tableBetter?: any) { + 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); + 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 = document.createElement("ul"); + for (const [, child] of Object.entries(children)) { + const { content, handler } = child; + const list = document.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 = document.createElement("div"); + const dropDown = document.createElement("span"); + if (isDropDown) { + dropDown.innerHTML = left + right; + } else { + dropDown.innerHTML = left; + } + container.classList.add("ql-table-dropdown"); + dropDown.classList.add("ql-table-tooltip-hover"); + container.appendChild(dropDown); + return container; + } + + createMenus() { + const { language, options = {} } = this.tableBetter; + const { menus } = options; + const useLanguage = language.useLanguage.bind(language); + const container = document.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, downIcon, !!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).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); + 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]).table(); + tableBlot.deleteRow(rows, this.deleteTable.bind(this)); + this.updateMenus(); + } + + deleteTable() { + const tableBlot = Quill.find(this.table); + 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); + const cells = tableBlot.descendants(TableCell); + const _left = Math.max(bounds.left, computeBounds.left); + const _right = Math.min(bounds.right, computeBounds.right); + const map: _Map = new Map(); + const leftMap: _Map = new Map(); + const rightMap: _Map = 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: TableCol, 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: HTMLTableElement): 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: HTMLTableCellElement, + rightTd: HTMLTableCellElement + ) { + const changeTds = []; + const delTds = []; + const colgroup = Quill.find(leftTd).table().colgroup(); + 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: _Map, 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); + 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: _Map) { + 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); + 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); + 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); + 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); + const [formats, cellId] = getCellFormats(leftTdBlot); + const head = leftTdBlot.children.head; + const tableBlot = leftTdBlot.table(); + const rows = tableBlot.tbody().children; + 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: TableCell = Quill.find(td); + 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); + child.replaceWith(child.statics.blotName, { ...formats, rowspan: rowspan - offset }); + }); + } + leftTdBlot.setChildrenId(cellId); + head.format(leftTdBlot.statics.blotName, { ...formats, colspan, rowspan: rowspan - offset }); + this.tableBetter.cellSelection.setSelected(head.parent.domNode); + this.quill.scrollSelectionIntoView(); + } + + setCellsMap(cell: TableCell, map: _Map) { + 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); + 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); + 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: HTMLTableElement = 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"); + 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: HTMLTableElement) { + 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..3858238c87 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/table-properties-form.ts @@ -0,0 +1,735 @@ +import Quill from "quill"; +import eraseIcon from "../assets/icon/erase.svg"; +import downIcon from "../assets/icon/down.svg"; +import paletteIcon from "../assets/icon/palette.svg"; +import saveIcon from "../assets/icon/save.svg"; +import closeIcon from "../assets/icon/close.svg"; +import { getProperties } from "../config"; +import { + addDimensionsUnit, + createTooltip, + getClosestElement, + getComputeSelectedCols, + isDimensions, + isValidColor, + setElementProperty, + setElementAttribute +} from "../utils"; +import { TableCellBlock, TableCell } from "../formats/table"; +import TableList, { ListContainer } from "../formats/list"; +import TableHeader from "../formats/header"; +import iro from "@jaames/iro"; + +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: string; + attribute: Props; +} + +interface ColorList { + value: string; + describe: string; +} + +const ACTION_LIST = [ + { icon: saveIcon, label: "save" }, + { icon: closeIcon, 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: any; + options: Options; + attrs: Props; + borderForm: HTMLElement[]; + saveButton: HTMLButtonElement; + form: HTMLDivElement; + constructor(tableMenus: any, 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 container = document.createElement("div"); + const fragment = document.createDocumentFragment(); + container.classList.add("properties-form-action-row"); + for (const { icon, label } of ACTION_LIST) { + const button = document.createElement("button"); + const iconContainer = document.createElement("span"); + iconContainer.innerHTML = icon; + button.appendChild(iconContainer); + setElementAttribute(button, { label }); + if (showLabel) { + const labelContainer = document.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 container = document.createElement("div"); + const fragment = document.createDocumentFragment(); + for (const { icon, describe, align } of menus) { + const container = document.createElement("span"); + container.innerHTML = icon; + 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 = (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 = document.createElement("div"); + container.classList.add("ql-table-color-container"); + const input = this.createColorInput(child); + const colorPicker = this.createColorPicker(child); + container.appendChild(input); + container.appendChild(colorPicker); + return container; + } + + createColorInput(child: Child) { + const container = this.createInput(child); + container.classList.add("label-field-view-color"); + return container; + } + + createColorList(propertyName: string) { + const useLanguage = this.getUseLanguage(); + const container = document.createElement("ul"); + const fragment = document.createDocumentFragment(); + container.classList.add("color-list"); + for (const { value, describe } of COLOR_LIST) { + const li = document.createElement("li"); + const tooltip = createTooltip(useLanguage(describe)); + li.setAttribute("data-color", value); + li.classList.add("ql-table-tooltip-hover"); + setElementProperty(li, { "background-color": value }); + li.appendChild(tooltip); + fragment.appendChild(li); + } + container.appendChild(fragment); + container.addEventListener("click", e => { + const target = e.target as HTMLLIElement; + const value = (target.tagName === "DIV" ? target.parentElement : target).getAttribute("data-color"); + this.setAttribute(propertyName, value, container); + this.updateInputStatus(container, false, true); + }); + return container; + } + + createColorPicker(child: Child) { + const { propertyName, value } = child; + const container = document.createElement("span"); + const colorButton = document.createElement("span"); + container.classList.add("color-picker"); + colorButton.classList.add("color-button"); + if (value) { + setElementProperty(colorButton, { "background-color": value }); + } else { + colorButton.classList.add("color-unselected"); + } + const select = this.createColorPickerSelect(propertyName); + colorButton.addEventListener("click", () => { + this.toggleHidden(select); + const colorContainer = this.getColorClosest(container); + const input: HTMLInputElement = colorContainer?.querySelector(".property-input"); + this.updateSelectedStatus(select, input?.value, "color"); + }); + container.appendChild(colorButton); + container.appendChild(select); + return container; + } + + createColorPickerIcon(svg: string, text: string, listener: EventListener) { + const container = document.createElement("div"); + const icon = document.createElement("span"); + const button = document.createElement("button"); + icon.innerHTML = svg; + button.innerText = text; + container.classList.add("erase-container"); + container.appendChild(icon); + container.appendChild(button); + container.addEventListener("click", listener); + return container; + } + + createColorPickerSelect(propertyName: string) { + const useLanguage = this.getUseLanguage(); + const container = document.createElement("div"); + const remove = this.createColorPickerIcon(eraseIcon, useLanguage("removeColor"), () => { + this.setAttribute(propertyName, "", container); + this.updateInputStatus(container, false, true); + }); + const list = this.createColorList(propertyName); + const palette = this.createPalette(propertyName, useLanguage, container); + container.classList.add("color-picker-select", "ql-hidden"); + container.appendChild(remove); + container.appendChild(list); + container.appendChild(palette); + return container; + } + + createDropdown(value: string, category?: string) { + const container = document.createElement("div"); + const dropText = document.createElement("span"); + const dropDown = document.createElement("span"); + switch (category) { + case "dropdown": + dropDown.innerHTML = downIcon; + dropDown.classList.add("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); + if (category === "dropdown") container.appendChild(dropDown); + return { dropdown: container, dropText }; + } + + createInput(child: Child) { + const { attribute, message, propertyName, value, valid } = child; + const { placeholder = "" } = attribute; + const container = document.createElement("div"); + const wrapper = document.createElement("div"); + const label = document.createElement("label"); + const input = document.createElement("input"); + const status = document.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 => { + // debounce + const value = (e.target as HTMLInputElement).value; + valid && this.switchHidden(status, valid(value)); + this.updateInputStatus(wrapper, valid && !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 container = document.createElement("ul"); + for (const option of options) { + const list = document.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; + dropText.innerText = value; + this.toggleBorderDisabled(value); + this.setAttribute(propertyName, value); + }); + return container; + } + + createPalette(propertyName: string, useLanguage: _useLanguage, parent: HTMLElement) { + const container = document.createElement("div"); + const palette = document.createElement("div"); + const wrap = document.createElement("div"); + const iroContainer = document.createElement("div"); + // @ts-ignore + const colorPicker = new iro.ColorPicker(iroContainer, { + width: 110, + layout: [ + { + component: iro.ui.Wheel, + options: {} + } + ] + }); + const eraseContainer = this.createColorPickerIcon(paletteIcon, useLanguage("colorPicker"), () => + this.toggleHidden(palette) + ); + const btns = this.createActionBtns((e: MouseEvent) => { + const target = (e.target as HTMLElement).closest("button"); + if (!target) return; + const label = target.getAttribute("label"); + if (label === "save") { + this.setAttribute(propertyName, colorPicker.color.hexString, parent); + this.updateInputStatus(container, false, true); + } + palette.classList.add("ql-hidden"); + parent.classList.add("ql-hidden"); + }, false); + palette.classList.add("color-picker-palette", "ql-hidden"); + wrap.classList.add("color-picker-wrap"); + iroContainer.classList.add("iro-container"); + wrap.appendChild(iroContainer); + wrap.appendChild(btns); + palette.appendChild(wrap); + container.appendChild(eraseContainer); + container.appendChild(palette); + return container; + } + + createProperty(property: Properties) { + const { content, children } = property; + const useLanguage = this.getUseLanguage(); + const container = document.createElement("div"); + const label = document.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 container = document.createElement("div"); + container.classList.add("ql-table-properties-form"); + const header = document.createElement("h2"); + const actions = this.createActionBtns((e: MouseEvent) => { + const target = (e.target as HTMLElement).closest("button"); + target && this.checkBtnsAction(target.getAttribute("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: HTMLElement, 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"); + } + + getComputeBounds(type: string) { + if (type === "table") { + const { table } = this.tableMenus; + const [tableBounds, containerBounds] = this.tableMenus.getCorrectBounds(table); + if (tableBounds.bottom > containerBounds.bottom) { + return { ...tableBounds, bottom: containerBounds.height }; + } + return tableBounds; + } else { + const { computeBounds } = this.tableMenus.getSelectedTdsInfo(); + return computeBounds; + } + } + + 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; + } + + getViewportSize() { + return { + viewWidth: document.documentElement.clientWidth, + viewHeight: document.documentElement.clientHeight + }; + } + + 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 [...list, ...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).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, quill.container); + for (const col of cols) { + col.setAttribute("width", `${width}`); + } + } + for (const td of selectedTds) { + const tdBlot = Quill.find(td); + 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: TableCell = tdBlot.replaceWith(blotName, { ...formats, style }); + newSelectedTds.push(parent.domNode); + } + this.tableMenus.tableBetter.cellSelection.setSelectedTds(newSelectedTds); + } + + saveTableAction() { + const { table, tableBetter } = this.tableMenus; + const temporary = Quill.find(table).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; + } + setElementProperty(temporary || table, attrs); + tableBetter.cellSelection.setSelected(td); + } + + setAttribute(propertyName: string, value: string, container?: HTMLElement) { + this.attrs[propertyName] = value; + if (propertyName.includes("-color")) { + 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 = 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 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 = element.querySelector(".property-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) { + container.classList.remove("ql-table-triangle-none"); + const { height, width } = container.getBoundingClientRect(); + const containerBounds = this.tableMenus.quill.container.getBoundingClientRect(); + const { top, left, right, bottom } = this.getComputeBounds(type); + const { viewHeight } = this.getViewportSize(); + let correctTop = bottom + 10; + let correctLeft = (left + right - width) >> 1; + if (correctTop + containerBounds.top + height > viewHeight) { + correctTop = top - height - 10; + if (correctTop < 0) { + correctTop = (containerBounds.height - height) >> 1; + container.classList.add("ql-table-triangle-none"); + } else { + container.classList.add("ql-table-triangle-up"); + container.classList.remove("ql-table-triangle-down"); + } + } else { + container.classList.add("ql-table-triangle-down"); + container.classList.remove("ql-table-triangle-up"); + } + if (correctLeft < containerBounds.left) { + correctLeft = 0; + container.classList.add("ql-table-triangle-none"); + } else if (correctLeft + width > containerBounds.right) { + correctLeft = containerBounds.right - width; + container.classList.add("ql-table-triangle-none"); + } + setElementProperty(container, { + left: `${correctLeft}px`, + top: `${correctTop}px` + }); + } + + updateSelectColor(element: Element, value: string) { + const input: HTMLInputElement = element.querySelector(".property-input"); + const colorButton: HTMLElement = element.querySelector(".color-button"); + const colorPickerSelect: HTMLElement = element.querySelector(".color-picker-select"); + const status: HTMLElement = element.querySelector(".label-field-view-status"); + if (!value) { + colorButton.classList.add("color-unselected"); + } else { + colorButton.classList.remove("color-unselected"); + } + input.value = value; + setElementProperty(colorButton, { "background-color": value }); + colorPickerSelect.classList.add("ql-hidden"); + this.switchHidden(status, isValidColor(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..7a6406bbd3 --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/ui/toolbar-table.ts @@ -0,0 +1,123 @@ +import Quill from "quill"; +import tableIcon from "../assets/icon/table.svg"; + +const Inline = Quill.import("blots/inline"); +const icons = Quill.import("ui/icons"); +icons["table-better"] = tableIcon; +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 x 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: _insertTable) { + 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: _insertTable) { + const [row, column] = this.getSelectAttrs(child); + insertTable(row, column); + this.hide(this.root); + } + + setLabelContent(label: Element, child: Element) { + if (!child) { + label.innerHTML = "0 x 0"; + } else { + const [row, column] = this.getSelectAttrs(child); + label.innerHTML = `${row} x ${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 { TableSelect, ToolbarTable as default }; 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..3a00e9186d --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/utils/clipboard-matchers.ts @@ -0,0 +1,88 @@ +import Delta from "quill-delta"; +import merge from "lodash.merge"; +import { filterWordStyle } from "./"; +import { TableCell } from "../formats/table"; + +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..ad9a515ecd --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/utils/index.ts @@ -0,0 +1,378 @@ +import Quill from "quill"; +import { TableCell, TableCellBlock, TableCol } from "../formats/table"; +import TableList, { ListContainer } from "../formats/list"; +import TableHeader from "../formats/header"; +import { COLORS, DEVIATION } from "../config"; + +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: AllowedChildren): 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) { + const [block] = cellBlot.descendant(TableCellBlock); + const [list] = cellBlot.descendant(ListContainer); + 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); + 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); + 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 | AllowedChildren): TableCell | null { + while (blot) { + if (blot.statics.blotName === TableCell.blotName) { + // @ts-ignore + return blot; + } + 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); + 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 type AllowedChildren = TableCellBlock | TableHeader | TableList; +export { + addDimensionsUnit, + convertUnitToInteger, + createTooltip, + debounce, + filterWordStyle, + getAlign, + getCellChildBlot, + getCellFormats, + getCellId, + getClosestElement, + getComputeBounds, + getComputeSelectedCols, + getComputeSelectedTds, + getCopyTd, + getCorrectBounds, + getCorrectCellBlot, + getElementStyle, + isDimensions, + isValidColor, + isValidDimensions, + removeElementProperty, + rgbToHex, + rgbaToHex, + setElementAttribute, + setElementProperty, + throttle, + throttleStrong, + updateTableWidth +}; diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/table.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/table.ts new file mode 100644 index 0000000000..adde1a6f7e --- /dev/null +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/table.ts @@ -0,0 +1,81 @@ +// import {TableCell, TableRow, TableBody, TableContainer} from "quill/formats/table"; + +// const ATTRIBUTES = ["colspan", "height", "width", "class", "id"]; + +// type tableCellAttributes = { +// id?: string; +// colspan?: string; +// class?: string; +// height?: string; +// width?: string; +// }; + +// class MxTableCell extends TableCell { +// static create(value: unknown): HTMLElement { +// const domNode = super.create(value as string) as HTMLElement; +// if (value as tableCellAttributes) { +// const cellAttr = value as tableCellAttributes; +// // for each tableCellAttributes type +// if (cellAttr.id) { +// domNode.setAttribute("id", cellAttr.id); +// } +// if (cellAttr.class) { +// domNode.setAttribute("class", cellAttr.class); +// } +// if (cellAttr.width) { +// domNode.setAttribute("width", cellAttr.width); +// } +// if(cellAttr.height){ +// domNode.setAttribute("height", cellAttr.height); +// } +// if (cellAttr.colspan) { +// domNode.setAttribute("colspan", cellAttr.colspan); +// } +// } +// return domNode; +// } + +// static formats(domNode: Element): Record { +// return ATTRIBUTES.reduce((formats: Record, attribute) => { +// if (domNode.hasAttribute(attribute)) { +// formats[attribute] = domNode.getAttribute(attribute); +// } +// return formats; +// }, {}); +// } +// } + +// export {MxTableCell}; + +// // export default class CustomLink extends Link { +// // format(name: string, value: unknown): void { +// // if (name !== this.statics.blotName || !value) { +// // super.format(name, value); +// // } else if ((value as linkConfigType)?.href !== undefined) { +// // const linkConfig = value as linkConfigType; +// // // @ts-expect-error the constructor is generic function, ts will consider sanitize not exist +// // this.domNode.setAttribute("href", getLink(this.constructor.sanitize(linkConfig.href))); +// // this.domNode.setAttribute("target", linkConfig.target ?? "_blank"); +// // this.domNode.setAttribute("title", linkConfig.title ?? ""); +// // this.domNode.textContent = linkConfig.text ?? linkConfig.href; +// // } else { +// // // @ts-expect-error the constructor is generic function, ts will consider sanitize not exist +// // this.domNode.setAttribute("href", getLink(this.constructor.sanitize(value))); +// // } +// // } + +// // static create(value: unknown): HTMLElement { +// // if ((value as linkConfigType)?.href !== undefined) { +// // const linkConfig = value as linkConfigType; +// // const node = super.create(linkConfig.href) as HTMLElement; +// // node.setAttribute("href", getLink(this.sanitize(linkConfig.href))); +// // node.setAttribute("rel", "noopener noreferrer"); +// // node.setAttribute("title", linkConfig.title ?? linkConfig.href); +// // node.setAttribute("target", linkConfig.target || "_blank"); +// // return node; +// // } else { +// // // @ts-expect-error type mismatch expected +// // return super.create(value); +// // } +// // } +// // } diff --git a/packages/pluggableWidgets/rich-text-web/typings/declare-svg.ts b/packages/pluggableWidgets/rich-text-web/typings/declare-svg.ts index 1bed3c6deb..8d19c68386 100644 --- a/packages/pluggableWidgets/rich-text-web/typings/declare-svg.ts +++ b/packages/pluggableWidgets/rich-text-web/typings/declare-svg.ts @@ -3,4 +3,6 @@ declare module "*.svg" { export = content; } +declare module 'quill-better-table'; + declare module '*.css'; \ No newline at end of file From 9c06976d09c8cb663237140cb707430e43a479f1 Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Tue, 25 Feb 2025 16:08:23 +0100 Subject: [PATCH 02/28] fix: wip - update quill-table-better files --- .../quill-table-better/config/index.ts | 13 +- .../quill-table-better/formats/header.ts | 17 +- .../quill-table-better/formats/list.ts | 24 ++- .../quill-table-better/formats/table.ts | 193 +++++++++++------- .../quill-table-better/modules/clipboard.ts | 18 +- .../quill-table-better/modules/toolbar.ts | 59 ++++-- .../quill-table-better/quill-table-better.ts | 133 ++++-------- .../utils/formats/quill-table-better/types.ts | 67 ++++++ .../quill-table-better/ui/cell-selection.ts | 14 +- .../quill-table-better/ui/operate-line.ts | 20 +- .../quill-table-better/ui/table-menus.ts | 113 +++++----- .../ui/table-properties-form.ts | 40 ++-- .../quill-table-better/ui/toolbar-table.ts | 15 +- .../utils/clipboard-matchers.ts | 5 +- .../formats/quill-table-better/utils/index.ts | 16 +- 15 files changed, 438 insertions(+), 309 deletions(-) diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/config/index.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/config/index.ts index c277223e95..0f17ee6377 100644 --- a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/config/index.ts +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/config/index.ts @@ -1,10 +1,11 @@ import alignBottomIcon from "../assets/icon/align-bottom.svg"; import alignCenterIcon from "../assets/icon/align-center.svg"; +import alignJustifyIcon from "../assets/icon/align-justify.svg"; import alignLeftIcon from "../assets/icon/align-left.svg"; import alignMiddleIcon from "../assets/icon/align-middle.svg"; -import alignJustifyIcon from "../assets/icon/align-justify.svg"; import alignRightIcon from "../assets/icon/align-right.svg"; import alignTopIcon from "../assets/icon/align-top.svg"; +import type { Props, UseLanguageHandler } from "../types"; import { convertUnitToInteger, isValidColor, isValidDimensions } from "../utils"; interface Options { @@ -206,7 +207,7 @@ const TABLE_PROPERTIES = [ "align" ]; -function getCellProperties(attribute: Props, useLanguage: _useLanguage) { +function getCellProperties(attribute: Props, useLanguage: UseLanguageHandler) { return { title: useLanguage("cellProps"), properties: [ @@ -327,7 +328,7 @@ function getCellProperties(attribute: Props, useLanguage: _useLanguage) { }; } -function getTableProperties(attribute: Props, useLanguage: _useLanguage) { +function getTableProperties(attribute: Props, useLanguage: UseLanguageHandler) { return { title: useLanguage("tblProps"), properties: [ @@ -421,7 +422,7 @@ function getTableProperties(attribute: Props, useLanguage: _useLanguage) { }; } -function getProperties({ type, attribute }: Options, useLanguage: _useLanguage) { +function getProperties({ type, attribute }: Options, useLanguage: UseLanguageHandler) { if (type === "table") return getTableProperties(attribute, useLanguage); return getCellProperties(attribute, useLanguage); } @@ -433,6 +434,6 @@ export { CELL_PROPERTIES, COLORS, DEVIATION, - TABLE_PROPERTIES, - getProperties + getProperties, + TABLE_PROPERTIES }; diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/header.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/header.ts index 6089d2c46b..bac5548659 100644 --- a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/header.ts +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/header.ts @@ -1,14 +1,19 @@ +import type { BlockBlot } from "parchment"; import Quill from "quill"; -import { type Props, type Range } from "../types"; -import { TableCellBlock, TableCell } from "./table"; -import { ListContainer } from "./list"; +import QuillHeader from "quill/formats/header"; +import type { Props, TableCellChildren } from "../types"; import { getCellFormats, getCorrectCellBlot } from "../utils"; -import Header from "quill/formats/header"; +import { ListContainer } from "./list"; +import { TableCell, TableCellBlock } from "./table"; + +const Header = QuillHeader as typeof BlockBlot; class TableHeader extends Header { static blotName = "table-header"; static className = "ql-table-header"; + parent: TableCell; + static create(formats: Props) { const { cellId, value } = formats; const node = super.create(value); @@ -58,9 +63,9 @@ class TableHeader extends Header { return formats; } - getCellFormats(parent: TableCell) { + getCellFormats(parent: TableCell | TableCellChildren) { const cellBlot = getCorrectCellBlot(parent); - return getCellFormats(cellBlot); + return getCellFormats(cellBlot!); } } diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/list.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/list.ts index ae4390593b..10ffb93ea7 100644 --- a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/list.ts +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/list.ts @@ -1,15 +1,22 @@ +import type { BlockBlot, ContainerBlot } from "parchment"; import Quill from "quill"; -import { type Props, type Range } from "../types"; -import { TableCell, TableCellBlock } from "./table"; -import { getCellFormats, getCorrectCellBlot } from "../utils"; +import QuillList from "quill/formats/list"; +import QuillContainer from "quill/blots/container"; import { CELL_ATTRIBUTE } from "../config"; -import Container from "quill/blots/container"; -import List from "quill/formats/list"; +import type { Props, TableCellChildren } from "../types"; +import { getCellFormats, getCorrectCellBlot } from "../utils"; +import { TableCell, TableCellBlock } from "./table"; + +const List = QuillList as typeof BlockBlot; +const Container = QuillContainer as typeof ContainerBlot; const DEFAULT_ATTRIBUTE = ["colspan", "rowspan"]; class ListContainer extends Container { + next: this | null; + parent: TableCell; + static create(value: Props) { - const node = super.create(); + const node = super.create() as HTMLElement; for (const key of DEFAULT_ATTRIBUTE) { if (value[key] == "1") delete value[key]; } @@ -55,6 +62,8 @@ ListContainer.className = "table-list-container"; ListContainer.tagName = "OL"; class TableList extends List { + parent: ListContainer; + format(name: string, value: string | Props, isReplace?: boolean) { const list = this.formats()[this.statics.blotName]; if (name === "list") { @@ -91,7 +100,7 @@ class TableList extends List { } } - getCellFormats(parent: TableCell) { + getCellFormats(parent: TableCell | TableCellChildren) { const cellBlot = getCorrectCellBlot(parent); return getCellFormats(cellBlot); } @@ -117,6 +126,7 @@ class TableList extends List { if (blot.statics.blotName === ListContainer.blotName) { return blot; } + // @ts-ignore blot = blot.parent; } return null; diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts index 540fb57a5b..3842c14d50 100644 --- a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts @@ -1,22 +1,27 @@ +import type { BlockBlot, ContainerBlot, LinkedList } from "parchment"; import Quill from "quill"; -import Block from "quill/blots/block"; -import Break from "quill/blots/break"; -import Container from "quill/blots/container"; -import { type Props, type Range } from "../types"; +import QuillBlock from "quill/blots/block"; +import QuillContainer from "quill/blots/container"; +import { CELL_ATTRIBUTE, CELL_DEFAULT_WIDTH, DEVIATION } from "../config"; +import type { Props, TableCellAllowedChildren } from "../types"; import { filterWordStyle, getCellChildBlot, getCellFormats, getCellId, getCopyTd, getCorrectCellBlot } from "../utils"; import TableHeader from "./header"; import { ListContainer } from "./list"; -import { CELL_ATTRIBUTE, CELL_DEFAULT_WIDTH, DEVIATION } from "../config"; - -// const Block = Quill.import('blots/block'); -// const Break = Quill.import('blots/break'); -// const Container = Quill.import('blots/container'); +const Block = QuillBlock as typeof BlockBlot; +const Container = QuillContainer as typeof ContainerBlot; const TABLE_ATTRIBUTE = ["border", "cellspacing", "style", "data-class"]; -const STYLE_RULES = ["color", "border", "width", "height"]; +// const STYLE_RULES = ["color", "border", "width", "height"]; const COL_ATTRIBUTE = ["width"]; class TableCellBlock extends Block { + static blotName = "table-cell-block"; + static className = "ql-table-block"; + static tagName = "P"; + + next: this | null; + parent: TableCell; + static create(value: string) { const node = super.create(); if (value) { @@ -71,11 +76,16 @@ class TableCellBlock extends Block { this.wrap(TableCell.blotName, formats); } } -TableCellBlock.blotName = "table-cell-block"; -TableCellBlock.className = "ql-table-block"; -TableCellBlock.tagName = "P"; class TableCell extends Container { + static blotName = "table-cell"; + static tagName = "TD"; + + children: LinkedList; + next: this | null; + parent: TableRow; + prev: this | null; + checkMerge() { if (super.checkMerge() && this.next.children.head != null && this.next.children.head.formats) { const thisHead = this.children.head.formats()[this.children.head.statics.blotName]; @@ -92,7 +102,7 @@ class TableCell extends Container { } static create(value: Props) { - const node = super.create(); + const node = super.create() as HTMLElement; const keys = Object.keys(value); for (const key of keys) { value[key] && node.setAttribute(key, value[key]); @@ -173,22 +183,26 @@ class TableCell extends Container { }); } - table() { + table(): TableContainer { let cur = this.parent; while (cur != null && cur.statics.blotName !== "table-container") { + // @ts-expect-error cur = cur.parent; } + // @ts-expect-error return cur; } - optimize(...args: unknown[]) { - super.optimize(...args); - this.children.forEach((child: TableCellBlock | TableHeader | ListContainer) => { + optimize(context?: unknown) { + super.optimize(context); + + this.children.forEach((child: TableCellAllowedChildren) => { if (child.next == null) return; const childFormats = getCellId(child.formats()[child.statics.blotName]); const nextFormats = getCellId(child.next.formats()[child.next.statics.blotName]); if (childFormats !== nextFormats) { const next = this.splitAfter(child); + // @ts-expect-error if (next) next.optimize(); // We might be able to merge with prev now if (this.prev) this.prev.optimize(); @@ -196,10 +210,16 @@ class TableCell extends Container { }); } } -TableCell.blotName = "table-cell"; -TableCell.tagName = "TD"; class TableRow extends Container { + static blotName = "table-row"; + static tagName = "TR"; + + children: LinkedList; + next: this | null; + parent: TableBody; + prev: this | null; + checkMerge() { if (super.checkMerge() && this.next.children.head != null && this.next.children.head.formats) { const thisHead = this.children.head.formats()[this.children.head.statics.blotName]; @@ -222,19 +242,33 @@ class TableRow extends Container { return -1; } } -TableRow.blotName = "table-row"; -TableRow.tagName = "TR"; -class TableBody extends Container {} -TableBody.blotName = "table-body"; -TableBody.tagName = "TBODY"; +class TableBody extends Container { + static blotName = "table-body"; + static tagName = "TBODY"; + + children: LinkedList; + next: this | null; + parent: TableContainer; +} class TableTemporary extends Block { + static blotName = "table-temporary"; + static className = "ql-table-temporary"; + static tagName = "temporary"; + + next: this | null; + static create(value: Props) { const node = super.create(); const keys = Object.keys(value); + const className = TableContainer.defaultClassName; for (const key of keys) { - node.setAttribute(key, value[key]); + if (key === "data-class" && !~value[key].indexOf(className)) { + node.setAttribute(key, `${className} ${value[key]}`); + } else { + node.setAttribute(key, value[key]); + } } return node; } @@ -271,11 +305,13 @@ class TableTemporary extends Block { super.optimize(...args); } } -TableTemporary.blotName = "table-temporary"; -TableTemporary.className = "ql-table-temporary"; -TableTemporary.tagName = "temporary"; class TableCol extends Block { + static blotName = "table-col"; + static tagName = "COL"; + + next: this | null; + static create(value: Props) { const node = super.create(); const keys = Object.keys(value); @@ -303,17 +339,26 @@ class TableCol extends Block { return this.domNode.outerHTML; } } -TableCol.blotName = "table-col"; -TableCol.tagName = "COL"; -class TableColgroup extends Container {} -TableColgroup.blotName = "table-colgroup"; -TableColgroup.tagName = "COLGROUP"; +class TableColgroup extends Container { + static blotName = "table-colgroup"; + static tagName = "COLGROUP"; + + children: LinkedList; + next: this | null; +} class TableContainer extends Container { + static blotName = "table-container"; + static defaultClassName = "ql-table-better"; + static tagName = "TABLE"; + + children: LinkedList; + colgroup() { + // @ts-expect-error const [colgroup] = this.descendant(TableColgroup); - return colgroup || this.findChild("table-colgroup"); + return colgroup || (this.findChild("table-colgroup") as TableColgroup); } deleteColumn(changeTds: [Element, number][], delTds: Element[], deleteTable: () => void, cols: Element[] = []) { @@ -324,7 +369,7 @@ class TableContainer extends Container { deleteTable(); } else { for (const [td, offset] of changeTds) { - this.setCellColspan(Quill.find(td), offset); + this.setCellColspan(Quill.find(td) as TableCell, offset); } for (const td of [...delTds, ...cols]) { if (td.parentElement.children.length === 1) { @@ -375,7 +420,7 @@ class TableContainer extends Container { this.setColumnCells(next, columnCells, { position, width }, formats, rowspan, prev); } for (const [row, formats, ref, prev] of columnCells) { - const cell: TableCell = this.scroll.create(TableCell.blotName, formats); + const cell = this.scroll.create(TableCell.blotName, formats) as TableCell; prev.moveChildren(cell); const _cellId = cellId(); cell.setChildrenId(_cellId); @@ -428,7 +473,7 @@ class TableContainer extends Container { const body = this.tbody(); if (body == null || body.children.head == null) return; const id = tableId(); - const row = this.scroll.create(TableRow.blotName); + 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) { @@ -462,7 +507,7 @@ class TableContainer extends Container { } } - getMaxColumns(children: TableCell[]) { + getMaxColumns(children: LinkedList) { return children.reduce((num: number, child: TableCell) => { const colspan = ~~child.domNode.getAttribute("colspan") || 1; return (num += colspan); @@ -470,8 +515,8 @@ class TableContainer extends Container { } insertColumn(position: number, isLast: boolean, w: number, offset: number) { - const colgroup = this.colgroup(); - const body = this.tbody(); + 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][] = []; @@ -528,12 +573,12 @@ class TableContainer extends Container { 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); - const cellBlock = this.scroll.create(TableCellBlock.blotName, cellId()); + 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); + row = this.scroll.create(TableRow.blotName) as TableRow; tbody.insertBefore(row, null); } row.insertBefore(cell, ref); @@ -542,7 +587,7 @@ class TableContainer extends Container { } insertRow(index: number, offset: number) { - const body = this.tbody(); + 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); @@ -556,15 +601,15 @@ class TableContainer extends Container { } else { delete formats["colspan"]; } - const cell = this.scroll.create(TableCell.blotName, formats); - const cellBlock = this.scroll.create(TableCellBlock.blotName, cellId()); + 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(...args: unknown[]) { - super.optimize(...args); + optimize(context: unknown) { + super.optimize(context); const temporaries = this.descendants(TableTemporary); this.setClassName(temporaries); if (temporaries.length > 1) { @@ -592,7 +637,7 @@ class TableContainer extends Container { const children = parentElement.querySelectorAll("td[rowspan]"); if (children.length) { for (const child of children) { - const cell = Quill.find(child); + const cell = Quill.find(child) as TableCell; const blotName = cell.statics.blotName; const formats = cell.formats()[blotName]; const rowspan = (~~formats["rowspan"] || 1) - 1; @@ -621,31 +666,27 @@ class TableContainer extends Container { } return classNames.join(" ").trim(); }; - const setClass = (temporary: TableTemporary, value: string) => { - temporary.domNode.setAttribute("data-class", value); + 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) { - const className = temporary.domNode.getAttribute("data-class"); - if (className !== _className && _className != null) { - setClass(temporary, getClassName(_className)); - } - if (!_className && !className) { - setClass(temporary, defaultClassName); - } + setClass(temporary, _className); } } else { - const className = _temporary.domNode.getAttribute("data-class"); - if (className !== _className && _className != null) { - setClass(_temporary, getClassName(_className)); - } - if (!_className && !className) { - setClass(_temporary, defaultClassName); - } + setClass(_temporary, _className); } } @@ -687,19 +728,17 @@ class TableContainer extends Container { } tbody() { + // @ts-expect-error const [body] = this.descendant(TableBody); - return body || this.findChild("table-body"); + return body || (this.findChild("table-body") as TableBody); } temporary() { + // @ts-expect-error const [temporary] = this.descendant(TableTemporary); return temporary; } } -TableContainer.blotName = "table-container"; -// TableContainer.className = 'ql-table-better'; -TableContainer.defaultClassName = "ql-table-better"; -TableContainer.tagName = "TABLE"; TableContainer.allowedChildren = [TableBody, TableTemporary, TableColgroup]; TableBody.requiredContainer = TableContainer; @@ -732,13 +771,13 @@ function tableId() { export { cellId, - TableCellBlock, - TableCell, - TableRow, TableBody, - TableTemporary, + TableCell, + TableCellBlock, + TableCol, + TableColgroup, TableContainer, tableId, - TableCol, - TableColgroup + TableRow, + TableTemporary }; 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 index fa3630caa0..c931b252a0 100644 --- 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 @@ -1,14 +1,28 @@ 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 = Quill.import("modules/clipboard"); +const Clipboard = QuillClipboard as typeof Module; const debug = logger("quill:clipboard"); class TableClipboard extends Clipboard { + 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); + 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); 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 index 28b2b995e5..94d4e79ce9 100644 --- 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 @@ -1,14 +1,27 @@ -import Quill from "quill"; -import Delta from "quill-delta"; import merge from "lodash.merge"; +import type { ContainerBlot } from "parchment"; import { EmbedBlot } from "parchment"; -import { getCorrectCellBlot } from "../utils"; -import { TableCell } from "../formats/table"; +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 Container from "quill/blots/container"; -import Toolbar from "quill/modules/toolbar"; +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; @@ -34,7 +47,12 @@ class TableToolbar extends Toolbar { this.controls.push([format, input]); } - private cellSelectionAttach(input: HTMLElement, format: string, e: Event | MouseEvent, cellSelection: any) { + private cellSelectionAttach( + input: HTMLElement, + format: string, + e: Event | MouseEvent, + cellSelection: CellSelection + ) { if (input.tagName === "SELECT") { // @ts-ignore if (input.selectedIndex < 0) return; @@ -53,16 +71,16 @@ class TableToolbar extends Toolbar { } getTableBetter() { - return this.quill.getModule("table-better") || {}; + return this.quill.getModule("table-better") as QuillTableBetter; } - setTableFormat(range: Range, selectedTds: Element[], value: string, name: string, lines: any[]) { + 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); + blot = line.format(name, value, isReplace) as TableCellChildren; } if (selectedTds.length < 2) { if (_isReplace || lines.length === 1) { @@ -108,7 +126,10 @@ class TableToolbar extends Toolbar { const [range] = this.quill.selection.getRange(); if (this.handlers[format] != null) { this.handlers[format].call(this, value); - } else if (this.quill.scroll.query(format).prototype instanceof EmbedBlot) { + } 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( @@ -126,7 +147,7 @@ class TableToolbar extends Toolbar { } function containers(blot: TableCell, index = 0, length = Number.MAX_VALUE) { - const getContainers = (blot: TableCell, blotIndex: number, blotLength: number) => { + const getContainers = (blot: TableCell | TableCellAllowedChildren, blotIndex: number, blotLength: number) => { // @ts-ignore let containers: Container[] = []; let lengthLeft = blotLength; @@ -147,22 +168,22 @@ function containers(blot: TableCell, index = 0, length = Number.MAX_VALUE) { return getContainers(blot, index, length); } -function getHeaderReplace(selectedTds: Element[], name: string, line: TableHeader, _isReplace: boolean) { +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: any[]): number { +function getLength(blots: TableCellChildren[]): number { return blots.reduce((sum, blot) => { return (sum += blot.length()); }, 0); } -function isReplace(range: Range, selectedTds: Element[], lines: any[]) { +function isReplace(range: Range, selectedTds: Element[], lines: TableCellChildren[]) { if (selectedTds.length === 1) { - const cellBlot = Quill.find(selectedTds[0]); + const cellBlot = Quill.find(selectedTds[0]) as TableCell; const _containers = containers(cellBlot, range.index, range.length); const length = getLength(_containers); const _length = getLength(lines); @@ -171,7 +192,7 @@ function isReplace(range: Range, selectedTds: Element[], lines: any[]) { return !!(selectedTds.length > 1); } -function tablehandler(value: string, selectedTds: Element[], name: string, lines?: any[]) { +function tablehandler(value: string, selectedTds: Element[], name: string, lines?: TableCellChildren[]) { const range = this.quill.getSelection(); if (!lines) { if (!range.length && selectedTds.length === 1) { @@ -186,7 +207,7 @@ function tablehandler(value: string, selectedTds: Element[], name: string, lines TableToolbar.DEFAULTS = merge({}, Toolbar.DEFAULTS, { handlers: { - header(value: string, lines?: any[]) { + header(value: string, lines?: TableCellChildren[]) { const { cellSelection } = this.getTableBetter(); const selectedTds = cellSelection?.selectedTds; if (selectedTds?.length) { @@ -194,7 +215,7 @@ TableToolbar.DEFAULTS = merge({}, Toolbar.DEFAULTS, { } this.quill.format("header", value, Quill.sources.USER); }, - list(value: string, lines?: any[]) { + list(value: string, lines?: TableCellChildren[]) { const { cellSelection } = this.getTableBetter(); const selectedTds = cellSelection?.selectedTds; if (selectedTds?.length) { 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 index 9e48d13c49..8e67f6cedd 100644 --- 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 @@ -1,33 +1,32 @@ +import type { EmitterSource, Range } from "quill"; import Quill from "quill"; import Delta from "quill-delta"; +import Module from "quill/core/module"; +import { CELL_DEFAULT_WIDTH } from "./config"; +import TableHeader from "./formats/header"; +import { ListContainer } from "./formats/list"; import { cellId, - TableCellBlock, - TableCell, - TableRow, TableBody, - TableTemporary, + TableCell, + TableCellBlock, + TableCol, + TableColgroup, TableContainer, tableId, - TableCol, - TableColgroup + TableRow, + TableTemporary } 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 TableClipboard from "./modules/clipboard"; +import TableToolbar from "./modules/toolbar"; +import type { BindingObject, Context, Props } from "./types"; 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"; -import { type Props, type Range } from "./types"; -interface Context { - [propName: string]: any; -} +import { matchTable, matchTableCell, matchTableCol, matchTableTemporary } from "./utils/clipboard-matchers"; interface Options { language?: @@ -46,72 +45,15 @@ interface Options { type Line = TableCellBlock | TableHeader | ListContainer; -const Module = Quill.import("core/module"); - class Table extends Module { language: Language; cellSelection: CellSelection; operateLine: OperateLine; tableMenus: TableMenus; tableSelect: TableSelect; - static keyboardBindings: { - "table-cell down": { key: string; collapsed: boolean; format: string[]; handler(): boolean }; - "table-cell up": { key: string; collapsed: boolean; format: string[]; handler(): boolean }; - "table-cell-block backspace": { - key: string; - format: string[]; - collapsed: boolean; - handler(range: Range, context: Context): any; - }; - "table-cell-block delete": { - key: string; - format: string[]; - collapsed: boolean; - handler(range: Range, context: Context): any; - }; - "table-header backspace": { - key: string; - format: string[]; - collapsed: boolean; - empty: boolean; - handler(range: Range, context: Context): any; - }; - "table-header delete": { - key: string; - format: string[]; - collapsed: boolean; - empty: boolean; - handler(range: Range, context: Context): any; - }; - "table-header enter": { - key: string; - collapsed: boolean; - format: string[]; - suffix: RegExp; - handler(range: Range, context: Context): void; - }; - "table-list backspace": { - key: string; - format: string[]; - collapsed: boolean; - empty: boolean; - handler(range: Range, context: Context): void; - }; - "table-list delete": { - key: string; - format: string[]; - collapsed: boolean; - empty: boolean; - handler(range: Range, context: Context): void; - }; - "table-list empty enter": { - key: string; - collapsed: boolean; - format: string[]; - empty: boolean; - handler(range: Range, context: Context): void; - }; - }; + options: Options; + + static keyboardBindings: { [propName: string]: BindingObject }; static register() { Quill.register(TableCellBlock, true); @@ -122,11 +64,16 @@ class Table extends Module { Quill.register(TableContainer, true); Quill.register(TableCol, true); Quill.register(TableColgroup, true); - Quill.register("modules/toolbar", TableToolbar, true); - Quill.register("modules/clipboard", TableClipboard, true); + Quill.register( + { + "modules/toolbar": TableToolbar, + "modules/clipboard": TableClipboard + }, + true + ); } - constructor(quill: any, options: Options) { + constructor(quill: Quill, options: Options) { super(quill, options); quill.clipboard.addMatcher("td, th", matchTableCell); quill.clipboard.addMatcher("tr", matchTable); @@ -140,7 +87,7 @@ class Table extends Module { 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); + this.registerToolbarTable(options?.toolbarTable); } clearHistorySelected() { @@ -164,7 +111,7 @@ class Table extends Module { this.quill.setSelection(offset, Quill.sources.SILENT); } - deleteTableTemporary(source: string = Quill.sources.API) { + deleteTableTemporary(source: EmitterSource = Quill.sources.API) { const temporaries = this.quill.scroll.descendants(TableTemporary); for (const temporary of temporaries) { temporary.remove(); @@ -173,15 +120,17 @@ class Table extends Module { this.quill.update(source); } - getTable(range = this.quill.getSelection()) { + 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; - const row = cell.parent; - const table = row.parent.parent; + const cell = block.parent as TableCell; + const row = cell.parent as TableRow; + const table = row.parent.parent as TableContainer; return [table, row, cell, offset]; } @@ -254,8 +203,8 @@ class Table extends Module { private registerToolbarTable(toolbarTable: boolean) { if (!toolbarTable) return; - Quill.register("formats/table-better", ToolbarTable, true); - const toolbar = this.quill.getModule("toolbar"); + 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); @@ -271,7 +220,7 @@ class Table extends Module { }); } - private showTools(force?: boolean) { + showTools(force?: boolean) { const [table, , cell] = this.getTable(); if (!table || !cell) return; this.cellSelection.setDisabled(true); @@ -320,10 +269,10 @@ const keyboardBindings = { collapsed: true, format: ["table-list"], empty: true, - handler(range: Range, context: Context) { + handler(_range: Range, context: Context) { const { line } = context; const { cellId } = line.parent.formats()[line.parent.statics.blotName]; - const blot = line.replaceWith(TableCellBlock.blotName, cellId); + 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); @@ -377,7 +326,7 @@ function makeTableHeaderHandler(key: string) { format: ["table-header"], collapsed: true, empty: true, - handler(range: Range, context: Context) { + handler(range: Range, _context: Context) { const [line] = this.quill.getLine(range.index); if (line.prev) { return removeLine.call(this, line, range); @@ -395,7 +344,7 @@ function makeTableListHandler(key: string) { format: ["table-list"], collapsed: true, empty: true, - handler(range: Range, context: Context) { + 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); 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 index 361f6631b8..07b1d9c554 100644 --- 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 @@ -1,3 +1,11 @@ +import Quill from "quill"; +import TableHeader from "./formats/header"; +import TableList, { ListContainer } from "./formats/list"; +import { 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; @@ -15,3 +23,62 @@ 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, + 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 index 30202a03db..7851b1410d 100644 --- 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 @@ -1,15 +1,13 @@ import Quill from "quill"; -import Delta from "quill-delta"; import type { Op } from "quill-delta"; +import Delta from "quill-delta"; +import Block, { BlockEmbed } from "quill/blots/block"; +import Container from "quill/blots/container"; +import { DEVIATION } from "../config"; +import { TableCell, TableCellBlock, TableContainer, TableRow } from "../formats/table"; +import type { AllowedChildren } from "../utils"; import { getComputeBounds, getComputeSelectedTds, getCopyTd, getCorrectBounds, getCorrectCellBlot } from "../utils"; import { applyFormat } from "../utils/clipboard-matchers"; -import type { AllowedChildren } from "../utils"; -import { TableCellBlock, TableCell, TableRow, TableContainer } from "../formats/table"; -import { DEVIATION } from "../config"; - -const Block = Quill.import("blots/block"); -const { BlockEmbed } = Quill.import("blots/block"); -const Container = Quill.import("blots/container"); const WHITE_LIST = [ "bold", 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 index eec8a7bb1d..7db00c90be 100644 --- 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 @@ -1,10 +1,10 @@ import Quill from "quill"; +import type { QuillTableBetter, TableCell, TableColgroup } from "../types"; import { setElementProperty, setElementAttribute, updateTableWidth } from "../utils"; -import { TableColgroup } from "../formats/table"; interface Options { - tableNode: Element; - cellNode: Element; + tableNode: HTMLElement; + cellNode: HTMLElement; mousePosition: { clientX: number; clientY: number; @@ -17,15 +17,15 @@ const LINE_CONTAINER_HEIGHT = 5; const LINE_CONTAINER_WIDTH = 5; class OperateLine { - quill: any; + quill: Quill; options: Options | null; drag: boolean; line: HTMLElement | null; dragBlock: HTMLElement | null; dragTable: HTMLElement | null; direction: string | null; - tableBetter: any; - constructor(quill: any, tableBetter?: any) { + tableBetter: QuillTableBetter; + constructor(quill: Quill, tableBetter?: QuillTableBetter) { this.quill = quill; this.options = null; this.drag = false; @@ -221,8 +221,8 @@ class OperateLine { const { right } = cell.getBoundingClientRect(); const change = ~~(clientX - right); const colSum = this.getLevelColSum(cell); - const tableBlot = Quill.find(cell).table(); - const colgroup = tableBlot.colgroup(); + const tableBlot = (Quill.find(cell) as TableCell).table(); + const colgroup = tableBlot.colgroup() as TableColgroup; const bounds = tableBlot.domNode.getBoundingClientRect(); if (colgroup) { const col = this.getCorrectCol(colgroup, colSum); @@ -283,8 +283,8 @@ class OperateLine { const averageX = changeX / maxColNum; const averageY = changeY / rows.length; const preNodes: [Element, string, string][] = []; - const tableBlot = Quill.find(cell).table(); - const colgroup = tableBlot.colgroup(); + 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; 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 index 663053bdab..f4582c8edc 100644 --- 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 @@ -1,29 +1,40 @@ +import type { LinkedList } from "parchment"; import Quill from "quill"; import Delta from "quill-delta"; +import cellIcon from "../assets/icon/cell.svg"; +import columnIcon from "../assets/icon/column.svg"; +import copyIcon from "../assets/icon/copy.svg"; +import deleteIcon from "../assets/icon/delete.svg"; +import downIcon from "../assets/icon/down.svg"; +import mergeIcon from "../assets/icon/merge.svg"; +import rowIcon from "../assets/icon/row.svg"; +import tableIcon from "../assets/icon/table.svg"; +import wrapIcon from "../assets/icon/wrap.svg"; +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, - getCorrectBounds, getComputeBounds, getComputeSelectedCols, getComputeSelectedTds, - setElementProperty, + getCorrectBounds, getElementStyle, + setElementProperty, updateTableWidth } from "../utils"; -import columnIcon from "../assets/icon/column.svg"; -import rowIcon from "../assets/icon/row.svg"; -import mergeIcon from "../assets/icon/merge.svg"; -import tableIcon from "../assets/icon/table.svg"; -import cellIcon from "../assets/icon/cell.svg"; -import wrapIcon from "../assets/icon/wrap.svg"; -import downIcon from "../assets/icon/down.svg"; -import deleteIcon from "../assets/icon/delete.svg"; -import copyIcon from "../assets/icon/copy.svg"; -import { TableCell, TableCol, TableRow, tableId } from "../formats/table"; import TablePropertiesForm from "./table-properties-form"; -import { CELL_DEFAULT_VALUES, CELL_DEFAULT_WIDTH, CELL_PROPERTIES, DEVIATION, TABLE_PROPERTIES } from "../config"; interface Children { [propName: string]: { @@ -46,7 +57,7 @@ enum Alignment { right = "margin-right" } -function getMenusConfig(useLanguage: _useLanguage, menus?: string[]): MenusDefaults { +function getMenusConfig(useLanguage: UseLanguageHandler, menus?: string[]): MenusDefaults { const DEFAULT: MenusDefaults = { column: { content: useLanguage("col"), @@ -212,15 +223,15 @@ function getMenusConfig(useLanguage: _useLanguage, menus?: string[]): MenusDefau } class TableMenus { - quill: any; - table: HTMLTableElement | null; + quill: Quill; + table: HTMLElement | null; root: HTMLElement; prevList: HTMLUListElement | null; prevTooltip: HTMLDivElement | null; scroll: boolean; - tableBetter: any; - tablePropertiesForm: any; - constructor(quill: any, tableBetter?: any) { + tableBetter: QuillTableBetter; + tablePropertiesForm: TablePropertiesForm; + constructor(quill: Quill, tableBetter?: QuillTableBetter) { this.quill = quill; this.table = null; this.prevList = null; @@ -234,7 +245,7 @@ class TableMenus { async copyTable() { if (!this.table) return; - const tableBlot = Quill.find(this.table); + const tableBlot = Quill.find(this.table) as TableContainer; if (!tableBlot) return; const html = "


" + tableBlot.getCopyTable(); const text = this.tableBetter.cellSelection.getText(html); @@ -307,7 +318,7 @@ class TableMenus { 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).table(); + 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"); @@ -321,7 +332,7 @@ class TableMenus { const map: { [propName: string]: TableRow } = {}; for (const td of selectedTds) { let rowspan = ~~td.getAttribute("rowspan") || 1; - let row = Quill.find(td.parentElement); + let row = Quill.find(td.parentElement) as TableRow; if (rowspan > 1) { while (row && rowspan) { const id = row.children.head.domNode.getAttribute("data-row"); @@ -342,13 +353,13 @@ class TableMenus { if (sum !== selectedTds.length) return; } this.tableBetter.cellSelection.updateSelected("row"); - const tableBlot = Quill.find(selectedTds[0]).table(); + 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); + const tableBlot = Quill.find(this.table) as TableContainer; if (!tableBlot) return; const offset = tableBlot.offset(this.quill.scroll); tableBlot.remove(); @@ -363,13 +374,13 @@ class TableMenus { } getCellsOffset(computeBounds: CorrectBound, bounds: CorrectBound, leftColspan: number, rightColspan: number) { - const tableBlot = Quill.find(this.table); + 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: _Map = new Map(); - const leftMap: _Map = new Map(); - const rightMap: _Map = new Map(); + 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) { @@ -386,7 +397,7 @@ class TableMenus { ); } - getColsOffset(colgroup: TableCol, computeBounds: CorrectBound, bounds: CorrectBound) { + 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); @@ -412,7 +423,7 @@ class TableMenus { return offset; } - getCorrectBounds(table: HTMLTableElement): CorrectBound[] { + getCorrectBounds(table: HTMLElement): CorrectBound[] { const bounds = this.quill.container.getBoundingClientRect(); const tableBounds = getCorrectBounds(table, this.quill.container); return tableBounds.width >= bounds.width @@ -420,15 +431,10 @@ class TableMenus { : [tableBounds, bounds]; } - getCorrectTds( - deleteTds: Element[], - computeBounds: CorrectBound, - leftTd: HTMLTableCellElement, - rightTd: HTMLTableCellElement - ) { - const changeTds = []; + getCorrectTds(deleteTds: Element[], computeBounds: CorrectBound, leftTd: Element, rightTd: Element) { + const changeTds: [Element, number][] = []; const delTds = []; - const colgroup = Quill.find(leftTd).table().colgroup(); + 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) { @@ -455,7 +461,7 @@ class TableMenus { return { changeTds, delTds }; } - getDiffOffset(map: _Map, colspan?: number) { + getDiffOffset(map: TableCellMap, colspan?: number) { let offset = 0; const tds = this.getTdsFromMap(map); if (tds.length) { @@ -492,7 +498,7 @@ class TableMenus { } getSelectedTdAttrs(td: HTMLElement) { - const cellBlot = Quill.find(td); + const cellBlot = Quill.find(td) as TableCell; const align = getAlign(cellBlot); const attr: Props = align ? { ...getElementStyle(td, CELL_PROPERTIES), "text-align": align } @@ -559,7 +565,7 @@ class TableMenus { return align || "center"; } - getTdsFromMap(map: _Map) { + getTdsFromMap(map: TableCellMap) { return Object.values(Object.fromEntries(map)).reduce( (tds: HTMLTableCellElement[], item: HTMLTableCellElement[]) => { return tds.length > item.length ? tds : item; @@ -595,7 +601,7 @@ class TableMenus { insertColumn(td: HTMLTableColElement, offset: number) { const { left, right, width } = td.getBoundingClientRect(); - const tdBlot = Quill.find(td); + const tdBlot = Quill.find(td) as TableCell; const tableBlot = tdBlot.table(); const isLast = td.parentElement.lastChild.isEqualNode(td); const position = offset > 0 ? right : left; @@ -604,7 +610,7 @@ class TableMenus { } insertParagraph(offset: number) { - const blot = Quill.find(this.table); + 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"); @@ -615,7 +621,7 @@ class TableMenus { } insertRow(td: HTMLTableColElement, offset: number) { - const tdBlot = Quill.find(td); + const tdBlot = Quill.find(td) as TableCell; const index = tdBlot.rowOffset(); const tableBlot = tdBlot.table(); if (offset > 0) { @@ -630,11 +636,11 @@ class TableMenus { mergeCells() { const { selectedTds } = this.tableBetter.cellSelection; const { computeBounds, leftTd } = this.getSelectedTdsInfo(); - const leftTdBlot = Quill.find(leftTd); + 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; + 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); @@ -658,7 +664,7 @@ class TableMenus { let offset = 0; for (const td of selectedTds) { if (leftTd.isEqualNode(td)) continue; - const blot: TableCell = Quill.find(td); + const blot = Quill.find(td) as TableCell; blot.moveChildren(leftTdBlot); blot.remove(); if (!blot.parent?.children?.length) offset++; @@ -669,16 +675,18 @@ class TableMenus { 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: _Map) { + 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]); @@ -694,7 +702,7 @@ class TableMenus { splitCell() { const { selectedTds } = this.tableBetter.cellSelection; const { leftTd } = this.getSelectedTdsInfo(); - const leftTdBlot = Quill.find(leftTd); + const leftTdBlot = Quill.find(leftTd) as TableCell; const head = leftTdBlot.children.head; for (const td of selectedTds) { const colspan = ~~td.getAttribute("colspan") || 1; @@ -702,7 +710,7 @@ class TableMenus { if (colspan === 1 && rowspan === 1) continue; const columnCells: [TableRow, string, TableCell | null][] = []; const { width, right } = td.getBoundingClientRect(); - const blot = Quill.find(td); + const blot = Quill.find(td) as TableCell; const tableBlot = blot.table(); const nextBlot = blot.next; const rowBlot = blot.row(); @@ -758,7 +766,7 @@ class TableMenus { this.prevTooltip = tooltip; } - updateMenus(table: HTMLTableElement = this.table) { + updateMenus(table: HTMLElement = this.table) { if (!table) return; requestAnimationFrame(() => { this.root.classList.remove("ql-table-triangle-none"); @@ -766,6 +774,7 @@ class TableMenus { 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; @@ -799,7 +808,7 @@ class TableMenus { this.scroll = scroll; } - updateTable(table: HTMLTableElement) { + updateTable(table: HTMLElement) { this.table = table; } } 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 index 3858238c87..7dbbb477e6 100644 --- 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 @@ -1,10 +1,22 @@ +import iro from "@jaames/iro"; import Quill from "quill"; -import eraseIcon from "../assets/icon/erase.svg"; +import closeIcon from "../assets/icon/close.svg"; import downIcon from "../assets/icon/down.svg"; +import eraseIcon from "../assets/icon/erase.svg"; import paletteIcon from "../assets/icon/palette.svg"; import saveIcon from "../assets/icon/save.svg"; -import closeIcon from "../assets/icon/close.svg"; import { getProperties } from "../config"; +import { ListContainer } from "../formats/list"; +import type { + Props, + TableCell, + TableCellBlock, + TableContainer, + TableHeader, + TableList, + TableMenus, + UseLanguageHandler +} from "../types"; import { addDimensionsUnit, createTooltip, @@ -12,13 +24,9 @@ import { getComputeSelectedCols, isDimensions, isValidColor, - setElementProperty, - setElementAttribute + setElementAttribute, + setElementProperty } from "../utils"; -import { TableCellBlock, TableCell } from "../formats/table"; -import TableList, { ListContainer } from "../formats/list"; -import TableHeader from "../formats/header"; -import iro from "@jaames/iro"; interface Child { category: string; @@ -77,13 +85,13 @@ const COLOR_LIST: ColorList[] = [ ]; class TablePropertiesForm { - tableMenus: any; + tableMenus: TableMenus; options: Options; attrs: Props; borderForm: HTMLElement[]; saveButton: HTMLButtonElement; form: HTMLDivElement; - constructor(tableMenus: any, options?: Options) { + constructor(tableMenus: TableMenus, options?: Options) { this.tableMenus = tableMenus; this.options = options; this.attrs = { ...options.attribute }; @@ -314,7 +322,7 @@ class TablePropertiesForm { return container; } - createPalette(propertyName: string, useLanguage: _useLanguage, parent: HTMLElement) { + createPalette(propertyName: string, useLanguage: UseLanguageHandler, parent: HTMLElement) { const container = document.createElement("div"); const palette = document.createElement("div"); const wrap = document.createElement("div"); @@ -431,7 +439,7 @@ class TablePropertiesForm { return container; } - getCellStyle(td: HTMLElement, attrs: Props) { + getCellStyle(td: Element, attrs: Props) { const style = (td.getAttribute("style") || "") .split(";") .filter((value: string) => value.trim()) @@ -522,7 +530,7 @@ class TablePropertiesForm { saveCellAction() { const { selectedTds } = this.tableMenus.tableBetter.cellSelection; const { quill, table } = this.tableMenus; - const colgroup = Quill.find(table).colgroup(); + const colgroup = (Quill.find(table) as TableContainer).colgroup(); const attrs = this.getDiffProperties(); const width = parseFloat(attrs["width"]); const align = attrs["text-align"]; @@ -537,7 +545,7 @@ class TablePropertiesForm { } } for (const td of selectedTds) { - const tdBlot = Quill.find(td); + const tdBlot = Quill.find(td) as TableCell; const blotName = tdBlot.statics.blotName; const formats = tdBlot.formats()[blotName]; const style = this.getCellStyle(td, attrs); @@ -553,7 +561,7 @@ class TablePropertiesForm { } }); } - const parent: TableCell = tdBlot.replaceWith(blotName, { ...formats, style }); + const parent = tdBlot.replaceWith(blotName, { ...formats, style }) as TableCell; newSelectedTds.push(parent.domNode); } this.tableMenus.tableBetter.cellSelection.setSelectedTds(newSelectedTds); @@ -561,7 +569,7 @@ class TablePropertiesForm { saveTableAction() { const { table, tableBetter } = this.tableMenus; - const temporary = Quill.find(table).temporary()?.domNode; + const temporary = (Quill.find(table) as TableContainer).temporary()?.domNode; const td = table.querySelector("td"); const attrs = this.getDiffProperties(); const align = attrs["align"]; 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 index 7a6406bbd3..ca70c89001 100644 --- 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 @@ -1,8 +1,11 @@ -import Quill from "quill"; +import type { InlineBlot } from "parchment"; +import QuillInline from "quill/blots/inline"; +import icons from "quill/ui/icons"; import tableIcon from "../assets/icon/table.svg"; +import type { InsertTableHandler } from "../types"; -const Inline = Quill.import("blots/inline"); -const icons = Quill.import("ui/icons"); +const Inline = QuillInline as typeof InlineBlot; +// @ts-expect-error icons["table-better"] = tableIcon; const SUM = 10; @@ -66,7 +69,7 @@ class TableSelect { return [row, column]; } - handleClick(e: MouseEvent, insertTable: _insertTable) { + handleClick(e: MouseEvent, insertTable: InsertTableHandler) { this.toggle(this.root); const span = (e.target as Element).closest("span[row]"); if (!span) { @@ -94,7 +97,7 @@ class TableSelect { element && element.classList.add("ql-hidden"); } - insertTable(child: Element, insertTable: _insertTable) { + insertTable(child: Element, insertTable: InsertTableHandler) { const [row, column] = this.getSelectAttrs(child); insertTable(row, column); this.hide(this.root); @@ -120,4 +123,4 @@ class TableSelect { } } -export { TableSelect, ToolbarTable as default }; +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 index 3a00e9186d..c1552841e6 100644 --- 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 @@ -1,7 +1,8 @@ -import Delta from "quill-delta"; import merge from "lodash.merge"; -import { filterWordStyle } from "./"; +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"]; 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 index ad9a515ecd..c31550f69e 100644 --- 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 @@ -1,4 +1,5 @@ import Quill from "quill"; +import type { CorrectBound, Props, TableCellChildren, TableContainer } from "../types"; import { TableCell, TableCellBlock, TableCol } from "../formats/table"; import TableList, { ListContainer } from "../formats/list"; import TableHeader from "../formats/header"; @@ -50,7 +51,7 @@ function getAlign(cellBlot: TableCell) { const blocks = cellBlot.descendants(TableCellBlock); const lists = cellBlot.descendants(TableList); const headers = cellBlot.descendants(TableHeader); - function getChildAlign(child: AllowedChildren): string { + function getChildAlign(child: TableCellChildren): string { for (const name of child.domNode.classList) { if (/ql-align-/.test(name)) { return name.split("ql-align-")[1]; @@ -74,8 +75,11 @@ function getAlign(cellBlot: TableCell) { } 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; } @@ -110,7 +114,7 @@ function getComputeBounds(startCorrectBounds: CorrectBound, endCorrectBounds: Co } function getComputeSelectedCols(computeBounds: CorrectBound, table: Element, container: Element) { - const tableParchment = Quill.find(table); + const tableParchment = Quill.find(table) as TableContainer; const cols = tableParchment.descendants(TableCol); let correctLeft = 0; return cols.reduce((selectedCols: Element[], col: TableCol) => { @@ -130,7 +134,7 @@ function getComputeSelectedTds( container: Element, type?: string ): Element[] { - const tableParchment = Quill.find(table); + 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); @@ -190,12 +194,13 @@ function getCorrectBounds(target: Element, container: Element) { }; } -function getCorrectCellBlot(blot: TableCell | AllowedChildren): TableCell | null { +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; @@ -324,7 +329,7 @@ function throttleStrong(cb: Function, delay: number) { } function updateTableWidth(table: HTMLElement, tableBounds: CorrectBound, change: number) { - const tableBlot = Quill.find(table); + const tableBlot = Quill.find(table) as TableContainer; if (!tableBlot) return; const colgroup = tableBlot.colgroup(); const temporary = tableBlot.temporary(); @@ -345,7 +350,6 @@ function updateTableWidth(table: HTMLElement, tableBounds: CorrectBound, change: } } -export type AllowedChildren = TableCellBlock | TableHeader | TableList; export { addDimensionsUnit, convertUnitToInteger, From 6e575041117e285865e93044630cea8ab61dc250 Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Wed, 19 Mar 2025 11:34:03 +0100 Subject: [PATCH 03/28] fix(table-better): add ts no check on external files --- .../rich-text-web/src/components/Editor.tsx | 4 +- .../quill-table-better/formats/header.ts | 1 + .../quill-table-better/formats/list.ts | 11 +-- .../quill-table-better/formats/table.ts | 17 ++-- .../quill-table-better/language/index.ts | 2 + .../quill-table-better/modules/clipboard.ts | 1 + .../quill-table-better/modules/toolbar.ts | 1 + .../quill-table-better/quill-table-better.ts | 1 + .../utils/formats/quill-table-better/types.ts | 3 +- .../quill-table-better/ui/cell-selection.ts | 86 +++++++++++-------- .../quill-table-better/ui/operate-line.ts | 1 + .../quill-table-better/ui/table-menus.ts | 1 + .../ui/table-properties-form.ts | 15 ++-- .../quill-table-better/ui/toolbar-table.ts | 1 + .../utils/clipboard-matchers.ts | 1 + .../formats/quill-table-better/utils/index.ts | 3 +- 16 files changed, 91 insertions(+), 58 deletions(-) diff --git a/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx b/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx index 9ca522d496..24fb2b7185 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx @@ -122,7 +122,9 @@ const Editor = forwardRef((props: EditorProps, ref: MutableRefObject { const name = attr.includes("data") ? attr : `data-${attr}`; if (domNode.hasAttribute(name)) { - formats[attr] = domNode.getAttribute(name); + formats[attr] = domNode.getAttribute(name) ?? ""; } return formats; }, {}); - formats["cellId"] = domNode.getAttribute("data-cell"); + formats["cellId"] = domNode.getAttribute("data-cell") ?? ""; for (const key of DEFAULT_ATTRIBUTE) { if (!formats[key]) formats[key] = "1"; } @@ -69,7 +70,7 @@ class TableList extends List { if (name === "list") { const [formats, cellId] = this.getCellFormats(this.parent); if (!value || value === list) { - this.setReplace(isReplace, formats); + this.setReplace(!!isReplace, formats); return this.replaceWith(TableCellBlock.blotName, cellId); } else if (value !== list) { return this.replaceWith(this.statics.blotName, value); @@ -83,7 +84,7 @@ class TableList extends List { this.wrap(name, { ...formats, cellId }); } else if (name === "header") { const [formats, cellId] = this.getCellFormats(this.parent); - this.setReplace(isReplace, formats); + this.setReplace(!!isReplace, formats); return this.replaceWith("table-header", { cellId, value }); } else if (name === TableCell.blotName) { const listContainer = this.getListContainer(this.parent); @@ -102,7 +103,7 @@ class TableList extends List { getCellFormats(parent: TableCell | TableCellChildren) { const cellBlot = getCorrectCellBlot(parent); - return getCellFormats(cellBlot); + return getCellFormats(cellBlot!); } getCorrectCellFormats(value: Props): [Props, string] { diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts index 3842c14d50..b5383cf86b 100644 --- a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import type { BlockBlot, ContainerBlot, LinkedList } from "parchment"; import Quill from "quill"; import QuillBlock from "quill/blots/block"; @@ -87,11 +88,11 @@ class TableCell extends Container { prev: this | null; checkMerge() { - if (super.checkMerge() && this.next.children.head != null && this.next.children.head.formats) { - const thisHead = this.children.head.formats()[this.children.head.statics.blotName]; - const thisTail = this.children.tail.formats()[this.children.tail.statics.blotName]; + if (super.checkMerge() && this.next?.children.head != null && this.next.children.head.formats) { + const thisHead = this.children.head?.formats()[this.children.head.statics.blotName]; + const thisTail = this.children.tail?.formats()[this.children.tail.statics.blotName]; const nextHead = this.next.children.head.formats()[this.next.children.head.statics.blotName]; - const nextTail = this.next.children.tail.formats()[this.next.children.tail.statics.blotName]; + const nextTail = this.next.children.tail?.formats()[this.next.children.tail.statics.blotName]; const _thisHead = getCellId(thisHead); const _thisTail = getCellId(thisTail); const _nextHead = getCellId(nextHead); @@ -117,7 +118,7 @@ class TableCell extends Container { if (attr === "rowspan" && rowspan) { formats[attr] = `${~~domNode.getAttribute(attr) - rowspan}`; } else { - formats[attr] = filterWordStyle(domNode.getAttribute(attr)); + formats[attr] = filterWordStyle(domNode.getAttribute(attr) ?? ""); } } return formats; @@ -137,7 +138,7 @@ class TableCell extends Container { } static getEmptyRowspan(domNode: Element) { - let nextNode = domNode.parentElement.nextElementSibling; + let nextNode = domNode.parentElement?.nextElementSibling; let rowspan = 0; while (nextNode && nextNode.tagName === "TR" && !nextNode.innerHTML.replace(/\s/g, "")) { rowspan++; @@ -148,13 +149,13 @@ class TableCell extends Container { static hasColgroup(domNode: Element) { while (domNode && domNode.tagName !== "TBODY") { - domNode = domNode.parentElement; + domNode = domNode.parentElement!; } while (domNode) { if (domNode.tagName === "COLGROUP") { return true; } - domNode = domNode.previousElementSibling; + domNode = domNode.previousElementSibling!; } return false; } 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 index 4e052bf371..71ea63f0f9 100644 --- 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 @@ -1,3 +1,5 @@ +// @ts-nocheck +import { Props } from "../types"; import en_US from "./en_US"; import zh_CN from "./zh_CN"; import fr_FR from "./fr_FR"; 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 index c931b252a0..2b255ed13a 100644 --- 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 @@ -10,6 +10,7 @@ const Clipboard = QuillClipboard as typeof Module; const debug = logger("quill:clipboard"); class TableClipboard extends Clipboard { + // @ts-ignore convert: ( { html, 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 index 94d4e79ce9..ffb159d953 100644 --- 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 @@ -1,3 +1,4 @@ +// @ts-nocheck import merge from "lodash.merge"; import type { ContainerBlot } from "parchment"; import { EmbedBlot } from "parchment"; 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 index 8e67f6cedd..5b37f8b801 100644 --- 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 @@ -1,3 +1,4 @@ +// @ts-nocheck import type { EmitterSource, Range } from "quill"; import Quill from "quill"; import Delta from "quill-delta"; 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 index 07b1d9c554..715219c1b6 100644 --- 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 @@ -1,7 +1,7 @@ import Quill from "quill"; import TableHeader from "./formats/header"; import TableList, { ListContainer } from "./formats/list"; -import { TableCell, TableCellBlock, TableColgroup, TableContainer, TableRow } from "./formats/table"; +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"; @@ -73,6 +73,7 @@ export type { Context, ListContainer, QuillTableBetter, + TableBody, TableCell, TableCellBlock, TableColgroup, 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 index 7851b1410d..b715e2375d 100644 --- 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 @@ -1,11 +1,19 @@ +// @ts-nocheck +import { BlockBlot, ContainerBlot, EmbedBlot } from "parchment"; import Quill from "quill"; -import type { Op } from "quill-delta"; +import type { AttributeMap, Op } from "quill-delta"; import Delta from "quill-delta"; -import Block, { BlockEmbed } from "quill/blots/block"; -import Container from "quill/blots/container"; import { DEVIATION } from "../config"; -import { TableCell, TableCellBlock, TableContainer, TableRow } from "../formats/table"; -import type { AllowedChildren } from "../utils"; +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"; @@ -28,20 +36,19 @@ const WHITE_LIST = [ // Only supports formatting for a single cell. const SINGLE_WHITE_LIST = ["link", "image"]; -// @ts-ignore -function isLine(blot: unknown): blot is Block | BlockEmbed { - return blot instanceof Block || blot instanceof BlockEmbed; +function isLine(blot: unknown): blot is BlockBlot | EmbedBlot { + return blot instanceof BlockBlot || blot instanceof EmbedBlot; } class CellSelection { - quill: any; + quill: Quill; selectedTds: Element[]; startTd: Element; endTd: Element; disabledList: Array; singleList: Array; - tableBetter: any; - constructor(quill: any, tableBetter: any) { + tableBetter: QuillTableBetter; + constructor(quill: Quill, tableBetter: QuillTableBetter) { this.quill = quill; this.selectedTds = []; this.startTd = null; @@ -79,7 +86,7 @@ class CellSelection { this.endTd = null; } - exitTableFocus(block: AllowedChildren, up: boolean) { + exitTableFocus(block: TableCellChildren, up: boolean) { const cell = getCorrectCellBlot(block); const table = cell.table(); const offset = up ? -1 : table.length(); @@ -105,7 +112,7 @@ class CellSelection { } getCopyData() { - const tableBlot = Quill.find(this.selectedTds[0]).table(); + 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(); @@ -145,9 +152,10 @@ class CellSelection { getCorrectRow(td: Element, key: string) { const offset = key === "next" ? 0 : -1; let rowspan = (~~td.getAttribute("rowspan") || 1) + offset || 1; - const cell: TableCell = Quill.find(td); + const cell = Quill.find(td) as TableCell; let row = cell.parent; while (row && rowspan) { + // @ts-expect-error row = row[key]; rowspan--; } @@ -156,7 +164,7 @@ class CellSelection { getCorrectValue(format: string, value: boolean | string) { for (const td of this.selectedTds) { - const blot = Quill.find(td); + const blot = Quill.find(td) as TableCell; const html = blot.html() || td.outerHTML; const delta = this.quill.clipboard.convert({ html, @@ -172,7 +180,7 @@ class CellSelection { return !value; } - getListCorrectValue(format: string, value: boolean | string, formats: any = {}) { + getListCorrectValue(format: string, value: boolean | string, formats: AttributeMap = {}) { if (format !== "list") return value; if (value === "check") { if (formats[format] === "checked" || formats[format] === "unchecked") { @@ -203,7 +211,7 @@ class CellSelection { }; } - getPasteInfo(td: Element, copyColumns: number, rowspan: number): any { + getPasteInfo(td: Element, copyColumns: number, rowspan: number) { let clospan = 0; let cloTd = null; let rowTd = null; @@ -341,6 +349,7 @@ class CellSelection { initWhiteList() { const toolbar = this.quill.getModule("toolbar"); + // @ts-expect-error Array.from(toolbar.container.querySelectorAll("button, select")).forEach(input => { // @ts-ignore this.attach(input); @@ -348,7 +357,7 @@ class CellSelection { } insertColumnCell(table: TableContainer, offset: number) { - const tbody = table.tbody(); + const tbody = table.tbody() as TableBody; if (!tbody) return; tbody.children.forEach((row: TableRow) => { const id = row.children.tail.domNode.getAttribute("data-row"); @@ -359,7 +368,7 @@ class CellSelection { } insertRow(table: TableContainer, offset: number, td: Element) { - const index = Quill.find(td).rowOffset(); + const index = (Quill.find(td) as TableCell).rowOffset(); while (offset--) { table.insertRow(index + 1, 1); } @@ -381,11 +390,10 @@ class CellSelection { } lines(blot: TableCell) { - const getLines = (blot: TableCell) => { - // @ts-ignore - let lines: (Block | BlockEmbed)[] = []; - blot.children.forEach((child: any) => { - if (child instanceof Container) { + 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); @@ -401,6 +409,7 @@ class CellSelection { 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))) { @@ -420,6 +429,7 @@ class CellSelection { 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); @@ -427,7 +437,7 @@ class CellSelection { return; } const td = up ? this.startTd : this.endTd; - const cell = Quill.find(td); + const cell = Quill.find(td) as TableCell; const targetRow = cell.parent[_key]; const { left: _left, right: _right } = td.getBoundingClientRect(); if (targetRow) { @@ -449,11 +459,13 @@ class CellSelection { 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); } } @@ -478,7 +490,7 @@ class CellSelection { container.innerHTML = html; const copyRows = Array.from(container.querySelectorAll("tr")); if (!copyRows.length) return; - const cell = Quill.find(this.startTd); + const cell = Quill.find(this.startTd) as TableCell; const row = cell.row(); const table = cell.table(); this.quill.history.cutoff(); @@ -492,11 +504,11 @@ class CellSelection { 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: HTMLTableCellElement[][], row: HTMLTableRowElement) => { + const copyTds = copyRows.reduce((copyTds: HTMLElement[][], row: HTMLTableRowElement) => { copyTds.push(Array.from(row.querySelectorAll("td"))); return copyTds; }, []); - const selectedTds: HTMLTableCellElement[] = []; + const selectedTds: HTMLElement[] = []; while (copyTds.length) { const copyTs = copyTds.shift(); const pasteTs = pasteTds.shift(); @@ -507,7 +519,7 @@ class CellSelection { const pasteTd = pasteTs.shift(); if (!pasteTd) { const id = prevPasteTd.getAttribute("data-row"); - const ref = Quill.find(prevPasteTd); + const ref = Quill.find(prevPasteTd) as TableCell; cell = table.insertColumnCell(ref.parent, id, ref.next); cell = this.pasteSelectedTd(cell.domNode, copyTd); prevPasteTd = cell.domNode; @@ -532,11 +544,11 @@ class CellSelection { const id = selectedTd.getAttribute("data-row"); const copyFormats = TableCell.formats(copyTd); Object.assign(copyFormats, { "data-row": id }); - const cell = Quill.find(selectedTd); - const _cell = cell.replaceWith(cell.statics.blotName, copyFormats); + 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); + 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 }); @@ -556,8 +568,8 @@ class CellSelection { } removeSelectedTdContent(td: Element) { - const tdBlot = Quill.find(td); - let head = tdBlot.children.head; + 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); @@ -607,7 +619,7 @@ class CellSelection { } setSelected(target: Element, force: boolean = true) { - const cell = Quill.find(target); + const cell = Quill.find(target) as TableCell; this.clearSelected(); this.startTd = target; this.endTd = target; @@ -630,9 +642,11 @@ class CellSelection { 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); + 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 { 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 index 7db00c90be..b6b0a5cd5a 100644 --- 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 @@ -1,3 +1,4 @@ +// @ts-nocheck import Quill from "quill"; import type { QuillTableBetter, TableCell, TableColgroup } from "../types"; import { setElementProperty, setElementAttribute, updateTableWidth } from "../utils"; 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 index f4582c8edc..26a3979ede 100644 --- 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 @@ -1,3 +1,4 @@ +// @ts-nocheck import type { LinkedList } from "parchment"; import Quill from "quill"; import Delta from "quill-delta"; 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 index 7dbbb477e6..067c07566e 100644 --- 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 @@ -1,3 +1,4 @@ +// @ts-nocheck import iro from "@jaames/iro"; import Quill from "quill"; import closeIcon from "../assets/icon/close.svg"; @@ -89,9 +90,9 @@ class TablePropertiesForm { options: Options; attrs: Props; borderForm: HTMLElement[]; - saveButton: HTMLButtonElement; + saveButton: HTMLButtonElement | null; form: HTMLDivElement; - constructor(tableMenus: TableMenus, options?: Options) { + constructor(tableMenus: TableMenus, options: Options) { this.tableMenus = tableMenus; this.options = options; this.attrs = { ...options.attribute }; @@ -192,8 +193,10 @@ class TablePropertiesForm { container.appendChild(fragment); container.addEventListener("click", e => { const target = e.target as HTMLLIElement; - const value = (target.tagName === "DIV" ? target.parentElement : target).getAttribute("data-color"); - this.setAttribute(propertyName, value, container); + const correctTarget = + target.tagName === "DIV" && target.parentElement !== null ? target.parentElement : target; + const value = correctTarget.getAttribute("data-color"); + this.setAttribute(propertyName, value ?? "", container); this.updateInputStatus(container, false, true); }); return container; @@ -214,8 +217,8 @@ class TablePropertiesForm { colorButton.addEventListener("click", () => { this.toggleHidden(select); const colorContainer = this.getColorClosest(container); - const input: HTMLInputElement = colorContainer?.querySelector(".property-input"); - this.updateSelectedStatus(select, input?.value, "color"); + const input: HTMLInputElement | undefined | null = colorContainer?.querySelector(".property-input"); + this.updateSelectedStatus(select, input?.value ?? "", "color"); }); container.appendChild(colorButton); container.appendChild(select); 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 index ca70c89001..62f7b87a83 100644 --- 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 @@ -1,3 +1,4 @@ +// @ts-nocheck import type { InlineBlot } from "parchment"; import QuillInline from "quill/blots/inline"; import icons from "quill/ui/icons"; 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 index c1552841e6..eb850f4049 100644 --- 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 @@ -1,3 +1,4 @@ +// @ts-nocheck import merge from "lodash.merge"; import Delta from "quill-delta"; import { TableCell } from "../formats/table"; 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 index c31550f69e..299b64bd31 100644 --- 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 @@ -1,3 +1,4 @@ +// @ts-nocheck import Quill from "quill"; import type { CorrectBound, Props, TableCellChildren, TableContainer } from "../types"; import { TableCell, TableCellBlock, TableCol } from "../formats/table"; @@ -30,7 +31,7 @@ function createTooltip(content: string) { } function debounce(cb: Function, delay: number) { - let timer: NodeJS.Timeout = null; + let timer: NodeJS.Timeout | null = null; return function () { let context = this; let args = arguments; From 874ee0f439eb23350e5710f3311d77809ad6c6a0 Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Wed, 19 Mar 2025 11:36:24 +0100 Subject: [PATCH 04/28] feat(table-better): update how svg files are added to DOM --- .../rich-text-web/src/components/Editor.tsx | 44 ++++++++++--------- .../src/utils/customPluginRegisters.ts | 7 +-- .../quill-table-better/ui/table-menus.ts | 9 ++-- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx b/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx index 24fb2b7185..2bc2a141ff 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx @@ -88,16 +88,23 @@ const Editor = forwardRef((props: EditorProps, ref: MutableRefObject { onTextChangeRef.current?.(...arg); }); diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/customPluginRegisters.ts b/packages/pluggableWidgets/rich-text-web/src/utils/customPluginRegisters.ts index 63cd633f11..dbdb6e78f0 100644 --- a/packages/pluggableWidgets/rich-text-web/src/utils/customPluginRegisters.ts +++ b/packages/pluggableWidgets/rich-text-web/src/utils/customPluginRegisters.ts @@ -36,9 +36,4 @@ Quill.register(Button, true); Quill.register("modules/resize", QuillResize, true); // add empty handler for view code, this format is handled by toolbar's custom config via ViewCodeDialog Quill.register({ "ui/view-code": Empty }); -Quill.register( - { - "modules/table-better": QuillTableBetter - }, - true -); +Quill.register({ "modules/table-better": QuillTableBetter }, true); 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 index 26a3979ede..e72bf7d46c 100644 --- 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 @@ -283,10 +283,13 @@ class TableMenus { createMenu(left: string, right: string, isDropDown: boolean) { const container = document.createElement("div"); const dropDown = document.createElement("span"); + const leftIcon = document.createElement("img"); + leftIcon.setAttribute("src", left); + dropDown.appendChild(leftIcon); if (isDropDown) { - dropDown.innerHTML = left + right; - } else { - dropDown.innerHTML = left; + const rightIcon = document.createElement("img"); + rightIcon.setAttribute("src", right); + dropDown.appendChild(rightIcon); } container.classList.add("ql-table-dropdown"); dropDown.classList.add("ql-table-tooltip-hover"); From 3417dddc49d2db80c9e37976dfb10a65476d7385 Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Wed, 19 Mar 2025 11:41:11 +0100 Subject: [PATCH 05/28] feat(table-better): improve table-better modal positioning with floating-ui --- .../assets/css/quill-table-better.scss | 9 +- .../ui/table-properties-form.ts | 153 +++++++++--------- 2 files changed, 78 insertions(+), 84 deletions(-) diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/css/quill-table-better.scss b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/css/quill-table-better.scss index 78bc44a078..185d65b6c2 100644 --- a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/css/quill-table-better.scss +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/css/quill-table-better.scss @@ -280,11 +280,12 @@ $focused-border: 1px solid $focused-border-color; } } .ql-table-properties-form { - width: 320px; - position: absolute; - left: 50%; - padding-bottom: 8px; background: $color-white; + padding-bottom: 8px; + position: fixed; + top: 0; + left: 0; + width: 320px; z-index: 1; @include boxShadow($color-ccced1); .properties-form-header { 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 index 067c07566e..591875e38d 100644 --- 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 @@ -1,4 +1,4 @@ -// @ts-nocheck +import { computePosition, flip, offset, shift } from "@floating-ui/react"; import iro from "@jaames/iro"; import Quill from "quill"; import closeIcon from "../assets/icon/close.svg"; @@ -53,7 +53,7 @@ interface Properties { } interface Options { - type: string; + type: "table" | "cell"; attribute: Props; } @@ -118,7 +118,9 @@ class TablePropertiesForm { for (const { icon, label } of ACTION_LIST) { const button = document.createElement("button"); const iconContainer = document.createElement("span"); - iconContainer.innerHTML = icon; + const iconImg = document.createElement("img"); + iconImg.setAttribute("src", icon); + iconContainer.appendChild(iconImg); button.appendChild(iconContainer); setElementAttribute(button, { label }); if (showLabel) { @@ -137,9 +139,11 @@ class TablePropertiesForm { const { menus, propertyName } = child; const container = document.createElement("div"); const fragment = document.createDocumentFragment(); - for (const { icon, describe, align } of menus) { + for (const { icon, describe, align } of menus ?? []) { const container = document.createElement("span"); - container.innerHTML = icon; + const iconImg = document.createElement("img"); + iconImg.setAttribute("src", icon); + container.appendChild(iconImg); container.setAttribute("data-align", align); container.classList.add("ql-table-tooltip-hover"); if (this.options.attribute[propertyName] === align) { @@ -152,10 +156,10 @@ class TablePropertiesForm { container.classList.add("ql-table-check-container"); container.appendChild(fragment); container.addEventListener("click", e => { - const target: HTMLSpanElement = (e.target as HTMLElement).closest("span.ql-table-tooltip-hover"); - const value = target.getAttribute("data-align"); - this.switchButton(container, target); - this.setAttribute(propertyName, value); + 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; } @@ -227,9 +231,9 @@ class TablePropertiesForm { createColorPickerIcon(svg: string, text: string, listener: EventListener) { const container = document.createElement("div"); - const icon = document.createElement("span"); + const icon = document.createElement("img"); const button = document.createElement("button"); - icon.innerHTML = svg; + icon.setAttribute("src", svg); button.innerText = text; container.classList.add("erase-container"); container.appendChild(icon); @@ -257,10 +261,10 @@ class TablePropertiesForm { createDropdown(value: string, category?: string) { const container = document.createElement("div"); const dropText = document.createElement("span"); - const dropDown = document.createElement("span"); + const dropDown = document.createElement("img"); switch (category) { case "dropdown": - dropDown.innerHTML = downIcon; + dropDown.setAttribute("src", downIcon); dropDown.classList.add("ql-table-dropdown-icon"); break; case "color": @@ -278,7 +282,7 @@ class TablePropertiesForm { createInput(child: Child) { const { attribute, message, propertyName, value, valid } = child; - const { placeholder = "" } = attribute; + const placeholder = attribute?.placeholder ?? ""; const container = document.createElement("div"); const wrapper = document.createElement("div"); const label = document.createElement("label"); @@ -287,14 +291,14 @@ class TablePropertiesForm { container.classList.add("label-field-view"); wrapper.classList.add("label-field-view-input-wrapper"); label.innerText = placeholder; - setElementAttribute(input, attribute); + setElementAttribute(input, attribute!); input.classList.add("property-input"); - input.value = value; + input.value = value ?? ""; input.addEventListener("input", e => { // debounce const value = (e.target as HTMLInputElement).value; valid && this.switchHidden(status, valid(value)); - this.updateInputStatus(wrapper, valid && !valid(value)); + this.updateInputStatus(wrapper, !valid?.(value)); this.setAttribute(propertyName, value, container); }); status.classList.add("label-field-view-status", "ql-hidden"); @@ -308,7 +312,7 @@ class TablePropertiesForm { createList(child: Child, dropText?: HTMLSpanElement) { const { options, propertyName } = child; - if (!options.length) return null; + if (!options?.length) return null; const container = document.createElement("ul"); for (const option of options) { const list = document.createElement("li"); @@ -318,7 +322,9 @@ class TablePropertiesForm { container.classList.add("ql-table-dropdown-list", "ql-hidden"); container.addEventListener("click", e => { const value = (e.target as HTMLLIElement).innerText; - dropText.innerText = value; + if (dropText) { + dropText.innerText = value; + } this.toggleBorderDisabled(value); this.setAttribute(propertyName, value); }); @@ -391,11 +397,11 @@ class TablePropertiesForm { const { category, value } = child; switch (category) { case "dropdown": - const { dropdown, dropText } = this.createDropdown(value, category); + const { dropdown, dropText } = this.createDropdown(value!, category); const list = this.createList(child, dropText); - dropdown.appendChild(list); + dropdown.appendChild(list!); dropdown.addEventListener("click", () => { - this.toggleHidden(list); + this.toggleHidden(list!); this.updateSelectedStatus(dropdown, dropText.innerText, "dropdown"); }); return dropdown; @@ -421,7 +427,8 @@ class TablePropertiesForm { const header = document.createElement("h2"); const actions = this.createActionBtns((e: MouseEvent) => { const target = (e.target as HTMLElement).closest("button"); - target && this.checkBtnsAction(target.getAttribute("label")); + const label = target?.getAttribute("label") ?? ""; + target && this.checkBtnsAction(label); }, true); header.innerText = title; header.classList.add("properties-form-header"); @@ -463,7 +470,7 @@ class TablePropertiesForm { getComputeBounds(type: string) { if (type === "table") { const { table } = this.tableMenus; - const [tableBounds, containerBounds] = this.tableMenus.getCorrectBounds(table); + const [tableBounds, containerBounds] = this.tableMenus.getCorrectBounds(table!); if (tableBounds.bottom > containerBounds.bottom) { return { ...tableBounds, bottom: containerBounds.height }; } @@ -503,7 +510,7 @@ class TablePropertiesForm { 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 [...list, ...colorPicker]) { + 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)) @@ -533,7 +540,7 @@ class TablePropertiesForm { saveCellAction() { const { selectedTds } = this.tableMenus.tableBetter.cellSelection; const { quill, table } = this.tableMenus; - const colgroup = (Quill.find(table) as TableContainer).colgroup(); + const colgroup = (Quill.find(table!) as TableContainer).colgroup(); const attrs = this.getDiffProperties(); const width = parseFloat(attrs["width"]); const align = attrs["text-align"]; @@ -542,7 +549,7 @@ class TablePropertiesForm { if (colgroup && width) { delete attrs["width"]; const { computeBounds } = this.tableMenus.getSelectedTdsInfo(); - const cols = getComputeSelectedCols(computeBounds, table, quill.container); + const cols = getComputeSelectedCols(computeBounds, table!, quill.container); for (const col of cols) { col.setAttribute("width", `${width}`); } @@ -572,8 +579,8 @@ class TablePropertiesForm { saveTableAction() { const { table, tableBetter } = this.tableMenus; - const temporary = (Quill.find(table) as TableContainer).temporary()?.domNode; - const td = table.querySelector("td"); + const temporary = (Quill.find(table!) as TableContainer).temporary()?.domNode; + const td = table?.querySelector("td"); const attrs = this.getDiffProperties(); const align = attrs["align"]; delete attrs["align"]; @@ -590,14 +597,15 @@ class TablePropertiesForm { default: break; } - setElementProperty(temporary || table, attrs); - tableBetter.cellSelection.setSelected(td); + const element = temporary || table; + setElementProperty(element!, attrs); + tableBetter.cellSelection.setSelected(td!); } setAttribute(propertyName: string, value: string, container?: HTMLElement) { this.attrs[propertyName] = value; - if (propertyName.includes("-color")) { - this.updateSelectColor(this.getColorClosest(container), value); + if (propertyName.includes("-color") && container) { + this.updateSelectColor(this.getColorClosest(container)!, value); } } @@ -609,7 +617,7 @@ class TablePropertiesForm { } setSaveButton(container: HTMLDivElement) { - const saveButton: HTMLButtonElement = container.querySelector('button[label="save"]'); + const saveButton: HTMLButtonElement | null = container.querySelector('button[label="save"]'); this.saveButton = saveButton; } @@ -624,7 +632,7 @@ class TablePropertiesForm { switchButton(container: HTMLDivElement, target: HTMLSpanElement) { const children = container.querySelectorAll("span.ql-table-tooltip-hover"); - for (const child of children) { + for (const child of Array.from(children)) { child.classList.remove("ql-table-btns-checked"); } target.classList.add("ql-table-btns-checked"); @@ -658,73 +666,58 @@ class TablePropertiesForm { } updateInputValue(element: Element, value: string) { - const input: HTMLInputElement = element.querySelector(".property-input"); - input.value = value; + 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"); + const wrapper = closestContainer?.querySelector(".label-field-view-input-wrapper"); if (status) { - wrapper.classList.add("label-field-view-error"); + wrapper?.classList.add("label-field-view-error"); this.setSaveButtonDisabled(true); } else { - wrapper.classList.remove("label-field-view-error"); + 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) { - container.classList.remove("ql-table-triangle-none"); - const { height, width } = container.getBoundingClientRect(); - const containerBounds = this.tableMenus.quill.container.getBoundingClientRect(); - const { top, left, right, bottom } = this.getComputeBounds(type); - const { viewHeight } = this.getViewportSize(); - let correctTop = bottom + 10; - let correctLeft = (left + right - width) >> 1; - if (correctTop + containerBounds.top + height > viewHeight) { - correctTop = top - height - 10; - if (correctTop < 0) { - correctTop = (containerBounds.height - height) >> 1; - container.classList.add("ql-table-triangle-none"); - } else { - container.classList.add("ql-table-triangle-up"); - container.classList.remove("ql-table-triangle-down"); - } - } else { - container.classList.add("ql-table-triangle-down"); - container.classList.remove("ql-table-triangle-up"); - } - if (correctLeft < containerBounds.left) { - correctLeft = 0; - container.classList.add("ql-table-triangle-none"); - } else if (correctLeft + width > containerBounds.right) { - correctLeft = containerBounds.right - width; - container.classList.add("ql-table-triangle-none"); - } - setElementProperty(container, { - left: `${correctLeft}px`, - top: `${correctTop}px` + 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 = element.querySelector(".property-input"); - const colorButton: HTMLElement = element.querySelector(".color-button"); - const colorPickerSelect: HTMLElement = element.querySelector(".color-picker-select"); - const status: HTMLElement = element.querySelector(".label-field-view-status"); + const input: HTMLInputElement | null = element.querySelector(".property-input"); + const colorButton: HTMLElement | null = element.querySelector(".color-button"); + const colorPickerSelect: HTMLElement | null = element.querySelector(".color-picker-select"); + const status: HTMLElement | null = element.querySelector(".label-field-view-status"); if (!value) { - colorButton.classList.add("color-unselected"); + colorButton?.classList.add("color-unselected"); } else { - colorButton.classList.remove("color-unselected"); + colorButton?.classList.remove("color-unselected"); + } + if (input) { + input.value = value; } - input.value = value; - setElementProperty(colorButton, { "background-color": value }); - colorPickerSelect.classList.add("ql-hidden"); - this.switchHidden(status, isValidColor(value)); + setElementProperty(colorButton!, { "background-color": value }); + colorPickerSelect?.classList.add("ql-hidden"); + this.switchHidden(status!, isValidColor(value)); } updateSelectedStatus(container: HTMLDivElement, value: string, type: string) { From 34ec963cd7e763a6e34acaf0c25cef7f2c9586ab Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Tue, 11 Mar 2025 16:53:48 +0100 Subject: [PATCH 06/28] feat(table-better): add table icon on toolbar --- .../src/components/CustomToolbars/constants.ts | 13 ++++++++++++- .../formats/quill-table-better/ui/toolbar-table.ts | 4 ---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/pluggableWidgets/rich-text-web/src/components/CustomToolbars/constants.ts b/packages/pluggableWidgets/rich-text-web/src/components/CustomToolbars/constants.ts index cdcc6e2c8d..19bdc7f3fe 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/CustomToolbars/constants.ts +++ b/packages/pluggableWidgets/rich-text-web/src/components/CustomToolbars/constants.ts @@ -157,6 +157,12 @@ export const TOOLBAR_MAPPING: toolbarMappingType = { component: FullscreenButton, title: "Fullscreen", custom: true + }, + "table-better": { + component: ToolbarButton, + className: "ql-table-better icons icon-Table", + title: "Create Table", + presetValue: 2 } }; @@ -176,7 +182,8 @@ export const TOOLBAR_GROUP: ToolbarGroupType = { header: ["header"], code: ["blockquote", "code", "codeBlock", "viewCode"], remove: ["clean"], - view: ["fullscreen"] + view: ["fullscreen"], + "table-better": ["table-better"] }; export type toolbarContentType = { @@ -232,6 +239,10 @@ export const DEFAULT_TOOLBAR: toolbarContentType[] = [ { presetValue: 2, children: TOOLBAR_GROUP.view + }, + { + presetValue: 2, + children: TOOLBAR_GROUP["table-better"] } ]; 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 index 62f7b87a83..0aa39117c2 100644 --- 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 @@ -1,13 +1,9 @@ // @ts-nocheck import type { InlineBlot } from "parchment"; import QuillInline from "quill/blots/inline"; -import icons from "quill/ui/icons"; -import tableIcon from "../assets/icon/table.svg"; import type { InsertTableHandler } from "../types"; const Inline = QuillInline as typeof InlineBlot; -// @ts-expect-error -icons["table-better"] = tableIcon; const SUM = 10; class ToolbarTable extends Inline {} From 40899abcdd7401d66609fd2472890f607cbffabc Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Fri, 7 Mar 2025 15:56:39 +0100 Subject: [PATCH 07/28] feat(table-better): change iro to coloris colorpicker --- .../rich-text-web/package.json | 1 + .../rich-text-web/src/components/Editor.tsx | 34 +- .../assets/css/quill-table-better.scss | 43 +- .../ui/table-properties-form.ts | 211 +---- pnpm-lock.yaml | 804 +++++++++++------- 5 files changed, 597 insertions(+), 496 deletions(-) diff --git a/packages/pluggableWidgets/rich-text-web/package.json b/packages/pluggableWidgets/rich-text-web/package.json index aaafbf0fe3..209562dbc1 100644 --- a/packages/pluggableWidgets/rich-text-web/package.json +++ b/packages/pluggableWidgets/rich-text-web/package.json @@ -44,6 +44,7 @@ }, "dependencies": { "@floating-ui/react": "^0.26.27", + "@melloware/coloris": "^0.24.0", "classnames": "^2.2.6", "dompurify": "^3.2.4", "katex": "^0.16.11", diff --git a/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx b/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx index 2bc2a141ff..ffb473bbd1 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx @@ -90,7 +90,7 @@ const Editor = forwardRef((props: EditorProps, ref: MutableRefObject + + +   + + +   +   +   + + + +

+ + + + + + +
+
Dit bericht kan informatie bevatten die niet voor u is bestemd. Indien u niet de geadresseerde bent of dit bericht abusievelijk aan u is toegezonden, wordt u verzocht dat aan de afzender te melden en het bericht te verwijderen. De Staat aanvaardt geen aansprakelijkheid voor schade, van welke aard ook, die verband houdt met risico's verbonden aan het elektronisch verzenden van berichten.
+ +
This message may contain information that is not intended for you. If you are not the addressee or if this message was sent to you by mistake, you are requested to inform the sender and delete the message. The State accepts no liability for damage of any kind resulting from the risks inherent in the electronic transmission of messages.
+ +
Ministerie van Infrastructuur en Waterstaat
+
+ `; + + const delta = quill.clipboard.convert({ html }); + quill.updateContents(delta, Quill.sources.USER); + quill.on(Quill.events.TEXT_CHANGE, (...arg) => { onTextChangeRef.current?.(...arg); }); diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/css/quill-table-better.scss b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/css/quill-table-better.scss index 185d65b6c2..73329c7bde 100644 --- a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/css/quill-table-better.scss +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/css/quill-table-better.scss @@ -179,15 +179,16 @@ $focused-border: 1px solid $focused-border-color; &-input-wrapper { position: relative; height: 100%; - & > label { - position: absolute; - left: 0; - top: -50%; - transform: translateY(50%) scale(0.75); - color: #999; - background: $color-white; - display: none; - } + } + &-input-wrapper > label, + label { + background: $color-white; + color: #999; + display: none; + position: absolute; + left: 0; + top: -8px; + transform: scale(0.75); } &-status { @extend .ql-table-tooltip-error; @@ -373,10 +374,26 @@ $focused-border: 1px solid $focused-border-color; display: flex; .label-field-view-color { flex: 1; - .property-input { - @extend .ql-table-input; - border: 1px solid transparent; - height: 100%; + .clr-field { + width: 100%; + &, + & .property-input { + height: 100%; + } + .property-input { + @extend .ql-table-input; + border: 1px solid transparent; + color: fieldtext; + min-width: 110px; + } + button { + height: 24px; + width: 24px; + right: 3px; + } + } + label { + display: block; } } .color-picker { 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 index 591875e38d..b5c3728119 100644 --- 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 @@ -1,30 +1,19 @@ import { computePosition, flip, offset, shift } from "@floating-ui/react"; -import iro from "@jaames/iro"; +import "@melloware/coloris/dist/coloris.css"; +import Coloris from "@melloware/coloris"; import Quill from "quill"; import closeIcon from "../assets/icon/close.svg"; import downIcon from "../assets/icon/down.svg"; -import eraseIcon from "../assets/icon/erase.svg"; -import paletteIcon from "../assets/icon/palette.svg"; import saveIcon from "../assets/icon/save.svg"; import { getProperties } from "../config"; import { ListContainer } from "../formats/list"; -import type { - Props, - TableCell, - TableCellBlock, - TableContainer, - TableHeader, - TableList, - TableMenus, - UseLanguageHandler -} from "../types"; +import type { Props, TableCell, TableCellBlock, TableContainer, TableHeader, TableList, TableMenus } from "../types"; import { addDimensionsUnit, createTooltip, getClosestElement, getComputeSelectedCols, isDimensions, - isValidColor, setElementAttribute, setElementProperty } from "../utils"; @@ -168,94 +157,44 @@ class TablePropertiesForm { const container = document.createElement("div"); container.classList.add("ql-table-color-container"); const input = this.createColorInput(child); - const colorPicker = this.createColorPicker(child); + this.createColorPicker(child, input.querySelector("input")); container.appendChild(input); - container.appendChild(colorPicker); return container; } - createColorInput(child: Child) { - const container = this.createInput(child); - container.classList.add("label-field-view-color"); - return container; - } + createColorInput(child: Child): HTMLDivElement { + const { attribute, value } = child; + const placeholder = attribute?.placeholder ?? ""; + const container = document.createElement("div"); + container.classList.add("label-field-view", "label-field-view-color"); + const label = document.createElement("label"); + label.innerText = placeholder; + const input = document.createElement("input"); + setElementAttribute(input, attribute!); + input.classList.add("property-input"); + input.value = value ?? ""; - createColorList(propertyName: string) { - const useLanguage = this.getUseLanguage(); - const container = document.createElement("ul"); - const fragment = document.createDocumentFragment(); - container.classList.add("color-list"); - for (const { value, describe } of COLOR_LIST) { - const li = document.createElement("li"); - const tooltip = createTooltip(useLanguage(describe)); - li.setAttribute("data-color", value); - li.classList.add("ql-table-tooltip-hover"); - setElementProperty(li, { "background-color": value }); - li.appendChild(tooltip); - fragment.appendChild(li); - } - container.appendChild(fragment); - container.addEventListener("click", e => { - const target = e.target as HTMLLIElement; - const correctTarget = - target.tagName === "DIV" && target.parentElement !== null ? target.parentElement : target; - const value = correctTarget.getAttribute("data-color"); - this.setAttribute(propertyName, value ?? "", container); - this.updateInputStatus(container, false, true); - }); + container.appendChild(input); + container.appendChild(label); return container; } - createColorPicker(child: Child) { - const { propertyName, value } = child; - const container = document.createElement("span"); - const colorButton = document.createElement("span"); - container.classList.add("color-picker"); - colorButton.classList.add("color-button"); - if (value) { - setElementProperty(colorButton, { "background-color": value }); - } else { - colorButton.classList.add("color-unselected"); + 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" + }); } - const select = this.createColorPickerSelect(propertyName); - colorButton.addEventListener("click", () => { - this.toggleHidden(select); - const colorContainer = this.getColorClosest(container); - const input: HTMLInputElement | undefined | null = colorContainer?.querySelector(".property-input"); - this.updateSelectedStatus(select, input?.value ?? "", "color"); - }); - container.appendChild(colorButton); - container.appendChild(select); - return container; - } - - createColorPickerIcon(svg: string, text: string, listener: EventListener) { - const container = document.createElement("div"); - const icon = document.createElement("img"); - const button = document.createElement("button"); - icon.setAttribute("src", svg); - button.innerText = text; - container.classList.add("erase-container"); - container.appendChild(icon); - container.appendChild(button); - container.addEventListener("click", listener); - return container; - } - - createColorPickerSelect(propertyName: string) { - const useLanguage = this.getUseLanguage(); - const container = document.createElement("div"); - const remove = this.createColorPickerIcon(eraseIcon, useLanguage("removeColor"), () => { - this.setAttribute(propertyName, "", container); - this.updateInputStatus(container, false, true); - }); - const list = this.createColorList(propertyName); - const palette = this.createPalette(propertyName, useLanguage, container); - container.classList.add("color-picker-select", "ql-hidden"); - container.appendChild(remove); - container.appendChild(list); - container.appendChild(palette); - return container; } createDropdown(value: string, category?: string) { @@ -280,8 +219,8 @@ class TablePropertiesForm { return { dropdown: container, dropText }; } - createInput(child: Child) { - const { attribute, message, propertyName, value, valid } = child; + createInput(child: Child): HTMLDivElement { + const { attribute, message, propertyName, valid, value } = child; const placeholder = attribute?.placeholder ?? ""; const container = document.createElement("div"); const wrapper = document.createElement("div"); @@ -295,7 +234,6 @@ class TablePropertiesForm { input.classList.add("property-input"); input.value = value ?? ""; input.addEventListener("input", e => { - // debounce const value = (e.target as HTMLInputElement).value; valid && this.switchHidden(status, valid(value)); this.updateInputStatus(wrapper, !valid?.(value)); @@ -331,46 +269,6 @@ class TablePropertiesForm { return container; } - createPalette(propertyName: string, useLanguage: UseLanguageHandler, parent: HTMLElement) { - const container = document.createElement("div"); - const palette = document.createElement("div"); - const wrap = document.createElement("div"); - const iroContainer = document.createElement("div"); - // @ts-ignore - const colorPicker = new iro.ColorPicker(iroContainer, { - width: 110, - layout: [ - { - component: iro.ui.Wheel, - options: {} - } - ] - }); - const eraseContainer = this.createColorPickerIcon(paletteIcon, useLanguage("colorPicker"), () => - this.toggleHidden(palette) - ); - const btns = this.createActionBtns((e: MouseEvent) => { - const target = (e.target as HTMLElement).closest("button"); - if (!target) return; - const label = target.getAttribute("label"); - if (label === "save") { - this.setAttribute(propertyName, colorPicker.color.hexString, parent); - this.updateInputStatus(container, false, true); - } - palette.classList.add("ql-hidden"); - parent.classList.add("ql-hidden"); - }, false); - palette.classList.add("color-picker-palette", "ql-hidden"); - wrap.classList.add("color-picker-wrap"); - iroContainer.classList.add("iro-container"); - wrap.appendChild(iroContainer); - wrap.appendChild(btns); - palette.appendChild(wrap); - container.appendChild(eraseContainer); - container.appendChild(palette); - return container; - } - createProperty(property: Properties) { const { content, children } = property; const useLanguage = this.getUseLanguage(); @@ -467,20 +365,6 @@ class TablePropertiesForm { return getClosestElement(container, ".ql-table-color-container"); } - getComputeBounds(type: string) { - if (type === "table") { - const { table } = this.tableMenus; - const [tableBounds, containerBounds] = this.tableMenus.getCorrectBounds(table!); - if (tableBounds.bottom > containerBounds.bottom) { - return { ...tableBounds, bottom: containerBounds.height }; - } - return tableBounds; - } else { - const { computeBounds } = this.tableMenus.getSelectedTdsInfo(); - return computeBounds; - } - } - getDiffProperties() { const change = this.attrs; const old = this.options.attribute; @@ -498,13 +382,6 @@ class TablePropertiesForm { return useLanguage; } - getViewportSize() { - return { - viewWidth: document.documentElement.clientWidth, - viewHeight: document.documentElement.clientHeight - }; - } - hiddenSelectList(element: HTMLElement) { const listClassName = ".ql-table-dropdown-properties"; const colorClassName = ".color-picker"; @@ -540,7 +417,7 @@ class TablePropertiesForm { saveCellAction() { const { selectedTds } = this.tableMenus.tableBetter.cellSelection; const { quill, table } = this.tableMenus; - const colgroup = (Quill.find(table!) as TableContainer).colgroup(); + const colgroup = (Quill.find(table as Node) as TableContainer).colgroup(); const attrs = this.getDiffProperties(); const width = parseFloat(attrs["width"]); const align = attrs["text-align"]; @@ -549,7 +426,7 @@ class TablePropertiesForm { if (colgroup && width) { delete attrs["width"]; const { computeBounds } = this.tableMenus.getSelectedTdsInfo(); - const cols = getComputeSelectedCols(computeBounds, table!, quill.container); + const cols = getComputeSelectedCols(computeBounds, table as Element, quill.container); for (const col of cols) { col.setAttribute("width", `${width}`); } @@ -579,7 +456,7 @@ class TablePropertiesForm { saveTableAction() { const { table, tableBetter } = this.tableMenus; - const temporary = (Quill.find(table!) as TableContainer).temporary()?.domNode; + const temporary = (Quill.find(table as Node) as TableContainer).temporary()?.domNode; const td = table?.querySelector("td"); const attrs = this.getDiffProperties(); const align = attrs["align"]; @@ -599,7 +476,7 @@ class TablePropertiesForm { } const element = temporary || table; setElementProperty(element!, attrs); - tableBetter.cellSelection.setSelected(td!); + tableBetter.cellSelection.setSelected(td as Element); } setAttribute(propertyName: string, value: string, container?: HTMLElement) { @@ -704,20 +581,10 @@ class TablePropertiesForm { updateSelectColor(element: Element, value: string) { const input: HTMLInputElement | null = element.querySelector(".property-input"); - const colorButton: HTMLElement | null = element.querySelector(".color-button"); - const colorPickerSelect: HTMLElement | null = element.querySelector(".color-picker-select"); - const status: HTMLElement | null = element.querySelector(".label-field-view-status"); - if (!value) { - colorButton?.classList.add("color-unselected"); - } else { - colorButton?.classList.remove("color-unselected"); - } + if (input) { input.value = value; } - setElementProperty(colorButton!, { "background-color": value }); - colorPickerSelect?.classList.add("ql-hidden"); - this.switchHidden(status!, isValidColor(value)); } updateSelectedStatus(container: HTMLDivElement, value: string, type: string) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1e4ec2e412..63825b5a1e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -550,7 +550,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -575,7 +575,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -609,7 +609,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -634,7 +634,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -662,7 +662,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -696,7 +696,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -724,7 +724,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -764,7 +764,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -798,7 +798,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -859,7 +859,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -927,7 +927,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -967,7 +967,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1001,7 +1001,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1044,7 +1044,7 @@ importers: devDependencies: '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1081,7 +1081,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1124,7 +1124,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1164,7 +1164,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1209,7 +1209,7 @@ importers: version: 6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9) mobx-react-lite: specifier: 4.0.7 - version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0) + version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0) devDependencies: '@mendix/automation-utils': specifier: workspace:* @@ -1219,7 +1219,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1264,7 +1264,7 @@ importers: version: 6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9) mobx-react-lite: specifier: 4.0.7 - version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0) + version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0) nanoevents: specifier: ^9.0.0 version: 9.0.0 @@ -1277,7 +1277,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1314,7 +1314,7 @@ importers: version: 7.25.9(@babel/core@7.26.10) '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@rollup/plugin-replace': specifier: ^6.0.2 version: 6.0.2(rollup@3.29.5) @@ -1333,7 +1333,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1376,7 +1376,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1409,7 +1409,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1439,7 +1439,7 @@ importers: version: 6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9) mobx-react-lite: specifier: 4.0.7 - version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0) + version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0) react-dropzone: specifier: ^14.2.3 version: 14.2.9(react@18.2.0) @@ -1452,7 +1452,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1494,7 +1494,7 @@ importers: version: 6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9) mobx-react-lite: specifier: 4.0.7 - version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0) + version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0) devDependencies: '@mendix/automation-utils': specifier: workspace:* @@ -1504,7 +1504,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1534,7 +1534,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1562,7 +1562,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1590,7 +1590,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1615,7 +1615,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1643,7 +1643,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1674,7 +1674,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1717,7 +1717,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1760,7 +1760,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1803,7 +1803,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1831,7 +1831,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1862,7 +1862,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1896,7 +1896,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1933,7 +1933,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1970,7 +1970,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -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 @@ -2091,7 +2094,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2128,7 +2131,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2165,7 +2168,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2205,7 +2208,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2233,7 +2236,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2264,7 +2267,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2292,7 +2295,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2323,7 +2326,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2411,40 +2414,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 +2459,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 @@ -3727,10 +3730,6 @@ packages: 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 +3754,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 +4018,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 +4106,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 +4845,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 +4869,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 +4888,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 +4902,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 +4921,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 +4952,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 +4970,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 +4989,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 +5147,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==} @@ -5943,7 +5940,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 +6415,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 +6681,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 +6697,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 +6725,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 +6837,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 +7267,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 +7542,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 +7595,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 +8402,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==} @@ -10537,7 +10506,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==} @@ -10738,8 +10706,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 +11028,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 @@ -13486,11 +13454,6 @@ 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) @@ -13500,14 +13463,6 @@ snapshots: '@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 +13509,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.23.0': {} - '@eslint/js@9.24.0': {} '@eslint/object-schema@2.1.6': {} @@ -14004,6 +13957,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 @@ -14032,7 +13987,7 @@ snapshots: '@types/react-dom': 18.2.14 '@types/react-native': 0.72.8(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)) '@types/testing-library__jest-dom': 5.14.9 - '@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) + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.24.0(jiti@2.4.2))(typescript@5.1.6))(eslint@7.32.0)(typescript@5.8.2) '@typescript-eslint/parser': 5.62.0(eslint@7.32.0)(typescript@5.8.2) ansi-colors: 4.1.1 babel-eslint: 10.1.0(eslint@7.32.0) @@ -14045,7 +14000,7 @@ snapshots: enzyme-to-json: 3.6.2(enzyme@3.11.0) eslint: 7.32.0 eslint-config-prettier: 8.10.0(eslint@7.32.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) + eslint-plugin-jest: 24.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.24.0(jiti@2.4.2))(typescript@5.1.6))(eslint@7.32.0)(typescript@5.8.2))(eslint@7.32.0)(typescript@5.8.2) eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@3.5.3) eslint-plugin-promise: 4.3.1 eslint-plugin-react: 7.28.0(eslint@7.32.0) @@ -14085,7 +14040,7 @@ snapshots: 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-node: 10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.14.0)(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.1.6) typescript: 5.8.2 xml2js: 0.6.2 zip-a-folder: 0.0.12 @@ -14322,48 +14277,154 @@ snapshots: - tslib - utf-8-validate - '@napi-rs/canvas-android-arm64@0.1.68': + '@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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1)': + dependencies: + '@babel/core': 7.26.10 + '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.10) + '@babel/preset-env': 7.26.9(@babel/core@7.26.10) + '@babel/preset-react': 7.26.3(@babel/core@7.26.10) + '@cfaester/enzyme-adapter-react-18': 0.6.0(enzyme@3.11.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@prettier/plugin-xml': 1.2.0 + '@rollup/plugin-alias': 5.1.1(rollup@3.29.5) + '@rollup/plugin-babel': 6.0.4(@babel/core@7.26.10)(@types/babel__core@7.20.3)(rollup@3.29.5) + '@rollup/plugin-commonjs': 28.0.3(rollup@3.29.5) + '@rollup/plugin-image': 3.0.3(rollup@3.29.5) + '@rollup/plugin-json': 6.1.0(rollup@3.29.5) + '@rollup/plugin-node-resolve': 15.3.1(rollup@3.29.5) + '@rollup/plugin-terser': 0.4.4(rollup@3.29.5) + '@rollup/plugin-typescript': 12.1.2(rollup@3.29.5)(tslib@2.8.1)(typescript@5.8.2) + '@rollup/plugin-url': 8.0.2(rollup@3.29.5) + '@rollup/pluginutils': 5.1.4(rollup@3.29.5) + '@testing-library/dom': 8.20.1 + '@testing-library/jest-dom': 5.17.0 + '@testing-library/react': 13.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@testing-library/user-event': 14.5.1(@testing-library/dom@8.20.1) + '@types/react': 18.2.36 + '@types/react-dom': 18.2.14 + '@types/react-native': 0.72.8(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)) + '@types/testing-library__jest-dom': 5.14.9 + '@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) + '@typescript-eslint/parser': 5.62.0(eslint@7.32.0)(typescript@5.8.2) + ansi-colors: 4.1.1 + babel-eslint: 10.1.0(eslint@7.32.0) + babel-jest: 29.7.0(@babel/core@7.26.10) + big.js: 6.2.2 + concurrently: 6.5.1 + core-js: 3.33.2 + dotenv: 8.6.0 + enzyme: 3.11.0 + enzyme-to-json: 3.6.2(enzyme@3.11.0) + eslint: 7.32.0 + eslint-config-prettier: 8.10.0(eslint@7.32.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) + eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@3.5.3) + eslint-plugin-promise: 4.3.1 + eslint-plugin-react: 7.28.0(eslint@7.32.0) + eslint-plugin-react-hooks: 4.6.0(eslint@7.32.0) + fast-glob: 3.3.2 + find-free-port: 2.0.0 + fs-extra: 9.1.0 + 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-environment-jsdom: 29.7.0 + jest-jasmine2: 29.7.0 + jest-junit: 13.2.0 + jest-react-hooks-shallow: 1.5.1 + make-dir: 3.1.0 + mendix: 10.20.60519 + metro-react-native-babel-preset: 0.74.1(@babel/core@7.26.10) + mime: 3.0.0 + node-fetch: 2.7.0 + postcss: 8.4.47 + postcss-import: 14.1.0(postcss@8.4.47) + postcss-url: 10.1.3(postcss@8.4.47) + prettier: 3.5.3 + react-test-renderer: 18.2.0(react@18.2.0) + recursive-copy: 2.0.14 + resolve: 1.22.8 + rollup: 3.29.5 + rollup-plugin-clear: 2.0.7 + 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-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-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 + zip-a-folder: 0.0.12 + transitivePeerDependencies: + - '@jest/transform' + - '@jest/types' + - '@swc/core' + - '@swc/wasm' + - '@types/babel__core' + - '@types/node' + - babel-plugin-macros + - bufferutil + - canvas + - encoding + - esbuild + - node-notifier + - picomatch + - react + - react-dom + - react-native + - supports-color + - tslib + - utf-8-validate + + '@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 +14441,7 @@ snapshots: '@pkgr/core@0.1.2': {} - '@pkgr/core@0.2.0': {} + '@pkgr/core@0.2.4': {} '@playwright/test@1.51.1': dependencies: @@ -14511,6 +14572,17 @@ snapshots: execa: 5.1.1 fast-glob: 3.3.2 + '@react-native-community/cli-config@14.1.0': + dependencies: + '@react-native-community/cli-tools': 14.1.0 + chalk: 4.1.2 + cosmiconfig: 9.0.0 + deepmerge: 4.3.1 + fast-glob: 3.3.2 + joi: 17.13.3 + transitivePeerDependencies: + - typescript + '@react-native-community/cli-config@14.1.0(typescript@5.1.6)': dependencies: '@react-native-community/cli-tools': 14.1.0 @@ -14539,6 +14611,27 @@ snapshots: transitivePeerDependencies: - supports-color + '@react-native-community/cli-doctor@14.1.0': + dependencies: + '@react-native-community/cli-config': 14.1.0 + '@react-native-community/cli-platform-android': 14.1.0 + '@react-native-community/cli-platform-apple': 14.1.0 + '@react-native-community/cli-platform-ios': 14.1.0 + '@react-native-community/cli-tools': 14.1.0 + chalk: 4.1.2 + command-exists: 1.2.9 + deepmerge: 4.3.1 + envinfo: 7.14.0 + execa: 5.1.1 + node-stream-zip: 1.15.0 + ora: 5.4.1 + semver: 7.7.1 + strip-ansi: 5.2.0 + wcwidth: 1.0.1 + yaml: 2.6.0 + transitivePeerDependencies: + - typescript + '@react-native-community/cli-doctor@14.1.0(typescript@5.1.6)': dependencies: '@react-native-community/cli-config': 14.1.0(typescript@5.1.6) @@ -14636,6 +14729,30 @@ snapshots: dependencies: joi: 17.13.3 + '@react-native-community/cli@14.1.0': + dependencies: + '@react-native-community/cli-clean': 14.1.0 + '@react-native-community/cli-config': 14.1.0 + '@react-native-community/cli-debugger-ui': 14.1.0 + '@react-native-community/cli-doctor': 14.1.0 + '@react-native-community/cli-server-api': 14.1.0 + '@react-native-community/cli-tools': 14.1.0 + '@react-native-community/cli-types': 14.1.0 + chalk: 4.1.2 + commander: 9.5.0 + deepmerge: 4.3.1 + execa: 5.1.1 + find-up: 5.0.0 + fs-extra: 8.1.0 + graceful-fs: 4.2.11 + prompts: 2.4.2 + semver: 7.7.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - typescript + - utf-8-validate + '@react-native-community/cli@14.1.0(typescript@5.1.6)': dependencies: '@react-native-community/cli-clean': 14.1.0 @@ -14938,6 +15055,12 @@ snapshots: nullthrows: 1.1.1 react-native: 0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2) + '@react-native/virtualized-lists@0.72.8(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react-native: 0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0) + '@react-native/virtualized-lists@0.75.3(@types/react@18.2.36)(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)': dependencies: invariant: 2.2.4 @@ -14965,6 +15088,15 @@ snapshots: optionalDependencies: '@types/react': 18.2.36 + '@react-native/virtualized-lists@0.75.3(@types/react@18.2.36)(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 18.2.0 + react-native: 0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.36 + '@restart/hooks@0.4.9(react@18.2.0)': dependencies: dequal: 2.0.3 @@ -15473,6 +15605,13 @@ snapshots: transitivePeerDependencies: - react-native + '@types/react-native@0.72.8(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))': + dependencies: + '@react-native/virtualized-lists': 0.72.8(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)) + '@types/react': 18.2.36 + transitivePeerDependencies: + - react-native + '@types/react-plotly.js@2.6.3': dependencies: '@types/plotly.js': 2.12.30 @@ -15553,15 +15692,34 @@ 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@5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.24.0(jiti@2.4.2))(typescript@5.1.6))(eslint@7.32.0)(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) + '@eslint-community/regexpp': 4.11.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) + '@typescript-eslint/utils': 5.62.0(eslint@7.32.0)(typescript@5.8.2) + debug: 4.3.7 + eslint: 7.32.0 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare-lite: 1.4.0 + semver: 7.7.1 + tsutils: 3.21.0(typescript@5.8.2) + optionalDependencies: + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + + '@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.11.1 + '@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 +15753,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 +15780,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 +15797,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 +15814,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 +15858,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 +15887,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 +15927,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)': @@ -16986,6 +17144,13 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 + cosmiconfig@9.0.0: + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + cosmiconfig@9.0.0(typescript@5.1.6): dependencies: env-paths: 2.2.1 @@ -17984,24 +18149,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.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.23.0(jiti@2.4.2) + 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 +18179,34 @@ 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@24.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.24.0(jiti@2.4.2))(typescript@5.1.6))(eslint@7.32.0)(typescript@5.8.2))(eslint@7.32.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/experimental-utils': 4.33.0(eslint@7.32.0)(typescript@5.8.2) + eslint: 7.32.0 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': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.24.0(jiti@2.4.2))(typescript@5.1.6))(eslint@7.32.0)(typescript@5.8.2) + transitivePeerDependencies: + - supports-color + - typescript + + 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.24.0(jiti@2.4.2))(typescript@5.8.2) + eslint: 9.24.0(jiti@2.4.2) + optionalDependencies: + '@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,30 +18229,30 @@ 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: @@ -18097,7 +18272,7 @@ snapshots: semver: 6.3.1 string.prototype.matchall: 4.0.10 - 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 +18280,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 @@ -18191,48 +18366,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 +18971,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 @@ -19090,8 +19223,6 @@ snapshots: ignore@4.0.6: {} - ignore@5.2.4: {} - ignore@5.3.2: {} ignore@7.0.3: {} @@ -19689,7 +19820,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@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) + ts-node: 10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.14.0)(typescript@5.1.6) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -20848,14 +20979,14 @@ snapshots: mkdirp@1.0.4: {} - mobx-react-lite@4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0): + mobx-react-lite@4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0): dependencies: mobx: 6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9) react: 18.2.0 use-sync-external-store: 1.2.0(react@18.2.0) optionalDependencies: react-dom: 18.2.0(react@18.2.0) - react-native: 0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2) + react-native: 0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0) mobx-react-lite@4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: @@ -21306,7 +21437,7 @@ snapshots: pdfjs-dist@5.1.91: optionalDependencies: - '@napi-rs/canvas': 0.1.68 + '@napi-rs/canvas': 0.1.69 peggy@1.2.0: {} @@ -21528,7 +21659,7 @@ snapshots: yaml: 1.10.2 optionalDependencies: 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) + ts-node: 10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.14.0)(typescript@5.1.6) postcss-merge-longhand@5.1.7(postcss@8.4.31): dependencies: @@ -21867,7 +21998,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: @@ -22284,6 +22415,59 @@ snapshots: - typescript - utf-8-validate + react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0): + dependencies: + '@jest/create-cache-key-function': 29.7.0 + '@react-native-community/cli': 14.1.0 + '@react-native-community/cli-platform-android': 14.1.0 + '@react-native-community/cli-platform-ios': 14.1.0 + '@react-native/assets-registry': 0.75.3 + '@react-native/codegen': 0.75.3(@babel/preset-env@7.26.9(@babel/core@7.26.10)) + '@react-native/community-cli-plugin': 0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10)) + '@react-native/gradle-plugin': 0.75.3 + '@react-native/js-polyfills': 0.75.3 + '@react-native/normalize-colors': 0.75.3 + '@react-native/virtualized-lists': 0.75.3(@types/react@18.2.36)(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + base64-js: 1.5.1 + chalk: 4.1.2 + commander: 9.5.0 + event-target-shim: 5.0.1 + flow-enums-runtime: 0.0.6 + glob: 7.2.3 + invariant: 2.2.4 + jest-environment-node: 29.7.0 + jsc-android: 250231.0.0 + memoize-one: 5.2.1 + metro-runtime: 0.80.12 + metro-source-map: 0.80.12 + mkdirp: 0.5.6 + nullthrows: 1.1.1 + pretty-format: 26.6.2 + promise: 8.3.0 + react: 18.2.0 + react-devtools-core: 5.3.2 + react-refresh: 0.14.2 + regenerator-runtime: 0.13.11 + scheduler: 0.24.0-canary-efb381bbf-20230505 + semver: 7.7.1 + stacktrace-parser: 0.1.10 + whatwg-fetch: 3.6.20 + ws: 6.2.3 + yargs: 17.7.2 + optionalDependencies: + '@types/react': 18.2.36 + transitivePeerDependencies: + - '@babel/core' + - '@babel/preset-env' + - bufferutil + - encoding + - supports-color + - typescript + - utf-8-validate + react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.1.6): dependencies: '@jest/create-cache-key-function': 29.7.0 @@ -23409,7 +23593,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 +23717,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 +24112,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 From c20198fec2e760686aff9d6a3010d84243459102 Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Thu, 27 Mar 2025 16:32:52 +0100 Subject: [PATCH 08/28] feat(table-better): add lodash.merge --- .../rich-text-web/package.json | 1 + .../rich-text-web/typings/declare-svg.ts | 4 +- .../rich-text-web/typings/global.d.ts | 2 + pnpm-lock.yaml | 530 +++--------------- 4 files changed, 97 insertions(+), 440 deletions(-) diff --git a/packages/pluggableWidgets/rich-text-web/package.json b/packages/pluggableWidgets/rich-text-web/package.json index 209562dbc1..537f9a9bd8 100644 --- a/packages/pluggableWidgets/rich-text-web/package.json +++ b/packages/pluggableWidgets/rich-text-web/package.json @@ -49,6 +49,7 @@ "dompurify": "^3.2.4", "katex": "^0.16.11", "linkifyjs": "^4.1.3", + "lodash.merge": "^4.6.2", "parchment": "^3.0.0", "quill": "^2.0.2", "quill-resize-module": "^2.0.4" diff --git a/packages/pluggableWidgets/rich-text-web/typings/declare-svg.ts b/packages/pluggableWidgets/rich-text-web/typings/declare-svg.ts index 8d19c68386..e65f2cb5a6 100644 --- a/packages/pluggableWidgets/rich-text-web/typings/declare-svg.ts +++ b/packages/pluggableWidgets/rich-text-web/typings/declare-svg.ts @@ -3,6 +3,4 @@ declare module "*.svg" { export = content; } -declare module 'quill-better-table'; - -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 63825b5a1e..37c6311295 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -550,7 +550,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -575,7 +575,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -609,7 +609,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -634,7 +634,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -662,7 +662,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -696,7 +696,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -724,7 +724,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -764,7 +764,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -798,7 +798,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -859,7 +859,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -927,7 +927,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -967,7 +967,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1001,7 +1001,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1044,7 +1044,7 @@ importers: devDependencies: '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1081,7 +1081,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1124,7 +1124,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1164,7 +1164,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1209,7 +1209,7 @@ importers: version: 6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9) mobx-react-lite: specifier: 4.0.7 - version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0) + version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0) devDependencies: '@mendix/automation-utils': specifier: workspace:* @@ -1219,7 +1219,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1264,7 +1264,7 @@ importers: version: 6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9) mobx-react-lite: specifier: 4.0.7 - version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0) + version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0) nanoevents: specifier: ^9.0.0 version: 9.0.0 @@ -1277,7 +1277,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1314,7 +1314,7 @@ importers: version: 7.25.9(@babel/core@7.26.10) '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@rollup/plugin-replace': specifier: ^6.0.2 version: 6.0.2(rollup@3.29.5) @@ -1333,7 +1333,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1376,7 +1376,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1409,7 +1409,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1439,7 +1439,7 @@ importers: version: 6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9) mobx-react-lite: specifier: 4.0.7 - version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0) + version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0) react-dropzone: specifier: ^14.2.3 version: 14.2.9(react@18.2.0) @@ -1452,7 +1452,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1494,7 +1494,7 @@ importers: version: 6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9) mobx-react-lite: specifier: 4.0.7 - version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0) + version: 4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0) devDependencies: '@mendix/automation-utils': specifier: workspace:* @@ -1504,7 +1504,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1534,7 +1534,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1562,7 +1562,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1590,7 +1590,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1615,7 +1615,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1643,7 +1643,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1674,7 +1674,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1717,7 +1717,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1760,7 +1760,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1803,7 +1803,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1831,7 +1831,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1862,7 +1862,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1896,7 +1896,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1933,7 +1933,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -1970,7 +1970,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2010,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 @@ -2094,7 +2097,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2131,7 +2134,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2168,7 +2171,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2208,7 +2211,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2236,7 +2239,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2267,7 +2270,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2295,7 +2298,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -2326,7 +2329,7 @@ importers: version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': specifier: 10.18.2 - version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) + version: 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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -3722,10 +3725,6 @@ 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} @@ -5328,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'} @@ -5369,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'} @@ -8979,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'} @@ -8998,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'} @@ -10556,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'} @@ -11895,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: @@ -13459,8 +13435,6 @@ snapshots: 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.20.0': @@ -13987,7 +13961,7 @@ snapshots: '@types/react-dom': 18.2.14 '@types/react-native': 0.72.8(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)) '@types/testing-library__jest-dom': 5.14.9 - '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.24.0(jiti@2.4.2))(typescript@5.1.6))(eslint@7.32.0)(typescript@5.8.2) + '@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) '@typescript-eslint/parser': 5.62.0(eslint@7.32.0)(typescript@5.8.2) ansi-colors: 4.1.1 babel-eslint: 10.1.0(eslint@7.32.0) @@ -14000,7 +13974,7 @@ snapshots: enzyme-to-json: 3.6.2(enzyme@3.11.0) eslint: 7.32.0 eslint-config-prettier: 8.10.0(eslint@7.32.0) - eslint-plugin-jest: 24.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.24.0(jiti@2.4.2))(typescript@5.1.6))(eslint@7.32.0)(typescript@5.8.2))(eslint@7.32.0)(typescript@5.8.2) + 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) eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@3.5.3) eslint-plugin-promise: 4.3.1 eslint-plugin-react: 7.28.0(eslint@7.32.0) @@ -14011,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 @@ -14033,14 +14007,14 @@ 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-node: 10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.14.0)(typescript@5.1.6) + 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 zip-a-folder: 0.0.12 @@ -14277,112 +14251,6 @@ snapshots: - tslib - utf-8-validate - '@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.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1)': - dependencies: - '@babel/core': 7.26.10 - '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.10) - '@babel/preset-env': 7.26.9(@babel/core@7.26.10) - '@babel/preset-react': 7.26.3(@babel/core@7.26.10) - '@cfaester/enzyme-adapter-react-18': 0.6.0(enzyme@3.11.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@prettier/plugin-xml': 1.2.0 - '@rollup/plugin-alias': 5.1.1(rollup@3.29.5) - '@rollup/plugin-babel': 6.0.4(@babel/core@7.26.10)(@types/babel__core@7.20.3)(rollup@3.29.5) - '@rollup/plugin-commonjs': 28.0.3(rollup@3.29.5) - '@rollup/plugin-image': 3.0.3(rollup@3.29.5) - '@rollup/plugin-json': 6.1.0(rollup@3.29.5) - '@rollup/plugin-node-resolve': 15.3.1(rollup@3.29.5) - '@rollup/plugin-terser': 0.4.4(rollup@3.29.5) - '@rollup/plugin-typescript': 12.1.2(rollup@3.29.5)(tslib@2.8.1)(typescript@5.8.2) - '@rollup/plugin-url': 8.0.2(rollup@3.29.5) - '@rollup/pluginutils': 5.1.4(rollup@3.29.5) - '@testing-library/dom': 8.20.1 - '@testing-library/jest-dom': 5.17.0 - '@testing-library/react': 13.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@testing-library/user-event': 14.5.1(@testing-library/dom@8.20.1) - '@types/react': 18.2.36 - '@types/react-dom': 18.2.14 - '@types/react-native': 0.72.8(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)) - '@types/testing-library__jest-dom': 5.14.9 - '@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) - '@typescript-eslint/parser': 5.62.0(eslint@7.32.0)(typescript@5.8.2) - ansi-colors: 4.1.1 - babel-eslint: 10.1.0(eslint@7.32.0) - babel-jest: 29.7.0(@babel/core@7.26.10) - big.js: 6.2.2 - concurrently: 6.5.1 - core-js: 3.33.2 - dotenv: 8.6.0 - enzyme: 3.11.0 - enzyme-to-json: 3.6.2(enzyme@3.11.0) - eslint: 7.32.0 - eslint-config-prettier: 8.10.0(eslint@7.32.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) - eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@3.5.3) - eslint-plugin-promise: 4.3.1 - eslint-plugin-react: 7.28.0(eslint@7.32.0) - eslint-plugin-react-hooks: 4.6.0(eslint@7.32.0) - fast-glob: 3.3.2 - find-free-port: 2.0.0 - fs-extra: 9.1.0 - 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-environment-jsdom: 29.7.0 - jest-jasmine2: 29.7.0 - jest-junit: 13.2.0 - jest-react-hooks-shallow: 1.5.1 - make-dir: 3.1.0 - mendix: 10.20.60519 - metro-react-native-babel-preset: 0.74.1(@babel/core@7.26.10) - mime: 3.0.0 - node-fetch: 2.7.0 - postcss: 8.4.47 - postcss-import: 14.1.0(postcss@8.4.47) - postcss-url: 10.1.3(postcss@8.4.47) - prettier: 3.5.3 - react-test-renderer: 18.2.0(react@18.2.0) - recursive-copy: 2.0.14 - resolve: 1.22.8 - rollup: 3.29.5 - rollup-plugin-clear: 2.0.7 - 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-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-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 - zip-a-folder: 0.0.12 - transitivePeerDependencies: - - '@jest/transform' - - '@jest/types' - - '@swc/core' - - '@swc/wasm' - - '@types/babel__core' - - '@types/node' - - babel-plugin-macros - - bufferutil - - canvas - - encoding - - esbuild - - node-notifier - - picomatch - - react - - react-dom - - react-native - - supports-color - - tslib - - utf-8-validate - '@napi-rs/canvas-android-arm64@0.1.69': optional: true @@ -14572,17 +14440,6 @@ snapshots: execa: 5.1.1 fast-glob: 3.3.2 - '@react-native-community/cli-config@14.1.0': - dependencies: - '@react-native-community/cli-tools': 14.1.0 - chalk: 4.1.2 - cosmiconfig: 9.0.0 - deepmerge: 4.3.1 - fast-glob: 3.3.2 - joi: 17.13.3 - transitivePeerDependencies: - - typescript - '@react-native-community/cli-config@14.1.0(typescript@5.1.6)': dependencies: '@react-native-community/cli-tools': 14.1.0 @@ -14611,27 +14468,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native-community/cli-doctor@14.1.0': - dependencies: - '@react-native-community/cli-config': 14.1.0 - '@react-native-community/cli-platform-android': 14.1.0 - '@react-native-community/cli-platform-apple': 14.1.0 - '@react-native-community/cli-platform-ios': 14.1.0 - '@react-native-community/cli-tools': 14.1.0 - chalk: 4.1.2 - command-exists: 1.2.9 - deepmerge: 4.3.1 - envinfo: 7.14.0 - execa: 5.1.1 - node-stream-zip: 1.15.0 - ora: 5.4.1 - semver: 7.7.1 - strip-ansi: 5.2.0 - wcwidth: 1.0.1 - yaml: 2.6.0 - transitivePeerDependencies: - - typescript - '@react-native-community/cli-doctor@14.1.0(typescript@5.1.6)': dependencies: '@react-native-community/cli-config': 14.1.0(typescript@5.1.6) @@ -14729,30 +14565,6 @@ snapshots: dependencies: joi: 17.13.3 - '@react-native-community/cli@14.1.0': - dependencies: - '@react-native-community/cli-clean': 14.1.0 - '@react-native-community/cli-config': 14.1.0 - '@react-native-community/cli-debugger-ui': 14.1.0 - '@react-native-community/cli-doctor': 14.1.0 - '@react-native-community/cli-server-api': 14.1.0 - '@react-native-community/cli-tools': 14.1.0 - '@react-native-community/cli-types': 14.1.0 - chalk: 4.1.2 - commander: 9.5.0 - deepmerge: 4.3.1 - execa: 5.1.1 - find-up: 5.0.0 - fs-extra: 8.1.0 - graceful-fs: 4.2.11 - prompts: 2.4.2 - semver: 7.7.1 - transitivePeerDependencies: - - bufferutil - - supports-color - - typescript - - utf-8-validate - '@react-native-community/cli@14.1.0(typescript@5.1.6)': dependencies: '@react-native-community/cli-clean': 14.1.0 @@ -15055,12 +14867,6 @@ snapshots: nullthrows: 1.1.1 react-native: 0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2) - '@react-native/virtualized-lists@0.72.8(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))': - dependencies: - invariant: 2.2.4 - nullthrows: 1.1.1 - react-native: 0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0) - '@react-native/virtualized-lists@0.75.3(@types/react@18.2.36)(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)': dependencies: invariant: 2.2.4 @@ -15088,15 +14894,6 @@ snapshots: optionalDependencies: '@types/react': 18.2.36 - '@react-native/virtualized-lists@0.75.3(@types/react@18.2.36)(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)': - dependencies: - invariant: 2.2.4 - nullthrows: 1.1.1 - react: 18.2.0 - react-native: 0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0) - optionalDependencies: - '@types/react': 18.2.36 - '@restart/hooks@0.4.9(react@18.2.0)': dependencies: dequal: 2.0.3 @@ -15605,13 +15402,6 @@ snapshots: transitivePeerDependencies: - react-native - '@types/react-native@0.72.8(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))': - dependencies: - '@react-native/virtualized-lists': 0.72.8(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)) - '@types/react': 18.2.36 - transitivePeerDependencies: - - react-native - '@types/react-plotly.js@2.6.3': dependencies: '@types/plotly.js': 2.12.30 @@ -15675,26 +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 - '@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) - '@typescript-eslint/utils': 5.62.0(eslint@7.32.0)(typescript@5.8.2) - debug: 4.3.7 - eslint: 7.32.0 - graphemer: 1.4.0 - ignore: 5.3.2 - natural-compare-lite: 1.4.0 - semver: 7.7.1 - tsutils: 3.21.0(typescript@5.8.2) - optionalDependencies: - typescript: 5.8.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.24.0(jiti@2.4.2))(typescript@5.1.6))(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) @@ -15713,7 +15484,7 @@ snapshots: '@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.11.1 + '@eslint-community/regexpp': 4.12.1 '@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) @@ -16311,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 @@ -16346,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: @@ -16368,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 @@ -17144,13 +16900,6 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 - cosmiconfig@9.0.0: - dependencies: - env-paths: 2.2.1 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - parse-json: 5.2.0 - cosmiconfig@9.0.0(typescript@5.1.6): dependencies: env-paths: 2.2.1 @@ -17877,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: @@ -18179,16 +17928,6 @@ snapshots: - supports-color - typescript - eslint-plugin-jest@24.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.24.0(jiti@2.4.2))(typescript@5.1.6))(eslint@7.32.0)(typescript@5.8.2))(eslint@7.32.0)(typescript@5.8.2): - dependencies: - '@typescript-eslint/experimental-utils': 4.33.0(eslint@7.32.0)(typescript@5.8.2) - eslint: 7.32.0 - optionalDependencies: - '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.24.0(jiti@2.4.2))(typescript@5.1.6))(eslint@7.32.0)(typescript@5.8.2) - transitivePeerDependencies: - - supports-color - - typescript - 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.24.0(jiti@2.4.2))(typescript@5.8.2) @@ -18256,21 +17995,21 @@ snapshots: 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.24.0(jiti@2.4.2)): dependencies: @@ -18328,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 @@ -19144,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: @@ -19820,7 +19559,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@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) + ts-node: 10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.14.0)(typescript@5.8.2) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -20051,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 @@ -20979,14 +20718,14 @@ snapshots: mkdirp@1.0.4: {} - mobx-react-lite@4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0): + mobx-react-lite@4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0): dependencies: mobx: 6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9) react: 18.2.0 use-sync-external-store: 1.2.0(react@18.2.0) optionalDependencies: react-dom: 18.2.0(react@18.2.0) - react-native: 0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0) + react-native: 0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2) mobx-react-lite@4.0.7(patch_hash=47fd2d1b5c35554ddd4fa32fcaa928a16fda9f82dca0ff68bcdc1f7c3e5f9d1a)(mobx@6.12.3(patch_hash=39c55279e8f75c9a322eba64dd22e1a398f621c64bbfc3632e55a97f46edfeb9))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: @@ -21195,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 @@ -21212,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 @@ -21228,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: @@ -21659,7 +21380,7 @@ snapshots: yaml: 1.10.2 optionalDependencies: 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) + ts-node: 10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.14.0)(typescript@5.8.2) postcss-merge-longhand@5.1.7(postcss@8.4.31): dependencies: @@ -22415,59 +22136,6 @@ snapshots: - typescript - utf-8-validate - react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0): - dependencies: - '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 14.1.0 - '@react-native-community/cli-platform-android': 14.1.0 - '@react-native-community/cli-platform-ios': 14.1.0 - '@react-native/assets-registry': 0.75.3 - '@react-native/codegen': 0.75.3(@babel/preset-env@7.26.9(@babel/core@7.26.10)) - '@react-native/community-cli-plugin': 0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10)) - '@react-native/gradle-plugin': 0.75.3 - '@react-native/js-polyfills': 0.75.3 - '@react-native/normalize-colors': 0.75.3 - '@react-native/virtualized-lists': 0.75.3(@types/react@18.2.36)(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0) - abort-controller: 3.0.0 - anser: 1.4.10 - ansi-regex: 5.0.1 - base64-js: 1.5.1 - chalk: 4.1.2 - commander: 9.5.0 - event-target-shim: 5.0.1 - flow-enums-runtime: 0.0.6 - glob: 7.2.3 - invariant: 2.2.4 - jest-environment-node: 29.7.0 - jsc-android: 250231.0.0 - memoize-one: 5.2.1 - metro-runtime: 0.80.12 - metro-source-map: 0.80.12 - mkdirp: 0.5.6 - nullthrows: 1.1.1 - pretty-format: 26.6.2 - promise: 8.3.0 - react: 18.2.0 - react-devtools-core: 5.3.2 - react-refresh: 0.14.2 - regenerator-runtime: 0.13.11 - scheduler: 0.24.0-canary-efb381bbf-20230505 - semver: 7.7.1 - stacktrace-parser: 0.1.10 - whatwg-fetch: 3.6.20 - ws: 6.2.3 - yargs: 17.7.2 - optionalDependencies: - '@types/react': 18.2.36 - transitivePeerDependencies: - - '@babel/core' - - '@babel/preset-env' - - bufferutil - - encoding - - supports-color - - typescript - - utf-8-validate - react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.1.6): dependencies: '@jest/create-cache-key-function': 29.7.0 @@ -23105,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: @@ -23528,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 @@ -23568,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: From 15f54298b588f752c48f4dc7a2a209a01c718be1 Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Thu, 27 Mar 2025 16:34:30 +0100 Subject: [PATCH 09/28] feat(rich-text): add toolbar keys for font size and table --- packages/pluggableWidgets/rich-text-web/src/RichText.xml | 5 ++++- .../src/components/CustomToolbars/constants.ts | 6 +++--- .../rich-text-web/typings/RichTextProps.d.ts | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/pluggableWidgets/rich-text-web/src/RichText.xml b/packages/pluggableWidgets/rich-text-web/src/RichText.xml index c0d51f4124..70aa5f01eb 100644 --- a/packages/pluggableWidgets/rich-text-web/src/RichText.xml +++ b/packages/pluggableWidgets/rich-text-web/src/RichText.xml @@ -1,5 +1,7 @@ - + Rich Text Rich inline or toolbar text editing Input elements @@ -266,6 +268,7 @@ Header Full screen Clean + Table diff --git a/packages/pluggableWidgets/rich-text-web/src/components/CustomToolbars/constants.ts b/packages/pluggableWidgets/rich-text-web/src/components/CustomToolbars/constants.ts index 19bdc7f3fe..105f8e90f0 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/CustomToolbars/constants.ts +++ b/packages/pluggableWidgets/rich-text-web/src/components/CustomToolbars/constants.ts @@ -158,7 +158,7 @@ export const TOOLBAR_MAPPING: toolbarMappingType = { title: "Fullscreen", custom: true }, - "table-better": { + tableBetter: { component: ToolbarButton, className: "ql-table-better icons icon-Table", title: "Create Table", @@ -183,7 +183,7 @@ export const TOOLBAR_GROUP: ToolbarGroupType = { code: ["blockquote", "code", "codeBlock", "viewCode"], remove: ["clean"], view: ["fullscreen"], - "table-better": ["table-better"] + tableBetter: ["tableBetter"] }; export type toolbarContentType = { @@ -242,7 +242,7 @@ export const DEFAULT_TOOLBAR: toolbarContentType[] = [ }, { presetValue: 2, - children: TOOLBAR_GROUP["table-better"] + children: TOOLBAR_GROUP["tableBetter"] } ]; diff --git a/packages/pluggableWidgets/rich-text-web/typings/RichTextProps.d.ts b/packages/pluggableWidgets/rich-text-web/typings/RichTextProps.d.ts index 4bf3a7e2aa..44c0561733 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; From 15f992fd9ca5c10f4df368ac43d301ca5f9da86a Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Thu, 27 Mar 2025 16:36:05 +0100 Subject: [PATCH 10/28] feat(table-better): small improvements on table-better --- .../rich-text-web/src/components/Editor.tsx | 32 -------- .../assets/css/quill-table-better.scss | 4 - .../quill-table-better/formats/header.ts | 4 +- .../quill-table-better/formats/table.ts | 31 +++---- .../quill-table-better/language/index.ts | 6 +- .../quill-table-better/quill-table-better.ts | 28 +++---- .../quill-table-better/ui/operate-line.ts | 10 ++- .../ui/table-properties-form.ts | 6 +- .../quill-table-better/ui/toolbar-table.ts | 6 +- .../formats/quill-table-better/utils/index.ts | 12 +-- .../rich-text-web/src/utils/formats/table.ts | 81 ------------------- 11 files changed, 55 insertions(+), 165 deletions(-) delete mode 100644 packages/pluggableWidgets/rich-text-web/src/utils/formats/table.ts diff --git a/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx b/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx index ffb473bbd1..32b7261fa0 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx @@ -142,38 +142,6 @@ const Editor = forwardRef((props: EditorProps, ref: MutableRefObject - - -   - - -   -   -   - - - -

- - - - - - -
-
Dit bericht kan informatie bevatten die niet voor u is bestemd. Indien u niet de geadresseerde bent of dit bericht abusievelijk aan u is toegezonden, wordt u verzocht dat aan de afzender te melden en het bericht te verwijderen. De Staat aanvaardt geen aansprakelijkheid voor schade, van welke aard ook, die verband houdt met risico's verbonden aan het elektronisch verzenden van berichten.
- -
This message may contain information that is not intended for you. If you are not the addressee or if this message was sent to you by mistake, you are requested to inform the sender and delete the message. The State accepts no liability for damage of any kind resulting from the risks inherent in the electronic transmission of messages.
- -
Ministerie van Infrastructuur en Waterstaat
-
- `; - - const delta = quill.clipboard.convert({ html }); - quill.updateContents(delta, Quill.sources.USER); - quill.on(Quill.events.TEXT_CHANGE, (...arg) => { onTextChangeRef.current?.(...arg); }); diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/css/quill-table-better.scss b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/css/quill-table-better.scss index 73329c7bde..8213858d37 100644 --- a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/css/quill-table-better.scss +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/assets/css/quill-table-better.scss @@ -487,10 +487,6 @@ $focused-border: 1px solid $focused-border-color; height: 100%; display: flex; flex-direction: column; - .iro-container { - flex: 1; - @extend .ql-table-center; - } } } } diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/header.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/header.ts index 83bfde18fd..c40259ec60 100644 --- a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/header.ts +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/header.ts @@ -12,6 +12,8 @@ class TableHeader extends Header { static blotName = "table-header"; static className = "ql-table-header"; + // @ts-ignore + next: this | null; // @ts-ignore parent: TableCell; @@ -22,7 +24,7 @@ class TableHeader extends Header { return node; } - format(name: string, value: string, isReplace?: boolean) { + format(name: string, value: string | Props, isReplace?: boolean) { if (name === "header") { const _value = this.statics.formats(this.domNode).value; const cellId = this.domNode.getAttribute("data-cell"); diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts index b5383cf86b..4494b9b4ee 100644 --- a/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts +++ b/packages/pluggableWidgets/rich-text-web/src/utils/formats/quill-table-better/formats/table.ts @@ -12,7 +12,6 @@ import { ListContainer } from "./list"; const Block = QuillBlock as typeof BlockBlot; const Container = QuillContainer as typeof ContainerBlot; const TABLE_ATTRIBUTE = ["border", "cellspacing", "style", "data-class"]; -// const STYLE_RULES = ["color", "border", "width", "height"]; const COL_ATTRIBUTE = ["width"]; class TableCellBlock extends Block { @@ -88,11 +87,11 @@ class TableCell extends Container { prev: this | null; checkMerge() { - if (super.checkMerge() && this.next?.children.head != null && this.next.children.head.formats) { - const thisHead = this.children.head?.formats()[this.children.head.statics.blotName]; - const thisTail = this.children.tail?.formats()[this.children.tail.statics.blotName]; + if (super.checkMerge() && this.next.children.head != null && this.next.children.head.formats) { + const thisHead = this.children.head.formats()[this.children.head.statics.blotName]; + const thisTail = this.children.tail.formats()[this.children.tail.statics.blotName]; const nextHead = this.next.children.head.formats()[this.next.children.head.statics.blotName]; - const nextTail = this.next.children.tail?.formats()[this.next.children.tail.statics.blotName]; + const nextTail = this.next.children.tail.formats()[this.next.children.tail.statics.blotName]; const _thisHead = getCellId(thisHead); const _thisTail = getCellId(thisTail); const _nextHead = getCellId(nextHead); @@ -118,7 +117,7 @@ class TableCell extends Container { if (attr === "rowspan" && rowspan) { formats[attr] = `${~~domNode.getAttribute(attr) - rowspan}`; } else { - formats[attr] = filterWordStyle(domNode.getAttribute(attr) ?? ""); + formats[attr] = filterWordStyle(domNode.getAttribute(attr)); } } return formats; @@ -132,13 +131,14 @@ class TableCell extends Container { return formats; } - formats() { - const formats = this.statics.formats(this.domNode, this.scroll); - return { [this.statics.blotName]: formats }; + formats(): { [key: string]: Props } { + const formats: Props = this.statics.formats(this.domNode, this.scroll); + const blotName: string = this.statics.blotName; + return { [blotName]: formats }; } static getEmptyRowspan(domNode: Element) { - let nextNode = domNode.parentElement?.nextElementSibling; + let nextNode = domNode.parentElement.nextElementSibling; let rowspan = 0; while (nextNode && nextNode.tagName === "TR" && !nextNode.innerHTML.replace(/\s/g, "")) { rowspan++; @@ -149,13 +149,13 @@ class TableCell extends Container { static hasColgroup(domNode: Element) { while (domNode && domNode.tagName !== "TBODY") { - domNode = domNode.parentElement!; + domNode = domNode.parentElement; } while (domNode) { if (domNode.tagName === "COLGROUP") { return true; } - domNode = domNode.previousElementSibling!; + domNode = domNode.previousElementSibling; } return false; } @@ -283,9 +283,10 @@ class TableTemporary extends Block { }, {}); } - formats() { - const formats = this.statics.formats(this.domNode, this.scroll); - return { [this.statics.blotName]: formats }; + formats(): { [key: string]: Props } { + const formats: Props = this.statics.formats(this.domNode, this.scroll); + const blotName: string = this.statics.blotName; + return { [blotName]: formats }; } optimize(...args: unknown[]) { 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 index 71ea63f0f9..9b0aa6b702 100644 --- 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 @@ -1,12 +1,12 @@ // @ts-nocheck -import { Props } from "../types"; +import type { Props } from "../types"; +import de_DE from "./de_DE"; import en_US from "./en_US"; -import zh_CN from "./zh_CN"; import fr_FR from "./fr_FR"; import pl_PL from "./pl_PL"; -import de_DE from "./de_DE"; import ru_RU from "./ru_RU"; import tr_TR from "./tr_TR"; +import zh_CN from "./zh_CN"; interface Config { [propName: string]: Props; 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 index 5b37f8b801..3496857db3 100644 --- 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 @@ -1,33 +1,33 @@ // @ts-nocheck -import type { EmitterSource, Range } from "quill"; import Quill from "quill"; import Delta from "quill-delta"; import Module from "quill/core/module"; -import { CELL_DEFAULT_WIDTH } from "./config"; -import TableHeader from "./formats/header"; -import { ListContainer } from "./formats/list"; +import type { EmitterSource, Range } from "quill"; +import type { BindingObject, Context, Props } from "./types"; import { cellId, - TableBody, - TableCell, TableCellBlock, - TableCol, - TableColgroup, + TableCell, + TableRow, + TableBody, + TableTemporary, TableContainer, tableId, - TableRow, - TableTemporary + 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 TableClipboard from "./modules/clipboard"; -import TableToolbar from "./modules/toolbar"; -import type { BindingObject, Context, Props } from "./types"; 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 { matchTable, matchTableCell, matchTableCol, matchTableTemporary } from "./utils/clipboard-matchers"; +import TableToolbar from "./modules/toolbar"; +import TableClipboard from "./modules/clipboard"; interface Options { language?: 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 index b6b0a5cd5a..d16eb4b470 100644 --- 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 @@ -1,7 +1,7 @@ // @ts-nocheck import Quill from "quill"; import type { QuillTableBetter, TableCell, TableColgroup } from "../types"; -import { setElementProperty, setElementAttribute, updateTableWidth } from "../utils"; +import { setElementAttribute, setElementProperty, updateTableWidth } from "../utils"; interface Options { tableNode: HTMLElement; @@ -408,9 +408,13 @@ class OperateLine { 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` }); + 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` }); + setElementProperty(this.line, { + top: `${~~clientY - containerRect.top - LINE_CONTAINER_HEIGHT / 2}px` + }); } } 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 index b5c3728119..c5b5c2a088 100644 --- 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 @@ -1,6 +1,6 @@ import { computePosition, flip, offset, shift } from "@floating-ui/react"; -import "@melloware/coloris/dist/coloris.css"; import Coloris from "@melloware/coloris"; +import "@melloware/coloris/dist/coloris.css"; import Quill from "quill"; import closeIcon from "../assets/icon/close.svg"; import downIcon from "../assets/icon/down.svg"; @@ -162,7 +162,7 @@ class TablePropertiesForm { return container; } - createColorInput(child: Child): HTMLDivElement { + createColorInput(child: Child) { const { attribute, value } = child; const placeholder = attribute?.placeholder ?? ""; const container = document.createElement("div"); @@ -219,7 +219,7 @@ class TablePropertiesForm { return { dropdown: container, dropText }; } - createInput(child: Child): HTMLDivElement { + createInput(child: Child) { const { attribute, message, propertyName, valid, value } = child; const placeholder = attribute?.placeholder ?? ""; const container = document.createElement("div"); 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 index 0aa39117c2..2993dbf743 100644 --- 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 @@ -37,7 +37,7 @@ class TableSelect { fragment.appendChild(child); } } - label.innerHTML = "0 x 0"; + 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"); @@ -102,10 +102,10 @@ class TableSelect { setLabelContent(label: Element, child: Element) { if (!child) { - label.innerHTML = "0 x 0"; + label.innerHTML = "0 × 0"; } else { const [row, column] = this.getSelectAttrs(child); - label.innerHTML = `${row} x ${column}`; + label.innerHTML = `${row} × ${column}`; } } 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 index 299b64bd31..e8010713ff 100644 --- 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 @@ -1,10 +1,10 @@ // @ts-nocheck import Quill from "quill"; -import type { CorrectBound, Props, TableCellChildren, TableContainer } from "../types"; -import { TableCell, TableCellBlock, TableCol } from "../formats/table"; -import TableList, { ListContainer } from "../formats/list"; -import TableHeader from "../formats/header"; 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; @@ -31,7 +31,7 @@ function createTooltip(content: string) { } function debounce(cb: Function, delay: number) { - let timer: NodeJS.Timeout | null = null; + let timer: NodeJS.Timeout = null; return function () { let context = this; let args = arguments; @@ -373,8 +373,8 @@ export { isValidColor, isValidDimensions, removeElementProperty, - rgbToHex, rgbaToHex, + rgbToHex, setElementAttribute, setElementProperty, throttle, diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/formats/table.ts b/packages/pluggableWidgets/rich-text-web/src/utils/formats/table.ts deleted file mode 100644 index adde1a6f7e..0000000000 --- a/packages/pluggableWidgets/rich-text-web/src/utils/formats/table.ts +++ /dev/null @@ -1,81 +0,0 @@ -// import {TableCell, TableRow, TableBody, TableContainer} from "quill/formats/table"; - -// const ATTRIBUTES = ["colspan", "height", "width", "class", "id"]; - -// type tableCellAttributes = { -// id?: string; -// colspan?: string; -// class?: string; -// height?: string; -// width?: string; -// }; - -// class MxTableCell extends TableCell { -// static create(value: unknown): HTMLElement { -// const domNode = super.create(value as string) as HTMLElement; -// if (value as tableCellAttributes) { -// const cellAttr = value as tableCellAttributes; -// // for each tableCellAttributes type -// if (cellAttr.id) { -// domNode.setAttribute("id", cellAttr.id); -// } -// if (cellAttr.class) { -// domNode.setAttribute("class", cellAttr.class); -// } -// if (cellAttr.width) { -// domNode.setAttribute("width", cellAttr.width); -// } -// if(cellAttr.height){ -// domNode.setAttribute("height", cellAttr.height); -// } -// if (cellAttr.colspan) { -// domNode.setAttribute("colspan", cellAttr.colspan); -// } -// } -// return domNode; -// } - -// static formats(domNode: Element): Record { -// return ATTRIBUTES.reduce((formats: Record, attribute) => { -// if (domNode.hasAttribute(attribute)) { -// formats[attribute] = domNode.getAttribute(attribute); -// } -// return formats; -// }, {}); -// } -// } - -// export {MxTableCell}; - -// // export default class CustomLink extends Link { -// // format(name: string, value: unknown): void { -// // if (name !== this.statics.blotName || !value) { -// // super.format(name, value); -// // } else if ((value as linkConfigType)?.href !== undefined) { -// // const linkConfig = value as linkConfigType; -// // // @ts-expect-error the constructor is generic function, ts will consider sanitize not exist -// // this.domNode.setAttribute("href", getLink(this.constructor.sanitize(linkConfig.href))); -// // this.domNode.setAttribute("target", linkConfig.target ?? "_blank"); -// // this.domNode.setAttribute("title", linkConfig.title ?? ""); -// // this.domNode.textContent = linkConfig.text ?? linkConfig.href; -// // } else { -// // // @ts-expect-error the constructor is generic function, ts will consider sanitize not exist -// // this.domNode.setAttribute("href", getLink(this.constructor.sanitize(value))); -// // } -// // } - -// // static create(value: unknown): HTMLElement { -// // if ((value as linkConfigType)?.href !== undefined) { -// // const linkConfig = value as linkConfigType; -// // const node = super.create(linkConfig.href) as HTMLElement; -// // node.setAttribute("href", getLink(this.sanitize(linkConfig.href))); -// // node.setAttribute("rel", "noopener noreferrer"); -// // node.setAttribute("title", linkConfig.title ?? linkConfig.href); -// // node.setAttribute("target", linkConfig.target || "_blank"); -// // return node; -// // } else { -// // // @ts-expect-error type mismatch expected -// // return super.create(value); -// // } -// // } -// // } From 319f1e8731010e826eeb55ed947a8ccd3b5fe4c6 Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Thu, 27 Mar 2025 16:37:06 +0100 Subject: [PATCH 11/28] feat(rich-text): update rollup config for table-better support --- .../pluggableWidgets/rich-text-web/rollup.config.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/pluggableWidgets/rich-text-web/rollup.config.js b/packages/pluggableWidgets/rich-text-web/rollup.config.js index a87ee9a3d2..d6ffe27ced 100644 --- a/packages/pluggableWidgets/rich-text-web/rollup.config.js +++ b/packages/pluggableWidgets/rich-text-web/rollup.config.js @@ -1,3 +1,4 @@ +import typescript from "@rollup/plugin-typescript"; import preserveDirectives from "rollup-preserve-directives"; import alias from "@rollup/plugin-alias"; @@ -5,7 +6,7 @@ export default args => { const result = args.configDefaultConfig; return result.map((config, _index) => { config.plugins = [ - ...config.plugins, + ...config.plugins.filter(plugin => plugin?.name !== "typescript"), preserveDirectives(), alias({ entries: [ @@ -14,8 +15,17 @@ export default args => { replacement: "$1.svg" } ] + }), + typescript({ + noEmitOnError: !args.watch, + sourceMap: config.sourceMaps, + inlineSources: config.sourceMaps, + target: "es2022", // we transpile the result with babel anyway, see below + useDefineForClassFields: false, + exclude: ["**/__tests__/**/*"] }) ]; + return config; }); }; From fe075ae287357727f5e0e91e23ac409bf3a3cf3c Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Thu, 27 Mar 2025 16:46:23 +0100 Subject: [PATCH 12/28] fix: eslint error fix --- .../rich-text-web/src/components/CustomToolbars/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pluggableWidgets/rich-text-web/src/components/CustomToolbars/constants.ts b/packages/pluggableWidgets/rich-text-web/src/components/CustomToolbars/constants.ts index 105f8e90f0..dfcda2a3c4 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/CustomToolbars/constants.ts +++ b/packages/pluggableWidgets/rich-text-web/src/components/CustomToolbars/constants.ts @@ -242,7 +242,7 @@ export const DEFAULT_TOOLBAR: toolbarContentType[] = [ }, { presetValue: 2, - children: TOOLBAR_GROUP["tableBetter"] + children: TOOLBAR_GROUP.tableBetter } ]; From 671b0f925a67f14251c6713dc8d7dafa40660295 Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Fri, 28 Mar 2025 09:38:39 +0100 Subject: [PATCH 13/28] test(rich-text): update failing snapshot --- .../__tests__/__snapshots__/RichText.spec.tsx.snap | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/pluggableWidgets/rich-text-web/src/__tests__/__snapshots__/RichText.spec.tsx.snap b/packages/pluggableWidgets/rich-text-web/src/__tests__/__snapshots__/RichText.spec.tsx.snap index a7e5b27479..4087874c64 100644 --- a/packages/pluggableWidgets/rich-text-web/src/__tests__/__snapshots__/RichText.spec.tsx.snap +++ b/packages/pluggableWidgets/rich-text-web/src/__tests__/__snapshots__/RichText.spec.tsx.snap @@ -660,6 +660,17 @@ exports[`Rich Text renders richtext widget with different config 1`] = ` title="Fullscreen" /> + +