@formicoidea/labre-core 0.58.0 → 0.60.0

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 (194) hide show
  1. package/architecture/code.c4 +175 -144
  2. package/architecture/domain.c4 +15 -9
  3. package/architecture/likec4.config.json +3 -3
  4. package/dist/_pkgs/affine-block-attachment/edgeless-clipboard-config.d.ts +3 -2
  5. package/dist/_pkgs/affine-block-attachment/edgeless-clipboard-config.js +18 -13
  6. package/dist/_pkgs/affine-block-callout/adapters/markdown.js +4 -1
  7. package/dist/_pkgs/affine-block-code/adapters/html.js +1 -1
  8. package/dist/_pkgs/affine-block-code/adapters/markdown/preprocessor.js +13 -1
  9. package/dist/_pkgs/affine-block-code/adapters/notion-html.js +1 -1
  10. package/dist/_pkgs/affine-block-code/code-block.d.ts +17 -2
  11. package/dist/_pkgs/affine-block-code/code-block.js +28 -23
  12. package/dist/_pkgs/affine-block-code/code-toolbar/components/lang-button.js +17 -4
  13. package/dist/_pkgs/affine-block-code/code-toolbar/components/preview-button.js +1 -1
  14. package/dist/_pkgs/affine-block-data-view/data-source.js +12 -5
  15. package/dist/_pkgs/affine-block-edgeless-text/edgeless-clipboard-config.d.ts +3 -2
  16. package/dist/_pkgs/affine-block-edgeless-text/edgeless-clipboard-config.js +8 -5
  17. package/dist/_pkgs/affine-block-image/asset-picker.d.ts +23 -2
  18. package/dist/_pkgs/affine-block-image/asset-picker.js +52 -12
  19. package/dist/_pkgs/affine-block-image/configs/replace-action.d.ts +8 -5
  20. package/dist/_pkgs/affine-block-image/configs/replace-action.js +8 -8
  21. package/dist/_pkgs/affine-block-image/configs/toolbar.js +2 -1
  22. package/dist/_pkgs/affine-block-image/crop/crop-controller.d.ts +15 -0
  23. package/dist/_pkgs/affine-block-image/crop/crop-controller.js +40 -2
  24. package/dist/_pkgs/affine-block-image/crop/crop-math.d.ts +22 -0
  25. package/dist/_pkgs/affine-block-image/crop/crop-math.js +55 -2
  26. package/dist/_pkgs/affine-block-image/crop/crop-overlay.d.ts +17 -3
  27. package/dist/_pkgs/affine-block-image/crop/crop-overlay.js +64 -6
  28. package/dist/_pkgs/affine-block-image/edgeless-clipboard-config.d.ts +3 -2
  29. package/dist/_pkgs/affine-block-image/edgeless-clipboard-config.js +20 -14
  30. package/dist/_pkgs/affine-block-image/image-block.js +1 -0
  31. package/dist/_pkgs/affine-block-image/image-edgeless-block.js +3 -0
  32. package/dist/_pkgs/affine-block-image/index.d.ts +2 -0
  33. package/dist/_pkgs/affine-block-image/index.js +2 -0
  34. package/dist/_pkgs/affine-block-image/replace/commands.d.ts +68 -0
  35. package/dist/_pkgs/affine-block-image/replace/commands.js +200 -0
  36. package/dist/_pkgs/affine-block-image/replace/replace-model.d.ts +44 -0
  37. package/dist/_pkgs/affine-block-image/replace/replace-model.js +168 -0
  38. package/dist/_pkgs/affine-block-image/replace/toolbar.d.ts +21 -0
  39. package/dist/_pkgs/affine-block-image/replace/toolbar.js +159 -0
  40. package/dist/_pkgs/affine-block-image/translations.d.ts +15 -2
  41. package/dist/_pkgs/affine-block-image/translations.js +35 -2
  42. package/dist/_pkgs/affine-block-image/utils.d.ts +7 -0
  43. package/dist/_pkgs/affine-block-image/utils.js +13 -0
  44. package/dist/_pkgs/affine-block-image/view.js +7 -0
  45. package/dist/_pkgs/affine-block-note/components/edgeless-page-block-title.d.ts +14 -5
  46. package/dist/_pkgs/affine-block-note/components/edgeless-page-block-title.js +18 -11
  47. package/dist/_pkgs/affine-block-note/config.d.ts +9 -2
  48. package/dist/_pkgs/affine-block-note/edgeless-clipboard-config.d.ts +3 -2
  49. package/dist/_pkgs/affine-block-note/edgeless-clipboard-config.js +8 -5
  50. package/dist/_pkgs/affine-block-paragraph/adapters/markdown.js +11 -0
  51. package/dist/_pkgs/affine-block-root/commands/invisible-characters-commands.d.ts +17 -0
  52. package/dist/_pkgs/affine-block-root/commands/invisible-characters-commands.js +123 -0
  53. package/dist/_pkgs/affine-block-root/edgeless/clipboard/command.js +82 -65
  54. package/dist/_pkgs/affine-block-root/edgeless/edgeless-keyboard.js +2 -0
  55. package/dist/_pkgs/affine-block-root/index.d.ts +1 -0
  56. package/dist/_pkgs/affine-block-root/index.js +1 -0
  57. package/dist/_pkgs/affine-block-root/translations.d.ts +6 -0
  58. package/dist/_pkgs/affine-block-root/translations.js +10 -0
  59. package/dist/_pkgs/affine-block-root/view.js +6 -1
  60. package/dist/_pkgs/affine-block-surface/commands/index.d.ts +1 -1
  61. package/dist/_pkgs/affine-block-surface/commands/index.js +1 -1
  62. package/dist/_pkgs/affine-block-surface/commands/reassociate-connectors.d.ts +9 -0
  63. package/dist/_pkgs/affine-block-surface/commands/reassociate-connectors.js +21 -12
  64. package/dist/_pkgs/affine-block-surface/extensions/clipboard-config.d.ts +33 -0
  65. package/dist/_pkgs/affine-block-surface/extensions/clipboard-config.js +53 -0
  66. package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +1 -0
  67. package/dist/_pkgs/affine-block-surface/extensions/index.js +1 -0
  68. package/dist/_pkgs/affine-block-surface/extensions/legend-label.d.ts +11 -0
  69. package/dist/_pkgs/affine-block-surface/extensions/legend-label.js +16 -0
  70. package/dist/_pkgs/affine-block-surface/extensions/legend.d.ts +1 -11
  71. package/dist/_pkgs/affine-block-surface/extensions/legend.js +2 -11
  72. package/dist/_pkgs/affine-block-surface/extensions/reading-toolbar.js +12 -12
  73. package/dist/_pkgs/affine-block-surface/extensions/toolbox.d.ts +62 -0
  74. package/dist/_pkgs/affine-block-surface/extensions/toolbox.js +1 -0
  75. package/dist/_pkgs/affine-block-surface/framework-background/background-view.js +2 -1
  76. package/dist/_pkgs/affine-block-surface/framework-background/band-widths.d.ts +104 -0
  77. package/dist/_pkgs/affine-block-surface/framework-background/band-widths.js +156 -0
  78. package/dist/_pkgs/affine-block-surface/framework-background/def.d.ts +87 -4
  79. package/dist/_pkgs/affine-block-surface/framework-background/def.js +26 -7
  80. package/dist/_pkgs/affine-block-surface/framework-background/ellipsis.d.ts +58 -0
  81. package/dist/_pkgs/affine-block-surface/framework-background/ellipsis.js +110 -0
  82. package/dist/_pkgs/affine-block-surface/framework-background/index.d.ts +3 -0
  83. package/dist/_pkgs/affine-block-surface/framework-background/index.js +3 -0
  84. package/dist/_pkgs/affine-block-surface/framework-background/labels.d.ts +12 -2
  85. package/dist/_pkgs/affine-block-surface/framework-background/labels.js +29 -5
  86. package/dist/_pkgs/affine-block-surface/framework-background/measure-text.d.ts +14 -0
  87. package/dist/_pkgs/affine-block-surface/framework-background/measure-text.js +31 -0
  88. package/dist/_pkgs/affine-block-surface/framework-background/renderer.d.ts +14 -1
  89. package/dist/_pkgs/affine-block-surface/framework-background/renderer.js +84 -31
  90. package/dist/_pkgs/affine-block-surface/interchange-headless.d.ts +2 -0
  91. package/dist/_pkgs/affine-block-surface/interchange-headless.js +2 -0
  92. package/dist/_pkgs/affine-block-table/adapters/html.js +26 -14
  93. package/dist/_pkgs/affine-block-table/adapters/utils.d.ts +1 -0
  94. package/dist/_pkgs/affine-block-table/adapters/utils.js +23 -5
  95. package/dist/_pkgs/affine-block-table/header-menu.d.ts +13 -0
  96. package/dist/_pkgs/affine-block-table/header-menu.js +25 -0
  97. package/dist/_pkgs/affine-block-table/selection-controller.d.ts +15 -0
  98. package/dist/_pkgs/affine-block-table/selection-controller.js +62 -0
  99. package/dist/_pkgs/affine-block-table/table-cell-css.d.ts +7 -0
  100. package/dist/_pkgs/affine-block-table/table-cell-css.js +10 -0
  101. package/dist/_pkgs/affine-block-table/table-cell.d.ts +8 -0
  102. package/dist/_pkgs/affine-block-table/table-cell.js +35 -3
  103. package/dist/_pkgs/affine-block-table/table-data-manager.d.ts +14 -0
  104. package/dist/_pkgs/affine-block-table/table-data-manager.js +44 -3
  105. package/dist/_pkgs/affine-block-table/translations.d.ts +14 -0
  106. package/dist/_pkgs/affine-block-table/translations.js +22 -0
  107. package/dist/_pkgs/affine-components/highlight-dropdown-menu/highlight-duotone-icon.js +8 -8
  108. package/dist/_pkgs/affine-components/highlight-dropdown-menu/text-duotone-icon.js +11 -11
  109. package/dist/_pkgs/affine-gfx-mindmap/toolbar/mindmap-tool-button.d.ts +2 -2
  110. package/dist/_pkgs/affine-gfx-template/builtin/other.d.ts +4 -0
  111. package/dist/_pkgs/affine-gfx-template/builtin/other.js +1 -1
  112. package/dist/_pkgs/affine-gfx-template/builtin/slides/build.d.ts +81 -0
  113. package/dist/_pkgs/affine-gfx-template/builtin/slides/build.js +276 -0
  114. package/dist/_pkgs/affine-gfx-template/builtin/slides/consts.d.ts +126 -0
  115. package/dist/_pkgs/affine-gfx-template/builtin/slides/consts.js +101 -0
  116. package/dist/_pkgs/affine-gfx-template/builtin/slides/index.d.ts +8 -0
  117. package/dist/_pkgs/affine-gfx-template/builtin/slides/index.js +27 -0
  118. package/dist/_pkgs/affine-gfx-template/builtin/slides/masks.d.ts +83 -0
  119. package/dist/_pkgs/affine-gfx-template/builtin/slides/masks.js +674 -0
  120. package/dist/_pkgs/affine-gfx-template/contribute.js +12 -17
  121. package/dist/_pkgs/affine-gfx-template/make-snapshot.d.ts +14 -2
  122. package/dist/_pkgs/affine-gfx-template/make-snapshot.js +6 -2
  123. package/dist/_pkgs/affine-gfx-template/services/template-middlewares.d.ts +12 -0
  124. package/dist/_pkgs/affine-gfx-template/services/template-middlewares.js +48 -0
  125. package/dist/_pkgs/affine-gfx-template/services/template.js +2 -1
  126. package/dist/_pkgs/affine-gfx-template/toolbar/builtin-templates.d.ts +15 -1
  127. package/dist/_pkgs/affine-gfx-template/toolbar/builtin-templates.js +33 -37
  128. package/dist/_pkgs/affine-gfx-template/toolbar/template-type.d.ts +6 -0
  129. package/dist/_pkgs/affine-gfx-template/translations.d.ts +94 -0
  130. package/dist/_pkgs/affine-gfx-template/translations.js +441 -2
  131. package/dist/_pkgs/affine-model/blocks/table/table-model.d.ts +4 -0
  132. package/dist/_pkgs/affine-model/blocks/table/table-model.js +4 -0
  133. package/dist/_pkgs/affine-model/elements/bpmn/node.d.ts +46 -3
  134. package/dist/_pkgs/affine-model/elements/bpmn/node.js +47 -4
  135. package/dist/_pkgs/affine-model/elements/bpmn/pool.d.ts +20 -0
  136. package/dist/_pkgs/affine-model/elements/bpmn/pool.js +33 -4
  137. package/dist/_pkgs/affine-model/elements/c4/board.d.ts +0 -22
  138. package/dist/_pkgs/affine-model/elements/c4/board.js +1 -22
  139. package/dist/_pkgs/affine-model/elements/c4/consts.d.ts +29 -0
  140. package/dist/_pkgs/affine-model/elements/c4/consts.js +29 -0
  141. package/dist/_pkgs/affine-model/elements/c4/index.d.ts +1 -0
  142. package/dist/_pkgs/affine-model/elements/c4/index.js +1 -0
  143. package/dist/_pkgs/affine-model/headless.d.ts +1 -0
  144. package/dist/_pkgs/affine-model/headless.js +1 -0
  145. package/dist/_pkgs/affine-shared/services/edit-props-store.d.ts +3 -16
  146. package/dist/_pkgs/affine-shared/services/edit-props-store.js +16 -16
  147. package/dist/_pkgs/affine-shared/services/editor-setting-service.d.ts +3 -0
  148. package/dist/_pkgs/affine-shared/services/editor-setting-service.js +4 -0
  149. package/dist/_pkgs/affine-shared/services/index.d.ts +1 -0
  150. package/dist/_pkgs/affine-shared/services/index.js +1 -0
  151. package/dist/_pkgs/affine-shared/services/invisible-characters.d.ts +33 -0
  152. package/dist/_pkgs/affine-shared/services/invisible-characters.js +63 -0
  153. package/dist/_pkgs/affine-shared/services/link-preview-service/link-preview-cache.d.ts +0 -9
  154. package/dist/_pkgs/affine-shared/services/link-preview-service/link-preview-cache.js +3 -9
  155. package/dist/_pkgs/affine-shared/services/telemetry-service/lifecycle.d.ts +26 -0
  156. package/dist/_pkgs/affine-shared/services/telemetry-service/telemetry-service.d.ts +4 -3
  157. package/dist/_pkgs/affine-shared/services/telemetry-service/types.d.ts +11 -0
  158. package/dist/_pkgs/affine-shared/utils/index.d.ts +1 -0
  159. package/dist/_pkgs/affine-shared/utils/index.js +1 -0
  160. package/dist/_pkgs/affine-shared/utils/invisible-characters.d.ts +42 -0
  161. package/dist/_pkgs/affine-shared/utils/invisible-characters.js +81 -0
  162. package/dist/_pkgs/affine-widget-edgeless-zoom-toolbar/index.js +26 -26
  163. package/dist/_pkgs/affine-widget-edgeless-zoom-toolbar/zoom-toolbar.js +13 -2
  164. package/dist/_pkgs/affine-widget-keyboard-toolbar/icons.js +98 -98
  165. package/dist/_pkgs/affine-widget-page-dragging-area/index.js +10 -10
  166. package/dist/_pkgs/affine-widget-viewport-overlay/index.js +13 -13
  167. package/dist/_pkgs/data-view/core/utils/menu-title.js +17 -17
  168. package/dist/_pkgs/data-view/view-presets/table/pc/header/column-header.js +6 -0
  169. package/dist/_pkgs/data-view/view-presets/table/pc/table-view-ui-logic.js +5 -2
  170. package/dist/_pkgs/std/clipboard/clipboard.d.ts +15 -1
  171. package/dist/_pkgs/std/clipboard/clipboard.js +18 -0
  172. package/dist/_pkgs/std/inline/components/embed-gap.js +1 -1
  173. package/dist/_pkgs/std/inline/components/v-line.js +1 -1
  174. package/dist/_pkgs/std/inline/components/v-text.d.ts +15 -2
  175. package/dist/_pkgs/std/inline/components/v-text.js +147 -15
  176. package/dist/_pkgs/std/inline/consts.d.ts +5 -0
  177. package/dist/_pkgs/std/inline/consts.js +5 -0
  178. package/dist/_pkgs/std/inline/utils/index.d.ts +1 -0
  179. package/dist/_pkgs/std/inline/utils/index.js +1 -0
  180. package/dist/_pkgs/std/inline/utils/invisible-characters.d.ts +57 -0
  181. package/dist/_pkgs/std/inline/utils/invisible-characters.js +162 -0
  182. package/dist/_pkgs/std/inline/utils/point-conversion.js +3 -3
  183. package/dist/_pkgs/std/inline/utils/text.d.ts +8 -0
  184. package/dist/_pkgs/std/inline/utils/text.js +11 -2
  185. package/dist/_pkgs/store/model/store/crud.d.ts +28 -0
  186. package/dist/_pkgs/store/model/store/crud.js +97 -30
  187. package/dist/_pkgs/store/model/store/query.js +3 -2
  188. package/dist/_pkgs/store/model/store/store.d.ts +21 -0
  189. package/dist/_pkgs/store/model/store/store.js +88 -21
  190. package/dist/_pkgs/store/transformer/transformer.d.ts +46 -0
  191. package/dist/_pkgs/store/transformer/transformer.js +72 -0
  192. package/dist/commands.js +6 -1
  193. package/dist/translations.js +2 -0
  194. package/package.json +3 -4
