@textbus/xnote 0.0.1-alpha.9 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +103 -1
  2. package/bundles/components/_api.d.ts +2 -0
  3. package/bundles/components/dropdown/dropdown-menu.d.ts +4 -1
  4. package/bundles/components/dropdown/dropdown.d.ts +3 -1
  5. package/bundles/components/keymap/keymap.d.ts +5 -0
  6. package/bundles/components/menu-heading/menu-heading.d.ts +2 -0
  7. package/bundles/components/menu-item/menu-item.d.ts +2 -1
  8. package/bundles/components/popup/popup.d.ts +1 -1
  9. package/bundles/fonts/textbus.svg +3 -32
  10. package/bundles/fonts/textbus.ttf +0 -0
  11. package/bundles/fonts/textbus.woff +0 -0
  12. package/bundles/index.css +2 -2
  13. package/bundles/index.esm.css +2 -2
  14. package/bundles/index.esm.js +1586 -677
  15. package/bundles/index.js +1597 -672
  16. package/bundles/plugins/_api.d.ts +1 -0
  17. package/bundles/plugins/_common/attr.tool.d.ts +2 -2
  18. package/bundles/plugins/_common/color.tool.d.ts +2 -2
  19. package/bundles/plugins/left-toolbar/insert-tool.d.ts +1 -0
  20. package/bundles/plugins/link-jump/link-jump.d.ts +4 -0
  21. package/bundles/public-api.d.ts +1 -0
  22. package/bundles/services/editor.service.d.ts +4 -0
  23. package/bundles/textbus/components/SlotRender.d.ts +14 -0
  24. package/bundles/textbus/components/_api.d.ts +3 -0
  25. package/bundles/textbus/components/at/at-component.view.d.ts +6 -0
  26. package/bundles/textbus/components/at/at.component.d.ts +35 -0
  27. package/bundles/textbus/components/blockqoute/blockquote.component.d.ts +4 -1
  28. package/bundles/textbus/components/highlight-box/highlight-box.component.d.ts +1 -0
  29. package/bundles/textbus/components/image/image.component.d.ts +2 -1
  30. package/bundles/textbus/components/katex/katex-editor.d.ts +7 -0
  31. package/bundles/textbus/components/katex/katex.component.d.ts +16 -0
  32. package/bundles/textbus/components/list/list.component.d.ts +3 -0
  33. package/bundles/textbus/components/paragraph/paragraph.component.d.ts +1 -0
  34. package/bundles/textbus/components/root/root.component.d.ts +2 -0
  35. package/bundles/textbus/components/source-code/source-code.component.d.ts +2 -1
  36. package/bundles/textbus/components/table/components/resize-column.d.ts +2 -1
  37. package/bundles/textbus/components/table/components/scroll.d.ts +1 -2
  38. package/bundles/textbus/components/table/components/top-bar.d.ts +2 -2
  39. package/bundles/textbus/components/table/table-selection-awareness-delegate.d.ts +15 -0
  40. package/bundles/textbus/components/table/table.component.d.ts +1 -1
  41. package/bundles/textbus/components/todolist/todolist.component.d.ts +1 -0
  42. package/bundles/textbus/components/video/video.component.d.ts +1 -1
  43. package/package.json +35 -11
@@ -1,15 +1,17 @@
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, onGetRanges, Formatter, onParentSlotUpdated, Textbus, RootComponentRef, filter, map, distinctUntilChanged, sampleTime, merge, debounceTime, throttleTime, delay, onCompositionStart } from '@textbus/core';
5
- import { VIEW_CONTAINER, DomAdapter, Input, SelectionBridge, VIEW_DOCUMENT, BrowserModule, Parser } from '@textbus/platform-browser';
6
- import { createPortal, DomRenderer, createApp, HTMLRenderer, OutputTranslator } from '@viewfly/platform-browser';
3
+ import { Injectable, InjectFlags, Injector, inject, createSignal, onUnmounted, createRef, withAnnotation, onUpdated, onMounted, InjectionToken, getCurrentInstance, ReflectiveInjector, createDynamicRef, jsx as jsx$1, viewfly, watch } from '@viewfly/core';
4
+ import { Subject, Selection, fromEvent, Subscription, Attribute, Keyboard, Commander, Controller, useContext, onBreak, onContentInsert, ContentType, merge, createVNode, Slot, Component, Registry, Query, QueryStateType, BehaviorSubject, onSlotApplyFormat, onSlotSetAttribute, onPaste, onFocus, onBlur, useDynamicShortcut, VTextNode, onFocusIn, onFocusOut, onDestroy, onGetRanges, Formatter, onParentSlotUpdated, Textbus, RootComponentRef, filter, map, distinctUntilChanged, sampleTime, debounceTime, throttleTime, delay, onContentInserted, onContentDeleted, switchMap, fromPromise, onCompositionStart } from '@textbus/core';
5
+ import { VIEW_CONTAINER, isMac, DomAdapter, Input, SelectionBridge, BrowserModule, VIEW_DOCUMENT, CollaborateSelectionAwarenessDelegate, isMobileBrowser, Parser } from '@textbus/platform-browser';
6
+ import { createPortal, createApp, DomRenderer, HTMLRenderer, OutputTranslator } from '@viewfly/platform-browser';
7
7
  import { useProduce } from '@viewfly/hooks';
8
8
  import highlightjs from 'highlight.js';
9
+ import Katex from 'katex';
9
10
  import { ViewflyAdapter, ViewflyVDomAdapter } from '@textbus/adapter-viewfly';
11
+ import { any2Hsl, hsl2Rgb } from '@tanbo/color';
10
12
  import { CollaborateModule } from '@textbus/collaborate';
11
13
 
12
- var scopedId$k = "vf-3d0183";
14
+ var scopedId$n = "vf-d94b56";
13
15
 
14
16
  /******************************************************************************
15
17
  Copyright (c) Microsoft Corporation.
@@ -28,6 +30,18 @@ PERFORMANCE OF THIS SOFTWARE.
28
30
  /* global Reflect, Promise, SuppressedError, Symbol */
29
31
 
30
32
 
