@lowdefy/blocks-tiptap 5.5.1 → 6.0.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 +27 -7
- 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 +91 -11
- 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/tests/TiptapMentionInput.e2e.yaml +140 -0
- package/dist/blocks/TiptapMentionInput/tests.yaml +90 -0
- package/dist/blocks/TiptapMentionInput/useTiptapMentionState.js +8 -5
- 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} +56 -50
- package/package.json +11 -10
- package/dist/blocks/TiptapInput/style.module.css +0 -60
- package/dist/blocks/utils/s3FileUpload.js +0 -53
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Copyright 2020-2026 Lowdefy, Inc
|
|
2
|
+
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
- id: default
|
|
16
|
+
type: TiptapMentionInput
|
|
17
|
+
- id: properties.placeholder
|
|
18
|
+
type: TiptapMentionInput
|
|
19
|
+
properties:
|
|
20
|
+
placeholder: 'Type @ to mention...'
|
|
21
|
+
- id: properties.disabled
|
|
22
|
+
type: TiptapMentionInput
|
|
23
|
+
properties:
|
|
24
|
+
disabled: true
|
|
25
|
+
- id: properties.mentions.options
|
|
26
|
+
type: TiptapMentionInput
|
|
27
|
+
properties:
|
|
28
|
+
mentions:
|
|
29
|
+
options:
|
|
30
|
+
- label: Alice
|
|
31
|
+
value:
|
|
32
|
+
_id: user_1
|
|
33
|
+
- label: Bob
|
|
34
|
+
value:
|
|
35
|
+
_id: user_2
|
|
36
|
+
- id: properties.mentions.char = '#'
|
|
37
|
+
type: TiptapMentionInput
|
|
38
|
+
properties:
|
|
39
|
+
placeholder: 'Type # to tag'
|
|
40
|
+
mentions:
|
|
41
|
+
char: '#'
|
|
42
|
+
options:
|
|
43
|
+
- label: bug
|
|
44
|
+
value:
|
|
45
|
+
_id: tag_bug
|
|
46
|
+
- id: properties.mentions.limit with sections
|
|
47
|
+
type: TiptapMentionInput
|
|
48
|
+
properties:
|
|
49
|
+
mentions:
|
|
50
|
+
limit: 2
|
|
51
|
+
options:
|
|
52
|
+
- label: Alice
|
|
53
|
+
value:
|
|
54
|
+
_id: user_1
|
|
55
|
+
tag:
|
|
56
|
+
section: People
|
|
57
|
+
- label: Bob
|
|
58
|
+
value:
|
|
59
|
+
_id: user_2
|
|
60
|
+
tag:
|
|
61
|
+
section: People
|
|
62
|
+
- label: Finance
|
|
63
|
+
value:
|
|
64
|
+
_id: role_finance
|
|
65
|
+
tag:
|
|
66
|
+
section: Roles
|
|
67
|
+
- id: properties.mentions group chips with tag.color
|
|
68
|
+
type: TiptapMentionInput
|
|
69
|
+
properties:
|
|
70
|
+
mentions:
|
|
71
|
+
options:
|
|
72
|
+
- label: Alice
|
|
73
|
+
value:
|
|
74
|
+
_id: user_1
|
|
75
|
+
tag:
|
|
76
|
+
section: People
|
|
77
|
+
- label: Finance
|
|
78
|
+
value:
|
|
79
|
+
role: finance-admin
|
|
80
|
+
tag:
|
|
81
|
+
section: Roles
|
|
82
|
+
group: finance
|
|
83
|
+
color: '#722ed1'
|
|
84
|
+
- label: Developers
|
|
85
|
+
value:
|
|
86
|
+
role: developer
|
|
87
|
+
tag:
|
|
88
|
+
section: Roles
|
|
89
|
+
group: devs
|
|
90
|
+
color: '#13c2c2'
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { useRef } from 'react';
|
|
16
16
|
import TurndownService from 'turndown';
|
|
17
|
-
import
|
|
17
|
+
import fileUpload from '../utils/fileUpload.js';
|
|
18
18
|
// Ref-tracked controller for the mention editor's value. Mirrors TiptapInput's
|
|
19
19
|
// useTiptapState but also extracts mentions from the document.
|
|
20
|
-
function useTiptapMentionState({ value, methods }) {
|
|
20
|
+
function useTiptapMentionState({ value, methods, hasDownloadRequest }) {
|
|
21
21
|
const valueRef = useRef(value);
|
|
22
22
|
valueRef.current = value;
|
|
23
23
|
const turndownService = new TurndownService();
|
|
@@ -43,7 +43,9 @@ function useTiptapMentionState({ value, methods }) {
|
|
|
43
43
|
const mentionsMap = new Map();
|
|
44
44
|
(json.content ?? []).filter((c)=>c.type === 'paragraph').forEach((c)=>{
|
|
45
45
|
c.content?.forEach((cc)=>{
|
|
46
|
-
|
|
46
|
+
// Only freshly picked mentions carry the option object; a node parsed
|
|
47
|
+
// back from saved html has a string id and no `value` to report.
|
|
48
|
+
if (cc.type === 'mention' && cc.attrs.id?.value !== undefined) {
|
|
47
49
|
mentionsMap.set(JSON.stringify(cc.attrs.id.value), cc.attrs.id.value);
|
|
48
50
|
}
|
|
49
51
|
});
|
|
@@ -58,9 +60,10 @@ function useTiptapMentionState({ value, methods }) {
|
|
|
58
60
|
});
|
|
59
61
|
};
|
|
60
62
|
const insertImage = async (editor, file, pos)=>{
|
|
61
|
-
const url = await
|
|
63
|
+
const url = await fileUpload({
|
|
62
64
|
file,
|
|
63
|
-
methods
|
|
65
|
+
methods,
|
|
66
|
+
hasDownloadRequest
|
|
64
67
|
});
|
|
65
68
|
// The upload is async: bail if the editor was torn down meanwhile (e.g. the
|
|
66
69
|
// surrounding page navigated away before the upload resolved), otherwise the
|
|
@@ -0,0 +1,63 @@
|
|
|
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 { type } from '@lowdefy/helpers';
|
|
16
|
+
import getLegacyObjectUrl from '@lowdefy/blocks-files/utils/getLegacyObjectUrl.js';
|
|
17
|
+
import getUploadPolicy from '@lowdefy/blocks-files/utils/getUploadPolicy.js';
|
|
18
|
+
import uploadFile from '@lowdefy/blocks-files/utils/uploadFile.js';
|
|
19
|
+
// Uploads a file through the app's upload-policy request (any storage
|
|
20
|
+
// provider) and resolves a display URL for the inline image. Inline images
|
|
21
|
+
// persist in saved markdown, so they must be public assets: the upload
|
|
22
|
+
// request should set the provider's public-read acl, and the download request
|
|
23
|
+
// should set public: true to return a stable, non-expiring URL. Without a
|
|
24
|
+
// download request the legacy unsigned object URL is used (S3-shaped,
|
|
25
|
+
// deprecated).
|
|
26
|
+
async function fileUpload({ file, methods, hasDownloadRequest }) {
|
|
27
|
+
if (type.isNone(file)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const descriptor = await getUploadPolicy({
|
|
31
|
+
methods,
|
|
32
|
+
file
|
|
33
|
+
});
|
|
34
|
+
file.bucket = descriptor.bucket;
|
|
35
|
+
file.key = descriptor.key;
|
|
36
|
+
await uploadFile({
|
|
37
|
+
descriptor,
|
|
38
|
+
file
|
|
39
|
+
});
|
|
40
|
+
if (hasDownloadRequest) {
|
|
41
|
+
const response = await methods.triggerEvent({
|
|
42
|
+
name: '__getDownloadPolicy',
|
|
43
|
+
event: {
|
|
44
|
+
file: {
|
|
45
|
+
bucket: descriptor.bucket,
|
|
46
|
+
key: descriptor.key,
|
|
47
|
+
name: file.name,
|
|
48
|
+
type: file.type
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
if (response.success !== true) {
|
|
53
|
+
throw new Error('Download policy request error.');
|
|
54
|
+
}
|
|
55
|
+
file.url = response.responses.__getDownloadPolicy.response[0];
|
|
56
|
+
return file.url;
|
|
57
|
+
}
|
|
58
|
+
file.url = getLegacyObjectUrl({
|
|
59
|
+
descriptor
|
|
60
|
+
});
|
|
61
|
+
return file.url;
|
|
62
|
+
}
|
|
63
|
+
export default fileUpload;
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ // Map validation.status → wrapper class. Matches the visual behavior of
|
|
16
16
|
// passing status="error" | "warning" to an antd <Input />, but rendered
|
|
17
|
-
// with our own CSS (see utils/style.
|
|
17
|
+
// with our own CSS (see utils/style.css) because antd v6 uses
|
|
18
18
|
// CSS-in-JS, so the .ant-input-status-* classes are not global.
|
|
19
19
|
function statusClass(status) {
|
|
20
20
|
if (status === 'error') return 'tiptap-wrapper-error';
|
|
@@ -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,16 @@
|
|
|
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
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lowdefy/blocks-tiptap",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Lowdefy TipTap rich-text editor blocks.",
|
|
6
6
|
"homepage": "https://lowdefy.com",
|
|
@@ -46,9 +46,10 @@
|
|
|
46
46
|
"dist/*"
|
|
47
47
|
],
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@lowdefy/block-utils": "
|
|
50
|
-
"@lowdefy/blocks-antd": "
|
|
51
|
-
"@lowdefy/
|
|
49
|
+
"@lowdefy/block-utils": "6.0.0",
|
|
50
|
+
"@lowdefy/blocks-antd": "6.0.0",
|
|
51
|
+
"@lowdefy/blocks-files": "6.0.0",
|
|
52
|
+
"@lowdefy/helpers": "6.0.0",
|
|
52
53
|
"@tiptap/core": "2.27.2",
|
|
53
54
|
"@tiptap/extension-bubble-menu": "2.27.2",
|
|
54
55
|
"@tiptap/extension-file-handler": "2.27.2",
|
|
@@ -73,11 +74,11 @@
|
|
|
73
74
|
"react-dom": ">=18"
|
|
74
75
|
},
|
|
75
76
|
"devDependencies": {
|
|
76
|
-
"@lowdefy/block-dev-e2e": "
|
|
77
|
-
"@lowdefy/e2e-utils": "
|
|
78
|
-
"@playwright/test": "1.
|
|
79
|
-
"@swc/cli": "0.8.
|
|
80
|
-
"@swc/core": "1.15.
|
|
77
|
+
"@lowdefy/block-dev-e2e": "6.0.0",
|
|
78
|
+
"@lowdefy/e2e-utils": "6.0.0",
|
|
79
|
+
"@playwright/test": "1.59.1",
|
|
80
|
+
"@swc/cli": "0.8.1",
|
|
81
|
+
"@swc/core": "1.15.32",
|
|
81
82
|
"copyfiles": "2.4.1"
|
|
82
83
|
},
|
|
83
84
|
"publishConfig": {
|
|
@@ -86,7 +87,7 @@
|
|
|
86
87
|
"scripts": {
|
|
87
88
|
"build": "swc src --out-dir dist --config-file ../../../../.swcrc --cli-config-file ../../../../.swc-cli.json && pnpm copyfiles",
|
|
88
89
|
"clean": "rm -rf dist",
|
|
89
|
-
"copyfiles": "copyfiles -u 1 \"./src/**/*\" dist -e \"./src/**/*.js\" -e \"./src/**/*.
|
|
90
|
+
"copyfiles": "copyfiles -u 1 \"./src/**/*\" dist -e \"./src/**/*.js\" -e \"./src/**/*.snap\"",
|
|
90
91
|
"e2e": "playwright test --config e2e/playwright.config.js",
|
|
91
92
|
"e2e:ui": "playwright test --config e2e/playwright.config.js --ui"
|
|
92
93
|
}
|
|
@@ -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;
|