vuewrite 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/vuewrite.d.ts +25 -1
- package/dist/vuewrite.js +90 -30
- package/package.json +1 -1
package/dist/vuewrite.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export declare type Block = {
|
|
|
29
29
|
text: string;
|
|
30
30
|
type?: string;
|
|
31
31
|
styles: Style[];
|
|
32
|
+
editable?: boolean;
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
export declare type Decorator = (style: Style) => HTMLAttributes | undefined;
|
|
@@ -63,6 +64,7 @@ end: number;
|
|
|
63
64
|
style: string;
|
|
64
65
|
meta?: any;
|
|
65
66
|
}[];
|
|
67
|
+
editable?: boolean | undefined;
|
|
66
68
|
} | null>;
|
|
67
69
|
isCollapsed: ComputedRef<boolean>;
|
|
68
70
|
selection: {
|
|
@@ -80,7 +82,11 @@ toggleStyle: (style: string) => void;
|
|
|
80
82
|
applyStyle: (_style: string, meta?: any) => void;
|
|
81
83
|
removeStyle: (_style: string) => void;
|
|
82
84
|
insertText: (data: string) => void;
|
|
85
|
+
insertBlock: (blockData: Partial<Block>) => void;
|
|
86
|
+
addNewLine: () => void;
|
|
87
|
+
removeNewLine: () => void;
|
|
83
88
|
selectAll: () => void;
|
|
89
|
+
getClientRects: (selection: TextEditorSelection) => DOMRectList;
|
|
84
90
|
}, unknown, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
|
|
85
91
|
keydown: (...args: any[]) => void;
|
|
86
92
|
"update:modelValue": (...args: any[]) => void;
|
|
@@ -104,8 +110,20 @@ onKeydown?: ((...args: any[]) => any) | undefined;
|
|
|
104
110
|
placeholder?(_: {}): any;
|
|
105
111
|
}>;
|
|
106
112
|
|
|
107
|
-
export declare type TextEditorRef = Pick<TextEditorStore, "currentStyles" | "currentBlock" | "isCollapsed" | "selection" | "toggleStyle" | "applyStyle" | "removeStyle" | "insertText" | "selectAll"> & {
|
|
113
|
+
export declare type TextEditorRef = Pick<TextEditorStore, "currentStyles" | "currentBlock" | "isCollapsed" | "selection" | "toggleStyle" | "applyStyle" | "removeStyle" | "insertText" | "insertBlock" | "addNewLine" | "removeNewLine" | "selectAll"> & {
|
|
108
114
|
isFocused: boolean;
|
|
115
|
+
getClientRects: (selection: TextEditorSelection) => DOMRectList;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
declare type TextEditorSelection = {
|
|
119
|
+
anchor: {
|
|
120
|
+
blockId: string;
|
|
121
|
+
offset: number;
|
|
122
|
+
};
|
|
123
|
+
focus: {
|
|
124
|
+
blockId: string;
|
|
125
|
+
offset: number;
|
|
126
|
+
};
|
|
109
127
|
};
|
|
110
128
|
|
|
111
129
|
declare class TextEditorStore {
|
|
@@ -119,6 +137,7 @@ declare class TextEditorStore {
|
|
|
119
137
|
style: string;
|
|
120
138
|
meta?: any;
|
|
121
139
|
}[];
|
|
140
|
+
editable?: boolean | undefined;
|
|
122
141
|
}[];
|
|
123
142
|
selection: {
|
|
124
143
|
anchor: {
|
|
@@ -143,6 +162,7 @@ declare class TextEditorStore {
|
|
|
143
162
|
style: string;
|
|
144
163
|
meta?: any;
|
|
145
164
|
}[];
|
|
165
|
+
editable?: boolean | undefined;
|
|
146
166
|
} | null>;
|
|
147
167
|
get currentBlock(): {
|
|
148
168
|
id: string;
|
|
@@ -154,13 +174,17 @@ declare class TextEditorStore {
|
|
|
154
174
|
style: string;
|
|
155
175
|
meta?: any;
|
|
156
176
|
}[];
|
|
177
|
+
editable?: boolean | undefined;
|
|
157
178
|
} | null;
|
|
158
179
|
_selectedText: ComputedRef<string>;
|
|
159
180
|
get selectedText(): string;
|
|
160
181
|
moveOffset(newOffset: number): void;
|
|
182
|
+
concatBlocks(start: Block, end: Block): void;
|
|
183
|
+
removeNewLine(): void;
|
|
161
184
|
onInput(_e: Event): void;
|
|
162
185
|
addNewLine(): void;
|
|
163
186
|
insertText(data: string): void;
|
|
187
|
+
insertBlock(blockData: Partial<Block>): void;
|
|
164
188
|
get startAndEnd(): [{
|
|
165
189
|
blockId: string;
|
|
166
190
|
offset: number;
|
package/dist/vuewrite.js
CHANGED
|
@@ -202,8 +202,33 @@ class TextEditorStore {
|
|
|
202
202
|
this.selection.anchor.offset = newOffset;
|
|
203
203
|
this.selection.focus.offset = newOffset;
|
|
204
204
|
}
|
|
205
|
+
concatBlocks(start, end) {
|
|
206
|
+
for (let style of end.styles) {
|
|
207
|
+
style.start += start.text.length;
|
|
208
|
+
style.end += start.text.length;
|
|
209
|
+
start.styles.push(style);
|
|
210
|
+
}
|
|
211
|
+
start.text = start.text + end.text;
|
|
212
|
+
}
|
|
213
|
+
removeNewLine() {
|
|
214
|
+
const blockIndex = this.blocks.findIndex((item) => item.id === this.selection.anchor.blockId);
|
|
215
|
+
if (blockIndex < 1)
|
|
216
|
+
return;
|
|
217
|
+
if (this.blocks[blockIndex - 1].editable === false) {
|
|
218
|
+
this.blocks.splice(blockIndex - 1, 1);
|
|
219
|
+
} else {
|
|
220
|
+
this.concatBlocks(this.blocks[blockIndex - 1], this.blocks[blockIndex]);
|
|
221
|
+
this.blocks.splice(blockIndex, 1);
|
|
222
|
+
}
|
|
223
|
+
this.selection.anchor.blockId = this.blocks[blockIndex - 1].id;
|
|
224
|
+
this.selection.focus.blockId = this.blocks[blockIndex - 1].id;
|
|
225
|
+
this.selection.anchor.offset = this.blocks[blockIndex - 1].text.length;
|
|
226
|
+
this.selection.focus.offset = this.blocks[blockIndex - 1].text.length;
|
|
227
|
+
}
|
|
205
228
|
onInput(_e) {
|
|
206
229
|
const ev = _e;
|
|
230
|
+
if (ev.defaultPrevented)
|
|
231
|
+
return;
|
|
207
232
|
ev.preventDefault();
|
|
208
233
|
const collapsed = this.isCollapsed;
|
|
209
234
|
if (!collapsed)
|
|
@@ -212,15 +237,12 @@ class TextEditorStore {
|
|
|
212
237
|
if (!block)
|
|
213
238
|
return;
|
|
214
239
|
if ((ev.inputType === "deleteContentBackward" || ev.inputType === "deleteContentForward") && collapsed) {
|
|
215
|
-
const blockIndex = this.blocks.findIndex((item) => item.id === this.selection.anchor.blockId);
|
|
216
240
|
if (ev.inputType === "deleteContentBackward") {
|
|
217
241
|
if (this.selection.anchor.offset === 0) {
|
|
218
|
-
if (
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
this.
|
|
222
|
-
this.selection.focus.offset = this.blocks[blockIndex - 1].text.length;
|
|
223
|
-
this.blocks.splice(blockIndex, 1);
|
|
242
|
+
if (block.type) {
|
|
243
|
+
delete block.type;
|
|
244
|
+
} else {
|
|
245
|
+
this.removeNewLine();
|
|
224
246
|
}
|
|
225
247
|
} else {
|
|
226
248
|
const offset = Math.max(0, this.selection.focus.offset - 1);
|
|
@@ -229,8 +251,13 @@ class TextEditorStore {
|
|
|
229
251
|
}
|
|
230
252
|
}
|
|
231
253
|
if (ev.inputType === "deleteContentForward") {
|
|
254
|
+
const blockIndex = this.blocks.findIndex((item) => item.id === this.selection.anchor.blockId);
|
|
232
255
|
if (this.selection.anchor.offset === this.blocks[blockIndex].text.length) {
|
|
233
|
-
this.blocks
|
|
256
|
+
const nextBlock = this.blocks[blockIndex + 1];
|
|
257
|
+
if (nextBlock) {
|
|
258
|
+
this.blocks.splice(blockIndex + 1, 1);
|
|
259
|
+
this.concatBlocks(this.blocks[blockIndex - 1], this.blocks[blockIndex]);
|
|
260
|
+
}
|
|
234
261
|
} else {
|
|
235
262
|
block.text = block.text.slice(0, this.selection.focus.offset) + block.text.slice(this.selection.focus.offset + 1);
|
|
236
263
|
this.moveStyles(block, this.selection.focus.offset + 1, 1);
|
|
@@ -260,6 +287,23 @@ class TextEditorStore {
|
|
|
260
287
|
block.text = block.text.slice(0, this.selection.focus.offset) + data + block.text.slice(this.selection.focus.offset);
|
|
261
288
|
this.moveOffset(clamp(this.selection.focus.offset + data.length, 0, block.text.length));
|
|
262
289
|
}
|
|
290
|
+
insertBlock(blockData) {
|
|
291
|
+
if (!this.currentBlock)
|
|
292
|
+
return;
|
|
293
|
+
this.deleteSelected();
|
|
294
|
+
if (this.currentBlock.text !== "") {
|
|
295
|
+
this.addNewLine();
|
|
296
|
+
}
|
|
297
|
+
if (this.currentBlock.text !== "") {
|
|
298
|
+
const selection = JSON.parse(JSON.stringify(this.selection));
|
|
299
|
+
this.addNewLine();
|
|
300
|
+
Object.assign(this.selection, selection);
|
|
301
|
+
}
|
|
302
|
+
Object.assign(this.currentBlock, blockData);
|
|
303
|
+
if (blockData.editable === false && this.currentBlock === this.blocks[this.blocks.length - 1]) {
|
|
304
|
+
this.addNewLine();
|
|
305
|
+
}
|
|
306
|
+
}
|
|
263
307
|
get startAndEnd() {
|
|
264
308
|
const a = this.blocks.findIndex((block) => block.id === this.selection.anchor.blockId);
|
|
265
309
|
const f = this.blocks.findIndex((block) => block.id === this.selection.focus.blockId);
|
|
@@ -487,6 +531,8 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
487
531
|
};
|
|
488
532
|
const content = () => {
|
|
489
533
|
const block = props.block;
|
|
534
|
+
if (block.editable === false)
|
|
535
|
+
return null;
|
|
490
536
|
if (block.text.length === 0) {
|
|
491
537
|
cleanTree(1);
|
|
492
538
|
return [h("br")];
|
|
@@ -609,11 +655,6 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
609
655
|
store.addNewLine();
|
|
610
656
|
}
|
|
611
657
|
}
|
|
612
|
-
if (e.code === "Backspace") {
|
|
613
|
-
if (store.isCollapsed && store.currentBlock === store.blocks[0] && store.selection.anchor.offset === 0) {
|
|
614
|
-
e.preventDefault();
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
658
|
if ((e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey) {
|
|
618
659
|
if (e.code === "KeyB" || e.code === "KeyI" || e.code === "KeyU") {
|
|
619
660
|
e.preventDefault();
|
|
@@ -623,21 +664,22 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
623
664
|
let cachedSelection = {};
|
|
624
665
|
useEventListener(document, "selectionchange", () => {
|
|
625
666
|
const sel = window.getSelection();
|
|
626
|
-
const anchor = findParent(sel.anchorNode, (el) => el.hasAttribute("data-vw-block-id"));
|
|
667
|
+
const anchor = findParent(sel.anchorNode, (el) => el.hasAttribute("data-vw-block-id") && el.parentElement === textEditorRef.value);
|
|
627
668
|
if (anchor) {
|
|
628
669
|
const offset = anchor === sel.anchorNode ? 0 : calcOffsetToNode(anchor, sel.anchorNode) + sel.anchorOffset;
|
|
629
670
|
store.selection.anchor = { blockId: anchor.getAttribute("data-vw-block-id"), offset };
|
|
630
671
|
}
|
|
631
|
-
const focus = findParent(sel.focusNode, (el) => el.hasAttribute("data-vw-block-id"));
|
|
672
|
+
const focus = findParent(sel.focusNode, (el) => el.hasAttribute("data-vw-block-id") && el.parentElement === textEditorRef.value);
|
|
632
673
|
if (focus) {
|
|
633
674
|
const offset = anchor === sel.focusNode ? 0 : calcOffsetToNode(focus, sel.focusNode) + sel.focusOffset;
|
|
634
675
|
store.selection.focus = { blockId: focus.getAttribute("data-vw-block-id"), offset };
|
|
635
676
|
}
|
|
636
|
-
if (store.isFocused.value !== !!focus || !!anchor) {
|
|
677
|
+
if (store.isFocused.value !== (!!focus || !!anchor)) {
|
|
637
678
|
store.isFocused.value = !!focus || !!anchor;
|
|
638
679
|
}
|
|
639
|
-
if (!anchor && !focus)
|
|
680
|
+
if (!anchor && !focus) {
|
|
640
681
|
cachedSelection = JSON.parse(JSON.stringify(store.selection));
|
|
682
|
+
}
|
|
641
683
|
});
|
|
642
684
|
let postRendered = false;
|
|
643
685
|
const onPostRender = () => {
|
|
@@ -650,6 +692,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
650
692
|
postRendered = false;
|
|
651
693
|
});
|
|
652
694
|
};
|
|
695
|
+
const getNode = (blockId) => {
|
|
696
|
+
for (let item of textEditorRef.value.children) {
|
|
697
|
+
if (item.getAttribute("data-vw-block-id") === blockId) {
|
|
698
|
+
return item;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
return null;
|
|
702
|
+
};
|
|
653
703
|
const applySelection = () => {
|
|
654
704
|
if (!store.isFocused.value) {
|
|
655
705
|
cachedSelection = JSON.parse(JSON.stringify(store.selection));
|
|
@@ -657,17 +707,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
657
707
|
}
|
|
658
708
|
if (isEqual(store.selection, cachedSelection))
|
|
659
709
|
return;
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
let focus = null;
|
|
663
|
-
for (let item of textEditorRef.value.children) {
|
|
664
|
-
if (item.getAttribute("data-vw-block-id") === store.selection.anchor.blockId) {
|
|
665
|
-
anchor = item;
|
|
666
|
-
}
|
|
667
|
-
if (item.getAttribute("data-vw-block-id") === store.selection.focus.blockId) {
|
|
668
|
-
focus = item;
|
|
669
|
-
}
|
|
710
|
+
if (store.selection.anchor.blockId === store.selection.focus.blockId && store.currentBlock && store.currentBlock.editable === false) {
|
|
711
|
+
return;
|
|
670
712
|
}
|
|
713
|
+
const anchor = getNode(store.selection.anchor.blockId);
|
|
714
|
+
const focus = getNode(store.selection.focus.blockId);
|
|
715
|
+
const nativeSelection = window.getSelection();
|
|
671
716
|
if (anchor && focus) {
|
|
672
717
|
nativeSelection.setBaseAndExtent(
|
|
673
718
|
...calcNodeByOffset(anchor, store.selection.anchor.offset),
|
|
@@ -705,6 +750,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
705
750
|
return;
|
|
706
751
|
store.insertText(text);
|
|
707
752
|
};
|
|
753
|
+
const getClientRects = (selection) => {
|
|
754
|
+
const anchor = getNode(selection.anchor.blockId);
|
|
755
|
+
const focus = getNode(selection.focus.blockId);
|
|
756
|
+
if (anchor && focus) {
|
|
757
|
+
const range = new Range();
|
|
758
|
+
range.setStart(...calcNodeByOffset(anchor, selection.anchor.offset));
|
|
759
|
+
range.setEnd(...calcNodeByOffset(focus, selection.focus.offset));
|
|
760
|
+
return range.getClientRects();
|
|
761
|
+
}
|
|
762
|
+
return new DOMRectList();
|
|
763
|
+
};
|
|
708
764
|
__expose({
|
|
709
765
|
currentStyles: store._currentStyles,
|
|
710
766
|
currentBlock: store._currentBlock,
|
|
@@ -715,14 +771,18 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
715
771
|
applyStyle: store.applyStyle.bind(store),
|
|
716
772
|
removeStyle: store.removeStyle.bind(store),
|
|
717
773
|
insertText: store.insertText.bind(store),
|
|
718
|
-
|
|
774
|
+
insertBlock: store.insertBlock.bind(store),
|
|
775
|
+
addNewLine: store.addNewLine.bind(store),
|
|
776
|
+
removeNewLine: store.removeNewLine.bind(store),
|
|
777
|
+
selectAll: store.selectAll.bind(store),
|
|
778
|
+
getClientRects
|
|
719
779
|
});
|
|
720
780
|
return (_ctx, _cache) => {
|
|
721
781
|
return openBlock(), createElementBlock("div", {
|
|
722
782
|
ref_key: "textEditorRef",
|
|
723
783
|
ref: textEditorRef,
|
|
724
784
|
contenteditable: "",
|
|
725
|
-
|
|
785
|
+
onBeforeinput: _cache[0] || (_cache[0] = //@ts-ignore
|
|
726
786
|
(...args) => unref(store).onInput && unref(store).onInput(...args)),
|
|
727
787
|
onKeydown: onKeyDown,
|
|
728
788
|
onCopy,
|
|
@@ -738,7 +798,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
738
798
|
onPostrender: onPostRender
|
|
739
799
|
}, null, 8, ["block", "slots", "decorator"]);
|
|
740
800
|
}), 128)),
|
|
741
|
-
unref(store).blocks.length === 1 && unref(store).blocks[0].text === "" ? renderSlot(_ctx.$slots, "placeholder", { key: 0 }) : createCommentVNode("", true)
|
|
801
|
+
unref(store).blocks.length === 1 && unref(store).blocks[0].text === "" && !unref(store).blocks[0].type ? renderSlot(_ctx.$slots, "placeholder", { key: 0 }) : createCommentVNode("", true)
|
|
742
802
|
], 544);
|
|
743
803
|
};
|
|
744
804
|
}
|