33
+ function __rest(s, e) {
34
+ var t = {};
35
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
36
+ t[p] = s[p];
37
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
38
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
39
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
40
+ t[p[i]] = s[p[i]];
41
+ }
42
+ return t;
43
+ }
44
+
31
45
  function __decorate(decorators, target, key, desc) {
32
46
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
33
47
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -71,7 +85,7 @@ let DropdownContextService = DropdownContextService_1 = class DropdownContextSer
71
85
  this.canHide = true;
72
86
  this.openStateChangeEvent = new Subject();
73
87
  this.timer = null;
74
- this.parentDropdownContextService = this.injector.get(DropdownContextService_1, InjectFlags.SkipSelf, null);
88
+ this.parentDropdownContextService = this.injector.get(DropdownContextService_1, null, InjectFlags.SkipSelf);
75
89
  this.onOpenStateChange = this.openStateChangeEvent.asObservable();
76
90
  dropdownService.onSiblingOpen.subscribe(id => {
77
91
  if (id === this.id) {
@@ -120,7 +134,7 @@ DropdownContextService = DropdownContextService_1 = __decorate([
120
134
  ], DropdownContextService);
121
135
 
122
136
  function Button(props) {
123
- const dropdownContextService = inject(DropdownContextService, InjectFlags.Optional, null);
137
+ const dropdownContextService = inject(DropdownContextService, null);
124
138
  const isActive = createSignal((dropdownContextService === null || dropdownContextService === void 0 ? void 0 : dropdownContextService.isOpen) || false);
125
139
  if (dropdownContextService) {
126
140
  const subscription = dropdownContextService.onOpenStateChange.subscribe(b => {
@@ -130,7 +144,7 @@ function Button(props) {
130
144
  subscription.unsubscribe();
131
145
  });
132
146
  }
133
- return withScopedCSS(scopedId$k, () => {
147
+ return withScopedCSS(scopedId$n, () => {
134
148
  return (jsxs("button", Object.assign({ type: "button" }, props, { class: [
135
149
  'btn',
136
150
  {
@@ -142,10 +156,10 @@ function Button(props) {
142
156
  });
143
157
  }
144
158
 
145
- var scopedId$j = "vf-ac7e8d";
159
+ var scopedId$m = "vf-ac7e8d";
146
160
 
147
161
  function ComponentToolbar(props) {
148
- return withScopedCSS(scopedId$j, () => {
162
+ return withScopedCSS(scopedId$m, () => {
149
163
  return (jsx("div", { class: "component-toolbar", style: props.style, children: jsx("div", { class: [
150
164
  'toolbar',
151
165
  {
@@ -155,15 +169,15 @@ function ComponentToolbar(props) {
155
169
  });
156
170
  }
157
171
 
158
- var scopedId$i = "vf-ede279";
172
+ var scopedId$l = "vf-ede279";
159
173
 
160
174
  function Divider() {
161
- return withScopedCSS(scopedId$i, () => {
175
+ return withScopedCSS(scopedId$l, () => {
162
176
  return jsx("div", { class: "divider" });
163
177
  });
164
178
  }
165
179
 
166
- var scopedId$h = "vf-4c1803";
180
+ var scopedId$k = "vf-8abf2c";
167
181
 
168
182
  function DragResize(props) {
169
183
  const isShow = createSignal(false);
@@ -184,7 +198,7 @@ function DragResize(props) {
184
198
  isShow.set(true);
185
199
  const width = ref.current.offsetWidth;
186
200
  const height = ref.current.offsetHeight;
187
- mask.current.innerText = `${Math.round(width)}px * ${Math.round(height)}px`;
201
+ sizeText.set(`${Math.round(width)}px * ${Math.round(height)}px`);
188
202
  });
189
203
  function selectComponent() {
190
204
  selection.selectComponent(component, true);
@@ -261,7 +275,7 @@ function DragResize(props) {
261
275
  }
262
276
  ele.style.width = endWidth + 'px';
263
277
  ele.style.height = endHeight + 'px';
264
- mask.current.innerText = `${Math.round(endWidth)}px * ${Math.round(endHeight)}px`;
278
+ sizeText.set(`${Math.round(endWidth)}px * ${Math.round(endHeight)}px`);
265
279
  });
266
280
  const unUp = fromEvent(document, 'mouseup').subscribe(() => {
267
281
  component.state.width = endWidth + 'px';
@@ -271,16 +285,17 @@ function DragResize(props) {
271
285
  unUp.unsubscribe();
272
286
  });
273
287
  }
274
- return withScopedCSS(scopedId$h, () => {
288
+ const sizeText = createSignal(`${component.state.width}*${component.state.height}`);
289
+ return withScopedCSS(scopedId$k, () => {
275
290
  return (jsxs("div", { class: "drag-resize", onClick: selectComponent, children: [jsx("div", { class: "container", ref: ref, children: props.children }), jsxs("div", { class: ['resize-tool', {
276
291
  active: isShow()
277
- }], 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" })] })] })] }));
292
+ }], children: [jsx("div", { class: "mask", ref: mask, children: sizeText() }), 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
293
  });
279
294
  }
280
295
 
281
- var scopedId$g = "vf-a99c5e";
296
+ var scopedId$j = "vf-a99c5e";
282
297
 
283
- var scopedId$f = "vf-41a617";
298
+ var scopedId$i = "vf-8a05e9";
284
299
 
285
300
  const DropdownMenuPortal = withAnnotation({
286
301
  providers: [
@@ -288,11 +303,14 @@ const DropdownMenuPortal = withAnnotation({
288
303
  ]
289
304
  }, function DropdownMenuPortal(props) {
290
305
  const dropdownContextService = inject(DropdownContextService);
306
+ const container = inject(VIEW_CONTAINER);
291
307
  const menuRef = createRef();
292
308
  let timer = null;
293
309
  const delay = 10;
294
- onMounted(() => {
310
+ function update() {
295
311
  const menuElement = menuRef.current;
312
+ menuElement.style.height = 'auto';
313
+ const containerRect = container.getBoundingClientRect();
296
314
  if (props.abreast) {
297
315
  const btnEle = props.triggerRef.current;
298
316
  const screenHeight = document.documentElement.clientHeight;
@@ -307,19 +325,19 @@ const DropdownMenuPortal = withAnnotation({
307
325
  else if (offsetTop + maxHeight > screenHeight - 10) {
308
326
  offsetTop = screenHeight - 10 - maxHeight;
309
327
  }
310
- menuElement.style.top = offsetTop + 'px';
328
+ menuElement.style.top = offsetTop - containerRect.top + 'px';
311
329
  const triggerRect = props.triggerRef.current.getBoundingClientRect();
312
330
  const leftDistance = triggerRect.left;
313
331
  const isToLeft = leftDistance >= menuElement.offsetWidth + 20;
314
- if (isToLeft) {
315
- menuElement.style.left = leftDistance - menuElement.offsetWidth - 20 + 'px';
332
+ if (isToLeft && props.toLeft) {
333
+ menuElement.style.left = leftDistance - menuElement.offsetWidth - 20 - containerRect.left + 'px';
316
334
  timer = setTimeout(() => {
317
335
  menuElement.style.transform = 'translateX(10px)';
318
336
  menuElement.style.opacity = '1';
319
337
  }, delay);
320
338
  }
321
339
  else {
322
- menuElement.style.left = triggerRect.right + 20 + 'px';
340
+ menuElement.style.left = triggerRect.right + 20 - containerRect.left + 'px';
323
341
  timer = setTimeout(() => {
324
342
  menuElement.style.transform = 'translateX(-10px)';
325
343
  menuElement.style.opacity = '1';
@@ -331,12 +349,12 @@ const DropdownMenuPortal = withAnnotation({
331
349
  const documentClientHeight = document.documentElement.clientHeight;
332
350
  const bottomDistance = documentClientHeight - triggerRect.bottom;
333
351
  const isToTop = bottomDistance < 200 && triggerRect.top > bottomDistance;
334
- menuElement.style.left = triggerRect.left + 'px';
352
+ menuElement.style.left = triggerRect.left - containerRect.left + 'px';
335
353
  if (isToTop) {
336
354
  const maxHeight = Math.max(menuElement.scrollHeight, menuElement.offsetHeight);
337
355
  const height = Math.min(triggerRect.top - 20, maxHeight, 400);
338
356
  menuElement.style.height = height + 'px';
339
- menuElement.style.top = triggerRect.top - 20 - height + 'px';
357
+ menuElement.style.top = triggerRect.top - 20 - height - containerRect.top + 'px';
340
358
  timer = setTimeout(() => {
341
359
  menuElement.style.transform = 'translateY(10px)';
342
360
  menuElement.style.opacity = '1';
@@ -344,30 +362,41 @@ const DropdownMenuPortal = withAnnotation({
344
362
  }
345
363
  else {
346
364
  menuElement.style.height = Math.min(bottomDistance - 20, menuElement.scrollHeight) + 'px';
347
- menuElement.style.top = triggerRect.bottom + 20 + 'px';
365
+ menuElement.style.top = triggerRect.bottom + 20 - containerRect.top + 'px';
348
366
  timer = setTimeout(() => {
349
367
  menuElement.style.transform = 'translateY(-10px)';
350
368
  menuElement.style.opacity = '1';
351
369
  }, delay);
352
370
  }
353
371
  }
372
+ }
373
+ onUpdated(() => {
374
+ update();
354
375
  });
355
376
  onUnmounted(() => {
356
377
  clearTimeout(timer);
357
378
  });
358
379
  function onEnter() {
380
+ if (props.noTrigger) {
381
+ return;
382
+ }
359
383
  dropdownContextService.canHide = false;
360
384
  dropdownContextService.open();
361
385
  }
362
386
  function onLeave() {
387
+ if (props.noTrigger) {
388
+ return;
389
+ }
363
390
  dropdownContextService.canHide = true;
364
391
  dropdownContextService.hide();
365
392
  }
366
- return createPortal(withScopedCSS(scopedId$f, () => {
393
+ return createPortal(withScopedCSS(scopedId$i, () => {
367
394
  return (jsx("div", { onMouseenter: onEnter, onMouseleave: onLeave, ref: menuRef, style: {
368
395
  width: props.width
369
- }, class: "dropdown-menu", children: jsx("div", { class: "dropdown-menu-content", children: props.children }) }));
370
- }), document.body);
396
+ }, class: "dropdown-menu", children: jsx("div", { class: "dropdown-menu-content", style: {
397
+ padding: props.padding
398
+ }, children: props.children }) }));
399
+ }), container);
371
400
  });
372
401
 
373
402
  const Dropdown = withAnnotation({
@@ -395,6 +424,9 @@ const Dropdown = withAnnotation({
395
424
  });
396
425
  const subscription = new Subscription();
397
426
  onMounted(() => {
427
+ if (props.trigger === 'none') {
428
+ return;
429
+ }
398
430
  if (props.trigger === 'click') {
399
431
  subscription.add(fromEvent(triggerRef.current, 'click').subscribe(toggle));
400
432
  return;
@@ -420,14 +452,14 @@ const Dropdown = withAnnotation({
420
452
  return {
421
453
  isShow(b) {
422
454
  if (b) {
423
- dropdownContextService.hide(false);
455
+ dropdownContextService.open();
424
456
  }
425
457
  else {
426
- dropdownContextService.open();
458
+ dropdownContextService.hide(false);
427
459
  }
428
460
  },
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) ?
461
+ $render: withScopedCSS(scopedId$j, () => {
462
+ 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, { toLeft: props.toLeft, padding: props.padding, noTrigger: props.trigger === 'none', width: props.width, abreast: props.abreast, triggerRef: triggerRef, children: Array.isArray(props.menu) ?
431
463
  props.menu.map(menu => {
432
464
  return (jsx("div", { class: "dropdown-menu-item", onClick: () => {
433
465
  var _a;
@@ -442,10 +474,54 @@ const Dropdown = withAnnotation({
442
474
  };
443
475
  });
444
476
 
445
- var scopedId$e = "vf-678daa";
477
+ var scopedId$h = "vf-c32a7b";
478
+
479
+ function Keymap(props) {
480
+ const arr = [];
481
+ const keymap = props.keymap;
482
+ if (keymap.ctrlKey) {
483
+ arr.push(isMac() ? jsx("span", { class: "xnote-icon-command" }) : jsx("span", { children: "Ctrl" }));
484
+ }
485
+ if (keymap.shiftKey) {
486
+ if (arr.length) {
487
+ arr.push('+');
488
+ }
489
+ arr.push(isMac() ? jsx("span", { class: "xnote-icon-shift" }) : jsx("span", { children: "Shift" }));
490
+ }
491
+ if (keymap.altKey) {
492
+ if (arr.length) {
493
+ arr.push('+');
494
+ }
495
+ arr.push(isMac() ? jsx("span", { class: "xnote-icon-opt" }) : jsx("span", { children: "Alt" }));
496
+ }
497
+ if (keymap.key) {
498
+ if (arr.length) {
499
+ arr.push('+');
500
+ }
501
+ if (Array.isArray(keymap.key)) {
502
+ arr.push(jsx("span", { children: keymap.key.join('/') }));
503
+ }
504
+ else {
505
+ arr.push(jsx("span", { children: keymap.key }));
506
+ }
507
+ }
508
+ return withScopedCSS(scopedId$h, () => {
509
+ return (jsx("span", { class: "keymap", children: arr }));
510
+ });
511
+ }
512
+
513
+ var scopedId$g = "vf-acaa5f";
514
+
515
+ function MenuHeading(props) {
516
+ return withScopedCSS(scopedId$g, () => {
517
+ return (jsx("div", { class: "menu-heading", children: props.children }));
518
+ });
519
+ }
520
+
521
+ var scopedId$f = "vf-c3b9dc";
446
522
 
447
523
  function MenuItem(props) {
448
- const dropdownContextService = inject(DropdownContextService, InjectFlags.Optional, null);
524
+ const dropdownContextService = inject(DropdownContextService, null);
449
525
  const isActive = createSignal((dropdownContextService === null || dropdownContextService === void 0 ? void 0 : dropdownContextService.isOpen) || false);
450
526
  if (dropdownContextService) {
451
527
  const subscription = dropdownContextService.onOpenStateChange.subscribe(b => {
@@ -462,8 +538,8 @@ function MenuItem(props) {
462
538
  }
463
539
  (_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props, props.value);
464
540
  }
465
- return withScopedCSS(scopedId$e, () => {
466
- return (jsxs("div", { class: ['menu-item', { disabled: props.disabled, active: props.arrow && isActive() }], onClick: click, children: [jsxs("div", { children: [props.icon && jsx("span", { class: "menu-icon", children: props.icon }), props.children] }), props.arrow ?
541
+ return withScopedCSS(scopedId$f, () => {
542
+ return (jsxs("div", { class: ['menu-item', { disabled: props.disabled, active: props.arrow && isActive() }], onClick: click, children: [jsxs("div", { class: "menu-item-content", children: [jsxs("div", { children: [props.icon && jsx("span", { class: "menu-icon", children: props.icon }), props.children] }), jsx("div", { children: props.desc })] }), props.arrow ?
467
543
  jsx("div", { class: "arrow", children: jsx("span", { class: "xnote-icon-arrow-right" }) }) :
468
544
  jsx("div", { class: [
469
545
  'menu-check',
@@ -472,11 +548,11 @@ function MenuItem(props) {
472
548
  });
473
549
  }
474
550
 
475
- var scopedId$d = "vf-a23c47";
551
+ var scopedId$e = "vf-a23c47";
476
552
 
477
553
  function Popup(props) {
478
554
  const host = inject(VIEW_CONTAINER);
479
- return createPortal(withScopedCSS(scopedId$d, () => {
555
+ return createPortal(withScopedCSS(scopedId$e, () => {
480
556
  return (jsx("div", { class: "popup", style: {
481
557
  left: props.left + 'px',
482
558
  top: props.top + 'px'
@@ -484,15 +560,15 @@ function Popup(props) {
484
560
  }), host);
485
561
  }
486
562
 
487
- var scopedId$c = "vf-216815";
563
+ var scopedId$d = "vf-216815";
488
564
 
489
565
  function ToolbarItem(props) {
490
- return withScopedCSS(scopedId$c, () => {
566
+ return withScopedCSS(scopedId$d, () => {
491
567
  return (jsx("div", { class: "toolbar-item", children: props.children }));
492
568
  });
493
569
  }
494
570
 
495
- var scopedId$b = "vf-2a8a65";
571
+ var scopedId$c = "vf-2a8a65";
496
572
 
497
573
  let RefreshService = class RefreshService {
498
574
  constructor() {
@@ -554,6 +630,308 @@ function useOutput() {
554
630
  return createSignal(inject(OutputInjectionToken));
555
631
  }
556
632
 
633
+ const headingAttr = new Attribute('Heading', {
634
+ render(node, formatValue) {
635
+ node.classes.add('xnote-' + formatValue);
636
+ }
637
+ });
638
+ const headingAttrLoader = {
639
+ match(element) {
640
+ return /H[1-6]/.test(element.tagName) || /(^|\s)xnote-h[1-6](\s|$)/.test(element.className);
641
+ },
642
+ read(element) {
643
+ if (/H[1-6]/.test(element.tagName)) {
644
+ return {
645
+ attribute: headingAttr,
646
+ value: element.tagName.toLowerCase()
647
+ };
648
+ }
649
+ return {
650
+ attribute: headingAttr,
651
+ value: element.className.substring(6)
652
+ };
653
+ }
654
+ };
655
+ function registerHeadingShortcut(textbus) {
656
+ const keyboard = textbus.get(Keyboard);
657
+ const commander = textbus.get(Commander);
658
+ const selection = textbus.get(Selection);
659
+ keyboard.addShortcut({
660
+ keymap: {
661
+ key: '0123456'.split(''),
662
+ ctrlKey: true
663
+ },
664
+ action(key) {
665
+ if (key === '0') {
666
+ commander.unApplyAttribute(headingAttr);
667
+ return;
668
+ }
669
+ commander.applyAttribute(headingAttr, 'h' + key);
670
+ }
671
+ });
672
+ keyboard.addZenCodingInterceptor({
673
+ match(content) {
674
+ return /^#{1,6}$/.test(content);
675
+ },
676
+ try(key) {
677
+ return key === ' ';
678
+ },
679
+ action(content) {
680
+ if (selection.commonAncestorComponent instanceof SourceCodeComponent) {
681
+ return false;
682
+ }
683
+ const commonAncestorSlot = selection.commonAncestorSlot;
684
+ commonAncestorSlot.cut();
685
+ commander.applyAttribute(headingAttr, 'h' + content.length);
686
+ selection.setPosition(commonAncestorSlot, 0);
687
+ return true;
688
+ }
689
+ });
690
+ }
691
+
692
+ function useBlockContent(slot) {
693
+ const textbus = useContext();
694
+ const selection = textbus.get(Selection);
695
+ onBreak(ev => {
696
+ if (typeof slot === 'function' ? slot(ev.target) : ev.target === slot) {
697
+ const p = new ParagraphComponent(textbus);
698
+ ev.target.insert(p);
699
+ selection.setPosition(p.state.slot, 0);
700
+ ev.preventDefault();
701
+ }
702
+ });
703
+ onContentInsert(ev => {
704
+ if ((typeof slot === 'function' ? slot(ev.target) : ev.target === slot) &&
705
+ (typeof ev.data.content === 'string' || ev.data.content.type !== ContentType.BlockComponent)) {
706
+ const p = new ParagraphComponent(textbus);
707
+ const childSlot = p.state.slot;
708
+ childSlot.insert(ev.data.content);
709
+ ev.target.insert(p);
710
+ selection.setPosition(childSlot, childSlot.index);
711
+ ev.preventDefault();
712
+ }
713
+ });
714
+ }
715
+
716
+ function SlotRender(props) {
717
+ const adapter = inject(DomAdapter);
718
+ const instance = getCurrentInstance();
719
+ const slot = props.slot;
720
+ const sub = merge(slot.__changeMarker__.onChange, slot.__changeMarker__.onForceChange).subscribe(() => {
721
+ if (props.slot.__changeMarker__.dirty) {
722
+ instance.markAsDirtied();
723
+ }
724
+ });
725
+ onUnmounted(() => {
726
+ sub.unsubscribe();
727
+ });
728
+ return () => {
729
+ const { slot, tag = 'div', renderEnv = false, elRef, elKey } = props, rest = __rest(props, ["slot", "tag", "renderEnv", "elRef", "elKey"]);
730
+ return adapter.slotRender(slot, children => {
731
+ return createVNode(tag, Object.assign({ ref: elRef, key: elKey }, rest), children);
732
+ }, renderEnv);
733
+ };
734
+ }
735
+
736
+ class BlockquoteComponent extends Component {
737
+ static fromJSON(textbus, json) {
738
+ const slot = textbus.get(Registry).createSlot(json.slot);
739
+ return new BlockquoteComponent(textbus, {
740
+ slot
741
+ });
742
+ }
743
+ constructor(textbus, state = {
744
+ slot: new Slot([
745
+ ContentType.BlockComponent
746
+ ])
747
+ }) {
748
+ super(textbus, state);
749
+ }
750
+ getSlots() {
751
+ return [this.state.slot];
752
+ }
753
+ setup() {
754
+ useBlockContent(this.state.slot);
755
+ }
756
+ }
757
+ BlockquoteComponent.type = ContentType.BlockComponent;
758
+ BlockquoteComponent.componentName = 'BlockquoteComponent';
759
+ BlockquoteComponent.zenCoding = {
760
+ key: ' ',
761
+ match(content, textbus) {
762
+ const selection = textbus.get(Selection);
763
+ if (selection.commonAncestorComponent instanceof ParagraphComponent) {
764
+ return /^>$/.test(content);
765
+ }
766
+ return false;
767
+ },
768
+ createState(_, textbus) {
769
+ const selection = textbus.get(Selection);
770
+ const commonAncestorSlot = selection.commonAncestorSlot;
771
+ const slot = new Slot([
772
+ ContentType.BlockComponent
773
+ ]);
774
+ if (commonAncestorSlot === null || commonAncestorSlot === void 0 ? void 0 : commonAncestorSlot.hasAttribute(textIndentAttr)) {
775
+ slot.setAttribute(textIndentAttr, commonAncestorSlot.getAttribute(textIndentAttr));
776
+ }
777
+ return {
778
+ slot
779
+ };
780
+ }
781
+ };
782
+ function toBlockquote(textbus) {
783
+ const query = textbus.get(Query);
784
+ const commander = textbus.get(Commander);
785
+ const selection = textbus.get(Selection);
786
+ const state = query.queryComponent(BlockquoteComponent);
787
+ if (state.state === QueryStateType.Enabled) {
788
+ const current = state.value;
789
+ const parent = current.parent;
790
+ const index = parent.indexOf(current);
791
+ parent.retain(index);
792
+ commander.removeComponent(current);
793
+ current.slots.at(0).sliceContent().forEach(i => {
794
+ parent.insert(i);
795
+ });
796
+ }
797
+ else {
798
+ const block = new BlockquoteComponent(textbus);
799
+ const slot = block.state.slot;
800
+ if (selection.startSlot === selection.endSlot) {
801
+ const parentComponent = selection.startSlot.parent;
802
+ const parentSlot = parentComponent.parent;
803
+ const position = parentSlot.indexOf(parentComponent);
804
+ slot.insert(parentComponent);
805
+ parentSlot.retain(position);
806
+ parentSlot.insert(block);
807
+ }
808
+ else {
809
+ const commonAncestorSlot = selection.commonAncestorSlot;
810
+ const scope = selection.getCommonAncestorSlotScope();
811
+ commonAncestorSlot.cut(scope.startOffset, scope.endOffset).sliceContent().forEach(i => {
812
+ slot.insert(i);
813
+ });
814
+ commonAncestorSlot.retain(scope.startOffset);
815
+ commonAncestorSlot.insert(block);
816
+ }
817
+ }
818
+ }
819
+ function registerBlockquoteShortcut(textbus) {
820
+ const keyboard = textbus.get(Keyboard);
821
+ keyboard.addShortcut({
822
+ keymap: {
823
+ ctrlKey: true,
824
+ key: '\''
825
+ },
826
+ action() {
827
+ toBlockquote(textbus);
828
+ }
829
+ });
830
+ }
831
+ function BlockquoteView(props) {
832
+ const readonly = useReadonly();
833
+ const output = useOutput();
834
+ return () => {
835
+ const slot = props.component.state.slot;
836
+ return (jsx("blockquote", { class: "xnote-blockquote", ref: props.rootRef, "data-component": props.component.name, children: jsx(SlotRender, { slot: slot, renderEnv: readonly() || output() }) }));
837
+ };
838
+ }
839
+ const blockquoteComponentLoader = {
840
+ match(element, returnableContentTypes) {
841
+ return returnableContentTypes.includes(ContentType.BlockComponent) && element.tagName === 'BLOCKQUOTE';
842
+ },
843
+ read(element, textbus, slotParser) {
844
+ const delta = slotParser(new Slot([
845
+ ContentType.BlockComponent,
846
+ ContentType.InlineComponent,
847
+ ContentType.Text
848
+ ]), element).toDelta();
849
+ const slot = new Slot([
850
+ ContentType.BlockComponent,
851
+ ]);
852
+ deltaToBlock(delta, textbus).forEach(i => {
853
+ slot.insert(i);
854
+ });
855
+ return new BlockquoteComponent(textbus, {
856
+ slot
857
+ });
858
+ },
859
+ };
860
+
861
+ class HighlightBoxComponent extends Component {
862
+ static fromJSON(textbus, json) {
863
+ return new HighlightBoxComponent(textbus, {
864
+ type: json.type,
865
+ slot: textbus.get(Registry).createSlot(json.slot)
866
+ });
867
+ }
868
+ constructor(textbus, state = {
869
+ type: '',
870
+ slot: new Slot([
871
+ ContentType.BlockComponent,
872
+ ])
873
+ }) {
874
+ super(textbus, state);
875
+ }
876
+ getSlots() {
877
+ return [this.state.slot];
878
+ }
879
+ setup() {
880
+ useBlockContent(this.state.slot);
881
+ }
882
+ }
883
+ HighlightBoxComponent.defaultTypes = ['❤️', '💡', '📌', '✅', '❎', '👍', '🎉', '🚫', '❗'];
884
+ HighlightBoxComponent.componentName = 'HighlightBoxComponent';
885
+ HighlightBoxComponent.type = ContentType.BlockComponent;
886
+ function HighlightBoxView(props) {
887
+ const readonly = useReadonly();
888
+ const output = useOutput();
889
+ const emoji = [];
890
+ for (let i = 0x1F600; i <= 0x1F64F; i++) {
891
+ emoji.push(i);
892
+ }
893
+ const dropdownRef = createRef();
894
+ function setType(type) {
895
+ var _a;
896
+ (_a = dropdownRef.current) === null || _a === void 0 ? void 0 : _a.isShow(false);
897
+ props.component.state.type = type;
898
+ }
899
+ return () => {
900
+ const { state, name } = props.component;
901
+ if (readonly() || output()) {
902
+ 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 || '❤️' }) }) }), jsx(SlotRender, { slot: state.slot, class: 'xnote-highlight-box-content', renderEnv: readonly() || output() })] }));
903
+ }
904
+ 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 => {
905
+ return (jsx("button", { onClick: () => setType(icon), type: "button", children: icon }));
906
+ }), jsx("div", { class: "xnote-highlight-box-heading", children: "\u66F4\u591A" }), emoji.map(i => {
907
+ const icon = String.fromCodePoint(i);
908
+ return (jsx("button", { onClick: () => setType(icon), type: "button", children: icon }));
909
+ })] }), children: jsx("div", { class: "xnote-highlight-box-icon", children: jsx("button", { type: "button", children: state.type || '❤️' }) }) }) }), jsx(SlotRender, { slot: state.slot, class: 'xnote-highlight-box-content', renderEnv: readonly() || output() })] }));
910
+ };
911
+ }
912
+ const highlightBoxComponentLoader = {
913
+ match(element) {
914
+ return element.tagName === 'DIV' && element.dataset.component === HighlightBoxComponent.componentName;
915
+ },
916
+ read(element, textbus, slotParser) {
917
+ const delta = slotParser(new Slot([
918
+ ContentType.BlockComponent,
919
+ ContentType.InlineComponent,
920
+ ContentType.Text
921
+ ]), element.querySelector('.xnote-highlight-box-content')).toDelta();
922
+ const slot = new Slot([
923
+ ContentType.BlockComponent,
924
+ ]);
925
+ deltaToBlock(delta, textbus).forEach(i => {
926
+ slot.insert(i);
927
+ });
928
+ return new HighlightBoxComponent(textbus, {
929
+ type: element.dataset.icon || '',
930
+ slot
931
+ });
932
+ }
933
+ };
934
+
557
935
  class ParagraphComponent extends Component {
558
936
  static fromJSON(textbus, json) {
559
937
  const slot = textbus.get(Registry).createSlot(json.slot);
@@ -569,16 +947,28 @@ class ParagraphComponent extends Component {
569
947
  }) {
570
948
  super(textbus, state);
571
949
  }
950
+ getSlots() {
951
+ return [this.state.slot];
952
+ }
572
953
  setup() {
573
954
  const injector = useContext();
574
955
  const commander = injector.get(Commander);
575
956
  const selection = injector.get(Selection);
576
957
  onBreak(ev => {
958
+ const isEmpty = this.state.slot.isEmpty;
577
959
  const afterSlot = ev.target.cut(ev.data.index);
960
+ afterSlot.removeAttribute(headingAttr);
578
961
  const nextParagraph = new ParagraphComponent(injector, {
579
962
  slot: afterSlot
580
963
  });
581
- commander.insertAfter(nextParagraph, this);
964
+ if (isEmpty && (this.parentComponent instanceof BlockquoteComponent ||
965
+ this.parentComponent instanceof HighlightBoxComponent)) {
966
+ commander.insertAfter(nextParagraph, this.parentComponent);
967
+ commander.removeComponent(this);
968
+ }
969
+ else {
970
+ commander.insertAfter(nextParagraph, this);
971
+ }
582
972
  selection.setPosition(afterSlot, 0);
583
973
  ev.preventDefault();
584
974
  });
@@ -587,22 +977,30 @@ class ParagraphComponent extends Component {
587
977
  ParagraphComponent.componentName = 'ParagraphComponent';
588
978
  ParagraphComponent.type = ContentType.BlockComponent;
589
979
  function ParagraphView(props) {
590
- const adapter = inject(DomAdapter);
591
980
  const readonly = useReadonly();
592
981
  const output = useOutput();
593
982
  return () => {
594
983
  const slot = props.component.state.slot;
595
- return (jsx("div", { class: "xnote-paragraph", ref: props.rootRef, "data-component": ParagraphComponent.name, children: adapter.slotRender(slot, children => {
596
- return (createVNode('p', null, children));
597
- }, readonly() || output()) }));
984
+ return (jsx("div", { class: "xnote-paragraph", ref: props.rootRef, "data-component": ParagraphComponent.componentName, children: jsx(SlotRender, { tag: "div", slot: slot, renderEnv: readonly() || output() }) }));
598
985
  };
599
986
  }
600
987
  const paragraphComponentLoader = {
601
- match(element) {
602
- return element.dataset.compoment === ParagraphComponent.name || /P|H[1-6]/.test(element.tagName);
988
+ match(element, returnableContentTypes) {
989
+ return returnableContentTypes.includes(ContentType.BlockComponent) && (element.dataset.component === ParagraphComponent.componentName || /^P|H[1-6]$/.test(element.tagName));
603
990
  },
604
991
  read(element, textbus, slotParser) {
605
- const content = /P|H[1-6]/.test(element.tagName) ? element : element.children[0];
992
+ let content;
993
+ if (/^P|H[1-6]$/.test(element.tagName)) {
994
+ content = element;
995
+ }
996
+ else {
997
+ content = element.children[0];
998
+ if (!content) {
999
+ const p = document.createElement('p');
1000
+ p.append(element.innerText);
1001
+ content = p;
1002
+ }
1003
+ }
606
1004
  const delta = slotParser(new Slot([
607
1005
  ContentType.Text,
608
1006
  ContentType.InlineComponent,
@@ -678,6 +1076,15 @@ const languageList = [{
678
1076
  }, {
679
1077
  label: 'Go',
680
1078
  value: 'Go'
1079
+ }, {
1080
+ label: 'Kotlin',
1081
+ value: 'kotlin'
1082
+ }, {
1083
+ label: 'Python',
1084
+ value: 'python'
1085
+ }, {
1086
+ label: 'PHP',
1087
+ value: 'php'
681
1088
  }, {
682
1089
  label: 'JSON',
683
1090
  value: 'JSON',
@@ -702,6 +1109,9 @@ const languageList = [{
702
1109
  }, {
703
1110
  label: 'Shell',
704
1111
  value: 'shell',
1112
+ }, {
1113
+ label: 'Katex',
1114
+ value: 'latex',
705
1115
  }, {
706
1116
  label: 'Yaml',
707
1117
  value: 'yaml',
@@ -720,11 +1130,16 @@ const languageList = [{
720
1130
  }, {
721
1131
  label: 'Dart',
722
1132
  value: 'dart',
1133
+ }, {
1134
+ label: 'Rust',
1135
+ value: 'rust',
723
1136
  }, {
724
1137
  label: '',
725
1138
  value: '',
726
1139
  }];
727
1140
  const sourceCodeThemes = [
1141
+ 'xnote-dark',
1142
+ 'xnote-dark-blue',
728
1143
  'github',
729
1144
  'atom-one-dark',
730
1145
  'foundation',
@@ -780,12 +1195,17 @@ class SourceCodeComponent extends Component {
780
1195
  theme: json.theme
781
1196
  });
782
1197
  }
1198
+ getSlots() {
1199
+ return this.state.slots.map(i => i.slot);
1200
+ }
783
1201
  setup() {
784
1202
  const textbus = useContext();
785
1203
  const selection = useContext(Selection);
786
1204
  onBreak(ev => {
787
1205
  const slots = this.state.slots;
788
- if (ev.target.isEmpty && ev.target === slots[slots.length - 1].slot) {
1206
+ const parentComponent = selection.commonAncestorComponent;
1207
+ const parentSlot = parentComponent.parent;
1208
+ if (parentSlot && ev.target.isEmpty && ev.target === slots[slots.length - 1].slot) {
789
1209
  const prevSlot = slots[slots.length - 2];
790
1210
  if (prevSlot === null || prevSlot === void 0 ? void 0 : prevSlot.slot.isEmpty) {
791
1211
  const slot = new Slot([
@@ -795,8 +1215,6 @@ class SourceCodeComponent extends Component {
795
1215
  const paragraph = new ParagraphComponent(textbus, {
796
1216
  slot
797
1217
  });
798
- const parentComponent = selection.commonAncestorComponent;
799
- const parentSlot = parentComponent.parent;
800
1218
  const index = parentSlot.indexOf(parentComponent);
801
1219
  parentSlot.retain(index + 1);
802
1220
  slots.pop();
@@ -824,6 +1242,12 @@ class SourceCodeComponent extends Component {
824
1242
  });
825
1243
  ev.preventDefault();
826
1244
  });
1245
+ onSlotApplyFormat(ev => {
1246
+ ev.preventDefault();
1247
+ });
1248
+ onSlotSetAttribute(ev => {
1249
+ ev.preventDefault();
1250
+ });
827
1251
  onPaste(ev => {
828
1252
  const codeList = [];
829
1253
  const sourceCode = ev.data.text;
@@ -947,11 +1371,15 @@ class SourceCodeComponent extends Component {
947
1371
  SourceCodeComponent.type = ContentType.BlockComponent;
948
1372
  SourceCodeComponent.componentName = 'SourceCodeComponent';
949
1373
  SourceCodeComponent.zenCoding = {
950
- key: 'Enter',
951
- match(c) {
952
- const matchString = languageList.map(i => i.label || i.value).concat('js', 'ts').join('|').replace(/\+/, '\\+');
953
- const reg = new RegExp(`^\`\`\`(${matchString})$`, 'i');
954
- return reg.test(c);
1374
+ key: ['Enter', ' '],
1375
+ match(c, textbus) {
1376
+ const selection = textbus.get(Selection);
1377
+ if (selection.commonAncestorComponent instanceof ParagraphComponent) {
1378
+ const matchString = languageList.map(i => i.label || i.value).concat('js', 'ts').join('|').replace(/\+/, '\\+');
1379
+ const reg = new RegExp(`^\`\`\`(${matchString})$`, 'i');
1380
+ return reg.test(c);
1381
+ }
1382
+ return false;
955
1383
  },
956
1384
  createState(content) {
957
1385
  const matchString = content.replace(/`/g, '').replace(/\+/, '\\+');
@@ -1018,7 +1446,7 @@ function SourceCodeView(props) {
1018
1446
  }
1019
1447
  const input = inject(Input);
1020
1448
  function updateCaret() {
1021
- input.caret.refresh(false);
1449
+ input.caret.refresh();
1022
1450
  }
1023
1451
  const readonly = useReadonly();
1024
1452
  const output = useOutput();
@@ -1055,28 +1483,6 @@ function SourceCodeView(props) {
1055
1483
  }
1056
1484
  }
1057
1485
  }
1058
- function nodesToVNodes(slot, nodes, index) {
1059
- return nodes.map(i => {
1060
- const location = {
1061
- slot,
1062
- startIndex: index,
1063
- endIndex: index + i.textContent.length
1064
- };
1065
- if (i.nodeType === Node.ELEMENT_NODE) {
1066
- const childNodes = Array.from(i.childNodes);
1067
- const vEle = createVNode('span', {
1068
- class: i.className
1069
- }, nodesToVNodes(slot, childNodes, index));
1070
- index = location.endIndex;
1071
- vEle.location = Object.assign({}, location);
1072
- return vEle;
1073
- }
1074
- index = location.endIndex;
1075
- const textNode = new VTextNode(i.textContent);
1076
- textNode.location = location;
1077
- return textNode;
1078
- });
1079
- }
1080
1486
  return (jsxs("div", { ref: props.rootRef, class: {
1081
1487
  'xnote-source-code': true,
1082
1488
  'xnote-source-code-line-number': state.lineNumber,
@@ -1107,7 +1513,7 @@ function SourceCodeView(props) {
1107
1513
  }
1108
1514
  ], children: [jsx("div", { class: "xnote-source-code-line-number-bg", style: {
1109
1515
  width: Math.max(String(slots.length).length, 2.5) + 'em'
1110
- } }), jsx("div", { onScroll: updateCaret, class: {
1516
+ } }), jsx("pre", { onScroll: updateCaret, class: {
1111
1517
  'xnote-source-code-content': true,
1112
1518
  'xnote-source-code-content-highlight': blockHighlight
1113
1519
  }, style: {
@@ -1128,7 +1534,7 @@ function SourceCodeView(props) {
1128
1534
  children.push(br);
1129
1535
  }
1130
1536
  }
1131
- return createVNode('pre', {
1537
+ return createVNode('div', {
1132
1538
  class: 'xnote-source-code-line' + (item.emphasize ? ' xnote-source-code-line-emphasize' : '')
1133
1539
  }, [
1134
1540
  createVNode('span', { class: 'xnote-source-code-line-content' }, children)
@@ -1137,10 +1543,33 @@ function SourceCodeView(props) {
1137
1543
  }) }), jsx("span", { class: "xnote-source-code-lang", children: lang })] })] }));
1138
1544
  };
1139
1545
  }
1546
+ function nodesToVNodes(slot, nodes, index) {
1547
+ return nodes.map(i => {
1548
+ const location = {
1549
+ slot,
1550
+ startIndex: index,
1551
+ endIndex: index + i.textContent.length
1552
+ };
1553
+ if (i.nodeType === Node.ELEMENT_NODE) {
1554
+ const childNodes = Array.from(i.childNodes);
1555
+ const vEle = createVNode('span', {
1556
+ class: i.className
1557
+ }, nodesToVNodes(slot, childNodes, index));
1558
+ index = location.endIndex;
1559
+ vEle.location = Object.assign({}, location);
1560
+ return vEle;
1561
+ }
1562
+ index = location.endIndex;
1563
+ const textNode = new VTextNode(i.textContent);
1564
+ textNode.location = location;
1565
+ return textNode;
1566
+ });
1567
+ }
1140
1568
  const sourceCodeComponentLoader = {
1141
- match(element) {
1142
- return (element.tagName === 'DIV' && element.dataset.component === SourceCodeComponent.componentName) ||
1143
- element.tagName === 'PRE';
1569
+ match(element, returnableContentTypes) {
1570
+ return returnableContentTypes.includes(ContentType.BlockComponent) &&
1571
+ ((element.tagName === 'DIV' && element.dataset.component === SourceCodeComponent.componentName) ||
1572
+ element.tagName === 'PRE');
1144
1573
  },
1145
1574
  read(el, textbus) {
1146
1575
  let slots = [];
@@ -1268,15 +1697,26 @@ function AttrTool(props) {
1268
1697
  textIndent: 0
1269
1698
  });
1270
1699
  function updateCheckStates() {
1271
- var _a, _b;
1272
- (_a = props.queryBefore) === null || _a === void 0 ? void 0 : _a.call(props);
1700
+ if (!props.slot && !selection.isSelected) {
1701
+ return;
1702
+ }
1273
1703
  setCheckStates(draft => {
1274
- const textAlignState = query.queryAttribute(textAlignAttr);
1275
- const textIndentState = query.queryAttribute(textIndentAttr);
1704
+ const range = props.slot ? {
1705
+ startSlot: props.slot,
1706
+ endSlot: props.slot,
1707
+ startOffset: 0,
1708
+ endOffset: props.slot.length
1709
+ } : {
1710
+ startSlot: selection.startSlot,
1711
+ startOffset: selection.startOffset,
1712
+ endSlot: selection.endSlot,
1713
+ endOffset: selection.endOffset
1714
+ };
1715
+ const textAlignState = query.queryAttributeByRange(textAlignAttr, range);
1716
+ const textIndentState = query.queryAttributeByRange(textIndentAttr, range);
1276
1717
  draft.textAlign = textAlignState.state === QueryStateType.Enabled ? textAlignState.value : 'left';
1277
1718
  draft.textIndent = textIndentState.state === QueryStateType.Enabled ? textIndentState.value : 0;
1278
1719
  });
1279
- (_b = props.queryAfter) === null || _b === void 0 ? void 0 : _b.call(props);
1280
1720
  }
1281
1721
  updateCheckStates();
1282
1722
  const subscription = refreshService.onRefresh.subscribe(() => {
@@ -1323,110 +1763,35 @@ function AttrTool(props) {
1323
1763
  break;
1324
1764
  }
1325
1765
  }
1326
- return withScopedCSS(scopedId$b, () => {
1766
+ return withScopedCSS(scopedId$c, () => {
1327
1767
  const states = checkStates();
1328
- return (jsx(Dropdown, { style: props.style, abreast: props.abreast, onCheck: updateAttr, trigger: 'hover', menu: [
1768
+ return (jsx(Dropdown, { width: 'auto', style: props.style, abreast: props.abreast, onCheck: updateAttr, trigger: 'hover', menu: [
1329
1769
  {
1330
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-paragraph-left" }), checked: states.textAlign === 'left', children: "\u5DE6\u5BF9\u9F50" }),
1770
+ label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-paragraph-left" }), desc: jsx(Keymap, { keymap: { key: 'L', ctrlKey: true } }), checked: states.textAlign === 'left', children: "\u5DE6\u5BF9\u9F50" }),
1331
1771
  value: 't-l'
1332
1772
  }, {
1333
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-paragraph-right" }), checked: states.textAlign === 'right', children: "\u53F3\u5BF9\u9F50" }),
1773
+ label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-paragraph-right" }), desc: jsx(Keymap, { keymap: { key: 'R', ctrlKey: true } }), checked: states.textAlign === 'right', children: "\u53F3\u5BF9\u9F50" }),
1334
1774
  value: 't-r'
1335
1775
  }, {
1336
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-paragraph-center" }), checked: states.textAlign === 'center', children: "\u5C45\u4E2D\u5BF9\u9F50" }),
1776
+ label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-paragraph-center" }), desc: jsx(Keymap, { keymap: { key: 'E', ctrlKey: true } }), checked: states.textAlign === 'center', children: "\u5C45\u4E2D\u5BF9\u9F50" }),
1337
1777
  value: 't-c'
1338
1778
  }, {
1339
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-paragraph-justify" }), checked: states.textAlign === 'justify', children: "\u5206\u6563\u5BF9\u9F50" }),
1779
+ label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-paragraph-justify" }), desc: jsx(Keymap, { keymap: { key: 'J', ctrlKey: true } }), checked: states.textAlign === 'justify', children: "\u5206\u6563\u5BF9\u9F50" }),
1340
1780
  value: 't-j'
1341
1781
  }, {
1342
1782
  label: jsx(Divider, {}),
1343
1783
  value: ''
1344
1784
  }, {
1345
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-indent-increase" }), children: "\u589E\u52A0\u7F29\u8FDB" }),
1785
+ label: jsx(MenuItem, { desc: jsx(Keymap, { keymap: { key: 'Tab' } }), icon: jsx("span", { class: "xnote-icon-indent-increase" }), children: "\u589E\u52A0\u7F29\u8FDB" }),
1346
1786
  value: 'i+'
1347
1787
  }, {
1348
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-indent-decrease" }), children: "\u51CF\u5C11\u7F29\u8FDB" }),
1788
+ label: jsx(MenuItem, { desc: jsx(Keymap, { keymap: { key: 'Tab', shiftKey: true } }), icon: jsx("span", { class: "xnote-icon-indent-decrease" }), children: "\u51CF\u5C11\u7F29\u8FDB" }),
1349
1789
  value: 'i-'
1350
1790
  }
1351
1791
  ], children: props.children || jsx(Button, { arrow: true, highlight: false, children: jsx("span", { class: `xnote-icon-paragraph-${states.textAlign || 'left'} icon` }) }) }));
1352
1792
  });
1353
1793
  }
1354
1794
 
1355
- const headingAttr = new Attribute('Heading', {
1356
- render(node, formatValue) {
1357
- node.classes.add('xnote-' + formatValue);
1358
- }
1359
- });
1360
- const headingAttrLoader = {
1361
- match(element) {
1362
- return /H[1-6]/.test(element.tagName) || /(^|\s)xnote-h[1-6](\s|$)/.test(element.className);
1363
- },
1364
- read(element) {
1365
- if (/H[1-6]/.test(element.tagName)) {
1366
- return {
1367
- attribute: headingAttr,
1368
- value: element.tagName.toLowerCase()
1369
- };
1370
- }
1371
- return {
1372
- attribute: headingAttr,
1373
- value: element.className.substring(6)
1374
- };
1375
- }
1376
- };
1377
- function registerHeadingShortcut(textbus) {
1378
- const keyboard = textbus.get(Keyboard);
1379
- const commander = textbus.get(Commander);
1380
- const selection = textbus.get(Selection);
1381
- keyboard.addShortcut({
1382
- keymap: {
1383
- key: '123456'.split(''),
1384
- ctrlKey: true
1385
- },
1386
- action(key) {
1387
- commander.applyAttribute(headingAttr, 'h' + key);
1388
- }
1389
- });
1390
- keyboard.addZenCodingInterceptor({
1391
- match(content) {
1392
- return /^#{1,6}$/.test(content);
1393
- },
1394
- try(key) {
1395
- return key === ' ';
1396
- },
1397
- action(content) {
1398
- const commonAncestorSlot = selection.commonAncestorSlot;
1399
- commonAncestorSlot.cut();
1400
- commander.applyAttribute(headingAttr, 'h' + content.length);
1401
- return true;
1402
- }
1403
- });
1404
- }
1405
-
1406
- function useBlockContent(slot) {
1407
- const textbus = useContext();
1408
- const selection = textbus.get(Selection);
1409
- onBreak(ev => {
1410
- if (typeof slot === 'function' ? slot(ev.target) : ev.target === slot) {
1411
- const p = new ParagraphComponent(textbus);
1412
- ev.target.insert(p);
1413
- selection.setPosition(p.state.slot, 0);
1414
- ev.preventDefault();
1415
- }
1416
- });
1417
- onContentInsert(ev => {
1418
- if ((typeof slot === 'function' ? slot(ev.target) : ev.target === slot) &&
1419
- (typeof ev.data.content === 'string' || ev.data.content.type !== ContentType.BlockComponent)) {
1420
- const p = new ParagraphComponent(textbus);
1421
- const childSlot = p.state.slot;
1422
- childSlot.insert(ev.data.content);
1423
- ev.target.insert(p);
1424
- selection.setPosition(childSlot, childSlot.index);
1425
- ev.preventDefault();
1426
- }
1427
- });
1428
- }
1429
-
1430
1795
  const defaultRowHeight = 30;
1431
1796
  const defaultColumnWidth = 100;
1432
1797
  class TableComponent extends Component {
@@ -1449,17 +1814,18 @@ class TableComponent extends Component {
1449
1814
  });
1450
1815
  }
1451
1816
  constructor(textbus, state = {
1452
- layoutWidth: Array.from({ length: 3 }).fill(100),
1817
+ layoutWidth: Array.from({ length: 5 }).fill(100),
1453
1818
  rows: Array.from({ length: 3 }).map(() => {
1454
1819
  return {
1455
1820
  height: defaultRowHeight,
1456
- cells: Array.from({ length: 3 }).map(() => {
1821
+ cells: Array.from({ length: 5 }).map(() => {
1822
+ const p = new ParagraphComponent(textbus);
1823
+ const slot = new Slot([ContentType.BlockComponent]);
1824
+ slot.insert(p);
1457
1825
  return {
1458
1826
  rowspan: 1,
1459
1827
  colspan: 1,
1460
- slot: new Slot([
1461
- ContentType.BlockComponent
1462
- ])
1828
+ slot
1463
1829
  };
1464
1830
  })
1465
1831
  };
@@ -1470,7 +1836,11 @@ class TableComponent extends Component {
1470
1836
  this.focus = new Subject();
1471
1837
  this.tableSelection = createSignal(null);
1472
1838
  }
1839
+ getSlots() {
1840
+ return this.state.rows.map(i => i.cells.map(j => j.slot)).flat();
1841
+ }
1473
1842
  setup() {
1843
+ const selection = useContext(Selection);
1474
1844
  onFocusIn(() => {
1475
1845
  this.focus.next(true);
1476
1846
  });
@@ -1480,12 +1850,42 @@ class TableComponent extends Component {
1480
1850
  useBlockContent((slot) => {
1481
1851
  return slot.parent === this;
1482
1852
  });
1483
- onGetRanges(ev => {
1484
- const selectPosition = this.tableSelection();
1853
+ const sub = selection.onChange.subscribe(() => {
1854
+ if (selection.commonAncestorComponent !== this || selection.isCollapsed) {
1855
+ this.tableSelection.set(null);
1856
+ }
1857
+ });
1858
+ onDestroy(() => {
1859
+ sub.unsubscribe();
1860
+ });
1861
+ const findPosition = (slot) => {
1862
+ let cell = slot;
1863
+ while ((cell === null || cell === void 0 ? void 0 : cell.parent) && cell.parent !== this) {
1864
+ cell = cell.parentSlot;
1865
+ }
1866
+ if (cell) {
1867
+ const rows = this.state.rows;
1868
+ for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
1869
+ const row = rows[rowIndex].cells;
1870
+ for (let colIndex = 0; colIndex < row.length; colIndex++) {
1871
+ const item = row[colIndex].slot;
1872
+ if (item === cell) {
1873
+ return {
1874
+ rowIndex,
1875
+ colIndex
1876
+ };
1877
+ }
1878
+ }
1879
+ }
1880
+ }
1881
+ return null;
1882
+ };
1883
+ const select = (ev, selectPosition) => {
1884
+ this.tableSelection.set(selectPosition);
1485
1885
  if (selectPosition) {
1486
1886
  const cells = [];
1487
- this.state.rows.slice(selectPosition.startRow, selectPosition.endRow + 1).forEach(row => {
1488
- cells.push(...row.cells.slice(selectPosition.startColumn, selectPosition.endColumn + 1).map(i => i.slot));
1887
+ this.state.rows.slice(selectPosition.startRow, selectPosition.endRow).forEach(row => {
1888
+ cells.push(...row.cells.slice(selectPosition.startColumn, selectPosition.endColumn).map(i => i.slot));
1489
1889
  });
1490
1890
  ev.useRanges(cells.map(i => {
1491
1891
  return {
@@ -1496,33 +1896,64 @@ class TableComponent extends Component {
1496
1896
  }));
1497
1897
  ev.preventDefault();
1498
1898
  }
1499
- });
1500
- }
1501
- afterContentCheck() {
1502
- const selection = this.selection;
1503
- const rows = this.state.rows;
1504
- rows.forEach(row => {
1505
- row.cells.forEach(cell => {
1506
- const slot = cell.slot;
1507
- if (slot.isEmpty) {
1508
- const childSlot = new Slot([
1509
- ContentType.Text,
1510
- ContentType.InlineComponent
1511
- ]);
1512
- const p = new ParagraphComponent(this.textbus, {
1513
- slot: childSlot
1514
- });
1515
- slot.insert(p);
1516
- if (slot === selection.anchorSlot) {
1517
- selection.setAnchor(childSlot, 0);
1518
- }
1519
- if (slot === selection.focusSlot) {
1520
- selection.setFocus(childSlot, 0);
1899
+ };
1900
+ onGetRanges(ev => {
1901
+ var _a;
1902
+ const startPosition = findPosition(selection.startSlot);
1903
+ const endPosition = findPosition(selection.endSlot);
1904
+ if (startPosition && endPosition) {
1905
+ if (startPosition.rowIndex === endPosition.rowIndex && startPosition.colIndex === endPosition.colIndex) {
1906
+ if (selection.startSlot === selection.endSlot && selection.startOffset === 0 && selection.endOffset === ((_a = selection.startSlot) === null || _a === void 0 ? void 0 : _a.length)) {
1907
+ select(ev, {
1908
+ startColumn: startPosition.colIndex,
1909
+ startRow: startPosition.rowIndex,
1910
+ endColumn: endPosition.colIndex + 1,
1911
+ endRow: endPosition.rowIndex + 1
1912
+ });
1913
+ return;
1521
1914
  }
1915
+ select(ev, null);
1916
+ return;
1522
1917
  }
1523
- });
1918
+ const [startColumn, endColumn] = [startPosition.colIndex, endPosition.colIndex].sort((a, b) => a - b);
1919
+ const [startRow, endRow] = [startPosition.rowIndex, endPosition.rowIndex].sort((a, b) => a - b);
1920
+ select(ev, {
1921
+ startColumn,
1922
+ startRow,
1923
+ endColumn: endColumn + 1,
1924
+ endRow: endRow + 1
1925
+ });
1926
+ }
1927
+ else {
1928
+ select(ev, null);
1929
+ }
1524
1930
  });
1525
1931
  }
1932
+ // afterContentCheck() {
1933
+ // const selection = this.selection
1934
+ // const rows = this.state.rows
1935
+ // rows.forEach(row => {
1936
+ // row.cells.forEach(cell => {
1937
+ // const slot = cell.slot
1938
+ // if (slot.isEmpty) {
1939
+ // const childSlot = new Slot([
1940
+ // ContentType.Text,
1941
+ // ContentType.InlineComponent
1942
+ // ])
1943
+ // const p = new ParagraphComponent(this.textbus, {
1944
+ // slot: childSlot
1945
+ // })
1946
+ // slot.insert(p)
1947
+ // if (slot === selection.anchorSlot) {
1948
+ // selection.setAnchor(childSlot, 0)
1949
+ // }
1950
+ // if (slot === selection.focusSlot) {
1951
+ // selection.setFocus(childSlot, 0)
1952
+ // }
1953
+ // }
1954
+ // })
1955
+ // })
1956
+ // }
1526
1957
  deleteColumn(index) {
1527
1958
  this.state.layoutWidth.splice(index, 1);
1528
1959
  this.state.rows.forEach(row => {
@@ -1645,12 +2076,16 @@ class TodolistComponent extends Component {
1645
2076
  checked: json.checked
1646
2077
  });
1647
2078
  }
2079
+ getSlots() {
2080
+ return [this.state.slot];
2081
+ }
1648
2082
  setup() {
1649
2083
  const textbus = useContext();
1650
2084
  const commander = useContext(Commander);
1651
2085
  const selection = useContext(Selection);
1652
2086
  onBreak(ev => {
1653
2087
  const slot = ev.target.cut(ev.data.index);
2088
+ slot.removeAttribute(headingAttr);
1654
2089
  if (ev.target.isEmpty && slot.isEmpty) {
1655
2090
  const beforeIndex = this.parent.indexOf(this);
1656
2091
  const beforeComponent = this.parent.getContentAtIndex(beforeIndex - 1);
@@ -1698,21 +2133,32 @@ class TodolistComponent extends Component {
1698
2133
  TodolistComponent.type = ContentType.BlockComponent;
1699
2134
  TodolistComponent.componentName = 'TodoListComponent';
1700
2135
  TodolistComponent.zenCoding = {
1701
- match: /^\[(x|\s)?\]$/,
2136
+ match(content, textbus) {
2137
+ const selection = textbus.get(Selection);
2138
+ if (selection.commonAncestorComponent instanceof ParagraphComponent) {
2139
+ return /^\[(x|\s)?\]$/.test(content);
2140
+ }
2141
+ return false;
2142
+ },
1702
2143
  key: ' ',
1703
- createState(content) {
2144
+ createState(content, textbus) {
2145
+ const selection = textbus.get(Selection);
2146
+ const commonAncestorSlot = selection.commonAncestorSlot;
2147
+ const slot = new Slot([
2148
+ ContentType.InlineComponent,
2149
+ ContentType.Text
2150
+ ]);
2151
+ if (commonAncestorSlot === null || commonAncestorSlot === void 0 ? void 0 : commonAncestorSlot.hasAttribute(textIndentAttr)) {
2152
+ slot.setAttribute(textIndentAttr, commonAncestorSlot.getAttribute(textIndentAttr));
2153
+ }
1704
2154
  const isChecked = content.charAt(1) === 'x';
1705
2155
  return {
1706
2156
  checked: isChecked,
1707
- slot: new Slot([
1708
- ContentType.InlineComponent,
1709
- ContentType.Text
1710
- ])
2157
+ slot
1711
2158
  };
1712
2159
  }
1713
2160
  };
1714
2161
  function TodolistView(props) {
1715
- const adapter = inject(DomAdapter);
1716
2162
  const component = props.component;
1717
2163
  const state = component.state;
1718
2164
  function toggle() {
@@ -1741,11 +2187,7 @@ function TodolistView(props) {
1741
2187
  marginLeft: indent * 24 + 'px',
1742
2188
  justifyContent: align[component.state.slot.getAttribute(textAlignAttr)],
1743
2189
  textAlign: component.state.slot.getAttribute(textAlignAttr) === 'justify' ? 'justify' : void 0
1744
- }, children: [jsx("div", { class: "xnote-todolist-icon", onClick: toggle, children: jsx("span", { "data-checked": checked, class: [checked ? 'xnote-icon-checkbox-checked' : 'xnote-icon-checkbox-unchecked'] }) }), adapter.slotRender(slot, children => {
1745
- return createVNode('div', {
1746
- class: 'xnote-todolist-content'
1747
- }, children);
1748
- }, readonly() || output())] }));
2190
+ }, children: [jsx("div", { class: "xnote-todolist-icon", onClick: toggle, children: jsx("span", { "data-checked": checked, class: [checked ? 'xnote-icon-checkbox-checked' : 'xnote-icon-checkbox-unchecked'] }) }), jsx(SlotRender, { slot: slot, tag: 'div', class: 'xnote-todolist-content', renderEnv: readonly() || output() })] }));
1749
2191
  };
1750
2192
  }
1751
2193
  const todolistComponentLoader = {
@@ -1764,68 +2206,40 @@ const todolistComponentLoader = {
1764
2206
  }
1765
2207
  };
1766
2208
 
1767
- class BlockquoteComponent extends Component {
1768
- static fromJSON(textbus, json) {
1769
- const slot = textbus.get(Registry).createSlot(json.slot);
1770
- return new BlockquoteComponent(textbus, {
1771
- slot
1772
- });
1773
- }
1774
- constructor(textbus, state = {
1775
- slot: new Slot([
1776
- ContentType.BlockComponent
1777
- ])
1778
- }) {
1779
- super(textbus, state);
1780
- }
1781
- setup() {
1782
- useBlockContent(this.state.slot);
1783
- }
2209
+ function toList(textbus, type) {
2210
+ const commander = textbus.get(Commander);
2211
+ commander.transform({
2212
+ targetType: ListComponent.type,
2213
+ slotFactory() {
2214
+ return new Slot([
2215
+ ContentType.InlineComponent,
2216
+ ContentType.Text
2217
+ ]);
2218
+ },
2219
+ stateFactory(slots) {
2220
+ return slots.map((slot, index) => {
2221
+ return new ListComponent(textbus, {
2222
+ type,
2223
+ reorder: index === 0,
2224
+ slot
2225
+ });
2226
+ });
2227
+ }
2228
+ });
1784
2229
  }
1785
- BlockquoteComponent.type = ContentType.BlockComponent;
1786
- BlockquoteComponent.componentName = 'BlockquoteComponent';
1787
- BlockquoteComponent.zenCoding = {
1788
- key: ' ',
1789
- match: /^>$/,
1790
- createState() {
1791
- return {
1792
- slot: new Slot([
1793
- ContentType.BlockComponent
1794
- ])
1795
- };
1796
- }
1797
- };
1798
- function BlockquoteView(props) {
1799
- const adapter = inject(DomAdapter);
1800
- const readonly = useReadonly();
1801
- const output = useOutput();
1802
- return () => {
1803
- const slot = props.component.state.slot;
1804
- return (jsx("blockquote", { class: "xnote-blockquote", ref: props.rootRef, "data-component": props.component.name, children: adapter.slotRender(slot, children => {
1805
- return createVNode('div', null, children);
1806
- }, readonly() || output()) }));
1807
- };
2230
+ function registerListShortcut(textbus) {
2231
+ const keyboard = textbus.get(Keyboard);
2232
+ keyboard.addShortcut({
2233
+ keymap: {
2234
+ key: ['o', 'u'],
2235
+ ctrlKey: true,
2236
+ shiftKey: true
2237
+ },
2238
+ action(key) {
2239
+ toList(textbus, key === 'o' ? 'OrderedList' : 'UnorderedList');
2240
+ }
2241
+ });
1808
2242
  }
1809
- const blockquoteComponentLoader = {
1810
- match(element) {
1811
- return element.tagName === 'BLOCKQUOTE';
1812
- },
1813
- read(element, textbus, slotParser) {
1814
- const delta = slotParser(new Slot([
1815
- ContentType.BlockComponent,
1816
- ]), element).toDelta();
1817
- const slot = new Slot([
1818
- ContentType.BlockComponent,
1819
- ]);
1820
- deltaToBlock(delta, textbus).forEach(i => {
1821
- slot.insert(i);
1822
- });
1823
- return new BlockquoteComponent(textbus, {
1824
- slot
1825
- });
1826
- },
1827
- };
1828
-
1829
2243
  class ListComponent extends Component {
1830
2244
  static fromJSON(textbus, json) {
1831
2245
  return new ListComponent(textbus, {
@@ -1834,6 +2248,9 @@ class ListComponent extends Component {
1834
2248
  slot: textbus.get(Registry).createSlot(json.slot)
1835
2249
  });
1836
2250
  }
2251
+ getSlots() {
2252
+ return [this.state.slot];
2253
+ }
1837
2254
  setup() {
1838
2255
  const textbus = useContext();
1839
2256
  const commander = useContext(Commander);
@@ -1847,8 +2264,7 @@ class ListComponent extends Component {
1847
2264
  const afterContent = parentSlot.sliceContent(index + 1);
1848
2265
  for (const item of afterContent) {
1849
2266
  if (item instanceof ListComponent &&
1850
- item.state.type === 'OrderedList' &&
1851
- item.state.slot.getAttribute(textIndentAttr) === this.state.slot.getAttribute(textIndentAttr)) {
2267
+ item.state.type === 'OrderedList') {
1852
2268
  if (item.state.reorder) {
1853
2269
  break;
1854
2270
  }
@@ -1861,6 +2277,7 @@ class ListComponent extends Component {
1861
2277
  });
1862
2278
  onBreak(ev => {
1863
2279
  const slot = ev.target.cut(ev.data.index);
2280
+ slot.removeAttribute(headingAttr);
1864
2281
  if (ev.target.isEmpty && slot.isEmpty) {
1865
2282
  const beforeIndex = this.parent.indexOf(this);
1866
2283
  const beforeComponent = this.parent.getContentAtIndex(beforeIndex - 1);
@@ -1911,7 +2328,7 @@ class ListComponent extends Component {
1911
2328
  key: 'Tab'
1912
2329
  },
1913
2330
  action: () => {
1914
- updateAfterList(this);
2331
+ Promise.resolve().then(() => updateAfterList(this));
1915
2332
  return false;
1916
2333
  }
1917
2334
  });
@@ -1931,15 +2348,27 @@ ListComponent.componentName = 'ListComponent';
1931
2348
  ListComponent.type = ContentType.BlockComponent;
1932
2349
  ListComponent.zenCoding = {
1933
2350
  key: ' ',
1934
- match: /^([1-9]\.|[+*])$/,
1935
- createState(content) {
2351
+ match(content, textbus) {
2352
+ const selection = textbus.get(Selection);
2353
+ if (selection.commonAncestorComponent instanceof ParagraphComponent) {
2354
+ return /^([1-9]\.|[+*-])$/.test(content);
2355
+ }
2356
+ return false;
2357
+ },
2358
+ createState(content, textbus) {
2359
+ const selection = textbus.get(Selection);
2360
+ const commonAncestorSlot = selection.commonAncestorSlot;
2361
+ const slot = new Slot([
2362
+ ContentType.InlineComponent,
2363
+ ContentType.Text
2364
+ ]);
2365
+ if (commonAncestorSlot === null || commonAncestorSlot === void 0 ? void 0 : commonAncestorSlot.hasAttribute(textIndentAttr)) {
2366
+ slot.setAttribute(textIndentAttr, commonAncestorSlot.getAttribute(textIndentAttr));
2367
+ }
1936
2368
  return {
1937
2369
  type: /[-+*]/.test(content) ? 'UnorderedList' : 'OrderedList',
1938
2370
  reorder: true,
1939
- slot: new Slot([
1940
- ContentType.InlineComponent,
1941
- ContentType.Text
1942
- ])
2371
+ slot
1943
2372
  };
1944
2373
  }
1945
2374
  };
@@ -1961,7 +2390,6 @@ function numberToLetter(num) {
1961
2390
  }).join('');
1962
2391
  }
1963
2392
  function ListComponentView(props) {
1964
- const adapter = inject(DomAdapter);
1965
2393
  const component = props.component;
1966
2394
  function reorder(is) {
1967
2395
  component.state.reorder = is;
@@ -1988,7 +2416,8 @@ function ListComponentView(props) {
1988
2416
  return () => {
1989
2417
  const ListType = component.state.type === 'UnorderedList' ? 'ul' : 'ol';
1990
2418
  const ulIcons = ['•', '◦', '▪'];
1991
- let icon = '';
2419
+ let icon;
2420
+ let listStep = 0;
1992
2421
  const indent = component.state.slot.getAttribute(textIndentAttr) || 0;
1993
2422
  if (ListType === 'ul') {
1994
2423
  icon = ulIcons[indent % 3];
@@ -1996,7 +2425,6 @@ function ListComponentView(props) {
1996
2425
  else {
1997
2426
  const parentSlot = component.parent;
1998
2427
  const index = parentSlot.indexOf(component);
1999
- let listStep = 0;
2000
2428
  if (!component.state.reorder) {
2001
2429
  const beforeContent = parentSlot.sliceContent(0, index);
2002
2430
  while (beforeContent.length) {
@@ -2027,7 +2455,7 @@ function ListComponentView(props) {
2027
2455
  icon = numberToLetter(listStep) + '.';
2028
2456
  }
2029
2457
  }
2030
- return (jsx(ListType, { ref: props.rootRef, "data-component": component.name, class: "xnote-list", style: {
2458
+ return (jsx(ListType, { ref: props.rootRef, "data-component": component.name, "data-reorder": (listStep === 0) + '', class: "xnote-list", style: {
2031
2459
  marginLeft: indent * 24 + 'px'
2032
2460
  }, children: jsxs("li", { style: {
2033
2461
  justifyContent: align[component.state.slot.getAttribute(textAlignAttr)],
@@ -2035,16 +2463,12 @@ function ListComponentView(props) {
2035
2463
  }, children: [jsx("div", { class: "xnote-list-type", children: (component.state.type === 'UnorderedList' || readonly() || output()) ?
2036
2464
  jsx("span", { class: "xnote-order-btn", children: icon })
2037
2465
  :
2038
- jsx(Dropdown, { menu: jsxs(Fragment, { children: [jsx(MenuItem, { onClick: () => reorder(false), children: "\u7EE7\u7EED\u7F16\u53F7" }), jsx(MenuItem, { onClick: () => reorder(true), children: "\u91CD\u65B0\u7F16\u53F7" })] }), children: jsx(Button, { style: { color: 'inherit' }, children: icon }) }) }), adapter.slotRender(component.state.slot, children => {
2039
- return createVNode('div', {
2040
- class: 'xnote-list-content'
2041
- }, children);
2042
- }, readonly() || output())] }) }));
2466
+ jsx(Dropdown, { menu: jsxs(Fragment, { children: [jsx(MenuItem, { onClick: () => reorder(false), children: "\u7EE7\u7EED\u7F16\u53F7" }), jsx(MenuItem, { onClick: () => reorder(true), children: "\u91CD\u65B0\u7F16\u53F7" })] }), children: jsx(Button, { style: { color: 'inherit' }, children: icon }) }) }), jsx(SlotRender, { slot: component.state.slot, class: 'xnote-list-content', renderEnv: readonly() || output() })] }) }));
2043
2467
  };
2044
2468
  }
2045
2469
  const listComponentLoader = {
2046
- match(element) {
2047
- return element.tagName === 'UL' || element.tagName === 'OL';
2470
+ match(element, returnableContentTypes) {
2471
+ return returnableContentTypes.includes(ContentType.BlockComponent) && (element.tagName === 'UL' || element.tagName === 'OL');
2048
2472
  },
2049
2473
  read(element, textbus, slotParser) {
2050
2474
  const type = element.tagName === 'OL' ? 'OrderedList' : 'UnorderedList';
@@ -2055,7 +2479,7 @@ const listComponentLoader = {
2055
2479
  ]), element.querySelector('.xnote-list-content') || document.createElement('div'));
2056
2480
  return new ListComponent(textbus, {
2057
2481
  slot,
2058
- reorder: true,
2482
+ reorder: element.dataset.reorder !== 'false',
2059
2483
  type
2060
2484
  });
2061
2485
  }
@@ -2098,119 +2522,58 @@ function useActiveBlock() {
2098
2522
  sourceCode: false,
2099
2523
  highlightBox: false
2100
2524
  });
2101
- function updateCheckStates() {
2525
+ function updateCheckStates(range) {
2102
2526
  setCheckStates(draft => {
2103
- const heading = query.queryAttribute(headingAttr);
2104
- draft.paragraph = query.queryComponent(ParagraphComponent).state === QueryStateType.Enabled;
2527
+ const heading = query.queryAttributeByRange(headingAttr, range);
2528
+ draft.paragraph = query.queryComponentByRange(ParagraphComponent, range).state === QueryStateType.Enabled;
2105
2529
  draft.h1 = draft.h2 = draft.h3 = draft.h4 = draft.h5 = draft.h6 = false;
2106
2530
  if (heading.state === QueryStateType.Enabled) {
2107
2531
  draft[heading.value] = true;
2108
2532
  draft.paragraph = false;
2109
2533
  }
2110
- const queryList = query.queryComponent(ListComponent);
2534
+ const queryList = query.queryComponentByRange(ListComponent, range);
2111
2535
  draft.unorderedList = queryList.state === QueryStateType.Enabled && queryList.value.state.type === 'UnorderedList';
2112
2536
  draft.orderedList = queryList.state === QueryStateType.Enabled && queryList.value.state.type === 'OrderedList';
2113
- draft.table = query.queryComponent(TableComponent).state === QueryStateType.Enabled;
2114
- draft.todolist = query.queryComponent(TodolistComponent).state === QueryStateType.Enabled;
2115
- draft.blockquote = query.queryComponent(BlockquoteComponent).state === QueryStateType.Enabled;
2116
- draft.sourceCode = query.queryComponent(SourceCodeComponent).state === QueryStateType.Enabled;
2537
+ draft.table = query.queryComponentByRange(TableComponent, range).state === QueryStateType.Enabled;
2538
+ draft.todolist = query.queryComponentByRange(TodolistComponent, range).state === QueryStateType.Enabled;
2539
+ draft.blockquote = query.queryComponentByRange(BlockquoteComponent, range).state === QueryStateType.Enabled;
2540
+ draft.sourceCode = query.queryComponentByRange(SourceCodeComponent, range).state === QueryStateType.Enabled;
2117
2541
  });
2118
2542
  }
2119
- updateCheckStates();
2120
2543
  const subscription = refreshService.onRefresh.subscribe(() => {
2121
- updateCheckStates();
2544
+ if (!selection.isSelected) {
2545
+ return;
2546
+ }
2547
+ updateCheckStates({
2548
+ startOffset: selection.startOffset,
2549
+ startSlot: selection.startSlot,
2550
+ endSlot: selection.endSlot,
2551
+ endOffset: selection.endOffset
2552
+ });
2122
2553
  });
2123
2554
  onUnmounted(() => {
2124
2555
  subscription.unsubscribe();
2125
2556
  });
2126
2557
  return function (slot = null) {
2127
2558
  if (slot) {
2128
- const snapshot = selection.createSnapshot();
2129
- selection.setBaseAndExtent(slot, 0, slot, slot.length);
2130
- updateCheckStates();
2131
- snapshot.restore();
2559
+ updateCheckStates({
2560
+ startOffset: 0,
2561
+ endOffset: slot.length,
2562
+ startSlot: slot,
2563
+ endSlot: slot
2564
+ });
2132
2565
  }
2133
- return checkStates();
2134
- };
2135
- }
2136
-
2137
- class HighlightBoxComponent extends Component {
2138
- static fromJSON(textbus, json) {
2139
- return new HighlightBoxComponent(textbus, {
2140
- type: json.type,
2141
- slot: textbus.get(Registry).createSlot(json.slot)
2142
- });
2143
- }
2144
- constructor(textbus, state = {
2145
- type: '',
2146
- slot: new Slot([
2147
- ContentType.BlockComponent,
2148
- ])
2149
- }) {
2150
- super(textbus, state);
2151
- }
2152
- setup() {
2153
- useBlockContent(this.state.slot);
2154
- }
2155
- }
2156
- HighlightBoxComponent.defaultTypes = ['❤️', '💡', '📌', '✅', '❎', '👍', '🎉', '🚫', '❗'];
2157
- HighlightBoxComponent.componentName = 'HighlightBoxComponent';
2158
- HighlightBoxComponent.type = ContentType.BlockComponent;
2159
- function HighlightBoxView(props) {
2160
- const adapter = inject(DomAdapter);
2161
- const readonly = useReadonly();
2162
- const output = useOutput();
2163
- const emoji = [];
2164
- for (let i = 0x1F600; i <= 0x1F64F; i++) {
2165
- emoji.push(i);
2166
- }
2167
- const dropdownRef = createRef();
2168
- function setType(type) {
2169
- var _a;
2170
- (_a = dropdownRef.current) === null || _a === void 0 ? void 0 : _a.isShow(false);
2171
- props.component.state.type = type;
2172
- }
2173
- return () => {
2174
- const { state, name } = props.component;
2175
- if (readonly() || output()) {
2176
- 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 => {
2177
- return createVNode('div', {
2178
- class: 'xnote-highlight-box-content'
2179
- }, children);
2180
- }, readonly() || output())] }));
2566
+ else if (selection.isSelected) {
2567
+ updateCheckStates({
2568
+ startOffset: selection.startOffset,
2569
+ startSlot: selection.startSlot,
2570
+ endSlot: selection.endSlot,
2571
+ endOffset: selection.endOffset
2572
+ });
2181
2573
  }
2182
- 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 => {
2183
- return (jsx("button", { onClick: () => setType(icon), type: "button", children: icon }));
2184
- }), jsx(Divider, {}), emoji.map(i => {
2185
- const icon = String.fromCodePoint(i);
2186
- return (jsx("button", { onClick: () => setType(icon), type: "button", children: icon }));
2187
- })] }), children: jsx("div", { class: "xnote-highlight-box-icon", children: jsx("button", { type: "button", children: state.type || '❤️' }) }) }) }), adapter.slotRender(state.slot, children => {
2188
- return createVNode('div', {
2189
- class: 'xnote-highlight-box-content'
2190
- }, children);
2191
- }, readonly() || output())] }));
2574
+ return checkStates();
2192
2575
  };
2193
2576
  }
2194
- const highlightBoxComponentLoader = {
2195
- match(element) {
2196
- return element.tagName === 'DIV' && element.dataset.component === HighlightBoxComponent.componentName;
2197
- },
2198
- read(element, textbus, slotParser) {
2199
- const delta = slotParser(new Slot([
2200
- ContentType.BlockComponent,
2201
- ]), element.querySelector('.xnote-highlight-box-content')).toDelta();
2202
- const slot = new Slot([
2203
- ContentType.BlockComponent,
2204
- ]);
2205
- deltaToBlock(delta, textbus).forEach(i => {
2206
- slot.insert(i);
2207
- });
2208
- return new HighlightBoxComponent(textbus, {
2209
- type: element.dataset.icon || '',
2210
- slot
2211
- });
2212
- }
2213
- };
2214
2577
 
2215
2578
  function useBlockTransform() {
2216
2579
  const commander = inject(Commander);
@@ -2278,62 +2641,10 @@ function useBlockTransform() {
2278
2641
  break;
2279
2642
  case 'ol':
2280
2643
  case 'ul':
2281
- {
2282
- commander.transform({
2283
- targetType: ListComponent.type,
2284
- slotFactory() {
2285
- return new Slot([
2286
- ContentType.InlineComponent,
2287
- ContentType.Text
2288
- ]);
2289
- },
2290
- stateFactory(slots) {
2291
- return slots.map((slot, index) => {
2292
- return new ListComponent(textbus, {
2293
- type: value === 'ol' ? 'OrderedList' : 'UnorderedList',
2294
- reorder: index === 0,
2295
- slot
2296
- });
2297
- });
2298
- }
2299
- });
2300
- }
2644
+ toList(textbus, value === 'ol' ? 'OrderedList' : 'UnorderedList');
2301
2645
  break;
2302
2646
  case 'blockquote':
2303
- {
2304
- const state = query.queryComponent(BlockquoteComponent);
2305
- if (state.state === QueryStateType.Enabled) {
2306
- const current = state.value;
2307
- const parent = current.parent;
2308
- const index = parent.indexOf(current);
2309
- parent.retain(index);
2310
- commander.removeComponent(current);
2311
- current.__slots__.get(0).sliceContent().forEach(i => {
2312
- parent.insert(i);
2313
- });
2314
- }
2315
- else {
2316
- const block = new BlockquoteComponent(textbus);
2317
- const slot = block.state.slot;
2318
- if (selection.startSlot === selection.endSlot) {
2319
- const parentComponent = selection.startSlot.parent;
2320
- const parentSlot = parentComponent.parent;
2321
- const position = parentSlot.indexOf(parentComponent);
2322
- slot.insert(parentComponent);
2323
- parentSlot.retain(position);
2324
- parentSlot.insert(block);
2325
- }
2326
- else {
2327
- const commonAncestorSlot = selection.commonAncestorSlot;
2328
- const scope = selection.getCommonAncestorSlotScope();
2329
- commonAncestorSlot.cut(scope.startOffset, scope.endOffset).sliceContent().forEach(i => {
2330
- slot.insert(i);
2331
- });
2332
- commonAncestorSlot.retain(scope.startOffset);
2333
- commonAncestorSlot.insert(block);
2334
- }
2335
- }
2336
- }
2647
+ toBlockquote(textbus);
2337
2648
  break;
2338
2649
  case 'sourceCode':
2339
2650
  {
@@ -2370,6 +2681,8 @@ function useBlockTransform() {
2370
2681
  lineNumber: true,
2371
2682
  autoBreak: true,
2372
2683
  slots: slots.map(slot => {
2684
+ slot.cleanFormats();
2685
+ slot.cleanAttributes();
2373
2686
  return {
2374
2687
  slot,
2375
2688
  emphasize: false
@@ -2390,7 +2703,7 @@ function useBlockTransform() {
2390
2703
  const index = parent.indexOf(current);
2391
2704
  parent.retain(index);
2392
2705
  commander.removeComponent(current);
2393
- current.__slots__.get(0).sliceContent().forEach(i => {
2706
+ current.slots.at(0).sliceContent().forEach(i => {
2394
2707
  parent.insert(i);
2395
2708
  });
2396
2709
  }
@@ -2424,7 +2737,7 @@ function useBlockTransform() {
2424
2737
  function BlockTool() {
2425
2738
  const checkStates = useActiveBlock();
2426
2739
  const transform = useBlockTransform();
2427
- return withScopedCSS(scopedId$b, () => {
2740
+ return withScopedCSS(scopedId$c, () => {
2428
2741
  const states = checkStates();
2429
2742
  const types = [
2430
2743
  [states.paragraph, 'xnote-icon-pilcrow'],
@@ -2439,7 +2752,7 @@ function BlockTool() {
2439
2752
  [states.todolist, 'xnote-icon-checkbox-checked'],
2440
2753
  [states.blockquote, 'xnote-icon-quotes-right'],
2441
2754
  [states.sourceCode, 'xnote-icon-source-code'],
2442
- [states.highlightBox, 'xnote-icon-paint-bucket'],
2755
+ [states.highlightBox, 'xnote-icon-highlight-box'],
2443
2756
  ];
2444
2757
  let currentType = 'xnote-icon-pilcrow';
2445
2758
  for (const t of types) {
@@ -2448,27 +2761,48 @@ function BlockTool() {
2448
2761
  break;
2449
2762
  }
2450
2763
  }
2451
- return (jsx(Dropdown, { onCheck: transform, trigger: 'hover', menu: [
2764
+ return (jsx(Dropdown, { width: 'auto', onCheck: transform, trigger: 'hover', menu: [
2452
2765
  {
2453
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-pilcrow" }), checked: states.paragraph, children: "\u6B63\u6587" }),
2766
+ label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-pilcrow" }), desc: jsx(Keymap, { keymap: {
2767
+ ctrlKey: true,
2768
+ key: '0'
2769
+ } }), checked: states.paragraph, children: "\u6B63\u6587" }),
2454
2770
  value: 'paragraph'
2455
2771
  }, {
2456
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-heading-h1" }), checked: states.h1, children: "\u4E00\u7EA7\u6807\u9898" }),
2772
+ label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-heading-h1" }), desc: jsx(Keymap, { keymap: {
2773
+ ctrlKey: true,
2774
+ key: '1'
2775
+ } }), checked: states.h1, children: "\u4E00\u7EA7\u6807\u9898" }),
2457
2776
  value: 'h1'
2458
2777
  }, {
2459
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-heading-h2" }), checked: states.h2, children: "\u4E8C\u7EA7\u6807\u9898" }),
2778
+ label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-heading-h2" }), desc: jsx(Keymap, { keymap: {
2779
+ ctrlKey: true,
2780
+ key: '2'
2781
+ } }), checked: states.h2, children: "\u4E8C\u7EA7\u6807\u9898" }),
2460
2782
  value: 'h2'
2461
2783
  }, {
2462
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-heading-h3" }), checked: states.h3, children: "\u4E09\u7EA7\u6807\u9898" }),
2784
+ label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-heading-h3" }), desc: jsx(Keymap, { keymap: {
2785
+ ctrlKey: true,
2786
+ key: '3'
2787
+ } }), checked: states.h3, children: "\u4E09\u7EA7\u6807\u9898" }),
2463
2788
  value: 'h3'
2464
2789
  }, {
2465
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-heading-h4" }), checked: states.h4, children: "\u56DB\u7EA7\u6807\u9898" }),
2790
+ label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-heading-h4" }), desc: jsx(Keymap, { keymap: {
2791
+ ctrlKey: true,
2792
+ key: '4'
2793
+ } }), checked: states.h4, children: "\u56DB\u7EA7\u6807\u9898" }),
2466
2794
  value: 'h4'
2467
2795
  }, {
2468
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-heading-h5" }), checked: states.h5, children: "\u4E94\u7EA7\u6807\u9898" }),
2796
+ label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-heading-h5" }), desc: jsx(Keymap, { keymap: {
2797
+ ctrlKey: true,
2798
+ key: '5'
2799
+ } }), checked: states.h5, children: "\u4E94\u7EA7\u6807\u9898" }),
2469
2800
  value: 'h5'
2470
2801
  }, {
2471
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-heading-h6" }), checked: states.h6, children: "\u516D\u7EA7\u6807\u9898" }),
2802
+ label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-heading-h6" }), desc: jsx(Keymap, { keymap: {
2803
+ ctrlKey: true,
2804
+ key: '6'
2805
+ } }), checked: states.h6, children: "\u516D\u7EA7\u6807\u9898" }),
2472
2806
  value: 'h6'
2473
2807
  }, {
2474
2808
  label: jsx(Divider, {}),
@@ -2477,19 +2811,19 @@ function BlockTool() {
2477
2811
  label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-checkbox-checked" }), checked: states.todolist, children: "\u5F85\u529E\u4E8B\u9879" }),
2478
2812
  value: 'todolist'
2479
2813
  }, {
2480
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-list-numbered" }), checked: states.orderedList, children: "\u6709\u5E8F\u5217\u8868" }),
2814
+ label: jsx(MenuItem, { desc: jsx(Keymap, { keymap: { key: 'O', shiftKey: true, ctrlKey: true } }), icon: jsx("span", { class: "xnote-icon-list-numbered" }), checked: states.orderedList, children: "\u6709\u5E8F\u5217\u8868" }),
2481
2815
  value: 'ol'
2482
2816
  }, {
2483
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-list" }), checked: states.unorderedList, children: "\u65E0\u5E8F\u5217\u8868" }),
2817
+ label: jsx(MenuItem, { desc: jsx(Keymap, { keymap: { key: 'U', shiftKey: true, ctrlKey: true } }), icon: jsx("span", { class: "xnote-icon-list" }), checked: states.unorderedList, children: "\u65E0\u5E8F\u5217\u8868" }),
2484
2818
  value: 'ul'
2485
2819
  }, {
2486
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-quotes-right" }), checked: states.blockquote, children: "\u5F15\u7528" }),
2820
+ label: jsx(MenuItem, { desc: jsx(Keymap, { keymap: { key: '\'', ctrlKey: true } }), icon: jsx("span", { class: "xnote-icon-quotes-right" }), checked: states.blockquote, children: "\u5F15\u7528" }),
2487
2821
  value: 'blockquote'
2488
2822
  }, {
2489
2823
  label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-source-code" }), checked: states.sourceCode, children: "\u4EE3\u7801\u5757" }),
2490
2824
  value: 'sourceCode'
2491
2825
  }, {
2492
- label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-paint-bucket" }), checked: states.highlightBox, children: "\u9AD8\u4EAE\u5757" }),
2826
+ label: jsx(MenuItem, { icon: jsx("span", { class: "xnote-icon-hightlight-box" }), checked: states.highlightBox, children: "\u9AD8\u4EAE\u5757" }),
2493
2827
  value: 'highlightBox'
2494
2828
  }
2495
2829
  ], children: jsx(Button, { arrow: true, highlight: false, children: jsx("span", { class: currentType }) }) }));
@@ -2855,12 +3189,13 @@ function CodeTool() {
2855
3189
  };
2856
3190
  }
2857
3191
 
2858
- var scopedId$a = "vf-1fbbdf";
3192
+ var scopedId$b = "vf-accb31";
2859
3193
 
2860
3194
  function ColorTool(props) {
2861
3195
  const query = inject(Query);
2862
3196
  const refreshService = inject(RefreshService);
2863
3197
  const commander = inject(Commander);
3198
+ const selection = inject(Selection);
2864
3199
  const textColor = createSignal('');
2865
3200
  const backgroundColor = createSignal('');
2866
3201
  const [viewModel] = useProduce({
@@ -2868,13 +3203,24 @@ function ColorTool(props) {
2868
3203
  disabled: false,
2869
3204
  });
2870
3205
  function updateCheckState() {
2871
- var _a, _b;
2872
- (_a = props.queryBefore) === null || _a === void 0 ? void 0 : _a.call(props);
2873
- const textState = query.queryFormat(colorFormatter);
2874
- const backgroundState = query.queryFormat(backgroundColorFormatter);
3206
+ if (!props.slot && !selection.isSelected) {
3207
+ return;
3208
+ }
3209
+ const range = props.slot ? {
3210
+ startSlot: props.slot,
3211
+ endSlot: props.slot,
3212
+ startOffset: 0,
3213
+ endOffset: props.slot.length
3214
+ } : {
3215
+ startSlot: selection.startSlot,
3216
+ startOffset: selection.startOffset,
3217
+ endSlot: selection.endSlot,
3218
+ endOffset: selection.endOffset
3219
+ };
3220
+ const textState = query.queryFormatByRange(colorFormatter, range);
3221
+ const backgroundState = query.queryFormatByRange(backgroundColorFormatter, range);
2875
3222
  textColor.set(textState.state === QueryStateType.Enabled ? textState.value : '');
2876
3223
  backgroundColor.set(backgroundState.state === QueryStateType.Enabled ? backgroundState.value : '');
2877
- (_b = props.queryAfter) === null || _b === void 0 ? void 0 : _b.call(props);
2878
3224
  }
2879
3225
  const sub = refreshService.onRefresh.subscribe(() => {
2880
3226
  updateCheckState();
@@ -2884,6 +3230,7 @@ function ColorTool(props) {
2884
3230
  sub.unsubscribe();
2885
3231
  });
2886
3232
  const textColors = [
3233
+ '#000',
2887
3234
  '#aaa',
2888
3235
  '#ff2e2e',
2889
3236
  '#ff8d45',
@@ -2893,6 +3240,7 @@ function ColorTool(props) {
2893
3240
  '#1296db',
2894
3241
  '#617fff',
2895
3242
  '#c459ff',
3243
+ '#fff',
2896
3244
  ];
2897
3245
  const backgroundColors = [
2898
3246
  '#aaa',
@@ -2904,15 +3252,16 @@ function ColorTool(props) {
2904
3252
  '#90a0e5',
2905
3253
  '#c596e0',
2906
3254
  ];
2907
- return withScopedCSS(scopedId$a, () => {
3255
+ return withScopedCSS(scopedId$b, () => {
2908
3256
  const vm = viewModel();
2909
- return (jsx(Dropdown, { style: props.style, abreast: props.abreast, trigger: 'hover', menu: jsxs("div", { children: [jsx("div", { class: "color-type", children: "\u6587\u5B57\u989C\u8272" }), jsxs("div", { class: "text-colors", children: [jsx("div", { class: {
3257
+ return (jsx(Dropdown, { style: props.style, width: '180px', abreast: props.abreast, trigger: 'hover', menu: jsxs("div", { children: [jsx("div", { class: "color-type", children: "\u6587\u5B57\u989C\u8272" }), jsxs("div", { class: "text-colors", children: [jsx("div", { class: {
3258
+ 'no-background': true,
2910
3259
  active: textColor() === ''
2911
3260
  }, onClick: () => {
2912
3261
  var _a;
2913
3262
  (_a = props.applyBefore) === null || _a === void 0 ? void 0 : _a.call(props);
2914
3263
  commander.unApplyFormat(colorFormatter);
2915
- }, children: "A" }), textColors.map(c => {
3264
+ } }), textColors.map(c => {
2916
3265
  return jsx("div", { class: {
2917
3266
  active: textColor() === c
2918
3267
  }, onClick: () => {
@@ -2972,6 +3321,9 @@ const isSupportFont = (function () {
2972
3321
  function FontFamilyTool() {
2973
3322
  const currentFontFamily = createSignal('');
2974
3323
  const fontFamilyOptions = [{
3324
+ label: '默认',
3325
+ value: ''
3326
+ }, {
2975
3327
  label: '宋体',
2976
3328
  value: 'SimSun, STSong'
2977
3329
  }, {
@@ -3013,7 +3365,12 @@ function FontFamilyTool() {
3013
3365
  }];
3014
3366
  const commander = inject(Commander);
3015
3367
  function check(v) {
3016
- commander.applyFormat(fontFamilyFormatter, v);
3368
+ if (v) {
3369
+ commander.applyFormat(fontFamilyFormatter, v);
3370
+ }
3371
+ else {
3372
+ commander.unApplyFormat(fontFamilyFormatter);
3373
+ }
3017
3374
  }
3018
3375
  const refreshService = inject(RefreshService);
3019
3376
  const query = inject(Query);
@@ -3022,7 +3379,7 @@ function FontFamilyTool() {
3022
3379
  const result = query.queryFormat(fontFamilyFormatter);
3023
3380
  const isHighlight = result.state === QueryStateType.Enabled;
3024
3381
  highlight.set(isHighlight);
3025
- currentFontFamily.set(isHighlight ? result.value : '默认');
3382
+ currentFontFamily.set(isHighlight ? result.value : '');
3026
3383
  });
3027
3384
  onUnmounted(() => {
3028
3385
  subscription.unsubscribe();
@@ -3030,7 +3387,7 @@ function FontFamilyTool() {
3030
3387
  return () => {
3031
3388
  var _a;
3032
3389
  return (jsx(Dropdown, { onCheck: check, menu: fontFamilyOptions.map(i => {
3033
- const disabled = !i.value.split(',').map(i => isSupportFont(i.trim())).some(v => v);
3390
+ const disabled = i.value ? !i.value.split(',').map(i => isSupportFont(i.trim())).some(v => v) : false;
3034
3391
  return {
3035
3392
  label: jsx(MenuItem, { disabled: disabled, checked: currentFontFamily() === i.value, children: i.label }),
3036
3393
  disabled,
@@ -3062,7 +3419,12 @@ function FontSizeTool() {
3062
3419
  ];
3063
3420
  const commander = inject(Commander);
3064
3421
  function check(v) {
3065
- commander.applyFormat(fontSizeFormatter, v);
3422
+ if (v) {
3423
+ commander.applyFormat(fontSizeFormatter, v);
3424
+ }
3425
+ else {
3426
+ commander.unApplyFormat(fontSizeFormatter);
3427
+ }
3066
3428
  }
3067
3429
  const refreshService = inject(RefreshService);
3068
3430
  const query = inject(Query);
@@ -3112,12 +3474,30 @@ function ItalicTool() {
3112
3474
  };
3113
3475
  }
3114
3476
 
3115
- var scopedId$9 = "vf-269a0b";
3477
+ var scopedId$a = "vf-e74208";
3478
+
3479
+ let EditorService = class EditorService {
3480
+ constructor() {
3481
+ this.hideInlineToolbar = false;
3482
+ this.canShowLeftToolbar = true;
3483
+ this.onLeftToolbarCanVisibleChange = new Subject();
3484
+ }
3485
+ changeLeftToolbarVisible(b) {
3486
+ this.canShowLeftToolbar = b;
3487
+ this.onLeftToolbarCanVisibleChange.next();
3488
+ }
3489
+ };
3490
+ EditorService = __decorate([
3491
+ Injectable({
3492
+ provideIn: 'root'
3493
+ })
3494
+ ], EditorService);
3116
3495
 
3117
3496
  function LinkTool(props) {
3118
3497
  const selectionBridge = inject(SelectionBridge);
3119
3498
  const selection = inject(Selection);
3120
3499
  const commander = inject(Commander);
3500
+ const editorService = inject(EditorService);
3121
3501
  const container = inject(VIEW_CONTAINER);
3122
3502
  const isShow = createSignal(false);
3123
3503
  const inputRef = createRef();
@@ -3138,22 +3518,24 @@ function LinkTool(props) {
3138
3518
  isClickFromSelf = false;
3139
3519
  return;
3140
3520
  }
3521
+ editorService.hideInlineToolbar = false;
3141
3522
  isShow.set(false);
3142
3523
  });
3143
3524
  onUnmounted(() => {
3144
3525
  sub.unsubscribe();
3145
3526
  });
3146
- return withScopedCSS(scopedId$9, () => {
3527
+ return withScopedCSS(scopedId$a, () => {
3147
3528
  const containerRect = container.getBoundingClientRect();
3148
3529
  const rect = isShow() ? selectionBridge.getRect({
3149
3530
  slot: selection.focusSlot,
3150
3531
  offset: selection.focusOffset
3151
3532
  }) : {};
3152
3533
  return (jsxs("span", { children: [jsx(Button, { onClick: () => {
3534
+ var _a;
3153
3535
  isShow.set(true);
3154
3536
  isClickFromSelf = true;
3155
- setTimeout(() => { var _a; return (_a = props.hideToolbar) === null || _a === void 0 ? void 0 : _a.call(props); }, 10);
3156
- }, arrow: true, children: jsx("span", { class: "xnote-icon-link" }) }), isShow() &&
3537
+ (_a = props.hideToolbar) === null || _a === void 0 ? void 0 : _a.call(props);
3538
+ }, children: jsx("span", { class: "xnote-icon-link" }) }), isShow() &&
3157
3539
  jsx(Popup, { left: rect.left - containerRect.left, top: rect.top + rect.height - containerRect.top, children: jsxs("form", { onSubmit: setLink, onClick: () => {
3158
3540
  isClickFromSelf = true;
3159
3541
  }, class: "input-group", children: [jsx("input", { ref: inputRef, placeholder: "\u8BF7\u8F93\u5165\u94FE\u63A5\u5730\u5740", type: "text" }), jsx(Button, { type: "submit", children: "\u786E\u5B9A" })] }) })] }));
@@ -3212,7 +3594,7 @@ function UnderlineTool() {
3212
3594
  };
3213
3595
  }
3214
3596
 
3215
- var scopedId$8 = "vf-cf8e1c";
3597
+ var scopedId$9 = "vf-cf8e1c";
3216
3598
 
3217
3599
  class FileUploader {
3218
3600
  }
@@ -3221,6 +3603,9 @@ class ImageComponent extends Component {
3221
3603
  static fromJSON(textbus, json) {
3222
3604
  return new ImageComponent(textbus, Object.assign({}, json));
3223
3605
  }
3606
+ getSlots() {
3607
+ return [];
3608
+ }
3224
3609
  }
3225
3610
  ImageComponent.type = ContentType.InlineComponent;
3226
3611
  ImageComponent.componentName = 'ImageComponent';
@@ -3247,9 +3632,11 @@ const imageComponentLoader = {
3247
3632
  return element.tagName === 'IMG' || element.dataset.component === ImageComponent.componentName;
3248
3633
  },
3249
3634
  read(element, textbus) {
3250
- var _a;
3635
+ const img = element instanceof HTMLImageElement ? element : (element.querySelector('img') || document.createElement('img'));
3251
3636
  return new ImageComponent(textbus, {
3252
- src: element instanceof HTMLImageElement ? element.src : ((_a = element.querySelector('img')) === null || _a === void 0 ? void 0 : _a.src) || ''
3637
+ src: img.src,
3638
+ width: img.style.width || 'auto',
3639
+ height: img.style.height || 'auto'
3253
3640
  });
3254
3641
  }
3255
3642
  };
@@ -3258,8 +3645,8 @@ class VideoComponent extends Component {
3258
3645
  static fromJSON(textbus, json) {
3259
3646
  return new VideoComponent(textbus, Object.assign({}, json));
3260
3647
  }
3261
- setup() {
3262
- //
3648
+ getSlots() {
3649
+ return [];
3263
3650
  }
3264
3651
  }
3265
3652
  VideoComponent.type = ContentType.InlineComponent;
@@ -3271,7 +3658,7 @@ function VideoView(props) {
3271
3658
  const output = useOutput();
3272
3659
  return () => {
3273
3660
  if (readonly() || output()) {
3274
- return (jsx("div", { class: "xnote-video", "data-component": name, children: jsx("video", { ref: videoRef, src: state.src, style: {
3661
+ return (jsx("div", { class: "xnote-video", ref: props.rootRef, "data-component": name, children: jsx("video", { ref: videoRef, src: state.src, style: {
3275
3662
  width: state.width,
3276
3663
  height: state.height
3277
3664
  } }) }));
@@ -3284,12 +3671,169 @@ function VideoView(props) {
3284
3671
  }
3285
3672
  const videoComponentLoader = {
3286
3673
  match(element) {
3287
- return element.tagName === 'IMG' || element.dataset.component === VideoComponent.componentName;
3674
+ return element.tagName === 'VIDEO' || element.dataset.component === VideoComponent.componentName;
3288
3675
  },
3289
3676
  read(element, textbus) {
3290
- var _a;
3677
+ const video = element instanceof HTMLVideoElement ? element : (element.querySelector('video') || document.createElement('video'));
3291
3678
  return new VideoComponent(textbus, {
3292
- src: element instanceof HTMLImageElement ? element.src : ((_a = element.querySelector('video')) === null || _a === void 0 ? void 0 : _a.src) || ''
3679
+ src: video.src,
3680
+ width: video.style.width || 'auto',
3681
+ height: video.style.height || 'auto'
3682
+ });
3683
+ }
3684
+ };
3685
+
3686
+ class KatexEditor extends Textbus {
3687
+ constructor() {
3688
+ const adapter = new ViewflyAdapter({
3689
+ [SourceCodeComponent.componentName]: SourceCodeView
3690
+ }, (host, root, injector) => {
3691
+ const appInjector = new ReflectiveInjector(injector, [{
3692
+ provide: OutputInjectionToken,
3693
+ useValue: true
3694
+ }]);
3695
+ const app = createApp(root, {
3696
+ context: appInjector
3697
+ }).mount(host);
3698
+ return () => {
3699
+ app.destroy();
3700
+ };
3701
+ });
3702
+ const browserModule = new BrowserModule({
3703
+ adapter,
3704
+ renderTo: () => {
3705
+ return this.host;
3706
+ }
3707
+ });
3708
+ super({
3709
+ components: [
3710
+ SourceCodeComponent
3711
+ ],
3712
+ imports: [browserModule]
3713
+ });
3714
+ this.onValueChange = new Subject();
3715
+ }
3716
+ mount(host, code) {
3717
+ this.host = host;
3718
+ const model = new SourceCodeComponent(this, {
3719
+ lineNumber: true,
3720
+ autoBreak: true,
3721
+ lang: 'latex',
3722
+ theme: 'github',
3723
+ slots: code.split('\n').map(i => {
3724
+ const slot = new Slot([ContentType.Text]);
3725
+ slot.insert(i);
3726
+ return {
3727
+ slot,
3728
+ emphasize: false
3729
+ };
3730
+ })
3731
+ });
3732
+ this.onChange.subscribe(() => {
3733
+ const str = model.state.slots.map(i => {
3734
+ if (i.slot.isEmpty) {
3735
+ return '';
3736
+ }
3737
+ return i.slot.toString();
3738
+ }).join('\n');
3739
+ this.onValueChange.next(str);
3740
+ });
3741
+ return this.render(model);
3742
+ }
3743
+ }
3744
+
3745
+ class KatexComponent extends Component {
3746
+ static fromJSON(textbus, state) {
3747
+ return new KatexComponent(textbus, state);
3748
+ }
3749
+ constructor(textbus, state = {
3750
+ text: '% \\f is defined as #1f(#2) using the macro\n' +
3751
+ '\\f\\relax{x} = \\int_{-\\infty}^\\infty\n' +
3752
+ '\\f\\hat\\xi\\,e^{2 \\pi i \\xi x}\n' +
3753
+ '\\,d\\xi'
3754
+ }) {
3755
+ super(textbus, state);
3756
+ }
3757
+ getSlots() {
3758
+ return [];
3759
+ }
3760
+ }
3761
+ KatexComponent.componentName = 'KatexComponent';
3762
+ KatexComponent.type = ContentType.InlineComponent;
3763
+ function domToVDom(el) {
3764
+ const attrs = {};
3765
+ el.getAttributeNames().forEach(key => {
3766
+ attrs[key] = el.getAttribute(key);
3767
+ });
3768
+ attrs.children = Array.from(el.childNodes).map(child => {
3769
+ if (child.nodeType === Node.ELEMENT_NODE) {
3770
+ return domToVDom(child);
3771
+ }
3772
+ return child.textContent || '';
3773
+ });
3774
+ return jsx$1(el.tagName.toLowerCase(), attrs);
3775
+ }
3776
+ function KatexComponentView(props) {
3777
+ function toDOM(value) {
3778
+ let htmlString;
3779
+ try {
3780
+ htmlString = Katex.renderToString(value, {
3781
+ displayMode: true,
3782
+ leqno: false,
3783
+ fleqn: false,
3784
+ throwOnError: true,
3785
+ errorColor: '#cc0000',
3786
+ strict: 'warn',
3787
+ output: 'html',
3788
+ trust: false,
3789
+ macros: { '\\f': '#1f(#2)' }
3790
+ });
3791
+ }
3792
+ catch (e) {
3793
+ htmlString = '<span style="color: red">公式错误</span>';
3794
+ }
3795
+ return new DOMParser().parseFromString(htmlString, 'text/html').body.children[0];
3796
+ }
3797
+ const selection = inject(Textbus);
3798
+ const editorRef = createDynamicRef(node => {
3799
+ const editor = new KatexEditor();
3800
+ editor.mount(node, props.component.state.text).then(() => {
3801
+ editor.focus();
3802
+ });
3803
+ selection.blur();
3804
+ const subscription = editor.onValueChange.subscribe((value) => {
3805
+ props.component.state.text = value;
3806
+ }).add(fromEvent(node, 'mousedown').subscribe(ev => ev.stopPropagation()), fromEvent(document, 'mousedown').subscribe(() => {
3807
+ var _a;
3808
+ (_a = dropdownRef.current) === null || _a === void 0 ? void 0 : _a.isShow(false);
3809
+ }));
3810
+ return () => {
3811
+ subscription.unsubscribe();
3812
+ editor.destroy();
3813
+ };
3814
+ });
3815
+ const dropdownRef = createRef();
3816
+ const output = useOutput();
3817
+ const readonly = useReadonly();
3818
+ return () => {
3819
+ const text = props.component.state.text;
3820
+ return (jsx("span", { onClick: () => {
3821
+ var _a;
3822
+ (_a = dropdownRef.current) === null || _a === void 0 ? void 0 : _a.isShow(true);
3823
+ }, ref: props.rootRef, "data-component": KatexComponent.componentName, "data-katex": encodeURIComponent(text), class: "xnote-katex", children: (output() || readonly()) ?
3824
+ domToVDom(toDOM(text))
3825
+ :
3826
+ jsx(Dropdown, { padding: '0', ref: dropdownRef, trigger: 'none', width: '600px', menu: jsx("div", { class: "xnote-katex-input", ref: editorRef }), children: domToVDom(toDOM(text)) }) }));
3827
+ };
3828
+ }
3829
+ const katexComponentLoader = {
3830
+ match(element) {
3831
+ return element.dataset.component === KatexComponent.componentName;
3832
+ },
3833
+ read(element, textbus) {
3834
+ const value = element.dataset.katex || '';
3835
+ return new KatexComponent(textbus, {
3836
+ text: decodeURIComponent(value)
3293
3837
  });
3294
3838
  }
3295
3839
  };
@@ -3298,7 +3842,8 @@ function InsertTool(props) {
3298
3842
  const commander = inject(Commander);
3299
3843
  const selection = inject(Selection);
3300
3844
  const textbus = inject(Textbus);
3301
- const fileUploader = inject(FileUploader, InjectFlags.Optional, null);
3845
+ const fileUploader = inject(FileUploader, null);
3846
+ const dropdownContextService = inject(DropdownContextService);
3302
3847
  function insert(type) {
3303
3848
  var _a;
3304
3849
  const component = (_a = props.slot) === null || _a === void 0 ? void 0 : _a.parent;
@@ -3312,6 +3857,8 @@ function InsertTool(props) {
3312
3857
  else {
3313
3858
  commander.insertAfter(comp, component);
3314
3859
  }
3860
+ dropdownContextService.canHide = true;
3861
+ dropdownContextService.hide(false);
3315
3862
  }
3316
3863
  switch (type) {
3317
3864
  case 'h1':
@@ -3373,7 +3920,9 @@ function InsertTool(props) {
3373
3920
  {
3374
3921
  const table = new TableComponent(textbus);
3375
3922
  insertComponent(table);
3376
- selection.setPosition(table.state.rows[0].cells[0].slot, 0);
3923
+ textbus.nextTick(() => {
3924
+ selection.selectFirstPosition(table, true, true);
3925
+ });
3377
3926
  }
3378
3927
  break;
3379
3928
  case 'todolist':
@@ -3392,7 +3941,7 @@ function InsertTool(props) {
3392
3941
  break;
3393
3942
  case 'image':
3394
3943
  if (fileUploader) {
3395
- Promise.resolve(fileUploader.uploadFile('image')).then(url => {
3944
+ Promise.resolve().then(() => fileUploader.uploadFile('image')).then(url => {
3396
3945
  const img = new ImageComponent(textbus, {
3397
3946
  src: url
3398
3947
  });
@@ -3402,7 +3951,7 @@ function InsertTool(props) {
3402
3951
  break;
3403
3952
  case 'video':
3404
3953
  if (fileUploader) {
3405
- Promise.resolve(fileUploader.uploadFile('video')).then(url => {
3954
+ Promise.resolve().then(() => fileUploader.uploadFile('video')).then(url => {
3406
3955
  const img = new VideoComponent(textbus, {
3407
3956
  src: url
3408
3957
  });
@@ -3419,14 +3968,23 @@ function InsertTool(props) {
3419
3968
  selection.setPosition(p.state.slot, 0);
3420
3969
  }
3421
3970
  break;
3971
+ case 'katex':
3972
+ {
3973
+ const p = new ParagraphComponent(textbus);
3974
+ const comp = new KatexComponent(textbus);
3975
+ p.state.slot.insert(comp);
3976
+ insertComponent(p);
3977
+ selection.selectComponent(comp);
3978
+ }
3979
+ break;
3422
3980
  }
3423
3981
  }
3424
- return withScopedCSS(scopedId$8, () => {
3425
- 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" })] });
3982
+ return withScopedCSS(scopedId$9, () => {
3983
+ 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-hightlight-box" }), children: "\u9AD8\u4EAE\u5757" }), jsx(MenuItem, { onClick: () => insert('katex'), icon: jsx("span", { class: "xnote-icon-function" }), children: "\u6570\u5B66\u516C\u5F0F" })] });
3426
3984
  });
3427
3985
  }
3428
3986
 
3429
- var scopedId$7 = "vf-b05292";
3987
+ var scopedId$8 = "vf-b05292";
3430
3988
 
3431
3989
  const LeftToolbar = withAnnotation({
3432
3990
  providers: [RefreshService]
@@ -3436,6 +3994,7 @@ const LeftToolbar = withAnnotation({
3436
3994
  const selection = inject(Selection);
3437
3995
  const rootComponentRef = inject(RootComponentRef);
3438
3996
  const refreshService = inject(RefreshService);
3997
+ const editorService = inject(EditorService);
3439
3998
  const checkStates = useActiveBlock();
3440
3999
  const toBlock = useBlockTransform();
3441
4000
  const activeSlot = createSignal(null);
@@ -3454,6 +4013,14 @@ const LeftToolbar = withAnnotation({
3454
4013
  top: 0,
3455
4014
  display: false
3456
4015
  });
4016
+ const sub = editorService.onLeftToolbarCanVisibleChange.subscribe(() => {
4017
+ updatePosition(d => {
4018
+ d.display = editorService.canShowLeftToolbar;
4019
+ });
4020
+ });
4021
+ onUnmounted(() => {
4022
+ sub.unsubscribe();
4023
+ });
3457
4024
  let isIgnoreMove = false;
3458
4025
  onMounted(() => {
3459
4026
  const rootComponent = rootComponentRef.component;
@@ -3461,12 +4028,14 @@ const LeftToolbar = withAnnotation({
3461
4028
  const sub = fromEvent(docContentContainer, 'mousemove').pipe(filter(() => {
3462
4029
  return !isIgnoreMove;
3463
4030
  }), map(ev => {
4031
+ var _a;
3464
4032
  let currentNode = ev.target;
3465
4033
  while (currentNode) {
3466
4034
  const slot = adapter.getSlotByNativeNode(currentNode);
3467
4035
  if (slot) {
3468
- if ((slot === null || slot === void 0 ? void 0 : slot.parent) instanceof SourceCodeComponent || (slot === null || slot === void 0 ? void 0 : slot.parent) instanceof TableComponent) {
3469
- return null;
4036
+ if (((_a = slot === null || slot === void 0 ? void 0 : slot.parent) === null || _a === void 0 ? void 0 : _a.type) === ContentType.InlineComponent) {
4037
+ currentNode = currentNode.parentNode;
4038
+ continue;
3470
4039
  }
3471
4040
  return slot;
3472
4041
  }
@@ -3481,7 +4050,9 @@ const LeftToolbar = withAnnotation({
3481
4050
  activeSlot.set(slot);
3482
4051
  if (slot) {
3483
4052
  checkStates(slot);
3484
- isEmptyBlock.set(slot.parent instanceof ParagraphComponent && slot.isEmpty);
4053
+ isEmptyBlock.set((slot.parent instanceof ParagraphComponent && slot.isEmpty) ||
4054
+ slot.parent instanceof SourceCodeComponent ||
4055
+ slot.parent instanceof TableComponent);
3485
4056
  const nativeNode = adapter.getNativeNodeByComponent(slot.parent);
3486
4057
  updatePosition(draft => {
3487
4058
  const containerRect = docContentContainer.getBoundingClientRect();
@@ -3533,19 +4104,7 @@ const LeftToolbar = withAnnotation({
3533
4104
  bindLeave();
3534
4105
  isShow.set(true);
3535
4106
  }));
3536
- });
3537
- let snapshot = null;
3538
- function queryBefore() {
3539
- const slot = activeSlot();
3540
- if (slot) {
3541
- snapshot = selection.createSnapshot();
3542
- selection.selectSlot(slot);
3543
- }
3544
- }
3545
- function queryAfter() {
3546
- snapshot === null || snapshot === void 0 ? void 0 : snapshot.restore();
3547
- snapshot = null;
3548
- }
4107
+ });
3549
4108
  function applyBefore() {
3550
4109
  const slot = activeSlot();
3551
4110
  if (slot) {
@@ -3577,7 +4136,7 @@ const LeftToolbar = withAnnotation({
3577
4136
  if (!slot) {
3578
4137
  return;
3579
4138
  }
3580
- if (slot.parent.__slots__.length <= 1) {
4139
+ if (slot.parent.slots.length <= 1) {
3581
4140
  commander.removeComponent(slot.parent);
3582
4141
  }
3583
4142
  else {
@@ -3589,20 +4148,21 @@ const LeftToolbar = withAnnotation({
3589
4148
  function changeIgnoreMove(b) {
3590
4149
  isIgnoreMove = b;
3591
4150
  }
3592
- return withScopedCSS(scopedId$7, () => {
4151
+ return withScopedCSS(scopedId$8, () => {
4152
+ var _a;
3593
4153
  const position = positionSignal();
3594
4154
  const slot = activeSlot();
3595
4155
  let activeNode = jsx("span", { class: "xnote-icon-pilcrow" });
3596
- const states = checkStates();
4156
+ const states = checkStates(slot);
3597
4157
  if (slot) {
3598
4158
  const types = [
3599
4159
  [states.paragraph, jsx("span", { class: "xnote-icon-pilcrow" })],
3600
4160
  [states.sourceCode, jsx("span", { class: "xnote-icon-source-code" })],
3601
4161
  [states.blockquote, jsx("span", { class: "xnote-icon-quotes-right" })],
3602
4162
  [states.todolist, jsx("span", { class: "xnote-icon-checkbox-checked" })],
3603
- [states.table, jsx("span", { class: "xnote-icon-table" })],
3604
4163
  [states.unorderedList, jsx("span", { class: "xnote-icon-list" })],
3605
4164
  [states.orderedList, jsx("span", { class: "xnote-icon-list-numbered" })],
4165
+ [states.table, jsx("span", { class: "xnote-icon-table" })],
3606
4166
  [states.h1, jsx("span", { class: "xnote-icon-heading-h1" })],
3607
4167
  [states.h2, jsx("span", { class: "xnote-icon-heading-h2" })],
3608
4168
  [states.h3, jsx("span", { class: "xnote-icon-heading-h3" })],
@@ -3617,18 +4177,20 @@ const LeftToolbar = withAnnotation({
3617
4177
  }
3618
4178
  }
3619
4179
  }
4180
+ const activeParentComponent = (_a = activeSlot()) === null || _a === void 0 ? void 0 : _a.parent;
4181
+ const needInsert = activeParentComponent instanceof TableComponent || activeParentComponent instanceof SourceCodeComponent;
3620
4182
  return (jsx("div", { class: "left-toolbar", ref: toolbarRef, children: jsx("div", { class: "left-toolbar-btn-wrap", ref: btnRef, style: {
3621
4183
  left: position.left + 'px',
3622
4184
  top: position.top + 'px',
3623
- display: position.display && selection.isCollapsed ? 'block' : 'none'
3624
- }, children: jsx(Dropdown, { onExpendStateChange: changeIgnoreMove, abreast: true, style: {
4185
+ display: position.display && selection.isCollapsed && editorService.canShowLeftToolbar ? 'block' : 'none'
4186
+ }, children: jsx(Dropdown, { toLeft: true, onExpendStateChange: changeIgnoreMove, abreast: true, style: {
3625
4187
  position: 'absolute',
3626
4188
  right: 0,
3627
4189
  top: 0
3628
4190
  }, menu: isEmptyBlock() ?
3629
- jsx(InsertTool, { replace: true, slot: activeSlot() })
4191
+ jsx(InsertTool, { replace: !needInsert, slot: activeSlot() })
3630
4192
  :
3631
- 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, applyBefore: applyBefore, queryBefore: queryBefore, queryAfter: queryAfter, 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, queryBefore: queryBefore, queryAfter: queryAfter, 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() ?
4193
+ 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() ?
3632
4194
  jsx("span", { children: jsx("i", { class: "xnote-icon-plus" }) })
3633
4195
  :
3634
4196
  jsxs("span", { children: [activeNode, jsx("i", { style: "font-size: 12px", class: "xnote-icon-more" })] }) }) }) }) }));
@@ -3663,24 +4225,74 @@ class LeftToolbarPlugin {
3663
4225
  }
3664
4226
  }
3665
4227
 
3666
- var scopedId$6 = "vf-fee98b";
4228
+ var scopedId$7 = "vf-3073ba";
3667
4229
 
3668
- let EditorService = class EditorService {
3669
- constructor() {
3670
- this.hideInlineToolbar = false;
4230
+ function LinkJump() {
4231
+ const selection = inject(Selection);
4232
+ const query = inject(Query);
4233
+ const bridge = inject(SelectionBridge);
4234
+ const container = inject(VIEW_CONTAINER);
4235
+ const href = createSignal('');
4236
+ const ref = createRef();
4237
+ const isShow = createSignal(false);
4238
+ function onSelectionChange() {
4239
+ if (selection.isCollapsed) {
4240
+ const queryState = query.queryFormat(linkFormatter);
4241
+ if (queryState.state === QueryStateType.Enabled) {
4242
+ const rect = bridge.getRect({
4243
+ slot: selection.startSlot,
4244
+ offset: selection.startOffset
4245
+ });
4246
+ if (rect) {
4247
+ const offsetRect = container.getBoundingClientRect();
4248
+ Object.assign(ref.current.style, {
4249
+ left: rect.left - offsetRect.left + 'px',
4250
+ top: rect.top - offsetRect.top + 'px'
4251
+ });
4252
+ isShow.set(true);
4253
+ let url = queryState.value.href;
4254
+ if (url.indexOf('://') < 0) {
4255
+ url = 'http://' + url;
4256
+ }
4257
+ href.set(url);
4258
+ return;
4259
+ }
4260
+ }
4261
+ }
4262
+ isShow.set(false);
3671
4263
  }
3672
- };
3673
- EditorService = __decorate([
3674
- Injectable({
3675
- provideIn: 'root'
3676
- })
3677
- ], EditorService);
4264
+ selection.onChange.pipe(delay()).subscribe(() => {
4265
+ onSelectionChange();
4266
+ });
4267
+ function cleanLink() {
4268
+ isShow.set(false);
4269
+ const commonAncestorSlot = selection.commonAncestorSlot;
4270
+ const index = selection.focusOffset;
4271
+ const ranges = commonAncestorSlot.getFormatRangesByFormatter(linkFormatter, 0, commonAncestorSlot.length);
4272
+ ranges.forEach(range => {
4273
+ if (range.startIndex < index && range.endIndex >= index) {
4274
+ commonAncestorSlot.applyFormat(linkFormatter, {
4275
+ startIndex: range.startIndex,
4276
+ endIndex: range.endIndex,
4277
+ value: null
4278
+ });
4279
+ }
4280
+ });
4281
+ }
4282
+ return createPortal(withScopedCSS(scopedId$7, () => {
4283
+ return (jsxs("div", { ref: ref, class: "link-jump-plugin", style: { display: isShow() ? '' : 'none' }, children: [jsx("span", { onClick: cleanLink, children: "\u6E05\u9664" }), jsx("a", { target: "_blank", href: href(), children: "\u8DF3\u8F6C" })] }));
4284
+ }), container);
4285
+ }
4286
+
4287
+ var scopedId$6 = "vf-fee98b";
3678
4288
 
3679
4289
  const Toolbar = withAnnotation({
3680
4290
  providers: [RefreshService]
3681
4291
  }, function Toolbar() {
3682
4292
  const selection = inject(Selection);
3683
4293
  const viewDocument = inject(VIEW_CONTAINER);
4294
+ const rootComponentRef = inject(RootComponentRef);
4295
+ const adapter = inject(DomAdapter);
3684
4296
  const bridge = inject(SelectionBridge);
3685
4297
  const textbus = inject(Textbus);
3686
4298
  const editorService = inject(EditorService);
@@ -3702,7 +4314,7 @@ const Toolbar = withAnnotation({
3702
4314
  const toolbarRef = createRef();
3703
4315
  function getTop() {
3704
4316
  const docRect = viewDocument.getBoundingClientRect();
3705
- const toolbarRect = toolbarRef.current.getBoundingClientRect();
4317
+ const toolbarHeight = 36;
3706
4318
  // const documentHeight = document.documentElement.clientHeight
3707
4319
  const selectionFocusRect = bridge.getRect({
3708
4320
  slot: selection.focusSlot,
@@ -3711,14 +4323,12 @@ const Toolbar = withAnnotation({
3711
4323
  if (!selectionFocusRect) {
3712
4324
  return null;
3713
4325
  }
3714
- // console.log(selectionFocusRect.top, toolbarRect.height)
3715
4326
  const centerLeft = selectionFocusRect.left;
3716
- const toBottom = selectionFocusRect.top < toolbarRect.height + 10;
4327
+ const toBottom = selectionFocusRect.top < toolbarHeight + 10;
3717
4328
  const top = toBottom ?
3718
4329
  selectionFocusRect.top + selectionFocusRect.height - docRect.top + 10 :
3719
- selectionFocusRect.top - docRect.top - toolbarRect.height - 10;
4330
+ selectionFocusRect.top - docRect.top - toolbarHeight - 10;
3720
4331
  updateViewPosition(draft => {
3721
- draft.isHide = false;
3722
4332
  draft.transitionDuration = .15;
3723
4333
  draft.left = centerLeft - docRect.left;
3724
4334
  draft.top = top + 10;
@@ -3739,13 +4349,15 @@ const Toolbar = withAnnotation({
3739
4349
  sub.unsubscribe();
3740
4350
  });
3741
4351
  function bindMouseup() {
3742
- mouseupSubscription = fromEvent(viewDocument, 'mouseup').pipe(filter(ev => {
4352
+ const docElement = adapter.getNativeNodeByComponent(rootComponentRef.component);
4353
+ mouseupSubscription = fromEvent(docElement, 'mouseup').pipe(filter(ev => {
3743
4354
  return !ev.composedPath().includes(toolbarRef.current);
3744
4355
  }), delay(100), filter(() => {
3745
4356
  return !selection.isCollapsed && !(selection.commonAncestorComponent instanceof SourceCodeComponent);
3746
4357
  }), map(getTop), delay(200)).subscribe((top) => {
3747
4358
  if (top !== null) {
3748
4359
  updateViewPosition(draft => {
4360
+ draft.isHide = false;
3749
4361
  draft.opacity = 1;
3750
4362
  draft.top = top;
3751
4363
  });
@@ -3764,10 +4376,10 @@ const Toolbar = withAnnotation({
3764
4376
  });
3765
4377
  bindMouseup();
3766
4378
  });
4379
+ const instance = getCurrentInstance();
3767
4380
  function hideToolbar() {
3768
- updateViewPosition(draft => {
3769
- draft.isHide = true;
3770
- });
4381
+ editorService.hideInlineToolbar = true;
4382
+ instance.markAsDirtied();
3771
4383
  }
3772
4384
  onUnmounted(() => {
3773
4385
  mousedownSubscription.unsubscribe();
@@ -3908,6 +4520,222 @@ class Matcher {
3908
4520
  }
3909
4521
  }
3910
4522
 
4523
+ class Organization {
4524
+ }
4525
+ function registerAtShortcut(textbus) {
4526
+ const keyboard = textbus.get(Keyboard);
4527
+ const selection = textbus.get(Selection);
4528
+ const commander = textbus.get(Commander);
4529
+ keyboard.addShortcut({
4530
+ keymap: {
4531
+ key: '@',
4532
+ shiftKey: true
4533
+ },
4534
+ action() {
4535
+ const { commonAncestorComponent } = selection;
4536
+ if (commonAncestorComponent instanceof SourceCodeComponent) {
4537
+ return false;
4538
+ }
4539
+ const at = new AtComponent(textbus);
4540
+ commander.insert(at);
4541
+ selection.setPosition(at.state.slot, 0);
4542
+ }
4543
+ });
4544
+ }
4545
+ class AtComponent extends Component {
4546
+ static fromJSON(textbus, { slot: slotState, userInfo }) {
4547
+ const registry = textbus.get(Registry);
4548
+ if (slotState) {
4549
+ const slot = registry.createSlot(slotState);
4550
+ return new AtComponent(textbus, {
4551
+ slot
4552
+ });
4553
+ }
4554
+ return new AtComponent(textbus, {
4555
+ userInfo,
4556
+ });
4557
+ }
4558
+ constructor(textbus, state = {
4559
+ slot: new Slot([ContentType.Text])
4560
+ }) {
4561
+ if (!state.userInfo && !state.slot) {
4562
+ state.slot = new Slot([ContentType.Text]);
4563
+ }
4564
+ super(textbus, state);
4565
+ this.focus = new Subject();
4566
+ this.members = createSignal([]);
4567
+ this.selectedIndex = createSignal(0);
4568
+ }
4569
+ getSlots() {
4570
+ if (this.state.slot) {
4571
+ return [this.state.slot];
4572
+ }
4573
+ return [];
4574
+ }
4575
+ setup() {
4576
+ let isFocus = false;
4577
+ onFocus(() => {
4578
+ isFocus = true;
4579
+ this.focus.next(true);
4580
+ onChange.next();
4581
+ });
4582
+ onBlur(() => {
4583
+ isFocus = false;
4584
+ this.focus.next(false);
4585
+ setTimeout(() => {
4586
+ if (this.parent && !this.state.userInfo) {
4587
+ const slot = this.state.slot;
4588
+ let text = '@';
4589
+ if (slot) {
4590
+ text += slot.isEmpty ? '' : slot.toString();
4591
+ }
4592
+ const snapshot = selection.createSnapshot();
4593
+ selection.selectComponent(this);
4594
+ commander.insert(text);
4595
+ snapshot.restore(true);
4596
+ }
4597
+ });
4598
+ });
4599
+ const organization = useContext(Organization);
4600
+ const selection = useContext(Selection);
4601
+ const commander = useContext(Commander);
4602
+ const onChange = new Subject();
4603
+ onContentInserted((ev) => {
4604
+ const key = this.state.slot.toString();
4605
+ if (key.length > 10) {
4606
+ selection.selectComponent(this);
4607
+ commander.insert(key);
4608
+ ev.preventDefault();
4609
+ return;
4610
+ }
4611
+ onChange.next();
4612
+ });
4613
+ onContentDeleted(() => {
4614
+ onChange.next();
4615
+ });
4616
+ onBreak((ev) => {
4617
+ const member = this.members()[this.selectedIndex()];
4618
+ if (member) {
4619
+ this.state.userInfo = Object.assign({}, member);
4620
+ }
4621
+ selection.selectComponentEnd(this);
4622
+ ev.preventDefault();
4623
+ });
4624
+ useDynamicShortcut({
4625
+ keymap: {
4626
+ key: ['ArrowDown', 'ArrowUp']
4627
+ },
4628
+ action: (key) => {
4629
+ let index = this.selectedIndex();
4630
+ if (key === 'ArrowUp') {
4631
+ if (index > 0) {
4632
+ index--;
4633
+ this.selectedIndex.set(index);
4634
+ }
4635
+ return;
4636
+ }
4637
+ if (index < this.members().length - 1) {
4638
+ index++;
4639
+ this.selectedIndex.set(index);
4640
+ }
4641
+ }
4642
+ });
4643
+ const subs = onChange.pipe(switchMap(() => {
4644
+ const key = this.state.slot.toString();
4645
+ return fromPromise(organization.getMembers(key));
4646
+ })).subscribe((members) => {
4647
+ this.members.set(members);
4648
+ this.selectedIndex.set(0);
4649
+ if (isFocus) {
4650
+ this.focus.next(true);
4651
+ }
4652
+ });
4653
+ onDestroy(() => {
4654
+ subs.unsubscribe();
4655
+ });
4656
+ }
4657
+ }
4658
+ AtComponent.componentName = 'AtComponent';
4659
+ AtComponent.type = ContentType.InlineComponent;
4660
+
4661
+ function AtComponentView(props) {
4662
+ const selection = inject(Selection);
4663
+ const dropdownRef = createRef();
4664
+ const subscription = props.component.focus.subscribe((b) => {
4665
+ if (dropdownRef.current && props.component.members().length) {
4666
+ dropdownRef.current.isShow(b);
4667
+ }
4668
+ });
4669
+ onUnmounted(() => {
4670
+ subscription.unsubscribe();
4671
+ });
4672
+ const readonly = useReadonly();
4673
+ const output = useOutput();
4674
+ const membersRef = createRef();
4675
+ onUpdated(() => {
4676
+ if (output() || readonly()) {
4677
+ return;
4678
+ }
4679
+ const container = membersRef.current;
4680
+ if (container) {
4681
+ const focusItem = container.children[props.component.selectedIndex()];
4682
+ if (focusItem) {
4683
+ const itemRect = focusItem.getBoundingClientRect();
4684
+ const dropdownMenu = container.parentNode.parentNode;
4685
+ const containerRect = dropdownMenu.getBoundingClientRect();
4686
+ if (itemRect.top - 5 < containerRect.top) {
4687
+ dropdownMenu.scrollTop += itemRect.top - 5 - containerRect.top;
4688
+ }
4689
+ else if (itemRect.bottom + 5 > containerRect.bottom) {
4690
+ dropdownMenu.scrollTop += itemRect.bottom + 5 - containerRect.bottom;
4691
+ }
4692
+ }
4693
+ }
4694
+ });
4695
+ return () => {
4696
+ const { slot, userInfo } = props.component.state;
4697
+ const selectedIndex = props.component.selectedIndex();
4698
+ if (userInfo) {
4699
+ return (jsxs("div", { class: "xnote-at xnote-at-complete", "data-info": encodeURIComponent(JSON.stringify(userInfo)), ref: props.rootRef, "data-component": props.component.name, children: [jsx("span", { children: "@" }), userInfo.name] }));
4700
+ }
4701
+ if (readonly() || output()) {
4702
+ return (jsxs("div", { class: "xnote-at", ref: props.rootRef, "data-component": props.component.name, children: [jsx("span", { children: "@" }), slot && jsx(SlotRender, { slot: slot, class: 'xnote-at-input', tag: "span" })] }));
4703
+ }
4704
+ const members = props.component.members();
4705
+ return (jsx("div", { 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) => {
4706
+ let hsl = any2Hsl(member.color);
4707
+ if (hsl === 'unknown') {
4708
+ hsl = any2Hsl('#000');
4709
+ }
4710
+ const rgb = hsl2Rgb(hsl);
4711
+ const yiq = (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
4712
+ const color = yiq >= 128 ? '#000' : '#fff';
4713
+ return (jsxs("div", { onClick: () => {
4714
+ props.component.state.userInfo = member;
4715
+ selection.selectComponentEnd(props.component);
4716
+ }, 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 }) :
4717
+ 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));
4718
+ }) }), children: [jsx("span", { children: "@" }), slot && jsx(SlotRender, { slot: slot, tag: 'span', class: 'xnote-at-input' })] }) }));
4719
+ };
4720
+ }
4721
+ const atComponentLoader = {
4722
+ match(element) {
4723
+ return element.dataset.component === AtComponent.componentName;
4724
+ },
4725
+ read(element, textbus, slotParser) {
4726
+ const data = element.dataset.info;
4727
+ if (data) {
4728
+ return new AtComponent(textbus, {
4729
+ userInfo: JSON.parse(decodeURIComponent(data))
4730
+ });
4731
+ }
4732
+ const slot = slotParser(new Slot([ContentType.Text]), element.querySelector('.xnote-at-input') || document.createElement('div'));
4733
+ return new AtComponent(textbus, {
4734
+ slot
4735
+ });
4736
+ }
4737
+ };
4738
+
3911
4739
  class RootComponent extends Component {
3912
4740
  constructor() {
3913
4741
  super(...arguments);
@@ -3919,17 +4747,36 @@ class RootComponent extends Component {
3919
4747
  content
3920
4748
  });
3921
4749
  }
4750
+ getSlots() {
4751
+ return [this.state.content];
4752
+ }
3922
4753
  setup() {
3923
- useBlockContent(this.state.content);
4754
+ useBlockContent((slot) => slot === this.state.content);
3924
4755
  onCompositionStart(ev => {
3925
4756
  this.onCompositionStart.next(ev);
3926
4757
  });
4758
+ onSlotSetAttribute(ev => {
4759
+ ev.preventDefault();
4760
+ });
4761
+ onSlotApplyFormat(ev => {
4762
+ ev.preventDefault();
4763
+ });
4764
+ }
4765
+ afterCheck() {
4766
+ const content = this.state.content;
4767
+ const lastContent = content.getContentAtIndex(content.length - 1);
4768
+ if (lastContent instanceof ParagraphComponent ||
4769
+ lastContent instanceof ListComponent ||
4770
+ lastContent instanceof TodolistComponent) {
4771
+ return;
4772
+ }
4773
+ content.retain(content.length);
4774
+ content.insert(new ParagraphComponent(this.textbus));
3927
4775
  }
3928
4776
  }
3929
4777
  RootComponent.componentName = 'RootComponent';
3930
4778
  RootComponent.type = ContentType.BlockComponent;
3931
4779
  function RootView(props) {
3932
- const adapter = inject(DomAdapter);
3933
4780
  const { content } = props.component.state;
3934
4781
  const ref = createDynamicRef(node => {
3935
4782
  const sub = props.component.onCompositionStart.subscribe(() => {
@@ -3939,16 +4786,14 @@ function RootView(props) {
3939
4786
  sub.unsubscribe();
3940
4787
  };
3941
4788
  });
4789
+ onUpdated(() => {
4790
+ props.component.afterCheck();
4791
+ });
3942
4792
  const readonly = useReadonly();
3943
4793
  const output = useOutput();
3944
4794
  return () => {
3945
4795
  const { rootRef } = props;
3946
- return (jsx("div", { class: "xnote-root", ref: [rootRef, ref], children: adapter.slotRender(content, children => {
3947
- return (createVNode('div', {
3948
- class: 'xnote-content',
3949
- 'data-placeholder': content.isEmpty ? '请输入内容' : ''
3950
- }, children));
3951
- }, readonly() || output()) }));
4796
+ return (jsx("div", { class: "xnote-root", dir: "auto", ref: [rootRef, ref], "data-component": props.component.name, children: jsx(SlotRender, { slot: content, tag: "div", class: "xnote-content", "data-placeholder": content.isEmpty ? '请输入内容' : '', renderEnv: readonly() || output() }) }));
3952
4797
  };
3953
4798
  }
3954
4799
  const rootComponentLoader = {
@@ -3962,9 +4807,7 @@ const rootComponentLoader = {
3962
4807
  ContentType.Text
3963
4808
  ]), element).toDelta();
3964
4809
  const slot = new Slot([
3965
- ContentType.BlockComponent,
3966
- ContentType.InlineComponent,
3967
- ContentType.Text
4810
+ ContentType.BlockComponent
3968
4811
  ]);
3969
4812
  deltaToBlock(delta, textbus).forEach(i => {
3970
4813
  slot.insert(i);
@@ -3991,6 +4834,7 @@ TableService = __decorate([
3991
4834
  function ResizeColumn(props) {
3992
4835
  const dragLineRef = createRef();
3993
4836
  let activeCol = null;
4837
+ const editorService = inject(EditorService);
3994
4838
  onMounted(() => {
3995
4839
  const { tableRef } = props;
3996
4840
  let isDrag = false;
@@ -4023,6 +4867,7 @@ function ResizeColumn(props) {
4023
4867
  }
4024
4868
  })).add(fromEvent(dragLineRef.current, 'mousedown').subscribe(downEvent => {
4025
4869
  isDrag = true;
4870
+ editorService.changeLeftToolbarVisible(false);
4026
4871
  props.onActiveStateChange(true);
4027
4872
  const x = downEvent.clientX;
4028
4873
  const layoutWidth = props.component.state.layoutWidth;
@@ -4030,16 +4875,20 @@ function ResizeColumn(props) {
4030
4875
  const initLeft = layoutWidth.slice(0, activeCol).reduce((a, b) => a + b, 0);
4031
4876
  const minWidth = 30;
4032
4877
  const minLeft = initLeft - initWidth + minWidth;
4878
+ const layoutWidthArr = layoutWidth.slice();
4033
4879
  const moveEvent = fromEvent(document, 'mousemove').subscribe(moveEvent => {
4034
4880
  const distanceX = moveEvent.clientX - x;
4035
4881
  dragLineRef.current.style.left = Math.max(initLeft + distanceX, minLeft) + 'px';
4036
- props.component.state.layoutWidth[activeCol - 1] = Math.max(initWidth + distanceX, minWidth);
4882
+ layoutWidthArr[activeCol - 1] = Math.max(initWidth + distanceX, minWidth);
4883
+ props.layoutWidth.set(layoutWidthArr.slice());
4037
4884
  }).add(fromEvent(document, 'mouseup').subscribe(upEvent => {
4038
4885
  isDrag = false;
4886
+ editorService.changeLeftToolbarVisible(true);
4039
4887
  props.onActiveStateChange(false);
4040
4888
  moveEvent.unsubscribe();
4041
4889
  const distanceX = upEvent.clientX - x;
4042
4890
  props.component.state.layoutWidth[activeCol - 1] = Math.max(initWidth + distanceX, minWidth);
4891
+ props.layoutWidth.set(props.component.state.layoutWidth);
4043
4892
  }));
4044
4893
  }));
4045
4894
  return () => {
@@ -4065,7 +4914,7 @@ function ResizeColumn(props) {
4065
4914
  });
4066
4915
  }
4067
4916
 
4068
- var scopedId$4 = "vf-d64cf9";
4917
+ var scopedId$4 = "vf-39cb2c";
4069
4918
 
4070
4919
  function TopBar(props) {
4071
4920
  const editorService = inject(EditorService);
@@ -4140,7 +4989,7 @@ function TopBar(props) {
4140
4989
  active: props.isFocus()
4141
4990
  }], children: jsxs("div", { class: "toolbar-wrapper", children: [jsx("div", { class: "insert-bar", children: jsx("table", { style: {
4142
4991
  transform: `translateX(${-leftDistance()}px)`
4143
- }, children: jsx("tbody", { children: jsx("tr", { children: state.layoutWidth.map((i, index) => {
4992
+ }, children: jsx("tbody", { children: jsx("tr", { children: props.layoutWidth().map((i, index) => {
4144
4993
  return (jsx("td", { style: { width: i + 'px', minWidth: i + 'px' }, children: jsxs("div", { class: "tool-container", children: [index === 0 && (jsx("span", { onMouseenter: () => {
4145
4994
  tableService.onInsertColumnBefore.next(0);
4146
4995
  }, onMouseleave: () => {
@@ -4166,7 +5015,7 @@ function TopBar(props) {
4166
5015
  }, children: jsx("span", { class: "xnote-icon-bin" }) }) }) })] }) }));
4167
5016
  }) }) }) }) }), jsx("div", { class: ['action-bar', { active: props.isFocus() }], children: jsx("table", { style: {
4168
5017
  transform: `translateX(${-leftDistance()}px)`
4169
- }, children: jsx("tbody", { children: jsx("tr", { children: state.layoutWidth.map((i, index) => {
5018
+ }, children: jsx("tbody", { children: jsx("tr", { children: props.layoutWidth().map((i, index) => {
4170
5019
  return jsx("td", { onClick: ev => {
4171
5020
  mouseDownFromToolbar = true;
4172
5021
  if (!ev.shiftKey) {
@@ -4186,7 +5035,7 @@ function TopBar(props) {
4186
5035
  });
4187
5036
  }
4188
5037
 
4189
- var scopedId$3 = "vf-b1149b";
5038
+ var scopedId$3 = "vf-7bef30";
4190
5039
 
4191
5040
  function Scroll(props) {
4192
5041
  const scrollRef = createRef();
@@ -4200,37 +5049,41 @@ function Scroll(props) {
4200
5049
  const el = scrollRef.current;
4201
5050
  function update() {
4202
5051
  if (props.isFocus()) {
4203
- input.caret.refresh(false);
5052
+ input.caret.refresh();
4204
5053
  }
4205
5054
  updateShowShadow(draft => {
4206
5055
  draft.leftEnd = el.scrollLeft === 0;
4207
5056
  draft.rightEnd = el.scrollLeft === el.scrollWidth - el.offsetWidth;
4208
5057
  });
4209
5058
  }
4210
- update();
5059
+ setTimeout(update);
4211
5060
  const s = fromEvent(el, 'scroll').subscribe(update);
4212
5061
  return () => s.unsubscribe();
4213
5062
  });
4214
5063
  onUpdated(() => {
4215
5064
  const el = scrollRef.current;
4216
- updateShowShadow(draft => {
4217
- draft.leftEnd = el.scrollLeft === 0;
4218
- draft.rightEnd = el.scrollLeft === el.scrollWidth - el.offsetWidth;
5065
+ setTimeout(() => {
5066
+ updateShowShadow(draft => {
5067
+ draft.leftEnd = el.scrollLeft === 0;
5068
+ draft.rightEnd = el.scrollLeft === el.scrollWidth - el.offsetWidth;
5069
+ });
4219
5070
  });
4220
5071
  });
4221
5072
  return withScopedCSS(scopedId$3, () => {
4222
- return jsx("div", { ref: [scrollRef, props.scrollRef], class: ['scroll-container', {
5073
+ return jsx("div", { ref: [scrollRef], class: ['scroll-container', {
4223
5074
  'left-end': showShadow().leftEnd,
4224
5075
  'right-end': showShadow().rightEnd,
4225
5076
  'active': props.isFocus(),
4226
5077
  // 'hide-selection': isSelectColumn()
4227
5078
  }], onScroll: ev => {
4228
- tableService.onScroll.next(ev.target.scrollLeft);
5079
+ setTimeout(() => {
5080
+ tableService.onScroll.next(ev.target.scrollLeft);
5081
+ }, 30);
4229
5082
  }, children: props.children });
4230
5083
  });
4231
5084
  }
4232
5085
 
4233
- var scopedId$2 = "vf-ef93c0";
5086
+ var scopedId$2 = "vf-aaece0";
4234
5087
 
4235
5088
  function LeftBar(props) {
4236
5089
  const editorService = inject(EditorService);
@@ -4430,9 +5283,9 @@ function SelectionMask(props) {
4430
5283
  updateStyles(draft => {
4431
5284
  draft.visible = true;
4432
5285
  draft.left = sum(state.layoutWidth.slice(0, selection.startColumn));
4433
- draft.top = sum(trs.slice(0, selection.startRow).map(i => i.offsetHeight)) + topCompensation;
5286
+ draft.top = trs[selection.startRow].offsetTop + topCompensation;
4434
5287
  draft.width = sum(state.layoutWidth.slice(selection.startColumn, selection.endColumn)) - 1 + 'px';
4435
- draft.height = sum(trs.slice(selection.startRow, selection.endRow).map(i => i.offsetHeight)) + heightCompensation + 'px';
5288
+ draft.height = trs[selection.endRow - 1].offsetTop + trs[selection.endRow - 1].offsetHeight + heightCompensation - draft.top + 'px';
4436
5289
  });
4437
5290
  }
4438
5291
  else {
@@ -4461,81 +5314,25 @@ function SelectionMask(props) {
4461
5314
  });
4462
5315
  }
4463
5316
 
5317
+ // import { SlotRender } from '../SlotRender'
4464
5318
  const TableComponentView = withAnnotation({
4465
5319
  providers: [TableService]
4466
5320
  }, function TableComponentView(props) {
4467
5321
  const adapter = inject(DomAdapter);
5322
+ const editorService = inject(EditorService);
4468
5323
  const isFocus = createSignal(false);
5324
+ const layoutWidth = createSignal(props.component.state.layoutWidth);
4469
5325
  const subscription = props.component.focus.subscribe(b => {
4470
5326
  isFocus.set(b);
5327
+ if (!b) {
5328
+ editorService.hideInlineToolbar = false;
5329
+ }
4471
5330
  });
4472
5331
  onUnmounted(() => {
4473
5332
  subscription.unsubscribe();
4474
5333
  });
4475
5334
  const tableRef = createRef();
4476
- const scrollRef = createRef();
4477
5335
  const isResizeColumn = createSignal(false);
4478
- const selection = inject(Selection);
4479
- const findPosition = (slot) => {
4480
- let cell = slot;
4481
- while ((cell === null || cell === void 0 ? void 0 : cell.parent) && cell.parent !== props.component) {
4482
- cell = cell.parentSlot;
4483
- }
4484
- if (cell) {
4485
- const rows = props.component.state.rows;
4486
- for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
4487
- const row = rows[rowIndex].cells;
4488
- for (let colIndex = 0; colIndex < row.length; colIndex++) {
4489
- const item = row[colIndex].slot;
4490
- if (item === cell) {
4491
- return {
4492
- rowIndex,
4493
- colIndex
4494
- };
4495
- }
4496
- }
4497
- }
4498
- }
4499
- return null;
4500
- };
4501
- onMounted(() => {
4502
- const sub = selection.onChange.subscribe(() => {
4503
- var _a;
4504
- if (selection.commonAncestorComponent !== props.component || selection.isCollapsed) {
4505
- props.component.tableSelection.set(null);
4506
- return;
4507
- }
4508
- const startPosition = findPosition(selection.startSlot);
4509
- const endPosition = findPosition(selection.endSlot);
4510
- if (startPosition && endPosition) {
4511
- if (startPosition.rowIndex === endPosition.rowIndex && startPosition.colIndex === endPosition.colIndex) {
4512
- if (selection.startSlot === selection.endSlot && selection.startOffset === 0 && selection.endOffset === ((_a = selection.startSlot) === null || _a === void 0 ? void 0 : _a.length)) {
4513
- props.component.tableSelection.set({
4514
- startColumn: startPosition.colIndex,
4515
- startRow: startPosition.rowIndex,
4516
- endColumn: endPosition.colIndex + 1,
4517
- endRow: endPosition.rowIndex + 1
4518
- });
4519
- return;
4520
- }
4521
- props.component.tableSelection.set(null);
4522
- return;
4523
- }
4524
- const [startColumn, endColumn] = [startPosition.colIndex, endPosition.colIndex].sort((a, b) => a - b);
4525
- const [startRow, endRow] = [startPosition.rowIndex, endPosition.rowIndex].sort((a, b) => a - b);
4526
- props.component.tableSelection.set({
4527
- startColumn,
4528
- startRow,
4529
- endColumn: endColumn + 1,
4530
- endRow: endRow + 1
4531
- });
4532
- }
4533
- else {
4534
- props.component.tableSelection.set(null);
4535
- }
4536
- });
4537
- return () => sub.unsubscribe();
4538
- });
4539
5336
  const rowMapping = new WeakMap();
4540
5337
  const readonly = useReadonly();
4541
5338
  const output = useOutput();
@@ -4548,45 +5345,42 @@ const TableComponentView = withAnnotation({
4548
5345
  }
4549
5346
  rowMapping.set(row, Math.random());
4550
5347
  });
4551
- Promise.resolve().then(() => {
4552
- props.component.afterContentCheck();
4553
- });
4554
5348
  if (readonly() || output()) {
4555
- return (jsx("div", { class: "xnote-table", "data-component": props.component.name, "data-layout-width": state.layoutWidth, ref: props.rootRef, children: jsx("div", { class: "xnote-table-container", children: jsxs("table", { class: [
4556
- 'xnote-table-content',
4557
- {
4558
- 'hide-selection': props.component.tableSelection()
4559
- }
4560
- ], children: [jsx("colgroup", { children: state.layoutWidth.map(w => {
4561
- return jsx("col", { style: { width: w + 'px', minWidth: w + 'px' } });
4562
- }) }), jsx("tbody", { children: rows.map((row) => {
4563
- return (jsx("tr", { children: row.cells.map(cell => {
4564
- return adapter.slotRender(cell.slot, children => {
4565
- return createVNode('td', {
4566
- key: cell.slot.id
4567
- }, children);
4568
- }, readonly() || output());
4569
- }) }, rowMapping.get(row)));
4570
- }) })] }) }) }));
4571
- }
4572
- return (jsxs("div", { class: "xnote-table", "data-component": props.component.name, "data-layout-width": state.layoutWidth, ref: props.rootRef, children: [jsx(TopBar, { isFocus: isFocus, component: props.component, scrollRef: scrollRef }), jsx(LeftBar, { tableRef: tableRef, isFocus: isFocus, component: props.component }), jsx(Scroll, { scrollRef: scrollRef, isFocus: isFocus, children: jsxs("div", { class: "xnote-table-container", children: [jsxs("table", { ref: tableRef, class: [
4573
- 'xnote-table-content',
4574
- {
4575
- 'hide-selection': props.component.tableSelection()
4576
- }
4577
- ], children: [jsx("colgroup", { children: state.layoutWidth.map(w => {
4578
- return jsx("col", { style: { width: w + 'px', minWidth: w + 'px' } });
4579
- }) }), jsx("tbody", { children: rows.map((row) => {
4580
- return (jsx("tr", { children: row.cells.map(cell => {
4581
- return adapter.slotRender(cell.slot, children => {
4582
- return createVNode('td', {
4583
- key: cell.slot.id
4584
- }, children);
4585
- }, readonly() || output());
4586
- }) }, rowMapping.get(row)));
4587
- }) })] }), jsx(ResizeColumn, { tableRef: tableRef, component: props.component, onActiveStateChange: isActive => {
4588
- isResizeColumn.set(isActive);
4589
- } }), jsx(SelectionMask, { tableRef: tableRef, component: props.component })] }) }), jsx(ResizeRow, { component: props.component, tableRef: tableRef })] }));
5349
+ return (jsx("div", { class: "xnote-table", "data-component": props.component.name, "data-layout-width": state.layoutWidth, children: jsx("div", { class: "xnote-table-inner", ref: props.rootRef, children: jsx("div", { class: "xnote-table-container", children: jsxs("table", { class: [
5350
+ 'xnote-table-content',
5351
+ {
5352
+ 'hide-selection': props.component.tableSelection()
5353
+ }
5354
+ ], children: [jsx("colgroup", { children: layoutWidth().map(w => {
5355
+ return jsx("col", { style: { width: w + 'px', minWidth: w + 'px' } });
5356
+ }) }), jsx("tbody", { children: rows.map((row) => {
5357
+ return (jsx("tr", { children: row.cells.map(cell => {
5358
+ return adapter.slotRender(cell.slot, children => {
5359
+ return createVNode('td', {
5360
+ key: cell.slot.id
5361
+ }, children);
5362
+ }, readonly() || output());
5363
+ }) }, rowMapping.get(row)));
5364
+ }) })] }) }) }) }));
5365
+ }
5366
+ return (jsx("div", { class: "xnote-table", "data-component": props.component.name, "data-layout-width": `[${state.layoutWidth.join(',')}]`, children: jsxs("div", { class: "xnote-table-inner", ref: props.rootRef, children: [jsx(TopBar, { isFocus: isFocus, layoutWidth: layoutWidth, component: props.component }), jsx(LeftBar, { tableRef: tableRef, isFocus: isFocus, component: props.component }), jsx(Scroll, { isFocus: isFocus, children: jsxs("div", { class: "xnote-table-container", children: [jsxs("table", { ref: tableRef, class: [
5367
+ 'xnote-table-content',
5368
+ {
5369
+ 'hide-selection': props.component.tableSelection()
5370
+ }
5371
+ ], children: [jsx("colgroup", { children: layoutWidth().map(w => {
5372
+ return jsx("col", { style: { width: w + 'px', minWidth: w + 'px' } });
5373
+ }) }), jsx("tbody", { children: rows.map((row) => {
5374
+ return (jsx("tr", { children: row.cells.map(cell => {
5375
+ return adapter.slotRender(cell.slot, children => {
5376
+ return createVNode('td', {
5377
+ key: cell.slot.id
5378
+ }, children);
5379
+ }, readonly() || output());
5380
+ }) }, rowMapping.get(row)));
5381
+ }) })] }), jsx(ResizeColumn, { tableRef: tableRef, component: props.component, layoutWidth: layoutWidth, onActiveStateChange: isActive => {
5382
+ isResizeColumn.set(isActive);
5383
+ } }), jsx(SelectionMask, { tableRef: tableRef, component: props.component })] }) }), jsx(ResizeRow, { component: props.component, tableRef: tableRef })] }) }));
4590
5384
  };
4591
5385
  });
4592
5386
  const tableComponentLoader = {
@@ -4594,10 +5388,11 @@ const tableComponentLoader = {
4594
5388
  return element.dataset.component === TableComponent.componentName || element.tagName === 'TABLE';
4595
5389
  },
4596
5390
  read(element, textbus, slotParser) {
5391
+ let content = element;
4597
5392
  if (element.tagName === 'DIV') {
4598
- element = element.querySelector('.xnote-table-content');
5393
+ content = element.querySelector('.xnote-table-content');
4599
5394
  }
4600
- const { tHead, tBodies, tFoot } = element;
5395
+ const { tHead, tBodies, tFoot } = content;
4601
5396
  const headers = [];
4602
5397
  const bodies = [];
4603
5398
  if (tHead) {
@@ -4615,6 +5410,8 @@ const tableComponentLoader = {
4615
5410
  });
4616
5411
  const delta = slotParser(new Slot([
4617
5412
  ContentType.BlockComponent,
5413
+ ContentType.InlineComponent,
5414
+ ContentType.Text
4618
5415
  ]), cell).toDelta();
4619
5416
  const results = deltaToBlock(delta, textbus);
4620
5417
  results.forEach(i => {
@@ -4640,6 +5437,8 @@ const tableComponentLoader = {
4640
5437
  });
4641
5438
  const delta = slotParser(new Slot([
4642
5439
  ContentType.BlockComponent,
5440
+ ContentType.InlineComponent,
5441
+ ContentType.Text
4643
5442
  ]), cell).toDelta();
4644
5443
  const results = deltaToBlock(delta, textbus);
4645
5444
  results.forEach(i => {
@@ -4735,6 +5534,88 @@ function autoComplete(table) {
4735
5534
  });
4736
5535
  }
4737
5536
 
5537
+ function findFocusCell(table, slot) {
5538
+ var _a;
5539
+ while (slot) {
5540
+ if (table.slots.includes(slot)) {
5541
+ return slot;
5542
+ }
5543
+ slot = (_a = slot.parent) === null || _a === void 0 ? void 0 : _a.parent;
5544
+ }
5545
+ return null;
5546
+ }
5547
+ let TableSelectionAwarenessDelegate = class TableSelectionAwarenessDelegate extends CollaborateSelectionAwarenessDelegate {
5548
+ constructor(domAdapter, selection) {
5549
+ super();
5550
+ this.domAdapter = domAdapter;
5551
+ this.selection = selection;
5552
+ }
5553
+ getRects(abstractSelection) {
5554
+ const { focusSlot, anchorSlot } = abstractSelection;
5555
+ const focusPaths = this.selection.getPathsBySlot(focusSlot);
5556
+ const anchorPaths = this.selection.getPathsBySlot(anchorSlot);
5557
+ const focusIsStart = Selection.compareSelectionPaths(focusPaths, anchorPaths);
5558
+ let startSlot;
5559
+ let endSlot;
5560
+ if (focusIsStart) {
5561
+ startSlot = focusSlot;
5562
+ endSlot = anchorSlot;
5563
+ }
5564
+ else {
5565
+ startSlot = anchorSlot;
5566
+ endSlot = focusSlot;
5567
+ }
5568
+ const commonAncestorComponent = Selection.getCommonAncestorComponent(startSlot, endSlot);
5569
+ if (!(commonAncestorComponent instanceof TableComponent)) {
5570
+ return false;
5571
+ }
5572
+ const range = getSelectedRanges(commonAncestorComponent, findFocusCell(commonAncestorComponent, startSlot), findFocusCell(commonAncestorComponent, endSlot));
5573
+ const rows = commonAncestorComponent.state.rows;
5574
+ const startFocusSlot = rows[range.startRow].cells[range.startColumn].slot;
5575
+ const endFocusSlot = rows[range.endRow].cells[range.endColumn].slot;
5576
+ const renderer = this.domAdapter;
5577
+ const startRect = renderer.getNativeNodeBySlot(startFocusSlot).getBoundingClientRect();
5578
+ const endRect = renderer.getNativeNodeBySlot(endFocusSlot).getBoundingClientRect();
5579
+ return [{
5580
+ left: startRect.left,
5581
+ top: startRect.top,
5582
+ width: endRect.left + endRect.width - startRect.left,
5583
+ height: endRect.top + endRect.height - startRect.top
5584
+ }];
5585
+ }
5586
+ };
5587
+ TableSelectionAwarenessDelegate = __decorate([
5588
+ Injectable(),
5589
+ __metadata("design:paramtypes", [DomAdapter,
5590
+ Selection])
5591
+ ], TableSelectionAwarenessDelegate);
5592
+ function getSelectedRanges(component, startSlot, endSlot) {
5593
+ const p1 = finedPosition(component, startSlot);
5594
+ const p2 = finedPosition(component, endSlot);
5595
+ return {
5596
+ startRow: Math.min(p1.rowIndex, p2.rowIndex),
5597
+ endRow: Math.max(p1.rowIndex, p2.rowIndex),
5598
+ startColumn: Math.min(p1.columnIndex, p2.columnIndex),
5599
+ endColumn: Math.max(p1.columnIndex, p2.columnIndex)
5600
+ };
5601
+ }
5602
+ function finedPosition(component, slot) {
5603
+ const rows = component.state.rows;
5604
+ for (let i = 0; i < rows.length; i++) {
5605
+ const row = rows[i];
5606
+ for (let j = 0; j < row.cells.length; j++) {
5607
+ const cell = row.cells[j].slot;
5608
+ if (cell === slot) {
5609
+ return {
5610
+ rowIndex: i,
5611
+ columnIndex: j
5612
+ };
5613
+ }
5614
+ }
5615
+ }
5616
+ return null;
5617
+ }
5618
+
4738
5619
  class Editor extends Textbus {
4739
5620
  constructor(editorConfig = {}) {
4740
5621
  const adapter = new ViewflyAdapter({
@@ -4747,13 +5628,15 @@ class Editor extends Textbus {
4747
5628
  [HighlightBoxComponent.componentName]: HighlightBoxView,
4748
5629
  [ListComponent.componentName]: ListComponentView,
4749
5630
  [ImageComponent.componentName]: ImageView,
4750
- [VideoComponent.componentName]: VideoView
5631
+ [VideoComponent.componentName]: VideoView,
5632
+ [AtComponent.componentName]: AtComponentView,
5633
+ [KatexComponent.componentName]: KatexComponentView,
4751
5634
  }, (host, root, injector) => {
4752
5635
  const appInjector = new ReflectiveInjector(injector, [{
4753
5636
  provide: OutputInjectionToken,
4754
5637
  useValue: false
4755
5638
  }]);
4756
- const app = createApp(root, {
5639
+ const app = createApp(jsxs(Fragment, { children: [root, jsx(LinkJump, {})] }), {
4757
5640
  context: appInjector
4758
5641
  }).mount(host);
4759
5642
  return () => {
@@ -4762,16 +5645,18 @@ class Editor extends Textbus {
4762
5645
  });
4763
5646
  const browserModule = new BrowserModule(Object.assign({ renderTo: () => {
4764
5647
  return this.host;
4765
- }, adapter, componentLoaders: [
5648
+ }, useContentEditable: isMobileBrowser(), adapter, componentLoaders: [
5649
+ atComponentLoader,
4766
5650
  sourceCodeComponentLoader,
5651
+ listComponentLoader,
4767
5652
  tableComponentLoader,
4768
5653
  imageComponentLoader,
4769
- videoComponentLoader,
4770
5654
  highlightBoxComponentLoader,
4771
5655
  blockquoteComponentLoader,
4772
- paragraphComponentLoader,
5656
+ videoComponentLoader,
4773
5657
  todolistComponentLoader,
4774
- listComponentLoader,
5658
+ katexComponentLoader,
5659
+ paragraphComponentLoader,
4775
5660
  ], formatLoaders: [
4776
5661
  backgroundColorFormatLoader,
4777
5662
  boldFormatLoader,
@@ -4791,6 +5676,10 @@ class Editor extends Textbus {
4791
5676
  const modules = [browserModule];
4792
5677
  if (editorConfig.collaborateConfig) {
4793
5678
  modules.push(new CollaborateModule(editorConfig.collaborateConfig));
5679
+ browserModule.providers.push({
5680
+ provide: CollaborateSelectionAwarenessDelegate,
5681
+ useClass: TableSelectionAwarenessDelegate
5682
+ });
4794
5683
  }
4795
5684
  const vDomAdapter = new ViewflyVDomAdapter({
4796
5685
  [ParagraphComponent.componentName]: ParagraphView,
@@ -4802,7 +5691,9 @@ class Editor extends Textbus {
4802
5691
  [HighlightBoxComponent.componentName]: HighlightBoxView,
4803
5692
  [ListComponent.componentName]: ListComponentView,
4804
5693
  [ImageComponent.componentName]: ImageView,
4805
- [VideoComponent.componentName]: VideoView
5694
+ [VideoComponent.componentName]: VideoView,
5695
+ [AtComponent.componentName]: AtComponentView,
5696
+ [KatexComponent.componentName]: KatexComponentView
4806
5697
  }, (host, root, injector) => {
4807
5698
  const appInjector = new ReflectiveInjector(injector, [{
4808
5699
  provide: OutputInjectionToken,
@@ -4831,7 +5722,9 @@ class Editor extends Textbus {
4831
5722
  TableComponent,
4832
5723
  HighlightBoxComponent,
4833
5724
  ListComponent,
4834
- VideoComponent
5725
+ VideoComponent,
5726
+ AtComponent,
5727
+ KatexComponent
4835
5728
  ], formatters: [
4836
5729
  backgroundColorFormatter,
4837
5730
  boldFormatter,
@@ -4859,6 +5752,9 @@ class Editor extends Textbus {
4859
5752
  registerHeadingShortcut(textbus);
4860
5753
  registerTextAlignShortcut(textbus);
4861
5754
  registerTextIndentShortcut(textbus);
5755
+ registerAtShortcut(textbus);
5756
+ registerListShortcut(textbus);
5757
+ registerBlockquoteShortcut(textbus);
4862
5758
  } }, editorConfig));
4863
5759
  this.editorConfig = editorConfig;
4864
5760
  this.translator = new OutputTranslator();
@@ -4871,9 +5767,22 @@ class Editor extends Textbus {
4871
5767
  if (config.content) {
4872
5768
  const parser = this.get(Parser);
4873
5769
  const doc = parser.parseDoc(config.content, rootComponentLoader);
4874
- rootComp = doc instanceof Component ? doc : new RootComponent(this, {
4875
- content: doc
4876
- });
5770
+ if (doc instanceof Component) {
5771
+ rootComp = doc;
5772
+ }
5773
+ else {
5774
+ const content = new Slot([
5775
+ ContentType.BlockComponent
5776
+ ]);
5777
+ if (doc instanceof Slot) {
5778
+ deltaToBlock(doc.toDelta(), this).forEach(i => {
5779
+ content.insert(i);
5780
+ });
5781
+ }
5782
+ rootComp = new RootComponent(this, {
5783
+ content
5784
+ });
5785
+ }
4877
5786
  }
4878
5787
  else {
4879
5788
  rootComp = new RootComponent(this, {
@@ -4887,4 +5796,4 @@ class Editor extends Textbus {
4887
5796
  }
4888
5797
  }
4889
5798
 
4890
- 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 };
5799
+ export { AtComponent, AtComponentView, AttrTool, BlockTool, BlockquoteComponent, BlockquoteView, BoldTool, Button, CodeTool, ColorTool, ComponentToolbar, Divider, DragResize, Dropdown, DropdownContextService, DropdownMenuPortal, DropdownService, Editor, EditorService, FileUploader, FontFamilyTool, FontSizeTool, HighlightBoxComponent, HighlightBoxView, ImageComponent, ImageView, InsertTool, ItalicTool, KatexComponent, KatexComponentView, Keymap, LeftToolbar, LeftToolbarPlugin, LinkJump, 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, katexComponentLoader, languageList, linkFormatLoader, linkFormatter, listComponentLoader, paragraphComponentLoader, registerAtShortcut, registerBlockquoteShortcut, registerBoldShortcut, registerCodeShortcut, registerHeadingShortcut, registerItalicShortcut, registerListShortcut, registerStrikeThroughShortcut, registerTextAlignShortcut, registerTextIndentShortcut, registerUnderlineShortcut, rootComponentLoader, sourceCodeComponentLoader, sourceCodeThemes, strikeThroughFormatLoader, strikeThroughFormatter, tableComponentLoader, textAlignAttr, textAlignAttrLoader, textIndentAttr, textIndentAttrLoader, toBlockquote, toList, todolistComponentLoader, toggleBold, toggleCode, toggleItalic, toggleStrikeThrough, toggleUnderline, underlineFormatLoader, underlineFormatter, useActiveBlock, useBlockContent, useBlockTransform, useOutput, useReadonly, videoComponentLoader };