vuewrite 0.0.21 → 0.0.22-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.
@@ -31,7 +31,7 @@ export declare type Block = {
31
31
  id: string;
32
32
  text: string;
33
33
  type?: string;
34
- styles: Style[];
34
+ styles?: Style[];
35
35
  editable?: boolean;
36
36
  };
37
37
 
@@ -46,7 +46,7 @@ declare type HistoryAction = {
46
46
  selection: TextEditorSelection;
47
47
  };
48
48
 
49
- declare type Modifier = (block: Block) => HTMLAttributes & {
49
+ declare type Renderer = (block: Block) => HTMLAttributes & {
50
50
  tag?: string;
51
51
  } | undefined;
52
52
 
@@ -59,7 +59,7 @@ export declare type Style = {
59
59
 
60
60
  export declare const TextEditor: __VLS_WithTemplateSlots<DefineComponent<__VLS_TypePropsToRuntimeProps<{
61
61
  decorator?: Decorator | undefined;
62
- modifier?: Modifier | undefined;
62
+ renderer?: Renderer | undefined;
63
63
  single?: boolean | undefined;
64
64
  modelValue?: string | {
65
65
  text: string;
@@ -77,12 +77,12 @@ currentBlock: ComputedRef< {
77
77
  id: string;
78
78
  text: string;
79
79
  type?: string | undefined;
80
- styles: {
80
+ styles?: {
81
81
  start: number;
82
82
  end: number;
83
83
  style: string;
84
84
  meta?: any;
85
- }[];
85
+ }[] | undefined;
86
86
  editable?: boolean | undefined;
87
87
  } | null>;
88
88
  isCollapsed: ComputedRef<boolean>;
@@ -104,6 +104,7 @@ insertText: (data: string) => void;
104
104
  insertBlock: (blockData: Partial<Block>) => void;
105
105
  addNewLine: () => void;
106
106
  removeNewLine: () => void;
107
+ removeCurrentBlock: () => void;
107
108
  selectAll: () => void;
108
109
  pushHistory: (type: string) => void;
109
110
  getClientRects: (selection: TextEditorSelection) => DOMRectList;
@@ -113,7 +114,7 @@ keydown: (...args: any[]) => void;
113
114
  "update:styles": (...args: any[]) => void;
114
115
  }, string, PublicProps, Readonly<ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
115
116
  decorator?: Decorator | undefined;
116
- modifier?: Modifier | undefined;
117
+ renderer?: Renderer | undefined;
117
118
  single?: boolean | undefined;
118
119
  modelValue?: string | {
119
120
  text: string;
@@ -149,7 +150,7 @@ declare class TextEditorHistory {
149
150
  redo(): void;
150
151
  }
151
152
 
152
- export declare type TextEditorRef = Pick<TextEditorStore, "currentStyles" | "currentBlock" | "isCollapsed" | "selection" | "toggleStyle" | "applyStyle" | "removeStyle" | "insertText" | "insertBlock" | "addNewLine" | "removeNewLine" | "selectAll"> & {
153
+ export declare type TextEditorRef = Pick<TextEditorStore, "currentStyles" | "currentBlock" | "isCollapsed" | "selection" | "toggleStyle" | "applyStyle" | "removeStyle" | "insertText" | "insertBlock" | "addNewLine" | "removeNewLine" | "selectAll" | "removeCurrentBlock"> & {
153
154
  isFocused: boolean;
154
155
  getClientRects: (selection: TextEditorSelection) => DOMRectList;
155
156
  pushHistory: TextEditorHistory["push"];
@@ -172,12 +173,12 @@ declare class TextEditorStore {
172
173
  id: string;
173
174
  text: string;
174
175
  type?: string | undefined;
175
- styles: {
176
+ styles?: {
176
177
  start: number;
177
178
  end: number;
178
179
  style: string;
179
180
  meta?: any;
180
- }[];
181
+ }[] | undefined;
181
182
  editable?: boolean | undefined;
182
183
  }[];
183
184
  selection: {
@@ -197,37 +198,39 @@ declare class TextEditorStore {
197
198
  id: string;
198
199
  text: string;
199
200
  type?: string | undefined;
200
- styles: {
201
+ styles?: {
201
202
  start: number;
202
203
  end: number;
203
204
  style: string;
204
205
  meta?: any;
205
- }[];
206
+ }[] | undefined;
206
207
  editable?: boolean | undefined;
207
208
  } | null>;
208
209
  get currentBlock(): {
209
210
  id: string;
210
211
  text: string;
211
212
  type?: string | undefined;
212
- styles: {
213
+ styles?: {
213
214
  start: number;
214
215
  end: number;
215
216
  style: string;
216
217
  meta?: any;
217
- }[];
218
+ }[] | undefined;
218
219
  editable?: boolean | undefined;
219
220
  } | null;
220
221
  _selectedText: ComputedRef<string>;
221
222
  get selectedText(): string;
222
223
  moveOffset(newOffset: number): void;
224
+ private addStyleToBlock;
223
225
  concatBlocks(start: Block, end: Block): void;
226
+ removeCurrentBlock(): void;
224
227
  removeNewLine(): void;
225
228
  onInput(_e: Event): void;
229
+ addNewLineBefore(): void;
226
230
  addNewLine(): void;
227
231
  addNewLineAfter(): {
228
232
  id: string;
229
233
  text: string;
230
- styles: never[];
231
234
  };
232
235
  insertText(data: string): void;
233
236
  insertBlock(blockData: Partial<Block>): void;
@@ -253,7 +256,7 @@ declare class TextEditorStore {
253
256
  export declare const TextEditorView: DefineComponent<Readonly<{
254
257
  styles?: any;
255
258
  decorator?: any;
256
- modifier?: any;
259
+ renderer?: any;
257
260
  parser?: any;
258
261
  modelValue?: any;
259
262
  }>, () => VNode<RendererNode, RendererElement, {
@@ -261,13 +264,13 @@ modelValue?: any;
261
264
  }>, unknown, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<ExtractPropTypes<Readonly<{
262
265
  styles?: any;
263
266
  decorator?: any;
264
- modifier?: any;
267
+ renderer?: any;
265
268
  parser?: any;
266
269
  modelValue?: any;
267
270
  }>>>, {
268
271
  readonly styles?: any;
269
272
  readonly decorator?: any;
270
- readonly modifier?: any;
273
+ readonly renderer?: any;
271
274
  readonly parser?: any;
272
275
  readonly modelValue?: any;
273
276
  }, {}>;
package/dist/vuewrite.js CHANGED
@@ -261,7 +261,10 @@ class TextEditorStore {
261
261
  if (startIndex < 0)
262
262
  return styles;
263
263
  for (let i = startIndex; i <= endIndex; i++) {
264
- for (let style of this.blocks[i].styles) {
264
+ const blockStyles = this.blocks[i].styles;
265
+ if (!blockStyles)
266
+ continue;
267
+ for (let style of blockStyles) {
265
268
  if (i === startIndex && start.offset < style.start)
266
269
  continue;
267
270
  if (i === endIndex && end.offset > style.end)
@@ -289,25 +292,56 @@ class TextEditorStore {
289
292
  this.selection.anchor.offset = newOffset;
290
293
  this.selection.focus.offset = newOffset;
291
294
  }
295
+ addStyleToBlock(block, style) {
296
+ if (!block.styles) {
297
+ block.styles = [style];
298
+ } else {
299
+ block.styles.push(style);
300
+ }
301
+ block.styles.sort((a, b) => a.start - b.start);
302
+ }
292
303
  concatBlocks(start, end) {
293
- for (let style of end.styles) {
294
- style.start += start.text.length;
295
- style.end += start.text.length;
296
- start.styles.push(style);
304
+ if (end.styles) {
305
+ for (let style of end.styles) {
306
+ style.start += start.text.length;
307
+ style.end += start.text.length;
308
+ this.addStyleToBlock(start, style);
309
+ }
297
310
  }
298
311
  start.text = start.text + end.text;
299
312
  }
313
+ removeCurrentBlock() {
314
+ const blockIndex = this.blocks.findIndex((item) => item.id === this.selection.anchor.blockId);
315
+ if (blockIndex < 0)
316
+ return;
317
+ this.blocks.splice(blockIndex, 1);
318
+ if (this.blocks.length === 0) {
319
+ this.blocks.push({ id: uid(), text: "" });
320
+ }
321
+ const newBlockIndex = Math.max(blockIndex - 1, 0);
322
+ this.selection.anchor.blockId = this.blocks[newBlockIndex].id;
323
+ this.selection.focus.blockId = this.blocks[newBlockIndex].id;
324
+ this.selection.anchor.offset = blockIndex === 0 ? 0 : this.blocks[newBlockIndex].text.length;
325
+ this.selection.focus.offset = blockIndex === 0 ? 0 : this.blocks[newBlockIndex].text.length;
326
+ this.history.push("removeBlock");
327
+ }
300
328
  removeNewLine() {
301
329
  const blockIndex = this.blocks.findIndex((item) => item.id === this.selection.anchor.blockId);
302
330
  if (blockIndex < 1)
303
331
  return;
304
- this.selection.anchor.blockId = this.blocks[blockIndex - 1].id;
305
- this.selection.focus.blockId = this.blocks[blockIndex - 1].id;
306
- this.selection.anchor.offset = this.blocks[blockIndex - 1].text.length;
307
- this.selection.focus.offset = this.blocks[blockIndex - 1].text.length;
308
332
  if (this.blocks[blockIndex - 1].editable === false) {
309
- this.blocks.splice(blockIndex - 1, 1);
333
+ if (this.blocks[blockIndex].text === "") {
334
+ this.blocks.splice(blockIndex, 1);
335
+ }
336
+ this.selection.anchor.blockId = this.blocks[blockIndex - 1].id;
337
+ this.selection.focus.blockId = this.blocks[blockIndex - 1].id;
338
+ this.selection.anchor.offset = 0;
339
+ this.selection.focus.offset = 0;
310
340
  } else {
341
+ this.selection.anchor.blockId = this.blocks[blockIndex - 1].id;
342
+ this.selection.focus.blockId = this.blocks[blockIndex - 1].id;
343
+ this.selection.anchor.offset = this.blocks[blockIndex - 1].text.length;
344
+ this.selection.focus.offset = this.blocks[blockIndex - 1].text.length;
311
345
  this.concatBlocks(this.blocks[blockIndex - 1], this.blocks[blockIndex]);
312
346
  this.blocks.splice(blockIndex, 1);
313
347
  }
@@ -358,20 +392,24 @@ class TextEditorStore {
358
392
  this.history.push("insertText");
359
393
  }
360
394
  }
395
+ addNewLineBefore() {
396
+ const index = this.blocks.findIndex((item) => item.id === this.selection.anchor.blockId);
397
+ const block = { id: uid(), text: "" };
398
+ this.blocks.splice(index, 0, block);
399
+ this.history.push("addNewLine");
400
+ }
361
401
  addNewLine() {
362
- if (this.isCollapsed && this.selection.anchor.offset === 0) {
363
- const index2 = this.blocks.findIndex((item) => item.id === this.selection.anchor.blockId);
364
- const block2 = { id: uid(), text: "", styles: [] };
365
- this.blocks.splice(index2, 0, block2);
366
- this.history.push("addNewLine");
402
+ var _a;
403
+ if (this.isCollapsed && this.selection.anchor.offset === 0 && ((_a = this.currentBlock) == null ? void 0 : _a.editable) !== false) {
404
+ this.addNewLineBefore();
367
405
  return;
368
406
  }
369
407
  this.deleteSelected();
370
408
  if (!this.currentBlock)
371
409
  return;
372
- const endText = this.currentBlock.text.slice(this.selection.anchor.offset);
410
+ const endText = this.currentBlock.editable === false ? "" : this.currentBlock.text.slice(this.selection.anchor.offset);
373
411
  this.currentBlock.text = this.currentBlock.text.slice(0, this.selection.anchor.offset);
374
- const block = { id: uid(), text: endText || "", styles: [] };
412
+ const block = { id: uid(), text: endText || "" };
375
413
  const index = this.blocks.findIndex((item) => item.id === this.selection.anchor.blockId);
376
414
  this.blocks.splice(index + 1, 0, block);
377
415
  this.selection.anchor = { blockId: block.id, offset: 0 };
@@ -380,7 +418,7 @@ class TextEditorStore {
380
418
  }
381
419
  addNewLineAfter() {
382
420
  const index = this.blocks.findIndex((item) => item.id === this.selection.anchor.blockId);
383
- const block = { id: uid(), text: "", styles: [] };
421
+ const block = { id: uid(), text: "" };
384
422
  this.blocks.splice(index + 1, 0, block);
385
423
  return block;
386
424
  }
@@ -424,6 +462,8 @@ class TextEditorStore {
424
462
  }
425
463
  }
426
464
  moveStyles(block, offset, delta) {
465
+ if (!block.styles)
466
+ return;
427
467
  for (let i = 0; i < block.styles.length; i++) {
428
468
  const style = block.styles[i];
429
469
  if (style.start >= offset)
@@ -468,20 +508,22 @@ class TextEditorStore {
468
508
  const _start = i === startIndex ? start.offset : 0;
469
509
  const _end = i === endIndex ? end.offset : block.text.length;
470
510
  let createNewStyle = true;
471
- for (let style of block.styles) {
472
- if (style.style !== _style)
473
- continue;
474
- if (style.start > _end || style.end < _start)
475
- continue;
476
- if (meta && !isEqual(meta, style.meta) && (style.start !== _start || style.end !== _end)) {
477
- if (_start === style.end || _end === style.start)
511
+ if (block.styles) {
512
+ for (let style of block.styles) {
513
+ if (style.style !== _style)
478
514
  continue;
479
- this.removeStyleAt(block, _start, _end, _style);
480
- } else {
481
- style.start = Math.min(style.start, _start);
482
- style.end = Math.max(style.end, _end);
483
- createNewStyle = false;
484
- style.meta = meta;
515
+ if (style.start > _end || style.end < _start)
516
+ continue;
517
+ if (meta && !isEqual(meta, style.meta) && (style.start !== _start || style.end !== _end)) {
518
+ if (_start === style.end || _end === style.start)
519
+ continue;
520
+ this.removeStyleAt(block, _start, _end, _style);
521
+ } else {
522
+ style.start = Math.min(style.start, _start);
523
+ style.end = Math.max(style.end, _end);
524
+ createNewStyle = false;
525
+ style.meta = meta;
526
+ }
485
527
  }
486
528
  }
487
529
  if (createNewStyle) {
@@ -491,14 +533,15 @@ class TextEditorStore {
491
533
  style: _style,
492
534
  meta
493
535
  };
494
- block.styles.push(newStyle);
495
- block.styles.sort((a, b) => a.start - b.start);
536
+ this.addStyleToBlock(block, newStyle);
496
537
  }
497
538
  }
498
539
  this.history.push("applyStyle");
499
540
  }
500
541
  removeStyleAt(block, _start, _end, _style) {
501
542
  const removeAll = typeof _style !== "string";
543
+ if (!block.styles)
544
+ return;
502
545
  for (let i = 0; i < block.styles.length; i++) {
503
546
  const style = block.styles[i];
504
547
  if (!removeAll && style.style !== _style)
@@ -517,6 +560,9 @@ class TextEditorStore {
517
560
  style.start = _end;
518
561
  }
519
562
  }
563
+ if (block.styles.length === 0) {
564
+ delete block.styles;
565
+ }
520
566
  }
521
567
  removeStyle(_style) {
522
568
  const [start, end, startIndex, endIndex] = this.startAndEnd;
@@ -533,7 +579,7 @@ class TextEditorStore {
533
579
  for (let i = startIndex; i <= endIndex; i++) {
534
580
  const block = this.blocks[i];
535
581
  if (i > startIndex && i < endIndex) {
536
- block.styles.length = 0;
582
+ delete block.styles;
537
583
  return;
538
584
  }
539
585
  const _start = i === startIndex ? start.offset : 0;
@@ -557,7 +603,7 @@ class TextEditorStore {
557
603
  let uidCounter = 0;
558
604
  const uid = () => (uidCounter++).toString();
559
605
  const _sfc_main$2 = defineComponent({
560
- props: ["block", "slots", "static", "decorator", "modifier", "parser"],
606
+ props: ["block", "slots", "static", "decorator", "renderer", "parser"],
561
607
  emits: ["postrender"],
562
608
  setup(props, { emit }) {
563
609
  const slot = computed(() => {
@@ -697,7 +743,7 @@ const _sfc_main$2 = defineComponent({
697
743
  const blockProps = {
698
744
  "data-vw-block-id": props.block.id
699
745
  };
700
- const additionalProps = props.modifier && props.modifier(props.block);
746
+ const additionalProps = props.renderer && props.renderer(props.block);
701
747
  if (additionalProps) {
702
748
  if (additionalProps.tag) {
703
749
  elementTag = additionalProps.tag;
@@ -825,7 +871,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
825
871
  __name: "TextEditor",
826
872
  props: {
827
873
  decorator: { type: Function },
828
- modifier: { type: Function },
874
+ renderer: { type: Function },
829
875
  single: { type: Boolean },
830
876
  modelValue: {},
831
877
  parser: { type: Function },
@@ -852,13 +898,11 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
852
898
  return;
853
899
  } else {
854
900
  for (let i = store.blocks.length; i < newValue.length; i++) {
855
- store.blocks.push({ id: uid(), text: "", styles: [] });
901
+ store.blocks.push({ id: uid(), text: "" });
856
902
  }
857
903
  store.blocks.length = newValue.length;
858
904
  for (let i = 0; i < newValue.length; i++) {
859
- store.blocks[i].text = newValue[i].text;
860
- store.blocks[i].type = newValue[i].type;
861
- store.blocks[i].styles = newValue[i].styles ?? [];
905
+ store.blocks[i] = { ...newValue[i], id: uid() };
862
906
  }
863
907
  }
864
908
  }, { immediate: true });
@@ -879,12 +923,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
879
923
  emit("update:styles", styles);
880
924
  emit("update:modelValue", modelValue);
881
925
  } else {
882
- modelValue = store.blocks.map((item) => ({
883
- type: item.type,
884
- text: item.text,
885
- styles: item.styles.length === 0 ? void 0 : item.styles
886
- }));
887
- emit("update:modelValue", modelValue);
926
+ emit("update:modelValue", store.blocks);
888
927
  }
889
928
  }, { deep: true });
890
929
  const onKeyDown = (e) => {
@@ -955,15 +994,13 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
955
994
  return null;
956
995
  };
957
996
  const applySelection = () => {
997
+ var _a;
958
998
  if (!store.isFocused.value) {
959
999
  cachedSelection = JSON.parse(JSON.stringify(store.selection));
960
1000
  return;
961
1001
  }
962
1002
  if (isEqual(store.selection, cachedSelection))
963
1003
  return;
964
- if (store.selection.anchor.blockId === store.selection.focus.blockId && store.currentBlock && store.currentBlock.editable === false) {
965
- return;
966
- }
967
1004
  const anchor = getNode(store.selection.anchor.blockId);
968
1005
  const focus = getNode(store.selection.focus.blockId);
969
1006
  const nativeSelection = window.getSelection();
@@ -973,6 +1010,12 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
973
1010
  ...calcNodeByOffset(focus, store.selection.focus.offset)
974
1011
  );
975
1012
  }
1013
+ if (store.selection.anchor.blockId === store.selection.focus.blockId && ((_a = store.currentBlock) == null ? void 0 : _a.editable) === false) {
1014
+ const innerText = anchor == null ? void 0 : anchor.querySelector("[data-vw-block-id]");
1015
+ if (innerText) {
1016
+ nativeSelection.setBaseAndExtent(innerText, 0, innerText, 0);
1017
+ }
1018
+ }
976
1019
  cachedSelection = JSON.parse(JSON.stringify(store.selection));
977
1020
  };
978
1021
  watch(() => store.selection, applySelection, { deep: true, flush: "post" });
@@ -1013,6 +1056,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1013
1056
  insertBlock: store.insertBlock.bind(store),
1014
1057
  addNewLine: store.addNewLine.bind(store),
1015
1058
  removeNewLine: store.removeNewLine.bind(store),
1059
+ removeCurrentBlock: store.removeCurrentBlock.bind(store),
1016
1060
  selectAll: store.selectAll.bind(store),
1017
1061
  pushHistory: store.history.push.bind(store.history),
1018
1062
  getClientRects
@@ -1037,11 +1081,11 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1037
1081
  key: block.id,
1038
1082
  block,
1039
1083
  slots: unref(slots),
1040
- modifier: props.modifier,
1084
+ renderer: props.renderer,
1041
1085
  decorator: props.decorator,
1042
1086
  parser: props.parser,
1043
1087
  onPostrender: onPostRender
1044
- }, null, 8, ["block", "slots", "modifier", "decorator", "parser"]);
1088
+ }, null, 8, ["block", "slots", "renderer", "decorator", "parser"]);
1045
1089
  }), 128)),
1046
1090
  unref(store).blocks.length === 1 && unref(store).blocks[0].text === "" && !unref(store).blocks[0].type ? renderSlot(_ctx.$slots, "placeholder", { key: 0 }) : createCommentVNode("", true)
1047
1091
  ], 544);
@@ -1049,7 +1093,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1049
1093
  }
1050
1094
  });
1051
1095
  const _sfc_main = defineComponent({
1052
- props: ["modelValue", "decorator", "parser", "styles", "modifier"],
1096
+ props: ["modelValue", "decorator", "parser", "styles", "renderer"],
1053
1097
  setup(props, { slots }) {
1054
1098
  const blocks = computed(() => {
1055
1099
  if (Array.isArray(props.modelValue)) {
@@ -1062,7 +1106,7 @@ const _sfc_main = defineComponent({
1062
1106
  block,
1063
1107
  slots,
1064
1108
  decorator: props.decorator,
1065
- modifier: props.modifier,
1109
+ renderer: props.renderer,
1066
1110
  parser: props.parser,
1067
1111
  static: true
1068
1112
  })));
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "vuewrite",
3
3
  "description": "Rich Text Editor based on Vue3 reactivity",
4
4
  "private": false,
5
- "version": "0.0.21",
5
+ "version": "0.0.22-a",
6
6
  "type": "module",
7
7
  "license": "MIT",
8
8
  "author": "den59k",