@formicoidea/labre-core 0.47.1 → 0.48.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 (32) hide show
  1. package/dist/_pkgs/affine-block-database/view.js +5 -0
  2. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/configs/new-doc.d.ts +25 -0
  3. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/configs/new-doc.js +71 -0
  4. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/configs/slash-menu.js +3 -11
  5. package/dist/_pkgs/affine-fragment-doc-title/index.d.ts +1 -1
  6. package/dist/_pkgs/affine-fragment-doc-title/index.js +1 -1
  7. package/dist/_pkgs/affine-fragment-doc-title/title-band/band-cell.d.ts +22 -0
  8. package/dist/_pkgs/affine-fragment-doc-title/title-band/band-cell.js +125 -0
  9. package/dist/_pkgs/affine-fragment-doc-title/title-band/format.d.ts +7 -19
  10. package/dist/_pkgs/affine-fragment-doc-title/title-band/format.js +0 -38
  11. package/dist/_pkgs/affine-fragment-doc-title/title-band/show-here.d.ts +19 -0
  12. package/dist/_pkgs/affine-fragment-doc-title/title-band/show-here.js +61 -0
  13. package/dist/_pkgs/affine-fragment-doc-title/title-band/title-band.d.ts +28 -18
  14. package/dist/_pkgs/affine-fragment-doc-title/title-band/title-band.js +225 -207
  15. package/dist/_pkgs/affine-fragment-doc-title/translations.d.ts +7 -4
  16. package/dist/_pkgs/affine-fragment-doc-title/translations.js +12 -9
  17. package/dist/_pkgs/affine-shared/services/linked-doc-creation-service.d.ts +15 -6
  18. package/dist/_pkgs/affine-shared/services/title-band-service.d.ts +10 -7
  19. package/dist/_pkgs/affine-shared/utils/model/doc.d.ts +10 -2
  20. package/dist/_pkgs/affine-shared/utils/model/doc.js +17 -7
  21. package/dist/_pkgs/data-view/core/component/tags/multi-tag-select.d.ts +7 -2
  22. package/dist/_pkgs/data-view/core/component/tags/multi-tag-select.js +22 -15
  23. package/dist/_pkgs/data-view/core/effect.js +2 -0
  24. package/dist/_pkgs/data-view/core/property/index.d.ts +1 -0
  25. package/dist/_pkgs/data-view/core/property/index.js +1 -0
  26. package/dist/_pkgs/data-view/core/property/standalone-cell.d.ts +95 -0
  27. package/dist/_pkgs/data-view/core/property/standalone-cell.js +306 -0
  28. package/dist/_pkgs/data-view/core/view-manager/property.d.ts +6 -0
  29. package/dist/_pkgs/data-view/property-presets/multi-select/cell-renderer.js +1 -1
  30. package/dist/_pkgs/data-view/property-presets/select/cell-renderer.js +1 -1
  31. package/dist/_pkgs/data-view/property-presets/text/cell-renderer.js +3 -1
  32. package/package.json +1 -1
@@ -2,16 +2,25 @@ import type { EditorHost } from '../../std/index.js';
2
2
  import { type ExtensionType, type Store } from '../../store/index.js';
3
3
  /**
4
4
  * Creates the new doc that the linked-doc features populate (the edgeless
5
- * "Create linked page" / "Turn into linked page" actions). By default this is a
6
- * fresh in-workspace doc; a host app can override it to ALSO persist or register
7
- * the doc (assign a stored id, create a metadata row, attach sync) before the
8
- * editor writes blocks into the returned store.
5
+ * "Create linked page" / "Turn into linked page" actions, and the slash menu's
6
+ * "New Page" since 0.48, which leaves a linked-doc card where it was typed). By
7
+ * default this is a fresh in-workspace doc; a host app can override it to ALSO
8
+ * persist or register the doc (assign a stored id, create a metadata row,
9
+ * attach sync) before the editor writes blocks into the returned store.
9
10
  *
10
- * The returned `Store` must be ready for `addBlock`. `title` is forwarded so the
11
- * host can record it; the caller still writes the page block's own title.
11
+ * The returned `Store` is left UNLOADED: the caller writes its blocks in
12
+ * `store.load(initFn)`, and a doc that is already loaded skips `initFn`.
13
+ * `title` is forwarded so the host can record it; the caller still writes the
14
+ * page block's own title.
12
15
  */
