@textbus/xnote 0.0.1-alpha.12 → 0.0.1-alpha.14

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,15 +1,16 @@
1
1
  import { jsxs, jsx, Fragment } from '@viewfly/core/jsx-runtime';
2
2
  import { withScopedCSS } from '@viewfly/scoped-css';
3
- import { Injectable, InjectFlags, Injector, inject, createSignal, onUnmounted, createRef, withAnnotation, onMounted, InjectionToken, viewfly, createDynamicRef, getCurrentInstance, onUpdated, watch, ReflectiveInjector } from '@viewfly/core';
4
- import { Subject, Selection, fromEvent, Subscription, Attribute, Keyboard, Commander, Controller, ContentType, Component, Registry, Slot, useContext, onBreak, createVNode, BehaviorSubject, onPaste, onFocus, onBlur, useDynamicShortcut, VTextNode, Query, QueryStateType, onContentInsert, onFocusIn, onFocusOut, onDestroy, onGetRanges, Formatter, onParentSlotUpdated, Textbus, RootComponentRef, filter, map, distinctUntilChanged, sampleTime, merge, debounceTime, throttleTime, delay, onCompositionStart } from '@textbus/core';
3
+ import { Injectable, InjectFlags, Injector, inject, createSignal, onUnmounted, createRef, withAnnotation, onUpdated, onMounted, InjectionToken, viewfly, createDynamicRef, getCurrentInstance, watch, ReflectiveInjector } from '@viewfly/core';
4
+ import { Subject, Selection, fromEvent, Subscription, Attribute, Keyboard, Commander, Controller, useContext, onBreak, onContentInsert, ContentType, Slot, Component, Registry, createVNode, BehaviorSubject, onPaste, onFocus, onBlur, useDynamicShortcut, VTextNode, Query, QueryStateType, onFocusIn, onFocusOut, onDestroy, onGetRanges, Formatter, onParentSlotUpdated, Textbus, RootComponentRef, filter, map, distinctUntilChanged, sampleTime, merge, debounceTime, throttleTime, delay, onContentInserted, onContentDeleted, switchMap, fromPromise, onCompositionStart } from '@textbus/core';
5
5
  import { VIEW_CONTAINER, DomAdapter, Input, SelectionBridge, VIEW_DOCUMENT, BrowserModule, Parser } from '@textbus/platform-browser';
6
6
  import { createPortal, DomRenderer, createApp, HTMLRenderer, OutputTranslator } from '@viewfly/platform-browser';
7
7
  import { useProduce } from '@viewfly/hooks';
8
8
  import highlightjs from 'highlight.js';
9
+ import { any2Hsl, hsl2Rgb } from '@tanbo/color';
9
10
  import { ViewflyAdapter, ViewflyVDomAdapter } from '@textbus/adapter-viewfly';
10
11
  import { CollaborateModule } from '@textbus/collaborate';
11
12
 
12
- var scopedId$k = "vf-3d0183";
13
+ var scopedId$l = "vf-3d0183";
13
14
 