@@ -1,7 +1,19 @@
1
1
  import { LitElement } from 'lit';
2
- export declare class VText extends LitElement {
2
+ declare const VText_base: typeof LitElement;
3
+ export declare class VText extends VText_base {
4
+ private readonly _std;
5
+ private _showInvisibles$;
3
6
  createRenderRoot(): this;
4
- render(): import("lit-html").TemplateResult<1>;
7
+ connectedCallback(): void;
8
+ private _segments;
9
+ render(): import("lit-html").TemplateResult<1> | import("lit-html").TemplateResult<1>[];
10
+ /**
11
+ * A placeholder, not text of the model: the zero-width character an empty
12
+ * line or an embed gap renders so the caret has somewhere to go. Counted as
13
+ * length 0 by the offsets (`calculateTextLength`), whatever its content —
14
+ * a zero-width space the USER stored is text and keeps its length.
15
+ */
16
+ accessor empty: boolean;
5
17
  accessor str: string;
6
18
  }
7
19
  declare global {
@@ -9,3 +21,4 @@ declare global {
9
21
  'v-text': VText;
10
22
  }
11
23
  }
24
+ export {};
@@ -32,43 +32,175 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
32
32
  }
33
33
  return useValue ? value : void 0;
34
34
  };
35
- import { html, LitElement } from 'lit';
35
+ import { SignalWatcher } from '../../../global/lit/index.js';
36
+ import { ContextConsumer } from '@lit/context';
37
+ import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
36
38
  import { property } from 'lit/decorators.js';
