@seamlet/astro 0.7.0 → 0.8.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/README.md +3 -1
- package/dist/bridge.d.ts +3 -3
- package/dist/bridge.js +324 -12
- package/dist/chunk-27XIZEVS.js +705 -0
- package/dist/{content-DeBXwSmg.d.ts → content-6k-E7NWf.d.ts} +1 -1
- package/dist/{messages-ClePO8N_.d.ts → messages-Dx0jNy3N.d.ts} +76 -4
- package/dist/{parse-content-DqToE6I6.d.ts → parse-content-C9ldnmvj.d.ts} +1 -1
- package/dist/protocol.d.ts +16 -4
- package/dist/protocol.js +25 -3
- package/dist/schema.d.ts +4 -4
- package/dist/site.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-4YLS3VPT.js +0 -160
package/README.md
CHANGED
|
@@ -162,6 +162,8 @@ import RichText from "@seamlet/astro/components/RichText.astro";
|
|
|
162
162
|
</style>
|
|
163
163
|
```
|
|
164
164
|
|
|
165
|
+
When the marked element holds the component alone, the editor types the text right on the page: a person clicks a paragraph and types, marks the selected words bold or italic (⌘B, ⌘I or the toolbar beside the selection) and puts a link on them. The element is then rendered with the same elements the component puts out, so style them from around it, never by classes of your own on them.
|
|
166
|
+
|
|
165
167
|
`plainTextOf` gives its words without marks, for a page title or a description.
|
|
166
168
|
|
|
167
169
|
## Presets
|
|
@@ -216,7 +218,7 @@ What was opened stays open while the page is rendered anew after every edit.
|
|
|
216
218
|
## What the integration adds
|
|
217
219
|
|
|
218
220
|
- `/preview` and `/preview/<page>`: the preview the CMS's editor frames. `GET` shows the published content; `POST` with the content as JSON shows that content without saving it, which is how the editor shows every edit at once. Only the CMS may frame it (`Content-Security-Policy: frame-ancestors`), and it is never indexed or cached.
|
|
219
|
-
- The bridge on the preview: it tells the editor where the marked elements are and what a person does on the page, and types texts in place.
|
|
221
|
+
- The bridge on the preview: it tells the editor where the marked elements are and what a person does on the page, and types texts in place, formatted ones too.
|
|
220
222
|
- `/seamlet-photos/<address>`: the site's own photo at an address its content gives it, found by `photos` of `defineSeamletSite`, for the CMS's editor.
|
|
221
223
|
- `/media/<site>/<file>`: the photos uploaded in the CMS, taken from it on request; a static build copies every uploaded photo its built pages refer to next to them, so a static host serves them too.
|
|
222
224
|
|
package/dist/bridge.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { F as Fields } from './content-
|
|
2
|
-
import { P as PageMessage, E as EditorMessage } from './messages-
|
|
3
|
-
import './parse-content-
|
|
1
|
+
import { F as Fields } from './content-6k-E7NWf.js';
|
|
2
|
+
import { P as PageMessage, E as EditorMessage } from './messages-Dx0jNy3N.js';
|
|
3
|
+
import './parse-content-C9ldnmvj.js';
|
|
4
4
|
|
|
5
5
|
interface BridgeOptions {
|
|
6
6
|
/** The origin of the CMS whose editor may frame the page, such as `https://cms.example.com`. */
|
package/dist/bridge.js
CHANGED
|
@@ -2,17 +2,59 @@ import {
|
|
|
2
2
|
PROTOCOL_VERSION,
|
|
3
3
|
carriesFiles,
|
|
4
4
|
closestMarkedPath,
|
|
5
|
+
formatsAt,
|
|
5
6
|
imageFieldAt,
|
|
7
|
+
insertPlainText,
|
|
8
|
+
isCollapsed,
|
|
9
|
+
linkSelectionAt,
|
|
10
|
+
rangeOf,
|
|
6
11
|
readEditorMessage,
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
readRichTextFrom,
|
|
13
|
+
readSelectionFrom,
|
|
14
|
+
renderInlineRichText,
|
|
15
|
+
renderRichText,
|
|
16
|
+
selectIn,
|
|
17
|
+
setLink,
|
|
18
|
+
shortcutOf,
|
|
19
|
+
toggleList,
|
|
20
|
+
toggleMark
|
|
21
|
+
} from "./chunk-27XIZEVS.js";
|
|
9
22
|
import {
|
|
10
23
|
FIELD_PATH_ATTRIBUTE,
|
|
11
24
|
REVEALED_ATTRIBUTE,
|
|
12
25
|
REVEAL_ATTRIBUTE,
|
|
13
|
-
REVEAL_EVENT
|
|
26
|
+
REVEAL_EVENT,
|
|
27
|
+
asOneParagraph,
|
|
28
|
+
readRichText,
|
|
29
|
+
resolveFieldPath
|
|
14
30
|
} from "./chunk-ZUJEM3P7.js";
|
|
15
31
|
|
|
32
|
+
// src/bridge/typed-fields.ts
|
|
33
|
+
function typedKindAt(schema, path) {
|
|
34
|
+
const target = resolveFieldPath(schema, path);
|
|
35
|
+
if (target?.kind !== "field") return void 0;
|
|
36
|
+
switch (target.field.kind) {
|
|
37
|
+
case "text":
|
|
38
|
+
return "plain";
|
|
39
|
+
case "richText":
|
|
40
|
+
return "rich";
|
|
41
|
+
case "number":
|
|
42
|
+
case "date":
|
|
43
|
+
case "time":
|
|
44
|
+
case "image":
|
|
45
|
+
case "link":
|
|
46
|
+
case "url":
|
|
47
|
+
case "toggle":
|
|
48
|
+
case "choice":
|
|
49
|
+
case "choices":
|
|
50
|
+
case "reference":
|
|
51
|
+
case "references":
|
|
52
|
+
case "group":
|
|
53
|
+
case "collection":
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
16
58
|
// src/bridge/page-markers.ts
|
|
17
59
|
var MARKER_SELECTOR = `[${FIELD_PATH_ATTRIBUTE}]`;
|
|
18
60
|
var HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
|
|
@@ -28,6 +70,10 @@ function linkAround(target) {
|
|
|
28
70
|
const isLink = isHtmlElement(element) && typeof href === "string";
|
|
29
71
|
return isLink ? { element, href } : void 0;
|
|
30
72
|
}
|
|
73
|
+
function isInTypedText(target) {
|
|
74
|
+
const editable = asElement(target)?.closest("[contenteditable]");
|
|
75
|
+
return editable !== null && editable !== void 0;
|
|
76
|
+
}
|
|
31
77
|
function findMarkedElement(document2, path) {
|
|
32
78
|
const element = document2.querySelector(
|
|
33
79
|
`[${FIELD_PATH_ATTRIBUTE}="${CSS.escape(path)}"]`
|
|
@@ -170,7 +216,7 @@ var DRAG_GONE_AFTER_MS = 150;
|
|
|
170
216
|
function listenToPage(document2, listeners) {
|
|
171
217
|
const view = document2.defaultView;
|
|
172
218
|
const hover = (event) => {
|
|
173
|
-
const link =
|
|
219
|
+
const link = linkToFollow(event.target);
|
|
174
220
|
listeners.onHover(
|
|
175
221
|
link === void 0 ? markedElementAround(event.target)?.path : void 0
|
|
176
222
|
);
|
|
@@ -182,7 +228,7 @@ function listenToPage(document2, listeners) {
|
|
|
182
228
|
};
|
|
183
229
|
const click = (event) => {
|
|
184
230
|
event.preventDefault();
|
|
185
|
-
const link =
|
|
231
|
+
const link = linkToFollow(event.target);
|
|
186
232
|
if (link !== void 0) {
|
|
187
233
|
listeners.onLinkClick(link);
|
|
188
234
|
return;
|
|
@@ -256,6 +302,9 @@ function listenToPage(document2, listeners) {
|
|
|
256
302
|
view?.removeEventListener("resize", listeners.onLayoutChange);
|
|
257
303
|
};
|
|
258
304
|
}
|
|
305
|
+
function linkToFollow(target) {
|
|
306
|
+
return isInTypedText(target) ? void 0 : nearerLink(target);
|
|
307
|
+
}
|
|
259
308
|
function nearerLink(target) {
|
|
260
309
|
const link = linkAround(target);
|
|
261
310
|
const marked = markedElementAround(target);
|
|
@@ -326,7 +375,7 @@ function createLayoutReports(document2, report) {
|
|
|
326
375
|
// src/bridge/page-rendering.ts
|
|
327
376
|
function createPageRenderer(options) {
|
|
328
377
|
let request;
|
|
329
|
-
const
|
|
378
|
+
const render2 = (content) => {
|
|
330
379
|
request?.abort();
|
|
331
380
|
const currentRequest = new AbortController();
|
|
332
381
|
request = currentRequest;
|
|
@@ -344,7 +393,7 @@ function createPageRenderer(options) {
|
|
|
344
393
|
});
|
|
345
394
|
};
|
|
346
395
|
return {
|
|
347
|
-
render,
|
|
396
|
+
render: render2,
|
|
348
397
|
stop: () => {
|
|
349
398
|
request?.abort();
|
|
350
399
|
}
|
|
@@ -501,21 +550,239 @@ function caretRangeAt(document2, point) {
|
|
|
501
550
|
return lookup.caretRangeFromPoint?.(point.x, point.y) ?? void 0;
|
|
502
551
|
}
|
|
503
552
|
|
|
553
|
+
// src/bridge/rich-text-editing.ts
|
|
554
|
+
var EDITABLE_AS_RICH_TEXT = "true";
|
|
555
|
+
var PASTED_LINE_BREAKS = /\s*\n\s*/gu;
|
|
556
|
+
var SPACE = " ";
|
|
557
|
+
function canEditRichTextInPlace(element, value, isInline) {
|
|
558
|
+
if (hasMarkedDescendants(element)) return false;
|
|
559
|
+
const normalized = readRichText(value) ?? [];
|
|
560
|
+
const expected = isInline ? asOneParagraph(normalized) : normalized;
|
|
561
|
+
const shown = readTextOf(element, isInline);
|
|
562
|
+
return JSON.stringify(shown) === JSON.stringify(expected);
|
|
563
|
+
}
|
|
564
|
+
function startRichTextEditing(element, options) {
|
|
565
|
+
const document2 = element.ownerDocument;
|
|
566
|
+
const view = document2.defaultView;
|
|
567
|
+
let lastSelection;
|
|
568
|
+
let reportFrame;
|
|
569
|
+
let blurTimer;
|
|
570
|
+
const readText = () => readTextOf(element, options.isInline);
|
|
571
|
+
const liveSelection = () => isSelectionIn(element) ? readSelectionFrom(element) : void 0;
|
|
572
|
+
const reportSelection = () => {
|
|
573
|
+
reportFrame = void 0;
|
|
574
|
+
options.onSelect(measureSelection(element, readText(), lastSelection));
|
|
575
|
+
};
|
|
576
|
+
const scheduleReport = () => {
|
|
577
|
+
if (reportFrame !== void 0) return;
|
|
578
|
+
reportFrame = view?.requestAnimationFrame(reportSelection);
|
|
579
|
+
};
|
|
580
|
+
const followSelection = () => {
|
|
581
|
+
const selection = document2.hasFocus() ? liveSelection() : void 0;
|
|
582
|
+
if (selection === void 0) return;
|
|
583
|
+
lastSelection = selection;
|
|
584
|
+
scheduleReport();
|
|
585
|
+
};
|
|
586
|
+
const reportInput = () => {
|
|
587
|
+
options.onInput(readText());
|
|
588
|
+
followSelection();
|
|
589
|
+
};
|
|
590
|
+
const change = (changed, selection) => {
|
|
591
|
+
render(element, changed, options.isInline);
|
|
592
|
+
lastSelection = selection;
|
|
593
|
+
if (document2.hasFocus()) selectIn(element, selection);
|
|
594
|
+
options.onInput(changed);
|
|
595
|
+
scheduleReport();
|
|
596
|
+
};
|
|
597
|
+
const format = (requested) => {
|
|
598
|
+
const selection = liveSelection() ?? lastSelection;
|
|
599
|
+
const isListInLine = requested === "list" && options.isInline;
|
|
600
|
+
if (selection === void 0 || isListInLine) return;
|
|
601
|
+
const current = readText();
|
|
602
|
+
const changed = requested === "list" ? toggleList(current, selection) : toggleMark(current, selection, requested);
|
|
603
|
+
change(changed, selection);
|
|
604
|
+
};
|
|
605
|
+
const linkTo = (href) => {
|
|
606
|
+
const selection = lastSelection;
|
|
607
|
+
if (selection === void 0) return;
|
|
608
|
+
const current = readText();
|
|
609
|
+
const target = isCollapsed(selection) ? linkSelectionAt(current, selection.start) : selection;
|
|
610
|
+
if (target === void 0) return;
|
|
611
|
+
change(setLink(current, target, href), selection);
|
|
612
|
+
};
|
|
613
|
+
const pressKey = (event) => {
|
|
614
|
+
const isEnd = event.key === "Enter" && options.isInline && !event.shiftKey;
|
|
615
|
+
const shortcut = formatShortcutOf(event);
|
|
616
|
+
if (event.key === "Escape") {
|
|
617
|
+
event.preventDefault();
|
|
618
|
+
end("reverted");
|
|
619
|
+
} else if (isEnd) {
|
|
620
|
+
event.preventDefault();
|
|
621
|
+
end("kept");
|
|
622
|
+
} else if (shortcut !== void 0) {
|
|
623
|
+
event.preventDefault();
|
|
624
|
+
if (shortcut !== "none") format(shortcut);
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
const pastePlainText = (event) => {
|
|
628
|
+
event.preventDefault();
|
|
629
|
+
const pasted = event.clipboardData?.getData("text/plain") ?? "";
|
|
630
|
+
const words = options.isInline ? pasted.replace(PASTED_LINE_BREAKS, SPACE) : pasted;
|
|
631
|
+
insertPlainText(element, words);
|
|
632
|
+
reportInput();
|
|
633
|
+
};
|
|
634
|
+
const refuseDrop = (event) => {
|
|
635
|
+
event.preventDefault();
|
|
636
|
+
};
|
|
637
|
+
const endOnBlur = () => {
|
|
638
|
+
clearTimeout(blurTimer);
|
|
639
|
+
blurTimer = setTimeout(() => {
|
|
640
|
+
const isFocusOnPage = document2.hasFocus();
|
|
641
|
+
const isFocusInText = document2.activeElement === element;
|
|
642
|
+
if (isFocusOnPage && !isFocusInText) end("kept");
|
|
643
|
+
});
|
|
644
|
+
};
|
|
645
|
+
const stopListening = () => {
|
|
646
|
+
clearTimeout(blurTimer);
|
|
647
|
+
if (reportFrame !== void 0) view?.cancelAnimationFrame(reportFrame);
|
|
648
|
+
element.removeEventListener("input", reportInput);
|
|
649
|
+
element.removeEventListener("keydown", pressKey);
|
|
650
|
+
element.removeEventListener("paste", pastePlainText);
|
|
651
|
+
element.removeEventListener("drop", refuseDrop);
|
|
652
|
+
element.removeEventListener("blur", endOnBlur);
|
|
653
|
+
document2.removeEventListener("selectionchange", followSelection);
|
|
654
|
+
document2.removeEventListener("scroll", scheduleReport, true);
|
|
655
|
+
view?.removeEventListener("resize", scheduleReport);
|
|
656
|
+
element.removeAttribute("contenteditable");
|
|
657
|
+
};
|
|
658
|
+
let hasEnded = false;
|
|
659
|
+
const end = (outcome) => {
|
|
660
|
+
if (hasEnded) return;
|
|
661
|
+
hasEnded = true;
|
|
662
|
+
stopListening();
|
|
663
|
+
options.onSelect(void 0);
|
|
664
|
+
options.onEnd(outcome);
|
|
665
|
+
};
|
|
666
|
+
element.setAttribute("contenteditable", EDITABLE_AS_RICH_TEXT);
|
|
667
|
+
element.addEventListener("input", reportInput);
|
|
668
|
+
element.addEventListener("keydown", pressKey);
|
|
669
|
+
element.addEventListener("paste", pastePlainText);
|
|
670
|
+
element.addEventListener("drop", refuseDrop);
|
|
671
|
+
element.addEventListener("blur", endOnBlur);
|
|
672
|
+
document2.addEventListener("selectionchange", followSelection);
|
|
673
|
+
document2.addEventListener("scroll", scheduleReport, true);
|
|
674
|
+
view?.addEventListener("resize", scheduleReport);
|
|
675
|
+
element.focus();
|
|
676
|
+
return {
|
|
677
|
+
format,
|
|
678
|
+
setLink: linkTo,
|
|
679
|
+
stop: () => {
|
|
680
|
+
end("kept");
|
|
681
|
+
}
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
function readTextOf(element, isInline) {
|
|
685
|
+
const read = readRichTextFrom(element);
|
|
686
|
+
return isInline ? asOneParagraph(read) : read;
|
|
687
|
+
}
|
|
688
|
+
function render(element, text, isInline) {
|
|
689
|
+
if (isInline) renderInlineRichText(element, text);
|
|
690
|
+
else renderRichText(element, text);
|
|
691
|
+
}
|
|
692
|
+
function measureSelection(element, text, selection) {
|
|
693
|
+
if (selection === void 0) return void 0;
|
|
694
|
+
const range = isSelectionIn(element) ? element.ownerDocument.getSelection()?.getRangeAt(0) : rangeOf(element, selection);
|
|
695
|
+
const box = (range === void 0 ? void 0 : boxOfRange(range)) ?? boxOf(element);
|
|
696
|
+
if (box === void 0) return void 0;
|
|
697
|
+
return {
|
|
698
|
+
box,
|
|
699
|
+
isCollapsed: isCollapsed(selection),
|
|
700
|
+
formats: formatsAt(text, selection)
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
function boxOfRange(range) {
|
|
704
|
+
const whole = range.getBoundingClientRect();
|
|
705
|
+
const rectangle = whole.width > 0 || whole.height > 0 ? whole : range.getClientRects()[0];
|
|
706
|
+
if (rectangle === void 0) return void 0;
|
|
707
|
+
const isShown = rectangle.width > 0 || rectangle.height > 0;
|
|
708
|
+
if (!isShown) return void 0;
|
|
709
|
+
return {
|
|
710
|
+
top: rectangle.top,
|
|
711
|
+
left: rectangle.left,
|
|
712
|
+
width: rectangle.width,
|
|
713
|
+
height: rectangle.height
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
function isSelectionIn(element) {
|
|
717
|
+
const selection = element.ownerDocument.getSelection();
|
|
718
|
+
const anchor = selection?.anchorNode ?? null;
|
|
719
|
+
const hasRange = (selection?.rangeCount ?? 0) > 0;
|
|
720
|
+
return hasRange && anchor !== null && element.contains(anchor);
|
|
721
|
+
}
|
|
722
|
+
function formatShortcutOf(event) {
|
|
723
|
+
const hasCommandKey = event.metaKey || event.ctrlKey;
|
|
724
|
+
if (!hasCommandKey || event.altKey || event.shiftKey) return void 0;
|
|
725
|
+
switch (event.code) {
|
|
726
|
+
case "KeyB":
|
|
727
|
+
return "bold";
|
|
728
|
+
case "KeyI":
|
|
729
|
+
return "italic";
|
|
730
|
+
case "KeyU":
|
|
731
|
+
return "none";
|
|
732
|
+
default:
|
|
733
|
+
return void 0;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
504
737
|
// src/bridge/page-typing.ts
|
|
738
|
+
var PREPARED_TYPING_TIMEOUT_MS = 3e3;
|
|
739
|
+
var EDITABLE_VALUES = {
|
|
740
|
+
plain: EDITABLE_AS_PLAIN_TEXT,
|
|
741
|
+
rich: EDITABLE_AS_RICH_TEXT
|
|
742
|
+
};
|
|
505
743
|
function createPageTyping(options) {
|
|
506
744
|
let stopEditing;
|
|
745
|
+
let richEditing;
|
|
746
|
+
let prepared;
|
|
747
|
+
const takePrepared = (isTyped) => {
|
|
748
|
+
if (prepared === void 0) return;
|
|
749
|
+
clearTimeout(prepared.timer);
|
|
750
|
+
if (!isTyped && stopEditing === void 0) {
|
|
751
|
+
prepared.element.blur();
|
|
752
|
+
prepared.element.removeAttribute("contenteditable");
|
|
753
|
+
}
|
|
754
|
+
prepared = void 0;
|
|
755
|
+
};
|
|
756
|
+
const prepare = (element, kind) => {
|
|
757
|
+
const isTypedAlready = element.hasAttribute("contenteditable");
|
|
758
|
+
if (isTypedAlready) return;
|
|
759
|
+
takePrepared(false);
|
|
760
|
+
element.setAttribute("contenteditable", EDITABLE_VALUES[kind]);
|
|
761
|
+
element.focus({ preventScroll: true });
|
|
762
|
+
const timer = setTimeout(() => {
|
|
763
|
+
takePrepared(false);
|
|
764
|
+
}, PREPARED_TYPING_TIMEOUT_MS);
|
|
765
|
+
prepared = { element, timer };
|
|
766
|
+
};
|
|
507
767
|
const stop = () => {
|
|
508
768
|
stopEditing?.();
|
|
509
769
|
};
|
|
770
|
+
const ended = (path) => (outcome) => {
|
|
771
|
+
stopEditing = void 0;
|
|
772
|
+
richEditing = void 0;
|
|
773
|
+
options.send({ type: "typing-ended", path, outcome });
|
|
774
|
+
};
|
|
510
775
|
const start = (request) => {
|
|
511
776
|
stop();
|
|
512
777
|
const { path } = request;
|
|
513
778
|
const element = findMarkedElement(options.document, path);
|
|
514
779
|
const canType = element !== void 0 && canEditTextInPlace(element, request.text);
|
|
515
780
|
if (!canType) {
|
|
781
|
+
takePrepared(false);
|
|
516
782
|
options.send({ type: "typing-refused", path });
|
|
517
783
|
return;
|
|
518
784
|
}
|
|
785
|
+
takePrepared(true);
|
|
519
786
|
options.send({ type: "typing-started", path });
|
|
520
787
|
stopEditing = startInlineTextEditing(element, {
|
|
521
788
|
isSingleLine: request.isSingleLine,
|
|
@@ -523,14 +790,46 @@ function createPageTyping(options) {
|
|
|
523
790
|
options.send({ type: "typed", path, text });
|
|
524
791
|
options.onInput();
|
|
525
792
|
},
|
|
526
|
-
onEnd: (
|
|
527
|
-
stopEditing = void 0;
|
|
528
|
-
options.send({ type: "typing-ended", path, outcome });
|
|
529
|
-
}
|
|
793
|
+
onEnd: ended(path)
|
|
530
794
|
});
|
|
531
795
|
placeCaretAt(element, request.point);
|
|
532
796
|
};
|
|
533
|
-
|
|
797
|
+
const startRich = (request) => {
|
|
798
|
+
stop();
|
|
799
|
+
const { path, isInline } = request;
|
|
800
|
+
const element = findMarkedElement(options.document, path);
|
|
801
|
+
const canType = element !== void 0 && canEditRichTextInPlace(element, request.text, isInline);
|
|
802
|
+
if (!canType) {
|
|
803
|
+
takePrepared(false);
|
|
804
|
+
options.send({ type: "typing-refused", path });
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
takePrepared(true);
|
|
808
|
+
options.send({ type: "typing-started", path });
|
|
809
|
+
const editing = startRichTextEditing(element, {
|
|
810
|
+
isInline,
|
|
811
|
+
onInput: (text) => {
|
|
812
|
+
options.send({ type: "rich-typed", path, text });
|
|
813
|
+
options.onInput();
|
|
814
|
+
},
|
|
815
|
+
onSelect: (selection) => {
|
|
816
|
+
options.send({ type: "typed-selection", path, selection });
|
|
817
|
+
},
|
|
818
|
+
onEnd: ended(path)
|
|
819
|
+
});
|
|
820
|
+
richEditing = editing;
|
|
821
|
+
stopEditing = editing.stop;
|
|
822
|
+
placeCaretAt(element, request.point);
|
|
823
|
+
};
|
|
824
|
+
return {
|
|
825
|
+
prepare,
|
|
826
|
+
isTyping: () => stopEditing !== void 0,
|
|
827
|
+
start,
|
|
828
|
+
startRich,
|
|
829
|
+
format: (format) => richEditing?.format(format),
|
|
830
|
+
setLink: (href) => richEditing?.setLink(href),
|
|
831
|
+
stop
|
|
832
|
+
};
|
|
534
833
|
}
|
|
535
834
|
|
|
536
835
|
// src/bridge/connect-to-editor.ts
|
|
@@ -591,6 +890,10 @@ function connectPage(document2, schema, send) {
|
|
|
591
890
|
send({ type: "hover", path });
|
|
592
891
|
},
|
|
593
892
|
onClick: (pointer) => {
|
|
893
|
+
const kind = pointer === void 0 ? void 0 : typedKindAt(schema, pointer.path);
|
|
894
|
+
if (pointer !== void 0 && kind !== void 0) {
|
|
895
|
+
typing.prepare(pointer.element, kind);
|
|
896
|
+
}
|
|
594
897
|
const target = pointer === void 0 ? void 0 : { path: pointer.path, point: pointer.point };
|
|
595
898
|
send({ type: "click", target });
|
|
596
899
|
},
|
|
@@ -624,6 +927,15 @@ function connectPage(document2, schema, send) {
|
|
|
624
927
|
case "start-typing":
|
|
625
928
|
typing.start(message);
|
|
626
929
|
break;
|
|
930
|
+
case "start-rich-typing":
|
|
931
|
+
typing.startRich(message);
|
|
932
|
+
break;
|
|
933
|
+
case "format-typed":
|
|
934
|
+
typing.format(message.format);
|
|
935
|
+
break;
|
|
936
|
+
case "link-typed":
|
|
937
|
+
typing.setLink(message.href);
|
|
938
|
+
break;
|
|
627
939
|
case "stop-typing":
|
|
628
940
|
typing.stop();
|
|
629
941
|
break;
|