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
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import type { BlockHandleController } from './BlockHandleController.svelte.js';
|
|
11
11
|
import { gapBefore, handleSpan } from '../columns/gaps.js';
|
|
12
12
|
import { renderSkipped, rendered } from '../../surface/overlay.js';
|
|
13
|
-
import { getOwnRowBottom } from '
|
|
13
|
+
import { getOwnRowBottom } from '../../dnd/geometry.js';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* The handles, in the overlay: one per registered movable block that
|
|
@@ -201,14 +201,15 @@
|
|
|
201
201
|
pointer-events: none;
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
/* Over a gap between two columns (one hit rule, the handles'): the handle
|
|
205
|
-
* spans the gap right of the column resize band,
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
* shows
|
|
204
|
+
/* Over a gap between two columns (one hit rule, the handles'): the handle's
|
|
205
|
+
* box spans the gap right of the column resize band, centered in the gap
|
|
206
|
+
* (`columns/gaps.ts`, one measurement), and takes the pointer at its
|
|
207
|
+
* block's whole row, shown or not — a pointer there hovers the block, so
|
|
208
|
+
* its grip is reached from any side. Its `+` (compact) and grip stand
|
|
209
|
+
* together flush with its block (Notion's "+ ⋮⋮"), never shrunk: wider
|
|
210
|
+
* than the box, the `+` reaches left under the band (the resizers' layer
|
|
211
|
+
* is above the handles'): where the band's guide shows, at every height,
|
|
212
|
+
* a press resizes; the `+`'s part left of the band takes its own. */
|
|
212
213
|
[data-edytor-block-handle-host][data-over-gap='true'] {
|
|
213
214
|
box-sizing: border-box;
|
|
214
215
|
width: var(--edytor-handle-gap-width, auto);
|
|
@@ -216,6 +217,10 @@
|
|
|
216
217
|
padding-inline-end: 0;
|
|
217
218
|
}
|
|
218
219
|
|
|
220
|
+
[data-edytor-block-handle-host][data-over-gap='true'] > :global(*) {
|
|
221
|
+
flex-shrink: 0;
|
|
222
|
+
}
|
|
223
|
+
|
|
219
224
|
[data-edytor-block-handle-host][data-over-gap='true']::before {
|
|
220
225
|
content: '';
|
|
221
226
|
position: absolute;
|
|
@@ -238,27 +243,4 @@
|
|
|
238
243
|
padding-inline-end: 0;
|
|
239
244
|
}
|
|
240
245
|
}
|
|
241
|
-
|
|
242
|
-
/* Where a handle's drag lands (`DropIndicator`): the bar (4px) and the nest
|
|
243
|
-
* backdrop, placed in the overlay and shown (`data-shown`) by the plugin;
|
|
244
|
-
* their look is a theme's (`edytor/themes/notion.css`). */
|
|
245
|
-
:global([data-edytor-drop-indicator]),
|
|
246
|
-
:global([data-edytor-drop-backdrop]) {
|
|
247
|
-
position: absolute;
|
|
248
|
-
pointer-events: none;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
:global([data-edytor-drop-indicator]) {
|
|
252
|
-
z-index: 100;
|
|
253
|
-
box-sizing: border-box;
|
|
254
|
-
height: 4px;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
:global([data-edytor-drop-backdrop]) {
|
|
258
|
-
z-index: 99;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
:global([data-edytor-drop-backdrop]:not([data-shown='true'])) {
|
|
262
|
-
visibility: hidden;
|
|
263
|
-
}
|
|
264
246
|
</style>
|
|
@@ -3,6 +3,7 @@ import { SvelteMap, SvelteSet } from 'svelte/reactivity';
|
|
|
3
3
|
import BlockHandles from './BlockHandles.svelte';
|
|
4
4
|
import { BlockHandleController } from './BlockHandleController.svelte.js';
|
|
5
5
|
import { hidden } from '../../selection/visibility.js';
|
|
6
|
+
import { isDropTarget } from '../../dnd/placement.js';
|
|
6
7
|
import { all, listen } from '../../utils/listen.js';
|
|
7
8
|
/**
|
|
8
9
|
* Block handles in the overlay, created lazily: a handle mounts
|
|
@@ -123,7 +124,7 @@ export const createBlockHandlesPlugin = (options = {}) => (edytor) => {
|
|
|
123
124
|
},
|
|
124
125
|
onBlockAttached: ({ node, block }) => {
|
|
125
126
|
// A table's rows move by its own row menus, its cells never (`table.fits`).
|
|
126
|
-
if (!
|
|
127
|
+
if (!isDropTarget(edytor, block))
|
|
127
128
|
return;
|
|
128
129
|
const offDropTarget = controller.addDropTarget(node, block);
|
|
129
130
|
// A layout and its columns are drop targets but have no handle (as
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Notion's drag ghost: a copy of the dragged blocks, rendered as they look in
|
|
3
|
-
* the editor, scaled down, that follows the pointer (the browser adds its own
|
|
4
|
-
* drag-image translucency). Cloned once when the drag starts and mounted by
|
|
5
|
-
* the drag library for the frame the browser takes its picture
|
|
6
|
-
* (`setCustomNativeDragPreview`), then removed with it.
|
|
7
|
-
*/
|
|
8
1
|
export type DragPreview = {
|
|
9
2
|
/** The ghost, `[data-edytor-drag-preview]`, to mount in the drag library's container. */
|
|
10
3
|
element: HTMLElement;
|
|
@@ -33,3 +26,29 @@ export declare const dragPreview: (root: HTMLElement, nodes: HTMLElement[], poin
|
|
|
33
26
|
clientX: number;
|
|
34
27
|
clientY: number;
|
|
35
28
|
}, columns?: number[]) => DragPreview;
|
|
29
|
+
type Pointer = {
|
|
30
|
+
clientX: number;
|
|
31
|
+
clientY: number;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* One of the editor's own drags from `element` (a block's handle, a table's
|
|
35
|
+
* grip): `canDrag` asks whether it may start, `data` is what its targets
|
|
36
|
+
* read, `id` the block another view sees it carry (no view takes it as a
|
|
37
|
+
* foreign drop); `begin` runs as it starts (the ghost and the targets),
|
|
38
|
+
* `start` once it has, and `end` after the drop target's own drop (the drag
|
|
39
|
+
* library tells the source first).
|
|
40
|
+
*/
|
|
41
|
+
export declare const dragSource: (element: HTMLElement, { canDrag, data, id, begin, start, end }: {
|
|
42
|
+
canDrag: () => boolean;
|
|
43
|
+
data: () => Record<string | symbol, unknown>;
|
|
44
|
+
id: () => string;
|
|
45
|
+
begin: (pointer: Pointer, setImage: DataTransfer["setDragImage"] | null) => void;
|
|
46
|
+
start?: () => void;
|
|
47
|
+
end: (dropped: boolean) => void;
|
|
48
|
+
}) => import("../../dnd/vendor/pragmatic/pragmatic-drag-and-drop/internal-types").CleanupFn;
|
|
49
|
+
/**
|
|
50
|
+
* The drag's ghost (`dragPreview` of `nodes` under `root`), mounted for the
|
|
51
|
+
* browser's picture of it, when the drag has an image to set.
|
|
52
|
+
*/
|
|
53
|
+
export declare const ghost: (setImage: DataTransfer["setDragImage"] | null, root: HTMLElement | null | undefined, nodes: HTMLElement[], pointer: Pointer, columns?: number[]) => void;
|
|
54
|
+
export {};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { draggable, setCustomNativeDragPreview } from '../../dnd/pragmatic.js';
|
|
2
|
+
import { EDYTOR_BLOCK_DRAG_MIME } from '../../events/onDrop.js';
|
|
1
3
|
/**
|
|
2
4
|
* Notion's drag ghost: a copy of the dragged blocks, rendered as they look in
|
|
3
5
|
* the editor, scaled down, that follows the pointer (the browser adds its own
|
|
@@ -227,3 +229,34 @@ export const dragPreview = (root, nodes, pointer, columns) => {
|
|
|
227
229
|
};
|
|
228
230
|
return { element, offset };
|
|
229
231
|
};
|
|
232
|
+
/**
|
|
233
|
+
* One of the editor's own drags from `element` (a block's handle, a table's
|
|
234
|
+
* grip): `canDrag` asks whether it may start, `data` is what its targets
|
|
235
|
+
* read, `id` the block another view sees it carry (no view takes it as a
|
|
236
|
+
* foreign drop); `begin` runs as it starts (the ghost and the targets),
|
|
237
|
+
* `start` once it has, and `end` after the drop target's own drop (the drag
|
|
238
|
+
* library tells the source first).
|
|
239
|
+
*/
|
|
240
|
+
export const dragSource = (element, { canDrag, data, id, begin, start, end }) => draggable({
|
|
241
|
+
element,
|
|
242
|
+
canDrag,
|
|
243
|
+
getInitialData: data,
|
|
244
|
+
getInitialDataForExternal: () => ({ [EDYTOR_BLOCK_DRAG_MIME]: id() }),
|
|
245
|
+
onGenerateDragPreview: ({ nativeSetDragImage, location }) => begin(location.current.input, nativeSetDragImage),
|
|
246
|
+
onDragStart: start,
|
|
247
|
+
onDrop: ({ location }) => queueMicrotask(() => end(location.current.dropTargets.length > 0))
|
|
248
|
+
});
|
|
249
|
+
/**
|
|
250
|
+
* The drag's ghost (`dragPreview` of `nodes` under `root`), mounted for the
|
|
251
|
+
* browser's picture of it, when the drag has an image to set.
|
|
252
|
+
*/
|
|
253
|
+
export const ghost = (setImage, root, nodes, pointer, columns) => {
|
|
254
|
+
if (!setImage || !root || !nodes.length)
|
|
255
|
+
return;
|
|
256
|
+
const preview = dragPreview(root, nodes, pointer, columns);
|
|
257
|
+
setCustomNativeDragPreview({
|
|
258
|
+
nativeSetDragImage: setImage,
|
|
259
|
+
getOffset: preview.offset,
|
|
260
|
+
render: ({ container }) => container.append(preview.element)
|
|
261
|
+
});
|
|
262
|
+
};
|
|
@@ -69,6 +69,11 @@ export declare class BlockMenuController {
|
|
|
69
69
|
* after). Delete and Turn into act on their `members`, its items too.
|
|
70
70
|
*/
|
|
71
71
|
blocks: Block[];
|
|
72
|
+
/**
|
|
73
|
+
* Where the menu stands: the handle that opened it (a `ChromeAnchor`:
|
|
74
|
+
* your `menu` places itself beside it, its flyout beside the menu);
|
|
75
|
+
* `null` while closed.
|
|
76
|
+
*/
|
|
72
77
|
anchor: HTMLElement | null;
|
|
73
78
|
query: string;
|
|
74
79
|
/** The keyboard's row. */
|
|
@@ -63,7 +63,12 @@ export class BlockMenuController {
|
|
|
63
63
|
* after). Delete and Turn into act on their `members`, its items too.
|
|
64
64
|
*/
|
|
65
65
|
blocks = $state([]);
|
|
66
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Where the menu stands: the handle that opened it (a `ChromeAnchor`:
|
|
68
|
+
* your `menu` places itself beside it, its flyout beside the menu);
|
|
69
|
+
* `null` while closed.
|
|
70
|
+
*/
|
|
71
|
+
anchor = $state.raw(null);
|
|
67
72
|
query = $state('');
|
|
68
73
|
/** The keyboard's row. */
|
|
69
74
|
index = $state(0);
|
|
@@ -473,7 +478,7 @@ export class BlockMenuController {
|
|
|
473
478
|
caret(block) {
|
|
474
479
|
const text = block && shownText(block, 'first');
|
|
475
480
|
if (text || !block?.isInTree)
|
|
476
|
-
this.edytor.dispatcher.
|
|
481
|
+
this.edytor.dispatcher.caretIn(text, 0);
|
|
477
482
|
else
|
|
478
483
|
this.edytor.selection.select(blockSelection([block.id]));
|
|
479
484
|
this.focus();
|
|
@@ -11,14 +11,9 @@ import { BlockMenuController, colorCommands } from './BlockMenuController.svelte
|
|
|
11
11
|
export const createBlockMenuPlugin = (options = {}) => (edytor) => {
|
|
12
12
|
const controller = new BlockMenuController(edytor, options);
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* no room, top-aligned with it, moved up as far as the viewport needs
|
|
18
|
-
* (never above its top edge), and scrolls inside when taller (Notion):
|
|
19
|
-
* every row is in the viewport, reachable by the mouse. It follows
|
|
20
|
-
* scrolls and resizes, and closes when the handle leaves the view.
|
|
21
|
-
* Measured in the overlay's frame; the placement (or the close) is written after.
|
|
14
|
+
* The menu places itself by `controller.anchor` (the handle), its
|
|
15
|
+
* flyout by the menu; measured in the overlay's frame, the menu closes
|
|
16
|
+
* when the handle leaves the page or the view.
|
|
22
17
|
*/
|
|
23
18
|
const close = () => controller.close(false);
|
|
24
19
|
const place = (host) => {
|
|
@@ -27,50 +22,10 @@ export const createBlockMenuPlugin = (options = {}) => (edytor) => {
|
|
|
27
22
|
return;
|
|
28
23
|
if (!anchor?.isConnected)
|
|
29
24
|
return close;
|
|
30
|
-
const view = host.ownerDocument.defaultView;
|
|
31
|
-
const menu = host.querySelector('[data-edytor-block-menu]') ??
|
|
32
|
-
host.firstElementChild;
|
|
33
|
-
if (!view || !menu)
|
|
34
|
-
return;
|
|
35
|
-
const [gap, edge, between] = [8, 8, 4];
|
|
36
25
|
const rect = anchor.getBoundingClientRect();
|
|
37
|
-
|
|
26
|
+
const height = host.ownerDocument.defaultView?.innerHeight ?? Infinity;
|
|
27
|
+
if (rect.bottom < 0 || rect.top > height)
|
|
38
28
|
return close;
|
|
39
|
-
// Layout sizes, not the box: the menus open with a scale (0.98 → 1), and a
|
|
40
|
-
// box read mid-animation would place them up to 2% short of their size.
|
|
41
|
-
const [width, height] = [menu.offsetWidth, menu.offsetHeight];
|
|
42
|
-
const right = rect.right + gap;
|
|
43
|
-
const left = rect.left - gap - width;
|
|
44
|
-
let x = right + width <= view.innerWidth - edge
|
|
45
|
-
? right
|
|
46
|
-
: left >= edge
|
|
47
|
-
? left
|
|
48
|
-
: Math.max(edge, Math.min(right, view.innerWidth - edge - width));
|
|
49
|
-
const y = rect.top + height <= view.innerHeight - edge
|
|
50
|
-
? rect.top
|
|
51
|
-
: Math.max(edge, Math.min(rect.bottom, view.innerHeight - edge) - height);
|
|
52
|
-
const flyout = host.querySelector('[data-edytor-block-menu-flyout]');
|
|
53
|
-
const frame = flyout?.parentElement;
|
|
54
|
-
let side = '';
|
|
55
|
-
let shift = '';
|
|
56
|
-
if (flyout && frame) {
|
|
57
|
-
const box = { width: flyout.offsetWidth, height: flyout.offsetHeight };
|
|
58
|
-
// Left of the menu when its right has no room (the menu stays where it is).
|
|
59
|
-
if (x + width + between + box.width > view.innerWidth - edge &&
|
|
60
|
-
x - between - box.width >= edge) {
|
|
61
|
-
side = 'row-reverse';
|
|
62
|
-
x -= between + box.width;
|
|
63
|
-
}
|
|
64
|
-
const top = Math.max(edge, Math.min(y, view.innerHeight - edge - box.height));
|
|
65
|
-
shift = `${top - y}px`;
|
|
66
|
-
}
|
|
67
|
-
return () => {
|
|
68
|
-
Object.assign(host.style, { left: `${x}px`, top: `${y}px` });
|
|
69
|
-
if (frame)
|
|
70
|
-
frame.style.flexDirection = side;
|
|
71
|
-
if (flyout)
|
|
72
|
-
flyout.style.marginTop = shift;
|
|
73
|
-
};
|
|
74
29
|
};
|
|
75
30
|
return {
|
|
76
31
|
// Colours by name in the slash menu (`/red`), as in Notion.
|
package/dist/plugins/chrome.d.ts
CHANGED
|
@@ -9,17 +9,33 @@ import type { Snippet } from 'svelte';
|
|
|
9
9
|
import type { Attachment } from 'svelte/attachments';
|
|
10
10
|
import type { Edytor } from '../edytor.svelte.js';
|
|
11
11
|
import { type BlockActivation, type BlockAddition } from './blockHandles/BlockHandleController.svelte.js';
|
|
12
|
+
/**
|
|
13
|
+
* Where a chrome surface stands, for the app's markup to place itself
|
|
14
|
+
* (Floating UI's virtual element: `computePosition(anchor, floating, …)`,
|
|
15
|
+
* or bits-ui's `customAnchor`): its box read now, in client pixels, on
|
|
16
|
+
* every call (the caret, the selection, a block, a grip, a button), and
|
|
17
|
+
* the element whose scrolling ancestors move it. The package places no
|
|
18
|
+
* popup.
|
|
19
|
+
*/
|
|
20
|
+
export type ChromeAnchor = {
|
|
21
|
+
getBoundingClientRect: () => DOMRect;
|
|
22
|
+
readonly contextElement?: Element;
|
|
23
|
+
};
|
|
24
|
+
/** A {@link ChromeAnchor} reading `rect` (an empty box while there is none) inside `context`. */
|
|
25
|
+
export declare const virtualAnchor: (rect: () => DOMRect | null | undefined, context: () => Element | null | undefined) => ChromeAnchor;
|
|
12
26
|
/**
|
|
13
27
|
* Mount the app's `snippet` for a chrome surface in a fixed host of the
|
|
14
|
-
* overlay (`data-<name
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
28
|
+
* overlay (`data-<name>`), rendered with `payload` while `shown` holds and
|
|
29
|
+
* closed (`close`) when the view turns readonly; the markup places itself
|
|
30
|
+
* by its controller's `anchor`. `measure` runs on the overlay's frames (a
|
|
31
|
+
* surface whose anchor left the page closes there). Without a snippet the
|
|
32
|
+
* surface renders nothing (its controller still works): nothing is
|
|
33
|
+
* mounted. Answers the teardown.
|
|
18
34
|
*/
|
|
19
35
|
export declare const mountChrome: <T>(edytor: Edytor, snippet: Snippet<[T]> | undefined, payload: T, shown: () => unknown, place: {
|
|
20
36
|
name: string;
|
|
21
37
|
zIndex: number;
|
|
22
|
-
measure
|
|
38
|
+
measure?: (host: HTMLElement, origin: DOMRect) => (() => void) | void;
|
|
23
39
|
}, close?: () => void) => () => void;
|
|
24
40
|
/**
|
|
25
41
|
* One row of a chrome list a controller builds for the app's markup: the
|
|
@@ -68,6 +84,12 @@ export declare const identify: (node: HTMLElement, id: string, role?: string) =>
|
|
|
68
84
|
export declare const attribute: (node: HTMLElement, name: string, value: string | undefined) => void;
|
|
69
85
|
/** Whether `node` may name a highlighted row (`aria-activedescendant`): a field, or an element with a role. */
|
|
70
86
|
export declare const namesRows: (node: HTMLElement) => boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Every press in `document` (capture; WebKit's lone `mousedown` after a
|
|
89
|
+
* drag too, `onPress`) outside the elements `inside` matches: `outside`
|
|
90
|
+
* hears it. Answers the teardown.
|
|
91
|
+
*/
|
|
92
|
+
export declare const onPressOutside: (edytor: Edytor, document: Document, inside: string, outside: (event: MouseEvent) => void) => () => void;
|
|
71
93
|
/**
|
|
72
94
|
* A handle menu's events on the editor `node` (the block menu, the `+`'s
|
|
73
95
|
* menu): a grip's activation (`BLOCK_ACTIVATE_EVENT`), a `+`'s offer
|
package/dist/plugins/chrome.js
CHANGED
|
@@ -2,15 +2,24 @@ import Chrome from './Chrome.svelte';
|
|
|
2
2
|
import { onPress } from '../events/onFocus.js';
|
|
3
3
|
import { all, listen } from '../utils/listen.js';
|
|
4
4
|
import { BLOCK_ACTIVATE_EVENT, BLOCK_ADD_EVENT } from './blockHandles/BlockHandleController.svelte.js';
|
|
5
|
+
/** A {@link ChromeAnchor} reading `rect` (an empty box while there is none) inside `context`. */
|
|
6
|
+
export const virtualAnchor = (rect, context) => ({
|
|
7
|
+
getBoundingClientRect: () => rect() ?? new DOMRect(),
|
|
8
|
+
get contextElement() {
|
|
9
|
+
return context() ?? undefined;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
5
12
|
/**
|
|
6
13
|
* Mount the app's `snippet` for a chrome surface in a fixed host of the
|
|
7
|
-
* overlay (`data-<name
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
14
|
+
* overlay (`data-<name>`), rendered with `payload` while `shown` holds and
|
|
15
|
+
* closed (`close`) when the view turns readonly; the markup places itself
|
|
16
|
+
* by its controller's `anchor`. `measure` runs on the overlay's frames (a
|
|
17
|
+
* surface whose anchor left the page closes there). Without a snippet the
|
|
18
|
+
* surface renders nothing (its controller still works): nothing is
|
|
19
|
+
* mounted. Answers the teardown.
|
|
11
20
|
*/
|
|
12
21
|
export const mountChrome = (edytor, snippet, payload, shown, place, close) => snippet
|
|
13
|
-
? edytor.overlay.mount((Chrome), { edytor, snippet, payload, shown, close }, place.name, place.zIndex, place.measure)
|
|
22
|
+
? edytor.overlay.mount((Chrome), { edytor, snippet, payload, shown, close }, place.name, place.zIndex, place.measure ?? (() => { }))
|
|
14
23
|
: () => { };
|
|
15
24
|
/**
|
|
16
25
|
* Write `value` as `node`'s attribute `name`, only when it changes:
|
|
@@ -74,6 +83,15 @@ export const attribute = (node, name, value) => {
|
|
|
74
83
|
};
|
|
75
84
|
/** Whether `node` may name a highlighted row (`aria-activedescendant`): a field, or an element with a role. */
|
|
76
85
|
export const namesRows = (node) => isField(node) || node.hasAttribute('role');
|
|
86
|
+
/**
|
|
87
|
+
* Every press in `document` (capture; WebKit's lone `mousedown` after a
|
|
88
|
+
* drag too, `onPress`) outside the elements `inside` matches: `outside`
|
|
89
|
+
* hears it. Answers the teardown.
|
|
90
|
+
*/
|
|
91
|
+
export const onPressOutside = (edytor, document, inside, outside) => onPress(edytor, document, (event) => {
|
|
92
|
+
if (!event.target?.closest?.(inside))
|
|
93
|
+
outside(event);
|
|
94
|
+
}, true);
|
|
77
95
|
/**
|
|
78
96
|
* A handle menu's events on the editor `node` (the block menu, the `+`'s
|
|
79
97
|
* menu): a grip's activation (`BLOCK_ACTIVATE_EVENT`), a `+`'s offer
|
|
@@ -81,7 +99,4 @@ export const namesRows = (node) => isField(node) || node.hasAttribute('role');
|
|
|
81
99
|
* matches (WebKit's lone `mousedown` after a drag too, `onPress`). Answers
|
|
82
100
|
* the teardown.
|
|
83
101
|
*/
|
|
84
|
-
export const handleMenuEvents = (edytor, node, activate, add, inside, outside) => all(listen(node, BLOCK_ACTIVATE_EVENT, activate), listen(node, BLOCK_ADD_EVENT, add),
|
|
85
|
-
if (!event.target?.closest?.(inside))
|
|
86
|
-
outside();
|
|
87
|
-
}, true));
|
|
102
|
+
export const handleMenuEvents = (edytor, node, activate, add, inside, outside) => all(listen(node, BLOCK_ACTIVATE_EVENT, activate), listen(node, BLOCK_ADD_EVENT, add), onPressOutside(edytor, node.ownerDocument, inside, outside));
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { getContext } from 'svelte';
|
|
3
3
|
import type { BlockView } from '../../plugins.js';
|
|
4
4
|
import type { Edytor } from '../../edytor.svelte.js';
|
|
5
|
-
import { DEFAULT_CODE_SETTINGS
|
|
5
|
+
import { DEFAULT_CODE_SETTINGS } from './languages.js';
|
|
6
6
|
import { languageMenus } from './languageMenu.svelte.js';
|
|
7
7
|
import { CodeHeader } from './header.svelte.js';
|
|
8
8
|
|
|
@@ -14,8 +14,10 @@
|
|
|
14
14
|
|
|
15
15
|
/** The options of the view rendering it (a suggestion's preview included). */
|
|
16
16
|
const edytor = getContext<Edytor>('edytor');
|
|
17
|
-
|
|
18
|
-
const
|
|
17
|
+
// The first code plugin listed owns the view's options (it draws the kind).
|
|
18
|
+
const menu = languageMenus.get(edytor);
|
|
19
|
+
const settings = menu?.settings ?? DEFAULT_CODE_SETTINGS;
|
|
20
|
+
const header = new CodeHeader(() => block, settings, menu);
|
|
19
21
|
$effect(() => header.dispose);
|
|
20
22
|
</script>
|
|
21
23
|
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
|
+
import { codeForms } from '../../export/forms.js';
|
|
2
3
|
import './code.css';
|
|
3
4
|
import type { Plugin, MarkSnippetPayload, BlockSnippetPayload } from '../../plugins.js';
|
|
4
5
|
import { Text } from '../../text/text.svelte.js';
|
|
5
6
|
import { runIntent } from '../../events/beforeInputCommands.js';
|
|
6
|
-
|
|
7
|
+
|
|
7
8
|
import { shown } from '../../selection/visibility.js';
|
|
8
9
|
import { caretBeside } from '../../selection/replaceSelection.js';
|
|
9
10
|
import { siblingSlot } from '../../session/handles.js';
|
|
10
11
|
import CodeHeader from './CodeHeader.svelte';
|
|
11
|
-
import LanguageMenuPanel from './LanguageMenu.svelte';
|
|
12
12
|
import { LanguageMenu, languageMenus } from './languageMenu.svelte.js';
|
|
13
13
|
import { codeEnglish, keywordsOf, labelsOf } from '../../labels.js';
|
|
14
14
|
import {
|
|
15
15
|
DEFAULT_CODE_SETTINGS,
|
|
16
|
-
codeSettings,
|
|
17
16
|
languageOf,
|
|
18
17
|
tokenizeCode,
|
|
19
18
|
type CodePluginOptions,
|
|
@@ -47,8 +46,9 @@
|
|
|
47
46
|
header: options.header,
|
|
48
47
|
menu: options.menu
|
|
49
48
|
};
|
|
50
|
-
|
|
51
|
-
//
|
|
49
|
+
// The view's code options and language list: the first code plugin
|
|
50
|
+
// listed owns them, as it draws the kind (first listed wins); the
|
|
51
|
+
// header reads them from it.
|
|
52
52
|
if (edytor && !languageMenus.has(edytor))
|
|
53
53
|
languageMenus.set(edytor, new LanguageMenu(edytor, own));
|
|
54
54
|
const ownMenu = () => {
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
onEdytorAttached: ({ node }) => {
|
|
116
116
|
const menu = ownMenu();
|
|
117
117
|
const snippet = menu?.settings.menu;
|
|
118
|
-
return snippet && menu.panel.mount(node,
|
|
118
|
+
return snippet && menu.panel.mount(node, snippet, menu, () => menu.open !== null);
|
|
119
119
|
},
|
|
120
120
|
hotkeys: {
|
|
121
121
|
// Alt+F10 at a caret in a code line: the keys go to its language button
|
|
@@ -174,7 +174,7 @@
|
|
|
174
174
|
edytor.idToBlock.get(
|
|
175
175
|
edytor.insertBlocks(siblingSlot(line), [{ type: 'codeLine' }]).ids[0] ?? ''
|
|
176
176
|
);
|
|
177
|
-
return prevent(() => edytor.dispatcher.
|
|
177
|
+
return prevent(() => edytor.dispatcher.caretIn(next()?.firstText, 0));
|
|
178
178
|
}
|
|
179
179
|
prevent(() => runIntent(edytor, 'insertParagraph'));
|
|
180
180
|
}
|
|
@@ -189,7 +189,10 @@
|
|
|
189
189
|
prevent(() => {
|
|
190
190
|
const before = caretBeside(block, 'blockBefore', new Set([block]));
|
|
191
191
|
edytor.deleteBlock(block.id);
|
|
192
|
-
edytor.dispatcher.
|
|
192
|
+
edytor.dispatcher.caretIn(
|
|
193
|
+
before?.text ?? code.firstEditableText,
|
|
194
|
+
before?.offset ?? 0
|
|
195
|
+
);
|
|
193
196
|
});
|
|
194
197
|
}
|
|
195
198
|
// Backspace in an empty block right after a code block removes it; the
|
|
@@ -202,7 +205,7 @@
|
|
|
202
205
|
prevent(() => {
|
|
203
206
|
edytor.deleteBlock(block.id);
|
|
204
207
|
const text = previous.lastText;
|
|
205
|
-
edytor.dispatcher.
|
|
208
|
+
edytor.dispatcher.caretIn(text, text?.length ?? 0);
|
|
206
209
|
});
|
|
207
210
|
}
|
|
208
211
|
if (block.type !== 'codeLine') return;
|
|
@@ -213,7 +216,7 @@
|
|
|
213
216
|
const [at, line] = [offset - startText.segStart, startText.stringContent];
|
|
214
217
|
// A closer typed before the same character steps over it.
|
|
215
218
|
if (CLOSERS.has(value) && line[at] === value) {
|
|
216
|
-
prevent(() => edytor.dispatcher.
|
|
219
|
+
prevent(() => edytor.dispatcher.caretIn(startText, at + 1));
|
|
217
220
|
}
|
|
218
221
|
// Quotes pair only at a word boundary: the apostrophe in `don't` stays single.
|
|
219
222
|
const inWord = QUOTES.has(value) && /\w/.test((line[at - 1] ?? '') + (line[at] ?? ''));
|
|
@@ -230,7 +233,7 @@
|
|
|
230
233
|
|
|
231
234
|
blocks: {
|
|
232
235
|
code: {
|
|
233
|
-
...
|
|
236
|
+
...codeForms().code,
|
|
234
237
|
snippet: code,
|
|
235
238
|
presets: [
|
|
236
239
|
{
|
|
@@ -244,8 +247,8 @@
|
|
|
244
247
|
empty: { content: [], children: [{ type: 'codeLine', content: [{ text: '' }] }] }
|
|
245
248
|
},
|
|
246
249
|
codeLine: {
|
|
250
|
+
...codeForms().codeLine,
|
|
247
251
|
snippet: codeLine,
|
|
248
|
-
html: (_, content) => `<pre><code>${content}</code></pre>`,
|
|
249
252
|
transformText: ({ text, block }) =>
|
|
250
253
|
tokenizeCode(text.stringContent, lineLanguage(block.id)),
|
|
251
254
|
// A line holding newlines keeps its first line; each other becomes a code line after it.
|
|
@@ -9,6 +9,7 @@ import { Text } from '../../text/text.svelte.js';
|
|
|
9
9
|
import { attribute } from '../chrome.js';
|
|
10
10
|
import { languageOf } from './languages.js';
|
|
11
11
|
import { all, listen } from '../../utils/listen.js';
|
|
12
|
+
import { keysOf } from '../list.svelte.js';
|
|
12
13
|
/** How long Copy reads Copied after a copy, in milliseconds. */
|
|
13
14
|
const COPIED_FOR = 1200;
|
|
14
15
|
/** A code block's text: its lines, joined by newlines. */
|
|
@@ -112,17 +113,12 @@ export class CodeHeader {
|
|
|
112
113
|
const mousedown = (event) => event.preventDefault();
|
|
113
114
|
// A click from Enter or Space has no pointer (`detail` 0): the keys opened it.
|
|
114
115
|
const click = (event) => this.toggle(event.detail === 0);
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
this.menu?.release();
|
|
122
|
-
else
|
|
123
|
-
return;
|
|
124
|
-
event.preventDefault();
|
|
125
|
-
};
|
|
116
|
+
const open = () => this.expanded || this.toggle(true);
|
|
117
|
+
const keydown = keysOf({
|
|
118
|
+
ArrowDown: open,
|
|
119
|
+
ArrowUp: open,
|
|
120
|
+
Escape: () => this.menu?.release()
|
|
121
|
+
});
|
|
126
122
|
const off = listen(node, 'mousedown', mousedown);
|
|
127
123
|
const off2 = listen(node, 'click', click);
|
|
128
124
|
const off3 = listen(node, 'keydown', keydown);
|
|
@@ -41,8 +41,11 @@ export declare class LanguageMenu extends ChromeList {
|
|
|
41
41
|
} | null;
|
|
42
42
|
/** The search field's text. */
|
|
43
43
|
query: string;
|
|
44
|
-
/**
|
|
45
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Where the list stands: the open block's language button
|
|
46
|
+
* (`ChromeAnchor`), which your `menu` places itself under.
|
|
47
|
+
*/
|
|
48
|
+
get anchor(): import("../chrome.js").ChromeAnchor;
|
|
46
49
|
/** The open block's language id. */
|
|
47
50
|
get current(): string | null;
|
|
48
51
|
/** The rows the query keeps: a language the plugin does not list first (the block's own), then the list. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { untrack } from 'svelte';
|
|
2
2
|
import { takeKeys } from '../../events/onFocus.js';
|
|
3
3
|
import { attribute } from '../chrome.js';
|
|
4
|
-
import { ChromeList, holdKeys } from '../list.svelte.js';
|
|
4
|
+
import { ChromeList, holdKeys, keysOf } from '../list.svelte.js';
|
|
5
5
|
import { Anchored } from '../anchored.svelte.js';
|
|
6
6
|
import { languageOf } from './languages.js';
|
|
7
7
|
import { all, listen } from '../../utils/listen.js';
|
|
@@ -40,9 +40,12 @@ export class LanguageMenu extends ChromeList {
|
|
|
40
40
|
this.settings = settings;
|
|
41
41
|
this.panel = new Anchored(edytor, 'edytor-code-language-host', () => (this.open ? this.#button(this.open.block) : undefined), () => this.close());
|
|
42
42
|
}
|
|
43
|
-
/**
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Where the list stands: the open block's language button
|
|
45
|
+
* (`ChromeAnchor`), which your `menu` places itself under.
|
|
46
|
+
*/
|
|
47
|
+
get anchor() {
|
|
48
|
+
return this.panel.anchor;
|
|
46
49
|
}
|
|
47
50
|
/** The open block's language id. */
|
|
48
51
|
get current() {
|
|
@@ -121,7 +124,6 @@ export class LanguageMenu extends ChromeList {
|
|
|
121
124
|
if (!open)
|
|
122
125
|
return;
|
|
123
126
|
this.open = null;
|
|
124
|
-
this.panel.box = null;
|
|
125
127
|
this.query = '';
|
|
126
128
|
this.edytor.overlay.invalidate();
|
|
127
129
|
if (keys === 'button')
|
|
@@ -152,21 +154,12 @@ export class LanguageMenu extends ChromeList {
|
|
|
152
154
|
return all(off, off2);
|
|
153
155
|
});
|
|
154
156
|
/** The search field's keys (`keys`). */
|
|
155
|
-
#keydown = (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
else if (event.key === 'Enter')
|
|
162
|
-
this.pick();
|
|
163
|
-
else if (event.key === 'Escape')
|
|
164
|
-
this.close(this.open?.keys ? 'button' : 'editor');
|
|
165
|
-
else
|
|
166
|
-
return;
|
|
167
|
-
event.preventDefault();
|
|
168
|
-
event.stopPropagation();
|
|
169
|
-
};
|
|
157
|
+
#keydown = keysOf({
|
|
158
|
+
ArrowDown: () => this.move(1),
|
|
159
|
+
ArrowUp: () => this.move(-1),
|
|
160
|
+
Enter: () => this.pick(),
|
|
161
|
+
Escape: () => this.close(this.open?.keys ? 'button' : 'editor')
|
|
162
|
+
}, true);
|
|
170
163
|
/**
|
|
171
164
|
* The keys back to the editor from a language button (its Escape): the
|
|
172
165
|
* host takes the focus, the caret shown where the selection is.
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { type LanguageDefinition } from '@tanstack/highlight/core';
|
|
9
9
|
import type { JSONText } from '../../utils/json.js';
|
|
10
|
-
import type { Edytor } from '../../edytor.svelte.js';
|
|
11
10
|
import type { Snippet } from 'svelte';
|
|
12
11
|
import type { CodeHeader } from './header.svelte.js';
|
|
13
12
|
import type { LanguageMenu } from './languageMenu.svelte.js';
|
|
@@ -68,8 +67,6 @@ export type CodeSettings = {
|
|
|
68
67
|
menu?: Snippet<[LanguageMenu]>;
|
|
69
68
|
};
|
|
70
69
|
export declare const DEFAULT_CODE_SETTINGS: CodeSettings;
|
|
71
|
-
/** Each view's code options, for its code blocks' header (which reads them through its view). */
|
|
72
|
-
export declare const codeSettings: WeakMap<Edytor, CodeSettings>;
|
|
73
70
|
/** A code block's language id: its `data.language`, else the default. */
|
|
74
71
|
export declare const languageOf: (data: {
|
|
75
72
|
language?: unknown;
|
|
@@ -99,7 +99,5 @@ export const DEFAULT_CODE_SETTINGS = {
|
|
|
99
99
|
languages: CODE_LANGUAGES,
|
|
100
100
|
defaultLanguage: 'javascript'
|
|
101
101
|
};
|
|
102
|
-
/** Each view's code options, for its code blocks' header (which reads them through its view). */
|
|
103
|
-
export const codeSettings = new WeakMap();
|
|
104
102
|
/** A code block's language id: its `data.language`, else the default. */
|
|
105
103
|
export const languageOf = (data, { defaultLanguage }) => (typeof data?.language === 'string' && data.language ? data.language : defaultLanguage);
|