@dou-ui/editor 0.0.0-stage → 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +10 -2
- package/dist/catalog.js +18 -0
- package/dist/catalog.js.map +1 -0
- package/dist/code/code-editor-block.js +6 -0
- package/dist/code/code-editor-block.js.map +1 -0
- package/dist/code/code-editor-block.vue_vue_type_script_setup_true_lang.js +116 -0
- package/dist/code/code-editor-block.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/code/index.js +69 -0
- package/dist/code/index.js.map +1 -0
- package/dist/code/languages.js +51 -0
- package/dist/code/languages.js.map +1 -0
- package/dist/code/view.js +255 -0
- package/dist/code/view.js.map +1 -0
- package/dist/collaboration/binding.js +381 -0
- package/dist/collaboration/binding.js.map +1 -0
- package/dist/collaboration/cursors.js +150 -0
- package/dist/collaboration/cursors.js.map +1 -0
- package/dist/collaboration/index.js +108 -0
- package/dist/collaboration/index.js.map +1 -0
- package/dist/collaboration/order.js +88 -0
- package/dist/collaboration/order.js.map +1 -0
- package/dist/collaboration/table.js +234 -0
- package/dist/collaboration/table.js.map +1 -0
- package/dist/collaboration/text.js +91 -0
- package/dist/collaboration/text.js.map +1 -0
- package/dist/components/block-handle.js +6 -0
- package/dist/components/block-handle.js.map +1 -0
- package/dist/components/block-handle.vue_vue_type_script_setup_true_lang.js +474 -0
- package/dist/components/block-handle.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/bubble-toolbar.js +6 -0
- package/dist/components/bubble-toolbar.js.map +1 -0
- package/dist/components/bubble-toolbar.vue_vue_type_script_setup_true_lang.js +381 -0
- package/dist/components/bubble-toolbar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/comment-button.js +6 -0
- package/dist/components/comment-button.js.map +1 -0
- package/dist/components/comment-button.vue_vue_type_script_setup_true_lang.js +83 -0
- package/dist/components/comment-button.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/comment-card.js +6 -0
- package/dist/components/comment-card.js.map +1 -0
- package/dist/components/comment-card.vue_vue_type_script_setup_true_lang.js +104 -0
- package/dist/components/comment-card.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/menu-escape.js +25 -0
- package/dist/components/menu-escape.js.map +1 -0
- package/dist/components/search-bar.js +6 -0
- package/dist/components/search-bar.js.map +1 -0
- package/dist/components/search-bar.vue_vue_type_script_setup_true_lang.js +192 -0
- package/dist/components/search-bar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/slash-menu.js +6 -0
- package/dist/components/slash-menu.js.map +1 -0
- package/dist/components/slash-menu.vue_vue_type_script_setup_true_lang.js +164 -0
- package/dist/components/slash-menu.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/core/align.js +94 -0
- package/dist/core/align.js.map +1 -0
- package/dist/core/block-selection.js +155 -0
- package/dist/core/block-selection.js.map +1 -0
- package/dist/core/blocks.js +132 -0
- package/dist/core/blocks.js.map +1 -0
- package/dist/core/changes.js +85 -0
- package/dist/core/changes.js.map +1 -0
- package/dist/core/colors.js +16 -0
- package/dist/core/colors.js.map +1 -0
- package/dist/core/commands.js +379 -0
- package/dist/core/commands.js.map +1 -0
- package/dist/core/comments.js +186 -0
- package/dist/core/comments.js.map +1 -0
- package/dist/core/compare.js +106 -0
- package/dist/core/compare.js.map +1 -0
- package/dist/core/convert.js +28 -0
- package/dist/core/convert.js.map +1 -0
- package/dist/core/diff.js +141 -0
- package/dist/core/diff.js.map +1 -0
- package/dist/core/editor.js +138 -0
- package/dist/core/editor.js.map +1 -0
- package/dist/core/extension.js +99 -0
- package/dist/core/extension.js.map +1 -0
- package/dist/core/file-drop.js +56 -0
- package/dist/core/file-drop.js.map +1 -0
- package/dist/core/highlight.js +120 -0
- package/dist/core/highlight.js.map +1 -0
- package/dist/core/input-rules.js +61 -0
- package/dist/core/input-rules.js.map +1 -0
- package/dist/core/keymap.js +38 -0
- package/dist/core/keymap.js.map +1 -0
- package/dist/core/model.js +196 -0
- package/dist/core/model.js.map +1 -0
- package/dist/core/output.js +263 -0
- package/dist/core/output.js.map +1 -0
- package/dist/core/plugins.js +102 -0
- package/dist/core/plugins.js.map +1 -0
- package/dist/core/prepare.js +102 -0
- package/dist/core/prepare.js.map +1 -0
- package/dist/core/schema.js +158 -0
- package/dist/core/schema.js.map +1 -0
- package/dist/core/search.js +197 -0
- package/dist/core/search.js.map +1 -0
- package/dist/core/selection.js +16 -0
- package/dist/core/selection.js.map +1 -0
- package/dist/core/slash.js +83 -0
- package/dist/core/slash.js.map +1 -0
- package/dist/core/transaction.js +311 -0
- package/dist/core/transaction.js.map +1 -0
- package/dist/define-block.js +177 -0
- package/dist/define-block.js.map +1 -0
- package/dist/document.js +157 -0
- package/dist/document.js.map +1 -0
- package/dist/dom.js +48 -0
- package/dist/dom.js.map +1 -0
- package/dist/editor.js +33 -0
- package/dist/editor.js.map +1 -0
- package/dist/editor.vue_vue_type_script_setup_true_lang.js +564 -0
- package/dist/editor.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/editor2.js +6 -0
- package/dist/editor2.js.map +1 -0
- package/dist/extensions/align/align-menu.js +6 -0
- package/dist/extensions/align/align-menu.js.map +1 -0
- package/dist/extensions/align/align-menu.vue_vue_type_script_setup_true_lang.js +82 -0
- package/dist/extensions/align/align-menu.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/extensions/align/align-sub.js +6 -0
- package/dist/extensions/align/align-sub.js.map +1 -0
- package/dist/extensions/align/align-sub.vue_vue_type_script_setup_true_lang.js +57 -0
- package/dist/extensions/align/align-sub.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/extensions/align/commands.js +40 -0
- package/dist/extensions/align/commands.js.map +1 -0
- package/dist/extensions/align/index.js +27 -0
- package/dist/extensions/align/index.js.map +1 -0
- package/dist/extensions/attachment/attachment-block.js +6 -0
- package/dist/extensions/attachment/attachment-block.js.map +1 -0
- package/dist/extensions/attachment/attachment-block.vue_vue_type_script_setup_true_lang.js +119 -0
- package/dist/extensions/attachment/attachment-block.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/extensions/attachment/files.js +66 -0
- package/dist/extensions/attachment/files.js.map +1 -0
- package/dist/extensions/attachment/index.js +132 -0
- package/dist/extensions/attachment/index.js.map +1 -0
- package/dist/extensions/blocks.js +170 -0
- package/dist/extensions/blocks.js.map +1 -0
- package/dist/extensions/callout/callout-block.js +6 -0
- package/dist/extensions/callout/callout-block.js.map +1 -0
- package/dist/extensions/callout/callout-block.vue_vue_type_script_setup_true_lang.js +71 -0
- package/dist/extensions/callout/callout-block.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/extensions/callout/html.js +61 -0
- package/dist/extensions/callout/html.js.map +1 -0
- package/dist/extensions/callout/index.js +52 -0
- package/dist/extensions/callout/index.js.map +1 -0
- package/dist/extensions/callout/tones.js +12 -0
- package/dist/extensions/callout/tones.js.map +1 -0
- package/dist/extensions/code-block/code-block-view.js +6 -0
- package/dist/extensions/code-block/code-block-view.js.map +1 -0
- package/dist/extensions/code-block/code-block-view.vue_vue_type_script_setup_true_lang.js +87 -0
- package/dist/extensions/code-block/code-block-view.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/extensions/code-block/index.js +98 -0
- package/dist/extensions/code-block/index.js.map +1 -0
- package/dist/extensions/code-block/languages.js +116 -0
- package/dist/extensions/code-block/languages.js.map +1 -0
- package/dist/extensions/colors/color-menu.js +6 -0
- package/dist/extensions/colors/color-menu.js.map +1 -0
- package/dist/extensions/colors/color-menu.vue_vue_type_script_setup_true_lang.js +113 -0
- package/dist/extensions/colors/color-menu.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/extensions/colors/index.js +49 -0
- package/dist/extensions/colors/index.js.map +1 -0
- package/dist/extensions/colors/palette.js +26 -0
- package/dist/extensions/colors/palette.js.map +1 -0
- package/dist/extensions/editor-kit.js +35 -0
- package/dist/extensions/editor-kit.js.map +1 -0
- package/dist/extensions/embed/embed-block.js +6 -0
- package/dist/extensions/embed/embed-block.js.map +1 -0
- package/dist/extensions/embed/embed-block.vue_vue_type_script_setup_true_lang.js +210 -0
- package/dist/extensions/embed/embed-block.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/extensions/embed/index.js +118 -0
- package/dist/extensions/embed/index.js.map +1 -0
- package/dist/extensions/embed/targets.js +79 -0
- package/dist/extensions/embed/targets.js.map +1 -0
- package/dist/extensions/formatting.js +153 -0
- package/dist/extensions/formatting.js.map +1 -0
- package/dist/extensions/image/image-block.js +6 -0
- package/dist/extensions/image/image-block.js.map +1 -0
- package/dist/extensions/image/image-block.vue_vue_type_script_setup_true_lang.js +206 -0
- package/dist/extensions/image/image-block.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/extensions/image/index.js +125 -0
- package/dist/extensions/image/index.js.map +1 -0
- package/dist/extensions/image/uploads.js +96 -0
- package/dist/extensions/image/uploads.js.map +1 -0
- package/dist/extensions/list-html.js +58 -0
- package/dist/extensions/list-html.js.map +1 -0
- package/dist/extensions/lists.js +182 -0
- package/dist/extensions/lists.js.map +1 -0
- package/dist/extensions/mention/index.js +56 -0
- package/dist/extensions/mention/index.js.map +1 -0
- package/dist/extensions/mention/mention-menu.js +6 -0
- package/dist/extensions/mention/mention-menu.js.map +1 -0
- package/dist/extensions/mention/mention-menu.vue_vue_type_script_setup_true_lang.js +132 -0
- package/dist/extensions/mention/mention-menu.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/extensions/mention/state.js +113 -0
- package/dist/extensions/mention/state.js.map +1 -0
- package/dist/extensions/table/commands.js +356 -0
- package/dist/extensions/table/commands.js.map +1 -0
- package/dist/extensions/table/html.js +134 -0
- package/dist/extensions/table/html.js.map +1 -0
- package/dist/extensions/table/index.js +56 -0
- package/dist/extensions/table/index.js.map +1 -0
- package/dist/extensions/table/plugin.js +81 -0
- package/dist/extensions/table/plugin.js.map +1 -0
- package/dist/extensions/table/schema.js +258 -0
- package/dist/extensions/table/schema.js.map +1 -0
- package/dist/extensions/table/table-controls.js +6 -0
- package/dist/extensions/table/table-controls.js.map +1 -0
- package/dist/extensions/table/table-controls.vue_vue_type_script_setup_true_lang.js +698 -0
- package/dist/extensions/table/table-controls.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/extensions/table/view.js +19 -0
- package/dist/extensions/table/view.js.map +1 -0
- package/dist/extensions/toggle/index.js +87 -0
- package/dist/extensions/toggle/index.js.map +1 -0
- package/dist/extensions/toggle/state.js +120 -0
- package/dist/extensions/toggle/state.js.map +1 -0
- package/dist/extensions/toggle/toggle-block.js +6 -0
- package/dist/extensions/toggle/toggle-block.js.map +1 -0
- package/dist/extensions/toggle/toggle-block.vue_vue_type_script_setup_true_lang.js +42 -0
- package/dist/extensions/toggle/toggle-block.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/locale.js +522 -0
- package/dist/locale.js.map +1 -0
- package/dist/markdown/index.js +24 -0
- package/dist/markdown/index.js.map +1 -0
- package/dist/style.css +1 -0
- package/dist/style.d.ts +1 -0
- package/dist/style.js +8 -0
- package/dist/types/catalog.d.ts +8 -0
- package/dist/types/code/code-editor-block.vue.d.ts +17 -0
- package/dist/types/code/index.d.ts +18 -0
- package/dist/types/code/languages.d.ts +7 -0
- package/dist/types/code/types.d.ts +37 -0
- package/dist/types/code/view.d.ts +12 -0
- package/dist/types/collaboration/binding.d.ts +32 -0
- package/dist/types/collaboration/cursors.d.ts +26 -0
- package/dist/types/collaboration/index.d.ts +47 -0
- package/dist/types/collaboration/order.d.ts +20 -0
- package/dist/types/collaboration/table.d.ts +25 -0
- package/dist/types/collaboration/text.d.ts +9 -0
- package/dist/types/components/block-handle.vue.d.ts +3 -0
- package/dist/types/components/bubble-toolbar.vue.d.ts +7 -0
- package/dist/types/components/comment-button.vue.d.ts +3 -0
- package/dist/types/components/comment-card.vue.d.ts +3 -0
- package/dist/types/components/menu-escape.d.ts +7 -0
- package/dist/types/components/search-bar.vue.d.ts +22 -0
- package/dist/types/components/slash-menu.vue.d.ts +11 -0
- package/dist/types/core/align.d.ts +16 -0
- package/dist/types/core/block-selection.d.ts +22 -0
- package/dist/types/core/blocks.d.ts +52 -0
- package/dist/types/core/changes.d.ts +14 -0
- package/dist/types/core/colors.d.ts +4 -0
- package/dist/types/core/commands.d.ts +61 -0
- package/dist/types/core/comments.d.ts +44 -0
- package/dist/types/core/compare.d.ts +10 -0
- package/dist/types/core/convert.d.ts +12 -0
- package/dist/types/core/diff.d.ts +49 -0
- package/dist/types/core/editor.d.ts +64 -0
- package/dist/types/core/extension.d.ts +167 -0
- package/dist/types/core/file-drop.d.ts +19 -0
- package/dist/types/core/highlight.d.ts +32 -0
- package/dist/types/core/input-rules.d.ts +21 -0
- package/dist/types/core/keymap.d.ts +8 -0
- package/dist/types/core/model.d.ts +158 -0
- package/dist/types/core/output.d.ts +64 -0
- package/dist/types/core/plugins.d.ts +24 -0
- package/dist/types/core/prepare.d.ts +23 -0
- package/dist/types/core/schema.d.ts +38 -0
- package/dist/types/core/search.d.ts +83 -0
- package/dist/types/core/selection.d.ts +8 -0
- package/dist/types/core/slash.d.ts +21 -0
- package/dist/types/core/transaction.d.ts +97 -0
- package/dist/types/define-block.d.ts +66 -0
- package/dist/types/document.d.ts +46 -0
- package/dist/types/dom.d.ts +17 -0
- package/dist/types/editor.d.ts +252 -0
- package/dist/types/editor.vue.d.ts +210 -0
- package/dist/types/extensions/align/align-menu.vue.d.ts +3 -0
- package/dist/types/extensions/align/align-sub.vue.d.ts +7 -0
- package/dist/types/extensions/align/commands.d.ts +13 -0
- package/dist/types/extensions/align/index.d.ts +7 -0
- package/dist/types/extensions/attachment/attachment-block.vue.d.ts +17 -0
- package/dist/types/extensions/attachment/files.d.ts +6 -0
- package/dist/types/extensions/attachment/index.d.ts +20 -0
- package/dist/types/extensions/blocks.d.ts +8 -0
- package/dist/types/extensions/callout/callout-block.vue.d.ts +14 -0
- package/dist/types/extensions/callout/html.d.ts +4 -0
- package/dist/types/extensions/callout/index.d.ts +3 -0
- package/dist/types/extensions/callout/tones.d.ts +8 -0
- package/dist/types/extensions/code-block/code-block-view.vue.d.ts +16 -0
- package/dist/types/extensions/code-block/index.d.ts +19 -0
- package/dist/types/extensions/code-block/languages.d.ts +9 -0
- package/dist/types/extensions/colors/color-menu.vue.d.ts +3 -0
- package/dist/types/extensions/colors/index.d.ts +7 -0
- package/dist/types/extensions/colors/palette.d.ts +7 -0
- package/dist/types/extensions/editor-kit.d.ts +37 -0
- package/dist/types/extensions/embed/embed-block.vue.d.ts +16 -0
- package/dist/types/extensions/embed/index.d.ts +18 -0
- package/dist/types/extensions/embed/targets.d.ts +32 -0
- package/dist/types/extensions/formatting.d.ts +8 -0
- package/dist/types/extensions/image/image-block.vue.d.ts +16 -0
- package/dist/types/extensions/image/index.d.ts +16 -0
- package/dist/types/extensions/image/uploads.d.ts +35 -0
- package/dist/types/extensions/list-html.d.ts +11 -0
- package/dist/types/extensions/lists.d.ts +6 -0
- package/dist/types/extensions/mention/index.d.ts +11 -0
- package/dist/types/extensions/mention/mention-menu.vue.d.ts +7 -0
- package/dist/types/extensions/mention/state.d.ts +28 -0
- package/dist/types/extensions/table/commands.d.ts +69 -0
- package/dist/types/extensions/table/html.d.ts +4 -0
- package/dist/types/extensions/table/index.d.ts +8 -0
- package/dist/types/extensions/table/plugin.d.ts +4 -0
- package/dist/types/extensions/table/schema.d.ts +23 -0
- package/dist/types/extensions/table/table-controls.vue.d.ts +3 -0
- package/dist/types/extensions/table/view.d.ts +13 -0
- package/dist/types/extensions/toggle/index.d.ts +7 -0
- package/dist/types/extensions/toggle/state.d.ts +17 -0
- package/dist/types/extensions/toggle/toggle-block.vue.d.ts +14 -0
- package/dist/types/index.d.ts +266 -0
- package/dist/types/locale.d.ts +195 -0
- package/dist/types/markdown/index.d.ts +14 -0
- package/dist/types/use-comments.d.ts +17 -0
- package/dist/use-comments.js +141 -0
- package/dist/use-comments.js.map +1 -0
- package/package.json +98 -4
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import { blockFromNode } from "../core/model.js";
|
|
2
|
+
import { isSafeHref } from "../core/schema.js";
|
|
3
|
+
import { labelOf } from "../core/extension.js";
|
|
4
|
+
import { isCurrent } from "../catalog.js";
|
|
5
|
+
import { blockAround } from "../core/blocks.js";
|
|
6
|
+
import { setBlockType } from "../core/commands.js";
|
|
7
|
+
import { getBlockSelection } from "../core/block-selection.js";
|
|
8
|
+
import { editorKey, provideToolbarMenus } from "../editor.js";
|
|
9
|
+
import { DouButton, DouDropdown, DouDropdownItem, DouInput, DouToggle, DouToggleGroup, DouToolbar, DouToolbarSeparator, DouTooltip, isComposing, useFloating, useZIndex } from "dou-ui";
|
|
10
|
+
import { Fragment, Transition, computed, createBlock, createCommentVNode, createElementBlock, createSlots, createTextVNode, createVNode, defineComponent, inject, nextTick, normalizeStyle, onBeforeUnmount, onMounted, openBlock, renderList, resolveDynamicComponent, shallowRef, toDisplayString, unref, useTemplateRef, watch, withCtx, withModifiers } from "vue";
|
|
11
|
+
import { TextSelection } from "prosemirror-state";
|
|
12
|
+
import { CheckIcon, ChevronDownIcon, LinkIcon, MessagePlusIcon, UnlinkIcon } from "@dou-ui/icons";
|
|
13
|
+
import { toggleMark } from "prosemirror-commands";
|
|
14
|
+
// src/components/bubble-toolbar.vue?vue&type=script&setup=true&lang.ts
|
|
15
|
+
var _hoisted_1 = ["data-placement"];
|
|
16
|
+
var _hoisted_2 = {
|
|
17
|
+
key: 0,
|
|
18
|
+
class: "dou-editor-bubble__link"
|
|
19
|
+
};
|
|
20
|
+
var bubble_toolbar_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
21
|
+
__name: "bubble-toolbar",
|
|
22
|
+
setup(__props, { expose: __expose }) {
|
|
23
|
+
const { view, state, focused, dragging, messages, kit, comments } = inject(editorKey);
|
|
24
|
+
const panel = useTemplateRef("panel");
|
|
25
|
+
const pressing = shallowRef(false);
|
|
26
|
+
const menuOpen = shallowRef(false);
|
|
27
|
+
const toolbarMenus = provideToolbarMenus();
|
|
28
|
+
const panelFocused = shallowRef(false);
|
|
29
|
+
watch(focused, (value) => value && (panelFocused.value = false));
|
|
30
|
+
function onPanelFocusOut(event) {
|
|
31
|
+
if (!panel.value?.contains(event.relatedTarget)) panelFocused.value = false;
|
|
32
|
+
}
|
|
33
|
+
function onPanelKeyDown(event) {
|
|
34
|
+
if (event.key !== "Escape" || linking.value || event.defaultPrevented) return;
|
|
35
|
+
event.preventDefault();
|
|
36
|
+
view.value?.focus();
|
|
37
|
+
}
|
|
38
|
+
const linking = shallowRef(null);
|
|
39
|
+
const href = shallowRef("");
|
|
40
|
+
const linkInput = useTemplateRef("linkInput");
|
|
41
|
+
const formattable = computed(() => {
|
|
42
|
+
const current = state.value;
|
|
43
|
+
if (!current || getBlockSelection(current)) return false;
|
|
44
|
+
const { selection } = current;
|
|
45
|
+
if (!(selection instanceof TextSelection) || selection.empty) return false;
|
|
46
|
+
let text = false;
|
|
47
|
+
current.doc.nodesBetween(selection.from, selection.to, (node) => {
|
|
48
|
+
if (node.isTextblock && !node.type.spec.code) text = true;
|
|
49
|
+
return !text;
|
|
50
|
+
});
|
|
51
|
+
return text;
|
|
52
|
+
});
|
|
53
|
+
const open = computed(() => !!linking.value || menuOpen.value || [...toolbarMenus].some((menu) => menu.value) || panelFocused.value || focused.value && formattable.value && !pressing.value && !dragging.value);
|
|
54
|
+
const anchor = { getBoundingClientRect() {
|
|
55
|
+
const current = view.value;
|
|
56
|
+
const range = linking.value ?? current?.state.selection;
|
|
57
|
+
if (!current || !range) return new DOMRect();
|
|
58
|
+
const start = current.coordsAtPos(range.from, 1);
|
|
59
|
+
const end = current.coordsAtPos(range.to, -1);
|
|
60
|
+
const sameLine = Math.abs(start.top - end.top) < 4;
|
|
61
|
+
const left = sameLine ? start.left : start.left;
|
|
62
|
+
const right = sameLine ? end.right : Math.max(start.left + 1, current.dom.getBoundingClientRect().right);
|
|
63
|
+
return new DOMRect(left, start.top, Math.max(1, right - left), start.bottom - start.top);
|
|
64
|
+
} };
|
|
65
|
+
const { style, placement, update } = useFloating(() => open.value ? anchor : null, panel, {
|
|
66
|
+
open,
|
|
67
|
+
placement: "top",
|
|
68
|
+
offset: 8
|
|
69
|
+
});
|
|
70
|
+
const { next } = useZIndex();
|
|
71
|
+
const zIndex = shallowRef(0);
|
|
72
|
+
watch(open, (value) => value && (zIndex.value = next()), { immediate: true });
|
|
73
|
+
watch(state, () => open.value && void nextTick(update));
|
|
74
|
+
function onPointerDown(event) {
|
|
75
|
+
if (event.button === 0 && view.value?.dom.contains(event.target)) pressing.value = true;
|
|
76
|
+
}
|
|
77
|
+
function onPointerUp() {
|
|
78
|
+
if (pressing.value) pressing.value = false;
|
|
79
|
+
}
|
|
80
|
+
function onKeyDown(event) {
|
|
81
|
+
if (!view.value?.dom.contains(event.target)) return;
|
|
82
|
+
const trigger = panel.value?.querySelector("[aria-expanded=\"true\"][aria-controls]");
|
|
83
|
+
if (!trigger) return;
|
|
84
|
+
const menu = document.getElementById(trigger.getAttribute("aria-controls"));
|
|
85
|
+
if (event.key === "Escape") {
|
|
86
|
+
event.preventDefault();
|
|
87
|
+
event.stopPropagation();
|
|
88
|
+
menuOpen.value = false;
|
|
89
|
+
for (const item of toolbarMenus) item.value = false;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (!menu || ![
|
|
93
|
+
"ArrowDown",
|
|
94
|
+
"ArrowUp",
|
|
95
|
+
"Home",
|
|
96
|
+
"End",
|
|
97
|
+
"Enter"
|
|
98
|
+
].includes(event.key)) return;
|
|
99
|
+
event.preventDefault();
|
|
100
|
+
event.stopPropagation();
|
|
101
|
+
const items = Array.from(menu.querySelectorAll("[role^=\"menuitem\"]:not([aria-disabled=\"true\"])"));
|
|
102
|
+
(event.key === "ArrowUp" || event.key === "End" ? items.at(-1) : items[0])?.focus();
|
|
103
|
+
}
|
|
104
|
+
onMounted(() => {
|
|
105
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
106
|
+
document.addEventListener("pointerup", onPointerUp, true);
|
|
107
|
+
document.addEventListener("keydown", onKeyDown, true);
|
|
108
|
+
});
|
|
109
|
+
onBeforeUnmount(() => {
|
|
110
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
111
|
+
document.removeEventListener("pointerup", onPointerUp, true);
|
|
112
|
+
document.removeEventListener("keydown", onKeyDown, true);
|
|
113
|
+
});
|
|
114
|
+
const schema = kit.schema;
|
|
115
|
+
const marks = kit.formats.filter((format) => schema.marks[format.mark]);
|
|
116
|
+
const active = computed(() => {
|
|
117
|
+
const current = state.value;
|
|
118
|
+
if (!current) return [];
|
|
119
|
+
const { from, to } = current.selection;
|
|
120
|
+
return marks.filter((mark) => current.doc.rangeHasMark(from, to, schema.marks[mark.mark])).map((mark) => mark.mark);
|
|
121
|
+
});
|
|
122
|
+
function onMarks(value) {
|
|
123
|
+
const pressed = Array.isArray(value) ? value : [];
|
|
124
|
+
const changed = marks.find((mark) => pressed.includes(mark.mark) !== active.value.includes(mark.mark));
|
|
125
|
+
const current = view.value;
|
|
126
|
+
if (!changed || !current) return;
|
|
127
|
+
toggleMark(schema.marks[changed.mark])(current.state, current.dispatch);
|
|
128
|
+
}
|
|
129
|
+
const turnOptions = kit.blockOptions.filter((option) => !!kit.schema.nodes[option.type]?.isTextblock);
|
|
130
|
+
const currentBlock = computed(() => {
|
|
131
|
+
const current = state.value;
|
|
132
|
+
const info = current && blockAround(current.selection.$from);
|
|
133
|
+
return info ? blockFromNode(info.node) : null;
|
|
134
|
+
});
|
|
135
|
+
const turnable = computed(() => {
|
|
136
|
+
const $from = state.value?.selection.$from;
|
|
137
|
+
return !!$from && $from.depth > 0 && $from.node($from.depth - 1).type.name === "block";
|
|
138
|
+
});
|
|
139
|
+
const currentOption = computed(() => {
|
|
140
|
+
const block = currentBlock.value;
|
|
141
|
+
return block ? turnOptions.find((option) => isCurrent(option, block.type, block.props)) : void 0;
|
|
142
|
+
});
|
|
143
|
+
function turnInto(option) {
|
|
144
|
+
const current = view.value;
|
|
145
|
+
if (!current) return;
|
|
146
|
+
setBlockType(option.type, option.props)(current.state, current.dispatch);
|
|
147
|
+
requestAnimationFrame(() => current.focus());
|
|
148
|
+
}
|
|
149
|
+
const linkMark = schema.marks.link;
|
|
150
|
+
const currentHref = computed(() => {
|
|
151
|
+
const current = state.value;
|
|
152
|
+
if (!current) return "";
|
|
153
|
+
const { from, to } = current.selection;
|
|
154
|
+
let found = "";
|
|
155
|
+
current.doc.nodesBetween(from, to, (node) => {
|
|
156
|
+
const mark = linkMark?.isInSet(node.marks);
|
|
157
|
+
if (mark) found ||= mark.attrs.href;
|
|
158
|
+
});
|
|
159
|
+
return found;
|
|
160
|
+
});
|
|
161
|
+
/** `Mod+K` and the link button: edit the link of the selected text. */
|
|
162
|
+
function editLink() {
|
|
163
|
+
const current = view.value;
|
|
164
|
+
if (!current || !linkMark || !formattable.value) return false;
|
|
165
|
+
const { from, to } = current.state.selection;
|
|
166
|
+
linking.value = {
|
|
167
|
+
from,
|
|
168
|
+
to
|
|
169
|
+
};
|
|
170
|
+
href.value = currentHref.value;
|
|
171
|
+
nextTick(() => linkInput.value?.focus());
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
/** `example.com` becomes `https://example.com`; other relative links stay. */
|
|
175
|
+
function normalise(value) {
|
|
176
|
+
const text = value.trim();
|
|
177
|
+
if (/^[\w-]+(\.[\w-]+)+(?:[/?#:]|$)/.test(text) && !text.includes(" ")) return `https://${text}`;
|
|
178
|
+
return text;
|
|
179
|
+
}
|
|
180
|
+
function applyLink() {
|
|
181
|
+
const current = view.value;
|
|
182
|
+
const range = linking.value;
|
|
183
|
+
if (!current || !range || !linkMark) return;
|
|
184
|
+
const value = normalise(href.value);
|
|
185
|
+
const tr = current.state.tr.removeMark(range.from, range.to, linkMark);
|
|
186
|
+
if (value && isSafeHref(value)) tr.addMark(range.from, range.to, linkMark.create({ href: value }));
|
|
187
|
+
current.dispatch(tr);
|
|
188
|
+
closeLink();
|
|
189
|
+
}
|
|
190
|
+
function removeLink() {
|
|
191
|
+
href.value = "";
|
|
192
|
+
applyLink();
|
|
193
|
+
}
|
|
194
|
+
function closeLink() {
|
|
195
|
+
const current = view.value;
|
|
196
|
+
const range = linking.value;
|
|
197
|
+
linking.value = null;
|
|
198
|
+
if (!current) return;
|
|
199
|
+
if (range) current.dispatch(current.state.tr.setSelection(TextSelection.create(current.state.doc, range.from, range.to)));
|
|
200
|
+
current.focus();
|
|
201
|
+
}
|
|
202
|
+
function onLinkKey(event) {
|
|
203
|
+
if (isComposing(event)) return;
|
|
204
|
+
if (event.key === "Enter") {
|
|
205
|
+
event.preventDefault();
|
|
206
|
+
applyLink();
|
|
207
|
+
} else if (event.key === "Escape") {
|
|
208
|
+
event.preventDefault();
|
|
209
|
+
event.stopPropagation();
|
|
210
|
+
closeLink();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function onLinkBlur(event) {
|
|
214
|
+
if (!panel.value?.contains(event.relatedTarget)) linking.value = null;
|
|
215
|
+
}
|
|
216
|
+
__expose({ editLink });
|
|
217
|
+
return (_ctx, _cache) => {
|
|
218
|
+
return openBlock(), createBlock(Transition, { name: "dou-floating" }, {
|
|
219
|
+
default: withCtx(() => [open.value ? (openBlock(), createElementBlock("div", {
|
|
220
|
+
key: 0,
|
|
221
|
+
ref_key: "panel",
|
|
222
|
+
ref: panel,
|
|
223
|
+
class: "dou-floating dou-editor-bubble",
|
|
224
|
+
style: normalizeStyle([unref(style), { zIndex: zIndex.value }]),
|
|
225
|
+
"data-placement": unref(placement),
|
|
226
|
+
onMousedown: _cache[5] || (_cache[5] = ($event) => !linking.value && $event.preventDefault()),
|
|
227
|
+
onFocusin: _cache[6] || (_cache[6] = ($event) => panelFocused.value = true),
|
|
228
|
+
onFocusout: onPanelFocusOut,
|
|
229
|
+
onKeydown: onPanelKeyDown
|
|
230
|
+
}, [linking.value ? (openBlock(), createElementBlock("div", _hoisted_2, [
|
|
231
|
+
createVNode(unref(DouInput), {
|
|
232
|
+
ref_key: "linkInput",
|
|
233
|
+
ref: linkInput,
|
|
234
|
+
modelValue: href.value,
|
|
235
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => href.value = $event),
|
|
236
|
+
size: "sm",
|
|
237
|
+
placeholder: unref(messages).linkPlaceholder,
|
|
238
|
+
"aria-label": unref(messages).link,
|
|
239
|
+
onKeydown: onLinkKey,
|
|
240
|
+
onBlur: onLinkBlur
|
|
241
|
+
}, {
|
|
242
|
+
prefix: withCtx(() => [createVNode(unref(LinkIcon))]),
|
|
243
|
+
_: 1
|
|
244
|
+
}, 8, [
|
|
245
|
+
"modelValue",
|
|
246
|
+
"placeholder",
|
|
247
|
+
"aria-label"
|
|
248
|
+
]),
|
|
249
|
+
createVNode(unref(DouButton), {
|
|
250
|
+
size: "sm",
|
|
251
|
+
variant: "ghost",
|
|
252
|
+
"aria-label": unref(messages).applyLink,
|
|
253
|
+
onMousedown: _cache[1] || (_cache[1] = withModifiers(() => {}, ["prevent"])),
|
|
254
|
+
onClick: applyLink
|
|
255
|
+
}, {
|
|
256
|
+
default: withCtx(() => [createVNode(unref(CheckIcon))]),
|
|
257
|
+
_: 1
|
|
258
|
+
}, 8, ["aria-label"]),
|
|
259
|
+
currentHref.value ? (openBlock(), createBlock(unref(DouButton), {
|
|
260
|
+
key: 0,
|
|
261
|
+
size: "sm",
|
|
262
|
+
variant: "ghost",
|
|
263
|
+
"aria-label": unref(messages).removeLink,
|
|
264
|
+
onMousedown: _cache[2] || (_cache[2] = withModifiers(() => {}, ["prevent"])),
|
|
265
|
+
onClick: removeLink
|
|
266
|
+
}, {
|
|
267
|
+
default: withCtx(() => [createVNode(unref(UnlinkIcon))]),
|
|
268
|
+
_: 1
|
|
269
|
+
}, 8, ["aria-label"])) : createCommentVNode("", true)
|
|
270
|
+
])) : (openBlock(), createBlock(unref(DouToolbar), {
|
|
271
|
+
key: 1,
|
|
272
|
+
size: "sm",
|
|
273
|
+
"aria-label": unref(messages).formatting
|
|
274
|
+
}, {
|
|
275
|
+
default: withCtx(() => [
|
|
276
|
+
turnable.value ? (openBlock(), createBlock(unref(DouDropdown), {
|
|
277
|
+
key: 0,
|
|
278
|
+
open: menuOpen.value,
|
|
279
|
+
"onUpdate:open": _cache[3] || (_cache[3] = ($event) => menuOpen.value = $event),
|
|
280
|
+
placement: "bottom-start",
|
|
281
|
+
class: "dou-editor-menu"
|
|
282
|
+
}, {
|
|
283
|
+
menu: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(turnOptions), (option) => {
|
|
284
|
+
return openBlock(), createBlock(unref(DouDropdownItem), {
|
|
285
|
+
key: option.key,
|
|
286
|
+
onClick: ($event) => turnInto(option)
|
|
287
|
+
}, createSlots({
|
|
288
|
+
prefix: withCtx(() => [(openBlock(), createBlock(resolveDynamicComponent(option.icon)))]),
|
|
289
|
+
default: withCtx(() => [createTextVNode(" " + toDisplayString(unref(labelOf)(option.label, unref(messages))) + " ", 1)]),
|
|
290
|
+
_: 2
|
|
291
|
+
}, [option === currentOption.value ? {
|
|
292
|
+
name: "suffix",
|
|
293
|
+
fn: withCtx(() => [createVNode(unref(CheckIcon))]),
|
|
294
|
+
key: "0"
|
|
295
|
+
} : void 0]), 1032, ["onClick"]);
|
|
296
|
+
}), 128))]),
|
|
297
|
+
default: withCtx(() => [createVNode(unref(DouButton), {
|
|
298
|
+
size: "sm",
|
|
299
|
+
variant: "ghost",
|
|
300
|
+
class: "dou-editor-bubble__type"
|
|
301
|
+
}, {
|
|
302
|
+
trailing: withCtx(() => [createVNode(unref(ChevronDownIcon))]),
|
|
303
|
+
default: withCtx(() => [createTextVNode(toDisplayString(currentOption.value ? unref(labelOf)(currentOption.value.label, unref(messages)) : unref(messages).turnInto) + " ", 1)]),
|
|
304
|
+
_: 1
|
|
305
|
+
})]),
|
|
306
|
+
_: 1
|
|
307
|
+
}, 8, ["open"])) : createCommentVNode("", true),
|
|
308
|
+
turnable.value && unref(marks).length ? (openBlock(), createBlock(unref(DouToolbarSeparator), { key: 1 })) : createCommentVNode("", true),
|
|
309
|
+
unref(marks).length ? (openBlock(), createBlock(unref(DouToggleGroup), {
|
|
310
|
+
key: 2,
|
|
311
|
+
type: "multiple",
|
|
312
|
+
"model-value": active.value,
|
|
313
|
+
"aria-label": unref(messages).formatting,
|
|
314
|
+
"onUpdate:modelValue": onMarks
|
|
315
|
+
}, {
|
|
316
|
+
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(marks), (mark) => {
|
|
317
|
+
return openBlock(), createBlock(unref(DouTooltip), {
|
|
318
|
+
key: mark.mark,
|
|
319
|
+
content: unref(labelOf)(mark.label, unref(messages)),
|
|
320
|
+
shortcut: mark.hotkey,
|
|
321
|
+
placement: "bottom"
|
|
322
|
+
}, {
|
|
323
|
+
default: withCtx(() => [createVNode(unref(DouToggle), {
|
|
324
|
+
value: mark.mark,
|
|
325
|
+
"aria-label": unref(labelOf)(mark.label, unref(messages))
|
|
326
|
+
}, {
|
|
327
|
+
default: withCtx(() => [(openBlock(), createBlock(resolveDynamicComponent(mark.icon)))]),
|
|
328
|
+
_: 2
|
|
329
|
+
}, 1032, ["value", "aria-label"])]),
|
|
330
|
+
_: 2
|
|
331
|
+
}, 1032, ["content", "shortcut"]);
|
|
332
|
+
}), 128))]),
|
|
333
|
+
_: 1
|
|
334
|
+
}, 8, ["model-value", "aria-label"])) : createCommentVNode("", true),
|
|
335
|
+
unref(kit).toolbar.length ? (openBlock(), createElementBlock(Fragment, { key: 3 }, [unref(marks).length ? (openBlock(), createBlock(unref(DouToolbarSeparator), { key: 0 })) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(unref(kit).toolbar, (control, index) => {
|
|
336
|
+
return openBlock(), createBlock(resolveDynamicComponent(control), { key: index });
|
|
337
|
+
}), 128))], 64)) : createCommentVNode("", true),
|
|
338
|
+
unref(linkMark) ? (openBlock(), createBlock(unref(DouToolbarSeparator), { key: 4 })) : createCommentVNode("", true),
|
|
339
|
+
unref(linkMark) ? (openBlock(), createBlock(unref(DouTooltip), {
|
|
340
|
+
key: 5,
|
|
341
|
+
content: unref(messages).link,
|
|
342
|
+
shortcut: "mod+k",
|
|
343
|
+
placement: "bottom"
|
|
344
|
+
}, {
|
|
345
|
+
default: withCtx(() => [createVNode(unref(DouToggle), {
|
|
346
|
+
pressed: !!currentHref.value,
|
|
347
|
+
"aria-label": unref(messages).link,
|
|
348
|
+
"onUpdate:pressed": editLink
|
|
349
|
+
}, {
|
|
350
|
+
default: withCtx(() => [createVNode(unref(LinkIcon))]),
|
|
351
|
+
_: 1
|
|
352
|
+
}, 8, ["pressed", "aria-label"])]),
|
|
353
|
+
_: 1
|
|
354
|
+
}, 8, ["content"])) : createCommentVNode("", true),
|
|
355
|
+
unref(comments).writable.value ? (openBlock(), createElementBlock(Fragment, { key: 6 }, [createVNode(unref(DouToolbarSeparator)), createVNode(unref(DouTooltip), {
|
|
356
|
+
content: unref(messages).comment,
|
|
357
|
+
shortcut: "mod+alt+m",
|
|
358
|
+
placement: "bottom"
|
|
359
|
+
}, {
|
|
360
|
+
default: withCtx(() => [createVNode(unref(DouButton), {
|
|
361
|
+
size: "sm",
|
|
362
|
+
variant: "ghost",
|
|
363
|
+
"aria-label": unref(messages).comment,
|
|
364
|
+
onClick: _cache[4] || (_cache[4] = ($event) => unref(comments).start())
|
|
365
|
+
}, {
|
|
366
|
+
default: withCtx(() => [createVNode(unref(MessagePlusIcon))]),
|
|
367
|
+
_: 1
|
|
368
|
+
}, 8, ["aria-label"])]),
|
|
369
|
+
_: 1
|
|
370
|
+
}, 8, ["content"])], 64)) : createCommentVNode("", true)
|
|
371
|
+
]),
|
|
372
|
+
_: 1
|
|
373
|
+
}, 8, ["aria-label"]))], 44, _hoisted_1)) : createCommentVNode("", true)]),
|
|
374
|
+
_: 1
|
|
375
|
+
});
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
export { bubble_toolbar_vue_vue_type_script_setup_true_lang_default as default };
|
|
380
|
+
|
|
381
|
+
//# sourceMappingURL=bubble-toolbar.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bubble-toolbar.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_Transition","_withCtx","_createElementBlock","_normalizeStyle","_unref","_createVNode","_withModifiers","_createCommentVNode","_Fragment","_renderList","_createSlots","_resolveDynamicComponent","_createTextVNode","_toDisplayString"],"sources":["../../src/components/bubble-toolbar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { CheckIcon, ChevronDownIcon, LinkIcon, MessagePlusIcon, UnlinkIcon } from '@dou-ui/icons'\nimport {\n DouButton,\n DouDropdown,\n DouDropdownItem,\n DouInput,\n DouToggle,\n DouToggleGroup,\n DouToolbar,\n DouToolbarSeparator,\n DouTooltip,\n isComposing,\n useFloating,\n useZIndex,\n type ToggleValue,\n type VirtualElement,\n} from 'dou-ui'\nimport { toggleMark } from 'prosemirror-commands'\nimport { TextSelection } from 'prosemirror-state'\nimport {\n computed,\n inject,\n nextTick,\n onBeforeUnmount,\n onMounted,\n shallowRef,\n useTemplateRef,\n watch,\n} from 'vue'\nimport { isCurrent } from '../catalog'\nimport { labelOf, type BlockOption } from '../core/extension'\nimport { getBlockSelection } from '../core/block-selection'\nimport { blockAround } from '../core/blocks'\nimport { setBlockType } from '../core/commands'\nimport { blockFromNode } from '../core/model'\nimport { isSafeHref } from '../core/schema'\nimport { editorKey, provideToolbarMenus } from '../editor'\n\nconst { view, state, focused, dragging, messages, kit, comments } = inject(editorKey)!\nconst panel = useTemplateRef<HTMLElement>('panel')\n\n// while the pointer is down the selection is still being made\nconst pressing = shallowRef(false)\nconst menuOpen = shallowRef(false)\n// the extensions' menus keep the toolbar too\nconst toolbarMenus = provideToolbarMenus()\n// so does the focus in the toolbar, e.g. back on a menu's button after Escape\nconst panelFocused = shallowRef(false)\nwatch(focused, (value) => value && (panelFocused.value = false))\nfunction onPanelFocusOut(event: FocusEvent) {\n if (!panel.value?.contains(event.relatedTarget as Node | null)) panelFocused.value = false\n}\nfunction onPanelKeyDown(event: KeyboardEvent) {\n if (event.key !== 'Escape' || linking.value || event.defaultPrevented) return\n event.preventDefault()\n view.value?.focus()\n}\nconst linking = shallowRef<{ from: number; to: number } | null>(null)\nconst href = shallowRef('')\nconst linkInput = useTemplateRef<InstanceType<typeof DouInput>>('linkInput')\n\nconst formattable = computed(() => {\n const current = state.value\n if (!current || getBlockSelection(current)) return false\n const { selection } = current\n if (!(selection instanceof TextSelection) || selection.empty) return false\n // nothing to format in code, or across a divider only\n let text = false\n current.doc.nodesBetween(selection.from, selection.to, (node) => {\n if (node.isTextblock && !node.type.spec.code) text = true\n return !text\n })\n return text\n})\n\nconst open = computed(\n () =>\n !!linking.value ||\n menuOpen.value ||\n [...toolbarMenus].some((menu) => menu.value) ||\n panelFocused.value ||\n (focused.value && formattable.value && !pressing.value && !dragging.value),\n)\n\nconst anchor: VirtualElement = {\n getBoundingClientRect() {\n const current = view.value\n const range = linking.value ?? current?.state.selection\n if (!current || !range) return new DOMRect()\n const start = current.coordsAtPos(range.from, 1)\n const end = current.coordsAtPos(range.to, -1)\n // a selection over several lines: centre on the first one\n const sameLine = Math.abs(start.top - end.top) < 4\n const left = sameLine ? start.left : start.left\n const right = sameLine\n ? end.right\n : Math.max(start.left + 1, current.dom.getBoundingClientRect().right)\n return new DOMRect(left, start.top, Math.max(1, right - left), start.bottom - start.top)\n },\n}\nconst { style, placement, update } = useFloating(() => (open.value ? anchor : null), panel, {\n open,\n placement: 'top',\n offset: 8,\n})\n// stacked like DouUI's own popups, above whatever opened before\nconst { next } = useZIndex()\nconst zIndex = shallowRef(0)\nwatch(open, (value) => value && (zIndex.value = next()), { immediate: true })\nwatch(state, () => open.value && void nextTick(update))\n\nfunction onPointerDown(event: PointerEvent) {\n if (event.button === 0 && view.value?.dom.contains(event.target as Node)) pressing.value = true\n}\nfunction onPointerUp() {\n if (pressing.value) pressing.value = false\n}\n/*\n * A menu opened with the mouse leaves the focus in the text: until it\n * closes, Escape closes it and the arrow keys and Enter go into it,\n * instead of acting on the text.\n */\nfunction onKeyDown(event: KeyboardEvent) {\n if (!view.value?.dom.contains(event.target as Node)) return\n const trigger = panel.value?.querySelector<HTMLElement>('[aria-expanded=\"true\"][aria-controls]')\n if (!trigger) return\n const menu = document.getElementById(trigger.getAttribute('aria-controls')!)\n if (event.key === 'Escape') {\n event.preventDefault()\n event.stopPropagation()\n menuOpen.value = false\n for (const item of toolbarMenus) item.value = false\n return\n }\n if (!menu || !['ArrowDown', 'ArrowUp', 'Home', 'End', 'Enter'].includes(event.key)) return\n event.preventDefault()\n event.stopPropagation()\n const items = Array.from(\n menu.querySelectorAll<HTMLElement>('[role^=\"menuitem\"]:not([aria-disabled=\"true\"])'),\n )\n const last = event.key === 'ArrowUp' || event.key === 'End'\n ;(last ? items.at(-1) : items[0])?.focus()\n}\n\nonMounted(() => {\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('pointerup', onPointerUp, true)\n document.addEventListener('keydown', onKeyDown, true)\n})\nonBeforeUnmount(() => {\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('pointerup', onPointerUp, true)\n document.removeEventListener('keydown', onKeyDown, true)\n})\n\n/* marks */\n\nconst schema = kit.schema\nconst marks = kit.formats.filter((format) => schema.marks[format.mark])\n\nconst active = computed<ToggleValue[]>(() => {\n const current = state.value\n if (!current) return []\n const { from, to } = current.selection\n return marks\n .filter((mark) => current.doc.rangeHasMark(from, to, schema.marks[mark.mark]!))\n .map((mark) => mark.mark)\n})\n\nfunction onMarks(value: ToggleValue | ToggleValue[] | null) {\n const pressed = Array.isArray(value) ? value : []\n const changed = marks.find(\n (mark) => pressed.includes(mark.mark) !== active.value.includes(mark.mark),\n )\n const current = view.value\n if (!changed || !current) return\n toggleMark(schema.marks[changed.mark]!)(current.state, current.dispatch)\n}\n\n/* turning the block into another type */\n\nconst turnOptions = kit.blockOptions.filter(\n (option) => !!kit.schema.nodes[option.type]?.isTextblock,\n)\nconst currentBlock = computed(() => {\n const current = state.value\n const info = current && blockAround(current.selection.$from)\n return info ? blockFromNode(info.node) : null\n})\n// text inside a table cell keeps its cell; only whole blocks change type\nconst turnable = computed(() => {\n const $from = state.value?.selection.$from\n return !!$from && $from.depth > 0 && $from.node($from.depth - 1).type.name === 'block'\n})\nconst currentOption = computed(() => {\n const block = currentBlock.value\n return block\n ? turnOptions.find((option) => isCurrent(option, block.type, block.props))\n : undefined\n})\n\nfunction turnInto(option: BlockOption) {\n const current = view.value\n if (!current) return\n setBlockType(option.type, option.props)(current.state, current.dispatch)\n requestAnimationFrame(() => current.focus())\n}\n\n/* links */\n\nconst linkMark = schema.marks.link\nconst currentHref = computed(() => {\n const current = state.value\n if (!current) return ''\n const { from, to } = current.selection\n let found = ''\n current.doc.nodesBetween(from, to, (node) => {\n const mark = linkMark?.isInSet(node.marks)\n if (mark) found ||= mark.attrs.href as string\n })\n return found\n})\n\n/** `Mod+K` and the link button: edit the link of the selected text. */\nfunction editLink(): boolean {\n const current = view.value\n if (!current || !linkMark || !formattable.value) return false\n const { from, to } = current.state.selection\n linking.value = { from, to }\n href.value = currentHref.value\n void nextTick(() => linkInput.value?.focus())\n return true\n}\n\n/** `example.com` becomes `https://example.com`; other relative links stay. */\nfunction normalise(value: string): string {\n const text = value.trim()\n if (/^[\\w-]+(\\.[\\w-]+)+(?:[/?#:]|$)/.test(text) && !text.includes(' ')) return `https://${text}`\n return text\n}\n\nfunction applyLink() {\n const current = view.value\n const range = linking.value\n if (!current || !range || !linkMark) return\n const value = normalise(href.value)\n const tr = current.state.tr.removeMark(range.from, range.to, linkMark)\n if (value && isSafeHref(value)) tr.addMark(range.from, range.to, linkMark.create({ href: value }))\n current.dispatch(tr)\n closeLink()\n}\n\nfunction removeLink() {\n href.value = ''\n applyLink()\n}\n\nfunction closeLink() {\n const current = view.value\n const range = linking.value\n linking.value = null\n if (!current) return\n if (range)\n current.dispatch(\n current.state.tr.setSelection(TextSelection.create(current.state.doc, range.from, range.to)),\n )\n current.focus()\n}\n\nfunction onLinkKey(event: KeyboardEvent) {\n if (isComposing(event)) return\n if (event.key === 'Enter') {\n event.preventDefault()\n applyLink()\n } else if (event.key === 'Escape') {\n event.preventDefault()\n event.stopPropagation()\n closeLink()\n }\n}\n\nfunction onLinkBlur(event: FocusEvent) {\n // leaving for anywhere but the toolbar ends editing without saving\n if (!panel.value?.contains(event.relatedTarget as Node)) linking.value = null\n}\n\ndefineExpose({ editLink })\n</script>\n\n<template>\n <Transition name=\"dou-floating\">\n <div\n v-if=\"open\"\n ref=\"panel\"\n class=\"dou-floating dou-editor-bubble\"\n :style=\"[style, { zIndex }]\"\n :data-placement=\"placement\"\n @mousedown=\"!linking && $event.preventDefault()\"\n @focusin=\"panelFocused = true\"\n @focusout=\"onPanelFocusOut\"\n @keydown=\"onPanelKeyDown\"\n >\n <div v-if=\"linking\" class=\"dou-editor-bubble__link\">\n <DouInput\n ref=\"linkInput\"\n v-model=\"href\"\n size=\"sm\"\n :placeholder=\"messages.linkPlaceholder\"\n :aria-label=\"messages.link\"\n @keydown=\"onLinkKey\"\n @blur=\"onLinkBlur\"\n >\n <template #prefix><LinkIcon /></template>\n </DouInput>\n <DouButton\n size=\"sm\"\n variant=\"ghost\"\n :aria-label=\"messages.applyLink\"\n @mousedown.prevent\n @click=\"applyLink\"\n >\n <CheckIcon />\n </DouButton>\n <DouButton\n v-if=\"currentHref\"\n size=\"sm\"\n variant=\"ghost\"\n :aria-label=\"messages.removeLink\"\n @mousedown.prevent\n @click=\"removeLink\"\n >\n <UnlinkIcon />\n </DouButton>\n </div>\n <DouToolbar v-else size=\"sm\" :aria-label=\"messages.formatting\">\n <DouDropdown\n v-if=\"turnable\"\n v-model:open=\"menuOpen\"\n placement=\"bottom-start\"\n class=\"dou-editor-menu\"\n >\n <DouButton size=\"sm\" variant=\"ghost\" class=\"dou-editor-bubble__type\">\n {{ currentOption ? labelOf(currentOption.label, messages) : messages.turnInto }}\n <template #trailing><ChevronDownIcon /></template>\n </DouButton>\n <template #menu>\n <DouDropdownItem\n v-for=\"option in turnOptions\"\n :key=\"option.key\"\n @click=\"turnInto(option)\"\n >\n <template #prefix><component :is=\"option.icon\" /></template>\n {{ labelOf(option.label, messages) }}\n <template v-if=\"option === currentOption\" #suffix><CheckIcon /></template>\n </DouDropdownItem>\n </template>\n </DouDropdown>\n <DouToolbarSeparator v-if=\"turnable && marks.length\" />\n <DouToggleGroup\n v-if=\"marks.length\"\n type=\"multiple\"\n :model-value=\"active\"\n :aria-label=\"messages.formatting\"\n @update:model-value=\"onMarks\"\n >\n <DouTooltip\n v-for=\"mark in marks\"\n :key=\"mark.mark\"\n :content=\"labelOf(mark.label, messages)\"\n :shortcut=\"mark.hotkey\"\n placement=\"bottom\"\n >\n <DouToggle :value=\"mark.mark\" :aria-label=\"labelOf(mark.label, messages)\">\n <component :is=\"mark.icon\" />\n </DouToggle>\n </DouTooltip>\n </DouToggleGroup>\n <template v-if=\"kit.toolbar.length\">\n <DouToolbarSeparator v-if=\"marks.length\" />\n <component :is=\"control\" v-for=\"(control, index) in kit.toolbar\" :key=\"index\" />\n </template>\n <DouToolbarSeparator v-if=\"linkMark\" />\n <DouTooltip v-if=\"linkMark\" :content=\"messages.link\" shortcut=\"mod+k\" placement=\"bottom\">\n <DouToggle\n :pressed=\"!!currentHref\"\n :aria-label=\"messages.link\"\n @update:pressed=\"editLink\"\n >\n <LinkIcon />\n </DouToggle>\n </DouTooltip>\n <template v-if=\"comments.writable.value\">\n <DouToolbarSeparator />\n <DouTooltip :content=\"messages.comment\" shortcut=\"mod+alt+m\" placement=\"bottom\">\n <DouButton\n size=\"sm\"\n variant=\"ghost\"\n :aria-label=\"messages.comment\"\n @click=\"comments.start()\"\n >\n <MessagePlusIcon />\n </DouButton>\n </DouTooltip>\n </template>\n </DouToolbar>\n </div>\n </Transition>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;EAuCA,MAAM,EAAE,MAAM,OAAO,SAAS,UAAU,UAAU,KAAK,aAAa,OAAO,SAAS;EACpF,MAAM,QAAQ,eAA4B,OAAO;EAGjD,MAAM,WAAW,WAAW,KAAK;EACjC,MAAM,WAAW,WAAW,KAAK;EAEjC,MAAM,eAAe,oBAAoB;EAEzC,MAAM,eAAe,WAAW,KAAK;EACrC,MAAM,UAAU,UAAU,UAAU,aAAa,QAAQ,MAAM;EAC/D,SAAS,gBAAgB,OAAmB;GAC1C,IAAI,CAAC,MAAM,OAAO,SAAS,MAAM,aAA4B,GAAG,aAAa,QAAQ;EACvF;EACA,SAAS,eAAe,OAAsB;GAC5C,IAAI,MAAM,QAAQ,YAAY,QAAQ,SAAS,MAAM,kBAAkB;GACvE,MAAM,eAAe;GACrB,KAAK,OAAO,MAAM;EACpB;EACA,MAAM,UAAU,WAAgD,IAAI;EACpE,MAAM,OAAO,WAAW,EAAE;EAC1B,MAAM,YAAY,eAA8C,WAAW;EAE3E,MAAM,cAAc,eAAe;GACjC,MAAM,UAAU,MAAM;GACtB,IAAI,CAAC,WAAW,kBAAkB,OAAO,GAAG,OAAO;GACnD,MAAM,EAAE,cAAc;GACtB,IAAI,EAAE,qBAAqB,kBAAkB,UAAU,OAAO,OAAO;GAErE,IAAI,OAAO;GACX,QAAQ,IAAI,aAAa,UAAU,MAAM,UAAU,KAAK,SAAS;IAC/D,IAAI,KAAK,eAAe,CAAC,KAAK,KAAK,KAAK,MAAM,OAAO;IACrD,OAAO,CAAC;GACV,CAAC;GACD,OAAO;EACT,CAAC;EAED,MAAM,OAAO,eAET,CAAC,CAAC,QAAQ,SACV,SAAS,SACT,CAAC,GAAG,YAAY,CAAC,CAAC,MAAM,SAAS,KAAK,KAAK,KAC3C,aAAa,SACZ,QAAQ,SAAS,YAAY,SAAS,CAAC,SAAS,SAAS,CAAC,SAAS,KACxE;EAEA,MAAM,SAAyB,EAC7B,wBAAwB;GACtB,MAAM,UAAU,KAAK;GACrB,MAAM,QAAQ,QAAQ,SAAS,SAAS,MAAM;GAC9C,IAAI,CAAC,WAAW,CAAC,OAAO,OAAO,IAAI,QAAQ;GAC3C,MAAM,QAAQ,QAAQ,YAAY,MAAM,MAAM,CAAC;GAC/C,MAAM,MAAM,QAAQ,YAAY,MAAM,IAAI,EAAE;GAE5C,MAAM,WAAW,KAAK,IAAI,MAAM,MAAM,IAAI,GAAG,IAAI;GACjD,MAAM,OAAO,WAAW,MAAM,OAAO,MAAM;GAC3C,MAAM,QAAQ,WACV,IAAI,QACJ,KAAK,IAAI,MAAM,OAAO,GAAG,QAAQ,IAAI,sBAAsB,CAAC,CAAC,KAAK;GACtE,OAAO,IAAI,QAAQ,MAAM,MAAM,KAAK,KAAK,IAAI,GAAG,QAAQ,IAAI,GAAG,MAAM,SAAS,MAAM,GAAG;EACzF,EACF;EACA,MAAM,EAAE,OAAO,WAAW,WAAW,kBAAmB,KAAK,QAAQ,SAAS,MAAO,OAAO;GAC1F;GACA,WAAW;GACX,QAAQ;EACV,CAAC;EAED,MAAM,EAAE,SAAS,UAAU;EAC3B,MAAM,SAAS,WAAW,CAAC;EAC3B,MAAM,OAAO,UAAU,UAAU,OAAO,QAAQ,KAAK,IAAI,EAAE,WAAW,KAAK,CAAC;EAC5E,MAAM,aAAa,KAAK,SAAS,KAAK,SAAS,MAAM,CAAC;EAEtD,SAAS,cAAc,OAAqB;GAC1C,IAAI,MAAM,WAAW,KAAK,KAAK,OAAO,IAAI,SAAS,MAAM,MAAc,GAAG,SAAS,QAAQ;EAC7F;EACA,SAAS,cAAc;GACrB,IAAI,SAAS,OAAO,SAAS,QAAQ;EACvC;EAMA,SAAS,UAAU,OAAsB;GACvC,IAAI,CAAC,KAAK,OAAO,IAAI,SAAS,MAAM,MAAc,GAAG;GACrD,MAAM,UAAU,MAAM,OAAO,cAA2B,yCAAuC;GAC/F,IAAI,CAAC,SAAS;GACd,MAAM,OAAO,SAAS,eAAe,QAAQ,aAAa,eAAe,CAAE;GAC3E,IAAI,MAAM,QAAQ,UAAU;IAC1B,MAAM,eAAe;IACrB,MAAM,gBAAgB;IACtB,SAAS,QAAQ;IACjB,KAAK,MAAM,QAAQ,cAAc,KAAK,QAAQ;IAC9C;GACF;GACA,IAAI,CAAC,QAAQ,CAAC;IAAC;IAAa;IAAW;IAAQ;IAAO;GAAO,CAAC,CAAC,SAAS,MAAM,GAAG,GAAG;GACpF,MAAM,eAAe;GACrB,MAAM,gBAAgB;GACtB,MAAM,QAAQ,MAAM,KAClB,KAAK,iBAA8B,oDAAgD,CACrF;GAEC,CADY,MAAM,QAAQ,aAAa,MAAM,QAAQ,QAC7C,MAAM,GAAG,EAAE,IAAI,MAAM,GAAA,EAAK,MAAM;EAC3C;EAEA,gBAAgB;GACd,SAAS,iBAAiB,eAAe,eAAe,IAAI;GAC5D,SAAS,iBAAiB,aAAa,aAAa,IAAI;GACxD,SAAS,iBAAiB,WAAW,WAAW,IAAI;EACtD,CAAC;EACD,sBAAsB;GACpB,SAAS,oBAAoB,eAAe,eAAe,IAAI;GAC/D,SAAS,oBAAoB,aAAa,aAAa,IAAI;GAC3D,SAAS,oBAAoB,WAAW,WAAW,IAAI;EACzD,CAAC;EAID,MAAM,SAAS,IAAI;EACnB,MAAM,QAAQ,IAAI,QAAQ,QAAQ,WAAW,OAAO,MAAM,OAAO,KAAK;EAEtE,MAAM,SAAS,eAA8B;GAC3C,MAAM,UAAU,MAAM;GACtB,IAAI,CAAC,SAAS,OAAO,CAAC;GACtB,MAAM,EAAE,MAAM,OAAO,QAAQ;GAC7B,OAAO,MACJ,QAAQ,SAAS,QAAQ,IAAI,aAAa,MAAM,IAAI,OAAO,MAAM,KAAK,KAAM,CAAC,CAAA,CAC7E,KAAK,SAAS,KAAK,IAAI;EAC5B,CAAC;EAED,SAAS,QAAQ,OAA2C;GAC1D,MAAM,UAAU,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;GAChD,MAAM,UAAU,MAAM,MACnB,SAAS,QAAQ,SAAS,KAAK,IAAI,MAAM,OAAO,MAAM,SAAS,KAAK,IAAI,CAC3E;GACA,MAAM,UAAU,KAAK;GACrB,IAAI,CAAC,WAAW,CAAC,SAAS;GAC1B,WAAW,OAAO,MAAM,QAAQ,KAAM,CAAC,CAAC,QAAQ,OAAO,QAAQ,QAAQ;EACzE;EAIA,MAAM,cAAc,IAAI,aAAa,QAClC,WAAW,CAAC,CAAC,IAAI,OAAO,MAAM,OAAO,KAAK,EAAE,WAC/C;EACA,MAAM,eAAe,eAAe;GAClC,MAAM,UAAU,MAAM;GACtB,MAAM,OAAO,WAAW,YAAY,QAAQ,UAAU,KAAK;GAC3D,OAAO,OAAO,cAAc,KAAK,IAAI,IAAI;EAC3C,CAAC;EAED,MAAM,WAAW,eAAe;GAC9B,MAAM,QAAQ,MAAM,OAAO,UAAU;GACrC,OAAO,CAAC,CAAC,SAAS,MAAM,QAAQ,KAAK,MAAM,KAAK,MAAM,QAAQ,CAAC,CAAC,CAAC,KAAK,SAAS;EACjF,CAAC;EACD,MAAM,gBAAgB,eAAe;GACnC,MAAM,QAAQ,aAAa;GAC3B,OAAO,QACH,YAAY,MAAM,WAAW,UAAU,QAAQ,MAAM,MAAM,MAAM,KAAK,CAAC,IACvE,KAAA;EACN,CAAC;EAED,SAAS,SAAS,QAAqB;GACrC,MAAM,UAAU,KAAK;GACrB,IAAI,CAAC,SAAS;GACd,aAAa,OAAO,MAAM,OAAO,KAAK,CAAC,CAAC,QAAQ,OAAO,QAAQ,QAAQ;GACvE,4BAA4B,QAAQ,MAAM,CAAC;EAC7C;EAIA,MAAM,WAAW,OAAO,MAAM;EAC9B,MAAM,cAAc,eAAe;GACjC,MAAM,UAAU,MAAM;GACtB,IAAI,CAAC,SAAS,OAAO;GACrB,MAAM,EAAE,MAAM,OAAO,QAAQ;GAC7B,IAAI,QAAQ;GACZ,QAAQ,IAAI,aAAa,MAAM,KAAK,SAAS;IAC3C,MAAM,OAAO,UAAU,QAAQ,KAAK,KAAK;IACzC,IAAI,MAAM,UAAU,KAAK,MAAM;GACjC,CAAC;GACD,OAAO;EACT,CAAC;;EAGD,SAAS,WAAoB;GAC3B,MAAM,UAAU,KAAK;GACrB,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,YAAY,OAAO,OAAO;GACxD,MAAM,EAAE,MAAM,OAAO,QAAQ,MAAM;GACnC,QAAQ,QAAQ;IAAE;IAAM;GAAG;GAC3B,KAAK,QAAQ,YAAY;GACzB,eAAoB,UAAU,OAAO,MAAM,CAAC;GAC5C,OAAO;EACT;;EAGA,SAAS,UAAU,OAAuB;GACxC,MAAM,OAAO,MAAM,KAAK;GACxB,IAAI,iCAAiC,KAAK,IAAI,KAAK,CAAC,KAAK,SAAS,GAAG,GAAG,OAAO,WAAW;GAC1F,OAAO;EACT;EAEA,SAAS,YAAY;GACnB,MAAM,UAAU,KAAK;GACrB,MAAM,QAAQ,QAAQ;GACtB,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,UAAU;GACrC,MAAM,QAAQ,UAAU,KAAK,KAAK;GAClC,MAAM,KAAK,QAAQ,MAAM,GAAG,WAAW,MAAM,MAAM,MAAM,IAAI,QAAQ;GACrE,IAAI,SAAS,WAAW,KAAK,GAAG,GAAG,QAAQ,MAAM,MAAM,MAAM,IAAI,SAAS,OAAO,EAAE,MAAM,MAAM,CAAC,CAAC;GACjG,QAAQ,SAAS,EAAE;GACnB,UAAU;EACZ;EAEA,SAAS,aAAa;GACpB,KAAK,QAAQ;GACb,UAAU;EACZ;EAEA,SAAS,YAAY;GACnB,MAAM,UAAU,KAAK;GACrB,MAAM,QAAQ,QAAQ;GACtB,QAAQ,QAAQ;GAChB,IAAI,CAAC,SAAS;GACd,IAAI,OACF,QAAQ,SACN,QAAQ,MAAM,GAAG,aAAa,cAAc,OAAO,QAAQ,MAAM,KAAK,MAAM,MAAM,MAAM,EAAE,CAAC,CAC7F;GACF,QAAQ,MAAM;EAChB;EAEA,SAAS,UAAU,OAAsB;GACvC,IAAI,YAAY,KAAK,GAAG;GACxB,IAAI,MAAM,QAAQ,SAAS;IACzB,MAAM,eAAe;IACrB,UAAU;GACZ,OAAO,IAAI,MAAM,QAAQ,UAAU;IACjC,MAAM,eAAe;IACrB,MAAM,gBAAgB;IACtB,UAAU;GACZ;EACF;EAEA,SAAS,WAAW,OAAmB;GAErC,IAAI,CAAC,MAAM,OAAO,SAAS,MAAM,aAAqB,GAAG,QAAQ,QAAQ;EAC3E;EAEA,SAAa,EAAE,SAAS,CAAC;;GAIvB,OAAAA,UAAA,GAAAC,YAoHaC,YAAA,EApHD,MAAK,eAAc,GAAA;IAC7B,SAAAC,cAkHM,CAjHE,KAAA,SADRH,UAAA,GAAAI,mBAkHM,OAAA;;KAhHA,SAAA;KAAJ,KAAI;KACJ,OAAM;KACL,OAAKC,eAAA,CAAGC,MAAA,KAAA,GAAK,EAAA,QAAI,OAAA,MAAM,CAAA,CAAA;KACvB,kBAAgBA,MAAA,SAAA;KAChB,aAAS,OAAA,OAAA,OAAA,MAAA,WAAA,CAAG,QAAA,SAAW,OAAO,eAAc;KAC5C,WAAO,OAAA,OAAA,OAAA,MAAA,WAAE,aAAA,QAAY;KACrB,YAAU;KACV,WAAS;I,IAEC,QAAA,SAAXN,UAAA,GAAAI,mBA+BM,OA/BN,YA+BM;KA9BJG,YAUWD,MAAA,QAAA,GAAA;MATL,SAAA;MAAJ,KAAI;MACK,YAAA,KAAA;MAAA,uBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,KAAI,QAAA;MACb,MAAK;MACJ,aAAaA,MAAA,QAAA,CAAQ,CAAC;MACtB,cAAYA,MAAA,QAAA,CAAQ,CAAC;MACrB,WAAS;MACT,QAAM;;MAEI,QAAMH,cAAa,CAAZI,YAAYD,MAAA,QAAA,CAAA,C;;;;;;;KAEhCC,YAQYD,MAAA,SAAA,GAAA;MAPV,MAAK;MACL,SAAQ;MACP,cAAYA,MAAA,QAAA,CAAQ,CAAC;MACrB,aAAS,OAAA,OAAA,OAAA,KAAAE,oBAAV,CAAA,GAAkB,CAAA,SAAA,CAAA;MACjB,SAAO;;MAER,SAAAL,cAAa,CAAbI,YAAaD,MAAA,SAAA,CAAA,C;;;KAGP,YAAA,SADRN,UAAA,GAAAC,YASYK,MAAA,SAAA,GAAA;;MAPV,MAAK;MACL,SAAQ;MACP,cAAYA,MAAA,QAAA,CAAQ,CAAC;MACrB,aAAS,OAAA,OAAA,OAAA,KAAAE,oBAAV,CAAA,GAAkB,CAAA,SAAA,CAAA;MACjB,SAAO;;MAER,SAAAL,cAAc,CAAdI,YAAcD,MAAA,UAAA,CAAA,C;;;I,OAGlBN,UAAA,GAAAC,YAsEaK,MAAA,UAAA,GAAA;;KAtEM,MAAK;KAAM,cAAYA,MAAA,QAAA,CAAQ,CAAC;;KACjD,SAAAH,cAqBc;MApBN,SAAA,SADRH,UAAA,GAAAC,YAqBcK,MAAA,WAAA,GAAA;;OAnBJ,MAAM,SAAA;OAAA,iBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,SAAQ,QAAA;OACtB,WAAU;OACV,OAAM;;OAMK,MAAIH,cAEkB,EAD/BH,UAAA,IAAA,GAAAI,mBAQkBM,UAAA,MAAAC,WAPCL,MAAA,WAAA,IAAV,WAAM;QADf,OAAAN,UAAA,GAAAC,YAQkBK,MAAA,eAAA,GAAA;SANf,KAAK,OAAO;SACZ,UAAK,WAAE,SAAS,MAAM;;SAEZ,QAAMH,cAAgC,EAA/BH,UAAA,GAAAC,YAA+BY,wBAAf,OAAO,IAAI,CAAA,E;SAAe,SAAAV,cAC5D,CAD4DW,gBAAA,MAC5DC,gBAAGT,MAAA,OAAA,CAAO,CAAC,OAAO,OAAOA,MAAA,QAAA,CAAQ,CAAA,IAAI,KACrC,CAAA,C;;Q,IAAgB,WAAW,cAAA,Q;SAAgB,MAAA;SAAO,IAAAH,cAAa,CAAbI,YAAaD,MAAA,SAAA,CAAA,C;;;;OAZnE,SAAAH,cAGY,CAHZI,YAGYD,MAAA,SAAA,GAAA;QAHD,MAAK;QAAK,SAAQ;QAAQ,OAAM;;QAE9B,UAAQH,cAAoB,CAAnBI,YAAmBD,MAAA,eAAA,CAAA,C;QADvC,SAAAH,cAAgF,CAA7EW,gBAAAC,gBAAA,cAAA,QAAgBT,MAAA,OAAA,CAAO,CAAC,cAAA,MAAc,OAAOA,MAAA,QAAA,CAAQ,IAAIA,MAAA,QAAA,CAAQ,CAAC,QAAQ,IAAG,KAChF,CAAA,C;;;;;MAcuB,SAAA,SAAYA,MAAA,KAAA,CAAK,CAAC,UAA7CN,UAAA,GAAAC,YAAuDK,MAAA,mBAAA,GAAA,EAAA,KAAA,EAAA,CAAA,K;MAE/CA,MAAA,KAAA,CAAK,CAAC,UADdN,UAAA,GAAAC,YAkBiBK,MAAA,cAAA,GAAA;;OAhBf,MAAK;OACJ,eAAa,OAAA;OACb,cAAYA,MAAA,QAAA,CAAQ,CAAC;OACrB,uBAAoB;;OAGnB,SAAAH,cAAqB,EADvBH,UAAA,IAAA,GAAAI,mBAUaM,UAAA,MAAAC,WATIL,MAAA,KAAA,IAAR,SAAI;QADb,OAAAN,UAAA,GAAAC,YAUaK,MAAA,UAAA,GAAA;SARV,KAAK,KAAK;SACV,SAASA,MAAA,OAAA,CAAO,CAAC,KAAK,OAAOA,MAAA,QAAA,CAAQ;SACrC,UAAU,KAAK;SAChB,WAAU;;SAEV,SAAAH,cAEY,CAFZI,YAEYD,MAAA,SAAA,GAAA;UAFA,OAAO,KAAK;UAAO,cAAYA,MAAA,OAAA,CAAO,CAAC,KAAK,OAAOA,MAAA,QAAA,CAAQ;;UACrE,SAAAH,cAA6B,EAA7BH,UAAA,GAAAC,YAA6BY,wBAAb,KAAK,IAAI,CAAA,E;;;;;;;;MAIfP,MAAA,GAAA,CAAG,CAAC,QAAQ,UAA5BN,UAAA,GAAAI,mBAGWM,UAAA,EAAA,KAAA,EAAA,GAAA,CAFkBJ,MAAA,KAAA,CAAK,CAAC,UAAjCN,UAAA,GAAAC,YAA2CK,MAAA,mBAAA,GAAA,EAAA,KAAA,EAAA,CAAA,K,+BAC3CN,UAAA,IAAA,GAAAI,mBAAgFM,UAAA,MAAAC,WAA5BL,MAAA,GAAA,CAAG,CAAC,UAAvB,SAAS,UAAK;OAA/C,OAAAN,UAAA,GAAAC,YAAgFY,wBAAhE,OAAO,GAAA,EAA2C,KAAK,MAAK,CAAA;;MAEnDP,MAAA,QAAA,KAA3BN,UAAA,GAAAC,YAAuCK,MAAA,mBAAA,GAAA,EAAA,KAAA,EAAA,CAAA,K;MACrBA,MAAA,QAAA,KAAlBN,UAAA,GAAAC,YAQaK,MAAA,UAAA,GAAA;;OARgB,SAASA,MAAA,QAAA,CAAQ,CAAC;OAAM,UAAS;OAAQ,WAAU;;OAC9E,SAAAH,cAMY,CANZI,YAMYD,MAAA,SAAA,GAAA;QALT,SAAO,CAAA,CAAI,YAAA;QACX,cAAYA,MAAA,QAAA,CAAQ,CAAC;QACrB,oBAAgB;;QAEjB,SAAAH,cAAY,CAAZI,YAAYD,MAAA,QAAA,CAAA,C;;;;;MAGAA,MAAA,QAAA,CAAQ,CAAC,SAAS,SAAlCN,UAAA,GAAAI,mBAYWM,UAAA,EAAA,KAAA,EAAA,GAAA,CAXTH,YAAuBD,MAAA,mBAAA,CAAA,GACvBC,YASaD,MAAA,UAAA,GAAA;OATA,SAASA,MAAA,QAAA,CAAQ,CAAC;OAAS,UAAS;OAAY,WAAU;;OACrE,SAAAH,cAOY,CAPZI,YAOYD,MAAA,SAAA,GAAA;QANV,MAAK;QACL,SAAQ;QACP,cAAYA,MAAA,QAAA,CAAQ,CAAC;QACrB,SAAK,OAAA,OAAA,OAAA,MAAA,WAAEA,MAAA,QAAA,CAAQ,CAAC,MAAK;;QAEtB,SAAAH,cAAmB,CAAnBI,YAAmBD,MAAA,eAAA,CAAA,C"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import comment_button_vue_vue_type_script_setup_true_lang_default from "./comment-button.vue_vue_type_script_setup_true_lang.js";
|
|
2
|
+
// src/components/comment-button.vue
|
|
3
|
+
var comment_button_default = comment_button_vue_vue_type_script_setup_true_lang_default;
|
|
4
|
+
export { comment_button_default as default };
|
|
5
|
+
|
|
6
|
+
//# sourceMappingURL=comment-button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-button.js","names":["_sfc_main"],"sources":["../../src/components/comment-button.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { MessagePlusIcon } from '@dou-ui/icons'\nimport { DouButton, useFloating, useZIndex, type VirtualElement } from 'dou-ui'\nimport { computed, inject, onBeforeUnmount, onMounted, shallowRef, watch } from 'vue'\nimport type { CommentRange } from '../core/comments'\nimport { editorKey } from '../editor'\n\n/*\n * A read-only editor has no formatting toolbar; selecting text there\n * shows this one button, to start a thread on it.\n */\n\nconst { view, comments, messages } = inject(editorKey)!\nconst panel = shallowRef<HTMLElement | null>(null)\nconst range = shallowRef<CommentRange | null>(null)\nconst pressing = shallowRef(false)\n\nconst open = computed(\n () => !!range.value && !pressing.value && !comments.pending.value && comments.writable.value,\n)\n\nconst anchor: VirtualElement = {\n getBoundingClientRect() {\n const current = view.value\n const at = range.value\n if (!current || !at) return new DOMRect()\n const first = current.coordsAtPos(at.from, 1)\n const last = current.coordsAtPos(at.to, -1)\n const right = Math.abs(first.top - last.top) < 4 ? last.right : first.left + 1\n return new DOMRect(\n first.left,\n first.top,\n Math.max(1, right - first.left),\n first.bottom - first.top,\n )\n },\n}\n\nconst { style, placement } = useFloating(() => (open.value ? anchor : null), panel, {\n open,\n placement: 'top',\n offset: 8,\n})\nconst { next } = useZIndex()\nconst zIndex = shallowRef(0)\nwatch(open, (value) => value && (zIndex.value = next()), { immediate: true })\n\nfunction read() {\n range.value = comments.selection()\n // selecting other text closes an open thread, as in an editable editor\n if (range.value && comments.active.value && !comments.pending.value) comments.open(null)\n}\nfunction onPointerDown(event: PointerEvent) {\n if (event.button === 0 && view.value?.dom.contains(event.target as Node)) pressing.value = true\n}\nfunction onPointerUp() {\n if (!pressing.value) return\n pressing.value = false\n read()\n}\nonMounted(() => {\n document.addEventListener('selectionchange', read)\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('pointerup', onPointerUp, true)\n})\nonBeforeUnmount(() => {\n document.removeEventListener('selectionchange', read)\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('pointerup', onPointerUp, true)\n})\n\nfunction start() {\n if (comments.start()) range.value = null\n}\n</script>\n\n<template>\n <Transition name=\"dou-floating\">\n <div\n v-if=\"open\"\n ref=\"panel\"\n class=\"dou-floating dou-editor-bubble\"\n :style=\"[style, { zIndex }]\"\n :data-placement=\"placement\"\n @mousedown.prevent\n >\n <DouButton size=\"sm\" variant=\"ghost\" @click=\"start\">\n <template #leading><MessagePlusIcon /></template>\n {{ messages.comment }}\n </DouButton>\n </div>\n </Transition>\n</template>\n"],"mappings":""}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { editorKey } from "../editor.js";
|
|
2
|
+
import { DouButton, useFloating, useZIndex } from "dou-ui";
|
|
3
|
+
import { Transition, computed, createBlock, createCommentVNode, createElementBlock, createTextVNode, createVNode, defineComponent, inject, normalizeStyle, onBeforeUnmount, onMounted, openBlock, shallowRef, toDisplayString, unref, watch, withCtx, withModifiers } from "vue";
|
|
4
|
+
import { MessagePlusIcon } from "@dou-ui/icons";
|
|
5
|
+
// src/components/comment-button.vue?vue&type=script&setup=true&lang.ts
|
|
6
|
+
var _hoisted_1 = ["data-placement"];
|
|
7
|
+
var comment_button_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
8
|
+
__name: "comment-button",
|
|
9
|
+
setup(__props) {
|
|
10
|
+
const { view, comments, messages } = inject(editorKey);
|
|
11
|
+
const panel = shallowRef(null);
|
|
12
|
+
const range = shallowRef(null);
|
|
13
|
+
const pressing = shallowRef(false);
|
|
14
|
+
const open = computed(() => !!range.value && !pressing.value && !comments.pending.value && comments.writable.value);
|
|
15
|
+
const anchor = { getBoundingClientRect() {
|
|
16
|
+
const current = view.value;
|
|
17
|
+
const at = range.value;
|
|
18
|
+
if (!current || !at) return new DOMRect();
|
|
19
|
+
const first = current.coordsAtPos(at.from, 1);
|
|
20
|
+
const last = current.coordsAtPos(at.to, -1);
|
|
21
|
+
const right = Math.abs(first.top - last.top) < 4 ? last.right : first.left + 1;
|
|
22
|
+
return new DOMRect(first.left, first.top, Math.max(1, right - first.left), first.bottom - first.top);
|
|
23
|
+
} };
|
|
24
|
+
const { style, placement } = useFloating(() => open.value ? anchor : null, panel, {
|
|
25
|
+
open,
|
|
26
|
+
placement: "top",
|
|
27
|
+
offset: 8
|
|
28
|
+
});
|
|
29
|
+
const { next } = useZIndex();
|
|
30
|
+
const zIndex = shallowRef(0);
|
|
31
|
+
watch(open, (value) => value && (zIndex.value = next()), { immediate: true });
|
|
32
|
+
function read() {
|
|
33
|
+
range.value = comments.selection();
|
|
34
|
+
if (range.value && comments.active.value && !comments.pending.value) comments.open(null);
|
|
35
|
+
}
|
|
36
|
+
function onPointerDown(event) {
|
|
37
|
+
if (event.button === 0 && view.value?.dom.contains(event.target)) pressing.value = true;
|
|
38
|
+
}
|
|
39
|
+
function onPointerUp() {
|
|
40
|
+
if (!pressing.value) return;
|
|
41
|
+
pressing.value = false;
|
|
42
|
+
read();
|
|
43
|
+
}
|
|
44
|
+
onMounted(() => {
|
|
45
|
+
document.addEventListener("selectionchange", read);
|
|
46
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
47
|
+
document.addEventListener("pointerup", onPointerUp, true);
|
|
48
|
+
});
|
|
49
|
+
onBeforeUnmount(() => {
|
|
50
|
+
document.removeEventListener("selectionchange", read);
|
|
51
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
52
|
+
document.removeEventListener("pointerup", onPointerUp, true);
|
|
53
|
+
});
|
|
54
|
+
function start() {
|
|
55
|
+
if (comments.start()) range.value = null;
|
|
56
|
+
}
|
|
57
|
+
return (_ctx, _cache) => {
|
|
58
|
+
return openBlock(), createBlock(Transition, { name: "dou-floating" }, {
|
|
59
|
+
default: withCtx(() => [open.value ? (openBlock(), createElementBlock("div", {
|
|
60
|
+
key: 0,
|
|
61
|
+
ref_key: "panel",
|
|
62
|
+
ref: panel,
|
|
63
|
+
class: "dou-floating dou-editor-bubble",
|
|
64
|
+
style: normalizeStyle([unref(style), { zIndex: zIndex.value }]),
|
|
65
|
+
"data-placement": unref(placement),
|
|
66
|
+
onMousedown: _cache[0] || (_cache[0] = withModifiers(() => {}, ["prevent"]))
|
|
67
|
+
}, [createVNode(unref(DouButton), {
|
|
68
|
+
size: "sm",
|
|
69
|
+
variant: "ghost",
|
|
70
|
+
onClick: start
|
|
71
|
+
}, {
|
|
72
|
+
leading: withCtx(() => [createVNode(unref(MessagePlusIcon))]),
|
|
73
|
+
default: withCtx(() => [createTextVNode(" " + toDisplayString(unref(messages).comment), 1)]),
|
|
74
|
+
_: 1
|
|
75
|
+
})], 44, _hoisted_1)) : createCommentVNode("", true)]),
|
|
76
|
+
_: 1
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
export { comment_button_vue_vue_type_script_setup_true_lang_default as default };
|
|
82
|
+
|
|
83
|
+
//# sourceMappingURL=comment-button.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-button.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_Transition","_withCtx","_createElementBlock","_normalizeStyle","_unref","_withModifiers","_createVNode","_createTextVNode","_toDisplayString","_createCommentVNode"],"sources":["../../src/components/comment-button.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { MessagePlusIcon } from '@dou-ui/icons'\nimport { DouButton, useFloating, useZIndex, type VirtualElement } from 'dou-ui'\nimport { computed, inject, onBeforeUnmount, onMounted, shallowRef, watch } from 'vue'\nimport type { CommentRange } from '../core/comments'\nimport { editorKey } from '../editor'\n\n/*\n * A read-only editor has no formatting toolbar; selecting text there\n * shows this one button, to start a thread on it.\n */\n\nconst { view, comments, messages } = inject(editorKey)!\nconst panel = shallowRef<HTMLElement | null>(null)\nconst range = shallowRef<CommentRange | null>(null)\nconst pressing = shallowRef(false)\n\nconst open = computed(\n () => !!range.value && !pressing.value && !comments.pending.value && comments.writable.value,\n)\n\nconst anchor: VirtualElement = {\n getBoundingClientRect() {\n const current = view.value\n const at = range.value\n if (!current || !at) return new DOMRect()\n const first = current.coordsAtPos(at.from, 1)\n const last = current.coordsAtPos(at.to, -1)\n const right = Math.abs(first.top - last.top) < 4 ? last.right : first.left + 1\n return new DOMRect(\n first.left,\n first.top,\n Math.max(1, right - first.left),\n first.bottom - first.top,\n )\n },\n}\n\nconst { style, placement } = useFloating(() => (open.value ? anchor : null), panel, {\n open,\n placement: 'top',\n offset: 8,\n})\nconst { next } = useZIndex()\nconst zIndex = shallowRef(0)\nwatch(open, (value) => value && (zIndex.value = next()), { immediate: true })\n\nfunction read() {\n range.value = comments.selection()\n // selecting other text closes an open thread, as in an editable editor\n if (range.value && comments.active.value && !comments.pending.value) comments.open(null)\n}\nfunction onPointerDown(event: PointerEvent) {\n if (event.button === 0 && view.value?.dom.contains(event.target as Node)) pressing.value = true\n}\nfunction onPointerUp() {\n if (!pressing.value) return\n pressing.value = false\n read()\n}\nonMounted(() => {\n document.addEventListener('selectionchange', read)\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('pointerup', onPointerUp, true)\n})\nonBeforeUnmount(() => {\n document.removeEventListener('selectionchange', read)\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('pointerup', onPointerUp, true)\n})\n\nfunction start() {\n if (comments.start()) range.value = null\n}\n</script>\n\n<template>\n <Transition name=\"dou-floating\">\n <div\n v-if=\"open\"\n ref=\"panel\"\n class=\"dou-floating dou-editor-bubble\"\n :style=\"[style, { zIndex }]\"\n :data-placement=\"placement\"\n @mousedown.prevent\n >\n <DouButton size=\"sm\" variant=\"ghost\" @click=\"start\">\n <template #leading><MessagePlusIcon /></template>\n {{ messages.comment }}\n </DouButton>\n </div>\n </Transition>\n</template>\n"],"mappings":";;;;;;;;;EAYA,MAAM,EAAE,MAAM,UAAU,aAAa,OAAO,SAAS;EACrD,MAAM,QAAQ,WAA+B,IAAI;EACjD,MAAM,QAAQ,WAAgC,IAAI;EAClD,MAAM,WAAW,WAAW,KAAK;EAEjC,MAAM,OAAO,eACL,CAAC,CAAC,MAAM,SAAS,CAAC,SAAS,SAAS,CAAC,SAAS,QAAQ,SAAS,SAAS,SAAS,KACzF;EAEA,MAAM,SAAyB,EAC7B,wBAAwB;GACtB,MAAM,UAAU,KAAK;GACrB,MAAM,KAAK,MAAM;GACjB,IAAI,CAAC,WAAW,CAAC,IAAI,OAAO,IAAI,QAAQ;GACxC,MAAM,QAAQ,QAAQ,YAAY,GAAG,MAAM,CAAC;GAC5C,MAAM,OAAO,QAAQ,YAAY,GAAG,IAAI,EAAE;GAC1C,MAAM,QAAQ,KAAK,IAAI,MAAM,MAAM,KAAK,GAAG,IAAI,IAAI,KAAK,QAAQ,MAAM,OAAO;GAC7E,OAAO,IAAI,QACT,MAAM,MACN,MAAM,KACN,KAAK,IAAI,GAAG,QAAQ,MAAM,IAAI,GAC9B,MAAM,SAAS,MAAM,GACvB;EACF,EACF;EAEA,MAAM,EAAE,OAAO,cAAc,kBAAmB,KAAK,QAAQ,SAAS,MAAO,OAAO;GAClF;GACA,WAAW;GACX,QAAQ;EACV,CAAC;EACD,MAAM,EAAE,SAAS,UAAU;EAC3B,MAAM,SAAS,WAAW,CAAC;EAC3B,MAAM,OAAO,UAAU,UAAU,OAAO,QAAQ,KAAK,IAAI,EAAE,WAAW,KAAK,CAAC;EAE5E,SAAS,OAAO;GACd,MAAM,QAAQ,SAAS,UAAU;GAEjC,IAAI,MAAM,SAAS,SAAS,OAAO,SAAS,CAAC,SAAS,QAAQ,OAAO,SAAS,KAAK,IAAI;EACzF;EACA,SAAS,cAAc,OAAqB;GAC1C,IAAI,MAAM,WAAW,KAAK,KAAK,OAAO,IAAI,SAAS,MAAM,MAAc,GAAG,SAAS,QAAQ;EAC7F;EACA,SAAS,cAAc;GACrB,IAAI,CAAC,SAAS,OAAO;GACrB,SAAS,QAAQ;GACjB,KAAK;EACP;EACA,gBAAgB;GACd,SAAS,iBAAiB,mBAAmB,IAAI;GACjD,SAAS,iBAAiB,eAAe,eAAe,IAAI;GAC5D,SAAS,iBAAiB,aAAa,aAAa,IAAI;EAC1D,CAAC;EACD,sBAAsB;GACpB,SAAS,oBAAoB,mBAAmB,IAAI;GACpD,SAAS,oBAAoB,eAAe,eAAe,IAAI;GAC/D,SAAS,oBAAoB,aAAa,aAAa,IAAI;EAC7D,CAAC;EAED,SAAS,QAAQ;GACf,IAAI,SAAS,MAAM,GAAG,MAAM,QAAQ;EACtC;;GAIE,OAAAA,UAAA,GAAAC,YAcaC,YAAA,EAdD,MAAK,eAAc,GAAA;IAC7B,SAAAC,cAYM,CAXE,KAAA,SADRH,UAAA,GAAAI,mBAYM,OAAA;;KAVA,SAAA;KAAJ,KAAI;KACJ,OAAM;KACL,OAAKC,eAAA,CAAGC,MAAA,KAAA,GAAK,EAAA,QAAI,OAAA,MAAM,CAAA,CAAA;KACvB,kBAAgBA,MAAA,SAAA;KAChB,aAAS,OAAA,OAAA,OAAA,KAAAC,oBAAV,CAAA,GAAkB,CAAA,SAAA,CAAA;I,IAElBC,YAGYF,MAAA,SAAA,GAAA;KAHD,MAAK;KAAK,SAAQ;KAAS,SAAO;;KAChC,SAAOH,cAAoB,CAAnBK,YAAmBF,MAAA,eAAA,CAAA,C;KAAW,SAAAH,cACjD,CADiDM,gBAAA,MACjDC,gBAAGJ,MAAA,QAAA,CAAQ,CAAC,OAAO,GAAA,CAAA,C"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import comment_card_vue_vue_type_script_setup_true_lang_default from "./comment-card.vue_vue_type_script_setup_true_lang.js";
|
|
2
|
+
// src/components/comment-card.vue
|
|
3
|
+
var comment_card_default = comment_card_vue_vue_type_script_setup_true_lang_default;
|
|
4
|
+
export { comment_card_default as default };
|
|
5
|
+
|
|
6
|
+
//# sourceMappingURL=comment-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-card.js","names":["_sfc_main"],"sources":["../../src/components/comment-card.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n DouCommentThread,\n useFloating,\n useLayer,\n useZIndex,\n type CommentThread,\n type VirtualElement,\n} from 'dou-ui'\nimport { computed, inject, nextTick, shallowRef, watch } from 'vue'\nimport { commentRange, type CommentRange } from '../core/comments'\nimport { editorKey } from '../editor'\n\n/*\n * The thread a piece of text is about, beside that text: opened by a\n * click on highlighted text or `v-model:activeComment`, or empty while\n * a new thread's first comment is being written.\n */\n\nconst { view, state, comments, messages } = inject(editorKey)!\nconst panel = shallowRef<HTMLElement | null>(null)\n\nconst thread = computed<CommentThread | null>(() => {\n const id = comments.active.value\n return (id && comments.threads.value.find((item) => item.id === id)) || null\n})\n\nconst range = computed<CommentRange | null>(() => {\n if (comments.pending.value) return comments.pending.value\n const current = state.value\n return thread.value && current ? commentRange(current.doc, thread.value.id) : null\n})\n\nconst open = computed(() => !!range.value)\n\nconst anchor: VirtualElement = {\n getBoundingClientRect() {\n const current = view.value\n const at = range.value\n if (!current || !at) return new DOMRect()\n const start = current.coordsAtPos(at.from, 1)\n const end = current.coordsAtPos(at.to, -1)\n // text over several lines: from its start to the editor's right edge\n const right =\n Math.abs(start.top - end.top) < 4\n ? end.right\n : Math.max(start.left + 1, current.dom.getBoundingClientRect().right)\n return new DOMRect(\n start.left,\n start.top,\n Math.max(1, right - start.left),\n end.bottom - start.top,\n )\n },\n}\n\nconst { style, placement, update } = useFloating(() => (open.value ? anchor : null), panel, {\n open,\n placement: 'bottom-start',\n offset: 6,\n})\nconst { next } = useZIndex()\nconst zIndex = shallowRef(0)\nwatch(open, (value) => value && (zIndex.value = next()), { immediate: true })\nwatch(state, () => open.value && void nextTick(update))\n\nconst threadView = shallowRef<InstanceType<typeof DouCommentThread> | null>(null)\n\n/** Focus was in the card, or went nowhere when what held it went away. */\nconst focusLost = () => {\n const el = document.activeElement\n return !el || el === document.body || !!panel.value?.contains(el)\n}\n\nfunction close() {\n const refocus = focusLost()\n comments.close()\n if (refocus) view.value?.focus()\n}\n\n// the card is a layer: Escape goes to a menu opened from it first, and a\n// press on such a menu isn't outside. A press on the editor's text is the\n// editor's: it opens the thread there, or closes the card.\nuseLayer({\n open,\n elements: () => [panel.value, view.value?.dom],\n onEscape: () => close(),\n onOutside: () => comments.close(),\n})\n\n// asked to (by the keyboard shortcut, or a thread just started): the reply box\nwatch(\n () => comments.focusRequest.value,\n async () => {\n await nextTick()\n await nextTick()\n threadView.value?.focus()\n },\n)\n\n// a thread resolved or removed from the card: back to the text, once\n// the card is gone (focus can sit in it while it fades out)\nfunction onClosed() {\n const el = document.activeElement\n if (!el || el === document.body) view.value?.focus()\n}\n</script>\n\n<template>\n <Transition name=\"dou-floating\" @after-leave=\"onClosed\">\n <div\n v-if=\"open\"\n ref=\"panel\"\n class=\"dou-floating dou-editor-comment\"\n role=\"dialog\"\n :aria-label=\"messages.commentThread\"\n :style=\"[style, { zIndex }]\"\n :data-placement=\"placement\"\n >\n <DouCommentThread\n ref=\"threadView\"\n :key=\"thread?.id ?? 'new'\"\n :thread=\"thread\"\n :author=\"comments.author.value\"\n :readonly=\"!comments.writable.value\"\n :autofocus=\"!thread\"\n @action=\"comments.apply\"\n @cancel=\"close\"\n />\n </div>\n </Transition>\n</template>\n"],"mappings":""}
|