13
16
  export interface LinkedDocCreationProvider {
14
17
  createLinkedDoc(host: EditorHost, title?: string): Store;
18
+ /**
19
+ * Whether a doc may be created from this editor at all (a host may refuse
20
+ * it on a doc shared with a guest, for instance). Read by the slash menu's
21
+ * "New Page", which hides itself on `false`. Absent means allowed (since 0.48).
22
+ */
23
+ canCreateLinkedDoc?(host: EditorHost): boolean;
15
24
  }
16
25
  export declare const LinkedDocCreationProvider: import("../../global/di/types.js").ServiceIdentifier<LinkedDocCreationProvider> & (<U extends LinkedDocCreationProvider = LinkedDocCreationProvider>(variant: import("../../global/di/types.js").ServiceVariant) => import("../../global/di/types.js").ServiceIdentifier<U>);
17
26
  /**
@@ -17,7 +17,7 @@ import type { ReadonlySignal } from '@preact/signals-core';
17
17
  * database cell read the same `type`, `data` and value.
18
18
  *
19
19
  * Absent, there is no band at all: no chips, no "+", no panel button, no "Not
20
- * shown in this document" row, and nothing else changes.
20
+ * shown on this page" row, and nothing else changes.
21
21
  */
22
22
  /**
23
23
  * One visible property of a page's sheet, in the order the band draws it.
@@ -103,12 +103,15 @@ export interface TitleBandService {
103
103
  collapsed$?(docId: string): ReadonlySignal<boolean>;
104
104
  setCollapsed?(docId: string, collapsed: boolean): void;
105
105
  /**
106
- * The child pages this document holds but does not display. Read **in the
107
- * canvas view only**, drawn in the note header as a "Not shown in this
108
- * document" row of page links that open through the linked-document path
109
- * (`RefNodeSlotsProvider.docLinkClicked`). In the page view the host draws
110
- * that row under the title itself, so a document never shows two. Absent
111
- * or empty, no row.
106
+ * The child pages this document holds but does not display, drawn in both
107
+ * views (under the title, and in the note header on the canvas) as a "Not
108
+ * shown on this page" row: each page is a link that opens through the
109
+ * linked-document path (`RefNodeSlotsProvider.docLinkClicked`; without it,
110
+ * no row), with a "Show here" button on a writable document that inserts
111
+ * an `affine:embed-linked-doc` card of it (end of the last note in the
112
+ * page view, centre of the visible canvas on the canvas). The library
113
+ * writes only that card: dropping the page from this list once it shows is
114
+ * the host's reading of the document. Absent or empty, no row.
112
115
  */
113
116
  notShown$?(docId: string): ReadonlySignal<readonly TitleBandNotShownPage[]>;
114
117
  }
