@formicoidea/labre-core 0.59.0 → 0.61.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 (72) hide show
  1. package/architecture/code.c4 +111 -104
  2. package/architecture/domain.c4 +4 -4
  3. package/dist/_pkgs/affine-block-attachment/asset-picker.d.ts +8 -0
  4. package/dist/_pkgs/affine-block-attachment/asset-picker.js +25 -1
  5. package/dist/_pkgs/affine-block-attachment/attachment-block.js +9 -7
  6. package/dist/_pkgs/affine-block-database/database-block.js +4 -5
  7. package/dist/_pkgs/affine-block-database/service/index.d.ts +1 -0
  8. package/dist/_pkgs/affine-block-database/service/index.js +1 -0
  9. package/dist/_pkgs/affine-block-database/service/initial-view.d.ts +33 -0
  10. package/dist/_pkgs/affine-block-database/service/initial-view.js +20 -0
  11. package/dist/_pkgs/affine-block-database/utils/current-view.d.ts +7 -0
  12. package/dist/_pkgs/affine-block-database/utils/current-view.js +14 -0
  13. package/dist/_pkgs/affine-block-embed/common/render-linked-doc.js +2 -0
  14. package/dist/_pkgs/affine-block-embed-doc/common/child-card.d.ts +25 -0
  15. package/dist/_pkgs/affine-block-embed-doc/common/child-card.js +27 -0
  16. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/commands/insert-embed-linked-doc.js +6 -1
  17. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/configs/new-doc.js +2 -2
  18. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/embed-linked-doc-block.js +2 -6
  19. package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/embed-synced-doc-block.js +2 -3
  20. package/dist/_pkgs/affine-block-embed-doc/page-drop/page-drop.js +3 -3
  21. package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +1 -0
  22. package/dist/_pkgs/affine-block-surface/extensions/index.js +1 -0
  23. package/dist/_pkgs/affine-block-surface/extensions/legend-label.d.ts +11 -0
  24. package/dist/_pkgs/affine-block-surface/extensions/legend-label.js +16 -0
  25. package/dist/_pkgs/affine-block-surface/extensions/legend.d.ts +1 -11
  26. package/dist/_pkgs/affine-block-surface/extensions/legend.js +2 -11
  27. package/dist/_pkgs/affine-block-surface/extensions/toolbox.d.ts +62 -0
  28. package/dist/_pkgs/affine-block-surface/extensions/toolbox.js +1 -0
  29. package/dist/_pkgs/affine-block-surface/interchange-headless.d.ts +2 -0
  30. package/dist/_pkgs/affine-block-surface/interchange-headless.js +2 -0
  31. package/dist/_pkgs/affine-components/icons/loading.d.ts +6 -0
  32. package/dist/_pkgs/affine-components/icons/loading.js +16 -12
  33. package/dist/_pkgs/affine-fragment-doc-title/title-band/show-here.js +2 -2
  34. package/dist/_pkgs/affine-fragment-doc-title/title-band/title-band.d.ts +8 -0
  35. package/dist/_pkgs/affine-fragment-doc-title/title-band/title-band.js +35 -13
  36. package/dist/_pkgs/affine-fragment-doc-title/translations.d.ts +1 -1
  37. package/dist/_pkgs/affine-fragment-doc-title/translations.js +1 -1
  38. package/dist/_pkgs/affine-gfx-mindmap/toolbar/basket-elements.d.ts +12 -0
  39. package/dist/_pkgs/affine-gfx-mindmap/toolbar/basket-elements.js +44 -5
  40. package/dist/_pkgs/affine-gfx-mindmap/toolbar/senior-tool.d.ts +3 -2
  41. package/dist/_pkgs/affine-gfx-mindmap/toolbar/senior-tool.js +3 -2
  42. package/dist/_pkgs/affine-gfx-template/builtin/slides/build.js +10 -10
  43. package/dist/_pkgs/affine-gfx-template/builtin/slides/consts.d.ts +48 -64
  44. package/dist/_pkgs/affine-gfx-template/builtin/slides/consts.js +24 -21
  45. package/dist/_pkgs/affine-gfx-template/builtin/slides/masks.d.ts +1 -2
  46. package/dist/_pkgs/affine-gfx-template/builtin/slides/masks.js +0 -34
  47. package/dist/_pkgs/affine-inline-reference/reference-node/configs/toolbar.js +2 -1
  48. package/dist/_pkgs/affine-model/elements/c4/board.d.ts +0 -22
  49. package/dist/_pkgs/affine-model/elements/c4/board.js +1 -22
  50. package/dist/_pkgs/affine-model/elements/c4/consts.d.ts +29 -0
  51. package/dist/_pkgs/affine-model/elements/c4/consts.js +29 -0
  52. package/dist/_pkgs/affine-model/elements/c4/index.d.ts +1 -0
  53. package/dist/_pkgs/affine-model/elements/c4/index.js +1 -0
  54. package/dist/_pkgs/affine-model/headless.d.ts +1 -0
  55. package/dist/_pkgs/affine-model/headless.js +1 -0
  56. package/dist/_pkgs/affine-shared/consts/index.d.ts +9 -0
  57. package/dist/_pkgs/affine-shared/consts/index.js +9 -0
  58. package/dist/_pkgs/affine-shared/services/asset-picker-service.d.ts +7 -6
  59. package/dist/_pkgs/affine-shared/services/asset-picker-service.js +5 -5
  60. package/dist/_pkgs/affine-shared/services/title-band-service.d.ts +19 -0
  61. package/dist/_pkgs/data-view/core/component/cell-status/cell-status-css.d.ts +1 -1
  62. package/dist/_pkgs/data-view/core/component/cell-status/cell-status-css.js +10 -10
  63. package/dist/_pkgs/data-view/core/component/cell-status/cell-status.d.ts +1 -1
  64. package/dist/_pkgs/data-view/core/component/cell-status/cell-status.js +7 -5
  65. package/dist/_pkgs/data-view/property-presets/number/cell-renderer.d.ts +18 -0
  66. package/dist/_pkgs/data-view/property-presets/number/cell-renderer.js +51 -10
  67. package/dist/_pkgs/data-view/property-presets/text/cell-renderer.d.ts +23 -1
  68. package/dist/_pkgs/data-view/property-presets/text/cell-renderer.js +56 -15
  69. package/dist/_pkgs/data-view/property-presets/typing-commit.d.ts +16 -0
  70. package/dist/_pkgs/data-view/property-presets/typing-commit.js +27 -0
  71. package/dist/_pkgs/data-view/view-presets/list/list-view.js +1 -1
  72. package/package.json +1 -1
