edytor 1.0.0 → 3.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/README.md +26 -69
- package/dist/block/block.svelte.d.ts +6 -4
- package/dist/block/block.svelte.js +12 -8
- package/dist/block/inlineBlock.svelte.d.ts +6 -2
- package/dist/block/inlineBlock.svelte.js +7 -2
- package/dist/clipboard/htmlFlow.d.ts +20 -7
- package/dist/clipboard/htmlFlow.js +23 -15
- package/dist/clipboard/serializeClipboardFragment.d.ts +37 -4
- package/dist/clipboard/serializeClipboardFragment.js +6 -4
- package/dist/clipboard/textBlocks.d.ts +8 -0
- package/dist/clipboard/textBlocks.js +6 -2
- package/dist/cloudflare/room/admission.js +3 -3
- package/dist/cloudflare/room/context.d.ts +7 -1
- package/dist/cloudflare/routeDocumentSocket.d.ts +17 -0
- package/dist/cloudflare/routeDocumentSocket.js +53 -0
- package/dist/collaboration/awarenessSelection.d.ts +22 -1
- package/dist/collaboration/awarenessSelection.js +42 -0
- package/dist/collaboration/comments/client.d.ts +1 -1
- package/dist/collaboration/comments/client.js +1 -1
- package/dist/collaboration/remoteSelection.js +3 -3
- package/dist/components/Block.svelte +3 -1
- package/dist/components/Edytor.svelte +38 -20
- package/dist/components/Edytor.svelte.d.ts +9 -4
- package/dist/components/InlineBlock.svelte +1 -1
- package/dist/crdt/admission.d.ts +5 -10
- package/dist/crdt/admission.js +5 -11
- package/dist/crdt/data.d.ts +10 -0
- package/dist/crdt/data.js +20 -2
- package/dist/crdt/doc/funnel.d.ts +7 -6
- package/dist/crdt/doc/funnel.js +10 -9
- package/dist/crdt/doc/gate.d.ts +0 -17
- package/dist/crdt/doc/gate.js +2 -41
- package/dist/crdt/doc/history.js +2 -2
- package/dist/crdt/doc/reads.d.ts +7 -0
- package/dist/crdt/doc/reads.js +11 -1
- package/dist/crdt/document.d.ts +13 -14
- package/dist/crdt/document.js +17 -19
- package/dist/crdt/edytor-doc.d.ts +22 -4
- package/dist/crdt/edytor-doc.js +5 -8
- package/dist/crdt/index.d.ts +9 -3
- package/dist/crdt/index.js +2 -2
- package/dist/crdt/operations.d.ts +1 -1
- package/dist/crdt/operations.js +1 -0
- package/dist/crdt/props.d.ts +32 -0
- package/dist/crdt/props.js +172 -0
- package/dist/crdt/protocol.d.ts +2 -2
- package/dist/crdt/protocol.js +2 -2
- package/dist/crdt/providers/index.d.ts +1 -1
- package/dist/crdt/providers/room.d.ts +10 -9
- package/dist/crdt/providers/room.js +13 -10
- package/dist/crdt/providers/websocket.d.ts +1 -1
- package/dist/crdt/providers/websocket.js +28 -29
- package/dist/crdt/semantics.js +3 -1
- package/dist/dnd/autoScroll.d.ts +15 -7
- package/dist/dnd/autoScroll.js +10 -15
- package/dist/{plugins/blockHandles → dnd}/dropIndicator.d.ts +2 -2
- package/dist/{plugins/blockHandles → dnd}/dropIndicator.js +2 -5
- package/dist/dnd/external.d.ts +6 -0
- package/dist/dnd/external.js +17 -0
- package/dist/{plugins/blockHandles → dnd}/geometry.d.ts +4 -2
- package/dist/{plugins/blockHandles → dnd}/geometry.js +3 -4
- package/dist/dnd/placement.d.ts +200 -0
- package/dist/dnd/placement.js +426 -0
- package/dist/dnd/pragmatic.d.ts +3 -1
- package/dist/dnd/pragmatic.js +12 -2
- package/dist/dnd/vendor/pragmatic/UPSTREAM.md +51 -18
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/drop-target-for-external.d.ts +4 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/drop-target-for-external.js +6 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/element-adapter.d.ts +0 -2
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/element-adapter.js +4 -22
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/external-adapter-types.d.ts +26 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/external-adapter.d.ts +30 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/external-adapter.js +203 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/get-available-items.js +13 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/get-available-types.js +9 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/is-an-available-type.js +19 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/monitor-for-external.d.ts +4 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/monitor-for-external.js +6 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/honey-pot-fix/make-honey-pot-fix.js +4 -16
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/internal-types.d.ts +1 -8
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/make-adapter/make-drop-target.js +5 -6
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/make-adapter/make-monitor.js +2 -3
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.d.ts +1 -1
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.js +6 -24
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/contains-files.d.ts +2 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/contains-files.js +5 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/get-files.d.ts +3 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/get-files.js +12 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/native-types.d.ts +12 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/util/changing-window/is-entering-window-in-safari.js +10 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/util/changing-window/is-entering-window.js +55 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/entry-point/external.d.ts +4 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/entry-point/external.js +8 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/internal-types.d.ts +0 -4
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/over-element/get-scroll-by.js +16 -72
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/over-element/try-scroll.js +1 -9
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/shared/configuration.js +4 -29
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/shared/get-scroll-change.js +2 -3
- package/dist/edytor.svelte.d.ts +19 -9
- package/dist/edytor.svelte.js +28 -33
- package/dist/events/beforeInputCommands.d.ts +2 -2
- package/dist/events/beforeInputCommands.js +8 -4
- package/dist/events/onBeforeInput.js +1 -1
- package/dist/events/onDrop.js +25 -10
- package/dist/events/onInput.d.ts +0 -12
- package/dist/events/onInput.js +1 -67
- package/dist/events/onPaste.d.ts +2 -1
- package/dist/events/onPaste.js +8 -3
- package/dist/export/forms.d.ts +627 -0
- package/dist/export/forms.js +749 -0
- package/dist/export/index.d.ts +170 -0
- package/dist/export/index.js +161 -0
- package/dist/export/markdown.d.ts +41 -0
- package/dist/export/markdown.js +585 -0
- package/dist/export/markdownWriter.d.ts +9 -0
- package/dist/export/markdownWriter.js +133 -0
- package/dist/export/mdx.d.ts +15 -0
- package/dist/export/mdx.js +33 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/kinds.js +1 -1
- package/dist/labels.d.ts +2 -0
- package/dist/labels.js +2 -1
- package/dist/plugins/anchored.svelte.d.ts +21 -25
- package/dist/plugins/anchored.svelte.js +23 -39
- package/dist/plugins/arrowMove/arrowMove.d.ts +1 -1
- package/dist/plugins/arrowMove/arrowMove.js +1 -1
- package/dist/plugins/blockHandles/BlockHandleController.svelte.d.ts +2 -122
- package/dist/plugins/blockHandles/BlockHandleController.svelte.js +48 -414
- package/dist/plugins/blockHandles/BlockHandles.svelte +14 -32
- package/dist/plugins/blockHandles/blockHandlesPlugin.js +2 -1
- package/dist/plugins/blockHandles/dragPreview.d.ts +26 -7
- package/dist/plugins/blockHandles/dragPreview.js +33 -0
- package/dist/plugins/blockMenu/BlockMenuController.svelte.d.ts +5 -0
- package/dist/plugins/blockMenu/BlockMenuController.svelte.js +7 -2
- package/dist/plugins/blockMenu/blockMenuPlugin.js +5 -50
- package/dist/plugins/chrome.d.ts +27 -5
- package/dist/plugins/chrome.js +24 -9
- package/dist/plugins/code/CodeHeader.svelte +5 -3
- package/dist/plugins/code/CodePlugin.svelte +15 -12
- package/dist/plugins/code/header.svelte.js +7 -11
- package/dist/plugins/code/languageMenu.svelte.d.ts +5 -2
- package/dist/plugins/code/languageMenu.svelte.js +13 -20
- package/dist/plugins/code/languages.d.ts +0 -3
- package/dist/plugins/code/languages.js +0 -2
- package/dist/plugins/columns/ColumnResize.svelte +3 -2
- package/dist/plugins/columns/ColumnsPlugin.svelte +8 -21
- package/dist/plugins/columns/gaps.d.ts +7 -5
- package/dist/plugins/columns/gaps.js +11 -6
- package/dist/plugins/columns/resize.svelte.d.ts +5 -6
- package/dist/plugins/columns/resize.svelte.js +12 -14
- package/dist/plugins/comments/CommentsController.svelte.d.ts +6 -0
- package/dist/plugins/comments/CommentsController.svelte.js +20 -0
- package/dist/plugins/equation/EquationPlugin.svelte +13 -30
- package/dist/plugins/equation/EquationPlugin.svelte.d.ts +1 -0
- package/dist/plugins/equation/equation.css +7 -0
- package/dist/plugins/equation/equation.svelte.d.ts +7 -15
- package/dist/plugins/equation/equation.svelte.js +13 -50
- package/dist/plugins/equation/tex.d.ts +17 -0
- package/dist/plugins/equation/tex.js +42 -0
- package/dist/plugins/fileDrop.d.ts +43 -0
- package/dist/plugins/fileDrop.js +122 -0
- package/dist/plugins/find/FindController.svelte.d.ts +5 -0
- package/dist/plugins/find/FindController.svelte.js +14 -14
- package/dist/plugins/find/findPlugin.js +1 -15
- package/dist/plugins/image/ImageChrome.svelte +8 -2
- package/dist/plugins/image/ImagePlugin.svelte +56 -84
- package/dist/plugins/image/ImagePlugin.svelte.d.ts +13 -1
- package/dist/plugins/image/controls.svelte.js +16 -2
- package/dist/plugins/image/image.css +17 -0
- package/dist/plugins/image/toolbar.svelte.d.ts +5 -4
- package/dist/plugins/image/toolbar.svelte.js +21 -31
- package/dist/plugins/index.d.ts +4 -5
- package/dist/plugins/index.js +0 -1
- package/dist/plugins/list.svelte.d.ts +9 -0
- package/dist/plugins/list.svelte.js +18 -0
- package/dist/plugins/markdownShortcuts.js +5 -5
- package/dist/plugins/marquee/marqueePlugin.js +0 -4
- package/dist/plugins/media/AudioPlugin.svelte +13 -1
- package/dist/plugins/media/AudioPlugin.svelte.d.ts +11 -1
- package/dist/plugins/media/BookmarkPlugin.svelte +6 -97
- package/dist/plugins/media/EmbedPlugin.svelte +5 -90
- package/dist/plugins/media/EmptySlot.svelte +36 -20
- package/dist/plugins/media/EmptySlot.svelte.d.ts +6 -15
- package/dist/plugins/media/FilePlugin.svelte +12 -20
- package/dist/plugins/media/FilePlugin.svelte.d.ts +9 -0
- package/dist/plugins/media/MediaEmpty.svelte +2 -55
- package/dist/plugins/media/MediaEmpty.svelte.d.ts +18 -14
- package/dist/plugins/media/SourceBlock.svelte +178 -52
- package/dist/plugins/media/SourceBlock.svelte.d.ts +13 -6
- package/dist/plugins/media/UploadPreview.svelte +32 -0
- package/dist/plugins/media/UploadPreview.svelte.d.ts +11 -0
- package/dist/plugins/media/VideoPlugin.svelte +13 -1
- package/dist/plugins/media/VideoPlugin.svelte.d.ts +11 -1
- package/dist/plugins/media/empty.svelte.d.ts +13 -4
- package/dist/plugins/media/empty.svelte.js +32 -26
- package/dist/plugins/media/media.d.ts +9 -63
- package/dist/plugins/media/media.js +1 -194
- package/dist/plugins/media/sources.d.ts +60 -0
- package/dist/plugins/media/sources.js +165 -0
- package/dist/plugins/media/upload.css +23 -0
- package/dist/plugins/media/urlPaste.svelte.d.ts +2 -1
- package/dist/plugins/media/urlPaste.svelte.js +12 -21
- package/dist/plugins/mention/MentionPlugin.svelte +50 -38
- package/dist/plugins/mention/MentionPlugin.svelte.d.ts +11 -2
- package/dist/plugins/mention/mention.css +6 -0
- package/dist/plugins/page/PagePlugin.svelte +2 -9
- package/dist/plugins/page/page.js +1 -1
- package/dist/plugins/pageLink/PageLinkPlugin.svelte +126 -28
- package/dist/plugins/pageLink/PageLinkPlugin.svelte.d.ts +13 -1
- package/dist/plugins/pageLink/pageLink.css +6 -0
- package/dist/plugins/richtext/RichTextPlugin.svelte +99 -204
- package/dist/plugins/richtext/RichTextPlugin.svelte.d.ts +1 -0
- package/dist/plugins/richtext/body.js +1 -1
- package/dist/plugins/richtext/calloutIcons.svelte.d.ts +2 -2
- package/dist/plugins/richtext/calloutIcons.svelte.js +5 -7
- package/dist/plugins/richtext/richTextOperations.d.ts +1 -19
- package/dist/plugins/richtext/richTextOperations.js +3 -49
- package/dist/plugins/richtext/richtext.css +6 -0
- package/dist/plugins/slashMenu/SlashMenuController.svelte.d.ts +2 -0
- package/dist/plugins/slashMenu/SlashMenuController.svelte.js +7 -0
- package/dist/plugins/slashMenu/slashMenuPlugin.js +5 -14
- package/dist/plugins/table/TableChrome.svelte +2 -3
- package/dist/plugins/table/TablePlugin.svelte +20 -54
- package/dist/plugins/table/chrome.svelte.d.ts +5 -2
- package/dist/plugins/table/chrome.svelte.js +33 -56
- package/dist/plugins/table/table.js +3 -3
- package/dist/plugins/toc/TocPlugin.svelte +2 -4
- package/dist/plugins/toolbar/ToolbarController.svelte.d.ts +7 -0
- package/dist/plugins/toolbar/ToolbarController.svelte.js +20 -13
- package/dist/plugins/toolbar/toolbarPlugin.js +19 -53
- package/dist/plugins/triggers/TriggerController.svelte.d.ts +7 -2
- package/dist/plugins/triggers/TriggerController.svelte.js +11 -4
- package/dist/plugins/triggers/place.js +1 -2
- package/dist/plugins/triggers/triggers.d.ts +6 -1
- package/dist/plugins/triggers/triggers.js +12 -13
- package/dist/plugins/uploads.svelte.d.ts +48 -32
- package/dist/plugins/uploads.svelte.js +119 -43
- package/dist/plugins.d.ts +66 -14
- package/dist/plugins.js +0 -24
- package/dist/selection/replaceSelection.js +2 -2
- package/dist/selection/selection.svelte.d.ts +4 -10
- package/dist/selection/selection.svelte.js +7 -11
- package/dist/session/attempt.d.ts +16 -6
- package/dist/session/attempt.js +1 -0
- package/dist/session/bindings.js +35 -32
- package/dist/session/commands.d.ts +7 -11
- package/dist/session/commands.js +15 -19
- package/dist/session/history.js +1 -0
- package/dist/session/inputRules.d.ts +6 -3
- package/dist/session/inputRules.js +10 -6
- package/dist/session/moves.d.ts +33 -0
- package/dist/session/moves.js +71 -1
- package/dist/session/navigation.d.ts +7 -0
- package/dist/session/navigation.js +20 -11
- package/dist/session/props.d.ts +28 -0
- package/dist/session/props.js +65 -0
- package/dist/session/suggestions.svelte.d.ts +0 -11
- package/dist/session/suggestions.svelte.js +15 -3
- package/dist/session/uploads.d.ts +29 -0
- package/dist/session/uploads.js +10 -0
- package/dist/surface/lines.js +1 -3
- package/dist/surface/observer.svelte.d.ts +17 -1
- package/dist/surface/observer.svelte.js +72 -17
- package/dist/surface/overlay.d.ts +0 -14
- package/dist/surface/overlay.js +0 -25
- package/dist/surface/projector.svelte.js +1 -1
- package/dist/text/text.svelte.js +3 -13
- package/dist/themes/notion.css +9 -0
- package/dist/utils/sanitize.d.ts +38 -0
- package/dist/utils/sanitize.js +82 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +5 -0
- package/package.json +18 -1
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/util/max-z-index.js +0 -3
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/util/supports-popover.js +0 -16
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/shared/is-axis-allowed.js +0 -3
- package/dist/plugins/code/LanguageMenu.svelte +0 -25
- package/dist/plugins/code/LanguageMenu.svelte.d.ts +0 -9
- package/dist/plugins/equation/EquationEditor.svelte +0 -27
- package/dist/plugins/equation/EquationEditor.svelte.d.ts +0 -9
- package/dist/plugins/image/ImageToolbarHost.svelte +0 -37
- package/dist/plugins/image/ImageToolbarHost.svelte.d.ts +0 -9
- package/dist/plugins/richtext/CalloutIconPicker.svelte +0 -26
- package/dist/plugins/richtext/CalloutIconPicker.svelte.d.ts +0 -9
- /package/dist/{plugins/columns → dnd}/stacking.d.ts +0 -0
- /package/dist/{plugins/columns → dnd}/stacking.js +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { Plugin } from '../../plugins.js';
|
|
4
|
-
import {
|
|
4
|
+
import { type FileRowPayload } from './media.js';
|
|
5
5
|
import { sourcePlugin } from './SourceBlock.svelte';
|
|
6
|
+
import type { Uploader } from '../uploads.svelte.js';
|
|
6
7
|
|
|
7
8
|
export type { FileRowPayload };
|
|
8
9
|
|
|
@@ -13,6 +14,14 @@
|
|
|
13
14
|
* downloads the file. The first file plugin listed in a view gives its row.
|
|
14
15
|
*/
|
|
15
16
|
row?: Snippet<[FileRowPayload]>;
|
|
17
|
+
/**
|
|
18
|
+
* Upload a file and answer its URL: an empty file block's Upload, and
|
|
19
|
+
* the pasted and dropped files no other kind takes, each placed as a
|
|
20
|
+
* file block at once (one undo step), its row showing the file's name,
|
|
21
|
+
* size and progress, then filled with the URL this answers. Without
|
|
22
|
+
* it, files are only linked.
|
|
23
|
+
*/
|
|
24
|
+
upload?: Uploader;
|
|
16
25
|
};
|
|
17
26
|
|
|
18
27
|
/**
|
|
@@ -24,24 +33,7 @@
|
|
|
24
33
|
sourcePlugin(
|
|
25
34
|
'file',
|
|
26
35
|
['attachment', 'upload', 'pdf', 'document'],
|
|
27
|
-
{
|
|
28
|
-
|
|
29
|
-
const src = safeMediaSrc(block.data?.src);
|
|
30
|
-
const name = String(block.data?.name || (src && fileNameOf(src)) || '');
|
|
31
|
-
const link = src ? `<a href="${escapeHtml(src)}">${escapeHtml(name)}</a>` : '';
|
|
32
|
-
return `<figure data-edytor-file>${link}<figcaption>${caption}</figcaption></figure>`;
|
|
33
|
-
},
|
|
34
|
-
plain: (block, caption) =>
|
|
35
|
-
[safeMediaSrc(block.data?.src), caption].filter(Boolean).join('\n'),
|
|
36
|
-
// Its own export: a `figure[data-edytor-file]` holding the link.
|
|
37
|
-
parse: (el) => {
|
|
38
|
-
if (el.localName !== 'figure' || !el.hasAttribute('data-edytor-file')) return;
|
|
39
|
-
const anchor = el.querySelector('a[href]');
|
|
40
|
-
const src = safeMediaSrc(anchor?.getAttribute('href'));
|
|
41
|
-
const name = anchor?.textContent?.trim().slice(0, 300);
|
|
42
|
-
return src ? { src, name: name || fileNameOf(src) } : undefined;
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
{ row: options.row }
|
|
36
|
+
{ row: options.row },
|
|
37
|
+
options.upload
|
|
46
38
|
);
|
|
47
39
|
</script>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { Plugin } from '../../plugins.js';
|
|
3
3
|
import { type FileRowPayload } from './media.js';
|
|
4
|
+
import type { Uploader } from '../uploads.svelte.js';
|
|
4
5
|
export type { FileRowPayload };
|
|
5
6
|
export type FilePluginOptions = {
|
|
6
7
|
/**
|
|
@@ -9,6 +10,14 @@ export type FilePluginOptions = {
|
|
|
9
10
|
* downloads the file. The first file plugin listed in a view gives its row.
|
|
10
11
|
*/
|
|
11
12
|
row?: Snippet<[FileRowPayload]>;
|
|
13
|
+
/**
|
|
14
|
+
* Upload a file and answer its URL: an empty file block's Upload, and
|
|
15
|
+
* the pasted and dropped files no other kind takes, each placed as a
|
|
16
|
+
* file block at once (one undo step), its row showing the file's name,
|
|
17
|
+
* size and progress, then filled with the URL this answers. Without
|
|
18
|
+
* it, files are only linked.
|
|
19
|
+
*/
|
|
20
|
+
upload?: Uploader;
|
|
12
21
|
};
|
|
13
22
|
/**
|
|
14
23
|
* Notion's file block: an attachment, uploaded through `upload` (or
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { MediaEmptyController } from './empty.svelte.js';
|
|
3
4
|
import type { Plugin } from '../../plugins.js';
|
|
4
5
|
import { emptyHosts } from './EmptySlot.svelte';
|
|
5
|
-
import Self from './MediaEmpty.svelte';
|
|
6
6
|
|
|
7
7
|
export type MediaEmptyOptions = {
|
|
8
8
|
/**
|
|
@@ -23,60 +23,7 @@
|
|
|
23
23
|
export const createMediaEmptyPlugin =
|
|
24
24
|
({ empty }: MediaEmptyOptions): Plugin =>
|
|
25
25
|
(edytor) => {
|
|
26
|
-
if (edytor && !emptyHosts.has(edytor)) emptyHosts.set(edytor,
|
|
26
|
+
if (edytor && !emptyHosts.has(edytor)) emptyHosts.set(edytor, empty);
|
|
27
27
|
return {};
|
|
28
28
|
};
|
|
29
29
|
</script>
|
|
30
|
-
|
|
31
|
-
<script lang="ts">
|
|
32
|
-
import { untrack } from 'svelte';
|
|
33
|
-
import type { Block } from '../../block/block.svelte.js';
|
|
34
|
-
import type { Edytor } from '../../edytor.svelte.js';
|
|
35
|
-
import type { MediaKind } from './media.js';
|
|
36
|
-
import { MediaEmptyController, type EmptyView } from './empty.svelte.js';
|
|
37
|
-
import { fileUploads } from '../uploads.svelte.js';
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* An image's or a media block's empty state: a `MediaEmptyController`,
|
|
41
|
-
* which the view's `empty` snippet draws. The kind in the
|
|
42
|
-
* block's view (`viewOf`) stores the link, or an uploaded file's URL
|
|
43
|
-
* (only on a block still empty when it lands). A readonly view, or a
|
|
44
|
-
* suggestion's preview (no `block`), may not write: no control may run
|
|
45
|
-
* `upload`. A pasted or dropped file shows its upload (`pending`); a
|
|
46
|
-
* failed one opens the panel with its error; data answered while the
|
|
47
|
-
* block was not shown fills it as soon as it shows.
|
|
48
|
-
*/
|
|
49
|
-
let {
|
|
50
|
-
block,
|
|
51
|
-
kind,
|
|
52
|
-
viewOf,
|
|
53
|
-
empty
|
|
54
|
-
}: {
|
|
55
|
-
block: Block | undefined;
|
|
56
|
-
kind: MediaKind | 'image';
|
|
57
|
-
/** The kind in a view: how it stores a source. */
|
|
58
|
-
viewOf: (edytor: Edytor | undefined) => EmptyView | undefined;
|
|
59
|
-
/** The view's `empty` snippet. */
|
|
60
|
-
empty: Snippet<[MediaEmptyController]>;
|
|
61
|
-
} = $props();
|
|
62
|
-
const panel = untrack(() => new MediaEmptyController(block, kind, viewOf(block?.edytor)));
|
|
63
|
-
/** The upload of a pasted or dropped file into this block, if any. */
|
|
64
|
-
const pending = $derived(panel.pending);
|
|
65
|
-
// After the flush that shows the block: never inside the transaction that showed it.
|
|
66
|
-
$effect(() => {
|
|
67
|
-
if (pending?.status === 'landed' && block && !block.edytor.readonly) {
|
|
68
|
-
const id = block.id;
|
|
69
|
-
untrack(() => fileUploads(block.edytor)?.fill(id));
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
// The panel opens on a failed upload, with its error; the user closes it.
|
|
73
|
-
$effect(() => {
|
|
74
|
-
if (pending?.status === 'failed')
|
|
75
|
-
untrack(() => {
|
|
76
|
-
panel.open = true;
|
|
77
|
-
panel.failed = 'upload';
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
</script>
|
|
81
|
-
|
|
82
|
-
{@render empty(panel)}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { MediaEmptyController } from './empty.svelte.js';
|
|
2
3
|
import type { Plugin } from '../../plugins.js';
|
|
3
4
|
export type MediaEmptyOptions = {
|
|
4
5
|
/**
|
|
@@ -16,18 +17,21 @@ export type MediaEmptyOptions = {
|
|
|
16
17
|
* listed claims the view.
|
|
17
18
|
*/
|
|
18
19
|
export declare const createMediaEmptyPlugin: ({ empty }: MediaEmptyOptions) => Plugin;
|
|
19
|
-
|
|
20
|
-
import
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
20
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
21
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
22
|
+
$$bindings?: Bindings;
|
|
23
|
+
} & Exports;
|
|
24
|
+
(internal: unknown, props: {
|
|
25
|
+
$$events?: Events;
|
|
26
|
+
$$slots?: Slots;
|
|
27
|
+
}): Exports & {
|
|
28
|
+
$set?: any;
|
|
29
|
+
$on?: any;
|
|
30
|
+
};
|
|
31
|
+
z_$$bindings?: Bindings;
|
|
32
|
+
}
|
|
33
|
+
declare const MediaEmpty: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
34
|
+
[evt: string]: CustomEvent<any>;
|
|
35
|
+
}, {}, {}, string>;
|
|
36
|
+
type MediaEmpty = InstanceType<typeof MediaEmpty>;
|
|
33
37
|
export default MediaEmpty;
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import { capped, mediaForms } from '../../export/forms.js';
|
|
3
|
+
import type { Block } from '../../block/block.svelte.js';
|
|
4
|
+
import type { BlockSnippetPayload, Plugin } from '../../plugins.js';
|
|
3
5
|
import EmptySlot from './EmptySlot.svelte';
|
|
4
6
|
import Control from '../Control.svelte';
|
|
5
7
|
import { labelsOf, mediaEnglish } from '../../labels.js';
|
|
8
|
+
import { emptyHosts } from './EmptySlot.svelte';
|
|
9
|
+
import UploadPreview from './UploadPreview.svelte';
|
|
10
|
+
import { fileUploads, uploadHooks, type Uploader } from '../uploads.svelte.js';
|
|
6
11
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
EMBED_ALLOW,
|
|
13
|
+
EMBED_SANDBOX,
|
|
14
|
+
embedSourceOf,
|
|
15
|
+
fileNameFor,
|
|
9
16
|
fileNameOf,
|
|
17
|
+
safeWebUrl,
|
|
18
|
+
type BookmarkCardPayload,
|
|
19
|
+
type EmbedFallbackPayload,
|
|
20
|
+
type MediaKind,
|
|
10
21
|
mediaControl,
|
|
11
22
|
mediaLink,
|
|
12
23
|
mediaPlugin,
|
|
13
|
-
mediaSourceOf,
|
|
14
24
|
mediaView,
|
|
15
25
|
safeMediaSrc,
|
|
16
26
|
LINK_REL,
|
|
@@ -20,8 +30,47 @@
|
|
|
20
30
|
|
|
21
31
|
type SourceKind = 'video' | 'audio' | 'file';
|
|
22
32
|
|
|
23
|
-
/** The view's file row
|
|
33
|
+
/** The view's markup for a file's row, a bookmark's card, an unplayable embed's link, if the app gave one. */
|
|
24
34
|
const rowOf = mediaControl('file', 'row');
|
|
35
|
+
const cardOf = mediaControl('bookmark', 'card');
|
|
36
|
+
const fallbackOf = mediaControl('embed', 'fallback');
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The view's embed allowlist: the first embed plugin listed in it (first
|
|
40
|
+
* wins, as for the kind). Never a broader list: no entry plays nothing.
|
|
41
|
+
*/
|
|
42
|
+
const providers = (block: Block | undefined) =>
|
|
43
|
+
mediaView(block?.edytor, 'embed')?.providers ?? [];
|
|
44
|
+
|
|
45
|
+
/** The fields of a bookmark's `preview` it stores and shows: text capped, images `safeWebUrl` only. */
|
|
46
|
+
export const previewData = (preview: Record<string, unknown> | null | undefined) => {
|
|
47
|
+
const fields = {
|
|
48
|
+
title: capped(preview?.title, 300),
|
|
49
|
+
description: capped(preview?.description, 1000),
|
|
50
|
+
image: safeWebUrl(preview?.image) ?? undefined,
|
|
51
|
+
icon: safeWebUrl(preview?.icon) ?? undefined
|
|
52
|
+
};
|
|
53
|
+
return Object.fromEntries(Object.entries(fields).filter(([, value]) => value !== undefined));
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/** A file's row: its source, name and size, and whether it is uploading. */
|
|
57
|
+
const fileRow = (
|
|
58
|
+
block: Block | undefined,
|
|
59
|
+
src: string,
|
|
60
|
+
name: string,
|
|
61
|
+
size: number | undefined,
|
|
62
|
+
progress?: number | null
|
|
63
|
+
): FileRowPayload => ({
|
|
64
|
+
block,
|
|
65
|
+
src,
|
|
66
|
+
name,
|
|
67
|
+
size,
|
|
68
|
+
sizeLabel:
|
|
69
|
+
size === undefined ? '' : labelsOf(block?.edytor, 'media', mediaEnglish).fileSize(size),
|
|
70
|
+
uploading: progress !== undefined,
|
|
71
|
+
progress: progress ?? null,
|
|
72
|
+
link: mediaLink({ draggable: 'false', download: name })
|
|
73
|
+
});
|
|
25
74
|
|
|
26
75
|
/** The files each kind takes: a video, an audio track, any other file. */
|
|
27
76
|
const ACCEPTS: Record<SourceKind, (file: File) => boolean> = {
|
|
@@ -48,32 +97,22 @@
|
|
|
48
97
|
* attachment; Notion's): a media kind (`mediaPlugin`) drawn by this
|
|
49
98
|
* snippet, a link or an uploaded file stored as one data write (a file's
|
|
50
99
|
* whole data, its source, name and size; a video's or audio track's
|
|
51
|
-
* `src`), and with an `upload
|
|
52
|
-
* (`media.files
|
|
100
|
+
* `src`), and with an `upload` (its uploader), the pasted, dropped and
|
|
101
|
+
* picked files it takes (`media.files`). A video or an audio track
|
|
53
102
|
* exports as its tag in a `figure` and imports from one (bare, or in a
|
|
54
|
-
* `figure`) with a safe `src` or `source
|
|
55
|
-
*
|
|
103
|
+
* `figure`) with a safe `src` or `source`, a file as its link; the file
|
|
104
|
+
* kind brings its `row` markup (`own`).
|
|
56
105
|
*/
|
|
57
106
|
export const sourcePlugin = (
|
|
58
107
|
kind: SourceKind,
|
|
59
108
|
keywords: string[],
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const src = safeMediaSrc(block.data?.src);
|
|
63
|
-
// The tag, then its attributes: `<video src="…" controls></video>`.
|
|
64
|
-
const media = src ? `<${kind}` + ` src="${escapeHtml(src)}" controls></${kind}>` : '';
|
|
65
|
-
return `<figure>${media}<figcaption>${caption}</figcaption></figure>`;
|
|
66
|
-
},
|
|
67
|
-
parse: (el) => {
|
|
68
|
-
const src = mediaSourceOf(claimed(el, kind));
|
|
69
|
-
return src ? { src } : undefined;
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
own: Pick<MediaView, 'row'> = {}
|
|
109
|
+
own: Pick<MediaView, 'row'> = {},
|
|
110
|
+
upload?: Uploader
|
|
73
111
|
): Plugin =>
|
|
74
|
-
mediaPlugin(kind, keywords, () => {
|
|
112
|
+
mediaPlugin(kind, keywords, (edytor) => {
|
|
75
113
|
return {
|
|
76
114
|
...own,
|
|
115
|
+
hooks: uploadHooks(edytor, upload),
|
|
77
116
|
store: (block, value, file) => {
|
|
78
117
|
const data = sourceData(kind, value, file);
|
|
79
118
|
if (!data) return 'invalid';
|
|
@@ -83,47 +122,111 @@
|
|
|
83
122
|
},
|
|
84
123
|
record: {
|
|
85
124
|
snippet: source,
|
|
86
|
-
// Its files
|
|
87
|
-
upload
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
125
|
+
// Its files, with an `upload`: an Upload and pasted or dropped files.
|
|
126
|
+
...(upload && {
|
|
127
|
+
upload: {
|
|
128
|
+
send: upload,
|
|
129
|
+
accepts: ACCEPTS[kind],
|
|
130
|
+
fallback: kind === 'file',
|
|
131
|
+
data: (file: File, answer: string) => sourceData(kind, answer, file),
|
|
132
|
+
filled: (data: Record<string, unknown>) => safeMediaSrc(data.src) !== null
|
|
133
|
+
}
|
|
134
|
+
}),
|
|
135
|
+
...mediaForms()[kind]
|
|
94
136
|
}
|
|
95
137
|
};
|
|
96
138
|
});
|
|
139
|
+
|
|
140
|
+
export { source };
|
|
97
141
|
</script>
|
|
98
142
|
|
|
99
143
|
<!--
|
|
100
|
-
A file (its name and size, linking to it), a video or an
|
|
101
|
-
the browser's player,
|
|
102
|
-
caption below.
|
|
144
|
+
A media block: a file (its name and size, linking to it), a video or an
|
|
145
|
+
audio track in the browser's player, an embed's player (or its link), a
|
|
146
|
+
bookmark's card, or the empty block until it has a source; its caption below.
|
|
103
147
|
-->
|
|
104
148
|
{#snippet source({ block, content }: BlockSnippetPayload<Record<string, unknown>>)}
|
|
105
|
-
{@const
|
|
106
|
-
{
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
149
|
+
{@const url = safeWebUrl(block.data.url)}
|
|
150
|
+
{@const src =
|
|
151
|
+
block.type === 'embed' || block.type === 'bookmark' ? url : safeMediaSrc(block.data.src)}
|
|
152
|
+
{@const player =
|
|
153
|
+
block.type === 'embed' && block.handle ? embedSourceOf(url, providers(block.handle)) : null}
|
|
154
|
+
{@const pending =
|
|
155
|
+
block.handle && !src ? fileUploads(block.handle.edytor)?.of(block.id) : undefined}
|
|
156
|
+
{#if player}
|
|
157
|
+
{@const { height, aspectRatio = '16 / 9' } = player.provider}
|
|
158
|
+
<div
|
|
159
|
+
use:block.void
|
|
160
|
+
data-edytor-embed
|
|
161
|
+
style:aspect-ratio={height ? undefined : aspectRatio}
|
|
162
|
+
style:height={height ? `${height}px` : undefined}
|
|
163
|
+
>
|
|
164
|
+
<iframe
|
|
165
|
+
src={player.src}
|
|
166
|
+
title={player.provider.name}
|
|
167
|
+
sandbox={EMBED_SANDBOX}
|
|
168
|
+
allow={EMBED_ALLOW}
|
|
169
|
+
referrerpolicy="strict-origin-when-cross-origin"
|
|
170
|
+
loading="lazy"
|
|
171
|
+
allowfullscreen
|
|
172
|
+
style="display: block; width: 100%; height: 100%; border: 0"
|
|
173
|
+
></iframe>
|
|
174
|
+
</div>
|
|
175
|
+
{:else if url && block.type === 'embed'}
|
|
176
|
+
<!-- A link no provider plays (a peer may store any), or a suggestion's preview (no handle, so no
|
|
177
|
+
view's allowlist): a plain link, never a frame. -->
|
|
178
|
+
<div use:block.void data-edytor-embed-unsupported>
|
|
179
|
+
<Control
|
|
180
|
+
own={fallbackOf}
|
|
181
|
+
initial={link}
|
|
182
|
+
payload={{ block: block.handle, url, link: mediaLink() }}
|
|
183
|
+
/>
|
|
184
|
+
</div>
|
|
185
|
+
{:else if url && block.type === 'bookmark'}
|
|
186
|
+
<div use:block.void data-edytor-bookmark>
|
|
187
|
+
<Control
|
|
188
|
+
own={cardOf}
|
|
189
|
+
initial={card}
|
|
190
|
+
payload={{
|
|
191
|
+
block: block.handle,
|
|
192
|
+
url,
|
|
193
|
+
...previewData(block.data),
|
|
194
|
+
link: mediaLink({ draggable: 'false' })
|
|
195
|
+
} as BookmarkCardPayload}
|
|
196
|
+
/>
|
|
197
|
+
</div>
|
|
198
|
+
{:else if src && block.type === 'file'}
|
|
110
199
|
<div use:block.void data-edytor-file>
|
|
111
200
|
<Control
|
|
112
201
|
own={rowOf}
|
|
113
202
|
{initial}
|
|
114
|
-
payload={
|
|
115
|
-
block
|
|
203
|
+
payload={fileRow(
|
|
204
|
+
block.handle,
|
|
116
205
|
src,
|
|
117
|
-
|
|
118
|
-
size
|
|
119
|
-
|
|
120
|
-
size === undefined
|
|
121
|
-
? ''
|
|
122
|
-
: labelsOf(block.handle?.edytor, 'media', mediaEnglish).fileSize(size),
|
|
123
|
-
link: mediaLink({ draggable: 'false', download: name })
|
|
124
|
-
}}
|
|
206
|
+
fileNameFor(block.data, src),
|
|
207
|
+
typeof block.data.size === 'number' ? block.data.size : undefined
|
|
208
|
+
)}
|
|
125
209
|
/>
|
|
126
210
|
</div>
|
|
211
|
+
{:else if !src && pending?.status === 'uploading' && !emptyHosts.has(block.handle!.edytor)}
|
|
212
|
+
<!-- An upload with no empty markup to draw it: the file's name and size at once, its progress. -->
|
|
213
|
+
<div use:block.void data-edytor-media-empty>
|
|
214
|
+
{#if block.type === 'file' && pending.preview}
|
|
215
|
+
<Control
|
|
216
|
+
own={rowOf}
|
|
217
|
+
{initial}
|
|
218
|
+
payload={fileRow(
|
|
219
|
+
block.handle,
|
|
220
|
+
pending.preview,
|
|
221
|
+
pending.name,
|
|
222
|
+
pending.size,
|
|
223
|
+
pending.progress
|
|
224
|
+
)}
|
|
225
|
+
/>
|
|
226
|
+
{:else}
|
|
227
|
+
<UploadPreview upload={pending} />
|
|
228
|
+
{/if}
|
|
229
|
+
</div>
|
|
127
230
|
{:else if src && block.type === 'video'}
|
|
128
231
|
<div use:block.void data-edytor-video>
|
|
129
232
|
<!-- svelte-ignore a11y_media_has_caption -->
|
|
@@ -144,8 +247,8 @@
|
|
|
144
247
|
<div use:block.void data-edytor-media-empty>
|
|
145
248
|
<EmptySlot
|
|
146
249
|
block={block.handle}
|
|
147
|
-
kind={block.type as
|
|
148
|
-
viewOf={(edytor) => mediaView(edytor, block.type as
|
|
250
|
+
kind={block.type as MediaKind}
|
|
251
|
+
viewOf={(edytor) => mediaView(edytor, block.type as MediaKind)}
|
|
149
252
|
/>
|
|
150
253
|
</div>
|
|
151
254
|
{/if}
|
|
@@ -154,11 +257,34 @@
|
|
|
154
257
|
<figcaption>{@render content()}</figcaption>
|
|
155
258
|
{/snippet}
|
|
156
259
|
|
|
260
|
+
<!-- An embed no provider plays: the link itself. -->
|
|
261
|
+
{#snippet link({ url, link }: EmbedFallbackPayload)}
|
|
262
|
+
<a href={url} target="_blank" rel={LINK_REL} {@attach link}>{url}</a>
|
|
263
|
+
{/snippet}
|
|
264
|
+
|
|
265
|
+
<!-- Notion's card: the page's title, description and URL (with its icon) beside its cover. -->
|
|
266
|
+
{#snippet card({ url, title, description, image, icon, link }: BookmarkCardPayload)}
|
|
267
|
+
<a href={url} target="_blank" rel={LINK_REL} draggable="false" {@attach link}>
|
|
268
|
+
<span data-edytor-bookmark-text>
|
|
269
|
+
<span data-edytor-bookmark-title>{title ?? url}</span>
|
|
270
|
+
{#if description}<span data-edytor-bookmark-description>{description}</span>{/if}
|
|
271
|
+
<span data-edytor-bookmark-url>
|
|
272
|
+
{#if icon}<img src={icon} alt="" draggable="false" />{/if}<span>{url}</span>
|
|
273
|
+
</span>
|
|
274
|
+
</span>
|
|
275
|
+
{#if image}
|
|
276
|
+
<span data-edytor-bookmark-cover><img src={image} alt="" draggable="false" /></span>
|
|
277
|
+
{/if}
|
|
278
|
+
</a>
|
|
279
|
+
{/snippet}
|
|
280
|
+
|
|
157
281
|
<!-- A file: its name and size, a link downloading it. -->
|
|
158
|
-
{#snippet initial({ src, name, sizeLabel, link }: FileRowPayload)}
|
|
282
|
+
{#snippet initial({ src, name, sizeLabel, link, uploading, progress }: FileRowPayload)}
|
|
159
283
|
<a href={src} target="_blank" rel={LINK_REL} draggable="false" download={name} {@attach link}>
|
|
160
284
|
<span aria-hidden="true">📎</span>
|
|
161
285
|
<span data-edytor-file-name>{name}</span>
|
|
162
286
|
{#if sizeLabel}<span data-edytor-file-size>{sizeLabel}</span>{/if}
|
|
163
287
|
</a>
|
|
288
|
+
{#if uploading}<progress data-edytor-file-progress value={progress ?? undefined} max="1"
|
|
289
|
+
></progress>{/if}
|
|
164
290
|
{/snippet}
|
|
@@ -1,18 +1,25 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BlockSnippetPayload, Plugin } from '../../plugins.js';
|
|
2
|
+
import { type Uploader } from '../uploads.svelte.js';
|
|
2
3
|
import { type MediaView } from './media.js';
|
|
4
|
+
declare const source: ({ block, content }: BlockSnippetPayload<Record<string, unknown>>) => ReturnType<import("svelte").Snippet>;
|
|
3
5
|
type SourceKind = 'video' | 'audio' | 'file';
|
|
6
|
+
/** The fields of a bookmark's `preview` it stores and shows: text capped, images `safeWebUrl` only. */
|
|
7
|
+
export declare const previewData: (preview: Record<string, unknown> | null | undefined) => {
|
|
8
|
+
[k: string]: string | undefined;
|
|
9
|
+
};
|
|
4
10
|
/**
|
|
5
11
|
* The plugin of a kind holding one source (a video, an audio track, an
|
|
6
12
|
* attachment; Notion's): a media kind (`mediaPlugin`) drawn by this
|
|
7
13
|
* snippet, a link or an uploaded file stored as one data write (a file's
|
|
8
14
|
* whole data, its source, name and size; a video's or audio track's
|
|
9
|
-
* `src`), and with an `upload
|
|
10
|
-
* (`media.files
|
|
15
|
+
* `src`), and with an `upload` (its uploader), the pasted, dropped and
|
|
16
|
+
* picked files it takes (`media.files`). A video or an audio track
|
|
11
17
|
* exports as its tag in a `figure` and imports from one (bare, or in a
|
|
12
|
-
* `figure`) with a safe `src` or `source
|
|
13
|
-
*
|
|
18
|
+
* `figure`) with a safe `src` or `source`, a file as its link; the file
|
|
19
|
+
* kind brings its `row` markup (`own`).
|
|
14
20
|
*/
|
|
15
|
-
export declare const sourcePlugin: (kind: SourceKind, keywords: string[],
|
|
21
|
+
export declare const sourcePlugin: (kind: SourceKind, keywords: string[], own?: Pick<MediaView, "row">, upload?: Uploader) => Plugin;
|
|
22
|
+
export { source };
|
|
16
23
|
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
17
24
|
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
18
25
|
$$bindings?: Bindings;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import './upload.css';
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import { getContext } from 'svelte';
|
|
7
|
+
import type { Edytor } from '../../edytor.svelte.js';
|
|
8
|
+
import type { FileUpload } from '../uploads.svelte.js';
|
|
9
|
+
import { labelsOf, mediaEnglish } from '../../labels.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A file uploading, the plugin's own markup when the view has no empty
|
|
13
|
+
* markup to draw it: an image at once from its object URL (this view's
|
|
14
|
+
* only, never stored) with the progress over it; another file's name and
|
|
15
|
+
* size, then the progress (indeterminate until `upload` reports one).
|
|
16
|
+
*/
|
|
17
|
+
let {
|
|
18
|
+
upload,
|
|
19
|
+
image = false
|
|
20
|
+
}: { upload: Extract<FileUpload, { status: 'uploading' }>; image?: boolean } = $props();
|
|
21
|
+
const labels = labelsOf(getContext<Edytor>('edytor'), 'media', mediaEnglish);
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<div data-edytor-upload data-edytor-upload-image={image ? '' : undefined} role="status">
|
|
25
|
+
{#if image && upload.preview}
|
|
26
|
+
<img src={upload.preview} alt={upload.name} draggable="false" />
|
|
27
|
+
{:else}
|
|
28
|
+
<span data-edytor-file-name>{upload.name}</span>
|
|
29
|
+
<span data-edytor-file-size>{labels.fileSize(upload.size)}</span>
|
|
30
|
+
{/if}
|
|
31
|
+
<progress value={upload.progress ?? undefined} max="1" aria-label={labels.uploading}></progress>
|
|
32
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import './upload.css';
|
|
2
|
+
import type { FileUpload } from '../uploads.svelte.js';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
upload: Extract<FileUpload, {
|
|
5
|
+
status: 'uploading';
|
|
6
|
+
}>;
|
|
7
|
+
image?: boolean;
|
|
8
|
+
};
|
|
9
|
+
declare const UploadPreview: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
10
|
+
type UploadPreview = ReturnType<typeof UploadPreview>;
|
|
11
|
+
export default UploadPreview;
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
2
|
import type { Plugin } from '../../plugins.js';
|
|
3
3
|
import { sourcePlugin } from './SourceBlock.svelte';
|
|
4
|
+
import type { Uploader } from '../uploads.svelte.js';
|
|
5
|
+
|
|
6
|
+
export type VideoPluginOptions = {
|
|
7
|
+
/**
|
|
8
|
+
* Upload a video file and answer its URL: an empty block's Upload, and
|
|
9
|
+
* the pasted and dropped video files, each placed as a block at once
|
|
10
|
+
* (one undo step), showing its name and progress, then filled with the
|
|
11
|
+
* URL this answers. Without it, videos are only linked.
|
|
12
|
+
*/
|
|
13
|
+
upload?: Uploader;
|
|
14
|
+
};
|
|
4
15
|
|
|
5
16
|
/**
|
|
6
17
|
* Notion's video block: a video file (an `http(s)` link, or an upload
|
|
@@ -8,5 +19,6 @@
|
|
|
8
19
|
* A YouTube or Vimeo link is an embed (`createEmbedPlugin()`). Void: its only
|
|
9
20
|
* text is the caption.
|
|
10
21
|
*/
|
|
11
|
-
export const createVideoPlugin = (): Plugin =>
|
|
22
|
+
export const createVideoPlugin = ({ upload }: VideoPluginOptions = {}): Plugin =>
|
|
23
|
+
sourcePlugin('video', ['movie', 'mp4', 'clip'], {}, upload);
|
|
12
24
|
</script>
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import type { Plugin } from '../../plugins.js';
|
|
2
|
+
import type { Uploader } from '../uploads.svelte.js';
|
|
3
|
+
export type VideoPluginOptions = {
|
|
4
|
+
/**
|
|
5
|
+
* Upload a video file and answer its URL: an empty block's Upload, and
|
|
6
|
+
* the pasted and dropped video files, each placed as a block at once
|
|
7
|
+
* (one undo step), showing its name and progress, then filled with the
|
|
8
|
+
* URL this answers. Without it, videos are only linked.
|
|
9
|
+
*/
|
|
10
|
+
upload?: Uploader;
|
|
11
|
+
};
|
|
2
12
|
/**
|
|
3
13
|
* Notion's video block: a video file (an `http(s)` link, or an upload
|
|
4
14
|
* through `upload`) in the browser's player, with an editable caption.
|
|
5
15
|
* A YouTube or Vimeo link is an embed (`createEmbedPlugin()`). Void: its only
|
|
6
16
|
* text is the caption.
|
|
7
17
|
*/
|
|
8
|
-
export declare const createVideoPlugin: () => Plugin;
|
|
18
|
+
export declare const createVideoPlugin: ({ upload }?: VideoPluginOptions) => Plugin;
|
|
9
19
|
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
10
20
|
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
11
21
|
$$bindings?: Bindings;
|
|
@@ -52,16 +52,25 @@ export declare class MediaEmptyController {
|
|
|
52
52
|
* block). Show a passive placeholder then.
|
|
53
53
|
*/
|
|
54
54
|
get readonly(): boolean;
|
|
55
|
-
/** The
|
|
55
|
+
/** The kind's plugin was given an `upload`: offer Upload. */
|
|
56
56
|
get canUpload(): boolean;
|
|
57
57
|
/** The upload of a pasted or dropped file into this block, if any (its `status`, `progress`, `preview`). */
|
|
58
58
|
get pending(): FileUpload | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* The file uploading into this block, shown at once: its object URL
|
|
61
|
+
* (this view's only, never stored; revoked once the upload ends), else `null`.
|
|
62
|
+
*/
|
|
63
|
+
get preview(): string | null;
|
|
64
|
+
/** The share of the upload sent, `0` to `1`; `null` before a report, or with no upload. */
|
|
65
|
+
get progress(): number | null;
|
|
59
66
|
/** Embed `value` (default the `draft`): the block takes the link, or `failed` says why not. */
|
|
60
67
|
embed: (value?: string) => void;
|
|
61
68
|
/**
|
|
62
|
-
* Upload `file` with
|
|
63
|
-
*
|
|
64
|
-
*
|
|
69
|
+
* Upload `file` with its kind's uploader (its plugin's `upload`), the
|
|
70
|
+
* block showing it meanwhile (`pending`, `preview`, `progress`), and
|
|
71
|
+
* store the URL it answers, only on the block as it was picked from:
|
|
72
|
+
* still in the tree, of its kind and empty (a peer may have set a
|
|
73
|
+
* source, or deleted it, meanwhile).
|
|
65
74
|
*/
|
|
66
75
|
upload: (picked: File) => Promise<void>;
|
|
67
76
|
/** The link field (`{@attach empty.field}`): Enter embeds its `draft`. */
|