vuewrite 0.0.19 → 0.0.21-a

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.
@@ -1,3 +1,3 @@
1
- {
2
- "recommendations": ["Vue.volar"]
3
- }
1
+ {
2
+ "recommendations": ["Vue.volar"]
3
+ }
package/README.md CHANGED
@@ -1,68 +1,68 @@
1
- # VueWrite
2
-
3
- VueWrite is another text editor that takes full advantage of Vue3's features.
4
- It contains no pre-made styles and blocks as its main goal is complete customization and extension
5
-
6
- ## Demo
7
-
8
- You can watch the demo [here](https://vuewrite.easix.ru)
9
-
10
- ## Quickstart
11
-
12
- ```vue
13
- <template>
14
- <TextEditor
15
- ref="textEditorRef"
16
- v-model="modelValue"
17
- single
18
- class="text-editor"
19
- :decorator="decorator"
20
- @keydown="onKeyDown"
21
- />
22
- </template>
23
-
24
- <script lang="ts">
25
- import { TextEditor, TextEditorRef } from 'vuewrite'
26
-
27
- const textEditorRef = shallowRef<TextEditorRef>()
28
- const modelValue = shallowRef("")
29
-
30
- const onKeyDown = (e: KeyboardEvent) => {
31
- if (!textEditorRef.value) return
32
- if ((e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey) {
33
- if (e.code === "KeyB") {
34
- textEditorRef.value.toggleStyle("bold")
35
- }
36
- if (e.code === "KeyI") {
37
- textEditorRef.value.toggleStyle("italic")
38
- }
39
- if (e.code === "KeyU") {
40
- textEditorRef.value.toggleStyle("underline")
41
- }
42
- }
43
- }
44
-
45
- const decorator = (style: Style) => {
46
- if (style.style === 'bold' || style.style === "underline" || style.style === "italic") {
47
- return { class: style.style }
48
- }
49
- }
50
-
51
- </script>
52
-
53
- <style lang="css">
54
- .text-editor {
55
- white-space: pre-wrap;
56
- }
57
- .text-editor .bold {
58
- font-weight: 700
59
- }
60
- .text-editor .italic {
61
- font-style: italic
62
- }
63
- .text-editor .underline {
64
- text-decoration: underline
65
- }
66
- </style>
67
-
1
+ # VueWrite
2
+
3
+ VueWrite is another text editor that takes full advantage of Vue3's features.
4
+ It contains no pre-made styles and blocks as its main goal is complete customization and extension
5
+
6
+ ## Demo
7
+
8
+ You can watch the demo [here](https://vuewrite.easix.ru)
9
+
10
+ ## Quickstart
11
+
12
+ ```vue
13
+ <template>
14
+ <TextEditor
15
+ ref="textEditorRef"
16
+ v-model="modelValue"
17
+ single
18
+ class="text-editor"
19
+ :decorator="decorator"
20
+ @keydown="onKeyDown"
21
+ />
22
+ </template>
23
+
24
+ <script lang="ts">
25
+ import { TextEditor, TextEditorRef } from 'vuewrite'
26
+
27
+ const textEditorRef = shallowRef<TextEditorRef>()
28
+ const modelValue = shallowRef("")
29
+
30
+ const onKeyDown = (e: KeyboardEvent) => {
31
+ if (!textEditorRef.value) return
32
+ if ((e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey) {
33
+ if (e.code === "KeyB") {
34
+ textEditorRef.value.toggleStyle("bold")
35
+ }
36
+ if (e.code === "KeyI") {
37
+ textEditorRef.value.toggleStyle("italic")
38
+ }
39
+ if (e.code === "KeyU") {
40
+ textEditorRef.value.toggleStyle("underline")
41
+ }
42
+ }
43
+ }
44
+
45
+ const decorator = (style: Style) => {
46
+ if (style.style === 'bold' || style.style === "underline" || style.style === "italic") {
47
+ return { class: style.style }
48
+ }
49
+ }
50
+
51
+ </script>
52
+
53
+ <style lang="css">
54
+ .text-editor {
55
+ white-space: pre-wrap;
56
+ }
57
+ .text-editor .bold {
58
+ font-weight: 700
59
+ }
60
+ .text-editor .italic {
61
+ font-style: italic
62
+ }
63
+ .text-editor .underline {
64
+ text-decoration: underline
65
+ }
66
+ </style>
67
+
68
68
  ```
@@ -40,11 +40,16 @@ export declare type Decorator = (style: Style) => HTMLAttributes & {
40
40
  } | undefined;
41
41
 
42
42
  declare type HistoryAction = {
43
- type: "insertText" | "setText";
43
+ type: string;
44
44
  blocks: Block[];
45
+ fullUpdate: boolean;
45
46
  selection: TextEditorSelection;
46
47
  };
47
48
 
49
+ declare type Renderer = (block: Block) => HTMLAttributes & {
50
+ tag?: string;
51
+ } | undefined;
52
+
48
53
  export declare type Style = {
49
54
  start: number;
50
55
  end: number;
@@ -54,6 +59,7 @@ export declare type Style = {
54
59
 
55
60
  export declare const TextEditor: __VLS_WithTemplateSlots<DefineComponent<__VLS_TypePropsToRuntimeProps<{
56
61
  decorator?: Decorator | undefined;
62
+ renderer?: Renderer | undefined;
57
63
  single?: boolean | undefined;
58
64
  modelValue?: string | {
59
65
  text: string;
@@ -99,7 +105,7 @@ insertBlock: (blockData: Partial<Block>) => void;
99
105
  addNewLine: () => void;
100
106
  removeNewLine: () => void;
101
107
  selectAll: () => void;
102
- pushHistory: (type: "insertText" | "setText") => void;
108
+ pushHistory: (type: string) => void;
103
109
  getClientRects: (selection: TextEditorSelection) => DOMRectList;
104
110
  }, unknown, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
105
111
  keydown: (...args: any[]) => void;
@@ -107,6 +113,7 @@ keydown: (...args: any[]) => void;
107
113
  "update:styles": (...args: any[]) => void;
108
114
  }, string, PublicProps, Readonly<ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
109
115
  decorator?: Decorator | undefined;
116
+ renderer?: Renderer | undefined;
110
117
  single?: boolean | undefined;
111
118
  modelValue?: string | {
112
119
  text: string;
@@ -129,8 +136,12 @@ onKeydown?: ((...args: any[]) => any) | undefined;
129
136
  declare class TextEditorHistory {
130
137
  actions: HistoryAction[];
131
138
  currentCursor: number;
139
+ private blocksIds;
140
+ private cachedBlocksJson;
132
141
  private store;
133
142
  constructor(store: TextEditorStore);
143
+ private cacheBlockIds;
144
+ private blockIdsChanged;
134
145
  tickStarted: boolean;
135
146
  push(type: HistoryAction["type"]): void;
136
147
  private applyAction;
@@ -242,6 +253,7 @@ declare class TextEditorStore {
242
253
  export declare const TextEditorView: DefineComponent<Readonly<{
243
254
  styles?: any;
244
255
  decorator?: any;
256
+ renderer?: any;
245
257
  parser?: any;
246
258
  modelValue?: any;
247
259
  }>, () => VNode<RendererNode, RendererElement, {
@@ -249,11 +261,13 @@ modelValue?: any;
249
261
  }>, unknown, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<ExtractPropTypes<Readonly<{
250
262
  styles?: any;
251
263
  decorator?: any;
264
+ renderer?: any;
252
265
  parser?: any;
253
266
  modelValue?: any;
254
267
  }>>>, {
255
268
  readonly styles?: any;
256
269
  readonly decorator?: any;
270
+ readonly renderer?: any;
257
271
  readonly parser?: any;
258
272
  readonly modelValue?: any;
259
273
  }, {}>;
package/dist/vuewrite.js CHANGED
@@ -4,7 +4,7 @@ var __publicField = (obj, key, value) => {
4
4
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
  return value;
6
6
  };
7
- import { getCurrentScope, onScopeDispose, unref, watch, nextTick, reactive, computed, ref, defineComponent, getCurrentInstance, h, useSlots, isProxy, toRaw, onMounted, openBlock, createElementBlock, Fragment, renderList, createBlock, renderSlot, createCommentVNode } from "vue";
7
+ import { getCurrentScope, onScopeDispose, unref, watch, reactive, computed, ref, defineComponent, getCurrentInstance, h, nextTick, useSlots, isProxy, toRaw, onMounted, openBlock, createElementBlock, Fragment, renderList, createBlock, renderSlot, createCommentVNode } from "vue";
8
8
  function tryOnScopeDispose(fn) {
9
9
  if (getCurrentScope()) {
10
10
  onScopeDispose(fn);
@@ -144,50 +144,57 @@ class TextEditorHistory {
144
144
  constructor(store) {
145
145
  __publicField(this, "actions", []);
146
146
  __publicField(this, "currentCursor", 0);
147
+ __publicField(this, "blocksIds", "");
148
+ __publicField(this, "cachedBlocksJson", "");
147
149
  __publicField(this, "store");
148
150
  __publicField(this, "tickStarted", false);
149
151
  this.store = store;
150
152
  window.showHistory = () => console.log(this.actions);
151
153
  }
154
+ cacheBlockIds() {
155
+ this.blocksIds = this.store.blocks.map((item) => item.id).join(",");
156
+ }
157
+ blockIdsChanged() {
158
+ return this.blocksIds !== this.store.blocks.map((item) => item.id).join(",");
159
+ }
152
160
  push(type) {
153
161
  var _a;
154
162
  if (this.currentCursor + 1 < this.actions.length) {
155
163
  this.actions.length = this.currentCursor + 1;
156
164
  }
157
- const lastAction = this.actions.length > 0 && this.currentCursor === this.actions.length - 1 ? this.actions[this.actions.length - 1] : null;
165
+ const lastAction = this.actions.length > 0 ? this.actions[this.actions.length - 1] : null;
158
166
  const selection = JSON.parse(JSON.stringify(this.store.selection));
159
- if (type === "insertText") {
167
+ const fullUpdate = type === "setText" || type === "addNewLine" || this.blockIdsChanged();
168
+ const blocksJson = JSON.stringify(this.store.blocks);
169
+ if (!fullUpdate && this.store.currentBlock) {
160
170
  const currentBlock = JSON.parse(JSON.stringify(this.store.currentBlock));
161
- if (lastAction && lastAction.type === type && ((_a = lastAction.blocks[0]) == null ? void 0 : _a.id) === currentBlock.id) {
171
+ if (lastAction && lastAction.type === type && ((_a = lastAction.blocks[0]) == null ? void 0 : _a.id) === currentBlock.id && (lastAction.type === "insertText" || lastAction.type === "deleteContentBackward" || lastAction.type === "deleteContentForward")) {
162
172
  lastAction.blocks = [currentBlock];
163
173
  lastAction.selection = selection;
164
174
  } else {
165
- this.actions.push({ type, blocks: [currentBlock], selection });
166
- }
167
- } else if (type === "setText") {
168
- const blocks = JSON.parse(JSON.stringify(this.store.blocks));
169
- if (this.tickStarted && lastAction) {
170
- lastAction.blocks = blocks;
171
- lastAction.selection = selection;
172
- } else {
173
- this.actions.push({ type: "setText", blocks, selection });
175
+ this.actions.push({ type, blocks: [currentBlock], selection, fullUpdate });
174
176
  }
177
+ } else {
178
+ this.actions.push({ type, blocks: JSON.parse(blocksJson), selection, fullUpdate });
175
179
  }
176
180
  this.currentCursor = this.actions.length - 1;
177
- if (!this.tickStarted && type === "setText") {
178
- this.tickStarted = true;
179
- nextTick(() => {
180
- this.tickStarted = false;
181
- });
181
+ if (fullUpdate) {
182
+ if (lastAction && !lastAction.fullUpdate) {
183
+ lastAction.fullUpdate = true;
184
+ lastAction.blocks = JSON.parse(this.cachedBlocksJson);
185
+ }
186
+ this.cacheBlockIds();
182
187
  }
188
+ this.cachedBlocksJson = blocksJson;
183
189
  }
184
190
  applyAction(action) {
185
- if (action.type === "setText") {
191
+ if (action.fullUpdate) {
186
192
  for (let i = 0; i < action.blocks.length; i++) {
187
193
  if (i >= this.store.blocks.length) {
188
194
  this.store.blocks.push({ ...action.blocks[i] });
189
195
  } else {
190
196
  Object.assign(this.store.blocks[i], action.blocks[i]);
197
+ this.store.blocks[i].type = action.blocks[i].type;
191
198
  }
192
199
  }
193
200
  if (this.store.blocks.length > action.blocks.length) {
@@ -198,10 +205,13 @@ class TextEditorHistory {
198
205
  const block = this.store.blocks.find((block2) => block2.id === _block.id);
199
206
  if (block) {
200
207
  block.text = _block.text;
208
+ block.styles = _block.styles;
209
+ block.type = _block.type;
201
210
  }
202
211
  }
203
212
  }
204
213
  Object.assign(this.store.selection, action.selection);
214
+ this.cacheBlockIds();
205
215
  }
206
216
  undo() {
207
217
  if (this.currentCursor === 0)
@@ -301,7 +311,6 @@ class TextEditorStore {
301
311
  this.concatBlocks(this.blocks[blockIndex - 1], this.blocks[blockIndex]);
302
312
  this.blocks.splice(blockIndex, 1);
303
313
  }
304
- this.history.push("setText");
305
314
  }
306
315
  onInput(_e) {
307
316
  const ev = _e;
@@ -327,6 +336,7 @@ class TextEditorStore {
327
336
  block.text = block.text.slice(0, offset) + block.text.slice(this.selection.focus.offset);
328
337
  this.moveOffset(offset);
329
338
  }
339
+ this.history.push("deleteContentBackward");
330
340
  }
331
341
  if (ev.inputType === "deleteContentForward") {
332
342
  const blockIndex = this.blocks.findIndex((item) => item.id === this.selection.anchor.blockId);
@@ -334,12 +344,13 @@ class TextEditorStore {
334
344
  const nextBlock = this.blocks[blockIndex + 1];
335
345
  if (nextBlock) {
336
346
  this.blocks.splice(blockIndex + 1, 1);
337
- this.concatBlocks(this.blocks[blockIndex - 1], this.blocks[blockIndex]);
347
+ this.concatBlocks(this.blocks[blockIndex], nextBlock);
338
348
  }
339
349
  } else {
340
350
  block.text = block.text.slice(0, this.selection.focus.offset) + block.text.slice(this.selection.focus.offset + 1);
341
351
  this.moveStyles(block, this.selection.focus.offset + 1, 1);
342
352
  }
353
+ this.history.push("deleteContentForward");
343
354
  }
344
355
  }
345
356
  if (ev.inputType === "insertText") {
@@ -352,6 +363,7 @@ class TextEditorStore {
352
363
  const index2 = this.blocks.findIndex((item) => item.id === this.selection.anchor.blockId);
353
364
  const block2 = { id: uid(), text: "", styles: [] };
354
365
  this.blocks.splice(index2, 0, block2);
366
+ this.history.push("addNewLine");
355
367
  return;
356
368
  }
357
369
  this.deleteSelected();
@@ -364,7 +376,7 @@ class TextEditorStore {
364
376
  this.blocks.splice(index + 1, 0, block);
365
377
  this.selection.anchor = { blockId: block.id, offset: 0 };
366
378
  this.selection.focus = { blockId: block.id, offset: 0 };
367
- this.history.push("setText");
379
+ this.history.push("addNewLine");
368
380
  }
369
381
  addNewLineAfter() {
370
382
  const index = this.blocks.findIndex((item) => item.id === this.selection.anchor.blockId);
@@ -448,6 +460,8 @@ class TextEditorStore {
448
460
  return this._currentStyles.value;
449
461
  }
450
462
  applyStyle(_style, meta) {
463
+ if (this.isCollapsed)
464
+ return;
451
465
  const [start, end, startIndex, endIndex] = this.startAndEnd;
452
466
  for (let i = startIndex; i <= endIndex; i++) {
453
467
  const block = this.blocks[i];
@@ -481,6 +495,7 @@ class TextEditorStore {
481
495
  block.styles.sort((a, b) => a.start - b.start);
482
496
  }
483
497
  }
498
+ this.history.push("applyStyle");
484
499
  }
485
500
  removeStyleAt(block, _start, _end, _style) {
486
501
  const removeAll = typeof _style !== "string";
@@ -511,6 +526,7 @@ class TextEditorStore {
511
526
  const _end = i === endIndex ? end.offset : block.text.length;
512
527
  this.removeStyleAt(block, _start, _end, _style);
513
528
  }
529
+ this.history.push("applyStyle");
514
530
  }
515
531
  removeAllStyles() {
516
532
  const [start, end, startIndex, endIndex] = this.startAndEnd;
@@ -541,7 +557,7 @@ class TextEditorStore {
541
557
  let uidCounter = 0;
542
558
  const uid = () => (uidCounter++).toString();
543
559
  const _sfc_main$2 = defineComponent({
544
- props: ["block", "slots", "static", "decorator", "parser"],
560
+ props: ["block", "slots", "static", "decorator", "renderer", "parser"],
545
561
  emits: ["postrender"],
546
562
  setup(props, { emit }) {
547
563
  const slot = computed(() => {
@@ -549,9 +565,6 @@ const _sfc_main$2 = defineComponent({
549
565
  return props.slots["default"] ?? null;
550
566
  return props.slots[props.block.type] ?? null;
551
567
  });
552
- const blockProps = {
553
- "data-vw-block-id": props.block.id
554
- };
555
568
  const instance = getCurrentInstance();
556
569
  const getRef = () => {
557
570
  if (!instance)
@@ -675,25 +688,144 @@ const _sfc_main$2 = defineComponent({
675
688
  elementTag = tag;
676
689
  }
677
690
  }
678
- if (Object.keys(attrs).length === 0)
691
+ if (Object.keys(attrs).length === 0 && elementTag === "span")
679
692
  return text;
680
693
  return h(elementTag, attrs, text);
681
694
  };
682
695
  return () => {
696
+ let elementTag = "div";
697
+ const blockProps = {
698
+ "data-vw-block-id": props.block.id
699
+ };
700
+ const additionalProps = props.renderer && props.renderer(props.block);
701
+ if (additionalProps) {
702
+ if (additionalProps.tag) {
703
+ elementTag = additionalProps.tag;
704
+ delete additionalProps.tag;
705
+ }
706
+ Object.assign(blockProps, additionalProps);
707
+ }
683
708
  if (slot.value) {
684
709
  const component = slot.value({ content, props: blockProps, block: props.block });
685
710
  if (Array.isArray(component) && component.length === 1)
686
711
  return component[0];
687
712
  return component;
688
713
  }
689
- return h("div", blockProps, content());
714
+ return h(elementTag, blockProps, content());
690
715
  };
691
716
  }
692
717
  });
718
+ const createClipboardEvents = (store, props) => {
719
+ const getSelected = () => {
720
+ const [start, end, startIndex, endIndex] = store.startAndEnd;
721
+ if (startIndex === endIndex) {
722
+ const text2 = store.blocks[startIndex].text.slice(start.offset, end.offset);
723
+ return [
724
+ new ClipboardItem({
725
+ "text/plain": new Blob([text2], { type: "text/plain" })
726
+ })
727
+ ];
728
+ }
729
+ const startText = store.blocks[startIndex].text.slice(start.offset);
730
+ const endText = store.blocks[endIndex].text.slice(0, end.offset);
731
+ const arr = [
732
+ { type: store.blocks[startIndex].type, text: startText },
733
+ ...store.blocks.slice(startIndex + 1, endIndex),
734
+ { type: store.blocks[endIndex].type, text: endText }
735
+ ];
736
+ const html = arr.map((item) => `<div>${item.text}</div>`).join("\n");
737
+ const text = arr.map((item) => item.text).join("\n");
738
+ return [
739
+ new ClipboardItem({
740
+ "text/html": new Blob([html], { type: "text/html" }),
741
+ "text/plain": new Blob([text], { type: "text/plain" })
742
+ })
743
+ ];
744
+ };
745
+ const onCopy = (e) => {
746
+ if (e.defaultPrevented)
747
+ return;
748
+ e.preventDefault();
749
+ navigator.clipboard.write(getSelected());
750
+ store.history.push("setText");
751
+ };
752
+ const onCut = (e) => {
753
+ if (e.defaultPrevented)
754
+ return;
755
+ e.preventDefault();
756
+ navigator.clipboard.write(getSelected());
757
+ store.deleteSelected();
758
+ store.history.push("setText");
759
+ };
760
+ const insertText = (text) => {
761
+ if (props.preventMultiline) {
762
+ const blocks = text.split("\n");
763
+ store.insertText(blocks[0]);
764
+ for (let i = 1; i < blocks.length; i++) {
765
+ store.addNewLine();
766
+ store.insertText(blocks[i]);
767
+ }
768
+ } else {
769
+ store.insertText(text);
770
+ }
771
+ };
772
+ const parseHtml = (node) => {
773
+ var _a;
774
+ let isTextNode = false;
775
+ for (let _node of node.childNodes) {
776
+ if (_node.nodeType === Node.TEXT_NODE && ((_a = _node.textContent) == null ? void 0 : _a.trim()) || _node.nodeType == Node.ELEMENT_NODE && _node.tagName === "SPAN") {
777
+ isTextNode = true;
778
+ break;
779
+ }
780
+ }
781
+ if (isTextNode) {
782
+ const text = node.textContent;
783
+ if (!text)
784
+ return;
785
+ insertText(text);
786
+ store.addNewLine();
787
+ return;
788
+ }
789
+ for (let child of node.children) {
790
+ if (child.tagName === "DIV") {
791
+ parseHtml(child);
792
+ } else {
793
+ insertText(child.textContent ?? "");
794
+ store.addNewLine();
795
+ }
796
+ }
797
+ };
798
+ const parser = new DOMParser();
799
+ const onPaste = (e) => {
800
+ var _a, _b;
801
+ if (e.defaultPrevented)
802
+ return;
803
+ e.preventDefault();
804
+ const html = (_a = e.clipboardData) == null ? void 0 : _a.getData("text/html");
805
+ if (html) {
806
+ store.deleteSelected();
807
+ const dom = parser.parseFromString(html, "text/html");
808
+ parseHtml(dom.body);
809
+ } else {
810
+ const text = (_b = e.clipboardData) == null ? void 0 : _b.getData("text");
811
+ if (!text)
812
+ return;
813
+ store.deleteSelected();
814
+ insertText(text);
815
+ }
816
+ store.history.push("setText");
817
+ };
818
+ return {
819
+ onCopy,
820
+ onCut,
821
+ onPaste
822
+ };
823
+ };
693
824
  const _sfc_main$1 = /* @__PURE__ */ defineComponent({
694
825
  __name: "TextEditor",
695
826
  props: {
696
827
  decorator: { type: Function },
828
+ renderer: { type: Function },
697
829
  single: { type: Boolean },
698
830
  modelValue: {},
699
831
  parser: { type: Function },
@@ -856,41 +988,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
856
988
  }
857
989
  store.history.push("setText");
858
990
  });
859
- const onCopy = (e) => {
860
- if (e.defaultPrevented)
861
- return;
862
- e.preventDefault();
863
- navigator.clipboard.writeText(store.selectedText);
864
- store.history.push("setText");
865
- };
866
- const onCut = (e) => {
867
- if (e.defaultPrevented)
868
- return;
869
- e.preventDefault();
870
- navigator.clipboard.writeText(store.selectedText);
871
- store.deleteSelected();
872
- store.history.push("setText");
873
- };
874
- const onPaste = (e) => {
875
- var _a;
876
- if (e.defaultPrevented)
877
- return;
878
- e.preventDefault();
879
- const text = (_a = e.clipboardData) == null ? void 0 : _a.getData("Text");
880
- if (!text)
881
- return;
882
- if (props.preventMultiline) {
883
- const blocks = text.split("\n");
884
- store.insertText(blocks[0]);
885
- for (let i = 1; i < blocks.length; i++) {
886
- store.addNewLine();
887
- store.insertText(blocks[i]);
888
- }
889
- } else {
890
- store.insertText(text);
891
- }
892
- store.history.push("setText");
893
- };
991
+ const { onCut, onCopy, onPaste } = createClipboardEvents(store, props);
894
992
  const getClientRects = (selection) => {
895
993
  const anchor = getNode(selection.anchor.blockId);
896
994
  const focus = getNode(selection.focus.blockId);
@@ -927,19 +1025,23 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
927
1025
  onBeforeinput: _cache[0] || (_cache[0] = //@ts-ignore
928
1026
  (...args) => unref(store).onInput && unref(store).onInput(...args)),
929
1027
  onKeydown: onKeyDown,
930
- onCopy,
931
- onPaste,
932
- onCut
1028
+ onCopy: _cache[1] || (_cache[1] = //@ts-ignore
1029
+ (...args) => unref(onCopy) && unref(onCopy)(...args)),
1030
+ onPaste: _cache[2] || (_cache[2] = //@ts-ignore
1031
+ (...args) => unref(onPaste) && unref(onPaste)(...args)),
1032
+ onCut: _cache[3] || (_cache[3] = //@ts-ignore
1033
+ (...args) => unref(onCut) && unref(onCut)(...args))
933
1034
  }, [
934
1035
  (openBlock(true), createElementBlock(Fragment, null, renderList(unref(store).blocks, (block) => {
935
1036
  return openBlock(), createBlock(_sfc_main$2, {
936
1037
  key: block.id,
937
1038
  block,
938
1039
  slots: unref(slots),
1040
+ renderer: props.renderer,
939
1041
  decorator: props.decorator,
940
1042
  parser: props.parser,
941
1043
  onPostrender: onPostRender
942
- }, null, 8, ["block", "slots", "decorator", "parser"]);
1044
+ }, null, 8, ["block", "slots", "renderer", "decorator", "parser"]);
943
1045
  }), 128)),
944
1046
  unref(store).blocks.length === 1 && unref(store).blocks[0].text === "" && !unref(store).blocks[0].type ? renderSlot(_ctx.$slots, "placeholder", { key: 0 }) : createCommentVNode("", true)
945
1047
  ], 544);
@@ -947,7 +1049,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
947
1049
  }
948
1050
  });
949
1051
  const _sfc_main = defineComponent({
950
- props: ["modelValue", "decorator", "parser", "styles"],
1052
+ props: ["modelValue", "decorator", "parser", "styles", "renderer"],
951
1053
  setup(props, { slots }) {
952
1054
  const blocks = computed(() => {
953
1055
  if (Array.isArray(props.modelValue)) {
@@ -960,6 +1062,7 @@ const _sfc_main = defineComponent({
960
1062
  block,
961
1063
  slots,
962
1064
  decorator: props.decorator,
1065
+ renderer: props.renderer,
963
1066
  parser: props.parser,
964
1067
  static: true
965
1068
  })));
package/package.json CHANGED
@@ -1,38 +1,39 @@
1
- {
2
- "name": "vuewrite",
3
- "description": "Rich Text Editor based on Vue3 reactivity",
4
- "private": false,
5
- "version": "0.0.19",
6
- "type": "module",
7
- "license": "MIT",
8
- "author": "den59k",
9
- "repository": {
10
- "type": "git",
11
- "url": "https://github.com/den59k/vuewrite.git"
12
- },
13
- "main": "dist/vuewrite.js",
14
- "types": "dist/vuewrite.d.ts",
15
- "scripts": {
16
- "dev": "vite",
17
- "build": "vue-tsc && vite build",
18
- "build:app": "vue-tsc && vite build -c vite-app.config.ts",
19
- "preview": "vite preview"
20
- },
21
- "dependencies": {
22
- "vue": "^3"
23
- },
24
- "devDependencies": {
25
- "@vitejs/plugin-vue": "^5.0.4",
26
- "@vueuse/core": "^10.10.0",
27
- "color2k": "^2.0.3",
28
- "sass": "^1.77.2",
29
- "typescript": "^5.2.2",
30
- "vite": "^5.2.0",
31
- "vite-plugin-dts": "^3.9.1",
32
- "vue-tsc": "^2.0.6",
33
- "vuesix": "^1.0.12"
34
- },
35
- "files": [
36
- "dist"
37
- ]
38
- }
1
+ {
2
+ "name": "vuewrite",
3
+ "description": "Rich Text Editor based on Vue3 reactivity",
4
+ "private": false,
5
+ "version": "0.0.21-a",
6
+ "type": "module",
7
+ "license": "MIT",
8
+ "author": "den59k",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/den59k/vuewrite.git"
12
+ },
13
+ "main": "dist/vuewrite.js",
14
+ "types": "dist/vuewrite.d.ts",
15
+ "scripts": {
16
+ "dev": "vite",
17
+ "build": "vue-tsc && vite build",
18
+ "build:app": "vue-tsc && vite build -c vite-app.config.ts",
19
+ "preview": "vite preview"
20
+ },
21
+ "dependencies": {
22
+ "vue": "^3",
23
+ "vuewrite": "^0.0.19"
24
+ },
25
+ "devDependencies": {
26
+ "@vitejs/plugin-vue": "^5.0.4",
27
+ "@vueuse/core": "^10.10.0",
28
+ "color2k": "^2.0.3",
29
+ "sass": "^1.77.2",
30
+ "typescript": "^5.2.2",
31
+ "vite": "^5.2.0",
32
+ "vite-plugin-dts": "^3.9.1",
33
+ "vue-tsc": "^2.0.6",
34
+ "vuesix": "^1.0.12"
35
+ },
36
+ "files": [
37
+ "dist"
38
+ ]
39
+ }