@domternal/vue 0.14.0 → 1.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 +44 -6
- package/dist/index.d.ts +24 -7
- package/dist/index.js +198 -292
- package/dist/index.js.map +1 -1
- package/package.json +14 -14
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineComponent, h, computed, Fragment, ref, watch, shallowRef, onMounted, nextTick, onScopeDispose, watchEffect, Teleport, inject, provide, getCurrentInstance, customRef, markRaw, shallowReactive, render } from 'vue';
|
|
2
|
-
import { positionFloatingOnce, PluginKey, positionFloating, ToolbarController, refocusEditorAfterCommand, createFloatingMenuPlugin, FloatingMenuController, defaultIcons, defaultBubbleContexts, createBubbleMenuPlugin, Document, Paragraph, Text, BaseKeymap, History, Editor } from '@domternal/core';
|
|
2
|
+
import { positionFloatingOnce, PluginKey, positionFloating, ToolbarController, refocusEditorAfterCommand, createFloatingMenuPlugin, FloatingMenuController, defaultIcons, defaultBubbleContexts, buildBubbleItemMaps, createBubbleShouldShow, createBubbleMenuPlugin, resolveBubbleNames, Document, Paragraph, Text, BaseKeymap, History, Editor, resolveBubbleMenuItems } from '@domternal/core';
|
|
3
3
|
export { Editor, generateHTML, generateJSON, generateText } from '@domternal/core';
|
|
4
4
|
|
|
5
5
|
// src/useEditor.ts
|
|
@@ -33,7 +33,8 @@ function useEditor(options = {}) {
|
|
|
33
33
|
extensions: [...defaults, ...extensions],
|
|
34
34
|
content: initialContent,
|
|
35
35
|
editable,
|
|
36
|
-
autofocus: focus
|
|
36
|
+
autofocus: focus,
|
|
37
|
+
...options.preset ? { preset: options.preset } : {}
|
|
37
38
|
});
|
|
38
39
|
markRaw(ed);
|
|
39
40
|
wireEvents(ed);
|
|
@@ -69,6 +70,7 @@ function useEditor(options = {}) {
|
|
|
69
70
|
const mount = editorRef.value;
|
|
70
71
|
if (mount && ed.view.dom.parentElement !== mount) {
|
|
71
72
|
mount.appendChild(ed.view.dom);
|
|
73
|
+
ed.adoptPresetClass();
|
|
72
74
|
}
|
|
73
75
|
return;
|
|
74
76
|
}
|
|
@@ -279,6 +281,7 @@ function useToolbarController(editor, layout) {
|
|
|
279
281
|
const toolbarRef = ref();
|
|
280
282
|
let cleanupFloating = null;
|
|
281
283
|
let clickOutsideHandler = null;
|
|
284
|
+
let escapeHandler = null;
|
|
282
285
|
let dismissOverlayHandler = null;
|
|
283
286
|
let editorEl = null;
|
|
284
287
|
let syncStateRaf = 0;
|
|
@@ -315,6 +318,17 @@ function useToolbarController(editor, layout) {
|
|
|
315
318
|
}
|
|
316
319
|
};
|
|
317
320
|
document.addEventListener("mousedown", clickOutsideHandler);
|
|
321
|
+
escapeHandler = (e) => {
|
|
322
|
+
if (!controller?.openDropdown) return;
|
|
323
|
+
if (e.key !== "Escape") return;
|
|
324
|
+
if (toolbarRef.value?.contains(document.activeElement)) return;
|
|
325
|
+
cleanupFloating?.();
|
|
326
|
+
cleanupFloating = null;
|
|
327
|
+
controller.closeDropdown();
|
|
328
|
+
syncState();
|
|
329
|
+
e.preventDefault();
|
|
330
|
+
};
|
|
331
|
+
document.addEventListener("keydown", escapeHandler);
|
|
318
332
|
editorEl = ed.view.dom.closest(".dm-editor");
|
|
319
333
|
if (editorEl) {
|
|
320
334
|
dismissOverlayHandler = () => {
|
|
@@ -338,6 +352,10 @@ function useToolbarController(editor, layout) {
|
|
|
338
352
|
document.removeEventListener("mousedown", clickOutsideHandler);
|
|
339
353
|
clickOutsideHandler = null;
|
|
340
354
|
}
|
|
355
|
+
if (escapeHandler) {
|
|
356
|
+
document.removeEventListener("keydown", escapeHandler);
|
|
357
|
+
escapeHandler = null;
|
|
358
|
+
}
|
|
341
359
|
if (dismissOverlayHandler && editorEl) {
|
|
342
360
|
editorEl.removeEventListener("dm:dismiss-overlays", dismissOverlayHandler);
|
|
343
361
|
dismissOverlayHandler = null;
|
|
@@ -848,11 +866,9 @@ var DomternalToolbar = defineComponent({
|
|
|
848
866
|
computed(() => props.editor ?? contextEditor.value),
|
|
849
867
|
props.layout
|
|
850
868
|
);
|
|
851
|
-
const {
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
getDropdownTriggerHtml
|
|
855
|
-
} = useToolbarIcons(props.icons);
|
|
869
|
+
const { getCachedIcon, getCachedItemContent, getDropdownTriggerHtml } = useToolbarIcons(
|
|
870
|
+
props.icons
|
|
871
|
+
);
|
|
856
872
|
const { getTooltip } = useTooltip();
|
|
857
873
|
const { onKeyDown } = useKeyboardNav(controllerRef, toolbarRef, closeDropdown);
|
|
858
874
|
function onButtonClick(item, event) {
|
|
@@ -932,7 +948,9 @@ var DomternalToolbar = defineComponent({
|
|
|
932
948
|
}
|
|
933
949
|
if (item.type === "dropdown") {
|
|
934
950
|
const dd = item;
|
|
935
|
-
const activeItem = dd.items.find(
|
|
951
|
+
const activeItem = dd.items.find(
|
|
952
|
+
(sub) => controllerRef.current?.activeMap.get(sub.name)
|
|
953
|
+
);
|
|
936
954
|
let triggerHtml = getDropdownTriggerHtml(dd, activeItem);
|
|
937
955
|
if (dd.dynamicLabel && !activeItem && dd.computedStyleProperty) {
|
|
938
956
|
let computed7;
|
|
@@ -982,20 +1000,6 @@ var INITIAL_TRAILING_STATE = {
|
|
|
982
1000
|
currentBgColorVar: null,
|
|
983
1001
|
hasAnyColor: false
|
|
984
1002
|
};
|
|
985
|
-
function isInsideTableCell($pos) {
|
|
986
|
-
for (let d = $pos.depth; d > 0; d--) {
|
|
987
|
-
const name = $pos.node(d).type.name;
|
|
988
|
-
if (name === "tableCell" || name === "tableHeader") return true;
|
|
989
|
-
}
|
|
990
|
-
return false;
|
|
991
|
-
}
|
|
992
|
-
function findCellNode(pos) {
|
|
993
|
-
for (let d = pos.depth; d > 0; d--) {
|
|
994
|
-
const node = pos.node(d);
|
|
995
|
-
if (node.type.name === "tableCell" || node.type.name === "tableHeader") return node;
|
|
996
|
-
}
|
|
997
|
-
return null;
|
|
998
|
-
}
|
|
999
1003
|
function useBubbleMenu(options) {
|
|
1000
1004
|
const { editor, shouldShow, placement = "top", offset = 8, updateDelay = 0, items, contexts: explicitContexts, icons: iconsRef } = options;
|
|
1001
1005
|
const menuRef = ref();
|
|
@@ -1008,9 +1012,7 @@ function useBubbleMenu(options) {
|
|
|
1008
1012
|
const trailing = shallowRef(INITIAL_TRAILING_STATE);
|
|
1009
1013
|
const activeMapRef = /* @__PURE__ */ new Map();
|
|
1010
1014
|
const disabledMapRef = /* @__PURE__ */ new Map();
|
|
1011
|
-
let
|
|
1012
|
-
let dropdownMap;
|
|
1013
|
-
let bubbleDefaults;
|
|
1015
|
+
let maps;
|
|
1014
1016
|
let currentResolvedItems = [];
|
|
1015
1017
|
let initialized = false;
|
|
1016
1018
|
let stopEditorWatch = null;
|
|
@@ -1021,125 +1023,8 @@ function useBubbleMenu(options) {
|
|
|
1021
1023
|
const exts = ed.extensionManager.extensions;
|
|
1022
1024
|
const hasNotionColorPicker = exts.some((e) => e.name === "notionColorPicker");
|
|
1023
1025
|
const hasBlockContextMenu = exts.some((e) => e.name === "blockContextMenu");
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
for (const item of ed.toolbarItems) {
|
|
1027
|
-
if (item.type === "button") {
|
|
1028
|
-
itemMap.set(item.name, item);
|
|
1029
|
-
} else if (item.type === "dropdown") {
|
|
1030
|
-
dropdownMap.set(item.name, item);
|
|
1031
|
-
for (const sub of item.items) {
|
|
1032
|
-
itemMap.set(sub.name, sub);
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
bubbleDefaults = /* @__PURE__ */ new Map();
|
|
1037
|
-
const byCtx = /* @__PURE__ */ new Map();
|
|
1038
|
-
const addItem = (btn) => {
|
|
1039
|
-
const ctx = btn["bubbleMenu"];
|
|
1040
|
-
if (!ctx) return;
|
|
1041
|
-
let arr = byCtx.get(ctx);
|
|
1042
|
-
if (!arr) {
|
|
1043
|
-
arr = [];
|
|
1044
|
-
byCtx.set(ctx, arr);
|
|
1045
|
-
}
|
|
1046
|
-
arr.push(btn);
|
|
1047
|
-
};
|
|
1048
|
-
for (const item of ed.toolbarItems) {
|
|
1049
|
-
if (item.type === "button") addItem(item);
|
|
1050
|
-
else if (item.type === "dropdown") {
|
|
1051
|
-
for (const sub of item.items) addItem(sub);
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
|
-
for (const [ctx, ctxItems] of byCtx) {
|
|
1055
|
-
ctxItems.sort((a, b) => (b.priority ?? 100) - (a.priority ?? 100));
|
|
1056
|
-
const result = [];
|
|
1057
|
-
let lastGroup;
|
|
1058
|
-
let sepIdx = 0;
|
|
1059
|
-
for (const item of ctxItems) {
|
|
1060
|
-
if (lastGroup !== void 0 && item.group !== lastGroup) {
|
|
1061
|
-
result.push({ type: "separator", name: `bsep-${String(sepIdx++)}` });
|
|
1062
|
-
}
|
|
1063
|
-
result.push(item);
|
|
1064
|
-
lastGroup = item.group;
|
|
1065
|
-
}
|
|
1066
|
-
bubbleDefaults.set(ctx, result);
|
|
1067
|
-
}
|
|
1068
|
-
const resolveNames = (names) => {
|
|
1069
|
-
const result = [];
|
|
1070
|
-
let sepIdx = 0;
|
|
1071
|
-
for (const name of names) {
|
|
1072
|
-
if (name === "|") {
|
|
1073
|
-
result.push({ type: "separator", name: `sep-${String(sepIdx++)}` });
|
|
1074
|
-
} else {
|
|
1075
|
-
const dropdown = dropdownMap.get(name);
|
|
1076
|
-
if (dropdown) {
|
|
1077
|
-
result.push(dropdown);
|
|
1078
|
-
continue;
|
|
1079
|
-
}
|
|
1080
|
-
const item = itemMap.get(name);
|
|
1081
|
-
if (item) result.push(item);
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
return result;
|
|
1085
|
-
};
|
|
1086
|
-
const getFormatItems = () => {
|
|
1087
|
-
return Array.from(itemMap.values()).filter((item) => item.group === "format").sort((a, b) => (b.priority ?? 100) - (a.priority ?? 100));
|
|
1088
|
-
};
|
|
1089
|
-
const detectContext = (selection, ctxs) => {
|
|
1090
|
-
if ("$anchorCell" in selection) return null;
|
|
1091
|
-
if (selection.node) return selection.node.type.name;
|
|
1092
|
-
if (selection.empty) return null;
|
|
1093
|
-
const fromCell = findCellNode(selection.$from);
|
|
1094
|
-
if (fromCell) {
|
|
1095
|
-
const toCell = findCellNode(selection.$to);
|
|
1096
|
-
if (toCell && fromCell !== toCell) return null;
|
|
1097
|
-
return "table";
|
|
1098
|
-
}
|
|
1099
|
-
const fromName = selection.$from.parent.type.name;
|
|
1100
|
-
if (fromName in ctxs) return fromName;
|
|
1101
|
-
if ("text" in ctxs && selection.$from.parent.type.spec.marks !== "") return "text";
|
|
1102
|
-
const toName = selection.$to.parent.type.name;
|
|
1103
|
-
if (toName in ctxs) return toName;
|
|
1104
|
-
if ("text" in ctxs && selection.$to.parent.type.spec.marks !== "") return "text";
|
|
1105
|
-
return null;
|
|
1106
|
-
};
|
|
1107
|
-
const filterBySchema = (contextName, schemaItems) => {
|
|
1108
|
-
if (contextName === "text" || contextName === "table") return schemaItems;
|
|
1109
|
-
const schema = ed.state.schema;
|
|
1110
|
-
if (!schema) return schemaItems;
|
|
1111
|
-
const nodeType = schema.nodes[contextName];
|
|
1112
|
-
if (!nodeType) return schemaItems;
|
|
1113
|
-
return schemaItems.filter((item) => {
|
|
1114
|
-
const markName = typeof item.isActive === "string" ? item.isActive : null;
|
|
1115
|
-
if (!markName) return true;
|
|
1116
|
-
const markType = schema.marks[markName];
|
|
1117
|
-
if (!markType) return true;
|
|
1118
|
-
return nodeType.allowsMarkType(markType);
|
|
1119
|
-
});
|
|
1120
|
-
};
|
|
1121
|
-
let shouldShowFn = shouldShow;
|
|
1122
|
-
if (!shouldShowFn) {
|
|
1123
|
-
if (contexts) {
|
|
1124
|
-
shouldShowFn = ({ state }) => {
|
|
1125
|
-
const context = detectContext(state.selection, contexts);
|
|
1126
|
-
if (!context) return false;
|
|
1127
|
-
if (context in contexts) {
|
|
1128
|
-
const val = contexts[context];
|
|
1129
|
-
if (val === null) return false;
|
|
1130
|
-
return val === true || Array.isArray(val) && val.length > 0;
|
|
1131
|
-
}
|
|
1132
|
-
return bubbleDefaults.has(context);
|
|
1133
|
-
};
|
|
1134
|
-
} else {
|
|
1135
|
-
shouldShowFn = ({ state }) => {
|
|
1136
|
-
if (state.selection.empty) return false;
|
|
1137
|
-
if (state.selection.node) return bubbleDefaults.has(state.selection.node.type.name);
|
|
1138
|
-
if (isInsideTableCell(state.selection.$from)) return false;
|
|
1139
|
-
return state.selection.$from.parent.type.spec.marks !== "" || state.selection.$to.parent.type.spec.marks !== "";
|
|
1140
|
-
};
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1026
|
+
maps = buildBubbleItemMaps(ed);
|
|
1027
|
+
const shouldShowFn = shouldShow ?? createBubbleShouldShow(maps, contexts);
|
|
1143
1028
|
const plugin = createBubbleMenuPlugin({
|
|
1144
1029
|
pluginKey,
|
|
1145
1030
|
editor: ed,
|
|
@@ -1154,13 +1039,15 @@ function useBubbleMenu(options) {
|
|
|
1154
1039
|
currentResolvedItems = newItems;
|
|
1155
1040
|
resolvedItems.value = newItems;
|
|
1156
1041
|
};
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1042
|
+
const fallbackItems = resolveBubbleNames(
|
|
1043
|
+
items ?? ["bold", "italic", "underline"],
|
|
1044
|
+
maps.itemMap,
|
|
1045
|
+
maps.dropdownMap
|
|
1046
|
+
);
|
|
1047
|
+
const refreshItems = () => {
|
|
1048
|
+
setItems(resolveBubbleMenuItems({ editor: ed, maps, contexts, fallbackItems }));
|
|
1049
|
+
};
|
|
1050
|
+
refreshItems();
|
|
1164
1051
|
const updateStates = (currentEd) => {
|
|
1165
1052
|
let canProxy = null;
|
|
1166
1053
|
try {
|
|
@@ -1185,7 +1072,6 @@ function useBubbleMenu(options) {
|
|
|
1185
1072
|
trackButton(item);
|
|
1186
1073
|
}
|
|
1187
1074
|
};
|
|
1188
|
-
const defaultItems = items ? resolveNames(items) : resolveNames(["bold", "italic", "underline"]);
|
|
1189
1075
|
const syncTrailingState = (currentEd) => {
|
|
1190
1076
|
const sel = currentEd.state.selection;
|
|
1191
1077
|
const isNode = !!sel.node;
|
|
@@ -1212,7 +1098,8 @@ function useBubbleMenu(options) {
|
|
|
1212
1098
|
}
|
|
1213
1099
|
trailing.value = {
|
|
1214
1100
|
isNodeSelection: isNode,
|
|
1215
|
-
|
|
1101
|
+
// Hidden without a live notionColorOpen listener: the trigger would be dead.
|
|
1102
|
+
showColorPickerButton: hasNotionColorPicker && currentEd.listenerCount("notionColorOpen") > 0,
|
|
1216
1103
|
showBlockMenuButton: hasBlockContextMenu,
|
|
1217
1104
|
blockMenuButtonDisabled: blockMenuDisabled,
|
|
1218
1105
|
currentTextColorVar: textVar,
|
|
@@ -1221,16 +1108,7 @@ function useBubbleMenu(options) {
|
|
|
1221
1108
|
};
|
|
1222
1109
|
};
|
|
1223
1110
|
const transactionHandler = () => {
|
|
1224
|
-
|
|
1225
|
-
updateContextItems(ed, contexts, detectContext, resolveNames, getFormatItems, filterBySchema, bubbleDefaults, setItems);
|
|
1226
|
-
} else {
|
|
1227
|
-
const sel = ed.state.selection;
|
|
1228
|
-
if (sel.node && bubbleDefaults.has(sel.node.type.name)) {
|
|
1229
|
-
setItems(bubbleDefaults.get(sel.node.type.name) ?? []);
|
|
1230
|
-
} else {
|
|
1231
|
-
setItems(defaultItems);
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1111
|
+
refreshItems();
|
|
1234
1112
|
updateStates(ed);
|
|
1235
1113
|
syncTrailingState(ed);
|
|
1236
1114
|
activeVersion.value++;
|
|
@@ -1265,30 +1143,6 @@ function useBubbleMenu(options) {
|
|
|
1265
1143
|
}
|
|
1266
1144
|
}
|
|
1267
1145
|
});
|
|
1268
|
-
function updateContextItems(ed, ctxs, detectContext, resolveNames, getFormatItems, filterBySchema, defaults, setItems) {
|
|
1269
|
-
const ctx = detectContext(ed.state.selection, ctxs);
|
|
1270
|
-
if (!ctx) {
|
|
1271
|
-
setItems([]);
|
|
1272
|
-
return;
|
|
1273
|
-
}
|
|
1274
|
-
if (ctx in ctxs) {
|
|
1275
|
-
const val = ctxs[ctx];
|
|
1276
|
-
if (val === null || Array.isArray(val) && val.length === 0) {
|
|
1277
|
-
setItems([]);
|
|
1278
|
-
return;
|
|
1279
|
-
}
|
|
1280
|
-
if (val === true) {
|
|
1281
|
-
setItems(filterBySchema(ctx, getFormatItems()));
|
|
1282
|
-
} else if (Array.isArray(val)) {
|
|
1283
|
-
const resolved = resolveNames(val);
|
|
1284
|
-
const buttons = resolved.filter((i) => i.type !== "separator");
|
|
1285
|
-
const filtered = new Set(filterBySchema(ctx, buttons).map((b) => b.name));
|
|
1286
|
-
setItems(resolved.filter((i) => i.type === "separator" || filtered.has(i.name)));
|
|
1287
|
-
}
|
|
1288
|
-
} else {
|
|
1289
|
-
setItems(defaults.get(ctx) ?? []);
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
1146
|
const isItemActive = (item) => {
|
|
1293
1147
|
return activeMapRef.get(item.name) ?? false;
|
|
1294
1148
|
};
|
|
@@ -1441,9 +1295,13 @@ var DomternalBubbleMenu = defineComponent({
|
|
|
1441
1295
|
}
|
|
1442
1296
|
}));
|
|
1443
1297
|
}
|
|
1444
|
-
|
|
1298
|
+
const showColor = t.showColorPickerButton && !t.isNodeSelection;
|
|
1299
|
+
const showBlock = t.showBlockMenuButton && !t.isNodeSelection;
|
|
1300
|
+
if (showColor) {
|
|
1301
|
+
if (children.length > 0) {
|
|
1302
|
+
children.push(h("span", { class: "dm-toolbar-separator", role: "separator" }));
|
|
1303
|
+
}
|
|
1445
1304
|
children.push(
|
|
1446
|
-
h("span", { class: "dm-toolbar-separator", role: "separator" }),
|
|
1447
1305
|
h("button", {
|
|
1448
1306
|
ref: colorBtnRef,
|
|
1449
1307
|
type: "button",
|
|
@@ -1469,9 +1327,11 @@ var DomternalBubbleMenu = defineComponent({
|
|
|
1469
1327
|
])
|
|
1470
1328
|
);
|
|
1471
1329
|
}
|
|
1472
|
-
if (
|
|
1330
|
+
if (showBlock) {
|
|
1331
|
+
if (children.length > 0) {
|
|
1332
|
+
children.push(h("span", { class: "dm-toolbar-separator", role: "separator" }));
|
|
1333
|
+
}
|
|
1473
1334
|
children.push(
|
|
1474
|
-
h("span", { class: "dm-toolbar-separator", role: "separator" }),
|
|
1475
1335
|
h("button", {
|
|
1476
1336
|
ref: blockMenuBtnRef,
|
|
1477
1337
|
type: "button",
|
|
@@ -2028,10 +1888,10 @@ var CATEGORY_ICONS = {
|
|
|
2028
1888
|
"Animals & Nature": "\u{1F431}",
|
|
2029
1889
|
"Food & Drink": "\u{1F355}",
|
|
2030
1890
|
"Travel & Places": "\u{1F697}",
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
1891
|
+
Activities: "\u26BD",
|
|
1892
|
+
Objects: "\u{1F4A1}",
|
|
1893
|
+
Symbols: "\u{1F523}",
|
|
1894
|
+
Flags: "\u{1F3C1}"
|
|
2035
1895
|
};
|
|
2036
1896
|
function categoryIcon(cat) {
|
|
2037
1897
|
return CATEGORY_ICONS[cat] ?? cat.charAt(0);
|
|
@@ -2079,7 +1939,7 @@ var DomternalEmojiPicker = defineComponent({
|
|
|
2079
1939
|
return;
|
|
2080
1940
|
}
|
|
2081
1941
|
const cols = 8;
|
|
2082
|
-
let next
|
|
1942
|
+
let next;
|
|
2083
1943
|
switch (event.key) {
|
|
2084
1944
|
case "ArrowRight":
|
|
2085
1945
|
event.preventDefault();
|
|
@@ -2108,20 +1968,24 @@ var DomternalEmojiPicker = defineComponent({
|
|
|
2108
1968
|
swatches[next]?.focus();
|
|
2109
1969
|
}
|
|
2110
1970
|
function renderEmojiButton(item) {
|
|
2111
|
-
return h(
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
1971
|
+
return h(
|
|
1972
|
+
"button",
|
|
1973
|
+
{
|
|
1974
|
+
key: item.name,
|
|
1975
|
+
type: "button",
|
|
1976
|
+
class: "dm-emoji-swatch",
|
|
1977
|
+
tabindex: -1,
|
|
1978
|
+
title: formatName(item.name),
|
|
1979
|
+
"aria-label": formatName(item.name),
|
|
1980
|
+
onMousedown: (e) => {
|
|
1981
|
+
e.preventDefault();
|
|
1982
|
+
},
|
|
1983
|
+
onClick: () => {
|
|
1984
|
+
selectEmoji(item);
|
|
1985
|
+
}
|
|
2120
1986
|
},
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
}
|
|
2124
|
-
}, item.emoji);
|
|
1987
|
+
item.emoji
|
|
1988
|
+
);
|
|
2125
1989
|
}
|
|
2126
1990
|
return () => {
|
|
2127
1991
|
if (!isOpen.value) {
|
|
@@ -2147,21 +2011,28 @@ var DomternalEmojiPicker = defineComponent({
|
|
|
2147
2011
|
"div",
|
|
2148
2012
|
{ class: "dm-emoji-picker-tabs", role: "tablist" },
|
|
2149
2013
|
categoryNames.value.map(
|
|
2150
|
-
(cat) => h(
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2014
|
+
(cat) => h(
|
|
2015
|
+
"button",
|
|
2016
|
+
{
|
|
2017
|
+
key: cat,
|
|
2018
|
+
type: "button",
|
|
2019
|
+
class: [
|
|
2020
|
+
"dm-emoji-picker-tab",
|
|
2021
|
+
activeCategory.value === cat && "dm-emoji-picker-tab--active"
|
|
2022
|
+
],
|
|
2023
|
+
role: "tab",
|
|
2024
|
+
"aria-selected": activeCategory.value === cat,
|
|
2025
|
+
title: cat,
|
|
2026
|
+
"aria-label": cat,
|
|
2027
|
+
onMousedown: (e) => {
|
|
2028
|
+
e.preventDefault();
|
|
2029
|
+
},
|
|
2030
|
+
onClick: () => {
|
|
2031
|
+
scrollToCategory(cat);
|
|
2032
|
+
}
|
|
2160
2033
|
},
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
}
|
|
2164
|
-
}, categoryIcon(cat))
|
|
2034
|
+
categoryIcon(cat)
|
|
2035
|
+
)
|
|
2165
2036
|
)
|
|
2166
2037
|
),
|
|
2167
2038
|
// Grid
|
|
@@ -2176,11 +2047,15 @@ var DomternalEmojiPicker = defineComponent({
|
|
|
2176
2047
|
] : [],
|
|
2177
2048
|
// All categories
|
|
2178
2049
|
...categoryNames.value.flatMap((cat) => [
|
|
2179
|
-
h(
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2050
|
+
h(
|
|
2051
|
+
"div",
|
|
2052
|
+
{
|
|
2053
|
+
key: `label-${cat}`,
|
|
2054
|
+
class: "dm-emoji-picker-category-label",
|
|
2055
|
+
"data-category": cat
|
|
2056
|
+
},
|
|
2057
|
+
cat
|
|
2058
|
+
),
|
|
2184
2059
|
...(categories.value.get(cat) ?? []).map(renderEmojiButton)
|
|
2185
2060
|
])
|
|
2186
2061
|
]
|
|
@@ -2198,6 +2073,7 @@ var Domternal = defineComponent({
|
|
|
2198
2073
|
extensions: { type: Array, default: void 0 },
|
|
2199
2074
|
content: { type: [String, Object], default: "" },
|
|
2200
2075
|
editable: { type: Boolean, default: true },
|
|
2076
|
+
preset: { type: String, default: void 0 },
|
|
2201
2077
|
autofocus: { type: [Boolean, String, Number], default: false },
|
|
2202
2078
|
outputFormat: { type: String, default: "html" },
|
|
2203
2079
|
immediatelyRender: { type: Boolean, default: false },
|
|
@@ -2213,6 +2089,7 @@ var Domternal = defineComponent({
|
|
|
2213
2089
|
...props.extensions && { extensions: props.extensions },
|
|
2214
2090
|
content: props.content,
|
|
2215
2091
|
editable: props.editable,
|
|
2092
|
+
...props.preset && { preset: props.preset },
|
|
2216
2093
|
autofocus: props.autofocus,
|
|
2217
2094
|
outputFormat: props.outputFormat,
|
|
2218
2095
|
immediatelyRender: props.immediatelyRender,
|
|
@@ -2249,6 +2126,7 @@ var DomternalContent = defineComponent({
|
|
|
2249
2126
|
const editorDom = ed.view.dom;
|
|
2250
2127
|
if (editorDom.parentElement !== container) {
|
|
2251
2128
|
container.appendChild(editorDom);
|
|
2129
|
+
ed.adoptPresetClass();
|
|
2252
2130
|
}
|
|
2253
2131
|
});
|
|
2254
2132
|
return () => {
|
|
@@ -2276,6 +2154,7 @@ var DomternalEditor = defineComponent({
|
|
|
2276
2154
|
extensions: { type: Array, default: void 0 },
|
|
2277
2155
|
content: { type: [String, Object], default: void 0 },
|
|
2278
2156
|
editable: { type: Boolean, default: true },
|
|
2157
|
+
preset: { type: String, default: void 0 },
|
|
2279
2158
|
autofocus: { type: [Boolean, String, Number], default: false },
|
|
2280
2159
|
immediatelyRender: { type: Boolean, default: false },
|
|
2281
2160
|
outputFormat: { type: String, default: "html" },
|
|
@@ -2296,6 +2175,7 @@ var DomternalEditor = defineComponent({
|
|
|
2296
2175
|
...props.extensions && { extensions: props.extensions },
|
|
2297
2176
|
content: props.modelValue ?? props.content ?? "",
|
|
2298
2177
|
editable: props.editable,
|
|
2178
|
+
...props.preset && { preset: props.preset },
|
|
2299
2179
|
autofocus: props.autofocus,
|
|
2300
2180
|
immediatelyRender: props.immediatelyRender,
|
|
2301
2181
|
outputFormat: props.outputFormat,
|
|
@@ -2385,6 +2265,7 @@ var EditorContent = defineComponent({
|
|
|
2385
2265
|
const editorDom = editor.view.dom;
|
|
2386
2266
|
if (editorDom.parentElement !== container) {
|
|
2387
2267
|
container.appendChild(editorDom);
|
|
2268
|
+
editor.adoptPresetClass();
|
|
2388
2269
|
}
|
|
2389
2270
|
});
|
|
2390
2271
|
return () => h("div", {
|
|
@@ -2394,6 +2275,14 @@ var EditorContent = defineComponent({
|
|
|
2394
2275
|
});
|
|
2395
2276
|
}
|
|
2396
2277
|
});
|
|
2278
|
+
function paletteFromExtensionOptions(options) {
|
|
2279
|
+
if (typeof options !== "object" || options === null || !("palette" in options)) return [];
|
|
2280
|
+
const palette = options.palette;
|
|
2281
|
+
if (!Array.isArray(palette) || !palette.every((token) => typeof token === "string")) {
|
|
2282
|
+
return [];
|
|
2283
|
+
}
|
|
2284
|
+
return [...palette];
|
|
2285
|
+
}
|
|
2397
2286
|
var TOKEN_LABELS = {
|
|
2398
2287
|
gray: "Gray",
|
|
2399
2288
|
brown: "Brown",
|
|
@@ -2458,8 +2347,7 @@ function useNotionColorPicker(options) {
|
|
|
2458
2347
|
if (!ed || ed.isDestroyed) return;
|
|
2459
2348
|
hostEl.value = ed.view.dom.closest(".dm-editor");
|
|
2460
2349
|
const ext = ed.extensionManager.extensions.find((e) => e.name === "notionColorPicker");
|
|
2461
|
-
|
|
2462
|
-
palette.value = extOptions?.palette ? [...extOptions.palette] : [];
|
|
2350
|
+
palette.value = paletteFromExtensionOptions(ext?.options);
|
|
2463
2351
|
const onOpen = (...args) => {
|
|
2464
2352
|
const detail = args[0];
|
|
2465
2353
|
const incomingAnchor = detail?.anchorElement;
|
|
@@ -2499,19 +2387,27 @@ function useNotionColorPicker(options) {
|
|
|
2499
2387
|
if (!open) return;
|
|
2500
2388
|
const controller = new AbortController();
|
|
2501
2389
|
const { signal } = controller;
|
|
2502
|
-
document.addEventListener(
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2390
|
+
document.addEventListener(
|
|
2391
|
+
"mousedown",
|
|
2392
|
+
(e) => {
|
|
2393
|
+
const target = e.target;
|
|
2394
|
+
if (!target) return;
|
|
2395
|
+
if (panelRef.value?.contains(target)) return;
|
|
2396
|
+
if (anchorEl.value?.contains(target)) return;
|
|
2397
|
+
close({ refocus: false });
|
|
2398
|
+
},
|
|
2399
|
+
{ signal }
|
|
2400
|
+
);
|
|
2401
|
+
document.addEventListener(
|
|
2402
|
+
"keydown",
|
|
2403
|
+
(e) => {
|
|
2404
|
+
if (e.key === "Escape" && isOpen.value) {
|
|
2405
|
+
e.preventDefault();
|
|
2406
|
+
close({ refocus: true });
|
|
2407
|
+
}
|
|
2408
|
+
},
|
|
2409
|
+
{ signal }
|
|
2410
|
+
);
|
|
2515
2411
|
onCleanup(() => {
|
|
2516
2412
|
controller.abort();
|
|
2517
2413
|
});
|
|
@@ -2535,14 +2431,12 @@ function useNotionColorPicker(options) {
|
|
|
2535
2431
|
const cols = 5;
|
|
2536
2432
|
const root = panelRef.value;
|
|
2537
2433
|
if (!root) return;
|
|
2538
|
-
const swatches = Array.from(
|
|
2539
|
-
root.querySelectorAll(".dm-ncp-swatch")
|
|
2540
|
-
);
|
|
2434
|
+
const swatches = Array.from(root.querySelectorAll(".dm-ncp-swatch"));
|
|
2541
2435
|
if (!swatches.length) return;
|
|
2542
2436
|
const active = document.activeElement;
|
|
2543
2437
|
const idx = active ? swatches.indexOf(active) : -1;
|
|
2544
2438
|
if (idx === -1) return;
|
|
2545
|
-
let next
|
|
2439
|
+
let next;
|
|
2546
2440
|
switch (event.key) {
|
|
2547
2441
|
case "ArrowRight":
|
|
2548
2442
|
event.preventDefault();
|
|
@@ -2597,7 +2491,9 @@ var DomternalNotionColorPicker = defineComponent({
|
|
|
2597
2491
|
},
|
|
2598
2492
|
setup(props, { slots }) {
|
|
2599
2493
|
const { editor: contextEditor } = useCurrentEditor();
|
|
2600
|
-
const editorRef = computed(
|
|
2494
|
+
const editorRef = computed(
|
|
2495
|
+
() => props.editor ?? contextEditor.value
|
|
2496
|
+
);
|
|
2601
2497
|
const api = useNotionColorPicker({ editor: editorRef });
|
|
2602
2498
|
const {
|
|
2603
2499
|
isOpen,
|
|
@@ -2626,7 +2522,9 @@ var DomternalNotionColorPicker = defineComponent({
|
|
|
2626
2522
|
id2 = requestAnimationFrame(() => {
|
|
2627
2523
|
if (!panel.isConnected) return;
|
|
2628
2524
|
const active = panel.querySelector(".dm-ncp-swatch.dm-ncp-active");
|
|
2629
|
-
const fallback = panel.querySelector(
|
|
2525
|
+
const fallback = panel.querySelector(
|
|
2526
|
+
'.dm-ncp-swatch--text[data-color="null"]'
|
|
2527
|
+
);
|
|
2630
2528
|
(active ?? fallback)?.focus({ preventScroll: true });
|
|
2631
2529
|
});
|
|
2632
2530
|
});
|
|
@@ -2660,21 +2558,23 @@ var DomternalNotionColorPicker = defineComponent({
|
|
|
2660
2558
|
applyText(null);
|
|
2661
2559
|
}
|
|
2662
2560
|
}),
|
|
2663
|
-
...pal.map(
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
e
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2561
|
+
...pal.map(
|
|
2562
|
+
(t) => h("button", {
|
|
2563
|
+
key: t,
|
|
2564
|
+
type: "button",
|
|
2565
|
+
class: ["dm-ncp-swatch", "dm-ncp-swatch--text", tToken === t && "dm-ncp-active"],
|
|
2566
|
+
"aria-pressed": tToken === t,
|
|
2567
|
+
"data-color": t,
|
|
2568
|
+
title: tokenLabel(t),
|
|
2569
|
+
"aria-label": `${tokenLabel(t)} text`,
|
|
2570
|
+
onMousedown: (e) => {
|
|
2571
|
+
e.preventDefault();
|
|
2572
|
+
},
|
|
2573
|
+
onClick: () => {
|
|
2574
|
+
applyText(t);
|
|
2575
|
+
}
|
|
2576
|
+
})
|
|
2577
|
+
)
|
|
2678
2578
|
])
|
|
2679
2579
|
]),
|
|
2680
2580
|
h("div", { class: "dm-ncp-section" }, [
|
|
@@ -2694,21 +2594,23 @@ var DomternalNotionColorPicker = defineComponent({
|
|
|
2694
2594
|
applyBg(null);
|
|
2695
2595
|
}
|
|
2696
2596
|
}),
|
|
2697
|
-
...pal.map(
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
e
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2597
|
+
...pal.map(
|
|
2598
|
+
(t) => h("button", {
|
|
2599
|
+
key: t,
|
|
2600
|
+
type: "button",
|
|
2601
|
+
class: ["dm-ncp-swatch", "dm-ncp-swatch--bg", bToken === t && "dm-ncp-active"],
|
|
2602
|
+
"aria-pressed": bToken === t,
|
|
2603
|
+
"data-color": t,
|
|
2604
|
+
title: `${tokenLabel(t)} background`,
|
|
2605
|
+
"aria-label": `${tokenLabel(t)} background`,
|
|
2606
|
+
onMousedown: (e) => {
|
|
2607
|
+
e.preventDefault();
|
|
2608
|
+
},
|
|
2609
|
+
onClick: () => {
|
|
2610
|
+
applyBg(t);
|
|
2611
|
+
}
|
|
2612
|
+
})
|
|
2613
|
+
)
|
|
2712
2614
|
])
|
|
2713
2615
|
])
|
|
2714
2616
|
];
|
|
@@ -2719,19 +2621,23 @@ var DomternalNotionColorPicker = defineComponent({
|
|
|
2719
2621
|
const slotChildren = slot ? slot({ api }) : void 0;
|
|
2720
2622
|
const panelChildren = slotChildren ?? renderDefaultPanel();
|
|
2721
2623
|
return h(Teleport, { to: hostEl.value }, [
|
|
2722
|
-
h(
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2624
|
+
h(
|
|
2625
|
+
"div",
|
|
2626
|
+
{
|
|
2627
|
+
ref: panelRef,
|
|
2628
|
+
class: "dm-notion-color-picker",
|
|
2629
|
+
"data-show": "",
|
|
2630
|
+
"data-dm-editor-ui": "",
|
|
2631
|
+
role: "dialog",
|
|
2632
|
+
"aria-label": "Text and background color",
|
|
2633
|
+
// Intentional non-modal: the picker doesn't trap focus (outside-click
|
|
2634
|
+
// closes, editor stays interactive). `role="dialog"` defaults to
|
|
2635
|
+
// modal=true for screen readers, so we explicitly opt out.
|
|
2636
|
+
"aria-modal": "false",
|
|
2637
|
+
onKeydown: onPanelKeydown
|
|
2638
|
+
},
|
|
2639
|
+
panelChildren
|
|
2640
|
+
)
|
|
2735
2641
|
]);
|
|
2736
2642
|
};
|
|
2737
2643
|
}
|