@@ -1,5 +1,13 @@
1
- import type { Workspace } from '../../../store/index.js';
1
+ import type { Store, Workspace } from '../../../store/index.js';
2
2
  export declare function createDefaultDoc(collection: Workspace, options?: {
3
3
  id?: string;
4
4
  title?: string;
5
- }): import("../../../store/index.js").Store;
5
+ }): Store;
6
+ /**
7
+ * The blocks of a blank page, written into an empty store: the page with its
8
+ * title, its surface, and one note holding an empty paragraph. Shared by
9
+ * `createDefaultDoc` and by the creation paths that receive their store from
10
+ * the host (`LinkedDocCreationProvider`), so a page opens the same whoever
11
+ * made it.
12
+ */
13
+ export declare function writeDefaultDocBlocks(store: Store, title?: string): void;
@@ -5,19 +5,29 @@ export function createDefaultDoc(collection, options = {}) {
5
5
  doc.load();
6
6
  const store = doc.getStore();
7
7
  const title = options.title ?? '';
8
- const rootId = store.addBlock('affine:page', {
9
- title: new Text(title),
10
- });
8
+ writeDefaultDocBlocks(store, title);
11
9
  collection.meta.setDocMeta(doc.id, {
12
10
  title,
13
11
  });
12
+ // To make sure the content of new doc would not be clear
13
+ // By undo operation for the first time
14
+ store.resetHistory();
15
+ return store;
16
+ }
17
+ /**
18
+ * The blocks of a blank page, written into an empty store: the page with its
19
+ * title, its surface, and one note holding an empty paragraph. Shared by
20
+ * `createDefaultDoc` and by the creation paths that receive their store from
21
+ * the host (`LinkedDocCreationProvider`), so a page opens the same whoever
22
+ * made it.
23
+ */
24
+ export function writeDefaultDocBlocks(store, title = '') {
25
+ const rootId = store.addBlock('affine:page', {
26
+ title: new Text(title),
27
+ });
14
28
  store.addBlock('affine:surface', {}, rootId);
15
29
  const noteId = store.addBlock('affine:note', {
16
30
  xywh: `[0, 0, ${DEFAULT_PAGE_BLOCK_WIDTH}, ${DEFAULT_PAGE_BLOCK_HEIGHT}]`,
17
31
  }, rootId);
18
32
  store.addBlock('affine:paragraph', {}, noteId);
19
- // To make sure the content of new doc would not be clear
20
- // By undo operation for the first time
21
- store.resetHistory();
22
- return store;
23
33
  }
@@ -7,7 +7,12 @@ export type TagManagerOptions = {
7
7
  value: ReadonlySignal<string[]>;
8
8
  onChange: (value: string[]) => void;
9
9
  options: ReadonlySignal<SelectTag[]>;
10
- onOptionsChange: (options: SelectTag[]) => void;
10
+ /**
11
+ * Absent, the options are fixed: the menu picks among them and offers no
12
+ * "Create", no option menu and no reordering (a standalone cell whose host
13
+ * cannot write the property's config, `standalone-cell.ts`).
14
+ */
15
+ onOptionsChange?: (options: SelectTag[]) => void;
11
16
  onComplete?: () => void;
12
17
  initialDraftText?: string;
13
18
  };
