@markput/react 0.14.0 → 0.14.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/index.d.ts +448 -443
- package/index.d.ts.map +1 -1
- package/index.js +743 -938
- package/index.js.map +1 -1
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -26,6 +26,12 @@ function merge(...objects) {
|
|
|
26
26
|
return Object.keys(result).length > 0 ? result : void 0;
|
|
27
27
|
}
|
|
28
28
|
//#endregion
|
|
29
|
+
//#region ../../core/src/shared/utils/replaceInString.ts
|
|
30
|
+
function replaceInString(current, range, replacement) {
|
|
31
|
+
if (range.start < 0 || range.end < range.start || range.end > current.length) return void 0;
|
|
32
|
+
return current.slice(0, range.start) + replacement + current.slice(range.end);
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
29
35
|
//#region ../../core/src/shared/constants.ts
|
|
30
36
|
const KEYBOARD = {
|
|
31
37
|
UP: "ArrowUp",
|
|
@@ -54,18 +60,20 @@ const DEFAULT_OPTIONS = [{
|
|
|
54
60
|
//#endregion
|
|
55
61
|
//#region ../../core/src/shared/classes/MarkputHandler.ts
|
|
56
62
|
var MarkputHandler = class {
|
|
57
|
-
constructor(
|
|
58
|
-
this.
|
|
63
|
+
constructor(dom, overlayFeature, parsing) {
|
|
64
|
+
this.dom = dom;
|
|
65
|
+
this.overlayFeature = overlayFeature;
|
|
66
|
+
this.parsing = parsing;
|
|
59
67
|
}
|
|
60
68
|
get container() {
|
|
61
|
-
return this.
|
|
69
|
+
return this.dom.container();
|
|
62
70
|
}
|
|
63
71
|
get overlay() {
|
|
64
|
-
return this.
|
|
72
|
+
return this.overlayFeature.element();
|
|
65
73
|
}
|
|
66
74
|
focus() {
|
|
67
|
-
const firstAddress = this.
|
|
68
|
-
if (firstAddress && this.
|
|
75
|
+
const firstAddress = this.parsing.index().addressFor([0]);
|
|
76
|
+
if (firstAddress && this.dom.focusAddress(firstAddress).ok) return;
|
|
69
77
|
this.container?.focus();
|
|
70
78
|
}
|
|
71
79
|
};
|
|
@@ -482,7 +490,8 @@ function signal(initial, opts) {
|
|
|
482
490
|
};
|
|
483
491
|
return signalOper.bind(node);
|
|
484
492
|
}
|
|
485
|
-
function computed(
|
|
493
|
+
function computed(getterOrOpts, opts) {
|
|
494
|
+
const isWritable = typeof getterOrOpts !== "function";
|
|
486
495
|
const node = {
|
|
487
496
|
value: void 0,
|
|
488
497
|
subs: void 0,
|
|
@@ -490,10 +499,19 @@ function computed(getter, opts) {
|
|
|
490
499
|
deps: void 0,
|
|
491
500
|
depsTail: void 0,
|
|
492
501
|
flags: ReactiveFlags.None,
|
|
493
|
-
getter,
|
|
494
|
-
equalsFn: opts?.equals ?? void 0
|
|
502
|
+
getter: isWritable ? getterOrOpts.get : getterOrOpts,
|
|
503
|
+
equalsFn: (isWritable ? getterOrOpts.equals : opts?.equals) ?? void 0
|
|
495
504
|
};
|
|
496
|
-
|
|
505
|
+
const readFn = computedOper.bind(node);
|
|
506
|
+
if (!isWritable) return readFn;
|
|
507
|
+
const writableComputed = function writableComputedOper(...args) {
|
|
508
|
+
if (args.length === 0) return readFn();
|
|
509
|
+
const next = args[0];
|
|
510
|
+
if (next === void 0) return;
|
|
511
|
+
getterOrOpts.set(next);
|
|
512
|
+
};
|
|
513
|
+
Object.defineProperty(writableComputed, "name", { value: "bound " + computedOper.name });
|
|
514
|
+
return writableComputed;
|
|
497
515
|
}
|
|
498
516
|
function event() {
|
|
499
517
|
const node = {
|
|
@@ -516,7 +534,7 @@ function event() {
|
|
|
516
534
|
callable.read = eventReadOper.bind(node);
|
|
517
535
|
return callable;
|
|
518
536
|
}
|
|
519
|
-
function
|
|
537
|
+
function effect(fn) {
|
|
520
538
|
const e = {
|
|
521
539
|
fn,
|
|
522
540
|
cleanup: void 0,
|
|
@@ -557,7 +575,7 @@ function effectScope(fn) {
|
|
|
557
575
|
function watch(dep, fn) {
|
|
558
576
|
let initialized = false;
|
|
559
577
|
let oldValue;
|
|
560
|
-
return
|
|
578
|
+
return effect(() => {
|
|
561
579
|
const newValue = "read" in dep ? dep.read() : dep();
|
|
562
580
|
if (!initialized) {
|
|
563
581
|
initialized = true;
|
|
@@ -588,8 +606,26 @@ function untracked(fn) {
|
|
|
588
606
|
setActiveSub(prev);
|
|
589
607
|
}
|
|
590
608
|
}
|
|
609
|
+
function model(opts) {
|
|
610
|
+
let internal;
|
|
611
|
+
const ensureInternal = () => {
|
|
612
|
+
if (internal !== void 0) return internal;
|
|
613
|
+
internal = signal(opts.default !== void 0 ? untracked(opts.default) : void 0, { equals: opts.equals });
|
|
614
|
+
return internal;
|
|
615
|
+
};
|
|
616
|
+
const getFn = opts.get ?? ((value) => value);
|
|
617
|
+
const setFn = opts.set ?? ((next, previous) => next ?? previous);
|
|
618
|
+
const reader = computed(() => getFn(ensureInternal()()));
|
|
619
|
+
const callable = function modelOper(...args) {
|
|
620
|
+
if (args.length === 0) return reader();
|
|
621
|
+
const sig = ensureInternal();
|
|
622
|
+
sig(setFn(args[0], sig()));
|
|
623
|
+
};
|
|
624
|
+
Object.defineProperty(callable, "name", { value: "bound " + computedOper.name });
|
|
625
|
+
return callable;
|
|
626
|
+
}
|
|
591
627
|
function listen(target, event, handler, options) {
|
|
592
|
-
return
|
|
628
|
+
return effect(() => {
|
|
593
629
|
target.addEventListener(event, handler, options);
|
|
594
630
|
return () => target.removeEventListener(event, handler, options);
|
|
595
631
|
});
|
|
@@ -1727,20 +1763,6 @@ function findToken(tokens, target, depth = 0, parent) {
|
|
|
1727
1763
|
}
|
|
1728
1764
|
}
|
|
1729
1765
|
//#endregion
|
|
1730
|
-
//#region ../../core/src/features/parsing/utils/valueParser.ts
|
|
1731
|
-
function parseWithParser(store, value) {
|
|
1732
|
-
const parser = store.parsing.parser();
|
|
1733
|
-
if (!parser) return [{
|
|
1734
|
-
type: "text",
|
|
1735
|
-
content: value,
|
|
1736
|
-
position: {
|
|
1737
|
-
start: 0,
|
|
1738
|
-
end: value.length
|
|
1739
|
-
}
|
|
1740
|
-
}];
|
|
1741
|
-
return parser.parse(value);
|
|
1742
|
-
}
|
|
1743
|
-
//#endregion
|
|
1744
1766
|
//#region ../../core/src/features/parsing/tokenIndex.ts
|
|
1745
1767
|
function pathEquals(a, b) {
|
|
1746
1768
|
return a.length === b.length && a.every((part, index) => part === b[index]);
|
|
@@ -1813,24 +1835,41 @@ function createTokenIndex(tokens, generation) {
|
|
|
1813
1835
|
};
|
|
1814
1836
|
}
|
|
1815
1837
|
//#endregion
|
|
1816
|
-
//#region ../../core/src/features/parsing/
|
|
1817
|
-
var
|
|
1838
|
+
//#region ../../core/src/features/parsing/ParseController.ts
|
|
1839
|
+
var ParseController = class {
|
|
1818
1840
|
#generation = signal(0);
|
|
1819
1841
|
#scope;
|
|
1820
|
-
constructor(
|
|
1821
|
-
this.
|
|
1842
|
+
constructor(lifecycle, value, mark, props, slots) {
|
|
1843
|
+
this.lifecycle = lifecycle;
|
|
1844
|
+
this.value = value;
|
|
1845
|
+
this.mark = mark;
|
|
1846
|
+
this.props = props;
|
|
1847
|
+
this.slots = slots;
|
|
1822
1848
|
this.tokens = signal([]);
|
|
1823
1849
|
this.index = computed(() => createTokenIndex(this.tokens(), this.#generation()));
|
|
1824
1850
|
this.parser = computed(() => {
|
|
1825
|
-
if (!this.
|
|
1826
|
-
const markups = this.
|
|
1851
|
+
if (!this.mark.enabled()) return;
|
|
1852
|
+
const markups = this.props.options().map((opt) => opt.markup);
|
|
1827
1853
|
if (!markups.some(Boolean)) return;
|
|
1828
|
-
return new Parser(markups, this.
|
|
1854
|
+
return new Parser(markups, this.slots.isBlock() ? { skipEmptyText: true } : void 0);
|
|
1829
1855
|
});
|
|
1830
1856
|
this.reparse = event();
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1857
|
+
lifecycle.onMounted(() => {
|
|
1858
|
+
this.acceptTokens(this.#parseValue(value.current()));
|
|
1859
|
+
this.#subscribeValue();
|
|
1860
|
+
});
|
|
1861
|
+
const toggle = (enabled) => {
|
|
1862
|
+
if (enabled && !this.#scope) this.#scope = effectScope(() => {
|
|
1863
|
+
this.#subscribeReactiveParse();
|
|
1864
|
+
this.#subscribeReparse();
|
|
1865
|
+
});
|
|
1866
|
+
if (!enabled && this.#scope) {
|
|
1867
|
+
this.#scope();
|
|
1868
|
+
this.#scope = void 0;
|
|
1869
|
+
}
|
|
1870
|
+
};
|
|
1871
|
+
watch(this.mark.enabled, toggle);
|
|
1872
|
+
toggle(this.mark.enabled());
|
|
1834
1873
|
}
|
|
1835
1874
|
acceptTokens(tokens) {
|
|
1836
1875
|
batch(() => {
|
|
@@ -1838,34 +1877,31 @@ var ParsingFeature = class {
|
|
|
1838
1877
|
this.#generation(this.#generation() + 1);
|
|
1839
1878
|
}, { mutable: true });
|
|
1840
1879
|
}
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
disable() {
|
|
1850
|
-
this.#scope?.();
|
|
1851
|
-
this.#scope = void 0;
|
|
1852
|
-
}
|
|
1853
|
-
sync(value = this._store.value.current()) {
|
|
1854
|
-
this.acceptTokens(this.parseValue(value));
|
|
1855
|
-
}
|
|
1856
|
-
#subscribeParse() {
|
|
1857
|
-
watch(this.reparse, () => {
|
|
1858
|
-
if (this._store.caret.recovery()) {
|
|
1859
|
-
const text = toString(this.tokens());
|
|
1860
|
-
this.acceptTokens(this.parseValue(text));
|
|
1861
|
-
return;
|
|
1880
|
+
#parseValue(value) {
|
|
1881
|
+
const parser = this.parser();
|
|
1882
|
+
if (!parser) return [{
|
|
1883
|
+
type: "text",
|
|
1884
|
+
content: value,
|
|
1885
|
+
position: {
|
|
1886
|
+
start: 0,
|
|
1887
|
+
end: value.length
|
|
1862
1888
|
}
|
|
1863
|
-
|
|
1889
|
+
}];
|
|
1890
|
+
return parser.parse(value);
|
|
1891
|
+
}
|
|
1892
|
+
#subscribeValue() {
|
|
1893
|
+
watch(this.value.current, (v) => {
|
|
1894
|
+
this.acceptTokens(this.#parseValue(v));
|
|
1864
1895
|
});
|
|
1865
1896
|
}
|
|
1866
1897
|
#subscribeReactiveParse() {
|
|
1867
1898
|
watch(computed(() => this.parser()), () => {
|
|
1868
|
-
|
|
1899
|
+
this.acceptTokens(this.#parseValue(this.value.current()));
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1902
|
+
#subscribeReparse() {
|
|
1903
|
+
watch(this.reparse, () => {
|
|
1904
|
+
this.acceptTokens(this.#parseValue(this.value.current()));
|
|
1869
1905
|
});
|
|
1870
1906
|
}
|
|
1871
1907
|
};
|
|
@@ -1896,304 +1932,144 @@ function nextText(walker) {
|
|
|
1896
1932
|
return node?.nodeType === 3 ? node : null;
|
|
1897
1933
|
}
|
|
1898
1934
|
//#endregion
|
|
1899
|
-
//#region ../../core/src/features/caret/
|
|
1900
|
-
var
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
} catch {
|
|
1933
|
-
return null;
|
|
1934
|
-
}
|
|
1935
|
-
}
|
|
1936
|
-
/**
|
|
1937
|
-
* Returns true if the caret is on the first visual line of the element.
|
|
1938
|
-
*/
|
|
1939
|
-
static isCaretOnFirstLine(element) {
|
|
1940
|
-
const caretRect = this.getCaretRect();
|
|
1941
|
-
if (!caretRect || caretRect.height === 0) return true;
|
|
1942
|
-
const elRect = element.getBoundingClientRect();
|
|
1943
|
-
return caretRect.top < elRect.top + caretRect.height + 2;
|
|
1944
|
-
}
|
|
1945
|
-
/**
|
|
1946
|
-
* Returns true if the caret is on the last visual line of the element.
|
|
1947
|
-
*/
|
|
1948
|
-
static isCaretOnLastLine(element) {
|
|
1949
|
-
const caretRect = this.getCaretRect();
|
|
1950
|
-
if (!caretRect || caretRect.height === 0) return true;
|
|
1951
|
-
const elRect = element.getBoundingClientRect();
|
|
1952
|
-
return caretRect.bottom > elRect.bottom - caretRect.height - 2;
|
|
1953
|
-
}
|
|
1954
|
-
/**
|
|
1955
|
-
* Positions the caret in `element` at the character closest to the given x coordinate.
|
|
1956
|
-
* `y` defaults to the vertical center of the element.
|
|
1957
|
-
*/
|
|
1958
|
-
static setAtX(element, x, y) {
|
|
1959
|
-
const elRect = element.getBoundingClientRect();
|
|
1960
|
-
const targetY = y ?? elRect.top + elRect.height / 2;
|
|
1961
|
-
const caretDoc = document;
|
|
1962
|
-
const caretPos = caretDoc.caretRangeFromPoint?.(x, targetY) ?? caretDoc.caretPositionFromPoint?.(x, targetY);
|
|
1963
|
-
if (!caretPos) return;
|
|
1964
|
-
const sel = window.getSelection();
|
|
1965
|
-
if (!sel) return;
|
|
1966
|
-
let domRange;
|
|
1967
|
-
if (caretPos instanceof Range) domRange = caretPos;
|
|
1968
|
-
else if ("offsetNode" in caretPos) {
|
|
1969
|
-
domRange = document.createRange();
|
|
1970
|
-
domRange.setStart(caretPos.offsetNode, caretPos.offset);
|
|
1971
|
-
domRange.collapse(true);
|
|
1972
|
-
} else return;
|
|
1973
|
-
if (!element.contains(domRange.startContainer)) {
|
|
1974
|
-
this.setIndex(element, Infinity);
|
|
1975
|
-
return;
|
|
1976
|
-
}
|
|
1977
|
-
sel.removeAllRanges();
|
|
1978
|
-
sel.addRange(domRange);
|
|
1979
|
-
}
|
|
1980
|
-
static trySetIndex(element, offset) {
|
|
1981
|
-
try {
|
|
1982
|
-
this.setIndex(element, offset);
|
|
1983
|
-
} catch (e) {
|
|
1984
|
-
console.error(e);
|
|
1985
|
-
}
|
|
1986
|
-
}
|
|
1987
|
-
/**
|
|
1988
|
-
* Sets the caret at character `offset` within `element` by walking text nodes.
|
|
1989
|
-
* Use Infinity to position at the very end of all text.
|
|
1990
|
-
*/
|
|
1991
|
-
static setIndex(element, offset) {
|
|
1992
|
-
const selection = window.getSelection();
|
|
1993
|
-
if (!selection) return;
|
|
1994
|
-
const walker = document.createTreeWalker(element, 4);
|
|
1995
|
-
let node = nextText(walker);
|
|
1996
|
-
if (!node) return;
|
|
1997
|
-
let remaining = isFinite(offset) ? Math.max(0, offset) : Infinity;
|
|
1998
|
-
for (;;) {
|
|
1999
|
-
const next = nextText(walker);
|
|
2000
|
-
if (!next || remaining <= node.length) {
|
|
2001
|
-
const charOffset = isFinite(remaining) ? Math.min(remaining, node.length) : node.length;
|
|
2002
|
-
const range = document.createRange();
|
|
2003
|
-
range.setStart(node, charOffset);
|
|
2004
|
-
range.collapse(true);
|
|
2005
|
-
selection.removeAllRanges();
|
|
2006
|
-
selection.addRange(range);
|
|
2007
|
-
return;
|
|
2008
|
-
}
|
|
2009
|
-
remaining -= node.length;
|
|
2010
|
-
node = next;
|
|
2011
|
-
}
|
|
2012
|
-
}
|
|
2013
|
-
static getCaretIndex(element) {
|
|
2014
|
-
let position = 0;
|
|
2015
|
-
const selection = window.getSelection();
|
|
2016
|
-
if (!selection?.rangeCount) return position;
|
|
2017
|
-
const range = selection.getRangeAt(0);
|
|
2018
|
-
const preCaretRange = range.cloneRange();
|
|
2019
|
-
preCaretRange.selectNodeContents(element);
|
|
2020
|
-
preCaretRange.setEnd(range.endContainer, range.endOffset);
|
|
2021
|
-
position = preCaretRange.toString().length;
|
|
2022
|
-
return position;
|
|
2023
|
-
}
|
|
2024
|
-
static setCaretToEnd(element) {
|
|
2025
|
-
if (!element) return;
|
|
2026
|
-
this.setIndex(element, Infinity);
|
|
2027
|
-
}
|
|
2028
|
-
static getIndex() {
|
|
2029
|
-
return window.getSelection()?.anchorOffset ?? NaN;
|
|
2030
|
-
}
|
|
2031
|
-
static setIndex1(offset) {
|
|
2032
|
-
const selection = window.getSelection();
|
|
2033
|
-
if (!selection?.anchorNode || !selection.rangeCount) return;
|
|
2034
|
-
const range = selection.getRangeAt(0);
|
|
2035
|
-
range.setStart(range.startContainer.firstChild ?? range.startContainer, offset);
|
|
2036
|
-
range.setEnd(range.startContainer.firstChild ?? range.startContainer, offset);
|
|
1935
|
+
//#region ../../core/src/features/caret/CaretModel.ts
|
|
1936
|
+
var CaretModel = class {
|
|
1937
|
+
constructor(lifecycle, dom, value) {
|
|
1938
|
+
this.lifecycle = lifecycle;
|
|
1939
|
+
this.dom = dom;
|
|
1940
|
+
this.value = value;
|
|
1941
|
+
this.selection = signal(void 0, { equals: shallow });
|
|
1942
|
+
this.position = computed({
|
|
1943
|
+
get: () => this.selection()?.start,
|
|
1944
|
+
set: (value) => this.selection(value !== void 0 ? {
|
|
1945
|
+
start: value,
|
|
1946
|
+
end: value
|
|
1947
|
+
} : void 0)
|
|
1948
|
+
});
|
|
1949
|
+
this.isUserSelecting = signal(false);
|
|
1950
|
+
this.isAllSelected = computed(() => {
|
|
1951
|
+
const s = this.selection();
|
|
1952
|
+
const v = this.value.current();
|
|
1953
|
+
return s?.start === 0 && s.end === v.length && v.length > 0;
|
|
1954
|
+
});
|
|
1955
|
+
lifecycle.onMounted(() => {
|
|
1956
|
+
this.#enableFocusTracking();
|
|
1957
|
+
this.#enableSelectionTracking();
|
|
1958
|
+
watch(dom.indexed, () => {
|
|
1959
|
+
dom.reconcile({ isUserSelecting: this.isUserSelecting() });
|
|
1960
|
+
this.#applyRangeToDOM();
|
|
1961
|
+
});
|
|
1962
|
+
effect(() => {
|
|
1963
|
+
const isUserSelecting = this.isUserSelecting();
|
|
1964
|
+
dom.readOnly();
|
|
1965
|
+
dom.reconcile({ isUserSelecting });
|
|
1966
|
+
});
|
|
1967
|
+
});
|
|
2037
1968
|
}
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
1969
|
+
selectAll() {
|
|
1970
|
+
this.selection({
|
|
1971
|
+
start: 0,
|
|
1972
|
+
end: this.value.current().length
|
|
1973
|
+
});
|
|
1974
|
+
this.#applyRangeToDOM();
|
|
2042
1975
|
}
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
function enableFocus(store) {
|
|
2047
|
-
const container = store.dom.container();
|
|
2048
|
-
if (!container) return () => {};
|
|
2049
|
-
const scope = effectScope(() => {
|
|
1976
|
+
#enableFocusTracking() {
|
|
1977
|
+
const container = this.dom.container();
|
|
1978
|
+
if (!container) return;
|
|
2050
1979
|
listen(container, "focusin", (e) => {
|
|
2051
|
-
const target =
|
|
1980
|
+
const target = e.target instanceof HTMLElement ? e.target : void 0;
|
|
2052
1981
|
if (!target) {
|
|
2053
|
-
|
|
1982
|
+
this.selection(void 0);
|
|
2054
1983
|
return;
|
|
2055
1984
|
}
|
|
2056
|
-
const result =
|
|
1985
|
+
const result = this.dom.locateNode(target);
|
|
2057
1986
|
if (!result.ok) {
|
|
2058
1987
|
if (result.reason === "control") return;
|
|
2059
|
-
|
|
1988
|
+
this.selection(void 0);
|
|
2060
1989
|
return;
|
|
2061
1990
|
}
|
|
2062
|
-
const
|
|
2063
|
-
|
|
2064
|
-
address: result.value.address,
|
|
2065
|
-
role
|
|
2066
|
-
});
|
|
1991
|
+
const rawSel = this.dom.readRawSelection();
|
|
1992
|
+
if (rawSel.ok) this.selection(rawSel.value.range);
|
|
2067
1993
|
});
|
|
2068
1994
|
listen(container, "focusout", () => {
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
const tokens = store.parsing.tokens();
|
|
2073
|
-
if (tokens.length === 1 && tokens[0].type === "text" && tokens[0].content === "") {
|
|
2074
|
-
const container = store.dom.container();
|
|
2075
|
-
(container ? firstHtmlChild(container) : null)?.focus();
|
|
2076
|
-
}
|
|
1995
|
+
queueMicrotask(() => {
|
|
1996
|
+
if (!container.contains(document.activeElement)) this.selection(void 0);
|
|
1997
|
+
});
|
|
2077
1998
|
});
|
|
2078
|
-
}
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
//#endregion
|
|
2082
|
-
//#region ../../core/src/features/caret/selection.ts
|
|
2083
|
-
function enableSelection(store) {
|
|
2084
|
-
let pressedNode = null;
|
|
2085
|
-
let isPressed = false;
|
|
2086
|
-
const scope = effectScope(() => {
|
|
1999
|
+
}
|
|
2000
|
+
#enableSelectionTracking() {
|
|
2001
|
+
let pressedAt = null;
|
|
2087
2002
|
listen(document, "mousedown", (e) => {
|
|
2088
|
-
|
|
2089
|
-
isPressed = true;
|
|
2003
|
+
pressedAt = nodeTarget(e);
|
|
2090
2004
|
});
|
|
2091
2005
|
listen(document, "mousemove", (e) => {
|
|
2092
|
-
|
|
2006
|
+
if (pressedAt === null) return;
|
|
2007
|
+
const container = this.dom.container();
|
|
2093
2008
|
if (!container) return;
|
|
2094
|
-
const
|
|
2095
|
-
const
|
|
2096
|
-
const
|
|
2097
|
-
if (
|
|
2098
|
-
if (store.caret.selecting() !== "drag") store.caret.selecting("drag");
|
|
2099
|
-
}
|
|
2009
|
+
const startedOutsideEditor = !container.contains(pressedAt);
|
|
2010
|
+
const sweepingAcrossNodes = pressedAt !== e.target;
|
|
2011
|
+
const selectionIntersectsEditor = window.getSelection()?.containsNode(container, true) ?? false;
|
|
2012
|
+
if ((startedOutsideEditor || sweepingAcrossNodes) && selectionIntersectsEditor) this.isUserSelecting(true);
|
|
2100
2013
|
});
|
|
2101
2014
|
listen(document, "mouseup", () => {
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
if (!sel || sel.isCollapsed) store.caret.selecting(void 0);
|
|
2107
|
-
}
|
|
2015
|
+
pressedAt = null;
|
|
2016
|
+
if (!this.isUserSelecting()) return;
|
|
2017
|
+
const sel = window.getSelection();
|
|
2018
|
+
if (!sel || sel.isCollapsed) this.isUserSelecting(false);
|
|
2108
2019
|
});
|
|
2109
2020
|
listen(document, "selectionchange", () => {
|
|
2110
2021
|
const sel = window.getSelection();
|
|
2111
|
-
if (
|
|
2022
|
+
if (this.isUserSelecting() && (!sel || sel.isCollapsed)) this.isUserSelecting(false);
|
|
2112
2023
|
if (!sel?.focusNode) return;
|
|
2113
|
-
const result =
|
|
2024
|
+
const result = this.dom.locateNode(sel.focusNode);
|
|
2114
2025
|
if (!result.ok) {
|
|
2115
2026
|
if (result.reason === "control") return;
|
|
2116
|
-
|
|
2027
|
+
this.selection(void 0);
|
|
2117
2028
|
return;
|
|
2118
2029
|
}
|
|
2119
|
-
const
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
role
|
|
2123
|
-
});
|
|
2124
|
-
});
|
|
2125
|
-
alienEffect(() => {
|
|
2126
|
-
if (store.caret.selecting() === "drag") store.dom.reconcile();
|
|
2030
|
+
const rawSel = this.dom.readRawSelection();
|
|
2031
|
+
if (rawSel.ok) this.selection(rawSel.value.range);
|
|
2032
|
+
else this.selection(void 0);
|
|
2127
2033
|
});
|
|
2128
|
-
});
|
|
2129
|
-
return () => {
|
|
2130
|
-
if (store.caret.selecting() === "drag") store.caret.selecting(void 0);
|
|
2131
|
-
scope();
|
|
2132
|
-
pressedNode = null;
|
|
2133
|
-
isPressed = false;
|
|
2134
|
-
};
|
|
2135
|
-
}
|
|
2136
|
-
//#endregion
|
|
2137
|
-
//#region ../../core/src/features/caret/CaretFeature.ts
|
|
2138
|
-
var CaretFeature = class {
|
|
2139
|
-
#disposers = [];
|
|
2140
|
-
constructor(_store) {
|
|
2141
|
-
this._store = _store;
|
|
2142
|
-
this.recovery = signal(void 0);
|
|
2143
|
-
this.location = signal(void 0);
|
|
2144
|
-
this.selecting = signal(void 0);
|
|
2145
|
-
}
|
|
2146
|
-
enable() {
|
|
2147
|
-
if (this.#disposers.length) return;
|
|
2148
|
-
this.#disposers = [enableFocus(this._store), enableSelection(this._store)];
|
|
2149
|
-
}
|
|
2150
|
-
disable() {
|
|
2151
|
-
this.#disposers.forEach((d) => d());
|
|
2152
|
-
this.#disposers = [];
|
|
2153
2034
|
}
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2035
|
+
#applyRangeToDOM() {
|
|
2036
|
+
if (this.isUserSelecting()) return;
|
|
2037
|
+
const sel = this.selection();
|
|
2038
|
+
if (sel === void 0) return;
|
|
2039
|
+
if (sel.start === sel.end) {
|
|
2040
|
+
const result = this.dom.placeAt(sel.start);
|
|
2041
|
+
if (!result.ok) {
|
|
2042
|
+
this.selection(void 0);
|
|
2043
|
+
return;
|
|
2044
|
+
}
|
|
2045
|
+
const applied = result.value.applied;
|
|
2046
|
+
if (applied !== sel.start) this.selection({
|
|
2047
|
+
start: applied,
|
|
2048
|
+
end: applied
|
|
2049
|
+
});
|
|
2050
|
+
return;
|
|
2051
|
+
}
|
|
2052
|
+
const result = this.dom.placeRange(sel);
|
|
2053
|
+
if (!result.ok) {
|
|
2054
|
+
this.selection(void 0);
|
|
2055
|
+
return;
|
|
2056
|
+
}
|
|
2057
|
+
this.selection(result.value.applied);
|
|
2159
2058
|
}
|
|
2160
2059
|
};
|
|
2161
2060
|
//#endregion
|
|
2162
|
-
//#region ../../core/src/features/caret/selectionHelpers.ts
|
|
2163
|
-
function isFullSelection(store) {
|
|
2164
|
-
const sel = window.getSelection();
|
|
2165
|
-
const container = store.dom.container();
|
|
2166
|
-
if (!sel?.rangeCount || !container?.firstChild || !container.lastChild) return false;
|
|
2167
|
-
try {
|
|
2168
|
-
const range = sel.getRangeAt(0);
|
|
2169
|
-
return container.contains(range.startContainer) && container.contains(range.endContainer) && range.toString().length > 0;
|
|
2170
|
-
} catch {
|
|
2171
|
-
return false;
|
|
2172
|
-
}
|
|
2173
|
-
}
|
|
2174
|
-
function selectAllText(store, event) {
|
|
2175
|
-
if ((event.ctrlKey || event.metaKey) && event.code === "KeyA") {
|
|
2176
|
-
if (store.slots.isBlock()) return;
|
|
2177
|
-
event.preventDefault();
|
|
2178
|
-
const selection = window.getSelection();
|
|
2179
|
-
const anchorNode = store.dom.container()?.firstChild;
|
|
2180
|
-
const focusNode = store.dom.container()?.lastChild;
|
|
2181
|
-
if (!selection || !anchorNode || !focusNode) return;
|
|
2182
|
-
selection.setBaseAndExtent(anchorNode, 0, focusNode, 1);
|
|
2183
|
-
store.caret.selecting("all");
|
|
2184
|
-
}
|
|
2185
|
-
}
|
|
2186
|
-
//#endregion
|
|
2187
2061
|
//#region ../../core/src/features/caret/TriggerFinder.ts
|
|
2188
2062
|
/** Regex to match word characters from the start of a string */
|
|
2189
2063
|
const wordRegex = /* @__PURE__ */ new RegExp(/^\w*/);
|
|
2190
2064
|
var TriggerFinder = class TriggerFinder {
|
|
2191
|
-
constructor(
|
|
2192
|
-
this.
|
|
2193
|
-
const
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
this.
|
|
2065
|
+
constructor(dom) {
|
|
2066
|
+
this.dom = dom;
|
|
2067
|
+
const sel = window.getSelection();
|
|
2068
|
+
const node = sel?.anchorNode;
|
|
2069
|
+
if (!sel || !node || !document.contains(node)) throw new Error("Anchor node of selection is not exists!");
|
|
2070
|
+
this.node = node;
|
|
2071
|
+
this.span = node.textContent ?? "";
|
|
2072
|
+
this.dividedText = this.getDividedTextBy(sel.anchorOffset);
|
|
2197
2073
|
}
|
|
2198
2074
|
/**
|
|
2199
2075
|
* Find overlay match in text using provided options and trigger extractor.
|
|
@@ -2210,11 +2086,11 @@ var TriggerFinder = class TriggerFinder {
|
|
|
2210
2086
|
* // Other framework usage
|
|
2211
2087
|
* TriggerFinder.find(vueOptions, (opt) => opt.overlay?.trigger ?? '@')
|
|
2212
2088
|
*/
|
|
2213
|
-
static find(options, getTrigger,
|
|
2089
|
+
static find(options, getTrigger, dom) {
|
|
2214
2090
|
if (!options) return;
|
|
2215
|
-
if (!
|
|
2091
|
+
if (!window.getSelection()?.isCollapsed) return;
|
|
2216
2092
|
try {
|
|
2217
|
-
return new TriggerFinder(
|
|
2093
|
+
return new TriggerFinder(dom).find(options, getTrigger);
|
|
2218
2094
|
} catch {
|
|
2219
2095
|
return;
|
|
2220
2096
|
}
|
|
@@ -2252,11 +2128,11 @@ var TriggerFinder = class TriggerFinder {
|
|
|
2252
2128
|
}
|
|
2253
2129
|
}
|
|
2254
2130
|
#rawRangeForMatch(source, index) {
|
|
2255
|
-
if (!this.
|
|
2131
|
+
if (!this.dom) return {
|
|
2256
2132
|
start: index,
|
|
2257
2133
|
end: index + source.length
|
|
2258
2134
|
};
|
|
2259
|
-
const boundary = this.
|
|
2135
|
+
const boundary = this.dom.rawPositionFromBoundary(this.node, index + source.length, "after");
|
|
2260
2136
|
if (!boundary.ok) return void 0;
|
|
2261
2137
|
return {
|
|
2262
2138
|
start: boundary.value - source.length,
|
|
@@ -2294,6 +2170,86 @@ var TriggerFinder = class TriggerFinder {
|
|
|
2294
2170
|
}
|
|
2295
2171
|
};
|
|
2296
2172
|
//#endregion
|
|
2173
|
+
//#region ../../core/src/features/caret/caretDom.ts
|
|
2174
|
+
function getCaretIndex(element) {
|
|
2175
|
+
let position = 0;
|
|
2176
|
+
const selection = window.getSelection();
|
|
2177
|
+
if (!selection?.rangeCount) return position;
|
|
2178
|
+
const range = selection.getRangeAt(0);
|
|
2179
|
+
const preCaretRange = range.cloneRange();
|
|
2180
|
+
preCaretRange.selectNodeContents(element);
|
|
2181
|
+
preCaretRange.setEnd(range.endContainer, range.endOffset);
|
|
2182
|
+
position = preCaretRange.toString().length;
|
|
2183
|
+
return position;
|
|
2184
|
+
}
|
|
2185
|
+
function getRect() {
|
|
2186
|
+
try {
|
|
2187
|
+
return (window.getSelection()?.getRangeAt(0))?.getBoundingClientRect() ?? null;
|
|
2188
|
+
} catch {
|
|
2189
|
+
return null;
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
function isOnFirstLine(element) {
|
|
2193
|
+
const caretRect = getRect();
|
|
2194
|
+
if (!caretRect || caretRect.height === 0) return true;
|
|
2195
|
+
const elRect = element.getBoundingClientRect();
|
|
2196
|
+
return caretRect.top < elRect.top + caretRect.height + 2;
|
|
2197
|
+
}
|
|
2198
|
+
function isOnLastLine(element) {
|
|
2199
|
+
const caretRect = getRect();
|
|
2200
|
+
if (!caretRect || caretRect.height === 0) return true;
|
|
2201
|
+
const elRect = element.getBoundingClientRect();
|
|
2202
|
+
return caretRect.bottom > elRect.bottom - caretRect.height - 2;
|
|
2203
|
+
}
|
|
2204
|
+
function setAtElement(element, offset) {
|
|
2205
|
+
try {
|
|
2206
|
+
const selection = window.getSelection();
|
|
2207
|
+
if (!selection) return;
|
|
2208
|
+
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
|
|
2209
|
+
let node = nextText(walker);
|
|
2210
|
+
if (!node) return;
|
|
2211
|
+
let remaining = isFinite(offset) ? Math.max(0, offset) : Infinity;
|
|
2212
|
+
for (;;) {
|
|
2213
|
+
const next = nextText(walker);
|
|
2214
|
+
if (!next || remaining <= node.length) {
|
|
2215
|
+
const charOffset = isFinite(remaining) ? Math.min(remaining, node.length) : node.length;
|
|
2216
|
+
const range = document.createRange();
|
|
2217
|
+
range.setStart(node, charOffset);
|
|
2218
|
+
range.collapse(true);
|
|
2219
|
+
selection.removeAllRanges();
|
|
2220
|
+
selection.addRange(range);
|
|
2221
|
+
return;
|
|
2222
|
+
}
|
|
2223
|
+
remaining -= node.length;
|
|
2224
|
+
node = next;
|
|
2225
|
+
}
|
|
2226
|
+
} catch (e) {
|
|
2227
|
+
console.error(e);
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
function setAtX(element, x, y) {
|
|
2231
|
+
const elRect = element.getBoundingClientRect();
|
|
2232
|
+
const targetY = y ?? elRect.top + elRect.height / 2;
|
|
2233
|
+
const caretDoc = document;
|
|
2234
|
+
const caretPos = caretDoc.caretRangeFromPoint?.(x, targetY) ?? caretDoc.caretPositionFromPoint?.(x, targetY);
|
|
2235
|
+
if (!caretPos) return;
|
|
2236
|
+
const sel = window.getSelection();
|
|
2237
|
+
if (!sel) return;
|
|
2238
|
+
let domRange;
|
|
2239
|
+
if (caretPos instanceof Range) domRange = caretPos;
|
|
2240
|
+
else if ("offsetNode" in caretPos) {
|
|
2241
|
+
domRange = document.createRange();
|
|
2242
|
+
domRange.setStart(caretPos.offsetNode, caretPos.offset);
|
|
2243
|
+
domRange.collapse(true);
|
|
2244
|
+
} else return;
|
|
2245
|
+
if (!element.contains(domRange.startContainer)) {
|
|
2246
|
+
setAtElement(element, Infinity);
|
|
2247
|
+
return;
|
|
2248
|
+
}
|
|
2249
|
+
sel.removeAllRanges();
|
|
2250
|
+
sel.addRange(domRange);
|
|
2251
|
+
}
|
|
2252
|
+
//#endregion
|
|
2297
2253
|
//#region ../../core/src/features/clipboard/pasteMarkup.ts
|
|
2298
2254
|
/** Custom MIME type for markput markup syntax. */
|
|
2299
2255
|
const MARKPUT_MIME = "application/x-markput";
|
|
@@ -2321,7 +2277,7 @@ function consumeMarkupPaste(container) {
|
|
|
2321
2277
|
return markup;
|
|
2322
2278
|
}
|
|
2323
2279
|
//#endregion
|
|
2324
|
-
//#region ../../core/src/features/clipboard/
|
|
2280
|
+
//#region ../../core/src/features/clipboard/ClipboardController.ts
|
|
2325
2281
|
function htmlFromRange(range) {
|
|
2326
2282
|
const fragment = range.cloneContents();
|
|
2327
2283
|
const div = document.createElement("div");
|
|
@@ -2342,47 +2298,36 @@ function trimTokensForRawRange(tokens, range) {
|
|
|
2342
2298
|
return Object.assign({}, token, { children: trimTokensForRawRange(token.children, range) });
|
|
2343
2299
|
});
|
|
2344
2300
|
}
|
|
2345
|
-
var
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
this.
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
this.#scope = effectScope(() => {
|
|
2301
|
+
var ClipboardController = class {
|
|
2302
|
+
constructor(lifecycle, edit, dom, parsing) {
|
|
2303
|
+
this.lifecycle = lifecycle;
|
|
2304
|
+
this.edit = edit;
|
|
2305
|
+
this.dom = dom;
|
|
2306
|
+
this.parsing = parsing;
|
|
2307
|
+
lifecycle.onMounted(() => {
|
|
2308
|
+
const container = dom.container();
|
|
2309
|
+
if (!container) return;
|
|
2355
2310
|
listen(container, "copy", (e) => {
|
|
2356
2311
|
this.#handleCopy(e);
|
|
2357
2312
|
});
|
|
2358
2313
|
listen(container, "cut", (e) => {
|
|
2359
2314
|
if (!this.#handleCopy(e)) return;
|
|
2360
|
-
const raw =
|
|
2315
|
+
const raw = dom.readRawSelection();
|
|
2361
2316
|
if (!raw.ok || raw.value.range.start === raw.value.range.end) return;
|
|
2362
|
-
|
|
2363
|
-
source: "cut",
|
|
2364
|
-
recover: {
|
|
2365
|
-
kind: "caret",
|
|
2366
|
-
rawPosition: raw.value.range.start
|
|
2367
|
-
}
|
|
2368
|
-
});
|
|
2317
|
+
edit.replace(raw.value.range, "");
|
|
2369
2318
|
});
|
|
2370
2319
|
});
|
|
2371
2320
|
}
|
|
2372
|
-
disable() {
|
|
2373
|
-
this.#scope?.();
|
|
2374
|
-
this.#scope = void 0;
|
|
2375
|
-
}
|
|
2376
2321
|
#handleCopy(e) {
|
|
2377
|
-
if (!this.
|
|
2378
|
-
const raw = this.
|
|
2322
|
+
if (!this.dom.container()) return false;
|
|
2323
|
+
const raw = this.dom.readRawSelection();
|
|
2379
2324
|
if (!raw.ok || raw.value.range.start === raw.value.range.end) return false;
|
|
2380
2325
|
const sel = window.getSelection();
|
|
2381
2326
|
const range = sel?.rangeCount ? sel.getRangeAt(0) : void 0;
|
|
2382
2327
|
if (!range) return false;
|
|
2383
2328
|
const plainText = range.toString();
|
|
2384
2329
|
const html = htmlFromRange(range);
|
|
2385
|
-
const markup = serializeRawRange(this.
|
|
2330
|
+
const markup = serializeRawRange(this.parsing.tokens(), raw.value.range);
|
|
2386
2331
|
e.preventDefault();
|
|
2387
2332
|
e.clipboardData?.setData("text/plain", plainText);
|
|
2388
2333
|
e.clipboardData?.setData("text/html", html);
|
|
@@ -2391,7 +2336,7 @@ var ClipboardFeature = class {
|
|
|
2391
2336
|
}
|
|
2392
2337
|
};
|
|
2393
2338
|
//#endregion
|
|
2394
|
-
//#region ../../core/src/features/dom/
|
|
2339
|
+
//#region ../../core/src/features/dom/DomController.ts
|
|
2395
2340
|
function nextTextNode(walker) {
|
|
2396
2341
|
const node = walker.nextNode();
|
|
2397
2342
|
return node instanceof Text ? node : null;
|
|
@@ -2451,7 +2396,7 @@ function hasEditableAncestorBefore(node, boundary) {
|
|
|
2451
2396
|
}
|
|
2452
2397
|
return false;
|
|
2453
2398
|
}
|
|
2454
|
-
var
|
|
2399
|
+
var DomController = class {
|
|
2455
2400
|
#domIndex = signal(void 0, { readonly: true });
|
|
2456
2401
|
#pendingControls = /* @__PURE__ */ new Map();
|
|
2457
2402
|
#pendingChildSequences = /* @__PURE__ */ new Map();
|
|
@@ -2463,29 +2408,31 @@ var DomFeature = class {
|
|
|
2463
2408
|
#rendering = false;
|
|
2464
2409
|
#isComposing = false;
|
|
2465
2410
|
#queuedRender = false;
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
this.
|
|
2411
|
+
constructor(lifecycle, props, parsing, value) {
|
|
2412
|
+
this.lifecycle = lifecycle;
|
|
2413
|
+
this.props = props;
|
|
2414
|
+
this.parsing = parsing;
|
|
2415
|
+
this.value = value;
|
|
2469
2416
|
this.index = computed(() => this.#domIndex());
|
|
2470
2417
|
this.container = signal(null);
|
|
2471
2418
|
this.diagnostics = event();
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2419
|
+
this.indexed = event();
|
|
2420
|
+
this.readOnly = computed(() => this.props.readOnly());
|
|
2421
|
+
lifecycle.onMounted(() => {
|
|
2422
|
+
const container = this.container();
|
|
2423
|
+
if (container) listen(container, "click", () => {
|
|
2424
|
+
const tokens = this.parsing.tokens();
|
|
2425
|
+
if (tokens.length === 1 && tokens[0].type === "text" && tokens[0].content === "") {
|
|
2426
|
+
const c = this.container();
|
|
2427
|
+
(c ? firstHtmlChild(c) : null)?.focus();
|
|
2428
|
+
}
|
|
2429
|
+
});
|
|
2430
|
+
watch(lifecycle.rendered, () => {
|
|
2477
2431
|
this.#handleRendered();
|
|
2478
2432
|
});
|
|
2479
|
-
watch(computed(() => (
|
|
2480
|
-
readOnly: this._store.props.readOnly(),
|
|
2481
|
-
selecting: this._store.caret.selecting()
|
|
2482
|
-
})), () => this.reconcile());
|
|
2433
|
+
watch(computed(() => props.readOnly()), () => this.reconcile());
|
|
2483
2434
|
});
|
|
2484
2435
|
}
|
|
2485
|
-
disable() {
|
|
2486
|
-
this.#scope?.();
|
|
2487
|
-
this.#scope = void 0;
|
|
2488
|
-
}
|
|
2489
2436
|
compositionStarted() {
|
|
2490
2437
|
this.#isComposing = true;
|
|
2491
2438
|
}
|
|
@@ -2515,8 +2462,8 @@ var DomFeature = class {
|
|
|
2515
2462
|
};
|
|
2516
2463
|
return callback;
|
|
2517
2464
|
}
|
|
2518
|
-
reconcile() {
|
|
2519
|
-
this.#reconcileStructuralTextSurfaces();
|
|
2465
|
+
reconcile(opts) {
|
|
2466
|
+
this.#reconcileStructuralTextSurfaces(opts?.isUserSelecting);
|
|
2520
2467
|
}
|
|
2521
2468
|
locateNode(node) {
|
|
2522
2469
|
if (!this.index()) return {
|
|
@@ -2561,18 +2508,43 @@ var DomFeature = class {
|
|
|
2561
2508
|
reason: "outsideEditor"
|
|
2562
2509
|
};
|
|
2563
2510
|
}
|
|
2564
|
-
|
|
2511
|
+
placeAt(rawPosition, affinity = "after") {
|
|
2565
2512
|
if (!this.index()) return {
|
|
2566
2513
|
ok: false,
|
|
2567
2514
|
reason: "notIndexed"
|
|
2568
2515
|
};
|
|
2569
|
-
const
|
|
2570
|
-
|
|
2516
|
+
const maxPos = this.value.current().length;
|
|
2517
|
+
const clamped = Math.min(rawPosition, maxPos);
|
|
2518
|
+
const target = this.#findTextTargetForRawPosition(clamped, affinity);
|
|
2519
|
+
if (!target) {
|
|
2520
|
+
const boundary = this.#focusMarkBoundaryForRawPosition(clamped);
|
|
2521
|
+
if (!boundary.ok) return boundary;
|
|
2522
|
+
return {
|
|
2523
|
+
ok: true,
|
|
2524
|
+
value: { applied: clamped }
|
|
2525
|
+
};
|
|
2526
|
+
}
|
|
2571
2527
|
target.element.focus();
|
|
2572
|
-
this.#placeCaretInTextSurface(target.element,
|
|
2528
|
+
this.#placeCaretInTextSurface(target.element, clamped - target.start);
|
|
2573
2529
|
return {
|
|
2574
2530
|
ok: true,
|
|
2575
|
-
value:
|
|
2531
|
+
value: { applied: clamped }
|
|
2532
|
+
};
|
|
2533
|
+
}
|
|
2534
|
+
placeRange(range) {
|
|
2535
|
+
const maxPos = this.value.current().length;
|
|
2536
|
+
const clamped = {
|
|
2537
|
+
start: Math.min(range.start, maxPos),
|
|
2538
|
+
end: Math.min(range.end, maxPos)
|
|
2539
|
+
};
|
|
2540
|
+
const result = this.#placeSelection({
|
|
2541
|
+
range: clamped,
|
|
2542
|
+
direction: void 0
|
|
2543
|
+
});
|
|
2544
|
+
if (!result.ok) return result;
|
|
2545
|
+
return {
|
|
2546
|
+
ok: true,
|
|
2547
|
+
value: { applied: clamped }
|
|
2576
2548
|
};
|
|
2577
2549
|
}
|
|
2578
2550
|
focusAddress(address, boundary = "start") {
|
|
@@ -2580,7 +2552,7 @@ var DomFeature = class {
|
|
|
2580
2552
|
ok: false,
|
|
2581
2553
|
reason: "notIndexed"
|
|
2582
2554
|
};
|
|
2583
|
-
if (!this.
|
|
2555
|
+
if (!this.parsing.index().resolveAddress(address).ok) return {
|
|
2584
2556
|
ok: false,
|
|
2585
2557
|
reason: "stale"
|
|
2586
2558
|
};
|
|
@@ -2591,12 +2563,7 @@ var DomFeature = class {
|
|
|
2591
2563
|
reason: "notIndexed"
|
|
2592
2564
|
};
|
|
2593
2565
|
target.focus();
|
|
2594
|
-
|
|
2595
|
-
if (role === "markDescendant") this.#placeCollapsedBoundary(target, boundary === "end" ? target.childNodes.length : 0);
|
|
2596
|
-
this._store.caret.location({
|
|
2597
|
-
address,
|
|
2598
|
-
role
|
|
2599
|
-
});
|
|
2566
|
+
if ((target === elements?.textElement ? "text" : target === elements?.rowElement ? "row" : "markDescendant") === "markDescendant") this.#placeCollapsedBoundary(target, boundary === "end" ? target.childNodes.length : 0);
|
|
2600
2567
|
return {
|
|
2601
2568
|
ok: true,
|
|
2602
2569
|
value: void 0
|
|
@@ -2618,7 +2585,7 @@ var DomFeature = class {
|
|
|
2618
2585
|
ok: false,
|
|
2619
2586
|
reason: "control"
|
|
2620
2587
|
} : location;
|
|
2621
|
-
const token = this.
|
|
2588
|
+
const token = this.parsing.index().resolveAddress(location.value.address);
|
|
2622
2589
|
if (!token.ok) return {
|
|
2623
2590
|
ok: false,
|
|
2624
2591
|
reason: "notIndexed"
|
|
@@ -2751,7 +2718,7 @@ var DomFeature = class {
|
|
|
2751
2718
|
});
|
|
2752
2719
|
return;
|
|
2753
2720
|
}
|
|
2754
|
-
const tokenIndex = this.
|
|
2721
|
+
const tokenIndex = this.parsing.index();
|
|
2755
2722
|
const pathElements = /* @__PURE__ */ new Map();
|
|
2756
2723
|
const elementRoles = /* @__PURE__ */ new WeakMap();
|
|
2757
2724
|
const controlElements = /* @__PURE__ */ new Set();
|
|
@@ -2759,15 +2726,14 @@ var DomFeature = class {
|
|
|
2759
2726
|
controlElements.add(element);
|
|
2760
2727
|
elementRoles.set(element, { role: "control" });
|
|
2761
2728
|
}
|
|
2762
|
-
const tokens = this.
|
|
2763
|
-
if (this.
|
|
2729
|
+
const tokens = this.parsing.tokens();
|
|
2730
|
+
if (this.props.layout() === "block") this.#indexBlockTokens(container, tokens, tokenIndex, controlElements, pathElements, elementRoles);
|
|
2764
2731
|
else this.#indexTokenSequence(container, tokens, [], void 0, tokenIndex, controlElements, pathElements, elementRoles);
|
|
2765
2732
|
this.#pathElements = pathElements;
|
|
2766
2733
|
this.#elementRoles = elementRoles;
|
|
2767
2734
|
this.#reconcileStructuralTextSurfaces();
|
|
2768
2735
|
batch(() => this.#domIndex({ generation: ++this.#generation }), { mutable: true });
|
|
2769
|
-
this
|
|
2770
|
-
this.#applyPendingRecovery();
|
|
2736
|
+
this.indexed();
|
|
2771
2737
|
}
|
|
2772
2738
|
#elementChildren(element) {
|
|
2773
2739
|
return Array.from(element.children).filter((child) => child instanceof HTMLElement);
|
|
@@ -2881,9 +2847,9 @@ var DomFeature = class {
|
|
|
2881
2847
|
});
|
|
2882
2848
|
this.#indexNestedTokenSequence(token, path, address, element, rowElement, tokenIndex, controlElements, pathElements, elementRoles);
|
|
2883
2849
|
}
|
|
2884
|
-
#reconcileStructuralTextSurfaces() {
|
|
2885
|
-
const tokenIndex = this.
|
|
2886
|
-
const editable = this.
|
|
2850
|
+
#reconcileStructuralTextSurfaces(isUserSelecting) {
|
|
2851
|
+
const tokenIndex = this.parsing.index();
|
|
2852
|
+
const editable = this.props.readOnly() || isUserSelecting ? "false" : "true";
|
|
2887
2853
|
for (const record of this.#pathElements.values()) {
|
|
2888
2854
|
const resolved = tokenIndex.resolveAddress(record.address);
|
|
2889
2855
|
if (!resolved.ok) {
|
|
@@ -2907,12 +2873,12 @@ var DomFeature = class {
|
|
|
2907
2873
|
record.textElement.contentEditable = editable;
|
|
2908
2874
|
continue;
|
|
2909
2875
|
}
|
|
2910
|
-
if (resolved.value.type === "mark") if (this.
|
|
2876
|
+
if (resolved.value.type === "mark") if (this.props.readOnly()) record.tokenElement.removeAttribute("tabindex");
|
|
2911
2877
|
else record.tokenElement.tabIndex = 0;
|
|
2912
2878
|
}
|
|
2913
2879
|
}
|
|
2914
2880
|
#rawPositionFromContainerBoundary(offset, affinity) {
|
|
2915
|
-
const tokens = this.
|
|
2881
|
+
const tokens = this.parsing.tokens();
|
|
2916
2882
|
if (tokens.length === 0) return {
|
|
2917
2883
|
ok: true,
|
|
2918
2884
|
value: 0
|
|
@@ -2934,7 +2900,7 @@ var DomFeature = class {
|
|
|
2934
2900
|
}
|
|
2935
2901
|
#rawPositionFromTokenChildBoundary(tokenElement, offset, token, affinity) {
|
|
2936
2902
|
if (token.type === "text") {
|
|
2937
|
-
const textElement = this.#pathElements.get(pathKey(this.
|
|
2903
|
+
const textElement = this.#pathElements.get(pathKey(this.parsing.index().pathFor(token) ?? []))?.textElement;
|
|
2938
2904
|
if (!textElement || textLength(textElement) === 0) return {
|
|
2939
2905
|
ok: true,
|
|
2940
2906
|
value: token.position.start
|
|
@@ -2943,8 +2909,8 @@ var DomFeature = class {
|
|
|
2943
2909
|
const before = this.#locateRegisteredDescendant(tokenElement.childNodes.item(offset - 1));
|
|
2944
2910
|
const after = this.#locateRegisteredDescendant(tokenElement.childNodes.item(offset));
|
|
2945
2911
|
if (before?.ok && after?.ok) {
|
|
2946
|
-
const beforeToken = this.
|
|
2947
|
-
const afterToken = this.
|
|
2912
|
+
const beforeToken = this.parsing.index().resolveAddress(before.value.address);
|
|
2913
|
+
const afterToken = this.parsing.index().resolveAddress(after.value.address);
|
|
2948
2914
|
if (beforeToken.ok && afterToken.ok) return {
|
|
2949
2915
|
ok: true,
|
|
2950
2916
|
value: affinity === "before" ? beforeToken.value.position.end : afterToken.value.position.start
|
|
@@ -2961,7 +2927,7 @@ var DomFeature = class {
|
|
|
2961
2927
|
}
|
|
2962
2928
|
#findTextTargetForRawPosition(rawPosition, affinity) {
|
|
2963
2929
|
const candidates = [];
|
|
2964
|
-
const tokenIndex = this.
|
|
2930
|
+
const tokenIndex = this.parsing.index();
|
|
2965
2931
|
for (const record of this.#pathElements.values()) {
|
|
2966
2932
|
if (!record.textElement) continue;
|
|
2967
2933
|
const resolved = tokenIndex.resolveAddress(record.address);
|
|
@@ -2979,7 +2945,7 @@ var DomFeature = class {
|
|
|
2979
2945
|
return candidates.find((candidate) => candidate.start >= rawPosition);
|
|
2980
2946
|
}
|
|
2981
2947
|
#focusMarkBoundaryForRawPosition(rawPosition) {
|
|
2982
|
-
const tokenIndex = this.
|
|
2948
|
+
const tokenIndex = this.parsing.index();
|
|
2983
2949
|
for (const record of this.#pathElements.values()) {
|
|
2984
2950
|
const resolved = tokenIndex.resolveAddress(record.address);
|
|
2985
2951
|
if (!resolved.ok || resolved.value.type !== "mark") continue;
|
|
@@ -2987,10 +2953,6 @@ var DomFeature = class {
|
|
|
2987
2953
|
const boundary = rawPosition === resolved.value.position.end ? "end" : "start";
|
|
2988
2954
|
record.tokenElement.focus();
|
|
2989
2955
|
this.#placeCollapsedBoundary(record.tokenElement, boundary === "end" ? record.tokenElement.childNodes.length : 0);
|
|
2990
|
-
this._store.caret.location({
|
|
2991
|
-
address: record.address,
|
|
2992
|
-
role: "markDescendant"
|
|
2993
|
-
});
|
|
2994
2956
|
return {
|
|
2995
2957
|
ok: true,
|
|
2996
2958
|
value: void 0
|
|
@@ -3021,25 +2983,6 @@ var DomFeature = class {
|
|
|
3021
2983
|
selection.removeAllRanges();
|
|
3022
2984
|
selection.addRange(range);
|
|
3023
2985
|
}
|
|
3024
|
-
#applyPendingRecovery() {
|
|
3025
|
-
const recovery = this._store.caret.recovery();
|
|
3026
|
-
if (!recovery) return;
|
|
3027
|
-
if (recovery.kind === "caret") {
|
|
3028
|
-
const result = this._store.caret.placeAt(recovery.rawPosition, recovery.affinity);
|
|
3029
|
-
this._store.caret.recovery(void 0);
|
|
3030
|
-
if (!result.ok) this.diagnostics({
|
|
3031
|
-
kind: "recoveryFailed",
|
|
3032
|
-
reason: `pending caret recovery could not be applied: ${result.reason}`
|
|
3033
|
-
});
|
|
3034
|
-
return;
|
|
3035
|
-
}
|
|
3036
|
-
const result = this.#placeSelection(recovery.selection);
|
|
3037
|
-
this._store.caret.recovery(void 0);
|
|
3038
|
-
if (!result.ok) this.diagnostics({
|
|
3039
|
-
kind: "recoveryFailed",
|
|
3040
|
-
reason: `pending selection recovery could not be applied: ${result.reason}`
|
|
3041
|
-
});
|
|
3042
|
-
}
|
|
3043
2986
|
#placeSelection(selection) {
|
|
3044
2987
|
const start = this.#findTextTargetForRawPosition(selection.range.start, "after");
|
|
3045
2988
|
const end = this.#findTextTargetForRawPosition(selection.range.end, "before");
|
|
@@ -3083,11 +3026,6 @@ var DomFeature = class {
|
|
|
3083
3026
|
offset: text.length
|
|
3084
3027
|
};
|
|
3085
3028
|
}
|
|
3086
|
-
#clearStaleCaretLocation() {
|
|
3087
|
-
const location = this._store.caret.location();
|
|
3088
|
-
if (!location) return;
|
|
3089
|
-
if (!this._store.parsing.index().resolveAddress(location.address).ok || !this.#pathElements.has(pathKey(location.address.path))) this._store.caret.location(void 0);
|
|
3090
|
-
}
|
|
3091
3029
|
};
|
|
3092
3030
|
//#endregion
|
|
3093
3031
|
//#region ../../core/src/features/editing/createRowContent.ts
|
|
@@ -3198,103 +3136,95 @@ const EMPTY_TEXT_TOKEN = {
|
|
|
3198
3136
|
}
|
|
3199
3137
|
};
|
|
3200
3138
|
//#endregion
|
|
3201
|
-
//#region ../../core/src/features/drag/
|
|
3202
|
-
var
|
|
3203
|
-
constructor(store) {
|
|
3204
|
-
this.store = store;
|
|
3205
|
-
this.action = event();
|
|
3206
|
-
}
|
|
3139
|
+
//#region ../../core/src/features/drag/DragController.ts
|
|
3140
|
+
var DragController = class {
|
|
3207
3141
|
#unsub;
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
this
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3142
|
+
constructor(props, value, parsing, caret) {
|
|
3143
|
+
this.props = props;
|
|
3144
|
+
this.value = value;
|
|
3145
|
+
this.parsing = parsing;
|
|
3146
|
+
this.caret = caret;
|
|
3147
|
+
this.action = event();
|
|
3148
|
+
const isDragEnabled = computed(() => this.props.layout() === "block" && !!this.props.draggable());
|
|
3149
|
+
const toggle = (enabled) => {
|
|
3150
|
+
if (enabled && !this.#unsub) this.#unsub = watch(this.action, (action) => {
|
|
3151
|
+
switch (action.type) {
|
|
3152
|
+
case "reorder":
|
|
3153
|
+
this.#reorder(action);
|
|
3154
|
+
break;
|
|
3155
|
+
case "add":
|
|
3156
|
+
this.#add(action);
|
|
3157
|
+
break;
|
|
3158
|
+
case "delete":
|
|
3159
|
+
this.#delete(action);
|
|
3160
|
+
break;
|
|
3161
|
+
case "duplicate":
|
|
3162
|
+
this.#duplicate(action);
|
|
3163
|
+
break;
|
|
3164
|
+
}
|
|
3165
|
+
});
|
|
3166
|
+
if (!enabled && this.#unsub) {
|
|
3167
|
+
this.#unsub();
|
|
3168
|
+
this.#unsub = void 0;
|
|
3224
3169
|
}
|
|
3225
|
-
}
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
this.#unsub?.();
|
|
3229
|
-
this.#unsub = void 0;
|
|
3170
|
+
};
|
|
3171
|
+
watch(isDragEnabled, toggle);
|
|
3172
|
+
toggle(isDragEnabled());
|
|
3230
3173
|
}
|
|
3231
3174
|
#reorder(action) {
|
|
3232
|
-
const value = this.
|
|
3233
|
-
const rows = this.
|
|
3175
|
+
const value = this.value.current();
|
|
3176
|
+
const rows = this.parsing.tokens();
|
|
3234
3177
|
const newValue = reorderDragRows(value, rows, action.source, action.target);
|
|
3235
|
-
if (newValue !== value)
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3178
|
+
if (newValue !== value) {
|
|
3179
|
+
const range = this.#rangeAfterDrag(action, rows, newValue);
|
|
3180
|
+
if (range) this.caret.selection(range);
|
|
3181
|
+
this.value.current(newValue);
|
|
3182
|
+
}
|
|
3239
3183
|
}
|
|
3240
3184
|
#add(action) {
|
|
3241
|
-
const value = this.
|
|
3242
|
-
const rawRows = this.
|
|
3185
|
+
const value = this.value.current();
|
|
3186
|
+
const rawRows = this.parsing.tokens();
|
|
3243
3187
|
const rows = rawRows.length > 0 ? rawRows : [EMPTY_TEXT_TOKEN];
|
|
3244
|
-
const newRowContent = createRowContent(this.
|
|
3188
|
+
const newRowContent = createRowContent(this.props.options());
|
|
3245
3189
|
const newValue = addDragRow(value, rows, action.afterIndex, newRowContent);
|
|
3246
|
-
this
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
});
|
|
3190
|
+
const range = this.#rangeAfterDrag(action, rows, newValue);
|
|
3191
|
+
if (range) this.caret.selection(range);
|
|
3192
|
+
this.value.current(newValue);
|
|
3250
3193
|
}
|
|
3251
3194
|
#delete(action) {
|
|
3252
|
-
const value = this.
|
|
3253
|
-
const rows = this.
|
|
3195
|
+
const value = this.value.current();
|
|
3196
|
+
const rows = this.parsing.tokens();
|
|
3254
3197
|
const newValue = deleteDragRow(value, rows, action.index);
|
|
3255
|
-
this
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
});
|
|
3198
|
+
const range = this.#rangeAfterDrag(action, rows, newValue);
|
|
3199
|
+
if (range) this.caret.selection(range);
|
|
3200
|
+
this.value.current(newValue);
|
|
3259
3201
|
}
|
|
3260
3202
|
#duplicate(action) {
|
|
3261
|
-
const value = this.
|
|
3262
|
-
const rows = this.
|
|
3203
|
+
const value = this.value.current();
|
|
3204
|
+
const rows = this.parsing.tokens();
|
|
3263
3205
|
const newValue = duplicateDragRow(value, rows, action.index);
|
|
3264
|
-
this
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
});
|
|
3206
|
+
const range = this.#rangeAfterDrag(action, rows, newValue);
|
|
3207
|
+
if (range) this.caret.selection(range);
|
|
3208
|
+
this.value.current(newValue);
|
|
3268
3209
|
}
|
|
3269
|
-
#
|
|
3210
|
+
#rangeAfterDrag(action, previousRows, nextValue) {
|
|
3211
|
+
let rawPosition;
|
|
3270
3212
|
if (action.type === "add") {
|
|
3271
3213
|
const after = previousRows.at(action.afterIndex);
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
rawPosition: after ? after.position.end : nextValue.length
|
|
3275
|
-
};
|
|
3276
|
-
}
|
|
3277
|
-
if (action.type === "duplicate") {
|
|
3214
|
+
rawPosition = after ? after.position.end : nextValue.length;
|
|
3215
|
+
} else if (action.type === "duplicate") {
|
|
3278
3216
|
const row = previousRows.at(action.index);
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
rawPosition: row.position.end
|
|
3282
|
-
} : void 0;
|
|
3283
|
-
}
|
|
3284
|
-
if (action.type === "delete") {
|
|
3217
|
+
rawPosition = row ? row.position.end : void 0;
|
|
3218
|
+
} else if (action.type === "delete") {
|
|
3285
3219
|
const next = previousRows.at(action.index + 1) ?? (action.index > 0 ? previousRows.at(action.index - 1) : void 0);
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
kind: "caret",
|
|
3291
|
-
rawPosition: 0
|
|
3292
|
-
};
|
|
3220
|
+
rawPosition = next ? Math.min(next.position.start, nextValue.length) : 0;
|
|
3221
|
+
} else {
|
|
3222
|
+
const moved = previousRows.at(action.source);
|
|
3223
|
+
rawPosition = moved ? Math.min(moved.position.start, nextValue.length) : void 0;
|
|
3293
3224
|
}
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
rawPosition: Math.min(moved.position.start, nextValue.length)
|
|
3225
|
+
return rawPosition !== void 0 ? {
|
|
3226
|
+
start: rawPosition,
|
|
3227
|
+
end: rawPosition
|
|
3298
3228
|
} : void 0;
|
|
3299
3229
|
}
|
|
3300
3230
|
};
|
|
@@ -3316,26 +3246,49 @@ function getAlwaysShowHandle(draggable) {
|
|
|
3316
3246
|
return typeof draggable === "object" && !!draggable.alwaysShowHandle;
|
|
3317
3247
|
}
|
|
3318
3248
|
//#endregion
|
|
3249
|
+
//#region ../../core/src/features/edit/EditController.ts
|
|
3250
|
+
/**
|
|
3251
|
+
* Single write path for text edits — delegates gating to {@link ValueModel.replace}
|
|
3252
|
+
* and only moves the caret when the edit is accepted. Wrapped in {@link batch}
|
|
3253
|
+
* so subscribers observe a consistent value/selection pair on one tick.
|
|
3254
|
+
*/
|
|
3255
|
+
var EditController = class {
|
|
3256
|
+
constructor(value, caret) {
|
|
3257
|
+
this.value = value;
|
|
3258
|
+
this.caret = caret;
|
|
3259
|
+
}
|
|
3260
|
+
replace(range, replacement) {
|
|
3261
|
+
batch(() => {
|
|
3262
|
+
if (!this.value.replace(range, replacement)) return;
|
|
3263
|
+
this.caret.position(range.start + replacement.length);
|
|
3264
|
+
});
|
|
3265
|
+
}
|
|
3266
|
+
};
|
|
3267
|
+
//#endregion
|
|
3319
3268
|
//#region ../../core/src/features/keyboard/arrowNav.ts
|
|
3320
3269
|
function enableArrowNav(store) {
|
|
3321
3270
|
const container = store.dom.container();
|
|
3322
|
-
if (!container) return
|
|
3323
|
-
|
|
3324
|
-
|
|
3271
|
+
if (!container) return;
|
|
3272
|
+
listen(container, "keydown", (e) => {
|
|
3273
|
+
if (store.slots.isBlock()) return;
|
|
3274
|
+
if (e.key === KEYBOARD.LEFT) shiftFocus(store, e, "prev");
|
|
3275
|
+
else if (e.key === KEYBOARD.RIGHT) shiftFocus(store, e, "next");
|
|
3276
|
+
if ((e.ctrlKey || e.metaKey) && e.code === "KeyA") {
|
|
3325
3277
|
if (store.slots.isBlock()) return;
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
});
|
|
3278
|
+
e.preventDefault();
|
|
3279
|
+
store.caret.selectAll();
|
|
3280
|
+
}
|
|
3330
3281
|
});
|
|
3331
|
-
return () => scope();
|
|
3332
3282
|
}
|
|
3333
3283
|
function shiftFocus(store, event, direction) {
|
|
3334
|
-
const
|
|
3335
|
-
|
|
3336
|
-
|
|
3284
|
+
const active = document.activeElement instanceof HTMLElement ? document.activeElement : void 0;
|
|
3285
|
+
const located = active ? store.dom.locateNode(active) : void 0;
|
|
3286
|
+
if (!located?.ok) return false;
|
|
3287
|
+
const isFocusedOnMarkElement = active === located.value.tokenElement && !located.value.textElement;
|
|
3288
|
+
const address = located.value.address;
|
|
3289
|
+
const token = store.parsing.index().resolveAddress(address);
|
|
3337
3290
|
if (!token.ok) return false;
|
|
3338
|
-
if (!
|
|
3291
|
+
if (!isFocusedOnMarkElement) {
|
|
3339
3292
|
const selection = store.dom.readRawSelection();
|
|
3340
3293
|
if (!selection.ok || selection.value.range.start !== selection.value.range.end) return false;
|
|
3341
3294
|
const atStart = selection.value.range.start <= token.value.position.start;
|
|
@@ -3343,20 +3296,20 @@ function shiftFocus(store, event, direction) {
|
|
|
3343
3296
|
if (direction === "prev" && !atStart) return false;
|
|
3344
3297
|
if (direction === "next" && !atEnd) return false;
|
|
3345
3298
|
}
|
|
3346
|
-
const path =
|
|
3299
|
+
const path = address.path;
|
|
3347
3300
|
const siblingIndex = direction === "prev" ? path[path.length - 1] - 1 : path[path.length - 1] + 1;
|
|
3348
3301
|
const siblingPath = [...path.slice(0, -1), siblingIndex];
|
|
3349
3302
|
const siblingAddress = store.parsing.index().addressFor(siblingPath);
|
|
3350
3303
|
if (!siblingAddress) return false;
|
|
3351
3304
|
event.preventDefault();
|
|
3352
|
-
if (!store.
|
|
3305
|
+
if (!store.dom.focusAddress(siblingAddress, direction === "prev" ? "end" : "start").ok) return false;
|
|
3353
3306
|
const sibling = store.parsing.index().resolve(siblingPath);
|
|
3354
3307
|
if (sibling?.type === "mark") return true;
|
|
3355
3308
|
if (direction === "prev") {
|
|
3356
|
-
store.
|
|
3309
|
+
store.dom.placeAt(sibling?.position.end ?? 0, "before");
|
|
3357
3310
|
return true;
|
|
3358
3311
|
}
|
|
3359
|
-
store.
|
|
3312
|
+
store.dom.placeAt(sibling?.position.start ?? 0, "after");
|
|
3360
3313
|
return true;
|
|
3361
3314
|
}
|
|
3362
3315
|
//#endregion
|
|
@@ -3367,22 +3320,19 @@ function isTextLikeRow(token) {
|
|
|
3367
3320
|
}
|
|
3368
3321
|
function enableBlockEdit(store) {
|
|
3369
3322
|
const container = store.dom.container();
|
|
3370
|
-
if (!container) return
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
handleEnter(store, e);
|
|
3378
|
-
});
|
|
3379
|
-
listen(container, "beforeinput", (e) => {
|
|
3380
|
-
if (!store.slots.isBlock()) return;
|
|
3381
|
-
if (e.defaultPrevented) return;
|
|
3382
|
-
handleBlockBeforeInput(store, e);
|
|
3383
|
-
}, true);
|
|
3323
|
+
if (!container) return;
|
|
3324
|
+
listen(container, "keydown", (e) => {
|
|
3325
|
+
if (!store.slots.isBlock()) return;
|
|
3326
|
+
if (e.key === KEYBOARD.LEFT || e.key === KEYBOARD.RIGHT) handleBlockArrowLeftRight(store, e, e.key === KEYBOARD.LEFT ? "left" : "right");
|
|
3327
|
+
else if (e.key === KEYBOARD.UP || e.key === KEYBOARD.DOWN) handleArrowUpDown(store, e);
|
|
3328
|
+
handleDelete(store, e);
|
|
3329
|
+
handleEnter(store, e);
|
|
3384
3330
|
});
|
|
3385
|
-
|
|
3331
|
+
listen(container, "beforeinput", (e) => {
|
|
3332
|
+
if (!store.slots.isBlock()) return;
|
|
3333
|
+
if (e.defaultPrevented) return;
|
|
3334
|
+
handleBlockBeforeInput(store, e);
|
|
3335
|
+
}, true);
|
|
3386
3336
|
}
|
|
3387
3337
|
function handleDelete(store, event) {
|
|
3388
3338
|
const container = store.dom.container();
|
|
@@ -3396,7 +3346,7 @@ function handleDelete(store, event) {
|
|
|
3396
3346
|
const value = store.value.current();
|
|
3397
3347
|
if (event.key === KEYBOARD.BACKSPACE) {
|
|
3398
3348
|
const blockDiv = blockDivs[blockIndex];
|
|
3399
|
-
const caretAtStart =
|
|
3349
|
+
const caretAtStart = getCaretIndex(blockDiv) === 0;
|
|
3400
3350
|
if (("content" in token ? token.content : "") === "") {
|
|
3401
3351
|
event.preventDefault();
|
|
3402
3352
|
const newValue = rows.length <= 1 ? "" : (() => {
|
|
@@ -3404,13 +3354,9 @@ function handleDelete(store, event) {
|
|
|
3404
3354
|
return value.slice(0, rows[blockIndex].position.start) + value.slice(rows[blockIndex + 1].position.start);
|
|
3405
3355
|
})();
|
|
3406
3356
|
const previous = rows.at(Math.max(0, blockIndex - 1));
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
kind: "caret",
|
|
3411
|
-
rawPosition: previous ? previous.position.end : 0
|
|
3412
|
-
}
|
|
3413
|
-
});
|
|
3357
|
+
const pos = previous ? previous.position.end : 0;
|
|
3358
|
+
store.caret.position(pos);
|
|
3359
|
+
store.value.current(newValue);
|
|
3414
3360
|
return;
|
|
3415
3361
|
}
|
|
3416
3362
|
if (caretAtStart && blockIndex > 0) {
|
|
@@ -3420,26 +3366,18 @@ function handleDelete(store, event) {
|
|
|
3420
3366
|
event.preventDefault();
|
|
3421
3367
|
const joinPos = getMergeDragRowJoinPos(rows, blockIndex);
|
|
3422
3368
|
const newValue = mergeDragRows(value, rows, blockIndex);
|
|
3423
|
-
store.
|
|
3424
|
-
|
|
3425
|
-
recover: {
|
|
3426
|
-
kind: "caret",
|
|
3427
|
-
rawPosition: joinPos
|
|
3428
|
-
}
|
|
3429
|
-
});
|
|
3369
|
+
store.caret.position(joinPos);
|
|
3370
|
+
store.value.current(newValue);
|
|
3430
3371
|
return;
|
|
3431
3372
|
}
|
|
3432
3373
|
event.preventDefault();
|
|
3433
|
-
|
|
3434
|
-
const target = blockDivs[blockIndex - 1];
|
|
3435
|
-
focusRow(store, prevToken, target, "end");
|
|
3436
|
-
});
|
|
3374
|
+
focusRow(store, prevToken, blockDivs[blockIndex - 1], "end");
|
|
3437
3375
|
return;
|
|
3438
3376
|
}
|
|
3439
3377
|
}
|
|
3440
3378
|
if (event.key === KEYBOARD.DELETE) {
|
|
3441
3379
|
const blockDiv = blockDivs[blockIndex];
|
|
3442
|
-
const caretIndex =
|
|
3380
|
+
const caretIndex = getCaretIndex(blockDiv);
|
|
3443
3381
|
const caretAtEnd = caretIndex === blockDiv.textContent.length;
|
|
3444
3382
|
if (caretIndex === 0 && blockIndex > 0) {
|
|
3445
3383
|
const prevToken = rows[blockIndex - 1];
|
|
@@ -3448,20 +3386,12 @@ function handleDelete(store, event) {
|
|
|
3448
3386
|
event.preventDefault();
|
|
3449
3387
|
const joinPos = getMergeDragRowJoinPos(rows, blockIndex);
|
|
3450
3388
|
const newValue = mergeDragRows(value, rows, blockIndex);
|
|
3451
|
-
store.
|
|
3452
|
-
|
|
3453
|
-
recover: {
|
|
3454
|
-
kind: "caret",
|
|
3455
|
-
rawPosition: joinPos
|
|
3456
|
-
}
|
|
3457
|
-
});
|
|
3389
|
+
store.caret.position(joinPos);
|
|
3390
|
+
store.value.current(newValue);
|
|
3458
3391
|
return;
|
|
3459
3392
|
}
|
|
3460
3393
|
event.preventDefault();
|
|
3461
|
-
|
|
3462
|
-
const target = blockDivs[blockIndex - 1];
|
|
3463
|
-
focusRow(store, prevToken, target, "end");
|
|
3464
|
-
});
|
|
3394
|
+
focusRow(store, prevToken, blockDivs[blockIndex - 1], "end");
|
|
3465
3395
|
return;
|
|
3466
3396
|
}
|
|
3467
3397
|
if (caretAtEnd && blockIndex < rows.length - 1) {
|
|
@@ -3471,20 +3401,12 @@ function handleDelete(store, event) {
|
|
|
3471
3401
|
event.preventDefault();
|
|
3472
3402
|
const joinPos = getMergeDragRowJoinPos(rows, blockIndex + 1);
|
|
3473
3403
|
const newValue = mergeDragRows(value, rows, blockIndex + 1);
|
|
3474
|
-
store.
|
|
3475
|
-
|
|
3476
|
-
recover: {
|
|
3477
|
-
kind: "caret",
|
|
3478
|
-
rawPosition: joinPos
|
|
3479
|
-
}
|
|
3480
|
-
});
|
|
3404
|
+
store.caret.position(joinPos);
|
|
3405
|
+
store.value.current(newValue);
|
|
3481
3406
|
return;
|
|
3482
3407
|
}
|
|
3483
3408
|
event.preventDefault();
|
|
3484
|
-
|
|
3485
|
-
const target = blockDivs[blockIndex + 1];
|
|
3486
|
-
focusRow(store, nextToken, target, "start");
|
|
3487
|
-
});
|
|
3409
|
+
focusRow(store, nextToken, blockDivs[blockIndex + 1], "start");
|
|
3488
3410
|
return;
|
|
3489
3411
|
}
|
|
3490
3412
|
}
|
|
@@ -3510,40 +3432,30 @@ function handleEnter(store, event) {
|
|
|
3510
3432
|
const newRowContent = createRowContent(store.props.options());
|
|
3511
3433
|
if (!isTextLikeRow(token)) {
|
|
3512
3434
|
const newValue = addDragRow(value, rows, blockIndex, newRowContent);
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
kind: "caret",
|
|
3517
|
-
rawPosition: token.position.end + newRowContent.length
|
|
3518
|
-
}
|
|
3519
|
-
});
|
|
3435
|
+
const pos = token.position.end + newRowContent.length;
|
|
3436
|
+
store.caret.position(pos);
|
|
3437
|
+
store.value.current(newValue);
|
|
3520
3438
|
return;
|
|
3521
3439
|
}
|
|
3522
3440
|
const raw = store.dom.readRawSelection();
|
|
3523
3441
|
const absolutePos = raw.ok ? raw.value.range.start : token.position.end;
|
|
3524
|
-
store.
|
|
3442
|
+
store.edit.replace({
|
|
3525
3443
|
start: absolutePos,
|
|
3526
3444
|
end: absolutePos
|
|
3527
|
-
}, newRowContent
|
|
3528
|
-
source: "block",
|
|
3529
|
-
recover: {
|
|
3530
|
-
kind: "caret",
|
|
3531
|
-
rawPosition: absolutePos + newRowContent.length
|
|
3532
|
-
}
|
|
3533
|
-
});
|
|
3445
|
+
}, newRowContent);
|
|
3534
3446
|
}
|
|
3535
3447
|
function focusRow(store, token, row, caret) {
|
|
3536
3448
|
if (token.type === "mark") {
|
|
3537
3449
|
const path = store.parsing.index().pathFor(token);
|
|
3538
3450
|
const address = path ? store.parsing.index().addressFor(path) : void 0;
|
|
3539
|
-
if (address && store.
|
|
3451
|
+
if (address && store.dom.focusAddress(address).ok) return;
|
|
3540
3452
|
}
|
|
3541
3453
|
row.focus();
|
|
3542
3454
|
if (caret === "start") {
|
|
3543
|
-
|
|
3455
|
+
setAtElement(row, 0);
|
|
3544
3456
|
return;
|
|
3545
3457
|
}
|
|
3546
|
-
|
|
3458
|
+
setAtElement(row, Infinity);
|
|
3547
3459
|
}
|
|
3548
3460
|
function handleBlockArrowLeftRight(store, event, direction) {
|
|
3549
3461
|
const container = store.dom.container();
|
|
@@ -3555,20 +3467,20 @@ function handleBlockArrowLeftRight(store, event, direction) {
|
|
|
3555
3467
|
if (blockIndex === -1) return false;
|
|
3556
3468
|
const blockDiv = blockDivs[blockIndex];
|
|
3557
3469
|
if (direction === "left") {
|
|
3558
|
-
if (
|
|
3470
|
+
if (getCaretIndex(blockDiv) !== 0) return false;
|
|
3559
3471
|
if (blockIndex === 0) return true;
|
|
3560
3472
|
event.preventDefault();
|
|
3561
3473
|
const prevBlock = blockDivs[blockIndex - 1];
|
|
3562
3474
|
prevBlock.focus();
|
|
3563
|
-
|
|
3475
|
+
setAtElement(prevBlock, Infinity);
|
|
3564
3476
|
return true;
|
|
3565
3477
|
}
|
|
3566
|
-
if (
|
|
3478
|
+
if (getCaretIndex(blockDiv) !== blockDiv.textContent.length) return false;
|
|
3567
3479
|
if (blockIndex >= blockDivs.length - 1) return true;
|
|
3568
3480
|
event.preventDefault();
|
|
3569
3481
|
const nextBlock = blockDivs[blockIndex + 1];
|
|
3570
3482
|
nextBlock.focus();
|
|
3571
|
-
|
|
3483
|
+
setAtElement(nextBlock, 0);
|
|
3572
3484
|
return true;
|
|
3573
3485
|
}
|
|
3574
3486
|
function handleArrowUpDown(store, event) {
|
|
@@ -3581,23 +3493,21 @@ function handleArrowUpDown(store, event) {
|
|
|
3581
3493
|
if (blockIndex === -1) return;
|
|
3582
3494
|
const blockDiv = blockDivs[blockIndex];
|
|
3583
3495
|
if (event.key === KEYBOARD.UP) {
|
|
3584
|
-
if (!
|
|
3496
|
+
if (!isOnFirstLine(blockDiv)) return;
|
|
3585
3497
|
if (blockIndex === 0) return;
|
|
3586
3498
|
event.preventDefault();
|
|
3587
|
-
const caretX =
|
|
3499
|
+
const caretX = getRect()?.left ?? blockDiv.getBoundingClientRect().left;
|
|
3588
3500
|
const prevBlockDiv = blockDivs[blockIndex - 1];
|
|
3589
3501
|
prevBlockDiv.focus();
|
|
3590
|
-
|
|
3591
|
-
Caret.setAtX(prevBlockDiv, caretX, prevRect.bottom - 4);
|
|
3502
|
+
setAtX(prevBlockDiv, caretX, prevBlockDiv.getBoundingClientRect().bottom - 4);
|
|
3592
3503
|
} else if (event.key === KEYBOARD.DOWN) {
|
|
3593
|
-
if (!
|
|
3504
|
+
if (!isOnLastLine(blockDiv)) return;
|
|
3594
3505
|
if (blockIndex >= blockDivs.length - 1) return;
|
|
3595
3506
|
event.preventDefault();
|
|
3596
|
-
const caretX =
|
|
3507
|
+
const caretX = getRect()?.left ?? blockDiv.getBoundingClientRect().left;
|
|
3597
3508
|
const nextBlockDiv = blockDivs[blockIndex + 1];
|
|
3598
3509
|
nextBlockDiv.focus();
|
|
3599
|
-
|
|
3600
|
-
Caret.setAtX(nextBlockDiv, caretX, nextRect.top + 4);
|
|
3510
|
+
setAtX(nextBlockDiv, caretX, nextBlockDiv.getBoundingClientRect().top + 4);
|
|
3601
3511
|
}
|
|
3602
3512
|
}
|
|
3603
3513
|
function handleBlockBeforeInput(store, event) {
|
|
@@ -3632,13 +3542,7 @@ function replaceBlockRange(store, event, replacement) {
|
|
|
3632
3542
|
const range = rangeForBlockInput(store, event, raw.value.range);
|
|
3633
3543
|
if (!range) return;
|
|
3634
3544
|
event.preventDefault();
|
|
3635
|
-
store.
|
|
3636
|
-
source: "block",
|
|
3637
|
-
recover: {
|
|
3638
|
-
kind: "caret",
|
|
3639
|
-
rawPosition: range.start + replacement.length
|
|
3640
|
-
}
|
|
3641
|
-
});
|
|
3545
|
+
store.edit.replace(range, replacement);
|
|
3642
3546
|
}
|
|
3643
3547
|
function rawRangeFromInputEvent$1(store, event) {
|
|
3644
3548
|
const ranges = event.getTargetRanges();
|
|
@@ -3688,68 +3592,51 @@ function rangeForBlockInput(store, event, range) {
|
|
|
3688
3592
|
//#region ../../core/src/features/keyboard/input.ts
|
|
3689
3593
|
function enableInput(store) {
|
|
3690
3594
|
const container = store.dom.container();
|
|
3691
|
-
if (!container) return
|
|
3595
|
+
if (!container) return;
|
|
3692
3596
|
let compositionRange;
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
});
|
|
3718
|
-
});
|
|
3719
|
-
listen(container, "beforeinput", (e) => {
|
|
3720
|
-
handleBeforeInput(store, e);
|
|
3721
|
-
}, true);
|
|
3722
|
-
listen(container, "keydown", (e) => {
|
|
3723
|
-
handleDeleteKey(store, e);
|
|
3724
|
-
});
|
|
3597
|
+
listen(container, "paste", (e) => {
|
|
3598
|
+
const c = store.dom.container();
|
|
3599
|
+
if (c) captureMarkupPaste(e, c);
|
|
3600
|
+
handlePaste(store, e);
|
|
3601
|
+
});
|
|
3602
|
+
listen(container, "compositionstart", () => {
|
|
3603
|
+
const selection = store.dom.readRawSelection();
|
|
3604
|
+
compositionRange = selection.ok ? selection.value.range : void 0;
|
|
3605
|
+
store.dom.compositionStarted();
|
|
3606
|
+
});
|
|
3607
|
+
listen(container, "compositionend", (e) => {
|
|
3608
|
+
const range = compositionRange;
|
|
3609
|
+
compositionRange = void 0;
|
|
3610
|
+
store.dom.compositionEnded();
|
|
3611
|
+
if (store.slots.isBlock()) return;
|
|
3612
|
+
if (!range) return;
|
|
3613
|
+
const data = e.data;
|
|
3614
|
+
store.edit.replace(range, data);
|
|
3615
|
+
});
|
|
3616
|
+
listen(container, "beforeinput", (e) => {
|
|
3617
|
+
handleBeforeInput(store, e);
|
|
3618
|
+
}, true);
|
|
3619
|
+
listen(container, "keydown", (e) => {
|
|
3620
|
+
handleDeleteKey(store, e);
|
|
3725
3621
|
});
|
|
3726
|
-
return () => scope();
|
|
3727
3622
|
}
|
|
3728
3623
|
function handleDeleteKey(store, event) {
|
|
3729
3624
|
if (store.slots.isBlock()) return;
|
|
3730
3625
|
if (event.key !== KEYBOARD.BACKSPACE && event.key !== KEYBOARD.DELETE) return;
|
|
3731
|
-
if (store.caret.
|
|
3626
|
+
if (store.caret.isAllSelected()) {
|
|
3732
3627
|
event.preventDefault();
|
|
3733
3628
|
replaceAllContentWith(store, "");
|
|
3734
3629
|
return;
|
|
3735
3630
|
}
|
|
3736
|
-
if (store.caret.selecting() === "all") store.caret.selecting(void 0);
|
|
3737
3631
|
const raw = store.dom.readRawSelection();
|
|
3738
3632
|
if (!raw.ok) return;
|
|
3739
3633
|
const range = rangeForDelete(store, event.key === KEYBOARD.BACKSPACE ? "deleteContentBackward" : "deleteContentForward", raw.value.range);
|
|
3740
3634
|
if (!range) return;
|
|
3741
3635
|
event.preventDefault();
|
|
3742
|
-
store.
|
|
3743
|
-
source: "input",
|
|
3744
|
-
recover: {
|
|
3745
|
-
kind: "caret",
|
|
3746
|
-
rawPosition: range.start
|
|
3747
|
-
}
|
|
3748
|
-
});
|
|
3636
|
+
store.edit.replace(range, "");
|
|
3749
3637
|
}
|
|
3750
3638
|
function handleBeforeInput(store, event) {
|
|
3751
|
-
|
|
3752
|
-
if (selecting === "all" && isFullSelection(store)) {
|
|
3639
|
+
if (store.caret.isAllSelected()) {
|
|
3753
3640
|
if (event.inputType === "insertFromPaste") {
|
|
3754
3641
|
event.preventDefault();
|
|
3755
3642
|
return;
|
|
@@ -3758,7 +3645,6 @@ function handleBeforeInput(store, event) {
|
|
|
3758
3645
|
replaceAllContentWith(store, event.inputType.startsWith("delete") ? "" : event.data ?? "");
|
|
3759
3646
|
return;
|
|
3760
3647
|
}
|
|
3761
|
-
if (selecting === "all") store.caret.selecting(void 0);
|
|
3762
3648
|
if (store.slots.isBlock()) return;
|
|
3763
3649
|
const raw = rawRangeFromInputEvent(store, event);
|
|
3764
3650
|
if (!raw.ok) return;
|
|
@@ -3767,13 +3653,7 @@ function handleBeforeInput(store, event) {
|
|
|
3767
3653
|
const range = rangeForInput(store, event, raw.value.range);
|
|
3768
3654
|
if (!range) return;
|
|
3769
3655
|
event.preventDefault();
|
|
3770
|
-
store.
|
|
3771
|
-
source: "input",
|
|
3772
|
-
recover: {
|
|
3773
|
-
kind: "caret",
|
|
3774
|
-
rawPosition: range.start + replacement.length
|
|
3775
|
-
}
|
|
3776
|
-
});
|
|
3656
|
+
store.edit.replace(range, replacement);
|
|
3777
3657
|
}
|
|
3778
3658
|
function rawRangeFromInputEvent(store, event) {
|
|
3779
3659
|
const ranges = getTargetRanges(event);
|
|
@@ -3843,55 +3723,60 @@ function adjacentMarkRange(tokens, position, backward) {
|
|
|
3843
3723
|
}
|
|
3844
3724
|
}
|
|
3845
3725
|
function handlePaste(store, event) {
|
|
3846
|
-
|
|
3847
|
-
if (selecting !== "all" || !isFullSelection(store)) {
|
|
3848
|
-
if (selecting === "all") store.caret.selecting(void 0);
|
|
3849
|
-
return;
|
|
3850
|
-
}
|
|
3726
|
+
if (!store.caret.isAllSelected()) return;
|
|
3851
3727
|
event.preventDefault();
|
|
3852
3728
|
const c = store.dom.container();
|
|
3853
3729
|
replaceAllContentWith(store, (c ? consumeMarkupPaste(c) : void 0) ?? event.clipboardData?.getData("text/plain") ?? "");
|
|
3854
3730
|
}
|
|
3855
3731
|
function replaceAllContentWith(store, newContent) {
|
|
3856
|
-
store.caret.
|
|
3857
|
-
store.value.
|
|
3858
|
-
source: "input",
|
|
3859
|
-
recover: {
|
|
3860
|
-
kind: "caret",
|
|
3861
|
-
rawPosition: newContent.length
|
|
3862
|
-
}
|
|
3863
|
-
});
|
|
3732
|
+
store.caret.position(newContent.length);
|
|
3733
|
+
store.value.current(newContent);
|
|
3864
3734
|
}
|
|
3865
3735
|
//#endregion
|
|
3866
|
-
//#region ../../core/src/features/keyboard/
|
|
3867
|
-
var
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3736
|
+
//#region ../../core/src/features/keyboard/KeyboardController.ts
|
|
3737
|
+
var KeyboardController = class {
|
|
3738
|
+
constructor(lifecycle, dom, value, caret, edit, slots, parsing, props) {
|
|
3739
|
+
const ctx = {
|
|
3740
|
+
dom,
|
|
3741
|
+
value,
|
|
3742
|
+
caret,
|
|
3743
|
+
edit,
|
|
3744
|
+
slots,
|
|
3745
|
+
parsing,
|
|
3746
|
+
props
|
|
3747
|
+
};
|
|
3748
|
+
lifecycle.onMounted(() => {
|
|
3749
|
+
enableInput(ctx);
|
|
3750
|
+
enableBlockEdit(ctx);
|
|
3751
|
+
enableArrowNav(ctx);
|
|
3752
|
+
});
|
|
3883
3753
|
}
|
|
3884
3754
|
};
|
|
3885
3755
|
//#endregion
|
|
3886
|
-
//#region ../../core/src/features/lifecycle/
|
|
3887
|
-
var
|
|
3756
|
+
//#region ../../core/src/features/lifecycle/Lifecycle.ts
|
|
3757
|
+
var Lifecycle = class {
|
|
3888
3758
|
constructor() {
|
|
3889
3759
|
this.mounted = event();
|
|
3890
3760
|
this.unmounted = event();
|
|
3891
3761
|
this.rendered = event();
|
|
3892
3762
|
}
|
|
3893
|
-
|
|
3894
|
-
|
|
3763
|
+
/**
|
|
3764
|
+
* Run `setup` when the editor is mounted. Any reactive subscription
|
|
3765
|
+
* created inside `setup` (`watch`, `listen`, `effect`, nested
|
|
3766
|
+
* `effectScope`) is automatically disposed on `unmounted` and re-created
|
|
3767
|
+
* on the next `mounted`.
|
|
3768
|
+
*/
|
|
3769
|
+
onMounted(setup) {
|
|
3770
|
+
let scope;
|
|
3771
|
+
watch(this.mounted, () => {
|
|
3772
|
+
if (scope) return;
|
|
3773
|
+
scope = effectScope(setup);
|
|
3774
|
+
});
|
|
3775
|
+
watch(this.unmounted, () => {
|
|
3776
|
+
scope?.();
|
|
3777
|
+
scope = void 0;
|
|
3778
|
+
});
|
|
3779
|
+
}
|
|
3895
3780
|
};
|
|
3896
3781
|
//#endregion
|
|
3897
3782
|
//#region ../../core/src/features/mark/MarkController.ts
|
|
@@ -3930,13 +3815,13 @@ var MarkController = class MarkController {
|
|
|
3930
3815
|
}
|
|
3931
3816
|
remove() {
|
|
3932
3817
|
const resolved = this.#resolve();
|
|
3933
|
-
if (!resolved
|
|
3934
|
-
|
|
3818
|
+
if (!resolved) return;
|
|
3819
|
+
this.store.value.replace(resolved.position, "");
|
|
3935
3820
|
}
|
|
3936
3821
|
update(patch) {
|
|
3937
3822
|
const resolved = this.#resolve();
|
|
3938
|
-
if (!resolved
|
|
3939
|
-
const token = resolved
|
|
3823
|
+
if (!resolved) return;
|
|
3824
|
+
const token = resolved;
|
|
3940
3825
|
const value = patch.value ?? token.value;
|
|
3941
3826
|
const meta = patch.meta?.kind === "clear" ? void 0 : patch.meta?.kind === "set" ? patch.meta.value : token.meta;
|
|
3942
3827
|
const slot = patch.slot?.kind === "clear" ? void 0 : patch.slot?.kind === "set" ? patch.slot.value : token.slot?.content;
|
|
@@ -3945,7 +3830,7 @@ var MarkController = class MarkController {
|
|
|
3945
3830
|
meta,
|
|
3946
3831
|
slot
|
|
3947
3832
|
});
|
|
3948
|
-
|
|
3833
|
+
this.store.value.replace(token.position, serialized);
|
|
3949
3834
|
}
|
|
3950
3835
|
#serialize(token, fields) {
|
|
3951
3836
|
return annotate(token.descriptor.markup, {
|
|
@@ -3955,19 +3840,10 @@ var MarkController = class MarkController {
|
|
|
3955
3840
|
});
|
|
3956
3841
|
}
|
|
3957
3842
|
#resolve() {
|
|
3958
|
-
if (this.store.props.readOnly()) return
|
|
3959
|
-
ok: false,
|
|
3960
|
-
reason: "readOnly"
|
|
3961
|
-
};
|
|
3843
|
+
if (this.store.props.readOnly()) return void 0;
|
|
3962
3844
|
const resolved = this.store.parsing.index().resolveAddress(this.address, this.#shape);
|
|
3963
|
-
if (!resolved.ok || resolved.value.type !== "mark") return
|
|
3964
|
-
|
|
3965
|
-
reason: "stale"
|
|
3966
|
-
};
|
|
3967
|
-
return {
|
|
3968
|
-
ok: true,
|
|
3969
|
-
value: resolved.value
|
|
3970
|
-
};
|
|
3845
|
+
if (!resolved.ok || resolved.value.type !== "mark") return void 0;
|
|
3846
|
+
return resolved.value;
|
|
3971
3847
|
}
|
|
3972
3848
|
};
|
|
3973
3849
|
//#endregion
|
|
@@ -4050,38 +3926,34 @@ function buildContainerProps(isDraggableBlock, readOnly, className, style, slotP
|
|
|
4050
3926
|
};
|
|
4051
3927
|
}
|
|
4052
3928
|
var SlotsFeature = class {
|
|
4053
|
-
constructor(
|
|
4054
|
-
this.
|
|
4055
|
-
this.isBlock = computed(() => this.
|
|
4056
|
-
this.isDraggable = computed(() => !!this.
|
|
4057
|
-
this.containerComponent = computed(() => resolveSlot("container", this.
|
|
4058
|
-
this.containerProps = computed(() => buildContainerProps(this.isDraggable() && this.isBlock(), this.
|
|
4059
|
-
this.blockComponent = computed(() => resolveSlot("block", this.
|
|
4060
|
-
this.blockProps = computed(() => resolveSlotProps("block", this.
|
|
4061
|
-
this.spanComponent = computed(() => resolveSlot("span", this.
|
|
4062
|
-
this.spanProps = computed(() => resolveSlotProps("span", this.
|
|
4063
|
-
}
|
|
4064
|
-
enable() {}
|
|
4065
|
-
disable() {}
|
|
3929
|
+
constructor(props) {
|
|
3930
|
+
this.props = props;
|
|
3931
|
+
this.isBlock = computed(() => this.props.layout() === "block");
|
|
3932
|
+
this.isDraggable = computed(() => !!this.props.draggable());
|
|
3933
|
+
this.containerComponent = computed(() => resolveSlot("container", this.props.slots()));
|
|
3934
|
+
this.containerProps = computed(() => buildContainerProps(this.isDraggable() && this.isBlock(), this.props.readOnly(), this.props.className(), this.props.style(), this.props.slotProps()), { equals: shallow });
|
|
3935
|
+
this.blockComponent = computed(() => resolveSlot("block", this.props.slots()));
|
|
3936
|
+
this.blockProps = computed(() => resolveSlotProps("block", this.props.slotProps()));
|
|
3937
|
+
this.spanComponent = computed(() => resolveSlot("span", this.props.slots()));
|
|
3938
|
+
this.spanProps = computed(() => resolveSlotProps("span", this.props.slotProps()));
|
|
3939
|
+
}
|
|
4066
3940
|
};
|
|
4067
3941
|
//#endregion
|
|
4068
3942
|
//#region ../../core/src/features/mark/MarkFeature.ts
|
|
4069
3943
|
var MarkFeature = class {
|
|
4070
|
-
constructor(
|
|
4071
|
-
this.
|
|
3944
|
+
constructor(props) {
|
|
3945
|
+
this.props = props;
|
|
4072
3946
|
this.enabled = computed(() => {
|
|
4073
|
-
if (this.
|
|
4074
|
-
return this.
|
|
3947
|
+
if (this.props.Mark()) return true;
|
|
3948
|
+
return this.props.options().some((opt) => "Mark" in opt && opt.Mark != null);
|
|
4075
3949
|
});
|
|
4076
3950
|
this.slot = computed(() => {
|
|
4077
|
-
const options = this.
|
|
4078
|
-
const Mark = this.
|
|
4079
|
-
const Span = this.
|
|
3951
|
+
const options = this.props.options();
|
|
3952
|
+
const Mark = this.props.Mark();
|
|
3953
|
+
const Span = this.props.Span();
|
|
4080
3954
|
return (token) => resolveMarkSlot(token, options, Mark, Span);
|
|
4081
3955
|
});
|
|
4082
3956
|
}
|
|
4083
|
-
enable() {}
|
|
4084
|
-
disable() {}
|
|
4085
3957
|
};
|
|
4086
3958
|
//#endregion
|
|
4087
3959
|
//#region ../../core/src/features/overlay/filterSuggestions.ts
|
|
@@ -4117,32 +3989,105 @@ function createMarkFromOverlay(match, value, meta) {
|
|
|
4117
3989
|
};
|
|
4118
3990
|
}
|
|
4119
3991
|
//#endregion
|
|
4120
|
-
//#region ../../core/src/features/overlay/
|
|
4121
|
-
var
|
|
3992
|
+
//#region ../../core/src/features/overlay/OverlayController.ts
|
|
3993
|
+
var OverlayController = class {
|
|
4122
3994
|
#scope;
|
|
4123
|
-
constructor(
|
|
4124
|
-
this.
|
|
3995
|
+
constructor(lifecycle, props, value, dom, caret, edit, parsing) {
|
|
3996
|
+
this.lifecycle = lifecycle;
|
|
3997
|
+
this.props = props;
|
|
3998
|
+
this.value = value;
|
|
3999
|
+
this.dom = dom;
|
|
4000
|
+
this.caret = caret;
|
|
4001
|
+
this.edit = edit;
|
|
4002
|
+
this.parsing = parsing;
|
|
4125
4003
|
this.match = signal(void 0);
|
|
4126
4004
|
this.element = signal(null);
|
|
4127
4005
|
this.slot = computed(() => {
|
|
4128
|
-
const Overlay = this.
|
|
4006
|
+
const Overlay = this.props.Overlay();
|
|
4129
4007
|
return (option, defaultComponent) => resolveOverlaySlot(Overlay, option, defaultComponent);
|
|
4130
4008
|
});
|
|
4131
4009
|
this.select = event();
|
|
4132
4010
|
this.close = event();
|
|
4011
|
+
this.position = computed(() => {
|
|
4012
|
+
if (!this.match()) return {
|
|
4013
|
+
left: 0,
|
|
4014
|
+
top: 0
|
|
4015
|
+
};
|
|
4016
|
+
const rect = getRect();
|
|
4017
|
+
if (!rect) return {
|
|
4018
|
+
left: 0,
|
|
4019
|
+
top: 0
|
|
4020
|
+
};
|
|
4021
|
+
return {
|
|
4022
|
+
left: rect.left,
|
|
4023
|
+
top: rect.top + rect.height + 1
|
|
4024
|
+
};
|
|
4025
|
+
});
|
|
4026
|
+
const hasOverlayTrigger = computed(() => this.props.options().some((opt) => opt.overlay?.trigger != null));
|
|
4027
|
+
const toggle = (enabled) => {
|
|
4028
|
+
if (enabled && !this.#scope) this.#scope = effectScope(() => {
|
|
4029
|
+
watch(this.close, () => {
|
|
4030
|
+
this.match(void 0);
|
|
4031
|
+
});
|
|
4032
|
+
watch(this.value.current, () => {
|
|
4033
|
+
const showOverlayOn = this.props.showOverlayOn();
|
|
4034
|
+
const type = "change";
|
|
4035
|
+
if (showOverlayOn === type || Array.isArray(showOverlayOn) && showOverlayOn.includes(type)) this.#probeTrigger();
|
|
4036
|
+
});
|
|
4037
|
+
effect(() => {
|
|
4038
|
+
if (this.match()) {
|
|
4039
|
+
listen(window, "keydown", (e) => {
|
|
4040
|
+
if (e.key === KEYBOARD.ESC) this.close();
|
|
4041
|
+
});
|
|
4042
|
+
listen(document, "click", (e) => {
|
|
4043
|
+
const target = e.target instanceof HTMLElement ? e.target : null;
|
|
4044
|
+
if (this.element()?.contains(target)) return;
|
|
4045
|
+
if (this.dom.container()?.contains(target)) return;
|
|
4046
|
+
this.close();
|
|
4047
|
+
}, true);
|
|
4048
|
+
}
|
|
4049
|
+
});
|
|
4050
|
+
const selectionChangeHandler = () => {
|
|
4051
|
+
if (!this.dom.container()?.contains(document.activeElement)) return;
|
|
4052
|
+
const showOverlayOn = this.props.showOverlayOn();
|
|
4053
|
+
const type = "selectionChange";
|
|
4054
|
+
if (showOverlayOn === type || Array.isArray(showOverlayOn) && showOverlayOn.includes(type)) this.#probeTrigger();
|
|
4055
|
+
};
|
|
4056
|
+
listen(document, "selectionchange", selectionChangeHandler);
|
|
4057
|
+
watch(this.select, (overlayEvent) => {
|
|
4058
|
+
const { mark, match: { option, range } } = overlayEvent;
|
|
4059
|
+
const markup = option.markup;
|
|
4060
|
+
if (!markup) return;
|
|
4061
|
+
const annotation = mark.type === "mark" ? annotate(markup, {
|
|
4062
|
+
value: mark.value,
|
|
4063
|
+
meta: mark.meta
|
|
4064
|
+
}) : annotate(markup, { value: mark.content });
|
|
4065
|
+
this.edit.replace(range, annotation);
|
|
4066
|
+
this.match(void 0);
|
|
4067
|
+
});
|
|
4068
|
+
});
|
|
4069
|
+
if (!enabled && this.#scope) {
|
|
4070
|
+
this.#scope();
|
|
4071
|
+
this.#scope = void 0;
|
|
4072
|
+
}
|
|
4073
|
+
};
|
|
4074
|
+
this.lifecycle.onMounted(() => {
|
|
4075
|
+
watch(hasOverlayTrigger, toggle);
|
|
4076
|
+
toggle(hasOverlayTrigger());
|
|
4077
|
+
});
|
|
4133
4078
|
}
|
|
4134
4079
|
#probeTrigger() {
|
|
4135
|
-
const match = TriggerFinder.find(this.
|
|
4080
|
+
const match = TriggerFinder.find(this.props.options(), (option) => option.overlay?.trigger, this.dom) ?? this.#probeTriggerFromCaretRange();
|
|
4136
4081
|
this.match(match);
|
|
4137
4082
|
}
|
|
4138
|
-
#
|
|
4139
|
-
const
|
|
4140
|
-
if (
|
|
4141
|
-
const
|
|
4142
|
-
const
|
|
4083
|
+
#probeTriggerFromCaretRange() {
|
|
4084
|
+
const sel = this.caret.selection();
|
|
4085
|
+
if (!sel || sel.start !== sel.end) return;
|
|
4086
|
+
const cursor = sel.start;
|
|
4087
|
+
const value = this.value.current();
|
|
4143
4088
|
const left = value.slice(0, cursor);
|
|
4144
4089
|
const rightWord = value.slice(cursor).match(/^\w*/)?.[0] ?? "";
|
|
4145
|
-
for (const option of this.
|
|
4090
|
+
for (const option of this.props.options()) {
|
|
4146
4091
|
const trigger = option.overlay?.trigger;
|
|
4147
4092
|
if (!trigger) continue;
|
|
4148
4093
|
const match = left.match(new RegExp(`${escape(trigger)}(\\w*)$`));
|
|
@@ -4158,65 +4103,11 @@ var OverlayFeature = class {
|
|
|
4158
4103
|
end: start + source.length
|
|
4159
4104
|
},
|
|
4160
4105
|
span: value,
|
|
4161
|
-
node: window.getSelection()?.anchorNode ?? this.
|
|
4106
|
+
node: window.getSelection()?.anchorNode ?? this.dom.container() ?? document.body,
|
|
4162
4107
|
option
|
|
4163
4108
|
};
|
|
4164
4109
|
}
|
|
4165
4110
|
}
|
|
4166
|
-
enable() {
|
|
4167
|
-
if (this.#scope) return;
|
|
4168
|
-
this.#scope = effectScope(() => {
|
|
4169
|
-
watch(this.close, () => {
|
|
4170
|
-
this.match(void 0);
|
|
4171
|
-
});
|
|
4172
|
-
watch(this._store.value.change, () => {
|
|
4173
|
-
const showOverlayOn = this._store.props.showOverlayOn();
|
|
4174
|
-
const type = "change";
|
|
4175
|
-
if (showOverlayOn === type || Array.isArray(showOverlayOn) && showOverlayOn.includes(type)) this.#probeTrigger();
|
|
4176
|
-
});
|
|
4177
|
-
alienEffect(() => {
|
|
4178
|
-
if (this.match()) {
|
|
4179
|
-
listen(window, "keydown", (e) => {
|
|
4180
|
-
if (e.key === KEYBOARD.ESC) this.close();
|
|
4181
|
-
});
|
|
4182
|
-
listen(document, "click", (e) => {
|
|
4183
|
-
const target = e.target instanceof HTMLElement ? e.target : null;
|
|
4184
|
-
if (this.element()?.contains(target)) return;
|
|
4185
|
-
if (this._store.dom.container()?.contains(target)) return;
|
|
4186
|
-
this.close();
|
|
4187
|
-
}, true);
|
|
4188
|
-
}
|
|
4189
|
-
});
|
|
4190
|
-
const selectionChangeHandler = () => {
|
|
4191
|
-
if (!this._store.dom.container()?.contains(document.activeElement)) return;
|
|
4192
|
-
const showOverlayOn = this._store.props.showOverlayOn();
|
|
4193
|
-
const type = "selectionChange";
|
|
4194
|
-
if (showOverlayOn === type || Array.isArray(showOverlayOn) && showOverlayOn.includes(type)) this.#probeTrigger();
|
|
4195
|
-
};
|
|
4196
|
-
listen(document, "selectionchange", selectionChangeHandler);
|
|
4197
|
-
watch(this.select, (overlayEvent) => {
|
|
4198
|
-
const { mark, match: { option, range } } = overlayEvent;
|
|
4199
|
-
const markup = option.markup;
|
|
4200
|
-
if (!markup) return;
|
|
4201
|
-
const annotation = mark.type === "mark" ? annotate(markup, {
|
|
4202
|
-
value: mark.value,
|
|
4203
|
-
meta: mark.meta
|
|
4204
|
-
}) : annotate(markup, { value: mark.content });
|
|
4205
|
-
this._store.value.replaceRange(range, annotation, {
|
|
4206
|
-
source: "overlay",
|
|
4207
|
-
recover: {
|
|
4208
|
-
kind: "caret",
|
|
4209
|
-
rawPosition: range.start + annotation.length
|
|
4210
|
-
}
|
|
4211
|
-
});
|
|
4212
|
-
this.match(void 0);
|
|
4213
|
-
});
|
|
4214
|
-
});
|
|
4215
|
-
}
|
|
4216
|
-
disable() {
|
|
4217
|
-
this.#scope?.();
|
|
4218
|
-
this.#scope = void 0;
|
|
4219
|
-
}
|
|
4220
4111
|
};
|
|
4221
4112
|
//#endregion
|
|
4222
4113
|
//#region ../../core/src/features/overlay/suggestionNavigation.ts
|
|
@@ -4249,10 +4140,9 @@ function navigateSuggestions(key, activeIndex, length) {
|
|
|
4249
4140
|
}
|
|
4250
4141
|
}
|
|
4251
4142
|
//#endregion
|
|
4252
|
-
//#region ../../core/src/features/props/
|
|
4253
|
-
var
|
|
4254
|
-
constructor(
|
|
4255
|
-
this._store = _store;
|
|
4143
|
+
//#region ../../core/src/features/props/PropsModel.ts
|
|
4144
|
+
var PropsModel = class {
|
|
4145
|
+
constructor() {
|
|
4256
4146
|
this.value = signal(void 0, { readonly: true });
|
|
4257
4147
|
this.defaultValue = signal(void 0, { readonly: true });
|
|
4258
4148
|
this.onChange = signal(void 0, { readonly: true });
|
|
@@ -4282,99 +4172,34 @@ var PropsFeature = class {
|
|
|
4282
4172
|
}
|
|
4283
4173
|
};
|
|
4284
4174
|
//#endregion
|
|
4285
|
-
//#region ../../core/src/features/value/
|
|
4286
|
-
var
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
this
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
}
|
|
4300
|
-
supersede() {
|
|
4301
|
-
this.#pending = void 0;
|
|
4302
|
-
}
|
|
4303
|
-
};
|
|
4304
|
-
//#endregion
|
|
4305
|
-
//#region ../../core/src/features/value/ValueFeature.ts
|
|
4306
|
-
var ValueFeature = class {
|
|
4307
|
-
#controlledEcho = new ControlledEcho();
|
|
4308
|
-
#scope;
|
|
4309
|
-
constructor(_store) {
|
|
4310
|
-
this._store = _store;
|
|
4311
|
-
this.current = signal("");
|
|
4312
|
-
this.isControlledMode = computed(() => this._store.props.value() !== void 0);
|
|
4313
|
-
this.change = event();
|
|
4314
|
-
}
|
|
4315
|
-
enable() {
|
|
4316
|
-
if (this.#scope) return;
|
|
4317
|
-
this.#commitAccepted(this._store.props.value() ?? this._store.props.defaultValue() ?? "");
|
|
4318
|
-
this.#scope = effectScope(() => {
|
|
4319
|
-
watch(this._store.props.value, (value) => {
|
|
4320
|
-
if (value === void 0) return;
|
|
4321
|
-
if (value === this.current()) return;
|
|
4322
|
-
const recovery = this.#controlledEcho.onEcho(value);
|
|
4323
|
-
this.#commitAccepted(value);
|
|
4324
|
-
if (recovery) this._store.caret.recovery(recovery);
|
|
4325
|
-
this.change();
|
|
4326
|
-
});
|
|
4175
|
+
//#region ../../core/src/features/value/ValueModel.ts
|
|
4176
|
+
var ValueModel = class {
|
|
4177
|
+
constructor(props) {
|
|
4178
|
+
this.props = props;
|
|
4179
|
+
this.isControlledMode = computed(() => this.props.value() !== void 0);
|
|
4180
|
+
this.current = model({
|
|
4181
|
+
default: () => this.props.defaultValue() ?? "",
|
|
4182
|
+
get: (value) => this.isControlledMode() ? this.props.value() ?? "" : value,
|
|
4183
|
+
set: (next, previous) => {
|
|
4184
|
+
if (next === void 0) return previous;
|
|
4185
|
+
if (this.props.readOnly()) return previous;
|
|
4186
|
+
this.props.onChange()?.(next);
|
|
4187
|
+
return this.isControlledMode() ? previous : next;
|
|
4188
|
+
}
|
|
4327
4189
|
});
|
|
4328
4190
|
}
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
reason: "invalidRange"
|
|
4342
|
-
};
|
|
4343
|
-
const candidate = current.slice(0, range.start) + replacement + current.slice(range.end);
|
|
4344
|
-
return this.#commitCandidate(candidate, options?.recover);
|
|
4345
|
-
}
|
|
4346
|
-
replaceAll(next, options) {
|
|
4347
|
-
return this.replaceRange({
|
|
4348
|
-
start: 0,
|
|
4349
|
-
end: this.current().length
|
|
4350
|
-
}, next, options);
|
|
4351
|
-
}
|
|
4352
|
-
#commitCandidate(candidate, recovery) {
|
|
4353
|
-
if (this.isControlledMode()) {
|
|
4354
|
-
this.#controlledEcho.propose(candidate, recovery);
|
|
4355
|
-
this._store.props.onChange()?.(candidate);
|
|
4356
|
-
return {
|
|
4357
|
-
ok: true,
|
|
4358
|
-
accepted: "pendingControlledEcho",
|
|
4359
|
-
value: candidate
|
|
4360
|
-
};
|
|
4361
|
-
}
|
|
4362
|
-
this._store.props.onChange()?.(candidate);
|
|
4363
|
-
this.#commitAccepted(candidate);
|
|
4364
|
-
this._store.caret.recovery(recovery);
|
|
4365
|
-
this.change();
|
|
4366
|
-
return {
|
|
4367
|
-
ok: true,
|
|
4368
|
-
accepted: "immediate",
|
|
4369
|
-
value: candidate
|
|
4370
|
-
};
|
|
4371
|
-
}
|
|
4372
|
-
#commitAccepted(value) {
|
|
4373
|
-
const tokens = this._store.parsing.parseValue(value);
|
|
4374
|
-
batch(() => {
|
|
4375
|
-
this._store.parsing.acceptTokens(tokens);
|
|
4376
|
-
this.current(value);
|
|
4377
|
-
});
|
|
4191
|
+
/**
|
|
4192
|
+
* Attempts to replace `range` with `replacement`. Returns `true` when the
|
|
4193
|
+
* edit was accepted (range valid and not read-only), `false` otherwise.
|
|
4194
|
+
* Callers use the return value to gate downstream side effects such as
|
|
4195
|
+
* caret placement.
|
|
4196
|
+
*/
|
|
4197
|
+
replace(range, replacement) {
|
|
4198
|
+
if (this.props.readOnly()) return false;
|
|
4199
|
+
const next = replaceInString(this.current(), range, replacement);
|
|
4200
|
+
if (next === void 0) return false;
|
|
4201
|
+
this.current(next);
|
|
4202
|
+
return true;
|
|
4378
4203
|
}
|
|
4379
4204
|
};
|
|
4380
4205
|
//#endregion
|
|
@@ -4554,34 +4379,20 @@ var Store = class {
|
|
|
4554
4379
|
constructor() {
|
|
4555
4380
|
this.key = new KeyGenerator();
|
|
4556
4381
|
this.blocks = new BlockRegistry();
|
|
4557
|
-
this.
|
|
4558
|
-
this.
|
|
4559
|
-
this.
|
|
4560
|
-
this.
|
|
4561
|
-
this.
|
|
4562
|
-
this.
|
|
4563
|
-
this.
|
|
4564
|
-
this.caret = new
|
|
4565
|
-
this.
|
|
4566
|
-
this.
|
|
4567
|
-
this.
|
|
4568
|
-
this.
|
|
4569
|
-
this.
|
|
4570
|
-
|
|
4571
|
-
this.lifecycle,
|
|
4572
|
-
this.value,
|
|
4573
|
-
this.mark,
|
|
4574
|
-
this.overlay,
|
|
4575
|
-
this.slots,
|
|
4576
|
-
this.caret,
|
|
4577
|
-
this.keyboard,
|
|
4578
|
-
this.dom,
|
|
4579
|
-
this.drag,
|
|
4580
|
-
this.clipboard,
|
|
4581
|
-
this.parsing
|
|
4582
|
-
];
|
|
4583
|
-
watch(this.lifecycle.mounted, () => features.forEach((f) => f.enable()));
|
|
4584
|
-
watch(this.lifecycle.unmounted, () => features.forEach((f) => f.disable()));
|
|
4382
|
+
this.lifecycle = new Lifecycle();
|
|
4383
|
+
this.props = new PropsModel();
|
|
4384
|
+
this.value = new ValueModel(this.props);
|
|
4385
|
+
this.mark = new MarkFeature(this.props);
|
|
4386
|
+
this.slots = new SlotsFeature(this.props);
|
|
4387
|
+
this.parsing = new ParseController(this.lifecycle, this.value, this.mark, this.props, this.slots);
|
|
4388
|
+
this.dom = new DomController(this.lifecycle, this.props, this.parsing, this.value);
|
|
4389
|
+
this.caret = new CaretModel(this.lifecycle, this.dom, this.value);
|
|
4390
|
+
this.edit = new EditController(this.value, this.caret);
|
|
4391
|
+
this.overlay = new OverlayController(this.lifecycle, this.props, this.value, this.dom, this.caret, this.edit, this.parsing);
|
|
4392
|
+
this.keyboard = new KeyboardController(this.lifecycle, this.dom, this.value, this.caret, this.edit, this.slots, this.parsing, this.props);
|
|
4393
|
+
this.drag = new DragController(this.props, this.value, this.parsing, this.caret);
|
|
4394
|
+
this.clipboard = new ClipboardController(this.lifecycle, this.edit, this.dom, this.parsing);
|
|
4395
|
+
this.handler = new MarkputHandler(this.dom, this.overlay, this.parsing);
|
|
4585
4396
|
}
|
|
4586
4397
|
};
|
|
4587
4398
|
//#endregion
|
|
@@ -4865,13 +4676,7 @@ function useOverlay() {
|
|
|
4865
4676
|
match: s.overlay.match,
|
|
4866
4677
|
overlay: s.overlay
|
|
4867
4678
|
}));
|
|
4868
|
-
const style =
|
|
4869
|
-
if (!match) return {
|
|
4870
|
-
left: 0,
|
|
4871
|
-
top: 0
|
|
4872
|
-
};
|
|
4873
|
-
return Caret.getAbsolutePosition();
|
|
4874
|
-
}, [match]);
|
|
4679
|
+
const style = useMarkput((s) => s.overlay.position());
|
|
4875
4680
|
const close = useCallback(() => overlay.close(), [overlay]);
|
|
4876
4681
|
return {
|
|
4877
4682
|
match,
|