@knime/kds-rich-text-editor 0.30.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +710 -0
  3. package/README.md +116 -0
  4. package/dist/index.css +282 -0
  5. package/dist/index.js +917 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/src/KdsRichTextEditor.vue.d.ts +35 -0
  8. package/dist/src/KdsRichTextEditor.vue.d.ts.map +1 -0
  9. package/dist/src/index.d.ts +6 -0
  10. package/dist/src/index.d.ts.map +1 -0
  11. package/dist/src/toolbar/KdsCreateLinkModal.vue.d.ts +459 -0
  12. package/dist/src/toolbar/KdsCreateLinkModal.vue.d.ts.map +1 -0
  13. package/dist/src/toolbar/RichTextEditorBaseToolbar.vue.d.ts +48 -0
  14. package/dist/src/toolbar/RichTextEditorBaseToolbar.vue.d.ts.map +1 -0
  15. package/dist/src/toolbar/RichTextEditorToolbar.vue.d.ts +10 -0
  16. package/dist/src/toolbar/RichTextEditorToolbar.vue.d.ts.map +1 -0
  17. package/dist/src/toolbar/types.d.ts +29 -0
  18. package/dist/src/toolbar/types.d.ts.map +1 -0
  19. package/dist/src/toolbar/useLinkTool.d.ts +22 -0
  20. package/dist/src/toolbar/useLinkTool.d.ts.map +1 -0
  21. package/dist/src/types.d.ts +112 -0
  22. package/dist/src/types.d.ts.map +1 -0
  23. package/dist/src/utils/custom-escape.d.ts +15 -0
  24. package/dist/src/utils/custom-escape.d.ts.map +1 -0
  25. package/dist/src/utils/custom-hard-break.d.ts +2 -0
  26. package/dist/src/utils/custom-hard-break.d.ts.map +1 -0
  27. package/dist/src/utils/custom-link.d.ts +16 -0
  28. package/dist/src/utils/custom-link.d.ts.map +1 -0
  29. package/dist/src/utils/custom-text-align.d.ts +2 -0
  30. package/dist/src/utils/custom-text-align.d.ts.map +1 -0
  31. package/dist/src/utils/paragraphTextStyle/extension.d.ts +17 -0
  32. package/dist/src/utils/paragraphTextStyle/extension.d.ts.map +1 -0
  33. package/dist/src/utils/paragraphTextStyle/index.d.ts +4 -0
  34. package/dist/src/utils/paragraphTextStyle/index.d.ts.map +1 -0
  35. package/package.json +76 -0