@@ -32,7 +37,7 @@ export declare class MultiTagSelect extends MultiTagSelect_base {
32
37
  accessor mode: 'multi' | 'single';
33
38
  accessor onChange: (value: string[]) => void;
34
39
  accessor onComplete: () => void;
35
- accessor onOptionsChange: (options: SelectTag[]) => void;
40
+ accessor onOptionsChange: ((options: SelectTag[]) => void) | undefined;
36
41
  accessor options: ReadonlySignal<SelectTag[]>;
37
42
  private readonly selectedIndex$;
38
43
  accessor value: ReadonlySignal<string[]>;
@@ -77,7 +77,7 @@ class TagManager {
77
77
  constructor(ops) {
78
78
  this.ops = ops;
79
79
  this.changeTag = (option) => {
80
- this.ops.onOptionsChange(this.ops.options.value.map(item => {
80
+ this.ops.onOptionsChange?.(this.ops.options.value.map(item => {
81
81
  if (item.id === option.id) {
82
82
  return {
83
83
  ...item,
@@ -90,7 +90,7 @@ class TagManager {
90
90
  this.color$ = signal(getTagColor());
91
91
  this.createOption = () => {
92
92
  const value = this.text$.value.trim();
93
- if (value === '')
93
+ if (value === '' || !this.ops.onOptionsChange)
94
94
  return;
95
95
  const id = nanoid();
96
96
  this.ops.onOptionsChange([
@@ -109,7 +109,7 @@ class TagManager {
109
109
  }
110
110
  };
111
111
  this.deleteOption = (id) => {
112
- this.ops.onOptionsChange(this.ops.options.value.filter(item => item.id !== id));
112
+ this.ops.onOptionsChange?.(this.ops.options.value.filter(item => item.id !== id));
113
113
  };
114
114
  this.filteredOptions$ = computed(() => {
115
115
  let matched = false;
@@ -129,7 +129,7 @@ class TagManager {
129
129
  matched = true;
130
130
  }
131
131
  }
132
- if (this.text$.value && !matched) {
132
+ if (this.text$.value && !matched && this.ops.onOptionsChange) {
133
133
  options.push({
134
134
  id: 'create',
135
135
  color: this.color$.value,
@@ -246,11 +246,16 @@ let MultiTagSelect = (() => {
246
246
  </div>`;
247
247
  }
248
248
  renderTags() {
249
+ const editable = !!this.onOptionsChange;
249
250
  return html `
250
251
  <div
251
252
  style="height: 0.5px;background-color: ${cssVarV2('layer/insideBorder/border')};margin: 4px 0;"
252
253
  ></div>
253
- <div class="${selectOptionsTipsStyle}">Select tag or create one</div>
254
+ ${editable
255
+ ? html `<div class="${selectOptionsTipsStyle}">
256
+ Select tag or create one
257
+ </div>`
258
+ : nothing}
254
259
  <div data-testid="tag-option-list" class="${selectOptionsContainerStyle}">
255
260
  ${repeat(this.tagManager.filteredOptions$.value, select => select.id, (select, index) => {
256
261
  const isSelected = index === this.selectedIndex$.value;
@@ -267,7 +272,7 @@ let MultiTagSelect = (() => {
267
272
  };
268
273
  return html `
269
274
  <div
270
- ${!select.isCreate ? sortable(select.id) : nothing}
275
+ ${editable && !select.isCreate ? sortable(select.id) : nothing}
271
276
  class="${classes}"
272
277
  @mouseenter="${mouseenter}"
273
278
  @click="${select.select}"
@@ -277,15 +282,17 @@ let MultiTagSelect = (() => {
277
282
  ? html ` <div class="${selectOptionNewIconStyle}">
278
283
  Create
279
284
  </div>`
280
- : html `
281
- <div
282
- ${dragHandler(select.id)}
283
- class="${selectOptionDragHandlerStyle}"
284
- ></div>
285
- `}
285
+ : editable
286
+ ? html `
287
+ <div
288
+ ${dragHandler(select.id)}
289
+ class="${selectOptionDragHandlerStyle}"
290
+ ></div>
291
+ `
292
+ : nothing}
286
293
  ${this.renderTag(select.value, select.color)}
287
294
  </div>
288
- ${!select.isCreate
295
+ ${editable && !select.isCreate
289
296
  ? html ` <div
290
297
  class="${selectOptionIconStyle}"
291
298
  @click="${clickOption}"
@@ -445,7 +452,7 @@ let MultiTagSelect = (() => {
445
452
  onDragEnd: evt => {
446
453
  const over = evt.over;
447
454
  const activeId = evt.active.id;
448
- if (over && over.id !== activeId) {
455
+ if (over && over.id !== activeId && this.onOptionsChange) {
449
456
  this.onOptionsChange(arrayMove(this.options.value, this.options.value.findIndex(v => v.id === activeId), this.options.value.findIndex(v => v.id === over.id)));
450
457
  this.requestUpdate();
451
458
  // const properties = this.filteredOptions$.value.map(v=>v.id);
@@ -470,7 +477,7 @@ let MultiTagSelect = (() => {
470
477
  this.#mode_accessor_storage = __runInitializers(this, _mode_initializers, 'multi');
471
478
  this.#onChange_accessor_storage = (__runInitializers(this, _mode_extraInitializers), __runInitializers(this, _onChange_initializers, void 0));
472
479
  this.#onComplete_accessor_storage = (__runInitializers(this, _onChange_extraInitializers), __runInitializers(this, _onComplete_initializers, void 0));
473
- this.#onOptionsChange_accessor_storage = (__runInitializers(this, _onComplete_extraInitializers), __runInitializers(this, _onOptionsChange_initializers, void 0));
480
+ this.#onOptionsChange_accessor_storage = (__runInitializers(this, _onComplete_extraInitializers), __runInitializers(this, _onOptionsChange_initializers, undefined));
474
481
  this.#options_accessor_storage = (__runInitializers(this, _onOptionsChange_extraInitializers), __runInitializers(this, _options_initializers, void 0));
475
482
  this.selectedIndex$ = (__runInitializers(this, _options_extraInitializers), signal(0));
476
483
  this.#value_accessor_storage = __runInitializers(this, _value_initializers, void 0);
@@ -13,6 +13,7 @@ import { SelectGroupView } from './group-by/renderer/select-group.js';
13
13
  import { StringGroupView } from './group-by/renderer/string-group.js';
14
14
  import { GroupSetting } from './group-by/setting.js';
15
15
  import { AffineLitIcon, UniAnyRender, UniLit } from './index.js';
16
+ import { StandaloneCellHost } from './property/standalone-cell.js';
16
17
  import { AnyRender } from './utils/uni-component/render-template.js';
17
18
  export function coreEffects() {
18
19
  customElements.define('affine-data-view-renderer', DataViewRootUI);
@@ -34,4 +35,5 @@ export function coreEffects() {
34
35
  customElements.define('uni-any-render', UniAnyRender);
35
36
  customElements.define('variable-ref-view', VariableRefView);
36
37
  customElements.define('affine-data-view-record-detail', RecordDetail);
38
+ customElements.define('dv-standalone-cell', StandaloneCellHost);
37
39
  }
@@ -3,4 +3,5 @@ export * from './convert.js';
3
3
  export * from './manager.js';
4
4
  export * from './property-config.js';
5
5
  export * from './renderer.js';
6
+ export * from './standalone-cell.js';
6
7
  export * from './types.js';
@@ -3,4 +3,5 @@ export * from './convert.js';
3
3
  export * from './manager.js';
4
4
  export * from './property-config.js';
5
5
  export * from './renderer.js';
6
+ export * from './standalone-cell.js';
6
7
  export * from './types.js';
@@ -0,0 +1,95 @@
1
+ import { type GeneralServiceIdentifier } from '../../../global/di/index.js';
2
+ import { ShadowlessElement } from '../../../std/index.js';
3
+ import type { ExtensionType } from '../../../store/index.js';
4
+ import { type ReadonlySignal } from '@preact/signals-core';
5
+ import { nothing } from 'lit';
6
+ import type { DatabaseFlags } from '../types.js';
7
+ import type { Cell } from '../view-manager/cell.js';
8
+ import type { PropertyMetaConfig } from './property-config.js';
9
+ /**
10
+ * A cell outside any view: one property's value drawn and edited by the very
11
+ * cell renderer a table cell mounts (checkbox, select, multi-select, date,
12
+ * number, text, a link…), for a host that has a value and no table, such as
13
+ * the title band under a page title (ADR 0035 §11).
14
+ *
15
+ * A cell renderer is written against a `Cell` bound to a `SingleView` and a
16
+ * data source. Outside a view there are neither, and building a data source
17
+ * for one value would be a second store. What the presets actually read is
18
+ * small, and this seam provides exactly that and nothing more:
19
+ * - of the property: `name$`, `data$`, `type$`, `readonly$`, `dataUpdate`,
20
+ * `renderer$`, `meta$`, and `dataCanSet`;
21
+ * - of the view: `featureFlags$` (the number format), `serviceGet` (the link
22
+ * cell's editor host) and `readonly$`;
23
+ * - of the cell: `value$` and `valueSet`, with the JSON value the raw one,
24
+ * which holds for every preset a standalone cell is drawn for.
25
+ * The rest of `SingleView` and `Row` is absent: a renderer that starts
26
+ * reading it fails `standalone-cell.unit.spec.ts`, which mounts every preset
27
+ * through this seam, rather than a host at run time.
28
+ */
29
+ export interface StandaloneCellSource<RawValue = unknown, Data extends Record<string, unknown> = Record<string, unknown>> {
30
+ readonly propertyId: string;
31
+ readonly name$: ReadonlySignal<string>;
32
+ readonly data$: ReadonlySignal<Data>;
33
+ readonly value$: ReadonlySignal<RawValue | undefined>;
34
+ readonly readonly$: ReadonlySignal<boolean>;
35
+ /** A value the cell's editor commits; the host decides when it shows. */
36
+ valueSet(value: RawValue | undefined): void;
37
+ /**
38
+ * Writes the property's config (a select's options). Absent, the config is
39
+ * not the host's to write here: a select offers its options and creates,
40
+ * renames, recolours, reorders or deletes none.
41
+ */
42
+ dataSet?(data: Data): void;
43
+ /** The view's flags (`enable_number_formatting`); absent, all off. */
44
+ readonly featureFlags$?: ReadonlySignal<DatabaseFlags>;
45
+ /** What `view.serviceGet` answers; absent, nothing. */
46
+ serviceGet?<T>(key: GeneralServiceIdentifier<T>): T | null;
47
+ }
48
+ /** A `Cell` for one value outside any view, drawn with `meta`'s renderer. */
49
+ export declare function createStandaloneCell<RawValue = unknown, Data extends Record<string, unknown> = Record<string, unknown>>(meta: PropertyMetaConfig, source: StandaloneCellSource<RawValue, Data>): Cell<RawValue, RawValue, Data>;
50
+ /**
51
+ * A property type a standalone cell can be drawn with, registered by the
52
+ * package that owns its renderer when that package sits above the host: the
53
+ * database block registers its `link` cell, which the title band (a fragment
54
+ * the database block depends on) cannot import. The presets of this package
55
+ * need no registration; a host imports them.
56
+ */
57
+ export declare const StandaloneCellMetaProvider: import("../../../global/di/types.js").ServiceIdentifier<PropertyMetaConfig> & (<U extends PropertyMetaConfig = PropertyMetaConfig>(variant: import("../../../global/di/types.js").ServiceVariant) => import("../../../global/di/types.js").ServiceIdentifier<U>);
58
+ export declare function StandaloneCellMetaExtension<Type extends string, Data extends NonNullable<unknown>, RawValue, JsonValue>(meta: PropertyMetaConfig<Type, Data, RawValue, JsonValue>): ExtensionType;
59
+ declare const StandaloneCellHost_base: typeof ShadowlessElement & import("../../../global/utils/types.js").Constructor<import("../../../global/lit/with-disposable.js").DisposableClass>;
60
+ /**
61
+ * The element that hosts a standalone cell: it mounts the cell renderer the
62
+ * way a table cell container does and owns the same edit lifecycle
63
+ * (`beforeEnterEditMode`, `afterEnterEditingMode`, `beforeExitEditingMode`),
64
+ * so a click, Enter or Space starts the renderer's own editor: the checkbox
65
+ * toggles, a select pops its tag menu, the date its picker, a text its input.
66
+ *
67
+ * Leaving: a popup editor (select, date) closes itself on a click away and
68
+ * calls `selectCurrentCell(false)`, as in the table; an editor drawn in place
69
+ * (an input inside this element) leaves when the focus does, Escape included.
70
+ * Either way the renderer's exit hook commits, exactly once.
71
+ */
72
+ export declare class StandaloneCellHost extends StandaloneCellHost_base {
73
+ static styles: import("lit").CSSResult;
74
+ private readonly _cell$;
75
+ private _exiting;
76
+ readonly isEditing$: import("@preact/signals-core").Signal<boolean>;
77
+ /** Opens the renderer's editor; a checkbox toggles instead. */
78
+ edit(): void;
79
+ /** Closes the editor; the renderer's exit hook commits its value. */
80
+ exit(): void;
81
+ private readonly _selectCurrentCell;
82
+ connectedCallback(): void;
83
+ render(): import("lit-html").TemplateResult<1> | typeof nothing;
84
+ accessor cell: Cell;
85
+ /** Drawn while the value is empty and no editor is open. */
86
+ accessor placeholder: string;
87
+ /** Draws the value and opens no editor. */
88
+ accessor readonly: boolean;
89
+ }
90
+ declare global {
91
+ interface HTMLElementTagNameMap {
92
+ 'dv-standalone-cell': StandaloneCellHost;
93
+ }
94
+ }
95
+ export {};