@verdant-web/tiptap 2.0.0 → 2.1.1

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.
@@ -0,0 +1,299 @@
1
+ import { mergeAttributes, Node } from '@tiptap/core';
2
+ import {
3
+ EntityFile,
4
+ EntityFileSnapshot,
5
+ id,
6
+ ObjectEntity,
7
+ } from '@verdant-web/store';
8
+
9
+ export type VerdantMediaFileMap = ObjectEntity<
10
+ Record<string, File>,
11
+ Record<string, EntityFile | undefined>,
12
+ Record<string, EntityFileSnapshot>
13
+ >;
14
+ export interface VerdantMediaExtensionOptions {
15
+ fileMap: VerdantMediaFileMap;
16
+ }
17
+
18
+ declare module '@tiptap/core' {
19
+ interface Commands<ReturnType> {
20
+ verdantMedia: {
21
+ /**
22
+ * Add a file to the editor content.
23
+ * @param file The file to add.
24
+ * @example
25
+ * editor
26
+ * .commands
27
+ * .insertMedia({ src: 'https://tiptap.dev/logo.png', alt: 'tiptap', title: 'tiptap logo' })
28
+ */
29
+ insertMedia: (file: File) => ReturnType;
30
+ };
31
+ }
32
+ }
33
+
34
+ const fileIdAttribute = 'data-verdant-file';
35
+ export const VerdantMediaExtension = Node.create<VerdantMediaExtensionOptions>({
36
+ name: 'verdant-media',
37
+ group: 'block',
38
+ draggable: true,
39
+ addOptions() {
40
+ return {
41
+ fileMap: null as any,
42
+ };
43
+ },
44
+ addAttributes() {
45
+ return {
46
+ [fileIdAttribute]: {
47
+ default: null,
48
+ },
49
+ alt: {
50
+ default: null,
51
+ },
52
+ };
53
+ },
54
+ parseHTML() {
55
+ return [
56
+ {
57
+ tag: `[${fileIdAttribute}]`,
58
+ getAttrs: (element) => {
59
+ const fileId = element.getAttribute(fileIdAttribute);
60
+ return {
61
+ [fileIdAttribute]: fileId,
62
+ };
63
+ },
64
+ },
65
+ ];
66
+ },
67
+ renderHTML(props) {
68
+ const fileId = props.node.attrs[fileIdAttribute];
69
+ if (!fileId) {
70
+ return ['div', props.HTMLAttributes, 'Missing file'];
71
+ }
72
+ const file = this.options.fileMap.get(fileId);
73
+ if (!file) {
74
+ return ['div', props.HTMLAttributes, 'Missing file'];
75
+ }
76
+ if (file.loading) {
77
+ // this means the user didn't preload files before rendering...
78
+ return [
79
+ 'div',
80
+ props.HTMLAttributes,
81
+ 'Loading file. This file was not preloaded before rendering the document.',
82
+ ];
83
+ }
84
+ const type = file.type;
85
+ if (type?.startsWith('image/')) {
86
+ return ['img', mergeAttributes({ src: file.url }, props.HTMLAttributes)];
87
+ } else if (type?.startsWith('video/')) {
88
+ return [
89
+ 'video',
90
+ mergeAttributes({ src: file.url }, props.HTMLAttributes),
91
+ ];
92
+ } else if (type?.startsWith('audio/')) {
93
+ return [
94
+ 'audio',
95
+ mergeAttributes({ src: file.url }, props.HTMLAttributes),
96
+ ];
97
+ } else {
98
+ // TODO: render file download
99
+ return ['div', props.HTMLAttributes, 'Unsupported file type'];
100
+ }
101
+ },
102
+ onBeforeCreate() {
103
+ this.editor.on('paste', (event) => {
104
+ const files = Array.from(event.event.clipboardData?.files ?? []);
105
+ if (files.length === 0) {
106
+ return;
107
+ }
108
+ for (const file of files) {
109
+ this.editor.chain().insertMedia(file).run();
110
+ }
111
+ event.event.preventDefault();
112
+ });
113
+ this.editor.on('drop', (event) => {
114
+ const files = Array.from(event.event.dataTransfer?.files ?? []);
115
+ if (files.length === 0) {
116
+ return;
117
+ }
118
+ for (const file of files) {
119
+ this.editor.chain().insertMedia(file).run();
120
+ }
121
+ event.event.preventDefault();
122
+ });
123
+ this.editor.on('update', ({ transaction }) => {
124
+ const fileIds = new Set<string>();
125
+ transaction.doc.forEach((node) => {
126
+ if (node.attrs[fileIdAttribute]) {
127
+ fileIds.add(node.attrs[fileIdAttribute]);
128
+ }
129
+ });
130
+ transaction.before.forEach((node) => {
131
+ const fileId = node.attrs[fileIdAttribute];
132
+ if (fileId && !fileIds.has(fileId)) {
133
+ // the file was removed from the document
134
+ this.options.fileMap.delete(fileId);
135
+ }
136
+ });
137
+ });
138
+ },
139
+ addCommands() {
140
+ return {
141
+ insertMedia:
142
+ (file: File) =>
143
+ ({ commands }) => {
144
+ const fileId = id();
145
+ this.options.fileMap.set(fileId, file);
146
+ return commands.insertContent(
147
+ {
148
+ type: this.name,
149
+ attrs: {
150
+ [fileIdAttribute]: fileId,
151
+ },
152
+ } as any,
153
+ {
154
+ updateSelection: false,
155
+ },
156
+ );
157
+ },
158
+ };
159
+ },
160
+ addNodeView() {
161
+ return ({ node, HTMLAttributes, extension }) => {
162
+ // create a root div to house all content
163
+ const root = document.createElement('div');
164
+ // we don't want users editing this content
165
+ root.setAttribute('contenteditable', 'false');
166
+ // attach any existing attributes if they are not null
167
+ Object.entries(HTMLAttributes).forEach(([key, value]) => {
168
+ if (value !== null) {
169
+ root.setAttribute(key, value as string);
170
+ }
171
+ });
172
+
173
+ // get the file ID from attrs
174
+ const fileId = node.attrs[fileIdAttribute];
175
+ if (!fileId) {
176
+ root.textContent = 'Missing file';
177
+ return {
178
+ dom: root,
179
+ };
180
+ }
181
+
182
+ // look up the file in the file map
183
+ // NOTE: for convenience/typing, "this" is used
184
+ // here, but in a userland node view you'd use `extension`.
185
+ const file = this.options.fileMap.get(fileId);
186
+
187
+ // this is a helper function to reconstruct the DOM
188
+ // whenever the file changes
189
+ function updateRootContent() {
190
+ // clear the DOM
191
+ root.innerHTML = '';
192
+ if (file) {
193
+ // minimal loading state
194
+ if (file.loading) {
195
+ root.textContent = 'Loading...';
196
+ return;
197
+ }
198
+
199
+ // minimal error state
200
+ if (file.failed) {
201
+ root.textContent = 'Failed to load file';
202
+ return;
203
+ }
204
+
205
+ // it's unlikely we get here without a url
206
+ // but just in case
207
+ const url = file.url;
208
+ if (!url) {
209
+ root.textContent = 'Failed to load file';
210
+ return;
211
+ }
212
+
213
+ // based on the file type, we try to render
214
+ // a useful DOM representation
215
+ const type = file.type;
216
+ if (type?.startsWith('image/')) {
217
+ const img = document.createElement('img');
218
+ img.src = file.url;
219
+ root.appendChild(img);
220
+ } else if (type?.startsWith('video/')) {
221
+ const video = document.createElement('video');
222
+ video.src = file.url;
223
+ video.controls = true;
224
+ root.appendChild(video);
225
+ } else if (type?.startsWith('audio/')) {
226
+ const audio = document.createElement('audio');
227
+ audio.src = file.url;
228
+ audio.controls = true;
229
+ root.appendChild(audio);
230
+ } else {
231
+ const a = document.createElement('a');
232
+ a.href = file.url;
233
+ a.textContent = 'Download';
234
+ root.appendChild(a);
235
+ }
236
+ }
237
+ }
238
+
239
+ // if the file is not in the file map, we subscribe to changes
240
+ // to its key in the map, and update the DOM when it changes.
241
+ if (!file) {
242
+ const unsub = this.options.fileMap.subscribeToField(
243
+ fileId,
244
+ 'change',
245
+ (file) => {
246
+ if (!file) return;
247
+ // we can unsub after the first change, all further
248
+ // changes can be monitored on the file itself.
249
+ unsub();
250
+ file.subscribe('change', updateRootContent);
251
+ updateRootContent();
252
+ },
253
+ );
254
+ root.textContent = 'Missing file';
255
+ return {
256
+ dom: root,
257
+ };
258
+ } else {
259
+ // otherwise, we go ahead and render whatever we have, and
260
+ // subscribe to future changes on the file for further
261
+ // updates.
262
+ updateRootContent();
263
+ file.subscribe('change', updateRootContent);
264
+ return {
265
+ dom: root,
266
+ };
267
+ }
268
+ };
269
+ },
270
+ });
271
+
272
+ export function createVerdantMediaExtension(fileMap: VerdantMediaFileMap) {
273
+ return VerdantMediaExtension.configure({ fileMap });
274
+ }
275
+
276
+ /**
277
+ * Preloads all files provided in the file map field. Use of this
278
+ * is highly recommended, if not required, when rendering a document
279
+ * to HTML. TipTap will not wait for files to load, so if they are
280
+ * not preloaded they will be blank in the rendered version.
281
+ */
282
+ export async function preloadMedia(files: VerdantMediaFileMap) {
283
+ await Promise.all(
284
+ Array.from(files.values()).map((file) => {
285
+ if (!file) return Promise.resolve();
286
+ // since files immediately begin loading on access,
287
+ // we just wait for the file to finish loading
288
+ if (!file.loading) return Promise.resolve();
289
+ return new Promise<void>((resolve) => {
290
+ const unsub = file.subscribe('change', () => {
291
+ if (!file.loading) {
292
+ unsub();
293
+ resolve();
294
+ }
295
+ });
296
+ });
297
+ }),
298
+ );
299
+ }
package/src/fields.ts CHANGED
@@ -131,3 +131,9 @@ export function createTipTapFieldSchema(options: {
131
131
 
132
132
  return rootField as any;
133
133
  }
134
+
135
+ export function createTipTapFileMapSchema() {
136
+ return schema.fields.map({
137
+ values: schema.fields.file(),
138
+ });
139
+ }
package/src/index.ts CHANGED
@@ -1,2 +1,4 @@
1
+ export * from './extensions/NodeId.js';
2
+ export * from './extensions/Verdant.js';
3
+ export * from './extensions/VerdantMedia.js';
1
4
  export * from './fields.js';
2
- export * from './plugins.js';
package/src/react.ts CHANGED
@@ -6,7 +6,11 @@ import {
6
6
  VerdantExtensionOptions,
7
7
  type EntitySnapshot,
8
8
  type ValidEntityKey,
9
- } from './plugins.js';
9
+ } from './extensions/Verdant.js';
10
+ import {
11
+ VerdantMediaExtension,
12
+ VerdantMediaFileMap,
13
+ } from './extensions/VerdantMedia.js';
10
14
 