37
39
  import { styleMap } from 'lit/directives/style-map.js';
38
- import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js';
40
+ import { stdContext } from '../../view/element/lit-host.js';
41
+ import { INLINE_ROOT_ATTR, SHOW_INVISIBLES_ATTR, ZERO_WIDTH_FOR_EMPTY_LINE, } from '../consts.js';
42
+ import { InvisibleCharactersDisplayIdentifier, segmentInvisibleCharacters, } from '../utils/invisible-characters.js';
43
+ const textStyle = styleMap({
44
+ 'word-break': 'break-word',
45
+ 'text-wrap': 'wrap',
46
+ 'white-space-collapse': 'break-spaces',
47
+ });
48
+ /**
49
+ * The marks of "show special characters". Each mark is drawn by an
50
+ * absolutely positioned `::before` over a span that still holds the original
51
+ * character: the layout, the offsets, a copy and the IME see the text as it is.
52
+ * Line ends are drawn per `v-line` from the attribute the editor sets on its
53
+ * host, so they need no element of their own. Colours are theme tokens.
54
+ */
55
+ const invisiblesStyles = css `
56
+ [data-v-invisible] {
57
+ position: relative;
58
+ }
59
+ [data-v-invisible]::before {
60
+ position: absolute;
61
+ left: 0;
62
+ right: 0;
63
+ text-align: center;
64
+ pointer-events: none;
65
+ user-select: none;
66
+ color: var(--affine-text-disable-color, currentColor);
67
+ font-weight: normal;
68
+ font-style: normal;
69
+ }
70
+ [data-v-invisible='space']::before {
71
+ content: '·';
72
+ }
73
+ [data-v-invisible='tab']::before {
74
+ content: '→';
75
+ }
76
+ [data-v-invisible='nbsp']::before {
77
+ content: '°';
78
+ }
79
+ [data-v-invisible='invisible']::before {
80
+ content: '';
81
+ left: -1px;
82
+ right: auto;
83
+ top: 10%;
84
+ bottom: 10%;
85
+ border-left: 2px solid var(--affine-error-color, currentColor);
86
+ }
87
+ [${unsafeCSS(SHOW_INVISIBLES_ATTR)}] v-line::after {
88
+ position: absolute;
89
+ pointer-events: none;
90
+ user-select: none;
91
+ color: var(--affine-text-disable-color, currentColor);
92
+ }
93
+ [${unsafeCSS(SHOW_INVISIBLES_ATTR)}] v-line:not(:last-of-type)::after {
94
+ content: '↵';
95
+ }
96
+ [${unsafeCSS(SHOW_INVISIBLES_ATTR)}] v-line:last-of-type::after {
97
+ content: '¶';
98
+ }
99
+ `;
100
+ /**
101
+ * One `[data-v-text]` span holding one text node. We need to avoid
102
+
103
+ * appearing before and after the span element, which will cause the sync
104
+ * problem about the cursor position.
105
+ */
106
+ function renderRun(text, kind, empty = false) {
107
+ return html `<span
108
+ style=${textStyle}
109
+ data-v-text="true"
110
+ data-v-empty=${empty ? 'true' : nothing}
111
+ data-v-invisible=${kind ?? nothing}
112
+ >${text}</span
113
+ >`;
114
+ }
115
+ const styledRoots = new WeakSet();
116
+ /**
117
+ * Adopt the marks' stylesheet once per document or shadow root, the first
118
+ * time a mark is rendered there: `v-text` renders in light DOM, so a static
119
+ * `styles` would never apply.
120
+ */
121
+ function adoptInvisiblesStyles(node) {
122
+ const root = node.getRootNode();
123
+ if (!(root instanceof Document || root instanceof ShadowRoot))
124
+ return;
125
+ if (styledRoots.has(root))
126
+ return;
127
+ const sheet = invisiblesStyles.styleSheet;
128
+ if (!sheet)
129
+ return;
130
+ styledRoots.add(root);
131
+ root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet];
132
+ }
39
133
  let VText = (() => {
40
- let _classSuper = LitElement;
134
+ let _classSuper = SignalWatcher(LitElement);
135
+ let _empty_decorators;
136
+ let _empty_initializers = [];
137
+ let _empty_extraInitializers = [];
41
138
  let _str_decorators;
42
139
  let _str_initializers = [];
43
140
  let _str_extraInitializers = [];
44
141
  return class VText extends _classSuper {
45
142
  static {
46
143
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
144
+ _empty_decorators = [property({ type: Boolean })];
47
145
  _str_decorators = [property({ attribute: false })];
146
+ __esDecorate(this, null, _empty_decorators, { kind: "accessor", name: "empty", static: false, private: false, access: { has: obj => "empty" in obj, get: obj => obj.empty, set: (obj, value) => { obj.empty = value; } }, metadata: _metadata }, _empty_initializers, _empty_extraInitializers);
48
147
  __esDecorate(this, null, _str_decorators, { kind: "accessor", name: "str", static: false, private: false, access: { has: obj => "str" in obj, get: obj => obj.str, set: (obj, value) => { obj.str = value; } }, metadata: _metadata }, _str_initializers, _str_extraInitializers);
49
148
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
50
149
  }
51
150
  createRenderRoot() {
52
151
  return this;
53
152
  }
153
+ connectedCallback() {
154
+ super.connectedCallback();
155
+ this._showInvisibles$ =
156
+ this._std.value?.getOptional(InvisibleCharactersDisplayIdentifier)
157
+ ?.showInvisibles$ ?? null;
158
+ }
159
+ _segments() {
160
+ if (!this._showInvisibles$?.value || this.empty)
161
+ return null;
162
+ // An embed's placeholder is one character of the model drawn as
163
+ // something else: never a mark on it.
164
+ if (this.closest('[data-v-embed="true"]'))
165
+ return null;
166
+ // Re-cutting the text under an IME composition would tear the
167
+ // composition apart: the plain run stays until the next render.
168
+ const root = this.closest(`[${INLINE_ROOT_ATTR}]`);
169
+ if (root?.inlineEditor?.isComposing)
170
+ return null;
171
+ return segmentInvisibleCharacters(this.str);
172
+ }
54
173
  render() {
55
- // we need to avoid \n appearing before and after the span element, which will
56
- // cause the sync problem about the cursor position
57
- return html `<span
58
- style=${styleMap({
59
- 'word-break': 'break-word',
60
- 'text-wrap': 'wrap',
61
- 'white-space-collapse': 'break-spaces',
62
- })}
63
- data-v-text="true"
64
- >${this.str}</span
65
- >`;
174
+ const segments = this._segments();
175
+ if (!segments)
176
+ return renderRun(this.str, undefined, this.empty);
177
+ adoptInvisiblesStyles(this);
178
+ // Several `[data-v-text]` spans, one text node each: offsets add the
179
+ // text nodes of every span (`getTextNodesFromElement`), so the caret and
180
+ // the selection map exactly as for one span.
181
+ return segments.map(segment => renderRun(segment.text, segment.kind));
66
182
  }
67
- #str_accessor_storage = __runInitializers(this, _str_initializers, ZERO_WIDTH_FOR_EMPTY_LINE);
183
+ #empty_accessor_storage;
184
+ /**
185
+ * A placeholder, not text of the model: the zero-width character an empty
186
+ * line or an embed gap renders so the caret has somewhere to go. Counted as
187
+ * length 0 by the offsets (`calculateTextLength`), whatever its content —
188
+ * a zero-width space the USER stored is text and keeps its length.
189
+ */
190
+ get empty() { return this.#empty_accessor_storage; }
191
+ set empty(value) { this.#empty_accessor_storage = value; }
192
+ #str_accessor_storage;
68
193
  get str() { return this.#str_accessor_storage; }
69
194
  set str(value) { this.#str_accessor_storage = value; }
70
195
  constructor() {
71
196
  super(...arguments);
197
+ // Resolved once, on connect: the editor host provides `std`, and `std` the
198
+ // viewer's choice. Outside a host (the document title, a standalone inline
199
+ // editor) there is none, and nothing is ever marked.
200
+ this._std = new ContextConsumer(this, { context: stdContext });
201
+ this._showInvisibles$ = null;
202
+ this.#empty_accessor_storage = __runInitializers(this, _empty_initializers, false);
203
+ this.#str_accessor_storage = (__runInitializers(this, _empty_extraInitializers), __runInitializers(this, _str_initializers, ZERO_WIDTH_FOR_EMPTY_LINE));
72
204
  __runInitializers(this, _str_extraInitializers);
73
205
  }
74
206
  };
@@ -1,3 +1,8 @@
1
1
  export declare const ZERO_WIDTH_FOR_EMPTY_LINE: string;
2
2
  export declare const ZERO_WIDTH_FOR_EMBED_NODE: string;
3
3
  export declare const INLINE_ROOT_ATTR = "data-v-root";
4
+ /**
5
+ * Set on the editor host while its viewer shows the special characters; the
6
+ * line ends are drawn from it (`v-text.ts`).
7
+ */
8
+ export declare const SHOW_INVISIBLES_ATTR = "data-show-invisibles";
@@ -2,3 +2,8 @@ import { IS_SAFARI } from '../../global/env/index.js';
2
2
  export const ZERO_WIDTH_FOR_EMPTY_LINE = IS_SAFARI ? '\u200C' : '\u200B';
3
3
  export const ZERO_WIDTH_FOR_EMBED_NODE = IS_SAFARI ? '\u200B' : '\u200C';
4
4
  export const INLINE_ROOT_ATTR = 'data-v-root';
5
+ /**
6
+ * Set on the editor host while its viewer shows the special characters; the
7
+ * line ends are drawn from it (`v-text.ts`).
8
+ */
9
+ export const SHOW_INVISIBLES_ATTR = 'data-show-invisibles';
@@ -9,3 +9,4 @@ export * from './range-conversion.js';
9
9
  export * from './renderer.js';
10
10
  export * from './text.js';
11
11
  export * from './transform-input.js';
12
+ export * from './invisible-characters.js';
@@ -9,3 +9,4 @@ export * from './range-conversion.js';
9
9
  export * from './renderer.js';
10
10
  export * from './text.js';
11
11
  export * from './transform-input.js';
12
+ export * from './invisible-characters.js';
@@ -0,0 +1,57 @@
1
+ import type { ReadonlySignal } from '@preact/signals-core';
2
+ /**
3
+ * The characters a reader cannot see and a writer rarely typed: the ones an
4
+ * AI text generator, a copy from a web page or a "watermarking" tool leaves in
5
+ * a paragraph. `text.invisibles.remove` strips them and the "show special
6
+ * characters" display marks them.
7
+ *
8
+ * - U+200B zero width space, U+2060 word joiner, U+FEFF zero width no-break
9
+ * space — a BOM inside a text is a watermark, never a byte order mark;
10
+ * - U+00AD soft hyphen, U+180E Mongolian vowel separator;
11
+ * - U+2061–U+2064 the invisible math operators;
12
+ * - U+E0000–U+E007F the tag characters ("ASCII smuggling");
13
+ * - U+200D zero width joiner — see {@link findInvisibleCharacters} for the
14
+ * two contexts where it and the tags are kept.
15
+ *
16
+ * Deliberately NOT here: U+200C zero width non-joiner, which Persian and the
17
+ * Indic scripts need, and the no-break spaces U+00A0 and U+202F, which French
18
+ * typography needs before `: ; ! ?` and inside quotation marks.
19
+ */
20
+ export declare const INVISIBLE_CHARACTERS: ReadonlySet<number>;
21
+ /** A character to strip or mark, as a UTF-16 slice of the string. */
22
+ export interface InvisibleCharacterRun {
23
+ index: number;
24
+ length: number;
25
+ }
26
+ /**
27
+ * Every character of {@link INVISIBLE_CHARACTERS} in `str`, one run per code
28
+ * point, in order. Kept, so never reported: a ZWJ joining two pictographs, and
29
+ * the tag sequence of a subdivision flag — stripping either would break an
30
+ * emoji the writer meant.
31
+ */
32
+ export declare function findInvisibleCharacters(str: string): InvisibleCharacterRun[];
33
+ /** What the "show special characters" display draws over a character. */
34
+ export type InvisibleCharacterKind = 'space' | 'tab' | 'nbsp' | 'invisible';
35
+ export interface InvisibleCharacterSegment {
36
+ text: string;
37
+ /** Absent: ordinary text, rendered as it is. */
38
+ kind?: InvisibleCharacterKind;
39
+ }
40
+ /**
41
+ * `str` cut so that every space, tab, no-break space and invisible character
42
+ * stands alone in its own segment, the rest kept in runs. `null` when there is
43
+ * nothing to mark, so the common case allocates nothing.
44
+ *
45
+ * The segments concatenate back to `str` exactly: the display keeps every
46
+ * character as it is and only draws over it.
47
+ */
48
+ export declare function segmentInvisibleCharacters(str: string): InvisibleCharacterSegment[] | null;
49
+ /**
50
+ * Whether THIS viewer asked to see the special characters. Provided by the
51
+ * editor (`InvisibleCharacters` in `@labre/affine-shared/services`), read by
52
+ * every `v-text` under the editor host; absent, nothing is marked.
53
+ */
54
+ export interface InvisibleCharactersDisplay {
55
+ readonly showInvisibles$: ReadonlySignal<boolean>;
56
+ }
57
+ export declare const InvisibleCharactersDisplayIdentifier: import("../../../global/di/types.js").ServiceIdentifier<InvisibleCharactersDisplay> & (<U extends InvisibleCharactersDisplay = InvisibleCharactersDisplay>(variant: import("../../../global/di/types.js").ServiceVariant) => import("../../../global/di/types.js").ServiceIdentifier<U>);
@@ -0,0 +1,162 @@
1
+ import { createIdentifier } from '../../../global/di/index.js';
2
+ /**
3
+ * The characters a reader cannot see and a writer rarely typed: the ones an
4
+ * AI text generator, a copy from a web page or a "watermarking" tool leaves in
5
+ * a paragraph. `text.invisibles.remove` strips them and the "show special
6
+ * characters" display marks them.
7
+ *
8
+ * - U+200B zero width space, U+2060 word joiner, U+FEFF zero width no-break
9
+ * space — a BOM inside a text is a watermark, never a byte order mark;
10
+ * - U+00AD soft hyphen, U+180E Mongolian vowel separator;
11
+ * - U+2061–U+2064 the invisible math operators;
12
+ * - U+E0000–U+E007F the tag characters ("ASCII smuggling");
13
+ * - U+200D zero width joiner — see {@link findInvisibleCharacters} for the
14
+ * two contexts where it and the tags are kept.
15
+ *
16
+ * Deliberately NOT here: U+200C zero width non-joiner, which Persian and the
17
+ * Indic scripts need, and the no-break spaces U+00A0 and U+202F, which French
18
+ * typography needs before `: ; ! ?` and inside quotation marks.
19
+ */
20
+ export const INVISIBLE_CHARACTERS = new Set([
21
+ 0x200b,
22
+ 0x200d,
23
+ 0x2060,
24
+ 0xfeff,
25
+ 0x00ad,
26
+ 0x180e,
27
+ 0x2061,
28
+ 0x2062,
29
+ 0x2063,
30
+ 0x2064,
31
+ ...Array.from({ length: 0x80 }, (_, i) => 0xe0000 + i),
32
+ ]);
33
+ const ZWJ = 0x200d;
34
+ const VARIATION_SELECTOR_16 = 0xfe0f;
35
+ const BLACK_FLAG = 0x1f3f4;
36
+ const CANCEL_TAG = 0xe007f;
37
+ const EXTENDED_PICTOGRAPHIC = /\p{Extended_Pictographic}/u;
38
+ function isPictographic(codePoint) {
39
+ return (codePoint !== undefined &&
40
+ EXTENDED_PICTOGRAPHIC.test(String.fromCodePoint(codePoint)));
41
+ }
42
+ function isSkinTone(codePoint) {
43
+ return codePoint >= 0x1f3fb && codePoint <= 0x1f3ff;
44
+ }
45
+ function codePointBefore(str, index) {
46
+ if (index <= 0)
47
+ return undefined;
48
+ const low = str.charCodeAt(index - 1);
49
+ if (low >= 0xdc00 && low <= 0xdfff && index >= 2) {
50
+ const high = str.charCodeAt(index - 2);
51
+ if (high >= 0xd800 && high <= 0xdbff)
52
+ return str.codePointAt(index - 2);
53
+ }
54
+ return low;
55
+ }
56
+ /**
57
+ * A ZWJ between two pictographs is the glue of an emoji sequence (woman
58
+ * technologist, heart on fire, family): the emoji before it may carry a
59
+ * variation selector or a skin tone.
60
+ */
61
+ function joinsEmoji(str, index) {
62
+ let before = index;
63
+ let previous = codePointBefore(str, before);
64
+ while (previous !== undefined &&
65
+ (previous === VARIATION_SELECTOR_16 || isSkinTone(previous))) {
66
+ before -= previous > 0xffff ? 2 : 1;
67
+ previous = codePointBefore(str, before);
68
+ }
69
+ return isPictographic(previous) && isPictographic(str.codePointAt(index + 1));
70
+ }
71
+ /**
72
+ * The tags after a black flag, closed by CANCEL TAG, spell a subdivision
73
+ * flag (Scotland, Wales, England): answers the index just past the sequence, or `-1`.
74
+ */
75
+ function endOfFlagTags(str, start) {
76
+ let index = start;
77
+ while (index < str.length) {
78
+ const codePoint = str.codePointAt(index);
79
+ if (codePoint < 0xe0020 || codePoint > 0xe007e)
80
+ break;
81
+ index += 2;
82
+ }
83
+ if (index === start || str.codePointAt(index) !== CANCEL_TAG)
84
+ return -1;
85
+ return index + 2;
86
+ }
87
+ /**
88
+ * Every character of {@link INVISIBLE_CHARACTERS} in `str`, one run per code
89
+ * point, in order. Kept, so never reported: a ZWJ joining two pictographs, and
90
+ * the tag sequence of a subdivision flag — stripping either would break an
91
+ * emoji the writer meant.
92
+ */
93
+ export function findInvisibleCharacters(str) {
94
+ const runs = [];
95
+ let index = 0;
96
+ while (index < str.length) {
97
+ const codePoint = str.codePointAt(index);
98
+ const size = codePoint > 0xffff ? 2 : 1;
99
+ if (codePoint === BLACK_FLAG) {
100
+ const end = endOfFlagTags(str, index + size);
101
+ index = end === -1 ? index + size : end;
102
+ continue;
103
+ }
104
+ if (INVISIBLE_CHARACTERS.has(codePoint) &&
105
+ !(codePoint === ZWJ && joinsEmoji(str, index))) {
106
+ runs.push({ index, length: size });
107
+ }
108
+ index += size;
109
+ }
110
+ return runs;
111
+ }
112
+ const MAYBE_SPECIAL = /[ \t\u00A0\u202F\u00AD\u180E\u200B\u200D\u2060-\u2064\uFEFF]|\udb40[\udc00-\udc7f]/;
113
+ function whitespaceKind(char) {
114
+ if (char === ' ')
115
+ return 'space';
116
+ if (char === '\t')
117
+ return 'tab';
118
+ if (char === '\u00A0' || char === '\u202F')
119
+ return 'nbsp';
120
+ return null;
121
+ }
122
+ /**
123
+ * `str` cut so that every space, tab, no-break space and invisible character
124
+ * stands alone in its own segment, the rest kept in runs. `null` when there is
125
+ * nothing to mark, so the common case allocates nothing.
126
+ *
127
+ * The segments concatenate back to `str` exactly: the display keeps every
128
+ * character as it is and only draws over it.
129
+ */
130
+ export function segmentInvisibleCharacters(str) {
131
+ if (!MAYBE_SPECIAL.test(str))
132
+ return null;
133
+ const invisible = new Map();
134
+ for (const run of findInvisibleCharacters(str)) {
135
+ invisible.set(run.index, run.length);
136
+ }
137
+ const segments = [];
138
+ let plainStart = 0;
139
+ const flush = (end) => {
140
+ if (end > plainStart)
141
+ segments.push({ text: str.slice(plainStart, end) });
142
+ };
143
+ let index = 0;
144
+ while (index < str.length) {
145
+ const length = invisible.get(index);
146
+ const kind = length ? 'invisible' : whitespaceKind(str[index]);
147
+ if (!kind) {
148
+ index += 1;
149
+ continue;
150
+ }
151
+ const size = length ?? 1;
152
+ flush(index);
153
+ segments.push({ text: str.slice(index, index + size), kind });
154
+ index += size;
155
+ plainStart = index;
156
+ }
157
+ if (segments.length === 0)
158
+ return null;
159
+ flush(str.length);
160
+ return segments;
161
+ }
162
+ export const InvisibleCharactersDisplayIdentifier = createIdentifier('InvisibleCharactersDisplay');
@@ -1,7 +1,7 @@
1
1
  import { BlockSuiteError, ErrorCode } from '../../../global/exceptions/index.js';
2
- import { INLINE_ROOT_ATTR, ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js';
2
+ import { INLINE_ROOT_ATTR } from '../consts.js';
3
3
  import { isInlineRoot, isNativeTextInVText, isVElement, isVLine, } from './guard.js';
4
- import { calculateTextLength, getTextNodesFromElement } from './text.js';
4
+ import { calculateTextLength, getTextNodesFromElement, isPlaceholderText, } from './text.js';
5
5
  export function nativePointToTextPoint(node, offset) {
6
6
  if (isNativeTextInVText(node)) {
7
7
  return [node, offset];
@@ -44,7 +44,7 @@ export function textPointToDomPoint(text, offset, rootElement) {
44
44
  for (const text of texts.slice(0, goalIndex)) {
45
45
  index += calculateTextLength(text);
46
46
  }
47
- if (text.wholeText !== ZERO_WIDTH_FOR_EMPTY_LINE) {
47
+ if (!isPlaceholderText(text)) {
48
48
  index += offset;
49
49
  }
50
50
  const textParentElement = text.parentElement;
@@ -1,2 +1,10 @@
1
+ /**
2
+ * Whether `text` is a placeholder rather than text of the model: the
3
+ * zero-width character an empty line or an embed gap renders (`v-text`'s
4
+ * `empty`, rendered as `data-v-empty`). Decided by the attribute, never by
5
+ * the content: a zero-width space the user stored, alone in its run (or in
6
+ * its own span when special characters are shown), is one character long.
7
+ */
8
+ export declare function isPlaceholderText(text: Text): boolean;
1
9
  export declare function calculateTextLength(text: Text): number;
2
10
  export declare function getTextNodesFromElement(element: Element): Text[];
@@ -1,6 +1,15 @@
1
- import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js';
1
+ /**
2
+ * Whether `text` is a placeholder rather than text of the model: the
3
+ * zero-width character an empty line or an embed gap renders (`v-text`'s
4
+ * `empty`, rendered as `data-v-empty`). Decided by the attribute, never by
5
+ * the content: a zero-width space the user stored, alone in its run (or in
6
+ * its own span when special characters are shown), is one character long.
7
+ */
8
+ export function isPlaceholderText(text) {
9
+ return text.parentElement?.dataset.vEmpty === 'true';
10
+ }
2
11
  export function calculateTextLength(text) {
3
- if (text.wholeText === ZERO_WIDTH_FOR_EMPTY_LINE) {
12
+ if (isPlaceholderText(text)) {
4
13
  return 0;
5
14
  }
6
15
  else {
@@ -5,7 +5,35 @@ export declare class DocCRUD {
5
5
  private readonly _yBlocks;
6
6
  private readonly _schema;
7
7
  get root(): string | null;
8
+ /**
9
+ * In-memory index of the tree: `childId -> parentId` plus the root id,
10
+ * rebuilt lazily after any structural change. Nothing here is written to Yjs
11
+ * (ADR 0041).
12
+ *
13
+ * Why: `root` scanned every block and `getParent` walked the tree from the
14
+ * root, so a load path calling `getParent` once per block was quadratic
15
+ * (#507: 11 s for 4000 blocks under a query with `viewType: 'hidden'`, whose
16
+ * `setAncestorsToDisplayIfHidden` climbs the ancestors of every block). #508
17
+ * only skipped that walk for queries that cannot hide blocks; the index
18
+ * makes the walk itself linear.
19
+ *
20
+ * Invalidation contract:
21
+ * - every transaction, local, remote (`Y.applyUpdate`) or undo, reaches
22
+ * `beforeObserverCalls` before any observer runs, so observers and
23
+ * everything after them read a fresh index;
24
+ * - inside a transaction, before that event, only the mutators below write
25
+ * the tree (`sys:children`, the blocks map): each drops the index before
26
+ * its first write, so a throw half-way leaves no stale index, and again
27
+ * after its last one, so a read in between cannot cache a half-written
28
+ * tree. A new writer of `sys:children` must do the same.
29
+ */
30
+ private _index;
31
+ /** Once deaf to remote changes, every read rebuilds (the pre-#507 cost). */
32
+ private _live;
33
+ private readonly _onBeforeObserverCalls;
8
34
  constructor(_yBlocks: Y.Map<YBlock>, _schema: Schema);
35
+ dispose(): void;
36
+ private _ensureIndex;
9
37
  private _getSiblings;
10
38
  addBlock(id: string, flavour: string, initialProps?: Record<string, unknown>, parent?: string | null, parentIndex?: number): void;
11
39
  deleteBlock(id: string, options?: {