@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
|
@@ -15,114 +15,70 @@
|
|
|
15
15
|
*/ import React, { useEffect } from 'react';
|
|
16
16
|
import { withBlockDefaults } from '@lowdefy/block-utils';
|
|
17
17
|
import { type } from '@lowdefy/helpers';
|
|
18
|
-
import {
|
|
18
|
+
import { EditorContent } from '@tiptap/react';
|
|
19
19
|
import Label from '@lowdefy/blocks-antd/blocks/Label/Label.js';
|
|
20
20
|
import PopoverMenu from '../utils/PopoverMenu.js';
|
|
21
|
-
import buildExtensions from '../utils/buildExtensions.js';
|
|
22
21
|
import computeHeightStyle from '../utils/computeHeightStyle.js';
|
|
23
22
|
import statusClass from '../utils/statusClass.js';
|
|
23
|
+
import useTiptapEditor from '../utils/useTiptapEditor.js';
|
|
24
24
|
import useTiptapState from './useTiptapState.js';
|
|
25
|
-
import './style.
|
|
25
|
+
import './style.css';
|
|
26
26
|
const TiptapInput = ({ blockId, components: { Icon, Link }, events, loading, methods, properties, required, validation, value })=>{
|
|
27
|
+
const uploadPolicyRequestId = properties.uploadPolicyRequestId ?? properties.s3PostPolicyRequestId;
|
|
28
|
+
const downloadPolicyRequestId = properties.downloadPolicyRequestId;
|
|
27
29
|
const { emit, insertImage } = useTiptapState({
|
|
28
30
|
value,
|
|
29
|
-
methods
|
|
31
|
+
methods,
|
|
32
|
+
hasDownloadRequest: !type.isNone(downloadPolicyRequestId)
|
|
30
33
|
});
|
|
31
34
|
const disabled = properties.disabled === true || loading;
|
|
32
|
-
const uploadEnabled = !type.isNone(
|
|
33
|
-
const extensions = buildExtensions({
|
|
34
|
-
properties,
|
|
35
|
-
insertImage,
|
|
36
|
-
uploadEnabled
|
|
37
|
-
});
|
|
35
|
+
const uploadEnabled = !type.isNone(uploadPolicyRequestId);
|
|
38
36
|
const heightStyle = computeHeightStyle({
|
|
39
37
|
rows: properties.rows,
|
|
40
38
|
autoSize: properties.autoSize
|
|
41
39
|
});
|
|
42
|
-
const editor =
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
name: 'onChange'
|
|
51
|
-
});
|
|
52
|
-
}
|
|
40
|
+
const editor = useTiptapEditor({
|
|
41
|
+
disabled,
|
|
42
|
+
emit,
|
|
43
|
+
insertImage,
|
|
44
|
+
methods,
|
|
45
|
+
properties,
|
|
46
|
+
uploadEnabled,
|
|
47
|
+
value
|
|
53
48
|
});
|
|
54
|
-
// Register upload-policy
|
|
49
|
+
// Register upload-policy and download-policy events once (if configured).
|
|
55
50
|
useEffect(()=>{
|
|
56
51
|
if (!uploadEnabled) return;
|
|
52
|
+
if (!type.isNone(properties.s3PostPolicyRequestId)) {
|
|
53
|
+
console.warn('TiptapInput property "s3PostPolicyRequestId" is deprecated. Use "uploadPolicyRequestId" instead.');
|
|
54
|
+
}
|
|
57
55
|
methods.registerEvent({
|
|
58
|
-
name: '
|
|
56
|
+
name: '__getUploadPolicy',
|
|
59
57
|
actions: [
|
|
60
58
|
{
|
|
61
|
-
id: '
|
|
59
|
+
id: '__getUploadPolicy',
|
|
62
60
|
type: 'Request',
|
|
63
61
|
params: [
|
|
64
|
-
|
|
62
|
+
uploadPolicyRequestId
|
|
65
63
|
]
|
|
66
64
|
}
|
|
67
65
|
]
|
|
68
66
|
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
editor.commands.focus();
|
|
83
|
-
});
|
|
84
|
-
}, [
|
|
85
|
-
editor
|
|
86
|
-
]);
|
|
87
|
-
// External value.html → editor sync. One-way only: we read value.html and
|
|
88
|
-
// push it into the editor with setContent(..., false) so tiptap's onUpdate
|
|
89
|
-
// does not fire. No write-back via emit() — that would race with concurrent
|
|
90
|
-
// SetState calls (child effects fire before parent effects, so a sibling's
|
|
91
|
-
// onMount SetState could be overwritten by our derived emit). Derived
|
|
92
|
-
// fields (text/markdown/fileList) are populated on user interaction via
|
|
93
|
-
// onUpdate; downstream consumers of seeded content should read value.html
|
|
94
|
-
// directly, or include the fields they need in their SetState payload.
|
|
95
|
-
useEffect(()=>{
|
|
96
|
-
if (!editor) return;
|
|
97
|
-
const next = value?.html ?? '';
|
|
98
|
-
const current = editor.getHTML();
|
|
99
|
-
if (next !== current) {
|
|
100
|
-
editor.commands.setContent(next, false);
|
|
101
|
-
}
|
|
102
|
-
}, [
|
|
103
|
-
value?.html,
|
|
104
|
-
editor
|
|
105
|
-
]);
|
|
106
|
-
useEffect(()=>{
|
|
107
|
-
if (!editor) return;
|
|
108
|
-
editor.setOptions({
|
|
109
|
-
editable: !disabled
|
|
110
|
-
});
|
|
111
|
-
}, [
|
|
112
|
-
editor,
|
|
113
|
-
disabled
|
|
114
|
-
]);
|
|
115
|
-
useEffect(()=>{
|
|
116
|
-
if (!editor) return;
|
|
117
|
-
const placeholderExt = editor.extensionManager.extensions.find((extension)=>extension.name === 'placeholder');
|
|
118
|
-
if (placeholderExt) {
|
|
119
|
-
placeholderExt.options.placeholder = properties.placeholder ?? '';
|
|
120
|
-
editor.view.dispatch(editor.state.tr);
|
|
67
|
+
if (!type.isNone(downloadPolicyRequestId)) {
|
|
68
|
+
methods.registerEvent({
|
|
69
|
+
name: '__getDownloadPolicy',
|
|
70
|
+
actions: [
|
|
71
|
+
{
|
|
72
|
+
id: '__getDownloadPolicy',
|
|
73
|
+
type: 'Request',
|
|
74
|
+
params: [
|
|
75
|
+
downloadPolicyRequestId
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
});
|
|
121
80
|
}
|
|
122
|
-
}, [
|
|
123
|
-
editor,
|
|
124
|
-
properties.placeholder
|
|
125
|
-
]);
|
|
81
|
+
}, []);
|
|
126
82
|
const wrapperClass = [
|
|
127
83
|
'tiptap-wrapper',
|
|
128
84
|
properties.bordered === false ? 'tiptap-wrapper-borderless' : '',
|
|
@@ -0,0 +1,210 @@
|
|
|
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
|
+
- title: Default
|
|
16
|
+
fullWidth: true
|
|
17
|
+
blocks:
|
|
18
|
+
- id: tiptap_default
|
|
19
|
+
type: TiptapInput
|
|
20
|
+
properties:
|
|
21
|
+
title: Notes
|
|
22
|
+
placeholder: 'Start typing here. Try **bold**, *italic*, or headings.'
|
|
23
|
+
|
|
24
|
+
- title: Pre-populated content
|
|
25
|
+
fullWidth: true
|
|
26
|
+
blocks:
|
|
27
|
+
- id: tiptap_prepopulated
|
|
28
|
+
type: TiptapInput
|
|
29
|
+
events:
|
|
30
|
+
onMount:
|
|
31
|
+
- id: tiptap_prepopulated_set
|
|
32
|
+
type: SetState
|
|
33
|
+
params:
|
|
34
|
+
tiptap_prepopulated:
|
|
35
|
+
html: >
|
|
36
|
+
<h2>What's new</h2>
|
|
37
|
+
<p>Highlights from this release:</p>
|
|
38
|
+
<ul>
|
|
39
|
+
<li>Rich-text editor built on <a href="https://tiptap.dev">TipTap</a></li>
|
|
40
|
+
<li>Drag-and-drop image uploads</li>
|
|
41
|
+
<li>Inline <strong>bold</strong>, <em>italic</em>, and <mark>highlights</mark></li>
|
|
42
|
+
</ul>
|
|
43
|
+
<blockquote><p>Pair it with a TextArea when you need a simple fallback.</p></blockquote>
|
|
44
|
+
properties:
|
|
45
|
+
title: Release notes
|
|
46
|
+
|
|
47
|
+
- title: Disabled (read-only)
|
|
48
|
+
fullWidth: true
|
|
49
|
+
blocks:
|
|
50
|
+
- id: tiptap_disabled
|
|
51
|
+
type: TiptapInput
|
|
52
|
+
events:
|
|
53
|
+
onMount:
|
|
54
|
+
- id: tiptap_disabled_set
|
|
55
|
+
type: SetState
|
|
56
|
+
params:
|
|
57
|
+
tiptap_disabled:
|
|
58
|
+
html: '<p>This editor is disabled and cannot be edited.</p>'
|
|
59
|
+
properties:
|
|
60
|
+
title: Read only
|
|
61
|
+
disabled: true
|
|
62
|
+
|
|
63
|
+
- title: Borderless
|
|
64
|
+
fullWidth: true
|
|
65
|
+
blocks:
|
|
66
|
+
- id: tiptap_borderless
|
|
67
|
+
type: TiptapInput
|
|
68
|
+
properties:
|
|
69
|
+
title: Borderless editor
|
|
70
|
+
bordered: false
|
|
71
|
+
placeholder: 'No border, just content.'
|
|
72
|
+
|
|
73
|
+
- title: Fixed rows — rows = 2
|
|
74
|
+
fullWidth: true
|
|
75
|
+
blocks:
|
|
76
|
+
- id: tiptap_rows_2
|
|
77
|
+
type: TiptapInput
|
|
78
|
+
properties:
|
|
79
|
+
title: Short note
|
|
80
|
+
placeholder: 'Exactly 2 rows tall.'
|
|
81
|
+
rows: 2
|
|
82
|
+
|
|
83
|
+
- title: autoSize — minRows 2, maxRows 5
|
|
84
|
+
fullWidth: true
|
|
85
|
+
blocks:
|
|
86
|
+
- id: tiptap_autosize_range
|
|
87
|
+
type: TiptapInput
|
|
88
|
+
properties:
|
|
89
|
+
title: Grows between 2 and 5 rows
|
|
90
|
+
placeholder: 'Keep typing — scrolls past 5 rows.'
|
|
91
|
+
autoSize:
|
|
92
|
+
minRows: 2
|
|
93
|
+
maxRows: 5
|
|
94
|
+
|
|
95
|
+
- title: Validation — required, with error state
|
|
96
|
+
fullWidth: true
|
|
97
|
+
blocks:
|
|
98
|
+
- id: tiptap_validation
|
|
99
|
+
type: TiptapInput
|
|
100
|
+
required: true
|
|
101
|
+
properties:
|
|
102
|
+
title: Release notes (required)
|
|
103
|
+
placeholder: 'Type at least 10 characters, then click Validate.'
|
|
104
|
+
rows: 3
|
|
105
|
+
validate:
|
|
106
|
+
- status: error
|
|
107
|
+
message: 'Release notes must be at least 10 characters.'
|
|
108
|
+
pass:
|
|
109
|
+
_gte:
|
|
110
|
+
- _string.length:
|
|
111
|
+
_state: tiptap_validation.text
|
|
112
|
+
- 10
|
|
113
|
+
- id: tiptap_validation_button
|
|
114
|
+
type: Button
|
|
115
|
+
properties:
|
|
116
|
+
title: Validate
|
|
117
|
+
events:
|
|
118
|
+
onClick:
|
|
119
|
+
- id: tiptap_validation_run
|
|
120
|
+
type: Validate
|
|
121
|
+
params:
|
|
122
|
+
- tiptap_validation
|
|
123
|
+
|
|
124
|
+
- title: autoSize = true — grows with content
|
|
125
|
+
fullWidth: true
|
|
126
|
+
blocks:
|
|
127
|
+
- id: tiptap_autosize_true
|
|
128
|
+
type: TiptapInput
|
|
129
|
+
properties:
|
|
130
|
+
title: Unconstrained
|
|
131
|
+
placeholder: 'No height cap.'
|
|
132
|
+
autoSize: true
|
|
133
|
+
|
|
134
|
+
- title: Minimal — tables, images and highlights disabled
|
|
135
|
+
fullWidth: true
|
|
136
|
+
blocks:
|
|
137
|
+
- id: tiptap_minimal
|
|
138
|
+
type: TiptapInput
|
|
139
|
+
properties:
|
|
140
|
+
title: Plain note
|
|
141
|
+
placeholder: 'Bold/italic/lists only.'
|
|
142
|
+
image:
|
|
143
|
+
disabled: true
|
|
144
|
+
table:
|
|
145
|
+
disabled: true
|
|
146
|
+
highlight:
|
|
147
|
+
disabled: true
|
|
148
|
+
|
|
149
|
+
- title: StarterKit overrides — disable code block and blockquote
|
|
150
|
+
fullWidth: true
|
|
151
|
+
blocks:
|
|
152
|
+
- id: tiptap_starterkit
|
|
153
|
+
type: TiptapInput
|
|
154
|
+
properties:
|
|
155
|
+
title: Short-form
|
|
156
|
+
placeholder: 'No code block or blockquote.'
|
|
157
|
+
starterKit:
|
|
158
|
+
codeBlock: false
|
|
159
|
+
blockquote: false
|
|
160
|
+
horizontalRule: false
|
|
161
|
+
|
|
162
|
+
- title: With table (tables enabled by default)
|
|
163
|
+
fullWidth: true
|
|
164
|
+
blocks:
|
|
165
|
+
- id: tiptap_with_table
|
|
166
|
+
type: TiptapInput
|
|
167
|
+
events:
|
|
168
|
+
onMount:
|
|
169
|
+
- id: tiptap_with_table_set
|
|
170
|
+
type: SetState
|
|
171
|
+
params:
|
|
172
|
+
tiptap_with_table:
|
|
173
|
+
html: >
|
|
174
|
+
<h3>Weekly sync</h3>
|
|
175
|
+
<p>Schedule for today's meeting:</p>
|
|
176
|
+
<table>
|
|
177
|
+
<thead>
|
|
178
|
+
<tr><th>Time</th><th>Topic</th><th>Owner</th></tr>
|
|
179
|
+
</thead>
|
|
180
|
+
<tbody>
|
|
181
|
+
<tr><td>09:00</td><td>Kickoff</td><td>Alice</td></tr>
|
|
182
|
+
<tr><td>09:15</td><td>Review last week</td><td>Bob</td></tr>
|
|
183
|
+
<tr><td>09:45</td><td>This week's plan</td><td>Carol</td></tr>
|
|
184
|
+
<tr><td>10:00</td><td>Wrap-up</td><td>Alice</td></tr>
|
|
185
|
+
</tbody>
|
|
186
|
+
</table>
|
|
187
|
+
<p>Notes:</p>
|
|
188
|
+
<ul>
|
|
189
|
+
<li>Bring the latest metrics</li>
|
|
190
|
+
<li>Send follow-ups within 24h</li>
|
|
191
|
+
</ul>
|
|
192
|
+
properties:
|
|
193
|
+
title: Agenda
|
|
194
|
+
|
|
195
|
+
- title: Link configuration — open in place (not new tab)
|
|
196
|
+
fullWidth: true
|
|
197
|
+
blocks:
|
|
198
|
+
- id: tiptap_links
|
|
199
|
+
type: TiptapInput
|
|
200
|
+
events:
|
|
201
|
+
onMount:
|
|
202
|
+
- id: tiptap_links_set
|
|
203
|
+
type: SetState
|
|
204
|
+
params:
|
|
205
|
+
tiptap_links:
|
|
206
|
+
html: '<p>Visit <a href="https://lowdefy.com">lowdefy.com</a> or type a URL and press space.</p>'
|
|
207
|
+
properties:
|
|
208
|
+
title: Open links in place
|
|
209
|
+
link:
|
|
210
|
+
openOnClick: false
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
items: {
|
|
35
35
|
type: 'string'
|
|
36
36
|
},
|
|
37
|
-
description: 'Mime-types accepted by the drag/drop and paste file handler. Defaults to common image types (jpeg, png, gif, webp). Only used when
|
|
37
|
+
description: 'Mime-types accepted by the drag/drop and paste file handler. Defaults to common image types (jpeg, png, gif, webp). Only used when uploadPolicyRequestId is set.'
|
|
38
38
|
},
|
|
39
39
|
autoSize: {
|
|
40
40
|
oneOf: [
|
|
@@ -166,9 +166,17 @@
|
|
|
166
166
|
minimum: 1,
|
|
167
167
|
description: 'Fix the editor height to exactly this many rows. Takes precedence over autoSize.'
|
|
168
168
|
},
|
|
169
|
+
downloadPolicyRequestId: {
|
|
170
|
+
type: 'string',
|
|
171
|
+
description: 'Id of a download request (e.g. AwsS3PresignedGetObject) used to resolve the inserted image URL after upload. Inline images persist in saved content, so the request should set public: true (and the upload request the provider public-read acl) to return a stable, non-expiring URL. When unset, a legacy unsigned object URL is constructed from the upload response (S3-shaped, deprecated).'
|
|
172
|
+
},
|
|
169
173
|
s3PostPolicyRequestId: {
|
|
170
174
|
type: 'string',
|
|
171
|
-
description: '
|
|
175
|
+
description: 'Deprecated — use uploadPolicyRequestId instead.'
|
|
176
|
+
},
|
|
177
|
+
uploadPolicyRequestId: {
|
|
178
|
+
type: 'string',
|
|
179
|
+
description: 'Id of an upload-policy request (e.g. AwsS3PresignedPostPolicy, GcsSignedPostPolicy, AzureBlobUploadSas). When set, images dragged or pasted into the editor are uploaded via that request and inserted as <img> nodes. Leave unset to disable image uploads.'
|
|
172
180
|
},
|
|
173
181
|
size: {
|
|
174
182
|
type: 'string',
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
@import '../utils/style.css';
|
|
2
|
+
|
|
3
|
+
.tableWrapper,
|
|
4
|
+
.tiptap-table {
|
|
5
|
+
display: block;
|
|
6
|
+
overflow-x: auto;
|
|
7
|
+
max-width: 80%;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.tableWrapper table,
|
|
11
|
+
.tiptap-table table {
|
|
12
|
+
border-collapse: collapse;
|
|
13
|
+
width: 100%;
|
|
14
|
+
min-width: 75px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.tableWrapper colgroup col,
|
|
18
|
+
.tiptap-table colgroup col {
|
|
19
|
+
width: auto;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.tableWrapper table,
|
|
23
|
+
.tableWrapper th,
|
|
24
|
+
.tableWrapper td,
|
|
25
|
+
.tiptap-table table,
|
|
26
|
+
.tiptap-table th,
|
|
27
|
+
.tiptap-table td {
|
|
28
|
+
border: 1px solid var(--ant-color-border);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.tableWrapper th,
|
|
32
|
+
.tableWrapper td,
|
|
33
|
+
.tiptap-table th,
|
|
34
|
+
.tiptap-table td {
|
|
35
|
+
padding: 2px;
|
|
36
|
+
text-align: left;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.tableWrapper th,
|
|
40
|
+
.tiptap-table th {
|
|
41
|
+
background-color: var(--ant-color-fill-tertiary);
|
|
42
|
+
font-weight: bold;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.tableWrapper tr:nth-child(even),
|
|
46
|
+
.tiptap-table tr:nth-child(even) {
|
|
47
|
+
background-color: var(--ant-color-fill-quaternary);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.tableWrapper tr:hover,
|
|
51
|
+
.tiptap-table tr:hover {
|
|
52
|
+
background-color: var(--ant-color-primary-bg);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.tableWrapper td p,
|
|
56
|
+
.tableWrapper th p,
|
|
57
|
+
.tiptap-table td p,
|
|
58
|
+
.tiptap-table th p {
|
|
59
|
+
margin: 0;
|
|
60
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
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: tiptap-input
|
|
16
|
+
type: Box
|
|
17
|
+
|
|
18
|
+
events:
|
|
19
|
+
onMount:
|
|
20
|
+
- id: seed_content
|
|
21
|
+
type: SetState
|
|
22
|
+
params:
|
|
23
|
+
tiptap_with_value:
|
|
24
|
+
html: '<p>Hello <strong>world</strong>.</p>'
|
|
25
|
+
tiptap_disabled:
|
|
26
|
+
html: '<p>Disabled content.</p>'
|
|
27
|
+
tiptap_borderless:
|
|
28
|
+
html: '<p>Borderless.</p>'
|
|
29
|
+
|
|
30
|
+
blocks:
|
|
31
|
+
- id: tiptap_empty
|
|
32
|
+
type: TiptapInput
|
|
33
|
+
|
|
34
|
+
- id: tiptap_placeholder
|
|
35
|
+
type: TiptapInput
|
|
36
|
+
properties:
|
|
37
|
+
placeholder: 'Start typing...'
|
|
38
|
+
|
|
39
|
+
- id: tiptap_with_value
|
|
40
|
+
type: TiptapInput
|
|
41
|
+
|
|
42
|
+
- id: tiptap_disabled
|
|
43
|
+
type: TiptapInput
|
|
44
|
+
properties:
|
|
45
|
+
disabled: true
|
|
46
|
+
|
|
47
|
+
- id: tiptap_borderless
|
|
48
|
+
type: TiptapInput
|
|
49
|
+
properties:
|
|
50
|
+
bordered: false
|
|
51
|
+
|
|
52
|
+
- id: tiptap_typing
|
|
53
|
+
type: TiptapInput
|
|
@@ -0,0 +1,65 @@
|
|
|
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: TiptapInput
|
|
17
|
+
- id: properties.placeholder
|
|
18
|
+
type: TiptapInput
|
|
19
|
+
properties:
|
|
20
|
+
placeholder: 'Start typing...'
|
|
21
|
+
- id: properties.title
|
|
22
|
+
type: TiptapInput
|
|
23
|
+
properties:
|
|
24
|
+
title: 'Note'
|
|
25
|
+
- id: properties.disabled
|
|
26
|
+
type: TiptapInput
|
|
27
|
+
properties:
|
|
28
|
+
disabled: true
|
|
29
|
+
- id: properties.bordered = false
|
|
30
|
+
type: TiptapInput
|
|
31
|
+
properties:
|
|
32
|
+
bordered: false
|
|
33
|
+
placeholder: 'No border.'
|
|
34
|
+
- id: properties.image and table disabled
|
|
35
|
+
type: TiptapInput
|
|
36
|
+
properties:
|
|
37
|
+
image:
|
|
38
|
+
disabled: true
|
|
39
|
+
table:
|
|
40
|
+
disabled: true
|
|
41
|
+
- id: properties.starterKit overrides
|
|
42
|
+
type: TiptapInput
|
|
43
|
+
properties:
|
|
44
|
+
starterKit:
|
|
45
|
+
codeBlock: false
|
|
46
|
+
blockquote: false
|
|
47
|
+
- id: properties.rows = 2
|
|
48
|
+
type: TiptapInput
|
|
49
|
+
properties:
|
|
50
|
+
rows: 2
|
|
51
|
+
- id: properties.autoSize = {minRows 2, maxRows 5}
|
|
52
|
+
type: TiptapInput
|
|
53
|
+
properties:
|
|
54
|
+
autoSize:
|
|
55
|
+
minRows: 2
|
|
56
|
+
maxRows: 5
|
|
57
|
+
- id: properties.autoSize = true
|
|
58
|
+
type: TiptapInput
|
|
59
|
+
properties:
|
|
60
|
+
autoSize: true
|
|
61
|
+
- id: properties.link.openOnClick = false
|
|
62
|
+
type: TiptapInput
|
|
63
|
+
properties:
|
|
64
|
+
link:
|
|
65
|
+
openOnClick: false
|
|
@@ -14,12 +14,12 @@
|
|
|
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 editor's value. No useState — the only
|
|
19
19
|
// source of truth for `fileList` is the `value` prop from Lowdefy. We mirror
|
|
20
20
|
// it into a ref each render so callbacks (onUpdate, insertImage) captured in
|
|
21
21
|
// closures always read the current value instead of a stale render snapshot.
|
|
22
|
-
function useTiptapState({ value, methods }) {
|
|
22
|
+
function useTiptapState({ value, methods, hasDownloadRequest }) {
|
|
23
23
|
const valueRef = useRef(value);
|
|
24
24
|
valueRef.current = value;
|
|
25
25
|
const turndownService = new TurndownService();
|
|
@@ -31,7 +31,7 @@ function useTiptapState({ value, methods }) {
|
|
|
31
31
|
}
|
|
32
32
|
});
|
|
33
33
|
// Emit a full `{fileList, html, text, markdown}` value to Lowdefy based on
|
|
34
|
-
// the editor's current document. When appendFile is supplied (an
|
|
34
|
+
// the editor's current document. When appendFile is supplied (an upload
|
|
35
35
|
// result), it is added to the current fileList before filtering by
|
|
36
36
|
// in-document image urls.
|
|
37
37
|
const emit = (editor, appendFile)=>{
|
|
@@ -54,9 +54,10 @@ function useTiptapState({ value, methods }) {
|
|
|
54
54
|
});
|
|
55
55
|
};
|
|
56
56
|
const insertImage = async (editor, file, pos)=>{
|
|
57
|
-
const url = await
|
|
57
|
+
const url = await fileUpload({
|
|
58
58
|
file,
|
|
59
|
-
methods
|
|
59
|
+
methods,
|
|
60
|
+
hasDownloadRequest
|
|
60
61
|
});
|
|
61
62
|
// The upload is async: bail if the editor was torn down meanwhile (e.g. the
|
|
62
63
|
// surrounding page navigated away before the upload resolved), otherwise the
|