14
15
  /******************************************************************************
15
16
  Copyright (c) Microsoft Corporation.
@@ -130,7 +131,7 @@ function Button(props) {
130
131
  subscription.unsubscribe();
131
132
  });
132
133
  }
133
- return withScopedCSS(scopedId$k, () => {
134
+ return withScopedCSS(scopedId$l, () => {
134
135
  return (jsxs("button", Object.assign({ type: "button" }, props, { class: [
135
136
  'btn',
136
137
  {
@@ -142,10 +143,10 @@ function Button(props) {
142
143
  });
143
144
  }
144
145
 
145
- var scopedId$j = "vf-ac7e8d";
146
+ var scopedId$k = "vf-ac7e8d";
146
147
 
147
148
  function ComponentToolbar(props) {
148
- return withScopedCSS(scopedId$j, () => {
149
+ return withScopedCSS(scopedId$k, () => {
149
150
  return (jsx("div", { class: "component-toolbar", style: props.style, children: jsx("div", { class: [
150
151
  'toolbar',
151
152
  {
@@ -155,15 +156,15 @@ function ComponentToolbar(props) {
155
156
  });
156
157
  }
157
158
 
158
- var scopedId$i = "vf-ede279";
159
+ var scopedId$j = "vf-ede279";
159
160
 
160
161
  function Divider() {
161
- return withScopedCSS(scopedId$i, () => {
162
+ return withScopedCSS(scopedId$j, () => {
162
163
  return jsx("div", { class: "divider" });
163
164
  });
164
165
  }
165
166
 
166
- var scopedId$h = "vf-4c1803";
167
+ var scopedId$i = "vf-4c1803";
167
168
 
168
169
  function DragResize(props) {
169
170
  const isShow = createSignal(false);
@@ -271,16 +272,16 @@ function DragResize(props) {
271
272
  unUp.unsubscribe();
272
273
  });
273
274
  }
274
- return withScopedCSS(scopedId$h, () => {
275
+ return withScopedCSS(scopedId$i, () => {
275
276
  return (jsxs("div", { class: "drag-resize", onClick: selectComponent, children: [jsx("div", { class: "container", ref: ref, children: props.children }), jsxs("div", { class: ['resize-tool', {
276
277
  active: isShow()
277
278
  }], children: [jsxs("div", { class: "mask", ref: mask, children: [component.state.width, "*", component.state.height] }), jsxs("div", { class: "btn-group", ref: btnGroup, onMousedown: drag, children: [jsx("button", { type: "button" }), jsx("button", { type: "button" }), jsx("button", { type: "button" }), jsx("button", { type: "button" }), jsx("button", { type: "button" }), jsx("button", { type: "button" }), jsx("button", { type: "button" }), jsx("button", { type: "button" })] })] })] }));
278
279
  });
279
280
  }
280
281
 
281
- var scopedId$g = "vf-a99c5e";
282
+ var scopedId$h = "vf-a99c5e";
282
283
 
283
- var scopedId$f = "vf-ab6f55";
284
+ var scopedId$g = "vf-ab6f55";
284
285
 
285
286
  const DropdownMenuPortal = withAnnotation({
286
287
  providers: [
@@ -291,7 +292,7 @@ const DropdownMenuPortal = withAnnotation({
291
292
  const menuRef = createRef();
292
293
  let timer = null;
293
294
  const delay = 10;
294
- onMounted(() => {
295
+ function update() {
295
296
  const menuElement = menuRef.current;
296
297
  if (props.abreast) {
297
298
  const btnEle = props.triggerRef.current;
@@ -351,19 +352,28 @@ const DropdownMenuPortal = withAnnotation({
351
352
  }, delay);
352
353
  }
353
354
  }
355
+ }
356
+ onUpdated(() => {
357
+ update();
354
358
  });
355
359
  onUnmounted(() => {
356
360
  clearTimeout(timer);
357
361
  });
358
362
  function onEnter() {
363
+ if (props.noTrigger) {
364
+ return;
365
+ }
359
366
  dropdownContextService.canHide = false;
360
367
  dropdownContextService.open();
361
368
  }
362
369
  function onLeave() {
370
+ if (props.noTrigger) {
371
+ return;
372
+ }
363
373
  dropdownContextService.canHide = true;
364
374
  dropdownContextService.hide();
365
375
  }
366
- return createPortal(withScopedCSS(scopedId$f, () => {
376
+ return createPortal(withScopedCSS(scopedId$g, () => {
367
377
  return (jsx("div", { onMouseenter: onEnter, onMouseleave: onLeave, ref: menuRef, style: {
368
378
  width: props.width
369
379
  }, class: "dropdown-menu", children: jsx("div", { class: "dropdown-menu-content", children: props.children }) }));
@@ -395,6 +405,9 @@ const Dropdown = withAnnotation({
395
405
  });
396
406
  const subscription = new Subscription();
397
407
  onMounted(() => {
408
+ if (props.trigger === 'none') {
409
+ return;
410
+ }
398
411
  if (props.trigger === 'click') {
399
412
  subscription.add(fromEvent(triggerRef.current, 'click').subscribe(toggle));
400
413
  return;
@@ -420,14 +433,14 @@ const Dropdown = withAnnotation({
420
433
  return {
421
434
  isShow(b) {
422
435
  if (b) {
423
- dropdownContextService.hide(false);
436
+ dropdownContextService.open();
424
437
  }
425
438
  else {
426
- dropdownContextService.open();
439
+ dropdownContextService.hide(false);
427
440
  }
428
441
  },
429
- $render: withScopedCSS(scopedId$g, () => {
430
- return (jsxs("div", { class: ['dropdown', props.class], style: props.style, ref: dropdownRef, children: [jsxs("div", { class: "dropdown-btn", ref: triggerRef, children: [jsx("div", { class: "dropdown-btn-inner", children: props.children }), jsx("div", { class: "dropdown-btn-arrow" })] }), isShow() && jsx(DropdownMenuPortal, { width: props.width, abreast: props.abreast, triggerRef: triggerRef, children: Array.isArray(props.menu) ?
442
+ $render: withScopedCSS(scopedId$h, () => {
443
+ return (jsxs("div", { class: ['dropdown', props.class], style: props.style, ref: dropdownRef, children: [jsxs("div", { class: "dropdown-btn", ref: triggerRef, children: [jsx("div", { class: "dropdown-btn-inner", children: props.children }), jsx("div", { class: "dropdown-btn-arrow" })] }), isShow() && jsx(DropdownMenuPortal, { noTrigger: props.trigger === 'none', width: props.width, abreast: props.abreast, triggerRef: triggerRef, children: Array.isArray(props.menu) ?
431
444
  props.menu.map(menu => {
432
445
  return (jsx("div", { class: "dropdown-menu-item", onClick: () => {
433
446
  var _a;
@@ -442,6 +455,14 @@ const Dropdown = withAnnotation({
442
455
  };
443
456
  });
444
457
 
458
+ var scopedId$f = "vf-acaa5f";
459
+
460
+ function MenuHeading(props) {
461
+ return withScopedCSS(scopedId$f, () => {
462
+ return (jsx("div", { class: "menu-heading", children: props.children }));
463
+ });
464
+ }
465
+
445
466
  var scopedId$e = "vf-678daa";
446
467
 
447
468
  function MenuItem(props) {
@@ -603,11 +624,192 @@ function registerHeadingShortcut(textbus) {
603
624
  const commonAncestorSlot = selection.commonAncestorSlot;
604
625
  commonAncestorSlot.cut();
605
626
  commander.applyAttribute(headingAttr, 'h' + content.length);
627
+ selection.setPosition(commonAncestorSlot, 0);
606
628
  return true;
607
629
  }
608
630
  });
609
631
  }
610
632
 
633
+ function useBlockContent(slot) {
634
+ const textbus = useContext();
635
+ const selection = textbus.get(Selection);
636
+ onBreak(ev => {
637
+ if (typeof slot === 'function' ? slot(ev.target) : ev.target === slot) {
638
+ const p = new ParagraphComponent(textbus);
639
+ ev.target.insert(p);
640
+ selection.setPosition(p.state.slot, 0);
641
+ ev.preventDefault();
642
+ }
643
+ });
644
+ onContentInsert(ev => {
645
+ if ((typeof slot === 'function' ? slot(ev.target) : ev.target === slot) &&
646
+ (typeof ev.data.content === 'string' || ev.data.content.type !== ContentType.BlockComponent)) {
647
+ const p = new ParagraphComponent(textbus);
648
+ const childSlot = p.state.slot;
649
+ childSlot.insert(ev.data.content);
650
+ ev.target.insert(p);
651
+ selection.setPosition(childSlot, childSlot.index);
652
+ ev.preventDefault();
653
+ }
654
+ });
655
+ }
656
+
657
+ class BlockquoteComponent extends Component {
658
+ static fromJSON(textbus, json) {
659
+ const slot = textbus.get(Registry).createSlot(json.slot);
660
+ return new BlockquoteComponent(textbus, {
661
+ slot
662
+ });
663
+ }
664
+ constructor(textbus, state = {
665
+ slot: new Slot([
666
+ ContentType.BlockComponent
667
+ ])
668
+ }) {
669
+ super(textbus, state);
670
+ }
671
+ setup() {
672
+ useBlockContent(this.state.slot);
673
+ }
674
+ }
675
+ BlockquoteComponent.type = ContentType.BlockComponent;
676
+ BlockquoteComponent.componentName = 'BlockquoteComponent';
677
+ BlockquoteComponent.zenCoding = {
678
+ key: ' ',
679
+ match(content, textbus) {
680
+ const selection = textbus.get(Selection);
681
+ if (selection.commonAncestorComponent instanceof ParagraphComponent) {
682
+ return /^>$/.test(content);
683
+ }
684
+ return false;
685
+ },
686
+ createState(_, textbus) {
687
+ const selection = textbus.get(Selection);
688
+ const commonAncestorSlot = selection.commonAncestorSlot;
689
+ const slot = new Slot([
690
+ ContentType.BlockComponent
691
+ ]);
692
+ if (commonAncestorSlot === null || commonAncestorSlot === void 0 ? void 0 : commonAncestorSlot.hasAttribute(textIndentAttr)) {
693
+ slot.setAttribute(textIndentAttr, commonAncestorSlot.getAttribute(textIndentAttr));
694
+ }
695
+ return {
696
+ slot
697
+ };
698
+ }
699
+ };
700
+ function BlockquoteView(props) {
701
+ const adapter = inject(DomAdapter);
702
+ const readonly = useReadonly();
703
+ const output = useOutput();
704
+ return () => {
705
+ const slot = props.component.state.slot;
706
+ return (jsx("blockquote", { class: "xnote-blockquote", ref: props.rootRef, "data-component": props.component.name, children: adapter.slotRender(slot, children => {
707
+ return createVNode('div', null, children);
708
+ }, readonly() || output()) }));
709
+ };
710
+ }
711
+ const blockquoteComponentLoader = {
712
+ match(element) {
713
+ return element.tagName === 'BLOCKQUOTE';
714
+ },
715
+ read(element, textbus, slotParser) {
716
+ const delta = slotParser(new Slot([
717
+ ContentType.BlockComponent,
718
+ ContentType.InlineComponent,
719
+ ContentType.Text
720
+ ]), element).toDelta();
721
+ const slot = new Slot([
722
+ ContentType.BlockComponent,
723
+ ]);
724
+ deltaToBlock(delta, textbus).forEach(i => {
725
+ slot.insert(i);
726
+ });
727
+ return new BlockquoteComponent(textbus, {
728
+ slot
729
+ });
730
+ },
731
+ };
732
+
733
+ class HighlightBoxComponent extends Component {
734
+ static fromJSON(textbus, json) {
735
+ return new HighlightBoxComponent(textbus, {
736
+ type: json.type,
737
+ slot: textbus.get(Registry).createSlot(json.slot)
738
+ });
739
+ }
740
+ constructor(textbus, state = {
741
+ type: '',
742
+ slot: new Slot([
743
+ ContentType.BlockComponent,
744
+ ])
745
+ }) {
746
+ super(textbus, state);
747
+ }
748
+ setup() {
749
+ useBlockContent(this.state.slot);
750
+ }
751
+ }
752
+ HighlightBoxComponent.defaultTypes = ['❤️', '💡', '📌', '✅', '❎', '👍', '🎉', '🚫', '❗'];
753
+ HighlightBoxComponent.componentName = 'HighlightBoxComponent';
754
+ HighlightBoxComponent.type = ContentType.BlockComponent;
755
+ function HighlightBoxView(props) {
756
+ const adapter = inject(DomAdapter);
757
+ const readonly = useReadonly();
758
+ const output = useOutput();
759
+ const emoji = [];
760
+ for (let i = 0x1F600; i <= 0x1F64F; i++) {
761
+ emoji.push(i);
762
+ }
763
+ const dropdownRef = createRef();
764
+ function setType(type) {
765
+ var _a;
766
+ (_a = dropdownRef.current) === null || _a === void 0 ? void 0 : _a.isShow(false);
767
+ props.component.state.type = type;
768
+ }
769
+ return () => {
770
+ const { state, name } = props.component;
771
+ if (readonly() || output()) {
772
+ return (jsxs("div", { "data-component": name, ref: props.rootRef, "data-icon": state.type, class: "xnote-highlight-box", children: [jsx("div", { class: "xnote-highlight-box-left", children: jsx("div", { class: "xnote-highlight-box-icon", children: jsx("button", { type: "button", children: state.type || '❤️' }) }) }), adapter.slotRender(state.slot, children => {
773
+ return createVNode('div', {
774
+ class: 'xnote-highlight-box-content'
775
+ }, children);
776
+ }, readonly() || output())] }));
777
+ }
778
+ return (jsxs("div", { "data-component": name, ref: props.rootRef, "data-icon": state.type, class: "xnote-highlight-box", children: [jsx("div", { class: "xnote-highlight-box-left", children: jsx(Dropdown, { trigger: "click", ref: dropdownRef, width: "282px", menu: jsxs("div", { class: "xnote-highlight-box-icons", children: [jsx("div", { class: "xnote-highlight-box-heading", children: "\u5E38\u7528" }), HighlightBoxComponent.defaultTypes.map(icon => {
779
+ return (jsx("button", { onClick: () => setType(icon), type: "button", children: icon }));
780
+ }), jsx("div", { class: "xnote-highlight-box-heading", children: "\u66F4\u591A" }), emoji.map(i => {
781
+ const icon = String.fromCodePoint(i);
782
+ return (jsx("button", { onClick: () => setType(icon), type: "button", children: icon }));
783
+ })] }), children: jsx("div", { class: "xnote-highlight-box-icon", children: jsx("button", { type: "button", children: state.type || '❤️' }) }) }) }), adapter.slotRender(state.slot, children => {
784
+ return createVNode('div', {
785
+ class: 'xnote-highlight-box-content'
786
+ }, children);
787
+ }, readonly() || output())] }));
788
+ };
789
+ }
790
+ const highlightBoxComponentLoader = {
791
+ match(element) {
792
+ return element.tagName === 'DIV' && element.dataset.component === HighlightBoxComponent.componentName;
793
+ },
794
+ read(element, textbus, slotParser) {
795
+ const delta = slotParser(new Slot([
796
+ ContentType.BlockComponent,
797
+ ContentType.InlineComponent,
798
+ ContentType.Text
799
+ ]), element.querySelector('.xnote-highlight-box-content')).toDelta();
800
+ const slot = new Slot([
801
+ ContentType.BlockComponent,
802
+ ]);
803
+ deltaToBlock(delta, textbus).forEach(i => {
804
+ slot.insert(i);
805
+ });
806
+ return new HighlightBoxComponent(textbus, {
807
+ type: element.dataset.icon || '',
808
+ slot
809
+ });
810
+ }
811
+ };
812
+
611
813
  class ParagraphComponent extends Component {
612
814
  static fromJSON(textbus, json) {
613
815
  const slot = textbus.get(Registry).createSlot(json.slot);
@@ -628,12 +830,20 @@ class ParagraphComponent extends Component {
628
830
  const commander = injector.get(Commander);
629
831
  const selection = injector.get(Selection);
630
832
  onBreak(ev => {
833
+ const isEmpty = this.state.slot.isEmpty;
631
834
  const afterSlot = ev.target.cut(ev.data.index);
632
835
  afterSlot.removeAttribute(headingAttr);
633
836
  const nextParagraph = new ParagraphComponent(injector, {
634
837
  slot: afterSlot
635
838
  });
636
- commander.insertAfter(nextParagraph, this);
839
+ if (isEmpty && (this.parentComponent instanceof BlockquoteComponent ||
840
+ this.parentComponent instanceof HighlightBoxComponent)) {
841
+ commander.insertAfter(nextParagraph, this.parentComponent);
842
+ commander.removeComponent(this);
843
+ }
844
+ else {
845
+ commander.insertAfter(nextParagraph, this);
846
+ }
637
847
  selection.setPosition(afterSlot, 0);
638
848
  ev.preventDefault();
639
849
  });
@@ -1422,30 +1632,6 @@ function AttrTool(props) {
1422
1632
  });
1423
1633
  }
1424
1634
 
1425
- function useBlockContent(slot) {
1426
- const textbus = useContext();
1427
- const selection = textbus.get(Selection);
1428
- onBreak(ev => {
1429
- if (typeof slot === 'function' ? slot(ev.target) : ev.target === slot) {
1430
- const p = new ParagraphComponent(textbus);
1431
- ev.target.insert(p);
1432
- selection.setPosition(p.state.slot, 0);
1433
- ev.preventDefault();
1434
- }
1435
- });
1436
- onContentInsert(ev => {
1437
- if ((typeof slot === 'function' ? slot(ev.target) : ev.target === slot) &&
1438
- (typeof ev.data.content === 'string' || ev.data.content.type !== ContentType.BlockComponent)) {
1439
- const p = new ParagraphComponent(textbus);
1440
- const childSlot = p.state.slot;
1441
- childSlot.insert(ev.data.content);
1442
- ev.target.insert(p);
1443
- selection.setPosition(childSlot, childSlot.index);
1444
- ev.preventDefault();
1445
- }
1446
- });
1447
- }
1448
-
1449
1635
  const defaultRowHeight = 30;
1450
1636
  const defaultColumnWidth = 100;
1451
1637
  class TableComponent extends Component {
@@ -1788,14 +1974,20 @@ TodolistComponent.zenCoding = {
1788
1974
  return false;
1789
1975
  },
1790
1976
  key: ' ',
1791
- createState(content) {
1977
+ createState(content, textbus) {
1978
+ const selection = textbus.get(Selection);
1979
+ const commonAncestorSlot = selection.commonAncestorSlot;
1980
+ const slot = new Slot([
1981
+ ContentType.InlineComponent,
1982
+ ContentType.Text
1983
+ ]);
1984
+ if (commonAncestorSlot === null || commonAncestorSlot === void 0 ? void 0 : commonAncestorSlot.hasAttribute(textIndentAttr)) {
1985
+ slot.setAttribute(textIndentAttr, commonAncestorSlot.getAttribute(textIndentAttr));
1986
+ }
1792
1987
  const isChecked = content.charAt(1) === 'x';
1793
1988
  return {
1794
1989
  checked: isChecked,
1795
- slot: new Slot([
1796
- ContentType.InlineComponent,
1797
- ContentType.Text
1798
- ])
1990
+ slot
1799
1991
  };
1800
1992
  }
1801
1993
  };
@@ -1852,76 +2044,6 @@ const todolistComponentLoader = {
1852
2044
  }
1853
2045
  };
1854
2046
 
1855
- class BlockquoteComponent extends Component {
1856
- static fromJSON(textbus, json) {
1857
- const slot = textbus.get(Registry).createSlot(json.slot);
1858
- return new BlockquoteComponent(textbus, {
1859
- slot
1860
- });
1861
- }
1862
- constructor(textbus, state = {
1863
- slot: new Slot([
1864
- ContentType.BlockComponent
1865
- ])
1866
- }) {
1867
- super(textbus, state);
1868
- }
1869
- setup() {
1870
- useBlockContent(this.state.slot);
1871
- }
1872
- }
1873
- BlockquoteComponent.type = ContentType.BlockComponent;
1874
- BlockquoteComponent.componentName = 'BlockquoteComponent';
1875
- BlockquoteComponent.zenCoding = {
1876
- key: ' ',
1877
- match(content, textbus) {
1878
- const selection = textbus.get(Selection);
1879
- if (selection.commonAncestorComponent instanceof ParagraphComponent) {
1880
- return /^>$/.test(content);
1881
- }
1882
- return false;
1883
- },
1884
- createState() {
1885
- return {
1886
- slot: new Slot([
1887
- ContentType.BlockComponent
1888
- ])
1889
- };
1890
- }
1891
- };
1892
- function BlockquoteView(props) {
1893
- const adapter = inject(DomAdapter);
1894
- const readonly = useReadonly();
1895
- const output = useOutput();
1896
- return () => {
1897
- const slot = props.component.state.slot;
1898
- return (jsx("blockquote", { class: "xnote-blockquote", ref: props.rootRef, "data-component": props.component.name, children: adapter.slotRender(slot, children => {
1899
- return createVNode('div', null, children);
1900
- }, readonly() || output()) }));
1901
- };
1902
- }
1903
- const blockquoteComponentLoader = {
1904
- match(element) {
1905
- return element.tagName === 'BLOCKQUOTE';
1906
- },
1907
- read(element, textbus, slotParser) {
1908
- const delta = slotParser(new Slot([
1909
- ContentType.BlockComponent,
1910
- ContentType.InlineComponent,
1911
- ContentType.Text
1912
- ]), element).toDelta();
1913
- const slot = new Slot([
1914
- ContentType.BlockComponent,
1915
- ]);
1916
- deltaToBlock(delta, textbus).forEach(i => {
1917
- slot.insert(i);
1918
- });
1919
- return new BlockquoteComponent(textbus, {
1920
- slot
1921
- });
1922
- },
1923
- };
1924
-
1925
2047
  class ListComponent extends Component {
1926
2048
  static fromJSON(textbus, json) {
1927
2049
  return new ListComponent(textbus, {
@@ -2035,14 +2157,20 @@ ListComponent.zenCoding = {
2035
2157
  }
2036
2158
  return false;
2037
2159
  },
2038
- createState(content) {
2160
+ createState(content, textbus) {
2161
+ const selection = textbus.get(Selection);
2162
+ const commonAncestorSlot = selection.commonAncestorSlot;
2163
+ const slot = new Slot([
2164
+ ContentType.InlineComponent,
2165
+ ContentType.Text
2166
+ ]);
2167
+ if (commonAncestorSlot === null || commonAncestorSlot === void 0 ? void 0 : commonAncestorSlot.hasAttribute(textIndentAttr)) {
2168
+ slot.setAttribute(textIndentAttr, commonAncestorSlot.getAttribute(textIndentAttr));
2169
+ }
2039
2170
  return {
2040
2171
  type: /[-+*]/.test(content) ? 'UnorderedList' : 'OrderedList',
2041
2172
  reorder: true,
2042
- slot: new Slot([
2043
- ContentType.InlineComponent,
2044
- ContentType.Text
2045
- ])
2173
+ slot
2046
2174
  };
2047
2175
  }
2048
2176
  };
@@ -2254,86 +2382,6 @@ function useActiveBlock() {
2254
2382
  };
2255
2383
  }
2256
2384
 
2257
- class HighlightBoxComponent extends Component {
2258
- static fromJSON(textbus, json) {
2259
- return new HighlightBoxComponent(textbus, {
2260
- type: json.type,
2261
- slot: textbus.get(Registry).createSlot(json.slot)
2262
- });
2263
- }
2264
- constructor(textbus, state = {
2265
- type: '',
2266
- slot: new Slot([
2267
- ContentType.BlockComponent,
2268
- ])
2269
- }) {
2270
- super(textbus, state);
2271
- }
2272
- setup() {
2273
- useBlockContent(this.state.slot);
2274
- }
2275
- }
2276
- HighlightBoxComponent.defaultTypes = ['❤️', '💡', '📌', '✅', '❎', '👍', '🎉', '🚫', '❗'];
2277
- HighlightBoxComponent.componentName = 'HighlightBoxComponent';
2278
- HighlightBoxComponent.type = ContentType.BlockComponent;
2279
- function HighlightBoxView(props) {
2280
- const adapter = inject(DomAdapter);
2281
- const readonly = useReadonly();
2282
- const output = useOutput();
2283
- const emoji = [];
2284
- for (let i = 0x1F600; i <= 0x1F64F; i++) {
2285
- emoji.push(i);
2286
- }
2287
- const dropdownRef = createRef();
2288
- function setType(type) {
2289
- var _a;
2290
- (_a = dropdownRef.current) === null || _a === void 0 ? void 0 : _a.isShow(false);
2291
- props.component.state.type = type;
2292
- }
2293
- return () => {
2294
- const { state, name } = props.component;
2295
- if (readonly() || output()) {
2296
- return (jsxs("div", { "data-component": name, ref: props.rootRef, "data-icon": state.type, class: "xnote-highlight-box", children: [jsx("div", { class: "xnote-highlight-box-left", children: jsx("div", { class: "xnote-highlight-box-icon", children: jsx("button", { type: "button", children: state.type || '❤️' }) }) }), adapter.slotRender(state.slot, children => {
2297
- return createVNode('div', {
2298
- class: 'xnote-highlight-box-content'
2299
- }, children);
2300
- }, readonly() || output())] }));
2301
- }
2302
- return (jsxs("div", { "data-component": name, ref: props.rootRef, "data-icon": state.type, class: "xnote-highlight-box", children: [jsx("div", { class: "xnote-highlight-box-left", children: jsx(Dropdown, { trigger: "click", ref: dropdownRef, width: "260px", menu: jsxs("div", { class: "xnote-highlight-box-icons", children: [HighlightBoxComponent.defaultTypes.map(icon => {
2303
- return (jsx("button", { onClick: () => setType(icon), type: "button", children: icon }));
2304
- }), jsx(Divider, {}), emoji.map(i => {
2305
- const icon = String.fromCodePoint(i);
2306
- return (jsx("button", { onClick: () => setType(icon), type: "button", children: icon }));
2307
- })] }), children: jsx("div", { class: "xnote-highlight-box-icon", children: jsx("button", { type: "button", children: state.type || '❤️' }) }) }) }), adapter.slotRender(state.slot, children => {
2308
- return createVNode('div', {
2309
- class: 'xnote-highlight-box-content'
2310
- }, children);
2311
- }, readonly() || output())] }));
2312
- };
2313
- }
2314
- const highlightBoxComponentLoader = {
2315
- match(element) {
2316
- return element.tagName === 'DIV' && element.dataset.component === HighlightBoxComponent.componentName;
2317
- },
2318
- read(element, textbus, slotParser) {
2319
- const delta = slotParser(new Slot([
2320
- ContentType.BlockComponent,
2321
- ContentType.InlineComponent,
2322
- ContentType.Text
2323
- ]), element.querySelector('.xnote-highlight-box-content')).toDelta();
2324
- const slot = new Slot([
2325
- ContentType.BlockComponent,
2326
- ]);
2327
- deltaToBlock(delta, textbus).forEach(i => {
2328
- slot.insert(i);
2329
- });
2330
- return new HighlightBoxComponent(textbus, {
2331
- type: element.dataset.icon || '',
2332
- slot
2333
- });
2334
- }
2335
- };
2336
-
2337
2385
  function useBlockTransform() {
2338
2386
  const commander = inject(Commander);
2339
2387
  const textbus = inject(Textbus);
@@ -3106,6 +3154,9 @@ const isSupportFont = (function () {
3106
3154
  function FontFamilyTool() {
3107
3155
  const currentFontFamily = createSignal('');
3108
3156
  const fontFamilyOptions = [{
3157
+ label: '默认',
3158
+ value: ''
3159
+ }, {
3109
3160
  label: '宋体',
3110
3161
  value: 'SimSun, STSong'
3111
3162
  }, {
@@ -3156,7 +3207,7 @@ function FontFamilyTool() {
3156
3207
  const result = query.queryFormat(fontFamilyFormatter);
3157
3208
  const isHighlight = result.state === QueryStateType.Enabled;
3158
3209
  highlight.set(isHighlight);
3159
- currentFontFamily.set(isHighlight ? result.value : '默认');
3210
+ currentFontFamily.set(isHighlight ? result.value : '');
3160
3211
  });
3161
3212
  onUnmounted(() => {
3162
3213
  subscription.unsubscribe();
@@ -3164,7 +3215,7 @@ function FontFamilyTool() {
3164
3215
  return () => {
3165
3216
  var _a;
3166
3217
  return (jsx(Dropdown, { onCheck: check, menu: fontFamilyOptions.map(i => {
3167
- const disabled = !i.value.split(',').map(i => isSupportFont(i.trim())).some(v => v);
3218
+ const disabled = i.value ? !i.value.split(',').map(i => isSupportFont(i.trim())).some(v => v) : false;
3168
3219
  return {
3169
3220
  label: jsx(MenuItem, { disabled: disabled, checked: currentFontFamily() === i.value, children: i.label }),
3170
3221
  disabled,
@@ -3556,7 +3607,7 @@ function InsertTool(props) {
3556
3607
  }
3557
3608
  }
3558
3609
  return withScopedCSS(scopedId$8, () => {
3559
- return jsxs(Fragment, { children: [jsxs("div", { class: "btn-group", children: [jsx(Button, { ordinary: true, onClick: () => insert('paragraph'), children: jsx("span", { class: "xnote-icon-pilcrow" }) }), jsx(Button, { ordinary: true, onClick: () => insert('h1'), children: jsx("span", { class: "xnote-icon-heading-h1" }) }), jsx(Button, { ordinary: true, onClick: () => insert('h2'), children: jsx("span", { class: "xnote-icon-heading-h2" }) }), jsx(Button, { ordinary: true, onClick: () => insert('h3'), children: jsx("span", { class: "xnote-icon-heading-h3" }) }), jsx(Button, { ordinary: true, onClick: () => insert('h4'), children: jsx("span", { class: "xnote-icon-heading-h4" }) }), jsx(Button, { ordinary: true, onClick: () => insert('h5'), children: jsx("span", { class: "xnote-icon-heading-h5" }) }), jsx(Button, { ordinary: true, onClick: () => insert('h6'), children: jsx("span", { class: "xnote-icon-heading-h6" }) }), jsx(Button, { ordinary: true, onClick: () => insert('ol'), children: jsx("span", { class: "xnote-icon-list-numbered" }) }), jsx(Button, { ordinary: true, onClick: () => insert('ul'), children: jsx("span", { class: "xnote-icon-list" }) }), jsx(Button, { ordinary: true, onClick: () => insert('sourceCode'), children: jsx("span", { class: "xnote-icon-source-code" }) })] }), jsx(Divider, {}), jsx(MenuItem, { onClick: () => insert('table'), icon: jsx("span", { class: "xnote-icon-table" }), children: "\u8868\u683C" }), jsx(MenuItem, { onClick: () => insert('todolist'), icon: jsx("span", { class: "xnote-icon-checkbox-checked" }), children: "\u5F85\u529E\u5217\u8868" }), jsx(MenuItem, { onClick: () => insert('image'), icon: jsx("span", { class: "xnote-icon-image" }), children: "\u56FE\u7247" }), jsx(MenuItem, { onClick: () => insert('video'), icon: jsx("span", { class: "xnote-icon-video" }), children: "\u89C6\u9891" }), jsx(MenuItem, { onClick: () => insert('highlightBox'), icon: jsx("span", { class: "xnote-icon-warning" }), children: "\u9AD8\u4EAE\u5757" })] });
3610
+ return jsxs(Fragment, { children: [props.hideTitle ? null : jsx(MenuHeading, { children: props.replace ? '替换为' : '在下面添加' }), jsxs("div", { class: "btn-group", children: [jsx(Button, { ordinary: true, onClick: () => insert('paragraph'), children: jsx("span", { class: "xnote-icon-pilcrow" }) }), jsx(Button, { ordinary: true, onClick: () => insert('h1'), children: jsx("span", { class: "xnote-icon-heading-h1" }) }), jsx(Button, { ordinary: true, onClick: () => insert('h2'), children: jsx("span", { class: "xnote-icon-heading-h2" }) }), jsx(Button, { ordinary: true, onClick: () => insert('h3'), children: jsx("span", { class: "xnote-icon-heading-h3" }) }), jsx(Button, { ordinary: true, onClick: () => insert('h4'), children: jsx("span", { class: "xnote-icon-heading-h4" }) }), jsx(Button, { ordinary: true, onClick: () => insert('h5'), children: jsx("span", { class: "xnote-icon-heading-h5" }) }), jsx(Button, { ordinary: true, onClick: () => insert('h6'), children: jsx("span", { class: "xnote-icon-heading-h6" }) }), jsx(Button, { ordinary: true, onClick: () => insert('ol'), children: jsx("span", { class: "xnote-icon-list-numbered" }) }), jsx(Button, { ordinary: true, onClick: () => insert('ul'), children: jsx("span", { class: "xnote-icon-list" }) }), jsx(Button, { ordinary: true, onClick: () => insert('sourceCode'), children: jsx("span", { class: "xnote-icon-source-code" }) })] }), jsx(Divider, {}), jsx(MenuItem, { onClick: () => insert('table'), icon: jsx("span", { class: "xnote-icon-table" }), children: "\u8868\u683C" }), jsx(MenuItem, { onClick: () => insert('todolist'), icon: jsx("span", { class: "xnote-icon-checkbox-checked" }), children: "\u5F85\u529E\u5217\u8868" }), jsx(MenuItem, { onClick: () => insert('image'), icon: jsx("span", { class: "xnote-icon-image" }), children: "\u56FE\u7247" }), jsx(MenuItem, { onClick: () => insert('video'), icon: jsx("span", { class: "xnote-icon-video" }), children: "\u89C6\u9891" }), jsx(MenuItem, { onClick: () => insert('highlightBox'), icon: jsx("span", { class: "xnote-icon-warning" }), children: "\u9AD8\u4EAE\u5757" })] });
3560
3611
  });
3561
3612
  }
3562
3613
 
@@ -3595,12 +3646,14 @@ const LeftToolbar = withAnnotation({
3595
3646
  const sub = fromEvent(docContentContainer, 'mousemove').pipe(filter(() => {
3596
3647
  return !isIgnoreMove;
3597
3648
  }), map(ev => {
3649
+ var _a;
3598
3650
  let currentNode = ev.target;
3599
3651
  while (currentNode) {
3600
3652
  const slot = adapter.getSlotByNativeNode(currentNode);
3601
3653
  if (slot) {
3602
- if ((slot === null || slot === void 0 ? void 0 : slot.parent) instanceof SourceCodeComponent || (slot === null || slot === void 0 ? void 0 : slot.parent) instanceof TableComponent) {
3603
- return null;
3654
+ if (((_a = slot === null || slot === void 0 ? void 0 : slot.parent) === null || _a === void 0 ? void 0 : _a.type) === ContentType.InlineComponent) {
3655
+ currentNode = currentNode.parentNode;
3656
+ continue;
3604
3657
  }
3605
3658
  return slot;
3606
3659
  }
@@ -3615,7 +3668,9 @@ const LeftToolbar = withAnnotation({
3615
3668
  activeSlot.set(slot);
3616
3669
  if (slot) {
3617
3670
  checkStates(slot);
3618
- isEmptyBlock.set(slot.parent instanceof ParagraphComponent && slot.isEmpty);
3671
+ isEmptyBlock.set((slot.parent instanceof ParagraphComponent && slot.isEmpty) ||
3672
+ slot.parent instanceof SourceCodeComponent ||
3673
+ slot.parent instanceof TableComponent);
3619
3674
  const nativeNode = adapter.getNativeNodeByComponent(slot.parent);
3620
3675
  updatePosition(draft => {
3621
3676
  const containerRect = docContentContainer.getBoundingClientRect();
@@ -3712,6 +3767,7 @@ const LeftToolbar = withAnnotation({
3712
3767
  isIgnoreMove = b;
3713
3768
  }
3714
3769
  return withScopedCSS(scopedId$7, () => {
3770
+ var _a;
3715
3771
  const position = positionSignal();
3716
3772
  const slot = activeSlot();
3717
3773
  let activeNode = jsx("span", { class: "xnote-icon-pilcrow" });
@@ -3739,6 +3795,8 @@ const LeftToolbar = withAnnotation({
3739
3795
  }
3740
3796
  }
3741
3797
  }
3798
+ const activeParentComponent = (_a = activeSlot()) === null || _a === void 0 ? void 0 : _a.parent;
3799
+ const needInsert = activeParentComponent instanceof TableComponent || activeParentComponent instanceof SourceCodeComponent;
3742
3800
  return (jsx("div", { class: "left-toolbar", ref: toolbarRef, children: jsx("div", { class: "left-toolbar-btn-wrap", ref: btnRef, style: {
3743
3801
  left: position.left + 'px',
3744
3802
  top: position.top + 'px',
@@ -3748,9 +3806,9 @@ const LeftToolbar = withAnnotation({
3748
3806
  right: 0,
3749
3807
  top: 0
3750
3808
  }, menu: isEmptyBlock() ?
3751
- jsx(InsertTool, { replace: true, slot: activeSlot() })
3809
+ jsx(InsertTool, { replace: !needInsert, slot: activeSlot() })
3752
3810
  :
3753
- jsxs(Fragment, { children: [jsxs("div", { class: "btn-group", children: [jsx(Button, { ordinary: true, highlight: states.paragraph, onClick: () => transform('paragraph'), children: jsx("span", { class: "xnote-icon-pilcrow" }) }), jsx(Button, { ordinary: true, highlight: states.h1, onClick: () => transform('h1'), children: jsx("span", { class: "xnote-icon-heading-h1" }) }), jsx(Button, { ordinary: true, highlight: states.h2, onClick: () => transform('h2'), children: jsx("span", { class: "xnote-icon-heading-h2" }) }), jsx(Button, { ordinary: true, highlight: states.h3, onClick: () => transform('h3'), children: jsx("span", { class: "xnote-icon-heading-h3" }) }), jsx(Button, { ordinary: true, highlight: states.h4, onClick: () => transform('h4'), children: jsx("span", { class: "xnote-icon-heading-h4" }) }), jsx(Button, { ordinary: true, highlight: states.todolist, onClick: () => transform('todolist'), children: jsx("span", { class: "xnote-icon-checkbox-checked" }) }), jsx(Button, { ordinary: true, highlight: states.orderedList, onClick: () => transform('ol'), children: jsx("span", { class: "xnote-icon-list-numbered" }) }), jsx(Button, { ordinary: true, highlight: states.unorderedList, onClick: () => transform('ul'), children: jsx("span", { class: "xnote-icon-list" }) }), jsx(Button, { ordinary: true, highlight: states.blockquote, onClick: () => transform('blockquote'), children: jsx("span", { class: "xnote-icon-quotes-right" }) }), jsx(Button, { ordinary: true, highlight: states.sourceCode, onClick: () => transform('sourceCode'), children: jsx("span", { class: "xnote-icon-source-code" }) })] }), jsx(Divider, {}), jsx(AttrTool, { style: { display: 'block' }, abreast: true, slot: slot, applyBefore: applyBefore, children: jsx(MenuItem, { arrow: true, icon: jsx("span", { class: "xnote-icon-indent-decrease" }), children: "\u7F29\u8FDB\u548C\u5BF9\u9F50" }) }), jsx(ColorTool, { style: { display: 'block' }, abreast: true, applyBefore: applyBefore, children: jsx(MenuItem, { arrow: true, icon: jsx("span", { class: "xnote-icon-color" }), children: "\u989C\u8272" }) }), jsx(Divider, {}), jsx(MenuItem, { onClick: copy, icon: jsx("span", { class: "xnote-icon-copy" }), children: "\u590D\u5236" }), jsx(MenuItem, { onClick: remove, icon: jsx("span", { class: "xnote-icon-bin" }), children: "\u5220\u9664" }), jsx(MenuItem, { onClick: cut, icon: jsx("span", { class: "xnote-icon-cut" }), children: "\u526A\u5207" }), jsx(Divider, {}), jsx(Dropdown, { style: { display: 'block' }, abreast: true, menu: jsx(InsertTool, { slot: activeSlot() }), children: jsx(MenuItem, { arrow: true, icon: jsx("span", { class: "xnote-icon-plus" }), children: "\u5728\u4E0B\u9762\u6DFB\u52A0" }) })] }), children: jsx("button", { type: "button", class: "left-toolbar-btn", children: isEmptyBlock() ?
3811
+ jsxs(Fragment, { children: [jsxs("div", { class: "btn-group", children: [jsx(Button, { ordinary: true, highlight: states.paragraph, onClick: () => transform('paragraph'), children: jsx("span", { class: "xnote-icon-pilcrow" }) }), jsx(Button, { ordinary: true, highlight: states.h1, onClick: () => transform('h1'), children: jsx("span", { class: "xnote-icon-heading-h1" }) }), jsx(Button, { ordinary: true, highlight: states.h2, onClick: () => transform('h2'), children: jsx("span", { class: "xnote-icon-heading-h2" }) }), jsx(Button, { ordinary: true, highlight: states.h3, onClick: () => transform('h3'), children: jsx("span", { class: "xnote-icon-heading-h3" }) }), jsx(Button, { ordinary: true, highlight: states.h4, onClick: () => transform('h4'), children: jsx("span", { class: "xnote-icon-heading-h4" }) }), jsx(Button, { ordinary: true, highlight: states.todolist, onClick: () => transform('todolist'), children: jsx("span", { class: "xnote-icon-checkbox-checked" }) }), jsx(Button, { ordinary: true, highlight: states.orderedList, onClick: () => transform('ol'), children: jsx("span", { class: "xnote-icon-list-numbered" }) }), jsx(Button, { ordinary: true, highlight: states.unorderedList, onClick: () => transform('ul'), children: jsx("span", { class: "xnote-icon-list" }) }), jsx(Button, { ordinary: true, highlight: states.blockquote, onClick: () => transform('blockquote'), children: jsx("span", { class: "xnote-icon-quotes-right" }) }), jsx(Button, { ordinary: true, highlight: states.sourceCode, onClick: () => transform('sourceCode'), children: jsx("span", { class: "xnote-icon-source-code" }) })] }), jsx(Divider, {}), jsx(AttrTool, { style: { display: 'block' }, abreast: true, slot: slot, applyBefore: applyBefore, children: jsx(MenuItem, { arrow: true, icon: jsx("span", { class: "xnote-icon-indent-decrease" }), children: "\u7F29\u8FDB\u548C\u5BF9\u9F50" }) }), jsx(ColorTool, { style: { display: 'block' }, abreast: true, applyBefore: applyBefore, children: jsx(MenuItem, { arrow: true, icon: jsx("span", { class: "xnote-icon-color" }), children: "\u989C\u8272" }) }), jsx(Divider, {}), jsx(MenuItem, { onClick: copy, icon: jsx("span", { class: "xnote-icon-copy" }), children: "\u590D\u5236" }), jsx(MenuItem, { onClick: remove, icon: jsx("span", { class: "xnote-icon-bin" }), children: "\u5220\u9664" }), jsx(MenuItem, { onClick: cut, icon: jsx("span", { class: "xnote-icon-cut" }), children: "\u526A\u5207" }), jsx(Divider, {}), jsx(Dropdown, { style: { display: 'block' }, abreast: true, menu: jsx(InsertTool, { hideTitle: true, slot: activeSlot() }), children: jsx(MenuItem, { arrow: true, icon: jsx("span", { class: "xnote-icon-plus" }), children: "\u5728\u4E0B\u9762\u6DFB\u52A0" }) })] }), children: jsx("button", { type: "button", class: "left-toolbar-btn", children: isEmptyBlock() ?
3754
3812
  jsx("span", { children: jsx("i", { class: "xnote-icon-plus" }) })
3755
3813
  :
3756
3814
  jsxs("span", { children: [activeNode, jsx("i", { style: "font-size: 12px", class: "xnote-icon-more" })] }) }) }) }) }));
@@ -4030,6 +4088,198 @@ class Matcher {
4030
4088
  }
4031
4089
  }
4032
4090
 
4091
+ class Organization {
4092
+ }
4093
+ function registerAtShortcut(textbus) {
4094
+ const keyboard = textbus.get(Keyboard);
4095
+ const selection = textbus.get(Selection);
4096
+ const commander = textbus.get(Commander);
4097
+ keyboard.addShortcut({
4098
+ keymap: {
4099
+ key: '@',
4100
+ shiftKey: true
4101
+ },
4102
+ action() {
4103
+ const { commonAncestorComponent } = selection;
4104
+ if (commonAncestorComponent instanceof SourceCodeComponent) {
4105
+ return false;
4106
+ }
4107
+ const at = new AtComponent(textbus);
4108
+ commander.insert(at);
4109
+ selection.setPosition(at.state.slot, 0);
4110
+ }
4111
+ });
4112
+ }
4113
+ class AtComponent extends Component {
4114
+ static fromJSON(textbus, { slot: slotState, userInfo }) {
4115
+ const registry = textbus.get(Registry);
4116
+ if (slotState) {
4117
+ const slot = registry.createSlot(slotState);
4118
+ return new AtComponent({
4119
+ slot
4120
+ });
4121
+ }
4122
+ return new AtComponent(textbus, {
4123
+ userInfo,
4124
+ });
4125
+ }
4126
+ constructor(textbus, state = {
4127
+ slot: new Slot([ContentType.Text])
4128
+ }) {
4129
+ if (!state.userInfo && !state.slot) {
4130
+ state.slot = new Slot([ContentType.Text]);
4131
+ }
4132
+ super(textbus, state);
4133
+ this.focus = new Subject();
4134
+ this.members = createSignal([]);
4135
+ this.selectedIndex = createSignal(0);
4136
+ }
4137
+ setup() {
4138
+ let isFocus = false;
4139
+ onFocus(() => {
4140
+ isFocus = true;
4141
+ this.focus.next(true);
4142
+ onChange.next();
4143
+ });
4144
+ onBlur(() => {
4145
+ isFocus = false;
4146
+ this.focus.next(false);
4147
+ });
4148
+ const organization = useContext(Organization);
4149
+ const selection = useContext(Selection);
4150
+ const commander = useContext(Commander);
4151
+ const onChange = new Subject();
4152
+ onContentInserted((ev) => {
4153
+ const key = this.state.slot.toString();
4154
+ if (key.length > 10) {
4155
+ selection.selectComponent(this);
4156
+ commander.insert(key);
4157
+ ev.preventDefault();
4158
+ return;
4159
+ }
4160
+ onChange.next();
4161
+ });
4162
+ onContentDeleted(() => {
4163
+ onChange.next();
4164
+ });
4165
+ onBreak((ev) => {
4166
+ const member = this.members()[this.selectedIndex()];
4167
+ if (member) {
4168
+ this.state.userInfo = Object.assign({}, member);
4169
+ }
4170
+ selection.selectComponentEnd(this);
4171
+ ev.preventDefault();
4172
+ });
4173
+ useDynamicShortcut({
4174
+ keymap: {
4175
+ key: ['ArrowDown', 'ArrowUp']
4176
+ },
4177
+ action: (key) => {
4178
+ let index = this.selectedIndex();
4179
+ if (key === 'ArrowUp') {
4180
+ if (index > 0) {
4181
+ index--;
4182
+ this.selectedIndex.set(index);
4183
+ }
4184
+ return;
4185
+ }
4186
+ if (index < this.members().length - 1) {
4187
+ index++;
4188
+ this.selectedIndex.set(index);
4189
+ }
4190
+ }
4191
+ });
4192
+ const subs = onChange.pipe(switchMap(() => {
4193
+ const key = this.state.slot.toString();
4194
+ return fromPromise(organization.getMembers(key));
4195
+ })).subscribe((members) => {
4196
+ this.members.set(members);
4197
+ this.selectedIndex.set(0);
4198
+ if (isFocus) {
4199
+ this.focus.next(true);
4200
+ }
4201
+ });
4202
+ onDestroy(() => {
4203
+ subs.unsubscribe();
4204
+ });
4205
+ }
4206
+ }
4207
+ AtComponent.componentName = 'AtComponent';
4208
+ AtComponent.type = ContentType.InlineComponent;
4209
+
4210
+ function AtComponentView(props) {
4211
+ const adapter = inject(DomAdapter);
4212
+ const selection = inject(Selection);
4213
+ const dropdownRef = createRef();
4214
+ const subscription = props.component.focus.subscribe((b) => {
4215
+ if (dropdownRef.current && props.component.members().length) {
4216
+ dropdownRef.current.isShow(b);
4217
+ }
4218
+ });
4219
+ onUnmounted(() => {
4220
+ subscription.unsubscribe();
4221
+ });
4222
+ const readonly = useReadonly();
4223
+ const output = useOutput();
4224
+ const membersRef = createRef();
4225
+ onUpdated(() => {
4226
+ if (output() || readonly()) {
4227
+ return;
4228
+ }
4229
+ const container = membersRef.current;
4230
+ if (container) {
4231
+ const focusItem = container.children[props.component.selectedIndex()];
4232
+ if (focusItem) {
4233
+ focusItem.scrollIntoView({
4234
+ behavior: 'smooth',
4235
+ block: 'center'
4236
+ });
4237
+ }
4238
+ }
4239
+ });
4240
+ return () => {
4241
+ const { slot, userInfo } = props.component.state;
4242
+ const selectedIndex = props.component.selectedIndex();
4243
+ if (userInfo) {
4244
+ return (jsxs("span", { class: "xnote-at xnote-at-complete", ref: props.rootRef, "data-component": props.component.name, children: ["@", userInfo.name] }));
4245
+ }
4246
+ if (readonly() || output()) {
4247
+ return (jsxs("span", { class: "xnote-at", ref: props.rootRef, "data-component": props.component.name, children: [jsx("span", { children: "@" }), slot && adapter.slotRender(slot, children => {
4248
+ return createVNode('span', {
4249
+ class: 'xnote-at-input'
4250
+ }, children);
4251
+ })] }));
4252
+ }
4253
+ const members = props.component.members();
4254
+ return (jsx("span", { class: "xnote-at", ref: props.rootRef, "data-component": props.component.name, children: jsxs(Dropdown, { trigger: 'none', ref: dropdownRef, menu: jsx("div", { class: "xnote-at-menu", ref: membersRef, children: members.map((member, index) => {
4255
+ let hsl = any2Hsl(member.color);
4256
+ if (hsl === 'unknown') {
4257
+ hsl = any2Hsl('#000');
4258
+ }
4259
+ const rgb = hsl2Rgb(hsl);
4260
+ const yiq = (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
4261
+ const color = yiq >= 128 ? '#000' : '#fff';
4262
+ return (jsxs("div", { onClick: () => {
4263
+ props.component.state.userInfo = member;
4264
+ selection.selectComponentEnd(props.component);
4265
+ }, class: ['xnote-at-member', { selected: index === selectedIndex }], children: [jsx("div", { class: "xnote-at-member-avatar", children: member.avatar ? jsx("img", { src: member.avatar, alt: member.name }) :
4266
+ jsx("span", { class: "xnote-at-member-avatar-bg", style: { background: member.color, color }, children: member.name }) }), jsxs("div", { class: "xnote-at-member-info", children: [jsx("div", { class: "xnote-at-member-name", children: member.name }), jsx("div", { class: "xnote-at-member-desc", children: member.groupName })] })] }, member.id));
4267
+ }) }), children: [jsx("span", { children: "@" }), slot && adapter.slotRender(slot, children => {
4268
+ return createVNode('span', {
4269
+ class: 'xnote-at-input'
4270
+ }, children);
4271
+ })] }) }));
4272
+ };
4273
+ }
4274
+ const atComponentLoader = {
4275
+ match(element) {
4276
+ return element.dataset.component === AtComponent.componentName;
4277
+ },
4278
+ read(element, textbus) {
4279
+ return new AtComponent(textbus);
4280
+ }
4281
+ };
4282
+
4033
4283
  class RootComponent extends Component {
4034
4284
  constructor() {
4035
4285
  super(...arguments);
@@ -4047,6 +4297,17 @@ class RootComponent extends Component {
4047
4297
  this.onCompositionStart.next(ev);
4048
4298
  });
4049
4299
  }
4300
+ afterCheck() {
4301
+ const content = this.state.content;
4302
+ const lastContent = content.getContentAtIndex(content.length - 1);
4303
+ if (lastContent instanceof ParagraphComponent ||
4304
+ lastContent instanceof ListComponent ||
4305
+ lastContent instanceof TodolistComponent) {
4306
+ return;
4307
+ }
4308
+ content.retain(content.length);
4309
+ content.insert(new ParagraphComponent(this.textbus));
4310
+ }
4050
4311
  }
4051
4312
  RootComponent.componentName = 'RootComponent';
4052
4313
  RootComponent.type = ContentType.BlockComponent;
@@ -4061,6 +4322,9 @@ function RootView(props) {
4061
4322
  sub.unsubscribe();
4062
4323
  };
4063
4324
  });
4325
+ onUpdated(() => {
4326
+ props.component.afterCheck();
4327
+ });
4064
4328
  const readonly = useReadonly();
4065
4329
  const output = useOutput();
4066
4330
  return () => {
@@ -4188,7 +4452,7 @@ function ResizeColumn(props) {
4188
4452
  });
4189
4453
  }
4190
4454
 
4191
- var scopedId$4 = "vf-d64cf9";
4455
+ var scopedId$4 = "vf-39cb2c";
4192
4456
 
4193
4457
  function TopBar(props) {
4194
4458
  const editorService = inject(EditorService);
@@ -4353,7 +4617,7 @@ function Scroll(props) {
4353
4617
  });
4354
4618
  }
4355
4619
 
4356
- var scopedId$2 = "vf-ef93c0";
4620
+ var scopedId$2 = "vf-aaece0";
4357
4621
 
4358
4622
  function LeftBar(props) {
4359
4623
  const editorService = inject(EditorService);
@@ -4814,7 +5078,8 @@ class Editor extends Textbus {
4814
5078
  [HighlightBoxComponent.componentName]: HighlightBoxView,
4815
5079
  [ListComponent.componentName]: ListComponentView,
4816
5080
  [ImageComponent.componentName]: ImageView,
4817
- [VideoComponent.componentName]: VideoView
5081
+ [VideoComponent.componentName]: VideoView,
5082
+ [AtComponent.componentName]: AtComponentView,
4818
5083
  }, (host, root, injector) => {
4819
5084
  const appInjector = new ReflectiveInjector(injector, [{
4820
5085
  provide: OutputInjectionToken,
@@ -4830,6 +5095,7 @@ class Editor extends Textbus {
4830
5095
  const browserModule = new BrowserModule(Object.assign({ renderTo: () => {
4831
5096
  return this.host;
4832
5097
  }, adapter, componentLoaders: [
5098
+ atComponentLoader,
4833
5099
  sourceCodeComponentLoader,
4834
5100
  tableComponentLoader,
4835
5101
  imageComponentLoader,
@@ -4869,7 +5135,8 @@ class Editor extends Textbus {
4869
5135
  [HighlightBoxComponent.componentName]: HighlightBoxView,
4870
5136
  [ListComponent.componentName]: ListComponentView,
4871
5137
  [ImageComponent.componentName]: ImageView,
4872
- [VideoComponent.componentName]: VideoView
5138
+ [VideoComponent.componentName]: VideoView,
5139
+ [AtComponent.componentName]: AtComponentView
4873
5140
  }, (host, root, injector) => {
4874
5141
  const appInjector = new ReflectiveInjector(injector, [{
4875
5142
  provide: OutputInjectionToken,
@@ -4898,7 +5165,8 @@ class Editor extends Textbus {
4898
5165
  TableComponent,
4899
5166
  HighlightBoxComponent,
4900
5167
  ListComponent,
4901
- VideoComponent
5168
+ VideoComponent,
5169
+ AtComponent
4902
5170
  ], formatters: [
4903
5171
  backgroundColorFormatter,
4904
5172
  boldFormatter,
@@ -4926,6 +5194,7 @@ class Editor extends Textbus {
4926
5194
  registerHeadingShortcut(textbus);
4927
5195
  registerTextAlignShortcut(textbus);
4928
5196
  registerTextIndentShortcut(textbus);
5197
+ registerAtShortcut(textbus);
4929
5198
  } }, editorConfig));
4930
5199
  this.editorConfig = editorConfig;
4931
5200
  this.translator = new OutputTranslator();
@@ -4967,4 +5236,4 @@ class Editor extends Textbus {
4967
5236
  }
4968
5237
  }
4969
5238
 
4970
- export { AttrTool, BlockTool, BlockquoteComponent, BlockquoteView, BoldTool, Button, CodeTool, ColorTool, ComponentToolbar, Divider, DragResize, Dropdown, DropdownContextService, DropdownMenuPortal, DropdownService, Editor, EditorService, FontFamilyTool, FontSizeTool, HighlightBoxComponent, HighlightBoxView, ImageComponent, ImageView, InsertTool, ItalicTool, LeftToolbar, LeftToolbarPlugin, LinkTool, ListComponent, ListComponentView, Matcher, MenuItem, OutputInjectionToken, ParagraphComponent, ParagraphView, Popup, RefreshService, RootComponent, RootView, SourceCodeComponent, SourceCodeView, StrikeThroughTool, TableComponent, TableComponentView, TodolistComponent, TodolistView, Toolbar, ToolbarItem, ToolbarPlugin, UnderlineTool, VideoComponent, VideoView, autoComplete, backgroundColorFormatLoader, backgroundColorFormatter, blockquoteComponentLoader, boldFormatLoader, boldFormatter, codeFormatLoader, codeFormatter, colorFormatLoader, colorFormatter, deltaToBlock, fontFamilyFormatLoader, fontFamilyFormatter, fontSizeFormatLoader, fontSizeFormatter, headingAttr, headingAttrLoader, highlightBoxComponentLoader, imageComponentLoader, isSupportFont, italicFormatLoader, italicFormatter, languageList, linkFormatLoader, linkFormatter, listComponentLoader, paragraphComponentLoader, registerBoldShortcut, registerCodeShortcut, registerHeadingShortcut, registerItalicShortcut, registerStrikeThroughShortcut, registerTextAlignShortcut, registerTextIndentShortcut, registerUnderlineShortcut, rootComponentLoader, sourceCodeComponentLoader, sourceCodeThemes, strikeThroughFormatLoader, strikeThroughFormatter, tableComponentLoader, textAlignAttr, textAlignAttrLoader, textIndentAttr, textIndentAttrLoader, todolistComponentLoader, toggleBold, toggleCode, toggleItalic, toggleStrikeThrough, toggleUnderline, underlineFormatLoader, underlineFormatter, useActiveBlock, useBlockContent, useBlockTransform, useOutput, useReadonly, videoComponentLoader };
5239
+ export { AtComponent, AtComponentView, AttrTool, BlockTool, BlockquoteComponent, BlockquoteView, BoldTool, Button, CodeTool, ColorTool, ComponentToolbar, Divider, DragResize, Dropdown, DropdownContextService, DropdownMenuPortal, DropdownService, Editor, EditorService, FontFamilyTool, FontSizeTool, HighlightBoxComponent, HighlightBoxView, ImageComponent, ImageView, InsertTool, ItalicTool, LeftToolbar, LeftToolbarPlugin, LinkTool, ListComponent, ListComponentView, Matcher, MenuHeading, MenuItem, Organization, OutputInjectionToken, ParagraphComponent, ParagraphView, Popup, RefreshService, RootComponent, RootView, SourceCodeComponent, SourceCodeView, StrikeThroughTool, TableComponent, TableComponentView, TodolistComponent, TodolistView, Toolbar, ToolbarItem, ToolbarPlugin, UnderlineTool, VideoComponent, VideoView, atComponentLoader, autoComplete, backgroundColorFormatLoader, backgroundColorFormatter, blockquoteComponentLoader, boldFormatLoader, boldFormatter, codeFormatLoader, codeFormatter, colorFormatLoader, colorFormatter, deltaToBlock, fontFamilyFormatLoader, fontFamilyFormatter, fontSizeFormatLoader, fontSizeFormatter, headingAttr, headingAttrLoader, highlightBoxComponentLoader, imageComponentLoader, isSupportFont, italicFormatLoader, italicFormatter, languageList, linkFormatLoader, linkFormatter, listComponentLoader, paragraphComponentLoader, registerAtShortcut, registerBoldShortcut, registerCodeShortcut, registerHeadingShortcut, registerItalicShortcut, registerStrikeThroughShortcut, registerTextAlignShortcut, registerTextIndentShortcut, registerUnderlineShortcut, rootComponentLoader, sourceCodeComponentLoader, sourceCodeThemes, strikeThroughFormatLoader, strikeThroughFormatter, tableComponentLoader, textAlignAttr, textAlignAttrLoader, textIndentAttr, textIndentAttrLoader, todolistComponentLoader, toggleBold, toggleCode, toggleItalic, toggleStrikeThrough, toggleUnderline, underlineFormatLoader, underlineFormatter, useActiveBlock, useBlockContent, useBlockTransform, useOutput, useReadonly, videoComponentLoader };