@@ -39,6 +39,7 @@ import { BaseCellRenderer } from '../../core/property/index.js';
39
39
  import { createFromBaseCellRenderer } from '../../core/property/renderer.js';
40
40
  import { stopPropagation } from '../../core/utils/event.js';
41
41
  import { createIcon } from '../../core/utils/uni-icon.js';
42
+ import { TypingCommit } from '../typing-commit.js';
42
43
  import { numberInputStyle, numberStyle } from './cell-renderer-css.js';
43
44
  import { numberPropertyModelConfig } from './define.js';
44
45
  import { formatNumber, parseNumber, } from './utils/formatter.js';
@@ -63,14 +64,15 @@ let NumberCell = (() => {
63
64
  });
64
65
  }
65
66
  });
67
+ this._baseSet = false;
68
+ this._typing = new TypingCommit(() => this._commitTyped());
66
69
  this._setValue = (str = this._inputEle?.value) => {
67
- if (!str) {
68
- this.valueSetNextTick(undefined);
70
+ this._typing.cancel();
71
+ // No input, nothing typed: never read as a cleared value.
72
+ if (str === undefined)
69
73
  return;
70
- }
71
- const enableNewFormatting = this.view.featureFlags$.value.enable_number_formatting;
72
- const value = enableNewFormatting ? parseNumber(str) : parseFloat(str);
73
- if (isNaN(value)) {
74
+ const value = this._parse(str);
75
+ if (value === null) {
74
76
  if (this._inputEle) {
75
77
  this._inputEle.value = this.value
76
78
  ? this._getFormattedString(this.value)
@@ -78,10 +80,11 @@ let NumberCell = (() => {
78
80
  }
79
81
  return;
80
82
  }
81
- if (this._inputEle) {
83
+ if (this._inputEle && value !== undefined) {
82
84
  this._inputEle.value = this._getFormattedString(value);
83
85
  }
84
- this.valueSetNextTick(value);
86
+ if (this._changed(value))
87
+ this.valueSetNextTick(value);
85
88
  };
86
89
  this.focusEnd = () => {
87
90
  if (!this._inputEle)
@@ -111,6 +114,34 @@ let NumberCell = (() => {
111
114
  : value.toString()
112
115
  : '';
113
116
  }
117
+ /** Parsed input; `null` for text that is not a number yet. */
118
+ _parse(str) {
119
+ if (!str)
120
+ return undefined;
121
+ const enableNewFormatting = this.view.featureFlags$.value.enable_number_formatting;
122
+ const value = enableNewFormatting ? parseNumber(str) : parseFloat(str);
123
+ return isNaN(value) ? null : value;
124
+ }
125
+ _changed(value) {
126
+ const base = this._baseSet ? this._base : this.value;
127
+ if (value === base)
128
+ return false;
129
+ this._base = value;
130
+ this._baseSet = true;
131
+ return true;
132
+ }
133
+ /** While typing: a number commits, a half-typed one waits, the input is
134
+ * left as typed. */
135
+ _commitTyped() {
136
+ this._typing.cancel();
137
+ const input = this._inputEle;
138
+ if (!input)
139
+ return;
140
+ const value = this._parse(input.value);
141
+ if (value === null || !this._changed(value))
142
+ return;
143
+ this.valueSetImmediate(value);
144
+ }
114
145
  _blur() {
115
146
  this.selectCurrentCell(false);
116
147
  }
@@ -125,14 +156,21 @@ let NumberCell = (() => {
125
156
  beforeExitEditingMode() {
126
157
  this._setValue();
127
158
  }
159
+ disconnectedCallback() {
160
+ if (this.isEditing$?.peek())
161
+ this._commitTyped();
162
+ this._typing.cancel();
163
+ super.disconnectedCallback();
164
+ }
128
165
  render() {
129
166
  if (this.isEditing$.value) {
130
- const formatted = this.value ? this._getFormattedString(this.value) : '';
167
+ this._opened ??= this.value ? this._getFormattedString(this.value) : '';
131
168
  return html `<input
132
169
  type="text"
133
170
  autocomplete="off"
134
- .value="${formatted}"
171
+ .value="${this._opened}"
135
172
  @keydown="${this._keydown}"
173
+ @input="${() => this._typing.schedule()}"
136
174
  @blur="${this._blur}"
137
175
  @focus="${this._focus}"
138
176
  class="${numberInputStyle} number"
@@ -140,6 +178,9 @@ let NumberCell = (() => {
140
178
  />`;
141
179
  }
142
180
  else {
181
+ this._opened = undefined;
182
+ this._base = undefined;
183
+ this._baseSet = false;
143
184
  return html ` <div class="${numberStyle} number">
144
185
  ${this._getFormattedString()}
145
186
  </div>`;
@@ -1,11 +1,33 @@
1
1
  import { BaseCellRenderer } from '../../core/property/index.js';
2
+ /**
3
+ * The plain-text cell (a hosted source's text and title columns, the title
4
+ * band's text). What is typed is committed while typing (after a pause),
5
+ * when the input loses the focus, when the cell leaves the DOM and when the
6
+ * cell exits editing (Enter, Escape, Tab, another cell): leaving by a path
7
+ * no view reports, a click outside the editor, lost the edit (recette 3,
8
+ * P3-5, `text-cell-commit.unit.spec.ts`). Escape commits too: what was typed
9
+ * is kept, as in the table before. A commit writes only what changed since
10
+ * the editor opened or last committed, so an exit without typing writes
11
+ * nothing and a value another peer wrote meanwhile is not overwritten.
12
+ */
2
13
  export declare class TextCell extends BaseCellRenderer<string, string> {
3
14
  private accessor _inputEle;
15
+ /**
16
+ * The text the input opened with, bound while editing: a value the
17
+ * source echoes back mid-typing (a commit while typing, a remote write)
18
+ * must not rewrite the input under the caret.
19
+ */
20
+ private _opened;
21
+ /** The last text handed to the source in this edit session. */
22
+ private _sent;
23
+ private readonly _typing;
4
24
  private readonly _keydown;
5
- private readonly _setValue;
25
+ private readonly _onBlur;
26
+ private _commit;
6
27
  focusEnd: () => void;
7
28
  afterEnterEditingMode(): void;
8
29
  beforeExitEditingMode(): void;
30
+ disconnectedCallback(): void;
9
31
  render(): import("lit-html").TemplateResult<1>;
10
32
  }
11
33
  export declare const textPropertyConfig: import("../../index.js").PropertyMetaConfig<"text", {}, string, string>;
@@ -37,8 +37,20 @@ import { query } from 'lit/decorators.js';
37
37
  import { BaseCellRenderer } from '../../core/property/index.js';
38
38
  import { createFromBaseCellRenderer } from '../../core/property/renderer.js';
39
39
  import { createIcon } from '../../core/utils/uni-icon.js';
40
+ import { TypingCommit } from '../typing-commit.js';
40
41
  import { textInputStyle, textStyle } from './cell-renderer-css.js';
41
42
  import { textPropertyModelConfig } from './define.js';
43
+ /**
44
+ * The plain-text cell (a hosted source's text and title columns, the title
45
+ * band's text). What is typed is committed while typing (after a pause),
46
+ * when the input loses the focus, when the cell leaves the DOM and when the
47
+ * cell exits editing (Enter, Escape, Tab, another cell): leaving by a path
48
+ * no view reports, a click outside the editor, lost the edit (recette 3,
49
+ * P3-5, `text-cell-commit.unit.spec.ts`). Escape commits too: what was typed
50
+ * is kept, as in the table before. A commit writes only what changed since
51
+ * the editor opened or last committed, so an exit without typing writes
52
+ * nothing and a value another peer wrote meanwhile is not overwritten.
53
+ */
42
54
  let TextCell = (() => {
43
55
  let _classSuper = BaseCellRenderer;
44
56
  let __inputEle_decorators;
@@ -48,21 +60,26 @@ let TextCell = (() => {
48
60
  constructor() {
49
61
  super(...arguments);
50
62
  this.#_inputEle_accessor_storage = __runInitializers(this, __inputEle_initializers, void 0);
51
- this._keydown = (__runInitializers(this, __inputEle_extraInitializers), (e) => {
63
+ /**
64
+ * The text the input opened with, bound while editing: a value the
65
+ * source echoes back mid-typing (a commit while typing, a remote write)
66
+ * must not rewrite the input under the caret.
67
+ */
68
+ this._opened = __runInitializers(this, __inputEle_extraInitializers);
69
+ this._typing = new TypingCommit(() => this._commit(false));
70
+ this._keydown = (e) => {
52
71
  if (e.key === 'Enter' && !e.isComposing) {
53
- // Leaving commits, once, through `beforeExitEditingMode`. Committing
54
- // here as well reset the input to the old value, which the exit then
55
- // wrote back over the new one (standalone-cell.unit.spec.ts).
72
+ // Leaving commits, through `beforeExitEditingMode`. Resetting the
73
+ // input here as well made the exit write the old value back over the
74
+ // new one (standalone-cell.unit.spec.ts).
56
75
  setTimeout(() => {
57
76
  this.selectCurrentCell(false);
58
77
  });
59
78
  }
60
- });
61
- this._setValue = (str = this._inputEle?.value) => {
62
- if (this._inputEle) {
63
- this._inputEle.value = `${this.value ?? ''}`;
64
- }
65
- this.valueSetNextTick(str);
79
+ };
80
+ this._onBlur = () => {
81
+ if (this.isEditing$.peek())
82
+ this._commit(false);
66
83
  };
67
84
  this.focusEnd = () => {
68
85
  if (!this._inputEle)
@@ -81,23 +98,47 @@ let TextCell = (() => {
81
98
  #_inputEle_accessor_storage;
82
99
  get _inputEle() { return this.#_inputEle_accessor_storage; }
83
100
  set _inputEle(value) { this.#_inputEle_accessor_storage = value; }
101
+ _commit(nextTick) {
102
+ this._typing.cancel();
103
+ const input = this._inputEle;
104
+ if (!input)
105
+ return;
106
+ const str = input.value;
107
+ const base = this._sent ?? this._opened ?? `${this.value ?? ''}`;
108
+ if (str === base)
109
+ return;
110
+ this._sent = str;
111
+ if (nextTick)
112
+ this.valueSetNextTick(str);
113
+ else
114
+ this.valueSetImmediate(str);
115
+ }
84
116
  afterEnterEditingMode() {
85
117
  this.focusEnd();
86
118
  }
87
119
  beforeExitEditingMode() {
88
- this._setValue();
120
+ this._commit(true);
121
+ }
122
+ disconnectedCallback() {
123
+ if (this.isEditing$?.peek())
124
+ this._commit(false);
125
+ this._typing.cancel();
126
+ super.disconnectedCallback();
89
127
  }
90
128
  render() {
91
129
  if (this.isEditing$.value) {
130
+ this._opened ??= `${this.value ?? ''}`;
92
131
  return html `<input
93
- .value="${this.value ?? ''}"
132
+ .value="${this._opened}"
94
133
  @keydown="${this._keydown}"
134
+ @input="${() => this._typing.schedule()}"
135
+ @blur="${this._onBlur}"
95
136
  class="${textInputStyle}"
96
137
  />`;
97
138
  }
98
- else {
99
- return html `<div class="${textStyle}">${this.value ?? ''}</div>`;
100
- }
139
+ this._opened = undefined;
140
+ this._sent = undefined;
141
+ return html `<div class="${textStyle}">${this.value ?? ''}</div>`;
101
142
  }
102
143
  };
103
144
  })();
@@ -0,0 +1,16 @@
1
+ /**
2
+ * How long an in-place cell editor (text, number) waits after the last
3
+ * keystroke before it commits what is typed. Short enough that a value
4
+ * typed and left by any path (a click outside the editor, a closed tab) is
5
+ * already written; long enough that a host writing to a server does not
6
+ * write once per keystroke (recette 3, P3-5).
7
+ */
8
+ export declare const TYPING_COMMIT_MS = 400;
9
+ /** The one commit waiting for the typing to pause. */
10
+ export declare class TypingCommit {
11
+ private readonly _commit;
12
+ private _timer;
13
+ constructor(_commit: () => void);
14
+ schedule(): void;
15
+ cancel(): void;
16
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * How long an in-place cell editor (text, number) waits after the last
3
+ * keystroke before it commits what is typed. Short enough that a value
4
+ * typed and left by any path (a click outside the editor, a closed tab) is
5
+ * already written; long enough that a host writing to a server does not
6
+ * write once per keystroke (recette 3, P3-5).
7
+ */
8
+ export const TYPING_COMMIT_MS = 400;
9
+ /** The one commit waiting for the typing to pause. */
10
+ export class TypingCommit {
11
+ constructor(_commit) {
12
+ this._commit = _commit;
13
+ }
14
+ schedule() {
15
+ this.cancel();
16
+ this._timer = setTimeout(() => {
17
+ this._timer = undefined;
18
+ this._commit();
19
+ }, TYPING_COMMIT_MS);
20
+ }
21
+ cancel() {
22
+ if (this._timer === undefined)
23
+ return;
24
+ clearTimeout(this._timer);
25
+ this._timer = undefined;
26
+ }
27
+ }
@@ -152,7 +152,7 @@ export class ListViewUI extends FlatViewUI {
152
152
  renderRow(rowId) {
153
153
  const view = this.view;
154
154
  const title = view.titleProperty$.value;
155
- // A value still loading keeps its chip, as a skeleton.
155
+ // A value still loading keeps its chip, with its spinner.
156
156
  const chips = view.bodyProperties$.value.filter(property => {
157
157
  const cell = property.cellGetOrCreate(rowId);
158
158
  return cell.status$?.value === 'pending' || !cell.isEmpty$.value;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@formicoidea/labre-core",
3
3
  "description": "Labre editor — the full BlockSuite-derived editor as one package.",
4
- "version": "0.59.0",
4
+ "version": "0.61.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "author": "lajola",