@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.
- package/CHANGELOG.md +7 -0
- package/LICENSE +710 -0
- package/README.md +116 -0
- package/dist/index.css +282 -0
- package/dist/index.js +917 -0
- package/dist/index.js.map +1 -0
- package/dist/src/KdsRichTextEditor.vue.d.ts +35 -0
- package/dist/src/KdsRichTextEditor.vue.d.ts.map +1 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/toolbar/KdsCreateLinkModal.vue.d.ts +459 -0
- package/dist/src/toolbar/KdsCreateLinkModal.vue.d.ts.map +1 -0
- package/dist/src/toolbar/RichTextEditorBaseToolbar.vue.d.ts +48 -0
- package/dist/src/toolbar/RichTextEditorBaseToolbar.vue.d.ts.map +1 -0
- package/dist/src/toolbar/RichTextEditorToolbar.vue.d.ts +10 -0
- package/dist/src/toolbar/RichTextEditorToolbar.vue.d.ts.map +1 -0
- package/dist/src/toolbar/types.d.ts +29 -0
- package/dist/src/toolbar/types.d.ts.map +1 -0
- package/dist/src/toolbar/useLinkTool.d.ts +22 -0
- package/dist/src/toolbar/useLinkTool.d.ts.map +1 -0
- package/dist/src/types.d.ts +112 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/utils/custom-escape.d.ts +15 -0
- package/dist/src/utils/custom-escape.d.ts.map +1 -0
- package/dist/src/utils/custom-hard-break.d.ts +2 -0
- package/dist/src/utils/custom-hard-break.d.ts.map +1 -0
- package/dist/src/utils/custom-link.d.ts +16 -0
- package/dist/src/utils/custom-link.d.ts.map +1 -0
- package/dist/src/utils/custom-text-align.d.ts +2 -0
- package/dist/src/utils/custom-text-align.d.ts.map +1 -0
- package/dist/src/utils/paragraphTextStyle/extension.d.ts +17 -0
- package/dist/src/utils/paragraphTextStyle/extension.d.ts.map +1 -0
- package/dist/src/utils/paragraphTextStyle/index.d.ts +4 -0
- package/dist/src/utils/paragraphTextStyle/index.d.ts.map +1 -0
- 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
|
+
}
|