@eventuras/scribo 0.8.3 → 0.10.7
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/dist/App.d.ts +11 -0
- package/dist/App.d.ts.map +1 -0
- package/dist/MarkdownEditor.d.ts +18 -0
- package/dist/MarkdownEditor.d.ts.map +1 -0
- package/dist/MarkdownEditor2.js +111 -0
- package/dist/MarkdownEditor2.js.map +1 -0
- package/dist/MarkdownInput.d.ts +27 -0
- package/dist/MarkdownInput.d.ts.map +1 -0
- package/dist/MarkdownInput.js +57 -0
- package/dist/MarkdownInput.js.map +1 -0
- package/dist/callout.js +5 -0
- package/dist/context/SharedHistoryContext.d.ts +11 -0
- package/dist/context/SharedHistoryContext.d.ts.map +1 -0
- package/dist/context/SharedHistoryContext.js +12 -0
- package/dist/context/SharedHistoryContext.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/main.d.ts +5 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +4 -0
- package/dist/nodes/EditorNodes.d.ts +4 -0
- package/dist/nodes/EditorNodes.d.ts.map +1 -0
- package/dist/nodes/EditorNodes.js +39 -0
- package/dist/nodes/EditorNodes.js.map +1 -0
- package/dist/nodes/callout/CalloutComponent.d.ts +6 -0
- package/dist/nodes/callout/CalloutComponent.d.ts.map +1 -0
- package/dist/nodes/callout/CalloutComponent.js +53 -0
- package/dist/nodes/callout/CalloutComponent.js.map +1 -0
- package/dist/nodes/callout/CalloutNode.d.ts +27 -0
- package/dist/nodes/callout/CalloutNode.d.ts.map +1 -0
- package/dist/nodes/callout/CalloutNode.js +153 -0
- package/dist/nodes/callout/CalloutNode.js.map +1 -0
- package/dist/nodes/callout/CalloutTransformer.d.ts +3 -0
- package/dist/nodes/callout/CalloutTransformer.d.ts.map +1 -0
- package/dist/nodes/callout/CalloutTransformer.js +48 -0
- package/dist/nodes/callout/CalloutTransformer.js.map +1 -0
- package/dist/nodes/callout/calloutPlugin.d.ts +3 -0
- package/dist/nodes/callout/calloutPlugin.d.ts.map +1 -0
- package/dist/nodes/callout/calloutPlugin.js +34 -0
- package/dist/nodes/callout/calloutPlugin.js.map +1 -0
- package/dist/nodes/callout/index.d.ts +6 -0
- package/dist/nodes/callout/index.d.ts.map +1 -0
- package/dist/nodes/schedule/ScheduleItemComponent.d.ts +9 -0
- package/dist/nodes/schedule/ScheduleItemComponent.d.ts.map +1 -0
- package/dist/nodes/schedule/ScheduleItemComponent.js +167 -0
- package/dist/nodes/schedule/ScheduleItemComponent.js.map +1 -0
- package/dist/nodes/schedule/ScheduleItemNode.d.ts +31 -0
- package/dist/nodes/schedule/ScheduleItemNode.d.ts.map +1 -0
- package/dist/nodes/schedule/ScheduleItemNode.js +94 -0
- package/dist/nodes/schedule/ScheduleItemNode.js.map +1 -0
- package/dist/nodes/schedule/ScheduleTransformer.d.ts +22 -0
- package/dist/nodes/schedule/ScheduleTransformer.d.ts.map +1 -0
- package/dist/nodes/schedule/ScheduleTransformer.js +60 -0
- package/dist/nodes/schedule/ScheduleTransformer.js.map +1 -0
- package/dist/nodes/schedule/index.d.ts +5 -0
- package/dist/nodes/schedule/index.d.ts.map +1 -0
- package/dist/nodes/schedule/schedulePlugin.d.ts +3 -0
- package/dist/nodes/schedule/schedulePlugin.d.ts.map +1 -0
- package/dist/nodes/schedule/schedulePlugin.js +33 -0
- package/dist/nodes/schedule/schedulePlugin.js.map +1 -0
- package/dist/plugins/AutoLinkPlugin.d.ts +3 -0
- package/dist/plugins/AutoLinkPlugin.d.ts.map +1 -0
- package/dist/plugins/AutoLinkPlugin.js +22 -0
- package/dist/plugins/AutoLinkPlugin.js.map +1 -0
- package/dist/plugins/FloatingLinkEditorPlugin.d.ts +7 -0
- package/dist/plugins/FloatingLinkEditorPlugin.d.ts.map +1 -0
- package/dist/plugins/FloatingLinkEditorPlugin2.js +302 -0
- package/dist/plugins/FloatingLinkEditorPlugin2.js.map +1 -0
- package/dist/plugins/HistoryPlugin.d.ts +26 -0
- package/dist/plugins/HistoryPlugin.d.ts.map +1 -0
- package/dist/plugins/LinkPlugin.d.ts +3 -0
- package/dist/plugins/LinkPlugin.d.ts.map +1 -0
- package/dist/plugins/LinkPlugin.js +18 -0
- package/dist/plugins/LinkPlugin.js.map +1 -0
- package/dist/plugins/ToolbarPlugin.d.ts +7 -0
- package/dist/plugins/ToolbarPlugin.d.ts.map +1 -0
- package/dist/plugins/ToolbarPlugin.js +372 -0
- package/dist/plugins/ToolbarPlugin.js.map +1 -0
- package/dist/schedule.js +4 -0
- package/dist/scribo.css +1977 -0
- package/dist/themes/EditorTheme.d.ts +4 -0
- package/dist/themes/EditorTheme.d.ts.map +1 -0
- package/dist/themes/EditorTheme2.js +107 -0
- package/dist/themes/EditorTheme2.js.map +1 -0
- package/dist/types.d.ts +26 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/ui/ContentEditable.d.ts +6 -0
- package/dist/ui/ContentEditable.d.ts.map +1 -0
- package/dist/ui/ContentEditable2.js +14 -0
- package/dist/ui/ContentEditable2.js.map +1 -0
- package/dist/ui/DropDown.d.ts +18 -0
- package/dist/ui/DropDown.d.ts.map +1 -0
- package/dist/ui/DropDown.js +162 -0
- package/dist/ui/DropDown.js.map +1 -0
- package/dist/ui/Placeholder.d.ts +6 -0
- package/dist/ui/Placeholder.d.ts.map +1 -0
- package/dist/ui/Placeholder2.js +13 -0
- package/dist/ui/Placeholder2.js.map +1 -0
- package/dist/utils/environment.d.ts +24 -0
- package/dist/utils/environment.d.ts.map +1 -0
- package/dist/utils/environment.js +20 -0
- package/dist/utils/environment.js.map +1 -0
- package/dist/utils/getSelectedNode.d.ts +3 -0
- package/dist/utils/getSelectedNode.d.ts.map +1 -0
- package/dist/utils/getSelectedNode.js +23 -0
- package/dist/utils/getSelectedNode.js.map +1 -0
- package/dist/utils/setFloatingElemPosition.d.ts +2 -0
- package/dist/utils/setFloatingElemPosition.d.ts.map +1 -0
- package/dist/utils/setFloatingElemPositionForLinkEditor.d.ts +2 -0
- package/dist/utils/setFloatingElemPositionForLinkEditor.d.ts.map +1 -0
- package/dist/utils/setFloatingElemPositionForLinkEditor.js +33 -0
- package/dist/utils/setFloatingElemPositionForLinkEditor.js.map +1 -0
- package/dist/utils/url.d.ts +11 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/dist/utils/url.js +33 -0
- package/dist/utils/url.js.map +1 -0
- package/dist/vite.svg +1 -0
- package/package.json +55 -38
- package/src/MarkdownEditor.css +61 -47
- package/src/MarkdownEditor.tsx +76 -29
- package/src/MarkdownInput.tsx +9 -10
- package/src/context/SharedHistoryContext.tsx +8 -16
- package/src/main.tsx +3 -3
- package/src/nodes/EditorNodes.ts +10 -10
- package/src/nodes/callout/Callout.css +94 -0
- package/src/nodes/callout/CalloutComponent.tsx +61 -0
- package/src/nodes/callout/CalloutNode.ts +197 -0
- package/src/nodes/callout/CalloutTransformer.ts +87 -0
- package/src/nodes/callout/calloutPlugin.ts +37 -0
- package/src/nodes/callout/index.ts +5 -0
- package/src/nodes/schedule/ScheduleItem.css +140 -0
- package/src/nodes/schedule/ScheduleItemComponent.tsx +195 -0
- package/src/nodes/schedule/ScheduleItemNode.ts +135 -0
- package/src/nodes/schedule/ScheduleTransformer.ts +80 -0
- package/src/nodes/schedule/index.ts +4 -0
- package/src/nodes/schedule/schedulePlugin.ts +33 -0
- package/src/plugins/AutoLinkPlugin.tsx +5 -10
- package/src/plugins/FloatingLinkEditorPlugin.tsx +42 -66
- package/src/plugins/HistoryPlugin.tsx +20 -30
- package/src/plugins/LinkPlugin.tsx +2 -3
- package/src/plugins/ToolbarPlugin.tsx +129 -141
- package/src/themes/EditorTheme.css +9 -5
- package/src/themes/EditorTheme.ts +89 -90
- package/src/types.ts +27 -0
- package/src/ui/ContentEditable.tsx +5 -5
- package/src/ui/DropDown.tsx +23 -41
- package/src/ui/Placeholder.tsx +21 -21
- package/src/utils/environment.ts +6 -12
- package/src/utils/getSelectedNode.ts +3 -5
- package/src/utils/setFloatingElemPosition.ts +2 -5
- package/src/utils/setFloatingElemPositionForLinkEditor.ts +1 -1
- package/src/utils/url.ts +4 -10
- package/tsconfig.json +8 -0
- package/CHANGELOG.md +0 -65
- package/README.md +0 -126
- package/RELEASE.md +0 -102
- package/eslint.config.js +0 -4
- package/src/App.css +0 -35
- package/src/App.tsx +0 -42
- package/src/index.tsx +0 -13
- package/tsconfig.node.json +0 -11
- package/vite.config.site.ts +0 -19
- package/vite.config.ts +0 -33
- /package/{src → dist}/vite-env.d.ts +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ElementTransformer } from '@lexical/markdown';
|
|
2
|
+
import { ScheduleItemData } from './ScheduleItemNode';
|
|
3
|
+
export declare function normalizeScheduleItemData(data: {
|
|
4
|
+
time: string;
|
|
5
|
+
title: string;
|
|
6
|
+
speaker?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
}): {
|
|
9
|
+
time: string;
|
|
10
|
+
title: string;
|
|
11
|
+
speaker: string | undefined;
|
|
12
|
+
description: string | undefined;
|
|
13
|
+
};
|
|
14
|
+
export declare function parseScheduleItemMarkdown(markdown: string): {
|
|
15
|
+
time: string;
|
|
16
|
+
title: string;
|
|
17
|
+
speaker: string | undefined;
|
|
18
|
+
description: string | undefined;
|
|
19
|
+
} | null;
|
|
20
|
+
export declare function formatScheduleItemMarkdown(data: ScheduleItemData): string;
|
|
21
|
+
export declare const SCHEDULE_ITEM_TRANSFORMER: ElementTransformer;
|
|
22
|
+
//# sourceMappingURL=ScheduleTransformer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScheduleTransformer.d.ts","sourceRoot":"","sources":["../../../src/nodes/schedule/ScheduleTransformer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,EAGL,KAAK,gBAAgB,EAEtB,MAAM,oBAAoB,CAAC;AAY5B,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;;;;;EAOA;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM;;;;;SAczD;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAIzE;AAED,eAAO,MAAM,yBAAyB,EAAE,kBAwBvC,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { $createScheduleItemNode, $isScheduleItemNode, ScheduleItemNode } from "./ScheduleItemNode.js";
|
|
2
|
+
//#region src/nodes/schedule/ScheduleTransformer.ts
|
|
3
|
+
/**
|
|
4
|
+
* Markdown format: `- **09:00–10:00** Title | Speaker | Description`
|
|
5
|
+
*
|
|
6
|
+
* This matches the format expected by the remarkSchedule plugin in
|
|
7
|
+
* markdown-plugin-happening, so the same markdown renders correctly
|
|
8
|
+
* both in the editor and on the frontend.
|
|
9
|
+
*/
|
|
10
|
+
var SCHEDULE_ITEM_REGEX = /^-\s+\*\*(\d{1,2}[.:]\d{2}(?:\s*[–-]\s*\d{1,2}[.:]\d{2})?)\s*\*\*\s+(.+)$/;
|
|
11
|
+
function normalizeScheduleItemData(data) {
|
|
12
|
+
return {
|
|
13
|
+
time: data.time.trim(),
|
|
14
|
+
title: data.title.trim(),
|
|
15
|
+
speaker: data.speaker?.trim() || void 0,
|
|
16
|
+
description: data.description?.trim() || void 0
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function parseScheduleItemMarkdown(markdown) {
|
|
20
|
+
const match = markdown.match(SCHEDULE_ITEM_REGEX);
|
|
21
|
+
if (!match) return null;
|
|
22
|
+
const time = (match[1] ?? "").replaceAll(".", ":").trim();
|
|
23
|
+
const parts = (match[2] ?? "").trim().split("|").map((s) => s.trim());
|
|
24
|
+
return normalizeScheduleItemData({
|
|
25
|
+
time,
|
|
26
|
+
title: parts[0] ?? "",
|
|
27
|
+
speaker: parts[1] || void 0,
|
|
28
|
+
description: parts[2] || void 0
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function formatScheduleItemMarkdown(data) {
|
|
32
|
+
const normalized = normalizeScheduleItemData(data);
|
|
33
|
+
const parts = [
|
|
34
|
+
normalized.title,
|
|
35
|
+
normalized.speaker,
|
|
36
|
+
normalized.description
|
|
37
|
+
].filter(Boolean);
|
|
38
|
+
return `- **${normalized.time}** ${parts.join(" | ")}`;
|
|
39
|
+
}
|
|
40
|
+
var SCHEDULE_ITEM_TRANSFORMER = {
|
|
41
|
+
type: "element",
|
|
42
|
+
dependencies: [ScheduleItemNode],
|
|
43
|
+
regExp: SCHEDULE_ITEM_REGEX,
|
|
44
|
+
export: (node) => {
|
|
45
|
+
if (!$isScheduleItemNode(node)) return null;
|
|
46
|
+
return formatScheduleItemMarkdown(node.getData());
|
|
47
|
+
},
|
|
48
|
+
replace: (parentNode, _children, match) => {
|
|
49
|
+
const parsed = parseScheduleItemMarkdown(match[0] ?? "");
|
|
50
|
+
const node = $createScheduleItemNode(parsed ?? {
|
|
51
|
+
time: ((match[1] ?? "").replaceAll(".", ":").trim() || "").trim(),
|
|
52
|
+
title: ""
|
|
53
|
+
});
|
|
54
|
+
parentNode.replace(node);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
//#endregion
|
|
58
|
+
export { SCHEDULE_ITEM_TRANSFORMER, formatScheduleItemMarkdown, normalizeScheduleItemData, parseScheduleItemMarkdown };
|
|
59
|
+
|
|
60
|
+
//# sourceMappingURL=ScheduleTransformer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScheduleTransformer.js","names":[],"sources":["../../../src/nodes/schedule/ScheduleTransformer.ts"],"sourcesContent":["import type { ElementTransformer } from '@lexical/markdown';\n\nimport {\n $createScheduleItemNode,\n $isScheduleItemNode,\n type ScheduleItemData,\n ScheduleItemNode,\n} from './ScheduleItemNode';\n\n/**\n * Markdown format: `- **09:00–10:00** Title | Speaker | Description`\n *\n * This matches the format expected by the remarkSchedule plugin in\n * markdown-plugin-happening, so the same markdown renders correctly\n * both in the editor and on the frontend.\n */\nconst SCHEDULE_ITEM_REGEX =\n /^-\\s+\\*\\*(\\d{1,2}[.:]\\d{2}(?:\\s*[–-]\\s*\\d{1,2}[.:]\\d{2})?)\\s*\\*\\*\\s+(.+)$/;\n\nexport function normalizeScheduleItemData(data: {\n time: string;\n title: string;\n speaker?: string;\n description?: string;\n}) {\n return {\n time: data.time.trim(),\n title: data.title.trim(),\n speaker: data.speaker?.trim() || undefined,\n description: data.description?.trim() || undefined,\n };\n}\n\nexport function parseScheduleItemMarkdown(markdown: string) {\n const match = markdown.match(SCHEDULE_ITEM_REGEX);\n if (!match) return null;\n\n const time = (match[1] ?? '').replaceAll('.', ':').trim();\n const rest = (match[2] ?? '').trim();\n const parts = rest.split('|').map((s) => s.trim());\n\n return normalizeScheduleItemData({\n time,\n title: parts[0] ?? '',\n speaker: parts[1] || undefined,\n description: parts[2] || undefined,\n });\n}\n\nexport function formatScheduleItemMarkdown(data: ScheduleItemData): string {\n const normalized = normalizeScheduleItemData(data);\n const parts = [normalized.title, normalized.speaker, normalized.description].filter(Boolean);\n return `- **${normalized.time}** ${parts.join(' | ')}`;\n}\n\nexport const SCHEDULE_ITEM_TRANSFORMER: ElementTransformer = {\n type: 'element',\n dependencies: [ScheduleItemNode],\n\n regExp: SCHEDULE_ITEM_REGEX,\n\n export: (node) => {\n if (!$isScheduleItemNode(node)) return null;\n\n return formatScheduleItemMarkdown(node.getData());\n },\n\n replace: (parentNode, _children, match) => {\n const parsed = parseScheduleItemMarkdown(match[0] ?? '');\n\n const node = $createScheduleItemNode(\n parsed ?? {\n time: ((match[1] ?? '').replaceAll('.', ':').trim() || '').trim(),\n title: '',\n }\n );\n\n parentNode.replace(node);\n },\n};\n"],"mappings":";;;;;;;;;AAgBA,IAAM,sBACJ;AAEF,SAAgB,0BAA0B,MAKvC;CACD,OAAO;EACL,MAAM,KAAK,KAAK,KAAK;EACrB,OAAO,KAAK,MAAM,KAAK;EACvB,SAAS,KAAK,SAAS,KAAK,KAAK,KAAA;EACjC,aAAa,KAAK,aAAa,KAAK,KAAK,KAAA;CAC3C;AACF;AAEA,SAAgB,0BAA0B,UAAkB;CAC1D,MAAM,QAAQ,SAAS,MAAM,mBAAmB;CAChD,IAAI,CAAC,OAAO,OAAO;CAEnB,MAAM,QAAQ,MAAM,MAAM,GAAA,CAAI,WAAW,KAAK,GAAG,CAAC,CAAC,KAAK;CAExD,MAAM,SADQ,MAAM,MAAM,GAAA,CAAI,KAChB,CAAA,CAAK,MAAM,GAAG,CAAC,CAAC,KAAK,MAAM,EAAE,KAAK,CAAC;CAEjD,OAAO,0BAA0B;EAC/B;EACA,OAAO,MAAM,MAAM;EACnB,SAAS,MAAM,MAAM,KAAA;EACrB,aAAa,MAAM,MAAM,KAAA;CAC3B,CAAC;AACH;AAEA,SAAgB,2BAA2B,MAAgC;CACzE,MAAM,aAAa,0BAA0B,IAAI;CACjD,MAAM,QAAQ;EAAC,WAAW;EAAO,WAAW;EAAS,WAAW;CAAW,CAAC,CAAC,OAAO,OAAO;CAC3F,OAAO,OAAO,WAAW,KAAK,KAAK,MAAM,KAAK,KAAK;AACrD;AAEA,IAAa,4BAAgD;CAC3D,MAAM;CACN,cAAc,CAAC,gBAAgB;CAE/B,QAAQ;CAER,SAAS,SAAS;EAChB,IAAI,CAAC,oBAAoB,IAAI,GAAG,OAAO;EAEvC,OAAO,2BAA2B,KAAK,QAAQ,CAAC;CAClD;CAEA,UAAU,YAAY,WAAW,UAAU;EACzC,MAAM,SAAS,0BAA0B,MAAM,MAAM,EAAE;EAEvD,MAAM,OAAO,wBACX,UAAU;GACR,QAAQ,MAAM,MAAM,GAAA,CAAI,WAAW,KAAK,GAAG,CAAC,CAAC,KAAK,KAAK,GAAA,CAAI,KAAK;GAChE,OAAO;EACT,CACF;EAEA,WAAW,QAAQ,IAAI;CACzB;AACF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { ScheduleItemData, SerializedScheduleItemNode } from './ScheduleItemNode';
|
|
2
|
+
export { $createScheduleItemNode, $isScheduleItemNode, ScheduleItemNode } from './ScheduleItemNode';
|
|
3
|
+
export { SCHEDULE_ITEM_TRANSFORMER } from './ScheduleTransformer';
|
|
4
|
+
export { schedulePlugin } from './schedulePlugin';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/nodes/schedule/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AACvF,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACpG,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedulePlugin.d.ts","sourceRoot":"","sources":["../../../src/nodes/schedule/schedulePlugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,eAAO,MAAM,cAAc,EAAE,YAyB5B,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { $createScheduleItemNode, ScheduleItemNode } from "./ScheduleItemNode.js";
|
|
2
|
+
import { SCHEDULE_ITEM_TRANSFORMER } from "./ScheduleTransformer.js";
|
|
3
|
+
import { $getSelection, $isRangeSelection } from "lexical";
|
|
4
|
+
import { $findMatchingParent } from "@lexical/utils";
|
|
5
|
+
//#region src/nodes/schedule/schedulePlugin.ts
|
|
6
|
+
var schedulePlugin = {
|
|
7
|
+
name: "schedule",
|
|
8
|
+
nodes: [ScheduleItemNode],
|
|
9
|
+
transformers: [SCHEDULE_ITEM_TRANSFORMER],
|
|
10
|
+
toolbarButtons: [{
|
|
11
|
+
key: "schedule-item",
|
|
12
|
+
label: "Schedule Item",
|
|
13
|
+
iconClass: "schedule",
|
|
14
|
+
onSelect: (editor) => {
|
|
15
|
+
editor.update(() => {
|
|
16
|
+
const selection = $getSelection();
|
|
17
|
+
if (!$isRangeSelection(selection)) return;
|
|
18
|
+
const anchor = selection.anchor.getNode();
|
|
19
|
+
const topLevel = $findMatchingParent(anchor, (n) => n.getParent()?.getType() === "root") ?? anchor;
|
|
20
|
+
const node = $createScheduleItemNode({
|
|
21
|
+
time: "",
|
|
22
|
+
title: ""
|
|
23
|
+
});
|
|
24
|
+
topLevel.insertAfter(node);
|
|
25
|
+
node.selectEnd();
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}]
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
export { schedulePlugin };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=schedulePlugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedulePlugin.js","names":[],"sources":["../../../src/nodes/schedule/schedulePlugin.ts"],"sourcesContent":["import { $findMatchingParent } from '@lexical/utils';\nimport { $getSelection, $isRangeSelection } from 'lexical';\n\nimport type { ScriboPlugin } from '../../types';\nimport { $createScheduleItemNode, ScheduleItemNode } from './ScheduleItemNode';\nimport { SCHEDULE_ITEM_TRANSFORMER } from './ScheduleTransformer';\n\nexport const schedulePlugin: ScriboPlugin = {\n name: 'schedule',\n nodes: [ScheduleItemNode],\n transformers: [SCHEDULE_ITEM_TRANSFORMER],\n toolbarButtons: [\n {\n key: 'schedule-item',\n label: 'Schedule Item',\n iconClass: 'schedule',\n onSelect: (editor) => {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n\n const anchor = selection.anchor.getNode();\n const topLevel =\n $findMatchingParent(anchor, (n) => n.getParent()?.getType() === 'root') ?? anchor;\n\n const node = $createScheduleItemNode({ time: '', title: '' });\n topLevel.insertAfter(node);\n node.selectEnd();\n });\n },\n },\n ],\n};\n"],"mappings":";;;;;AAOA,IAAa,iBAA+B;CAC1C,MAAM;CACN,OAAO,CAAC,gBAAgB;CACxB,cAAc,CAAC,yBAAyB;CACxC,gBAAgB,CACd;EACE,KAAK;EACL,OAAO;EACP,WAAW;EACX,WAAW,WAAW;GACpB,OAAO,aAAa;IAClB,MAAM,YAAY,cAAc;IAChC,IAAI,CAAC,kBAAkB,SAAS,GAAG;IAEnC,MAAM,SAAS,UAAU,OAAO,QAAQ;IACxC,MAAM,WACJ,oBAAoB,SAAS,MAAM,EAAE,UAAU,CAAC,EAAE,QAAQ,MAAM,MAAM,KAAK;IAE7E,MAAM,OAAO,wBAAwB;KAAE,MAAM;KAAI,OAAO;IAAG,CAAC;IAC5D,SAAS,YAAY,IAAI;IACzB,KAAK,UAAU;GACjB,CAAC;EACH;CACF,CACF;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutoLinkPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/AutoLinkPlugin.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAiBjC,MAAM,CAAC,OAAO,UAAU,qBAAqB,IAAI,GAAG,CAAC,OAAO,CAE3D"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { AutoLinkPlugin, createLinkMatcherWithRegExp } from "@lexical/react/LexicalAutoLinkPlugin";
|
|
3
|
+
//#region src/plugins/AutoLinkPlugin.tsx
|
|
4
|
+
/**
|
|
5
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
6
|
+
*
|
|
7
|
+
* This source code is licensed under the MIT license found in the
|
|
8
|
+
* LICENSE file in the root directory of this source tree.
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
var MATCHERS = [createLinkMatcherWithRegExp(/((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)(?<![-.+():%])/, (text) => {
|
|
12
|
+
return text.startsWith("http") ? text : `https://${text}`;
|
|
13
|
+
}), createLinkMatcherWithRegExp(/(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\])|(([a-zA-Z\-\d]+\.)+[a-zA-Z]{2,}))/, (text) => {
|
|
14
|
+
return `mailto:${text}`;
|
|
15
|
+
})];
|
|
16
|
+
function LexicalAutoLinkPlugin() {
|
|
17
|
+
return /* @__PURE__ */ jsx(AutoLinkPlugin, { matchers: MATCHERS });
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { LexicalAutoLinkPlugin as default };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=AutoLinkPlugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutoLinkPlugin.js","names":[],"sources":["../../src/plugins/AutoLinkPlugin.tsx"],"sourcesContent":["/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { AutoLinkPlugin, createLinkMatcherWithRegExp } from '@lexical/react/LexicalAutoLinkPlugin';\nimport type { JSX } from 'react';\n\nconst URL_REGEX =\n /((https?:\\/\\/(www\\.)?)|(www\\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)(?<![-.+():%])/;\n\nconst EMAIL_REGEX =\n /(([^<>()[\\]\\\\.,;:\\s@\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\])|(([a-zA-Z\\-\\d]+\\.)+[a-zA-Z]{2,}))/;\n\nconst MATCHERS = [\n createLinkMatcherWithRegExp(URL_REGEX, (text) => {\n return text.startsWith('http') ? text : `https://${text}`;\n }),\n createLinkMatcherWithRegExp(EMAIL_REGEX, (text) => {\n return `mailto:${text}`;\n }),\n];\n\nexport default function LexicalAutoLinkPlugin(): JSX.Element {\n return <AutoLinkPlugin matchers={MATCHERS} />;\n}\n"],"mappings":";;;;;;;;;;AAiBA,IAAM,WAAW,CACf,4BAA4B,iIAAY,SAAS;CAC/C,OAAO,KAAK,WAAW,MAAM,IAAI,OAAO,WAAW;AACrD,CAAC,GACD,4BAA4B,2IAAc,SAAS;CACjD,OAAO,UAAU;AACnB,CAAC,CACH;AAEA,SAAwB,wBAAqC;CAC3D,OAAO,oBAAC,gBAAD,EAAgB,UAAU,SAAW,CAAA;AAC9C"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { JSX, Dispatch } from 'react';
|
|
2
|
+
export default function FloatingLinkEditorPlugin({ anchorElem, isLinkEditMode, setIsLinkEditMode, }: {
|
|
3
|
+
anchorElem?: HTMLElement;
|
|
4
|
+
isLinkEditMode: boolean;
|
|
5
|
+
setIsLinkEditMode: Dispatch<boolean>;
|
|
6
|
+
}): JSX.Element | null;
|
|
7
|
+
//# sourceMappingURL=FloatingLinkEditorPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FloatingLinkEditorPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/FloatingLinkEditorPlugin.tsx"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAEjC,OAAO,gCAAgC,CAAC;AAqBxC,OAAO,EAAE,KAAK,QAAQ,EAA4C,MAAM,OAAO,CAAC;AA6YhF,MAAM,CAAC,OAAO,UAAU,wBAAwB,CAAC,EAC/C,UAAU,EACV,cAAc,EACd,iBAAiB,GAClB,EAAE;IACD,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,OAAO,CAAC;IACxB,iBAAiB,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;CACtC,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAkBrB"}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/* empty css */
|
|
2
|
+
import { getSelectedNode } from "../utils/getSelectedNode.js";
|
|
3
|
+
import { setFloatingElemPositionForLinkEditor } from "../utils/setFloatingElemPositionForLinkEditor.js";
|
|
4
|
+
import { sanitizeUrl } from "../utils/url.js";
|
|
5
|
+
import { $getSelection, $isLineBreakNode, $isNodeSelection, $isRangeSelection, CLICK_COMMAND, COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, KEY_ESCAPE_COMMAND, SELECTION_CHANGE_COMMAND, getDOMSelection } from "lexical";
|
|
6
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { $createLinkNode, $isAutoLinkNode, $isLinkNode, TOGGLE_LINK_COMMAND } from "@lexical/link";
|
|
9
|
+
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
10
|
+
import { $findMatchingParent, mergeRegister } from "@lexical/utils";
|
|
11
|
+
import { createPortal } from "react-dom";
|
|
12
|
+
//#region src/plugins/FloatingLinkEditorPlugin.tsx
|
|
13
|
+
function preventDefault(event) {
|
|
14
|
+
event.preventDefault();
|
|
15
|
+
}
|
|
16
|
+
function FloatingLinkEditor({ editor, isLink, setIsLink, anchorElem, isLinkEditMode, setIsLinkEditMode }) {
|
|
17
|
+
const editorRef = useRef(null);
|
|
18
|
+
const inputRef = useRef(null);
|
|
19
|
+
const [linkUrl, setLinkUrl] = useState("");
|
|
20
|
+
const [editedLinkUrl, setEditedLinkUrl] = useState("https://");
|
|
21
|
+
const [lastSelection, setLastSelection] = useState(null);
|
|
22
|
+
const $updateLinkEditor = useCallback(() => {
|
|
23
|
+
const selection = $getSelection();
|
|
24
|
+
if ($isRangeSelection(selection)) {
|
|
25
|
+
const node = getSelectedNode(selection);
|
|
26
|
+
const linkParent = $findMatchingParent(node, $isLinkNode);
|
|
27
|
+
if (linkParent) setLinkUrl(linkParent.getURL());
|
|
28
|
+
else if ($isLinkNode(node)) setLinkUrl(node.getURL());
|
|
29
|
+
else setLinkUrl("");
|
|
30
|
+
if (isLinkEditMode) setEditedLinkUrl(linkUrl);
|
|
31
|
+
} else if ($isNodeSelection(selection)) {
|
|
32
|
+
const nodes = selection.getNodes();
|
|
33
|
+
if (nodes.length > 0) {
|
|
34
|
+
const node = nodes[0];
|
|
35
|
+
const parent = node.getParent();
|
|
36
|
+
if ($isLinkNode(parent)) setLinkUrl(parent.getURL());
|
|
37
|
+
else if ($isLinkNode(node)) setLinkUrl(node.getURL());
|
|
38
|
+
else setLinkUrl("");
|
|
39
|
+
if (isLinkEditMode) setEditedLinkUrl(linkUrl);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const editorElem = editorRef.current;
|
|
43
|
+
const nativeSelection = getDOMSelection(editor._window);
|
|
44
|
+
const activeElement = document.activeElement;
|
|
45
|
+
if (editorElem === null) return;
|
|
46
|
+
const rootElement = editor.getRootElement();
|
|
47
|
+
if (selection !== null && rootElement !== null && editor.isEditable()) {
|
|
48
|
+
let domRect;
|
|
49
|
+
if ($isNodeSelection(selection)) {
|
|
50
|
+
const nodes = selection.getNodes();
|
|
51
|
+
if (nodes.length > 0) {
|
|
52
|
+
const element = editor.getElementByKey(nodes[0].getKey());
|
|
53
|
+
if (element) domRect = element.getBoundingClientRect();
|
|
54
|
+
}
|
|
55
|
+
} else if (nativeSelection !== null && rootElement.contains(nativeSelection.anchorNode)) domRect = nativeSelection.focusNode?.parentElement?.getBoundingClientRect();
|
|
56
|
+
if (domRect) {
|
|
57
|
+
domRect.y += 40;
|
|
58
|
+
setFloatingElemPositionForLinkEditor(domRect, editorElem, anchorElem);
|
|
59
|
+
}
|
|
60
|
+
setLastSelection(selection);
|
|
61
|
+
} else if (activeElement?.className !== "link-input") {
|
|
62
|
+
if (rootElement !== null) setFloatingElemPositionForLinkEditor(null, editorElem, anchorElem);
|
|
63
|
+
setLastSelection(null);
|
|
64
|
+
setIsLinkEditMode(false);
|
|
65
|
+
setLinkUrl("");
|
|
66
|
+
}
|
|
67
|
+
return true;
|
|
68
|
+
}, [
|
|
69
|
+
anchorElem,
|
|
70
|
+
editor,
|
|
71
|
+
setIsLinkEditMode,
|
|
72
|
+
isLinkEditMode,
|
|
73
|
+
linkUrl
|
|
74
|
+
]);
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
const scrollerElem = anchorElem.parentElement;
|
|
77
|
+
const update = () => {
|
|
78
|
+
editor.getEditorState().read(() => {
|
|
79
|
+
$updateLinkEditor();
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
window.addEventListener("resize", update);
|
|
83
|
+
if (scrollerElem) scrollerElem.addEventListener("scroll", update);
|
|
84
|
+
return () => {
|
|
85
|
+
window.removeEventListener("resize", update);
|
|
86
|
+
if (scrollerElem) scrollerElem.removeEventListener("scroll", update);
|
|
87
|
+
};
|
|
88
|
+
}, [
|
|
89
|
+
anchorElem.parentElement,
|
|
90
|
+
editor,
|
|
91
|
+
$updateLinkEditor
|
|
92
|
+
]);
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
return mergeRegister(editor.registerUpdateListener(({ editorState }) => {
|
|
95
|
+
editorState.read(() => {
|
|
96
|
+
$updateLinkEditor();
|
|
97
|
+
});
|
|
98
|
+
}), editor.registerCommand(SELECTION_CHANGE_COMMAND, () => {
|
|
99
|
+
$updateLinkEditor();
|
|
100
|
+
return true;
|
|
101
|
+
}, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_ESCAPE_COMMAND, () => {
|
|
102
|
+
if (isLink) {
|
|
103
|
+
setIsLink(false);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}, COMMAND_PRIORITY_HIGH));
|
|
108
|
+
}, [
|
|
109
|
+
editor,
|
|
110
|
+
$updateLinkEditor,
|
|
111
|
+
setIsLink,
|
|
112
|
+
isLink
|
|
113
|
+
]);
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
editor.getEditorState().read(() => {
|
|
116
|
+
$updateLinkEditor();
|
|
117
|
+
});
|
|
118
|
+
}, [editor, $updateLinkEditor]);
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (isLinkEditMode && inputRef.current) inputRef.current.focus();
|
|
121
|
+
}, [isLinkEditMode, isLink]);
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
const editorElement = editorRef.current;
|
|
124
|
+
if (editorElement === null) return;
|
|
125
|
+
const handleBlur = (event) => {
|
|
126
|
+
if (!editorElement.contains(event.relatedTarget) && isLink) {
|
|
127
|
+
setIsLink(false);
|
|
128
|
+
setIsLinkEditMode(false);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
editorElement.addEventListener("focusout", handleBlur);
|
|
132
|
+
return () => {
|
|
133
|
+
editorElement.removeEventListener("focusout", handleBlur);
|
|
134
|
+
};
|
|
135
|
+
}, [
|
|
136
|
+
editorRef,
|
|
137
|
+
setIsLink,
|
|
138
|
+
setIsLinkEditMode,
|
|
139
|
+
isLink
|
|
140
|
+
]);
|
|
141
|
+
const monitorInputInteraction = (event) => {
|
|
142
|
+
if (event.key === "Enter") handleLinkSubmission(event);
|
|
143
|
+
else if (event.key === "Escape") {
|
|
144
|
+
event.preventDefault();
|
|
145
|
+
setIsLinkEditMode(false);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const handleLinkSubmission = (event) => {
|
|
149
|
+
event.preventDefault();
|
|
150
|
+
if (lastSelection !== null) {
|
|
151
|
+
if (linkUrl !== "") editor.update(() => {
|
|
152
|
+
editor.dispatchCommand(TOGGLE_LINK_COMMAND, sanitizeUrl(editedLinkUrl));
|
|
153
|
+
const selection = $getSelection();
|
|
154
|
+
if ($isRangeSelection(selection)) {
|
|
155
|
+
const parent = getSelectedNode(selection).getParent();
|
|
156
|
+
if ($isAutoLinkNode(parent)) {
|
|
157
|
+
const linkNode = $createLinkNode(parent.getURL(), {
|
|
158
|
+
rel: parent.__rel,
|
|
159
|
+
target: parent.__target,
|
|
160
|
+
title: parent.__title
|
|
161
|
+
});
|
|
162
|
+
parent.replace(linkNode, true);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
setEditedLinkUrl("https://");
|
|
167
|
+
setIsLinkEditMode(false);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
171
|
+
ref: editorRef,
|
|
172
|
+
className: "link-editor",
|
|
173
|
+
children: [isLink && isLinkEditMode && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("input", {
|
|
174
|
+
ref: inputRef,
|
|
175
|
+
className: "link-input",
|
|
176
|
+
value: editedLinkUrl,
|
|
177
|
+
onChange: (event) => {
|
|
178
|
+
setEditedLinkUrl(event.target.value);
|
|
179
|
+
},
|
|
180
|
+
onKeyDown: (event) => {
|
|
181
|
+
monitorInputInteraction(event);
|
|
182
|
+
}
|
|
183
|
+
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
184
|
+
className: "link-cancel",
|
|
185
|
+
role: "button",
|
|
186
|
+
tabIndex: 0,
|
|
187
|
+
onMouseDown: preventDefault,
|
|
188
|
+
onClick: () => {
|
|
189
|
+
setIsLinkEditMode(false);
|
|
190
|
+
}
|
|
191
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
192
|
+
className: "link-confirm",
|
|
193
|
+
role: "button",
|
|
194
|
+
tabIndex: 0,
|
|
195
|
+
onMouseDown: preventDefault,
|
|
196
|
+
onClick: handleLinkSubmission
|
|
197
|
+
})] })] }), isLink && !isLinkEditMode && /* @__PURE__ */ jsxs("div", {
|
|
198
|
+
className: "link-view",
|
|
199
|
+
children: [
|
|
200
|
+
/* @__PURE__ */ jsx("a", {
|
|
201
|
+
href: sanitizeUrl(linkUrl),
|
|
202
|
+
target: "_blank",
|
|
203
|
+
rel: "noopener noreferrer",
|
|
204
|
+
children: linkUrl
|
|
205
|
+
}),
|
|
206
|
+
/* @__PURE__ */ jsx("div", {
|
|
207
|
+
className: "link-edit",
|
|
208
|
+
role: "button",
|
|
209
|
+
tabIndex: 0,
|
|
210
|
+
onMouseDown: preventDefault,
|
|
211
|
+
onClick: (event) => {
|
|
212
|
+
event.preventDefault();
|
|
213
|
+
setEditedLinkUrl(linkUrl);
|
|
214
|
+
setIsLinkEditMode(true);
|
|
215
|
+
}
|
|
216
|
+
}),
|
|
217
|
+
/* @__PURE__ */ jsx("div", {
|
|
218
|
+
className: "link-trash",
|
|
219
|
+
role: "button",
|
|
220
|
+
tabIndex: 0,
|
|
221
|
+
onMouseDown: preventDefault,
|
|
222
|
+
onClick: () => {
|
|
223
|
+
editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
]
|
|
227
|
+
})]
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
function useFloatingLinkEditorToolbar(editor, anchorElem, isLinkEditMode, setIsLinkEditMode) {
|
|
231
|
+
const [activeEditor, setActiveEditor] = useState(editor);
|
|
232
|
+
const [isLink, setIsLink] = useState(false);
|
|
233
|
+
useEffect(() => {
|
|
234
|
+
function $updateToolbar() {
|
|
235
|
+
const selection = $getSelection();
|
|
236
|
+
if ($isRangeSelection(selection)) {
|
|
237
|
+
const focusNode = getSelectedNode(selection);
|
|
238
|
+
const focusLinkNode = $findMatchingParent(focusNode, $isLinkNode);
|
|
239
|
+
const focusAutoLinkNode = $findMatchingParent(focusNode, $isAutoLinkNode);
|
|
240
|
+
if (!(focusLinkNode || focusAutoLinkNode)) {
|
|
241
|
+
setIsLink(false);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (!selection.getNodes().filter((node) => !$isLineBreakNode(node)).find((node) => {
|
|
245
|
+
const linkNode = $findMatchingParent(node, $isLinkNode);
|
|
246
|
+
const autoLinkNode = $findMatchingParent(node, $isAutoLinkNode);
|
|
247
|
+
return focusLinkNode && !focusLinkNode.is(linkNode) || linkNode && !linkNode.is(focusLinkNode) || focusAutoLinkNode && !focusAutoLinkNode.is(autoLinkNode) || autoLinkNode && (!autoLinkNode.is(focusAutoLinkNode) || autoLinkNode.getIsUnlinked());
|
|
248
|
+
})) setIsLink(true);
|
|
249
|
+
else setIsLink(false);
|
|
250
|
+
} else if ($isNodeSelection(selection)) {
|
|
251
|
+
const nodes = selection.getNodes();
|
|
252
|
+
if (nodes.length === 0) {
|
|
253
|
+
setIsLink(false);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const node = nodes[0];
|
|
257
|
+
const parent = node.getParent();
|
|
258
|
+
if ($isLinkNode(parent) || $isLinkNode(node)) setIsLink(true);
|
|
259
|
+
else setIsLink(false);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return mergeRegister(editor.registerUpdateListener(({ editorState }) => {
|
|
263
|
+
editorState.read(() => {
|
|
264
|
+
$updateToolbar();
|
|
265
|
+
});
|
|
266
|
+
}), editor.registerCommand(SELECTION_CHANGE_COMMAND, (_payload, newEditor) => {
|
|
267
|
+
$updateToolbar();
|
|
268
|
+
setActiveEditor(newEditor);
|
|
269
|
+
return false;
|
|
270
|
+
}, COMMAND_PRIORITY_CRITICAL), editor.registerCommand(CLICK_COMMAND, (payload) => {
|
|
271
|
+
const selection = $getSelection();
|
|
272
|
+
if ($isRangeSelection(selection)) {
|
|
273
|
+
const node = getSelectedNode(selection);
|
|
274
|
+
const linkNode = $findMatchingParent(node, $isLinkNode);
|
|
275
|
+
if ($isLinkNode(linkNode) && (payload.metaKey || payload.ctrlKey)) {
|
|
276
|
+
window.open(linkNode.getURL(), "_blank");
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return false;
|
|
281
|
+
}, COMMAND_PRIORITY_LOW));
|
|
282
|
+
}, [editor]);
|
|
283
|
+
return createPortal(/* @__PURE__ */ jsx(FloatingLinkEditor, {
|
|
284
|
+
editor: activeEditor,
|
|
285
|
+
isLink,
|
|
286
|
+
anchorElem,
|
|
287
|
+
setIsLink,
|
|
288
|
+
isLinkEditMode,
|
|
289
|
+
setIsLinkEditMode
|
|
290
|
+
}), anchorElem);
|
|
291
|
+
}
|
|
292
|
+
function FloatingLinkEditorPlugin({ anchorElem, isLinkEditMode, setIsLinkEditMode }) {
|
|
293
|
+
const [editor] = useLexicalComposerContext();
|
|
294
|
+
const defaultAnchorElem = typeof document !== "undefined" ? document.body : null;
|
|
295
|
+
const effectiveAnchorElem = anchorElem ?? defaultAnchorElem;
|
|
296
|
+
if (!effectiveAnchorElem) return null;
|
|
297
|
+
return useFloatingLinkEditorToolbar(editor, effectiveAnchorElem, isLinkEditMode, setIsLinkEditMode);
|
|
298
|
+
}
|
|
299
|
+
//#endregion
|
|
300
|
+
export { FloatingLinkEditorPlugin as default };
|
|
301
|
+
|
|
302
|
+
//# sourceMappingURL=FloatingLinkEditorPlugin2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FloatingLinkEditorPlugin2.js","names":[],"sources":["../../src/plugins/FloatingLinkEditorPlugin.tsx"],"sourcesContent":["// @ts-nocheck\n// https://github.com/facebook/lexical/blob/main/packages/lexical-playground/src/plugins/FloatingLinkEditorPlugin/index.tsx\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\nimport type { JSX } from 'react';\n\nimport './FloatingLinkEditorPlugin.css';\n\nimport { $createLinkNode, $isAutoLinkNode, $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { $findMatchingParent, mergeRegister } from '@lexical/utils';\nimport {\n $getSelection,\n $isLineBreakNode,\n $isNodeSelection,\n $isRangeSelection,\n type BaseSelection,\n CLICK_COMMAND,\n COMMAND_PRIORITY_CRITICAL,\n COMMAND_PRIORITY_HIGH,\n COMMAND_PRIORITY_LOW,\n getDOMSelection,\n KEY_ESCAPE_COMMAND,\n type LexicalEditor,\n SELECTION_CHANGE_COMMAND,\n} from 'lexical';\nimport type * as React from 'react';\nimport { type Dispatch, useCallback, useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { getSelectedNode } from '../utils/getSelectedNode';\nimport { setFloatingElemPositionForLinkEditor } from '../utils/setFloatingElemPositionForLinkEditor';\nimport { sanitizeUrl } from '../utils/url';\n\nfunction preventDefault(\n event: React.KeyboardEvent<HTMLInputElement> | React.MouseEvent<HTMLElement>\n): void {\n event.preventDefault();\n}\n\nfunction FloatingLinkEditor({\n editor,\n isLink,\n setIsLink,\n anchorElem,\n isLinkEditMode,\n setIsLinkEditMode,\n}: Readonly<{\n editor: LexicalEditor;\n isLink: boolean;\n setIsLink: Dispatch<boolean>;\n anchorElem: HTMLElement;\n isLinkEditMode: boolean;\n setIsLinkEditMode: Dispatch<boolean>;\n}>): JSX.Element {\n const editorRef = useRef<HTMLDivElement | null>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const [linkUrl, setLinkUrl] = useState('');\n const [editedLinkUrl, setEditedLinkUrl] = useState('https://');\n const [lastSelection, setLastSelection] = useState<BaseSelection | null>(null);\n\n const $updateLinkEditor = useCallback(() => {\n const selection = $getSelection();\n if ($isRangeSelection(selection)) {\n const node = getSelectedNode(selection);\n const linkParent = $findMatchingParent(node, $isLinkNode);\n\n if (linkParent) {\n setLinkUrl(linkParent.getURL());\n } else if ($isLinkNode(node)) {\n setLinkUrl(node.getURL());\n } else {\n setLinkUrl('');\n }\n if (isLinkEditMode) {\n setEditedLinkUrl(linkUrl);\n }\n } else if ($isNodeSelection(selection)) {\n const nodes = selection.getNodes();\n if (nodes.length > 0) {\n const node = nodes[0];\n const parent = node.getParent();\n if ($isLinkNode(parent)) {\n setLinkUrl(parent.getURL());\n } else if ($isLinkNode(node)) {\n setLinkUrl(node.getURL());\n } else {\n setLinkUrl('');\n }\n if (isLinkEditMode) {\n setEditedLinkUrl(linkUrl);\n }\n }\n }\n\n const editorElem = editorRef.current;\n const nativeSelection = getDOMSelection(editor._window);\n const activeElement = document.activeElement;\n\n if (editorElem === null) {\n return;\n }\n\n const rootElement = editor.getRootElement();\n\n if (selection !== null && rootElement !== null && editor.isEditable()) {\n let domRect: DOMRect | undefined;\n\n if ($isNodeSelection(selection)) {\n const nodes = selection.getNodes();\n if (nodes.length > 0) {\n const element = editor.getElementByKey(nodes[0].getKey());\n if (element) {\n domRect = element.getBoundingClientRect();\n }\n }\n } else if (nativeSelection !== null && rootElement.contains(nativeSelection.anchorNode)) {\n domRect = nativeSelection.focusNode?.parentElement?.getBoundingClientRect();\n }\n\n if (domRect) {\n domRect.y += 40;\n setFloatingElemPositionForLinkEditor(domRect, editorElem, anchorElem);\n }\n setLastSelection(selection);\n } else if (activeElement?.className !== 'link-input') {\n if (rootElement !== null) {\n setFloatingElemPositionForLinkEditor(null, editorElem, anchorElem);\n }\n setLastSelection(null);\n setIsLinkEditMode(false);\n setLinkUrl('');\n }\n\n return true;\n }, [anchorElem, editor, setIsLinkEditMode, isLinkEditMode, linkUrl]);\n\n useEffect(() => {\n const scrollerElem = anchorElem.parentElement;\n\n const update = () => {\n editor.getEditorState().read(() => {\n $updateLinkEditor();\n });\n };\n\n window.addEventListener('resize', update);\n\n if (scrollerElem) {\n scrollerElem.addEventListener('scroll', update);\n }\n\n return () => {\n window.removeEventListener('resize', update);\n\n if (scrollerElem) {\n scrollerElem.removeEventListener('scroll', update);\n }\n };\n }, [anchorElem.parentElement, editor, $updateLinkEditor]);\n\n useEffect(() => {\n return mergeRegister(\n editor.registerUpdateListener(({ editorState }) => {\n editorState.read(() => {\n $updateLinkEditor();\n });\n }),\n\n editor.registerCommand(\n SELECTION_CHANGE_COMMAND,\n () => {\n $updateLinkEditor();\n return true;\n },\n COMMAND_PRIORITY_LOW\n ),\n editor.registerCommand(\n KEY_ESCAPE_COMMAND,\n () => {\n if (isLink) {\n setIsLink(false);\n return true;\n }\n return false;\n },\n COMMAND_PRIORITY_HIGH\n )\n );\n }, [editor, $updateLinkEditor, setIsLink, isLink]);\n\n useEffect(() => {\n editor.getEditorState().read(() => {\n $updateLinkEditor();\n });\n }, [editor, $updateLinkEditor]);\n\n useEffect(() => {\n if (isLinkEditMode && inputRef.current) {\n inputRef.current.focus();\n }\n }, [isLinkEditMode, isLink]);\n\n useEffect(() => {\n const editorElement = editorRef.current;\n if (editorElement === null) {\n return;\n }\n const handleBlur = (event: FocusEvent) => {\n if (!editorElement.contains(event.relatedTarget as Element) && isLink) {\n setIsLink(false);\n setIsLinkEditMode(false);\n }\n };\n editorElement.addEventListener('focusout', handleBlur);\n return () => {\n editorElement.removeEventListener('focusout', handleBlur);\n };\n }, [editorRef, setIsLink, setIsLinkEditMode, isLink]);\n\n const monitorInputInteraction = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n handleLinkSubmission(event);\n } else if (event.key === 'Escape') {\n event.preventDefault();\n setIsLinkEditMode(false);\n }\n };\n\n const handleLinkSubmission = (\n event: React.KeyboardEvent<HTMLInputElement> | React.MouseEvent<HTMLElement>\n ) => {\n event.preventDefault();\n if (lastSelection !== null) {\n if (linkUrl !== '') {\n editor.update(() => {\n editor.dispatchCommand(TOGGLE_LINK_COMMAND, sanitizeUrl(editedLinkUrl));\n const selection = $getSelection();\n if ($isRangeSelection(selection)) {\n const parent = getSelectedNode(selection).getParent();\n if ($isAutoLinkNode(parent)) {\n const linkNode = $createLinkNode(parent.getURL(), {\n rel: parent.__rel,\n target: parent.__target,\n title: parent.__title,\n });\n parent.replace(linkNode, true);\n }\n }\n });\n }\n setEditedLinkUrl('https://');\n setIsLinkEditMode(false);\n }\n };\n\n return (\n <div ref={editorRef} className=\"link-editor\">\n {isLink && isLinkEditMode && (\n <>\n <input\n ref={inputRef}\n className=\"link-input\"\n value={editedLinkUrl}\n onChange={(event) => {\n setEditedLinkUrl(event.target.value);\n }}\n onKeyDown={(event) => {\n monitorInputInteraction(event);\n }}\n />\n <div>\n <div\n className=\"link-cancel\"\n role=\"button\"\n tabIndex={0}\n onMouseDown={preventDefault}\n onClick={() => {\n setIsLinkEditMode(false);\n }}\n />\n\n <div\n className=\"link-confirm\"\n role=\"button\"\n tabIndex={0}\n onMouseDown={preventDefault}\n onClick={handleLinkSubmission}\n />\n </div>\n </>\n )}\n {isLink && !isLinkEditMode && (\n <div className=\"link-view\">\n <a href={sanitizeUrl(linkUrl)} target=\"_blank\" rel=\"noopener noreferrer\">\n {linkUrl}\n </a>\n <div\n className=\"link-edit\"\n role=\"button\"\n tabIndex={0}\n onMouseDown={preventDefault}\n onClick={(event) => {\n event.preventDefault();\n setEditedLinkUrl(linkUrl);\n setIsLinkEditMode(true);\n }}\n />\n <div\n className=\"link-trash\"\n role=\"button\"\n tabIndex={0}\n onMouseDown={preventDefault}\n onClick={() => {\n editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);\n }}\n />\n </div>\n )}\n </div>\n );\n}\n\nfunction useFloatingLinkEditorToolbar(\n editor: LexicalEditor,\n anchorElem: HTMLElement,\n isLinkEditMode: boolean,\n setIsLinkEditMode: Dispatch<boolean>\n): JSX.Element | null {\n const [activeEditor, setActiveEditor] = useState(editor);\n const [isLink, setIsLink] = useState(false);\n\n useEffect(() => {\n function $updateToolbar() {\n const selection = $getSelection();\n if ($isRangeSelection(selection)) {\n const focusNode = getSelectedNode(selection);\n const focusLinkNode = $findMatchingParent(focusNode, $isLinkNode);\n const focusAutoLinkNode = $findMatchingParent(focusNode, $isAutoLinkNode);\n if (!(focusLinkNode || focusAutoLinkNode)) {\n setIsLink(false);\n return;\n }\n const badNode = selection\n .getNodes()\n .filter((node) => !$isLineBreakNode(node))\n .find((node) => {\n const linkNode = $findMatchingParent(node, $isLinkNode);\n const autoLinkNode = $findMatchingParent(node, $isAutoLinkNode);\n return (\n (focusLinkNode && !focusLinkNode.is(linkNode)) ||\n (linkNode && !linkNode.is(focusLinkNode)) ||\n (focusAutoLinkNode && !focusAutoLinkNode.is(autoLinkNode)) ||\n (autoLinkNode &&\n (!autoLinkNode.is(focusAutoLinkNode) || autoLinkNode.getIsUnlinked()))\n );\n });\n if (!badNode) {\n setIsLink(true);\n } else {\n setIsLink(false);\n }\n } else if ($isNodeSelection(selection)) {\n const nodes = selection.getNodes();\n if (nodes.length === 0) {\n setIsLink(false);\n return;\n }\n const node = nodes[0];\n const parent = node.getParent();\n if ($isLinkNode(parent) || $isLinkNode(node)) {\n setIsLink(true);\n } else {\n setIsLink(false);\n }\n }\n }\n return mergeRegister(\n editor.registerUpdateListener(({ editorState }) => {\n editorState.read(() => {\n $updateToolbar();\n });\n }),\n editor.registerCommand(\n SELECTION_CHANGE_COMMAND,\n (_payload, newEditor) => {\n $updateToolbar();\n setActiveEditor(newEditor);\n return false;\n },\n COMMAND_PRIORITY_CRITICAL\n ),\n editor.registerCommand(\n CLICK_COMMAND,\n (payload) => {\n const selection = $getSelection();\n if ($isRangeSelection(selection)) {\n const node = getSelectedNode(selection);\n const linkNode = $findMatchingParent(node, $isLinkNode);\n if ($isLinkNode(linkNode) && (payload.metaKey || payload.ctrlKey)) {\n window.open(linkNode.getURL(), '_blank');\n return true;\n }\n }\n return false;\n },\n COMMAND_PRIORITY_LOW\n )\n );\n }, [editor]);\n\n return createPortal(\n <FloatingLinkEditor\n editor={activeEditor}\n isLink={isLink}\n anchorElem={anchorElem}\n setIsLink={setIsLink}\n isLinkEditMode={isLinkEditMode}\n setIsLinkEditMode={setIsLinkEditMode}\n />,\n anchorElem\n );\n}\n\nexport default function FloatingLinkEditorPlugin({\n anchorElem,\n isLinkEditMode,\n setIsLinkEditMode,\n}: {\n anchorElem?: HTMLElement;\n isLinkEditMode: boolean;\n setIsLinkEditMode: Dispatch<boolean>;\n}): JSX.Element | null {\n const [editor] = useLexicalComposerContext();\n\n // Use document.body as default, but only in browser environment\n const defaultAnchorElem = typeof document !== 'undefined' ? document.body : null;\n const effectiveAnchorElem = anchorElem ?? defaultAnchorElem;\n\n // Don't render if we don't have a valid anchor element\n if (!effectiveAnchorElem) {\n return null;\n }\n\n return useFloatingLinkEditorToolbar(\n editor,\n effectiveAnchorElem,\n isLinkEditMode,\n setIsLinkEditMode\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { EditorState, LexicalEditor } from 'lexical';
|
|
2
|
+
export type HistoryStateEntry = {
|
|
3
|
+
editor: LexicalEditor;
|
|
4
|
+
editorState: EditorState;
|
|
5
|
+
};
|
|
6
|
+
export type HistoryState = {
|
|
7
|
+
current: null | HistoryStateEntry;
|
|
8
|
+
redoStack: Array<HistoryStateEntry>;
|
|
9
|
+
undoStack: Array<HistoryStateEntry>;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Registers necessary listeners to manage undo/redo history stack and related editor commands.
|
|
13
|
+
* It returns `unregister` callback that cleans up all listeners and should be called on editor unmount.
|
|
14
|
+
* @param editor - The lexical editor.
|
|
15
|
+
* @param historyState - The history state, containing the current state and the undo/redo stack.
|
|
16
|
+
* @param delay - The time (in milliseconds) the editor should delay generating a new history stack,
|
|
17
|
+
* instead of merging the current changes with the current stack.
|
|
18
|
+
* @returns The listeners cleanup callback function.
|
|
19
|
+
*/
|
|
20
|
+
export declare function registerHistory(editor: LexicalEditor, historyState: HistoryState, delay: number): () => void;
|
|
21
|
+
/**
|
|
22
|
+
* Creates an empty history state.
|
|
23
|
+
* @returns - The empty history state, as an object.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createEmptyHistoryState(): HistoryState;
|
|
26
|
+
//# sourceMappingURL=HistoryPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HistoryPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/HistoryPlugin.tsx"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAwB,MAAM,SAAS,CAAC;AA0BhF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,aAAa,CAAC;IACtB,WAAW,EAAE,WAAW,CAAC;CAC1B,CAAC;AACF,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,IAAI,GAAG,iBAAiB,CAAC;IAClC,SAAS,EAAE,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACpC,SAAS,EAAE,KAAK,CAAC,iBAAiB,CAAC,CAAC;CACrC,CAAC;AA0UF;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,YAAY,EAC1B,KAAK,EAAE,MAAM,GACZ,MAAM,IAAI,CAqGZ;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,YAAY,CAMtD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LinkPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/LinkPlugin.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAIjC,MAAM,CAAC,OAAO,UAAU,UAAU,IAAI,GAAG,CAAC,OAAO,CAEhD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { validateUrl } from "../utils/url.js";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { LinkPlugin } from "@lexical/react/LexicalLinkPlugin";
|
|
4
|
+
//#region src/plugins/LinkPlugin.tsx
|
|
5
|
+
/**
|
|
6
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
7
|
+
*
|
|
8
|
+
* This source code is licensed under the MIT license found in the
|
|
9
|
+
* LICENSE file in the root directory of this source tree.
|
|
10
|
+
*
|
|
11
|
+
*/
|
|
12
|
+
function LinkPlugin$1() {
|
|
13
|
+
return /* @__PURE__ */ jsx(LinkPlugin, { validateUrl });
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { LinkPlugin$1 as default };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=LinkPlugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LinkPlugin.js","names":[],"sources":["../../src/plugins/LinkPlugin.tsx"],"sourcesContent":["/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { LinkPlugin as LexicalLinkPlugin } from '@lexical/react/LexicalLinkPlugin';\nimport type { JSX } from 'react';\n\nimport { validateUrl } from '../utils/url';\n\nexport default function LinkPlugin(): JSX.Element {\n return <LexicalLinkPlugin validateUrl={validateUrl} />;\n}\n"],"mappings":";;;;;;;;;;;AAaA,SAAwB,eAA0B;CAChD,OAAO,oBAAC,YAAD,EAAgC,YAAc,CAAA;AACvD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { JSX, Dispatch } from 'react';
|
|
2
|
+
import { ScriboToolbarButton } from '../types';
|
|
3
|
+
export default function ToolbarPlugin({ setIsLinkEditMode, toolbarButtons, }: Readonly<{
|
|
4
|
+
setIsLinkEditMode: Dispatch<boolean>;
|
|
5
|
+
toolbarButtons?: ScriboToolbarButton[];
|
|
6
|
+
}>): JSX.Element;
|
|
7
|
+
//# sourceMappingURL=ToolbarPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToolbarPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/ToolbarPlugin.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA4CH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,KAAK,QAAQ,EAAoC,MAAM,OAAO,CAAC;AACxE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAiMpD,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EACpC,iBAAiB,EACjB,cAAmB,GACpB,EAAE,QAAQ,CAAC;IACV,iBAAiB,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IACrC,cAAc,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACxC,CAAC,GAAG,GAAG,CAAC,OAAO,CAqQf"}
|