@lowdefy/blocks-tiptap 5.6.0 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blocks/TiptapInput/TiptapInput.js +37 -81
- package/dist/blocks/TiptapInput/gallery.yaml +210 -0
- package/dist/blocks/TiptapInput/meta.js +10 -2
- package/dist/blocks/TiptapInput/style.css +60 -0
- package/dist/blocks/TiptapInput/tests/TiptapInput.e2e.yaml +53 -0
- package/dist/blocks/TiptapInput/tests.yaml +65 -0
- package/dist/blocks/TiptapInput/useTiptapState.js +6 -5
- package/dist/blocks/TiptapMentionInput/TiptapMentionInput.js +37 -80
- package/dist/blocks/TiptapMentionInput/gallery.yaml +296 -0
- package/dist/blocks/TiptapMentionInput/meta.js +10 -2
- package/dist/blocks/TiptapMentionInput/{style.module.css → style.css} +39 -39
- package/dist/blocks/TiptapMentionInput/suggestion.js +60 -40
- package/dist/blocks/TiptapMentionInput/tests/TiptapMentionInput.e2e.yaml +140 -0
- package/dist/blocks/TiptapMentionInput/tests.yaml +90 -0
- package/dist/blocks/TiptapMentionInput/useTiptapMentionState.js +5 -4
- package/dist/blocks/utils/PopoverMenu.js +54 -21
- package/dist/blocks/utils/buildExtensions.js +11 -13
- package/dist/blocks/utils/buildStarterKit.js +48 -0
- package/dist/blocks/utils/fileUpload.js +63 -0
- package/dist/blocks/utils/statusClass.js +1 -1
- package/dist/blocks/utils/{style.module.css → style.css} +64 -50
- package/dist/blocks/utils/useTiptapEditor.js +106 -0
- package/package.json +24 -25
- package/dist/blocks/TiptapInput/style.module.css +0 -60
- package/dist/blocks/utils/s3FileUpload.js +0 -53
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
stylesheet class — we replicate the input look using antd's theme
|
|
4
4
|
CSS variables (--ant-color-*, --ant-border-radius) so the block
|
|
5
5
|
tracks the active theme without depending on cssinjs. */
|
|
6
|
-
|
|
6
|
+
.tiptap-wrapper {
|
|
7
7
|
border: 1px solid var(--ant-color-border, #d9d9d9);
|
|
8
8
|
border-radius: var(--ant-border-radius, 6px);
|
|
9
9
|
background: var(--ant-color-bg-container, #fff);
|
|
@@ -13,73 +13,79 @@
|
|
|
13
13
|
box-shadow 0.2s,
|
|
14
14
|
background 0.2s;
|
|
15
15
|
padding: 0;
|
|
16
|
+
/* Column flex so the editable fills the wrapper's min-height (see ProseMirror rule), making the
|
|
17
|
+
whole multi-line box a click/focus target — not just the first line of content. */
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
.tiptap-wrapper:hover {
|
|
19
23
|
border-color: var(--ant-color-primary-hover, #4096ff);
|
|
20
24
|
}
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
.tiptap-wrapper:focus-within {
|
|
23
27
|
border-color: var(--ant-color-primary, #1677ff);
|
|
24
28
|
box-shadow: 0 0 0 2px var(--ant-color-primary-bg, rgba(22, 119, 255, 0.1));
|
|
25
29
|
outline: none;
|
|
26
30
|
}
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
.tiptap-wrapper-borderless {
|
|
29
33
|
border-color: transparent;
|
|
30
34
|
background: transparent;
|
|
31
35
|
}
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
.tiptap-wrapper-borderless:hover,
|
|
38
|
+
.tiptap-wrapper-borderless:focus-within {
|
|
35
39
|
border-color: transparent;
|
|
36
40
|
box-shadow: none;
|
|
37
41
|
}
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
.tiptap-wrapper-error {
|
|
40
44
|
border-color: var(--ant-color-error, #ff4d4f);
|
|
41
45
|
}
|
|
42
46
|
|
|
43
|
-
|
|
47
|
+
.tiptap-wrapper-error:hover {
|
|
44
48
|
border-color: var(--ant-color-error-hover, var(--ant-color-error, #ff4d4f));
|
|
45
49
|
}
|
|
46
50
|
|
|
47
|
-
|
|
51
|
+
.tiptap-wrapper-error:focus-within {
|
|
48
52
|
border-color: var(--ant-color-error, #ff4d4f);
|
|
49
53
|
box-shadow: 0 0 0 2px var(--ant-color-error-bg, rgba(255, 77, 79, 0.1));
|
|
50
54
|
}
|
|
51
55
|
|
|
52
|
-
|
|
56
|
+
.tiptap-wrapper-warning {
|
|
53
57
|
border-color: var(--ant-color-warning, #faad14);
|
|
54
58
|
}
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
.tiptap-wrapper-warning:hover {
|
|
57
61
|
border-color: var(--ant-color-warning-hover, var(--ant-color-warning, #faad14));
|
|
58
62
|
}
|
|
59
63
|
|
|
60
|
-
|
|
64
|
+
.tiptap-wrapper-warning:focus-within {
|
|
61
65
|
border-color: var(--ant-color-warning, #faad14);
|
|
62
66
|
box-shadow: 0 0 0 2px var(--ant-color-warning-bg, rgba(250, 173, 20, 0.1));
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
|
|
69
|
+
.tiptap-wrapper-disabled {
|
|
66
70
|
background: var(--ant-color-bg-container-disabled, rgba(0, 0, 0, 0.04));
|
|
67
71
|
color: var(--ant-color-text-disabled, rgba(0, 0, 0, 0.25));
|
|
68
72
|
cursor: not-allowed;
|
|
69
73
|
}
|
|
70
74
|
|
|
71
|
-
|
|
75
|
+
.tiptap-wrapper-disabled:hover {
|
|
72
76
|
border-color: var(--ant-color-border, #d9d9d9);
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
|
|
79
|
+
.tiptap-wrapper-disabled .tiptap.ProseMirror {
|
|
76
80
|
cursor: not-allowed;
|
|
77
81
|
}
|
|
78
82
|
|
|
79
|
-
/* ProseMirror editable — sits inside the wrapper.
|
|
80
|
-
|
|
83
|
+
/* ProseMirror editable — sits inside the wrapper. Grow to fill the wrapper's min-height so a click
|
|
84
|
+
anywhere in the box (not only the first content line) lands in the editor and places the cursor. */
|
|
85
|
+
.tiptap.ProseMirror {
|
|
81
86
|
padding: 8px;
|
|
82
87
|
outline: none;
|
|
88
|
+
flex: 1 1 auto;
|
|
83
89
|
}
|
|
84
90
|
|
|
85
91
|
/* Editor content styling.
|
|
@@ -100,38 +106,38 @@
|
|
|
100
106
|
|
|
101
107
|
/* Paragraphs: a small gap so successive lines (each a new <p> from pressing
|
|
102
108
|
Enter) read as separate lines instead of merging. */
|
|
103
|
-
|
|
109
|
+
.tiptap p {
|
|
104
110
|
margin: 0 0 0.5em;
|
|
105
111
|
}
|
|
106
112
|
|
|
107
|
-
|
|
113
|
+
.tiptap > p:last-child {
|
|
108
114
|
margin-bottom: 0;
|
|
109
115
|
}
|
|
110
116
|
|
|
111
117
|
/* Lists: restore the markers and indent the antd reset removes. */
|
|
112
|
-
|
|
113
|
-
|
|
118
|
+
.tiptap ul,
|
|
119
|
+
.tiptap ol {
|
|
114
120
|
margin: 0 0 0.5em;
|
|
115
121
|
padding-left: 1.5em;
|
|
116
122
|
}
|
|
117
123
|
|
|
118
|
-
|
|
124
|
+
.tiptap ul {
|
|
119
125
|
list-style: disc;
|
|
120
126
|
}
|
|
121
127
|
|
|
122
|
-
|
|
128
|
+
.tiptap ol {
|
|
123
129
|
list-style: decimal;
|
|
124
130
|
}
|
|
125
131
|
|
|
126
132
|
/* Keep paragraphs inside list items and nested lists tight. */
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
133
|
+
.tiptap li p,
|
|
134
|
+
.tiptap li ul,
|
|
135
|
+
.tiptap li ol {
|
|
130
136
|
margin-bottom: 0;
|
|
131
137
|
}
|
|
132
138
|
|
|
133
139
|
/* Blockquote: restore the indent and add a quote bar. */
|
|
134
|
-
|
|
140
|
+
.tiptap blockquote {
|
|
135
141
|
margin: 0 0 0.5em;
|
|
136
142
|
padding-left: 1em;
|
|
137
143
|
border-left: 3px solid var(--ant-color-border, #d9d9d9);
|
|
@@ -140,44 +146,44 @@
|
|
|
140
146
|
|
|
141
147
|
/* Headings: the reset flattens all six to weight 500 with no size scale.
|
|
142
148
|
Restore a distinct, descending scale so heading levels are visible. */
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
+
.tiptap h1,
|
|
150
|
+
.tiptap h2,
|
|
151
|
+
.tiptap h3,
|
|
152
|
+
.tiptap h4,
|
|
153
|
+
.tiptap h5,
|
|
154
|
+
.tiptap h6 {
|
|
149
155
|
margin: 0 0 0.5em;
|
|
150
156
|
font-weight: 600;
|
|
151
157
|
line-height: 1.3;
|
|
152
158
|
}
|
|
153
159
|
|
|
154
|
-
|
|
160
|
+
.tiptap h1 {
|
|
155
161
|
font-size: 2em;
|
|
156
162
|
}
|
|
157
163
|
|
|
158
|
-
|
|
164
|
+
.tiptap h2 {
|
|
159
165
|
font-size: 1.5em;
|
|
160
166
|
}
|
|
161
167
|
|
|
162
|
-
|
|
168
|
+
.tiptap h3 {
|
|
163
169
|
font-size: 1.25em;
|
|
164
170
|
}
|
|
165
171
|
|
|
166
|
-
|
|
172
|
+
.tiptap h4 {
|
|
167
173
|
font-size: 1.1em;
|
|
168
174
|
}
|
|
169
175
|
|
|
170
|
-
|
|
176
|
+
.tiptap h5 {
|
|
171
177
|
font-size: 1em;
|
|
172
178
|
}
|
|
173
179
|
|
|
174
|
-
|
|
180
|
+
.tiptap h6 {
|
|
175
181
|
font-size: 0.9em;
|
|
176
182
|
}
|
|
177
183
|
|
|
178
184
|
/* Horizontal rule: the reset sets height 0 with no border, making it invisible.
|
|
179
185
|
Render it as a themed divider. */
|
|
180
|
-
|
|
186
|
+
.tiptap hr {
|
|
181
187
|
height: 0;
|
|
182
188
|
margin: 0.5em 0;
|
|
183
189
|
border: none;
|
|
@@ -186,7 +192,7 @@
|
|
|
186
192
|
|
|
187
193
|
/* Inline code: monospace from the reset, but no background — give it the
|
|
188
194
|
code chip look. */
|
|
189
|
-
|
|
195
|
+
.tiptap code {
|
|
190
196
|
padding: 0.1em 0.3em;
|
|
191
197
|
border-radius: var(--ant-border-radius-sm, 4px);
|
|
192
198
|
background: var(--ant-color-fill-tertiary, rgba(0, 0, 0, 0.04));
|
|
@@ -195,7 +201,7 @@
|
|
|
195
201
|
|
|
196
202
|
/* Code block: a padded, scrollable monospace box. The nested <code> resets to
|
|
197
203
|
plain so it doesn't inherit the inline-code chip styling above. */
|
|
198
|
-
|
|
204
|
+
.tiptap pre {
|
|
199
205
|
margin: 0 0 0.5em;
|
|
200
206
|
padding: 8px 12px;
|
|
201
207
|
border-radius: var(--ant-border-radius, 6px);
|
|
@@ -203,7 +209,7 @@
|
|
|
203
209
|
overflow-x: auto;
|
|
204
210
|
}
|
|
205
211
|
|
|
206
|
-
|
|
212
|
+
.tiptap pre code {
|
|
207
213
|
padding: 0;
|
|
208
214
|
border-radius: 0;
|
|
209
215
|
background: none;
|
|
@@ -213,12 +219,12 @@
|
|
|
213
219
|
/* Highlight marks normally carry an inline background-color from the extension;
|
|
214
220
|
this is a fallback so a color-less <mark> (e.g. pasted or seeded HTML) stays
|
|
215
221
|
visible instead of blending into the text. */
|
|
216
|
-
|
|
222
|
+
.tiptap mark {
|
|
217
223
|
background-color: var(--ant-color-warning-bg, rgba(255, 229, 143, 0.5));
|
|
218
224
|
color: inherit;
|
|
219
225
|
}
|
|
220
226
|
|
|
221
|
-
|
|
227
|
+
.tiptap p.is-editor-empty:first-child::before {
|
|
222
228
|
color: var(--ant-color-text-placeholder, rgba(0, 0, 0, 0.25));
|
|
223
229
|
content: attr(data-placeholder);
|
|
224
230
|
float: left;
|
|
@@ -226,7 +232,7 @@
|
|
|
226
232
|
pointer-events: none;
|
|
227
233
|
}
|
|
228
234
|
|
|
229
|
-
|
|
235
|
+
.tiptap-popover {
|
|
230
236
|
background: rgba(0, 0, 0, 0.85);
|
|
231
237
|
color: var(--ant-color-text-light-solid, #fff);
|
|
232
238
|
border-radius: var(--ant-border-radius, 8px);
|
|
@@ -235,7 +241,7 @@
|
|
|
235
241
|
display: flex;
|
|
236
242
|
}
|
|
237
243
|
|
|
238
|
-
|
|
244
|
+
.tiptap-icon {
|
|
239
245
|
border-radius: var(--ant-border-radius-sm, 4px);
|
|
240
246
|
display: flex;
|
|
241
247
|
width: 16px;
|
|
@@ -245,16 +251,24 @@
|
|
|
245
251
|
color: var(--ant-color-text-light-solid, #fff);
|
|
246
252
|
}
|
|
247
253
|
|
|
248
|
-
|
|
254
|
+
.tiptap-icon.disabled {
|
|
249
255
|
pointer-events: none;
|
|
250
256
|
}
|
|
251
257
|
|
|
252
|
-
|
|
258
|
+
.tiptap-icon:hover {
|
|
253
259
|
background: var(--ant-color-icon-hover, rgba(0, 0, 0, 0.75));
|
|
254
260
|
color: var(--ant-color-text-light-solid, #fff);
|
|
255
261
|
cursor: pointer;
|
|
256
262
|
}
|
|
257
263
|
|
|
258
|
-
|
|
264
|
+
.tiptap-icon + .tiptap-icon {
|
|
259
265
|
margin-left: 4px;
|
|
260
266
|
}
|
|
267
|
+
|
|
268
|
+
/* TipTap v2 injected this rule into every page with an editor; v3 does not.
|
|
269
|
+
The mention suggestion and group-members popovers are tippy.js popups, which
|
|
270
|
+
fade in with it and only unmount a hidden popup once that fade-out ends, so
|
|
271
|
+
without it a popup hidden by an outside click would stay on screen. */
|
|
272
|
+
.tippy-box[data-animation='fade'][data-state='hidden'] {
|
|
273
|
+
opacity: 0;
|
|
274
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import { useEffect, useRef } from 'react';
|
|
16
|
+
import { useEditor } from '@tiptap/react';
|
|
17
|
+
import buildExtensions from './buildExtensions.js';
|
|
18
|
+
// The TipTap editor of the TiptapInput and TiptapMentionInput blocks: creates it, registers the
|
|
19
|
+
// block's clear, setContent and focus methods, and keeps it in sync with the block's value,
|
|
20
|
+
// disabled state and placeholder.
|
|
21
|
+
function useTiptapEditor({ disabled, editorProps = {}, emit, insertImage, mentionExtension, methods, properties, uploadEnabled, value }) {
|
|
22
|
+
// The Placeholder extension is created once, so it reads the current text from a ref.
|
|
23
|
+
const placeholderRef = useRef();
|
|
24
|
+
placeholderRef.current = properties.placeholder ?? '';
|
|
25
|
+
const extensions = buildExtensions({
|
|
26
|
+
properties,
|
|
27
|
+
getPlaceholder: ()=>placeholderRef.current,
|
|
28
|
+
insertImage,
|
|
29
|
+
mentionExtension,
|
|
30
|
+
uploadEnabled
|
|
31
|
+
});
|
|
32
|
+
const editor = useEditor({
|
|
33
|
+
editorProps,
|
|
34
|
+
extensions,
|
|
35
|
+
content: value?.html || '',
|
|
36
|
+
editable: ()=>!disabled,
|
|
37
|
+
onUpdate ({ editor }) {
|
|
38
|
+
// User-driven change. Emit the full derived value to Lowdefy.
|
|
39
|
+
emit(editor);
|
|
40
|
+
methods.triggerEvent({
|
|
41
|
+
name: 'onChange'
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
// Register methods as soon as the editor is available.
|
|
46
|
+
useEffect(()=>{
|
|
47
|
+
if (!editor) return;
|
|
48
|
+
// emitUpdate false: the methods emit the value themselves and must not trigger onChange.
|
|
49
|
+
methods.registerMethod('clear', ()=>{
|
|
50
|
+
editor.commands.clearContent(false);
|
|
51
|
+
emit(editor);
|
|
52
|
+
});
|
|
53
|
+
methods.registerMethod('setContent', (args)=>{
|
|
54
|
+
editor.commands.setContent(args?.html ?? '', {
|
|
55
|
+
emitUpdate: false
|
|
56
|
+
});
|
|
57
|
+
emit(editor);
|
|
58
|
+
});
|
|
59
|
+
methods.registerMethod('focus', ()=>{
|
|
60
|
+
editor.commands.focus();
|
|
61
|
+
});
|
|
62
|
+
}, [
|
|
63
|
+
editor
|
|
64
|
+
]);
|
|
65
|
+
// External value.html → editor sync. One-way only: we read value.html and
|
|
66
|
+
// push it into the editor with emitUpdate false so tiptap's onUpdate
|
|
67
|
+
// does not fire. No write-back via emit() — that would race with concurrent
|
|
68
|
+
// SetState calls (child effects fire before parent effects, so a sibling's
|
|
69
|
+
// onMount SetState could be overwritten by our derived emit). Derived
|
|
70
|
+
// fields (text/markdown/fileList, and mentions for TiptapMentionInput) are
|
|
71
|
+
// populated on user interaction via onUpdate; downstream consumers of seeded
|
|
72
|
+
// content should read value.html directly, or include the fields they need
|
|
73
|
+
// in their SetState payload.
|
|
74
|
+
useEffect(()=>{
|
|
75
|
+
if (!editor) return;
|
|
76
|
+
const next = value?.html ?? '';
|
|
77
|
+
const current = editor.getHTML();
|
|
78
|
+
if (next !== current) {
|
|
79
|
+
editor.commands.setContent(next, {
|
|
80
|
+
emitUpdate: false
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}, [
|
|
84
|
+
value?.html,
|
|
85
|
+
editor
|
|
86
|
+
]);
|
|
87
|
+
useEffect(()=>{
|
|
88
|
+
if (!editor) return;
|
|
89
|
+
editor.setOptions({
|
|
90
|
+
editable: !disabled
|
|
91
|
+
});
|
|
92
|
+
}, [
|
|
93
|
+
editor,
|
|
94
|
+
disabled
|
|
95
|
+
]);
|
|
96
|
+
// Redraw the placeholder when its text changes.
|
|
97
|
+
useEffect(()=>{
|
|
98
|
+
if (!editor) return;
|
|
99
|
+
editor.view.dispatch(editor.state.tr);
|
|
100
|
+
}, [
|
|
101
|
+
editor,
|
|
102
|
+
properties.placeholder
|
|
103
|
+
]);
|
|
104
|
+
return editor;
|
|
105
|
+
}
|
|
106
|
+
export default useTiptapEditor;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lowdefy/blocks-tiptap",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.1.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Lowdefy TipTap rich-text editor blocks.",
|
|
6
6
|
"homepage": "https://lowdefy.com",
|
|
@@ -46,24 +46,23 @@
|
|
|
46
46
|
"dist/*"
|
|
47
47
|
],
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@lowdefy/block-utils": "
|
|
50
|
-
"@lowdefy/blocks-antd": "
|
|
51
|
-
"@lowdefy/
|
|
52
|
-
"@
|
|
53
|
-
"@tiptap/
|
|
54
|
-
"@tiptap/extension-
|
|
55
|
-
"@tiptap/extension-
|
|
56
|
-
"@tiptap/extension-
|
|
57
|
-
"@tiptap/extension-
|
|
58
|
-
"@tiptap/extension-
|
|
59
|
-
"@tiptap/extension-
|
|
60
|
-
"@tiptap/extension-table": "
|
|
61
|
-
"@tiptap/
|
|
62
|
-
"@tiptap/
|
|
63
|
-
"@tiptap/
|
|
64
|
-
"@tiptap/
|
|
65
|
-
"@tiptap/
|
|
66
|
-
"@tiptap/starter-kit": "2.27.2",
|
|
49
|
+
"@lowdefy/block-utils": "6.1.0",
|
|
50
|
+
"@lowdefy/blocks-antd": "6.1.0",
|
|
51
|
+
"@lowdefy/blocks-files": "6.1.0",
|
|
52
|
+
"@lowdefy/helpers": "6.1.0",
|
|
53
|
+
"@tiptap/core": "3.31.3",
|
|
54
|
+
"@tiptap/extension-bubble-menu": "3.31.3",
|
|
55
|
+
"@tiptap/extension-file-handler": "3.31.3",
|
|
56
|
+
"@tiptap/extension-highlight": "3.31.3",
|
|
57
|
+
"@tiptap/extension-image": "3.31.3",
|
|
58
|
+
"@tiptap/extension-link": "3.31.3",
|
|
59
|
+
"@tiptap/extension-mention": "3.31.3",
|
|
60
|
+
"@tiptap/extension-table": "3.31.3",
|
|
61
|
+
"@tiptap/extensions": "3.31.3",
|
|
62
|
+
"@tiptap/pm": "3.31.3",
|
|
63
|
+
"@tiptap/react": "3.31.3",
|
|
64
|
+
"@tiptap/starter-kit": "3.31.3",
|
|
65
|
+
"@tiptap/suggestion": "3.31.3",
|
|
67
66
|
"react-icons": "5.6.0",
|
|
68
67
|
"tippy.js": "6.3.7",
|
|
69
68
|
"turndown": "7.2.0"
|
|
@@ -73,11 +72,11 @@
|
|
|
73
72
|
"react-dom": ">=18"
|
|
74
73
|
},
|
|
75
74
|
"devDependencies": {
|
|
76
|
-
"@lowdefy/block-dev-e2e": "
|
|
77
|
-
"@lowdefy/e2e-utils": "
|
|
78
|
-
"@playwright/test": "1.
|
|
79
|
-
"@swc/cli": "0.8.
|
|
80
|
-
"@swc/core": "1.15.
|
|
75
|
+
"@lowdefy/block-dev-e2e": "6.1.0",
|
|
76
|
+
"@lowdefy/e2e-utils": "6.1.0",
|
|
77
|
+
"@playwright/test": "1.59.1",
|
|
78
|
+
"@swc/cli": "0.8.1",
|
|
79
|
+
"@swc/core": "1.15.32",
|
|
81
80
|
"copyfiles": "2.4.1"
|
|
82
81
|
},
|
|
83
82
|
"publishConfig": {
|
|
@@ -86,7 +85,7 @@
|
|
|
86
85
|
"scripts": {
|
|
87
86
|
"build": "swc src --out-dir dist --config-file ../../../../.swcrc --cli-config-file ../../../../.swc-cli.json && pnpm copyfiles",
|
|
88
87
|
"clean": "rm -rf dist",
|
|
89
|
-
"copyfiles": "copyfiles -u 1 \"./src/**/*\" dist -e \"./src/**/*.js\" -e \"./src/**/*.
|
|
88
|
+
"copyfiles": "copyfiles -u 1 \"./src/**/*\" dist -e \"./src/**/*.js\" -e \"./src/**/*.snap\"",
|
|
90
89
|
"e2e": "playwright test --config e2e/playwright.config.js",
|
|
91
90
|
"e2e:ui": "playwright test --config e2e/playwright.config.js --ui"
|
|
92
91
|
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
@import '../utils/style.module.css';
|
|
2
|
-
|
|
3
|
-
:global(.tableWrapper),
|
|
4
|
-
:global(.tiptap-table) {
|
|
5
|
-
display: block;
|
|
6
|
-
overflow-x: auto;
|
|
7
|
-
max-width: 80%;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
:global(.tableWrapper) :global(table),
|
|
11
|
-
:global(.tiptap-table) :global(table) {
|
|
12
|
-
border-collapse: collapse;
|
|
13
|
-
width: 100%;
|
|
14
|
-
min-width: 75px;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
:global(.tableWrapper) :global(colgroup) :global(col),
|
|
18
|
-
:global(.tiptap-table) :global(colgroup) :global(col) {
|
|
19
|
-
width: auto;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
:global(.tableWrapper) :global(table),
|
|
23
|
-
:global(.tableWrapper) :global(th),
|
|
24
|
-
:global(.tableWrapper) :global(td),
|
|
25
|
-
:global(.tiptap-table) :global(table),
|
|
26
|
-
:global(.tiptap-table) :global(th),
|
|
27
|
-
:global(.tiptap-table) :global(td) {
|
|
28
|
-
border: 1px solid var(--ant-color-border);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
:global(.tableWrapper) :global(th),
|
|
32
|
-
:global(.tableWrapper) :global(td),
|
|
33
|
-
:global(.tiptap-table) :global(th),
|
|
34
|
-
:global(.tiptap-table) :global(td) {
|
|
35
|
-
padding: 2px;
|
|
36
|
-
text-align: left;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
:global(.tableWrapper) :global(th),
|
|
40
|
-
:global(.tiptap-table) :global(th) {
|
|
41
|
-
background-color: var(--ant-color-fill-tertiary);
|
|
42
|
-
font-weight: bold;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
:global(.tableWrapper) :global(tr):nth-child(even),
|
|
46
|
-
:global(.tiptap-table) :global(tr):nth-child(even) {
|
|
47
|
-
background-color: var(--ant-color-fill-quaternary);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
:global(.tableWrapper) :global(tr):hover,
|
|
51
|
-
:global(.tiptap-table) :global(tr):hover {
|
|
52
|
-
background-color: var(--ant-color-primary-bg);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
:global(.tableWrapper) :global(td) :global(p),
|
|
56
|
-
:global(.tableWrapper) :global(th) :global(p),
|
|
57
|
-
:global(.tiptap-table) :global(td) :global(p),
|
|
58
|
-
:global(.tiptap-table) :global(th) :global(p) {
|
|
59
|
-
margin: 0;
|
|
60
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
-
|
|
4
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
you may not use this file except in compliance with the License.
|
|
6
|
-
You may obtain a copy of the License at
|
|
7
|
-
|
|
8
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
|
|
10
|
-
Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
See the License for the specific language governing permissions and
|
|
14
|
-
limitations under the License.
|
|
15
|
-
*/ async function s3FileUpload({ file, methods }) {
|
|
16
|
-
if (!file) {
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
const { lastModified, name, size, type, uid } = file;
|
|
20
|
-
const s3PostPolicyResponse = await methods.triggerEvent({
|
|
21
|
-
name: '__getS3PostPolicy',
|
|
22
|
-
event: {
|
|
23
|
-
file: {
|
|
24
|
-
name,
|
|
25
|
-
lastModified,
|
|
26
|
-
size,
|
|
27
|
-
type,
|
|
28
|
-
uid
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
if (s3PostPolicyResponse.success !== true) {
|
|
33
|
-
throw new Error('S3 post policy request error.');
|
|
34
|
-
}
|
|
35
|
-
const { url, fields } = s3PostPolicyResponse.responses.__getS3PostPolicy.response[0];
|
|
36
|
-
const { bucket, key } = fields;
|
|
37
|
-
file.bucket = bucket;
|
|
38
|
-
file.key = key;
|
|
39
|
-
const formData = new FormData();
|
|
40
|
-
Object.keys(fields).forEach((field)=>{
|
|
41
|
-
formData.append(field, fields[field]);
|
|
42
|
-
});
|
|
43
|
-
formData.append('file', file);
|
|
44
|
-
await fetch(url, {
|
|
45
|
-
method: 'POST',
|
|
46
|
-
body: formData
|
|
47
|
-
});
|
|
48
|
-
// createPresignedPost returns the bucket endpoint with a trailing slash, so only
|
|
49
|
-
// add a separator when it is missing to avoid a double slash before the key.
|
|
50
|
-
file.url = url.endsWith('/') ? `${url}${key}` : `${url}/${key}`;
|
|
51
|
-
return file.url;
|
|
52
|
-
}
|
|
53
|
-
export default s3FileUpload;
|