11
15
  export function useSyncedEditor<
12
16
  Ent extends AnyEntity<any, any, any>,
@@ -19,11 +23,13 @@ export function useSyncedEditor<
19
23
  editorDependencies,
20
24
  nullDocumentDefault,
21
25
  extensionOptions,
26
+ files,
22
27
  }: {
23
28
  editorOptions?: UseEditorOptions;
24
29
  editorDependencies?: any[];
25
30
  nullDocumentDefault?: EntitySnapshot<Ent, Key>;
26
31
  extensionOptions?: Partial<VerdantExtensionOptions>;
32
+ files?: VerdantMediaFileMap;
27
33
  } = {},
28
34
  ) {
29
35
  const cachedOptions = useRef({
@@ -36,13 +42,20 @@ export function useSyncedEditor<
36
42
  };
37
43
  // create a configured version of the Verdant extension, which handles
38
44
  // the actual syncing of the editor content to the field
39
- const [extension] = useState(() =>
40
- VerdantExtension.configure({
41
- parent,
42
- fieldName: fieldName as string | number,
43
- nullDocumentDefault,
44
- ...extensionOptions,
45
- }),
45
+ const [extensions] = useState(() =>
46
+ [
47
+ VerdantExtension.configure({
48
+ parent,
49
+ fieldName: fieldName as string | number,
50
+ nullDocumentDefault,
51
+ ...extensionOptions,
52
+ }),
53
+ files
54
+ ? VerdantMediaExtension.configure({
55
+ fileMap: files,
56
+ })
57
+ : undefined,
58
+ ].filter((v) => !!v),
46
59
  );
47
60
  const editor = useEditor(
48
61
  {
@@ -50,7 +63,7 @@ export function useSyncedEditor<
50
63
  onContentError(props) {
51
64
  console.error('Content error:', props.error);
52
65
  },
53
- extensions: [extension, ...(extraOptions?.extensions ?? [])],
66
+ extensions: [...extensions, ...(extraOptions?.extensions ?? [])],
54
67
  },
55
68
  editorDependencies,
56
69
  );
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugins.js","sourceRoot":"","sources":["../../src/plugins.ts"],"names":[],"mappings":"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"}