package/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # KNIME® Design System – Rich Text Editor
2
+
3
+ This is part of the [KNIME Design System](../../README.md) maintained by the [UI Core Team](mailto:team-ui-core@knime.com).
4
+
5
+ This package contains the `KdsRichTextEditor` component and its toolbar, a WYSIWYG editor that follows the KNIME Design System. It is based on the [Vue] JavaScript framework, built on the KNIME Design System tokens, and powered by [Tiptap]/[ProseMirror].
6
+
7
+ It's published as npm package: [@knime/kds-rich-text-editor]
8
+
9
+ ## Why a separate package?
10
+
11
+ Tiptap and ProseMirror add a large, DOM-parsing dependency subtree (~50 packages) that is irrelevant to most consumers of `@knime/kds-components`. Keeping the editor in its own package keeps that dependency, bundle, and security-audit/SBOM surface **opt-in** — only apps that install this package pull it in. See the [root README](../../README.md) for the package overview.
12
+
13
+ The Tiptap/ProseMirror packages are declared as regular `dependencies` but are **externalized** in the build (see [`vite.config.js`](vite.config.js)). They are resolved at consume time rather than bundled, so consumers dedupe a single ProseMirror instance and can pull CVE-patched transitive versions via their own lockfile without waiting on a republish.
14
+
15
+ ## Development
16
+
17
+ This package is part of the [KNIME Design System monorepo](../../README.md). For setup instructions, see the **[root README](../../README.md)**.
18
+
19
+ ### Launch development server
20
+
21
+ From the root of the monorepo:
22
+
23
+ ```sh
24
+ pnpm dev # Starts Storybook with all design system components
25
+ ```
26
+
27
+ ### Testing
28
+
29
+ Unit tests are based on [Vitest]. Run from the monorepo root:
30
+
31
+ ```sh
32
+ pnpm run test:unit # Run all unit tests (packages/*)
33
+ pnpm run coverage # Generate coverage reports
34
+ ```
35
+
36
+ ### Running security audit
37
+
38
+ Security audits are run at the monorepo root:
39
+
40
+ ```sh
41
+ pnpm run audit
42
+ ```
43
+
44
+ ### Logging
45
+
46
+ You can log using the global `consola` variable (which the embedding application needs to provide).
47
+
48
+ See https://github.com/nuxt/consola for details.
49
+
50
+ ## Building
51
+
52
+ To build the editor as a [Vue library]:
53
+
54
+ ```sh
55
+ pnpm run build # Build only this package
56
+ ```
57
+
58
+ Results are saved to `dist/`.
59
+
60
+ ## Versioning & Publishing
61
+
62
+ Versioning and publishing are managed at the **[root level](../../README.md#changesets--publishing)**.
63
+
64
+ All `@knime/kds-*` packages (including this one) are versioned together via Changesets. For release workflows, see the [root README](../../README.md).
65
+
66
+ ## Using the editor in a Vue application
67
+
68
+ Install the [@knime/kds-rich-text-editor] npm package as a dependency. It requires `@knime/kds-components` and `vue` as peer dependencies:
69
+
70
+ ```sh
71
+ pnpm add @knime/kds-rich-text-editor @knime/kds-components @knime/kds-styles
72
+ ```
73
+
74
+ ```vue
75
+ <script setup lang="ts">
76
+ import { ref } from "vue";
77
+
78
+ import { KdsRichTextEditor } from "@knime/kds-rich-text-editor";
79
+
80
+ const value = ref("<p>Hello world</p>");
81
+ </script>
82
+
83
+ <template>
84
+ <KdsRichTextEditor
85
+ v-model="value"
86
+ :base-extensions="{ bold: true, italic: true, link: true }"
87
+ />
88
+ </template>
89
+ ```
90
+
91
+ ### Public exports
92
+
93
+ All public symbols follow the KDS `Kds` prefix convention:
94
+
95
+ | Export | Kind | Description |
96
+ | --------------------------- | --------- | --------------------------------------------------- |
97
+ | `KdsRichTextEditor` | component | The editor (with built-in toolbar) |
98
+ | `KdsCreateLinkModal` | component | Modal used by the link tool |
99
+ | `kdsDefaultLinkToolOptions` | const | Default URL validator / sanitizer for the link tool |
100
+ | `KdsLinkToolOptions` | type | Options for the link tool |
101
+ | `KdsRichTextEditorProps` | type | Props of `KdsRichTextEditor` |
102
+ | `KdsBaseExtensionsConfig` | type | Opt-in map of built-in Tiptap extensions |
103
+
104
+ ### Requirements
105
+
106
+ The editor expects that the embedding app provides the following:
107
+
108
+ - Vue and Consola compatible to the versions defined in [`package.json`](package.json)
109
+ - `@knime/kds-components` and the `@knime/kds-styles` CSS variables imported once in the app entry
110
+
111
+ [Vue]: https://vuejs.org/
112
+ [Tiptap]: https://tiptap.dev/
113
+ [ProseMirror]: https://prosemirror.net/
114
+ [Vue library]: https://vitejs.dev/guide/build.html#library-mode
115
+ [Vitest]: https://vitest.dev/
116
+ [@knime/kds-rich-text-editor]: https://www.npmjs.com/package/@knime/kds-rich-text-editor
package/dist/index.css ADDED
@@ -0,0 +1,282 @@
1
+
2
+ .modal[data-v-5b224eb0] {
3
+ --modal-width: var(--kds-dimension-component-width-32x);
4
+ }
5
+ .modal-footer {
6
+ &[data-v-5b224eb0] {
7
+ display: flex;
8
+ gap: var(--kds-spacing-container-0-5x);
9
+ align-items: center;
10
+ justify-content: flex-end;
11
+ width: 100%;
12
+ }
13
+ &.spread-buttons[data-v-5b224eb0] {
14
+ justify-content: space-between;
15
+ }
16
+ }
17
+ .controls-apply-group[data-v-5b224eb0] {
18
+ display: flex;
19
+ gap: var(--kds-spacing-container-0-5x);
20
+ }
21
+
22
+ .tools[data-v-f4d33607] {
23
+ display: flex;
24
+ gap: var(--kds-spacing-container-0-25x);
25
+ align-items: center;
26
+ height: 100%;
27
+ }
28
+
29
+ .editor-wrapper {
30
+ &[data-v-06a9c7b9] {
31
+ /* Fixed 44px toolbar height per the design (28px content + 8px padding on
32
+ * each side). Defined explicitly so the toolbar expand/collapse transition
33
+ * has a concrete target height; the small toolbar buttons (24px) center
34
+ * within the content area. */
35
+ --toolbar-height: calc(
36
+ var(--kds-dimension-component-height-1-75x) +
37
+ var(--kds-spacing-container-0-5x) * 2
38
+ );
39
+
40
+ position: relative;
41
+ isolation: isolate;
42
+ }
43
+ &.disabled[data-v-06a9c7b9] {
44
+ color: var(--kds-color-text-and-icon-disabled);
45
+ }
46
+ }
47
+
48
+ /* stylelint-disable selector-class-pattern */
49
+ .rich-text-editor {
50
+ &[data-v-06a9c7b9] {
51
+ height: 100%;
52
+ max-height: var(--f4686d76);
53
+ padding: var(--kds-spacing-container-0-5x);
54
+ overflow-y: auto;
55
+
56
+ /* stylelint-disable knime/no-deep-nesting */
57
+ /* stylelint-enable selector-class-pattern */
58
+ }
59
+ &.editable {
60
+ &[data-v-06a9c7b9] {
61
+ cursor: text;
62
+ background: var(--kds-color-background-input-initial);
63
+ }
64
+ &[data-v-06a9c7b9] .ProseMirror {
65
+ min-height: var(--a618f0d2);
66
+ }
67
+ }
68
+ &[data-v-06a9c7b9] .ProseMirror {
69
+ height: 100%;
70
+
71
+ /* The following rich text styles are kept in sync with KdsDescription. */
72
+ p {
73
+ & {
74
+ padding: 0;
75
+ margin: 0 0 var(--kds-spacing-container-0-37x);
76
+ font: var(--kds-font-base-body-small);
77
+ }
78
+ &:last-child {
79
+ margin-bottom: 0;
80
+ }
81
+ }
82
+ p.small-text {
83
+ font: var(--kds-font-base-subtext-xsmall);
84
+ }
85
+ strong,
86
+ b {
87
+ font-weight: var(--kds-core-font-weight-strong);
88
+ }
89
+ i,
90
+ em {
91
+ font-style: italic;
92
+ }
93
+ h3 {
94
+ margin: 0;
95
+ font: var(--kds-font-base-body-medium-strong);
96
+ }
97
+ h4 {
98
+ margin: 0;
99
+ font: var(--kds-font-base-body-small-strong);
100
+ }
101
+ pre {
102
+ & {
103
+ width: fit-content;
104
+ padding: var(--kds-spacing-container-0-75x);
105
+ font: var(--kds-font-base-code-xsmall);
106
+ background: var(--kds-color-surface-subtle);
107
+ border-radius: var(--kds-border-radius-container-0-25x);
108
+ }
109
+ & > code {
110
+ padding: 0;
111
+ background: none;
112
+ }
113
+ }
114
+ & :not(pre) > code {
115
+ padding: var(--kds-spacing-container-0-12x)
116
+ var(--kds-spacing-container-0-25x);
117
+ font: var(--kds-font-base-code-xsmall);
118
+ background: var(--kds-color-surface-subtle);
119
+ box-decoration-break: clone;
120
+ border-radius: var(--kds-border-radius-container-0-12x);
121
+ }
122
+
123
+ /** keep in sync with KdsLink */
124
+ a {
125
+ & {
126
+ display: inline-flex;
127
+ align-items: center;
128
+ justify-content: center;
129
+ width: fit-content;
130
+ max-width: 100%;
131
+ padding: var(--kds-spacing-container-none)
132
+ var(--kds-spacing-container-0-10x);
133
+ font: var(--kds-font-base-body-small);
134
+ color: var(--kds-color-text-and-icon-neutral);
135
+ white-space: nowrap;
136
+ text-decoration-line: underline;
137
+ cursor: pointer;
138
+ border-radius: var(--kds-border-radius-container-0-12x);
139
+
140
+ /** internal links */
141
+
142
+ /** external links */
143
+ }
144
+ &:focus-visible {
145
+ outline: var(--kds-border-action-focused);
146
+ outline-offset: var(--kds-spacing-container-none);
147
+ }
148
+ &[href^="http"] {
149
+ & {
150
+ --link-color: var(--kds-color-text-and-icon-selected);
151
+
152
+ color: var(--link-color);
153
+ }
154
+ &:visited {
155
+ --link-color: var(--kds-color-text-and-icon-info);
156
+
157
+ color: var(--link-color);
158
+ }
159
+ &:hover {
160
+ --link-color: var(--kds-color-text-and-icon-primary-inverted);
161
+
162
+ color: var(--link-color);
163
+ background-color: var(--kds-color-background-primary-bold-hover);
164
+ }
165
+ &:active {
166
+ --link-color: var(--kds-color-text-and-icon-selected-inverted);
167
+
168
+ color: var(--link-color);
169
+ background-color: var(--kds-color-background-primary-bold-active);
170
+ }
171
+ &::after {
172
+ display: block;
173
+ width: var(--kds-dimension-icon-0-56x);
174
+ height: var(--kds-dimension-icon-0-56x);
175
+ margin-left: var(--kds-spacing-container-0-12x);
176
+ content: "";
177
+ background-color: var(--link-color);
178
+ mask-image: var(--c15f49ba);
179
+ mask-repeat: no-repeat;
180
+ mask-size: contain;
181
+ }
182
+ }
183
+ &:not([href^="http"]) {
184
+ & {
185
+ color: var(--kds-color-text-and-icon-neutral);
186
+ }
187
+ &:visited {
188
+ color: var(--kds-color-text-and-icon-info);
189
+ }
190
+ &:hover {
191
+ background-color: var(--kds-color-background-neutral-hover);
192
+ }
193
+ &:active {
194
+ background-color: var(--kds-color-background-neutral-active);
195
+ }
196
+ }
197
+ }
198
+ ol,
199
+ ul {
200
+ padding-left: var(--kds-spacing-container-2x);
201
+ }
202
+ dd {
203
+ margin-left: var(--kds-spacing-container-1x);
204
+ }
205
+ table {
206
+ & {
207
+ border-spacing: var(--kds-spacing-container-0-25x) 0;
208
+ border-collapse: separate;
209
+ }
210
+ td,
211
+ th {
212
+ padding: var(--kds-spacing-container-0-25x);
213
+ }
214
+ th {
215
+ font: var(--kds-font-base-body-small-strong);
216
+ text-align: left;
217
+ border-bottom: var(--kds-border-width-icon-stroke-l) solid
218
+ var(--kds-color-border-neutral);
219
+ }
220
+ td {
221
+ font: var(--kds-font-base-body-small);
222
+ border-bottom: var(--kds-border-width-icon-stroke-s) solid
223
+ var(--kds-color-border-neutral);
224
+ }
225
+ }
226
+ }
227
+ &[data-v-06a9c7b9] :has(:deep(.ProseMirror:focus)) {
228
+ outline: var(--kds-border-action-focused);
229
+ outline-offset: var(--kds-spacing-offset-focus);
230
+ }
231
+ &[data-v-06a9c7b9] .ProseMirror:focus-visible,
232
+ &[data-v-06a9c7b9] .ProseMirror:focus {
233
+ outline: transparent;
234
+ }
235
+ }
236
+ .editor-wrapper.with-border {
237
+ &[data-v-06a9c7b9] {
238
+ border: var(--kds-border-action-input);
239
+ border-radius: var(--kds-border-radius-container-0-37x);
240
+ }
241
+ &.disabled[data-v-06a9c7b9] {
242
+ border: var(--kds-border-action-disabled);
243
+ }
244
+ & .toolbar-wrapper[data-v-06a9c7b9] {
245
+ border-top-left-radius: var(--kds-border-radius-container-0-37x);
246
+ border-top-right-radius: var(--kds-border-radius-container-0-37x);
247
+ }
248
+ & .rich-text-editor[data-v-06a9c7b9] {
249
+ border-bottom-right-radius: var(--kds-border-radius-container-0-37x);
250
+ border-bottom-left-radius: var(--kds-border-radius-container-0-37x);
251
+ }
252
+ }
253
+ .embedded-toolbar {
254
+ &[data-v-06a9c7b9] {
255
+ height: var(--toolbar-height);
256
+ padding: var(--kds-spacing-container-0-5x);
257
+ overflow-x: auto;
258
+ overscroll-behavior: contain;
259
+ white-space: pre;
260
+ scrollbar-width: none; /* for firefox */
261
+ background: var(--kds-color-background-input-initial);
262
+ border-bottom: var(--kds-border-base-muted);
263
+ -ms-overflow-style: none; /* needed to hide scroll bar in edge */
264
+ }
265
+ &[data-v-06a9c7b9]::-webkit-scrollbar {
266
+ display: none;
267
+ }
268
+ }
269
+ .expand-enter-active[data-v-06a9c7b9],
270
+ .expand-leave-active[data-v-06a9c7b9] {
271
+ transition: all 0.15s ease;
272
+ }
273
+ .expand-enter-from[data-v-06a9c7b9],
274
+ .expand-leave-to[data-v-06a9c7b9] {
275
+ height: 0;
276
+ opacity: 0;
277
+ }
278
+ .expand-enter-to[data-v-06a9c7b9],
279
+ .expand-leave-from[data-v-06a9c7b9] {
280
+ height: var(--toolbar-height);
281
+ opacity: 1;
282
+ }