@formicoidea/labre-core 0.58.0 → 0.59.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 (167) hide show
  1. package/architecture/code.c4 +94 -65
  2. package/architecture/domain.c4 +11 -5
  3. package/dist/_pkgs/affine-block-attachment/edgeless-clipboard-config.d.ts +3 -2
  4. package/dist/_pkgs/affine-block-attachment/edgeless-clipboard-config.js +18 -13
  5. package/dist/_pkgs/affine-block-callout/adapters/markdown.js +4 -1
  6. package/dist/_pkgs/affine-block-code/adapters/html.js +1 -1
  7. package/dist/_pkgs/affine-block-code/adapters/markdown/preprocessor.js +13 -1
  8. package/dist/_pkgs/affine-block-code/adapters/notion-html.js +1 -1
  9. package/dist/_pkgs/affine-block-code/code-block.d.ts +17 -2
  10. package/dist/_pkgs/affine-block-code/code-block.js +28 -23
  11. package/dist/_pkgs/affine-block-code/code-toolbar/components/lang-button.js +17 -4
  12. package/dist/_pkgs/affine-block-code/code-toolbar/components/preview-button.js +1 -1
  13. package/dist/_pkgs/affine-block-data-view/data-source.js +12 -5
  14. package/dist/_pkgs/affine-block-edgeless-text/edgeless-clipboard-config.d.ts +3 -2
  15. package/dist/_pkgs/affine-block-edgeless-text/edgeless-clipboard-config.js +8 -5
  16. package/dist/_pkgs/affine-block-image/asset-picker.d.ts +23 -2
  17. package/dist/_pkgs/affine-block-image/asset-picker.js +52 -12
  18. package/dist/_pkgs/affine-block-image/configs/replace-action.d.ts +8 -5
  19. package/dist/_pkgs/affine-block-image/configs/replace-action.js +8 -8
  20. package/dist/_pkgs/affine-block-image/configs/toolbar.js +2 -1
  21. package/dist/_pkgs/affine-block-image/crop/crop-controller.d.ts +15 -0
  22. package/dist/_pkgs/affine-block-image/crop/crop-controller.js +40 -2
  23. package/dist/_pkgs/affine-block-image/crop/crop-math.d.ts +22 -0
  24. package/dist/_pkgs/affine-block-image/crop/crop-math.js +55 -2
  25. package/dist/_pkgs/affine-block-image/crop/crop-overlay.d.ts +17 -3
  26. package/dist/_pkgs/affine-block-image/crop/crop-overlay.js +64 -6
  27. package/dist/_pkgs/affine-block-image/edgeless-clipboard-config.d.ts +3 -2
  28. package/dist/_pkgs/affine-block-image/edgeless-clipboard-config.js +20 -14
  29. package/dist/_pkgs/affine-block-image/image-block.js +1 -0
  30. package/dist/_pkgs/affine-block-image/image-edgeless-block.js +3 -0
  31. package/dist/_pkgs/affine-block-image/index.d.ts +2 -0
  32. package/dist/_pkgs/affine-block-image/index.js +2 -0
  33. package/dist/_pkgs/affine-block-image/replace/commands.d.ts +68 -0
  34. package/dist/_pkgs/affine-block-image/replace/commands.js +200 -0
  35. package/dist/_pkgs/affine-block-image/replace/replace-model.d.ts +44 -0
  36. package/dist/_pkgs/affine-block-image/replace/replace-model.js +168 -0
  37. package/dist/_pkgs/affine-block-image/replace/toolbar.d.ts +21 -0
  38. package/dist/_pkgs/affine-block-image/replace/toolbar.js +159 -0
  39. package/dist/_pkgs/affine-block-image/translations.d.ts +15 -2
  40. package/dist/_pkgs/affine-block-image/translations.js +35 -2
  41. package/dist/_pkgs/affine-block-image/utils.d.ts +7 -0
  42. package/dist/_pkgs/affine-block-image/utils.js +13 -0
  43. package/dist/_pkgs/affine-block-image/view.js +7 -0
  44. package/dist/_pkgs/affine-block-note/components/edgeless-page-block-title.d.ts +14 -5
  45. package/dist/_pkgs/affine-block-note/components/edgeless-page-block-title.js +18 -11
  46. package/dist/_pkgs/affine-block-note/config.d.ts +9 -2
  47. package/dist/_pkgs/affine-block-note/edgeless-clipboard-config.d.ts +3 -2
  48. package/dist/_pkgs/affine-block-note/edgeless-clipboard-config.js +8 -5
  49. package/dist/_pkgs/affine-block-paragraph/adapters/markdown.js +11 -0
  50. package/dist/_pkgs/affine-block-root/commands/invisible-characters-commands.d.ts +17 -0
  51. package/dist/_pkgs/affine-block-root/commands/invisible-characters-commands.js +123 -0
  52. package/dist/_pkgs/affine-block-root/edgeless/clipboard/command.js +82 -65
  53. package/dist/_pkgs/affine-block-root/edgeless/edgeless-keyboard.js +2 -0
  54. package/dist/_pkgs/affine-block-root/index.d.ts +1 -0
  55. package/dist/_pkgs/affine-block-root/index.js +1 -0
  56. package/dist/_pkgs/affine-block-root/translations.d.ts +6 -0
  57. package/dist/_pkgs/affine-block-root/translations.js +10 -0
  58. package/dist/_pkgs/affine-block-root/view.js +6 -1
  59. package/dist/_pkgs/affine-block-surface/commands/index.d.ts +1 -1
  60. package/dist/_pkgs/affine-block-surface/commands/index.js +1 -1
  61. package/dist/_pkgs/affine-block-surface/commands/reassociate-connectors.d.ts +9 -0
  62. package/dist/_pkgs/affine-block-surface/commands/reassociate-connectors.js +21 -12
  63. package/dist/_pkgs/affine-block-surface/extensions/clipboard-config.d.ts +33 -0
  64. package/dist/_pkgs/affine-block-surface/extensions/clipboard-config.js +53 -0
  65. package/dist/_pkgs/affine-block-surface/framework-background/background-view.js +2 -1
  66. package/dist/_pkgs/affine-block-surface/framework-background/band-widths.d.ts +104 -0
  67. package/dist/_pkgs/affine-block-surface/framework-background/band-widths.js +156 -0
  68. package/dist/_pkgs/affine-block-surface/framework-background/def.d.ts +87 -4
  69. package/dist/_pkgs/affine-block-surface/framework-background/def.js +26 -7
  70. package/dist/_pkgs/affine-block-surface/framework-background/ellipsis.d.ts +58 -0
  71. package/dist/_pkgs/affine-block-surface/framework-background/ellipsis.js +110 -0
  72. package/dist/_pkgs/affine-block-surface/framework-background/index.d.ts +3 -0
  73. package/dist/_pkgs/affine-block-surface/framework-background/index.js +3 -0
  74. package/dist/_pkgs/affine-block-surface/framework-background/labels.d.ts +12 -2
  75. package/dist/_pkgs/affine-block-surface/framework-background/labels.js +29 -5
  76. package/dist/_pkgs/affine-block-surface/framework-background/measure-text.d.ts +14 -0
  77. package/dist/_pkgs/affine-block-surface/framework-background/measure-text.js +31 -0
  78. package/dist/_pkgs/affine-block-surface/framework-background/renderer.d.ts +14 -1
  79. package/dist/_pkgs/affine-block-surface/framework-background/renderer.js +84 -31
  80. package/dist/_pkgs/affine-block-table/adapters/html.js +26 -14
  81. package/dist/_pkgs/affine-block-table/adapters/utils.d.ts +1 -0
  82. package/dist/_pkgs/affine-block-table/adapters/utils.js +23 -5
  83. package/dist/_pkgs/affine-block-table/header-menu.d.ts +13 -0
  84. package/dist/_pkgs/affine-block-table/header-menu.js +25 -0
  85. package/dist/_pkgs/affine-block-table/selection-controller.d.ts +15 -0
  86. package/dist/_pkgs/affine-block-table/selection-controller.js +62 -0
  87. package/dist/_pkgs/affine-block-table/table-cell-css.d.ts +7 -0
  88. package/dist/_pkgs/affine-block-table/table-cell-css.js +10 -0
  89. package/dist/_pkgs/affine-block-table/table-cell.d.ts +8 -0
  90. package/dist/_pkgs/affine-block-table/table-cell.js +35 -3
  91. package/dist/_pkgs/affine-block-table/table-data-manager.d.ts +14 -0
  92. package/dist/_pkgs/affine-block-table/table-data-manager.js +44 -3
  93. package/dist/_pkgs/affine-block-table/translations.d.ts +14 -0
  94. package/dist/_pkgs/affine-block-table/translations.js +22 -0
  95. package/dist/_pkgs/affine-gfx-mindmap/toolbar/mindmap-tool-button.d.ts +2 -2
  96. package/dist/_pkgs/affine-gfx-template/builtin/other.d.ts +4 -0
  97. package/dist/_pkgs/affine-gfx-template/builtin/other.js +1 -1
  98. package/dist/_pkgs/affine-gfx-template/builtin/slides/build.d.ts +81 -0
  99. package/dist/_pkgs/affine-gfx-template/builtin/slides/build.js +276 -0
  100. package/dist/_pkgs/affine-gfx-template/builtin/slides/consts.d.ts +126 -0
  101. package/dist/_pkgs/affine-gfx-template/builtin/slides/consts.js +101 -0
  102. package/dist/_pkgs/affine-gfx-template/builtin/slides/index.d.ts +8 -0
  103. package/dist/_pkgs/affine-gfx-template/builtin/slides/index.js +27 -0
  104. package/dist/_pkgs/affine-gfx-template/builtin/slides/masks.d.ts +83 -0
  105. package/dist/_pkgs/affine-gfx-template/builtin/slides/masks.js +674 -0
  106. package/dist/_pkgs/affine-gfx-template/contribute.js +12 -17
  107. package/dist/_pkgs/affine-gfx-template/make-snapshot.d.ts +14 -2
  108. package/dist/_pkgs/affine-gfx-template/make-snapshot.js +6 -2
  109. package/dist/_pkgs/affine-gfx-template/services/template-middlewares.d.ts +12 -0
  110. package/dist/_pkgs/affine-gfx-template/services/template-middlewares.js +48 -0
  111. package/dist/_pkgs/affine-gfx-template/services/template.js +2 -1
  112. package/dist/_pkgs/affine-gfx-template/toolbar/builtin-templates.d.ts +15 -1
  113. package/dist/_pkgs/affine-gfx-template/toolbar/builtin-templates.js +33 -37
  114. package/dist/_pkgs/affine-gfx-template/toolbar/template-type.d.ts +6 -0
  115. package/dist/_pkgs/affine-gfx-template/translations.d.ts +94 -0
  116. package/dist/_pkgs/affine-gfx-template/translations.js +441 -2
  117. package/dist/_pkgs/affine-model/blocks/table/table-model.d.ts +4 -0
  118. package/dist/_pkgs/affine-model/blocks/table/table-model.js +4 -0
  119. package/dist/_pkgs/affine-model/elements/bpmn/node.d.ts +46 -3
  120. package/dist/_pkgs/affine-model/elements/bpmn/node.js +47 -4
  121. package/dist/_pkgs/affine-model/elements/bpmn/pool.d.ts +20 -0
  122. package/dist/_pkgs/affine-model/elements/bpmn/pool.js +33 -4
  123. package/dist/_pkgs/affine-shared/services/edit-props-store.d.ts +3 -16
  124. package/dist/_pkgs/affine-shared/services/edit-props-store.js +16 -16
  125. package/dist/_pkgs/affine-shared/services/editor-setting-service.d.ts +3 -0
  126. package/dist/_pkgs/affine-shared/services/editor-setting-service.js +4 -0
  127. package/dist/_pkgs/affine-shared/services/index.d.ts +1 -0
  128. package/dist/_pkgs/affine-shared/services/index.js +1 -0
  129. package/dist/_pkgs/affine-shared/services/invisible-characters.d.ts +33 -0
  130. package/dist/_pkgs/affine-shared/services/invisible-characters.js +63 -0
  131. package/dist/_pkgs/affine-shared/services/link-preview-service/link-preview-cache.d.ts +0 -9
  132. package/dist/_pkgs/affine-shared/services/link-preview-service/link-preview-cache.js +3 -9
  133. package/dist/_pkgs/affine-shared/services/telemetry-service/lifecycle.d.ts +26 -0
  134. package/dist/_pkgs/affine-shared/services/telemetry-service/telemetry-service.d.ts +4 -3
  135. package/dist/_pkgs/affine-shared/services/telemetry-service/types.d.ts +11 -0
  136. package/dist/_pkgs/affine-shared/utils/index.d.ts +1 -0
  137. package/dist/_pkgs/affine-shared/utils/index.js +1 -0
  138. package/dist/_pkgs/affine-shared/utils/invisible-characters.d.ts +42 -0
  139. package/dist/_pkgs/affine-shared/utils/invisible-characters.js +81 -0
  140. package/dist/_pkgs/affine-widget-edgeless-zoom-toolbar/zoom-toolbar.js +13 -2
  141. package/dist/_pkgs/data-view/view-presets/table/pc/header/column-header.js +6 -0
  142. package/dist/_pkgs/data-view/view-presets/table/pc/table-view-ui-logic.js +5 -2
  143. package/dist/_pkgs/std/clipboard/clipboard.d.ts +15 -1
  144. package/dist/_pkgs/std/clipboard/clipboard.js +18 -0
  145. package/dist/_pkgs/std/inline/components/embed-gap.js +1 -1
  146. package/dist/_pkgs/std/inline/components/v-line.js +1 -1
  147. package/dist/_pkgs/std/inline/components/v-text.d.ts +15 -2
  148. package/dist/_pkgs/std/inline/components/v-text.js +147 -15
  149. package/dist/_pkgs/std/inline/consts.d.ts +5 -0
  150. package/dist/_pkgs/std/inline/consts.js +5 -0
  151. package/dist/_pkgs/std/inline/utils/index.d.ts +1 -0
  152. package/dist/_pkgs/std/inline/utils/index.js +1 -0
  153. package/dist/_pkgs/std/inline/utils/invisible-characters.d.ts +57 -0
  154. package/dist/_pkgs/std/inline/utils/invisible-characters.js +162 -0
  155. package/dist/_pkgs/std/inline/utils/point-conversion.js +3 -3
  156. package/dist/_pkgs/std/inline/utils/text.d.ts +8 -0
  157. package/dist/_pkgs/std/inline/utils/text.js +11 -2
  158. package/dist/_pkgs/store/model/store/crud.d.ts +28 -0
  159. package/dist/_pkgs/store/model/store/crud.js +97 -30
  160. package/dist/_pkgs/store/model/store/query.js +3 -2
  161. package/dist/_pkgs/store/model/store/store.d.ts +21 -0
  162. package/dist/_pkgs/store/model/store/store.js +88 -21
  163. package/dist/_pkgs/store/transformer/transformer.d.ts +46 -0
  164. package/dist/_pkgs/store/transformer/transformer.js +72 -0
  165. package/dist/commands.js +6 -1
  166. package/dist/translations.js +2 -0
  167. package/package.json +3 -4
@@ -42,12 +42,12 @@ export const tableBlockHtmlAdapterMatcher = {
42
42
  fromBlockSnapshot: {
43
43
  enter: (o, context) => {
44
44
  const { walkerContext } = context;
45
- const { columns, rows, cells } = o.node
45
+ const { columns, rows, cells, headerRow, headerColumn } = o.node
46
46
  .props;
47
47
  const table = processTable(columns, rows, cells);
48
- const createAstTableCell = (children) => ({
48
+ const createAstTableCell = (children, header) => ({
49
49
  type: 'element',
50
- tagName: 'td',
50
+ tagName: header ? 'th' : 'td',
51
51
  properties: Object.create(null),
52
52
  children: [
53
53
  {
@@ -67,18 +67,30 @@ export const tableBlockHtmlAdapterMatcher = {
67
67
  children: cells,
68
68
  });
69
69
  const { deltaConverter } = context;
70
- const tableBodyAst = {
70
+ // ADR 0043: the header row goes in a `thead`, header cells are `th`.
71
+ const hasHeaderRow = headerRow === true && table.rows.length > 0;
72
+ const hasHeaderColumn = headerColumn === true;
73
+ const astRows = table.rows.map((v, rowIndex) => {
74
+ return createAstTableRow(v.cells.map((cell, columnIndex) => {
75
+ return createAstTableCell(typeof cell.value === 'string'
76
+ ? [{ type: 'text', value: cell.value }]
77
+ : deltaConverter.deltaToAST(cell.value.delta), (hasHeaderRow && rowIndex === 0) ||
78
+ (hasHeaderColumn && columnIndex === 0));
79
+ }));
80
+ });
81
+ const section = (tagName, children) => ({
71
82
  type: 'element',
72
- tagName: 'tbody',
83
+ tagName,
73
84
  properties: Object.create(null),
74
- children: table.rows.map(v => {
75
- return createAstTableRow(v.cells.map(cell => {
76
- return createAstTableCell(typeof cell.value === 'string'
77
- ? [{ type: 'text', value: cell.value }]
78
- : deltaConverter.deltaToAST(cell.value.delta));
79
- }));
80
- }),
81
- };
85
+ children,
86
+ });
87
+ const tableChildren = hasHeaderRow
88
+ ? [section('thead', astRows.slice(0, 1))]
89
+ : [];
90
+ const bodyRows = hasHeaderRow ? astRows.slice(1) : astRows;
91
+ if (!hasHeaderRow || bodyRows.length > 0) {
92
+ tableChildren.push(section('tbody', bodyRows));
93
+ }
82
94
  walkerContext
83
95
  .openNode({
84
96
  type: 'element',
@@ -87,7 +99,7 @@ export const tableBlockHtmlAdapterMatcher = {
87
99
  border: true,
88
100
  style: 'border-collapse: collapse;border-spacing: 0;',
89
101
  },
90
- children: [tableBodyAst],
102
+ children: tableChildren,
91
103
  })
92
104
  .closeNode();
93
105
  walkerContext.skipAllChildren();
@@ -28,6 +28,7 @@ export declare const createTableProps: (deltasLists: RichTextType[][]) => {
28
28
  };
29
29
  export declare const parseTableFromHtml: (element: Element, astToDelta: (ast: HtmlAST) => RichTextType) => TableBlockPropsSerialized;
30
30
  export declare const parseTableFromMarkdown: (node: MarkdownTable, astToDelta: (ast: MarkdownAST) => RichTextType) => {
31
+ headerRow: true;
31
32
  columns: {
32
33
  [k: string]: TableColumn;
33
34
  };
@@ -115,11 +115,23 @@ export const createTableProps = (deltasLists) => {
115
115
  cells,
116
116
  };
117
117
  };
118
+ /**
119
+ * A row's cells in order, `td` and `th` alike: a body row may open on a `th`
120
+ * (a header column, which the HTML export writes since ADR 0043), and keeping
121
+ * only `td` dropped that cell.
122
+ */
123
+ const rowCells = (tr) => tr.children.filter((child) => HastUtils.isElement(child) &&
124
+ (child.tagName === 'td' || child.tagName === 'th'));
118
125
  export const parseTableFromHtml = (element, astToDelta) => {
119
- const headerRows = getAllTag(element, 'thead').flatMap(node => getAllTag(node, 'tr').map(tr => getAllTag(tr, 'th')));
120
- const bodyRows = getAllTag(element, 'tbody').flatMap(node => getAllTag(node, 'tr').map(tr => getAllTag(tr, 'td')));
121
- const footerRows = getAllTag(element, 'tfoot').flatMap(node => getAllTag(node, 'tr').map(tr => getAllTag(tr, 'td')));
126
+ const heads = getAllTag(element, 'thead');
127
+ const headerRows = heads.flatMap(node => getAllTag(node, 'tr').map(rowCells));
128
+ const bodyRows = getAllTag(element, 'tbody').flatMap(node => getAllTag(node, 'tr').map(rowCells));
129
+ const footerRows = getAllTag(element, 'tfoot').flatMap(node => getAllTag(node, 'tr').map(rowCells));
122
130
  const allRows = [...headerRows, ...bodyRows, ...footerRows];
131
+ // ADR 0043: a `thead` is a header row; a body whose every row opens on a
132
+ // `th` is a header column. `true` or absent, never `false`.
133
+ const headerRow = heads.length > 0;
134
+ const headerColumn = bodyRows.length > 0 && bodyRows.every(cells => cells[0]?.tagName === 'th');
123
135
  const rowTextLists = [];
124
136
  allRows.forEach(cells => {
125
137
  const row = [];
@@ -128,7 +140,11 @@ export const parseTableFromHtml = (element, astToDelta) => {
128
140
  });
129
141
  rowTextLists.push(row);
130
142
  });
131
- return createTableProps(rowTextLists);
143
+ return {
144
+ ...createTableProps(rowTextLists),
145
+ ...(headerRow ? { headerRow: true } : {}),
146
+ ...(headerColumn ? { headerColumn: true } : {}),
147
+ };
132
148
  };
133
149
  /**
134
150
  * A cell holds rich text, and no inline matcher turns an `image` into a delta:
@@ -162,5 +178,7 @@ export const parseTableFromMarkdown = (node, astToDelta) => {
162
178
  });
163
179
  rowTextLists.push(rowText);
164
180
  });
165
- return createTableProps(rowTextLists);
181
+ // GFM has no table without a header row: the first row always was one
182
+ // (ADR 0043).
183
+ return { ...createTableProps(rowTextLists), headerRow: true };
166
184
  };
@@ -0,0 +1,13 @@
1
+ import type { BlockStdScope } from '../std/index.js';
2
+ /**
3
+ * The "Header row" / "Header column" item of the first row's / first
4
+ * column's menu (ADR 0043): a plain action with the menu's check mark, the
5
+ * toggle-switch row of `menu.toggleSwitch` hands its click the value it was
6
+ * built with.
7
+ *
8
+ * Kept out of `table-cell.ts` on purpose: the literal guard treats every
9
+ * literal of a file that calls `translateKey` as covered when it equals some
10
+ * fallback, and the cell menus' older labels ("Copy", "Delete"…) are still
11
+ * untranslated literals its baseline must keep seeing.
12
+ */
13
+ export declare function headerToggleMenuItem(std: BlockStdScope | undefined, kind: 'row' | 'column', on: boolean, toggle: (on: boolean) => void): (menu: import("../affine-components/context-menu/menu.js").Menu) => import("lit-html").TemplateResult<1> | undefined;
@@ -0,0 +1,25 @@
1
+ import { menu } from '../affine-components/context-menu/index.js';
2
+ import { translateKey } from '../affine-shared/services/index.js';
3
+ import { HeaderColumnIcon, HeaderRowIcon } from '@blocksuite/icons/lit';
4
+ import { TABLE_HEADER_COLUMN, TABLE_HEADER_ROW } from './translations.js';
5
+ /**
6
+ * The "Header row" / "Header column" item of the first row's / first
7
+ * column's menu (ADR 0043): a plain action with the menu's check mark, the
8
+ * toggle-switch row of `menu.toggleSwitch` hands its click the value it was
9
+ * built with.
10
+ *
11
+ * Kept out of `table-cell.ts` on purpose: the literal guard treats every
12
+ * literal of a file that calls `translateKey` as covered when it equals some
13
+ * fallback, and the cell menus' older labels ("Copy", "Delete"…) are still
14
+ * untranslated literals its baseline must keep seeing.
15
+ */
16
+ export function headerToggleMenuItem(std, kind, on, toggle) {
17
+ const wording = kind === 'row' ? TABLE_HEADER_ROW : TABLE_HEADER_COLUMN;
18
+ return menu.action({
19
+ name: std ? translateKey(std, ...wording) : wording[1],
20
+ prefix: kind === 'row' ? HeaderRowIcon() : HeaderColumnIcon(),
21
+ isSelected: on,
22
+ testId: `table-header-${kind}-toggle`,
23
+ select: () => toggle(!on),
24
+ });
25
+ }
@@ -2,6 +2,13 @@ import type { UIEventStateContext } from '../std/index.js';
2
2
  import type { ReactiveController } from 'lit';
3
3
  import { type TableAreaSelection, TableSelectionData } from './selection-schema.js';
4
4
  import type { TableBlockComponent } from './table-block.js';
5
+ /**
6
+ * The width that makes a column end where the table's scroll box ends: what
7
+ * the box offers minus what the other columns already take, never below
8
+ * `ColumnMinWidth`. `undefined` when nothing is left to give, so the caller
9
+ * writes nothing.
10
+ */
11
+ export declare function remainingColumnWidth(available: number, otherColumnsWidth: number): number | undefined;
5
12
  export declare class SelectionController implements ReactiveController {
6
13
  readonly host: TableBlockComponent;
7
14
  constructor(host: TableBlockComponent);
@@ -16,6 +23,14 @@ export declare class SelectionController implements ReactiveController {
16
23
  private get clipboard();
17
24
  private get scale();
18
25
  widthAdjust(dragHandle: HTMLElement, event: MouseEvent): void;
26
+ /**
27
+ * Double-click on a column's resize handle: the column takes the room left
28
+ * between the table and the right edge of its scroll box. Measured in the
29
+ * table's own unscaled pixels (`clientWidth` ignores the edgeless zoom, the
30
+ * cells' rects do not, hence `getScale()`); the container's own padding and
31
+ * the virtual padding around the table are not room a column can take.
32
+ */
33
+ fitColumnToRemainingSpace(columnId: string): void;
19
34
  dragListener(): void;
20
35
  startColumnDrag(x: number, columnDragHandle: HTMLElement): {
21
36
  onMove: (x: number) => void;
@@ -3,9 +3,23 @@ import { IS_MOBILE } from '../global/env/index.js';
3
3
  import { computed } from '@preact/signals-core';
4
4
  import { ColumnMinWidth, DefaultColumnWidth } from './consts.js';
5
5
  import { TableSelection, TableSelectionData, } from './selection-schema.js';
6
+ import { tableContainer } from './table-block-css.js';
6
7
  import { createColumnDragPreview, createRowDragPreview, TableCellComponentName, } from './table-cell.js';
7
8
  import { cleanSelection, isTableDragHandle } from './utils.js';
8
9
  const TEXT = 'text/plain';
10
+ /**
11
+ * The width that makes a column end where the table's scroll box ends: what
12
+ * the box offers minus what the other columns already take, never below
13
+ * `ColumnMinWidth`. `undefined` when nothing is left to give, so the caller
14
+ * writes nothing.
15
+ */
16
+ export function remainingColumnWidth(available, otherColumnsWidth) {
17
+ const remainder = Math.floor(available - otherColumnsWidth);
18
+ if (!Number.isFinite(remainder) || remainder <= 0)
19
+ return;
20
+ return Math.max(ColumnMinWidth, remainder);
21
+ }
22
+ const px = (value) => parseFloat(value) || 0;
9
23
  export class SelectionController {
10
24
  constructor(host) {
11
25
  this.host = host;
@@ -221,10 +235,58 @@ export class SelectionController {
221
235
  window.addEventListener('mousemove', onMove);
222
236
  window.addEventListener('mouseup', onUp);
223
237
  }
238
+ /**
239
+ * Double-click on a column's resize handle: the column takes the room left
240
+ * between the table and the right edge of its scroll box. Measured in the
241
+ * table's own unscaled pixels (`clientWidth` ignores the edgeless zoom, the
242
+ * cells' rects do not, hence `getScale()`); the container's own padding and
243
+ * the virtual padding around the table are not room a column can take.
244
+ */
245
+ fitColumnToRemainingSpace(columnId) {
246
+ if (this.dataManager.readonly$.peek())
247
+ return;
248
+ const container = this.host.querySelector(`.${tableContainer}`);
249
+ const firstRow = this.host.querySelector('tr');
250
+ if (!container || !firstRow)
251
+ return;
252
+ const containerStyle = getComputedStyle(container);
253
+ const inner = container.firstElementChild;
254
+ const innerStyle = inner instanceof HTMLElement ? getComputedStyle(inner) : undefined;
255
+ const available = container.clientWidth -
256
+ px(containerStyle.paddingLeft) -
257
+ px(containerStyle.paddingRight) -
258
+ px(innerStyle?.paddingLeft ?? '') -
259
+ px(innerStyle?.paddingRight ?? '');
260
+ const scale = this.scale;
261
+ let others = 0;
262
+ firstRow
263
+ .querySelectorAll('td[data-column-id]')
264
+ .forEach(cell => {
265
+ if (cell.dataset['columnId'] === columnId)
266
+ return;
267
+ others += cell.getBoundingClientRect().width / scale;
268
+ });
269
+ const width = remainingColumnWidth(available, others);
270
+ if (width === undefined)
271
+ return;
272
+ this.dataManager.setColumnWidth(columnId, width);
273
+ }
224
274
  dragListener() {
225
275
  if (IS_MOBILE || this.dataManager.readonly$.value) {
226
276
  return;
227
277
  }
278
+ this.host.disposables.addFromEvent(this.host, 'dblclick', event => {
279
+ const target = event.target;
280
+ if (!(target instanceof HTMLElement))
281
+ return;
282
+ const handle = target.closest('[data-width-adjust-column-id]');
283
+ const columnId = handle?.dataset['widthAdjustColumnId'];
284
+ if (!columnId)
285
+ return;
286
+ event.preventDefault();
287
+ event.stopPropagation();
288
+ this.fitColumnToRemainingSpace(columnId);
289
+ });
228
290
  // Keep the pointer sequence inside the table too: in edgeless the canvas
229
291
  // listens for `pointerdown` and would start dragging the block.
230
292
  this.host.disposables.addFromEvent(this.host, 'pointerdown', event => {
@@ -1,4 +1,11 @@
1
1
  export declare const cellContainerStyle: string;
2
+ /**
3
+ * A header cell (ADR 0043). Only a class, so an explicit row or column
4
+ * background — written inline by `tdStyle` — still wins over the tint. Not
5
+ * `table.headerBackground.default`: that token is the page colour in both
6
+ * themes, so the tint would not show.
7
+ */
8
+ export declare const headerCellStyle: string;
2
9
  export declare const columnOptionsCellStyle: string;
3
10
  export declare const columnOptionsStyle: string;
4
11
  export declare const rowOptionsCellStyle: string;
@@ -10,6 +10,16 @@ export const cellContainerStyle = css({
10
10
  textAlign: 'start',
11
11
  verticalAlign: 'top',
12
12
  });
13
+ /**
14
+ * A header cell (ADR 0043). Only a class, so an explicit row or column
15
+ * background — written inline by `tdStyle` — still wins over the tint. Not
16
+ * `table.headerBackground.default`: that token is the page colour in both
17
+ * themes, so the tint would not show.
18
+ */
19
+ export const headerCellStyle = css({
20
+ fontWeight: 600,
21
+ backgroundColor: cssVarV2.layer.background.secondary,
22
+ });
13
23
  export const columnOptionsCellStyle = css({
14
24
  position: 'absolute',
15
25
  height: '0',
@@ -23,6 +23,13 @@ export declare class TableCell extends TableCell_base {
23
23
  get hoverRowIndex$(): import("@preact/signals-core").Signal<number | undefined>;
24
24
  get inlineManager(): import("../std/inline/index.js").InlineManager<import("../affine-shared/types/index.js").AffineTextAttributes> | undefined;
25
25
  get topContenteditableElement(): import("../std/index.js").BlockComponent<import("../store/index.js").BlockModel<object>, import("../std/index.js").BlockService, string> | null | undefined;
26
+ /**
27
+ * The header toggle sits in the first row's / first column's menu only: the
28
+ * header is positional (ADR 0043), so no other row could be the one it
29
+ * marks.
30
+ */
31
+ private headerToggle;
32
+ private get isHeader();
26
33
  openColumnOptions(target: PopupTarget, column: TableColumn, columnIndex: number): void;
27
34
  openRowOptions(target: PopupTarget, row: TableRow, rowIndex: number): void;
28
35
  createColorPickerMenu(currentColor: string | undefined, select: (color?: string) => void): (menu: import("../affine-components/context-menu/menu.js").Menu) => import("lit-html").TemplateResult<1> | undefined;
@@ -43,6 +50,7 @@ export declare class TableCell extends TableCell_base {
43
50
  private readonly _handleKeyDown;
44
51
  connectedCallback(): void;
45
52
  firstUpdated(): void;
53
+ private tdClass;
46
54
  render(): import("lit-html").TemplateResult<1>;
47
55
  }
48
56
  export declare const createColumnDragPreview: (cells: TableCell[]) => HTMLDivElement;
@@ -46,12 +46,14 @@ import { computed, effect, signal } from '@preact/signals-core';
46
46
  import { html, nothing } from 'lit';
47
47
  import { property, query } from 'lit/decorators.js';
48
48
  import { classMap } from 'lit/directives/class-map.js';
49
+ import { ifDefined } from 'lit/directives/if-defined.js';
49
50
  import { ref } from 'lit/directives/ref.js';
50
51
  import { styleMap } from 'lit/directives/style-map.js';
51
52
  import { colorList } from './color.js';
52
53
  import { ColumnMaxWidth, DefaultColumnWidth } from './consts.js';
54
+ import { headerToggleMenuItem } from './header-menu.js';
53
55
  import { TableSelectionData, } from './selection-schema.js';
54
- import { cellContainerStyle, columnLeftIndicatorStyle, columnOptionsCellStyle, columnOptionsStyle, columnRightIndicatorStyle, rowBottomIndicatorStyle, rowOptionsCellStyle, rowOptionsStyle, rowTopIndicatorStyle, threePointerIconDotStyle, threePointerIconStyle, } from './table-cell-css.js';
56
+ import { cellContainerStyle, columnLeftIndicatorStyle, columnOptionsCellStyle, columnOptionsStyle, columnRightIndicatorStyle, headerCellStyle, rowBottomIndicatorStyle, rowOptionsCellStyle, rowOptionsStyle, rowTopIndicatorStyle, threePointerIconDotStyle, threePointerIconStyle, } from './table-cell-css.js';
55
57
  export const TableCellComponentName = 'affine-table-cell';
56
58
  let TableCell = (() => {
57
59
  let _classSuper = SignalWatcher(WithDisposable(ShadowlessElement));
@@ -196,6 +198,22 @@ let TableCell = (() => {
196
198
  return this.closest('affine-table')
197
199
  ?.topContenteditableElement;
198
200
  }
201
+ /**
202
+ * The header toggle sits in the first row's / first column's menu only: the
203
+ * header is positional (ADR 0043), so no other row could be the one it
204
+ * marks.
205
+ */
206
+ headerToggle(kind) {
207
+ const std = this.closest('affine-table')?.std;
208
+ const dataManager = this.dataManager;
209
+ return kind === 'row'
210
+ ? headerToggleMenuItem(std, kind, dataManager.headerRow$.peek(), on => dataManager.setHeaderRow(on))
211
+ : headerToggleMenuItem(std, kind, dataManager.headerColumn$.peek(), on => dataManager.setHeaderColumn(on));
212
+ }
213
+ get isHeader() {
214
+ return ((this.rowIndex === 0 && this.dataManager.headerRow$.value) ||
215
+ (this.columnIndex === 0 && this.dataManager.headerColumn$.value));
216
+ }
199
217
  openColumnOptions(target, column, columnIndex) {
200
218
  this.selectionController.setSelected({
201
219
  type: 'column',
@@ -232,6 +250,7 @@ let TableCell = (() => {
232
250
  })),
233
251
  },
234
252
  }),
253
+ ...(columnIndex === 0 ? [this.headerToggle('column')] : []),
235
254
  ...(column.backgroundColor
236
255
  ? [
237
256
  menu.action({
@@ -345,6 +364,7 @@ let TableCell = (() => {
345
364
  })),
346
365
  },
347
366
  }),
367
+ ...(rowIndex === 0 ? [this.headerToggle('row')] : []),
348
368
  ...(row.backgroundColor
349
369
  ? [
350
370
  menu.action({
@@ -706,9 +726,20 @@ let TableCell = (() => {
706
726
  })
707
727
  .catch(console.error);
708
728
  }
729
+ tdClass() {
730
+ return classMap({
731
+ [cellContainerStyle]: true,
732
+ [headerCellStyle]: this.isHeader,
733
+ });
734
+ }
709
735
  render() {
736
+ const header = this.isHeader ? '' : undefined;
710
737
  if (!this.text) {
711
- return html `<td class=${cellContainerStyle} style=${this.tdStyle()}>
738
+ return html `<td
739
+ class=${this.tdClass()}
740
+ data-header=${ifDefined(header)}
741
+ style=${this.tdStyle()}
742
+ >
712
743
  <div
713
744
  style=${styleMap({
714
745
  padding: '8px 12px',
@@ -729,7 +760,8 @@ let TableCell = (() => {
729
760
  this.tdMouseLeave();
730
761
  }}
731
762
  @contextmenu=${this.onContextMenu}
732
- class=${cellContainerStyle}
763
+ class=${this.tdClass()}
764
+ data-header=${ifDefined(header)}
733
765
  style=${this.tdStyle()}
734
766
  >
735
767
  <rich-text
@@ -20,6 +20,9 @@ export declare class TableDataManager {
20
20
  width: number;
21
21
  } | undefined>;
22
22
  readonly cellCountTips$: ReadonlySignal<string>;
23
+ /** ADR 0043: anything but a stored `true` reads as off. */
24
+ readonly headerRow$: ReadonlySignal<boolean>;
25
+ readonly headerColumn$: ReadonlySignal<boolean>;
23
26
  readonly rows$: ReadonlySignal<import("../affine-model/index.js").TableRow[]>;
24
27
  readonly columns$: ReadonlySignal<import("../affine-model/index.js").TableColumn[]>;
25
28
  readonly uiRows$: ReadonlySignal<(import("../affine-model/index.js").TableRow | {
@@ -43,7 +46,18 @@ export declare class TableDataManager {
43
46
  updateColumnOrder(columnId: string, newOrder: string): void;
44
47
  setRowBackgroundColor(rowId: string, color?: string): void;
45
48
  setColumnBackgroundColor(columnId: string, color?: string): void;
49
+ /**
50
+ * One call per gesture (a resize drag writes once, on release; a fit writes
51
+ * once), so the `captureSync` here makes each gesture its own undo step.
52
+ */
46
53
  setColumnWidth(columnId: string, width: number): void;
54
+ setHeaderRow(on: boolean): void;
55
+ setHeaderColumn(on: boolean): void;
56
+ /**
57
+ * `true` or absent, never `false` (ADR 0043): turning a header off deletes
58
+ * the key, so an off table stores exactly what a pre-0043 table stored.
59
+ */
60
+ private setHeader;
47
61
  clearRow(rowId: string): void;
48
62
  clearColumn(columnId: string): void;
49
63
  clearCellsBySelection(selection: TableAreaSelection): void;
@@ -19,6 +19,9 @@ export class TableDataManager {
19
19
  this.virtualRowCount$ = signal(0);
20
20
  this.virtualWidth$ = signal();
21
21
  this.cellCountTips$ = computed(() => `${this.virtualRowCount$.value + this.rows$.value.length} x ${this.virtualColumnCount$.value + this.columns$.value.length}`);
22
+ /** ADR 0043: anything but a stored `true` reads as off. */
23
+ this.headerRow$ = computed(() => this.model.props.headerRow$.value === true);
24
+ this.headerColumn$ = computed(() => this.model.props.headerColumn$.value === true);
22
25
  this.rows$ = computed(() => {
23
26
  return Object.values(this.model.props.rows$.value).sort((a, b) => a.order > b.order ? 1 : -1);
24
27
  });
@@ -201,10 +204,48 @@ export class TableDataManager {
201
204
  }
202
205
  });
203
206
  }
207
+ /**
208
+ * One call per gesture (a resize drag writes once, on release; a fit writes
209
+ * once), so the `captureSync` here makes each gesture its own undo step.
210
+ */
204
211
  setColumnWidth(columnId, width) {
205
- this.model.store.transact(() => {
206
- if (this.model.props.columns[columnId]) {
207
- this.model.props.columns[columnId].width = width;
212
+ const store = this.model.store;
213
+ if (store.readonly)
214
+ return;
215
+ const column = this.model.props.columns[columnId];
216
+ if (!column || column.width === width)
217
+ return;
218
+ store.captureSync();
219
+ store.transact(() => {
220
+ const target = this.model.props.columns[columnId];
221
+ if (target) {
222
+ target.width = width;
223
+ }
224
+ });
225
+ }
226
+ setHeaderRow(on) {
227
+ this.setHeader('headerRow', on);
228
+ }
229
+ setHeaderColumn(on) {
230
+ this.setHeader('headerColumn', on);
231
+ }
232
+ /**
233
+ * `true` or absent, never `false` (ADR 0043): turning a header off deletes
234
+ * the key, so an off table stores exactly what a pre-0043 table stored.
235
+ */
236
+ setHeader(key, on) {
237
+ const store = this.model.store;
238
+ if (store.readonly)
239
+ return;
240
+ if ((this.model.props[key] === true) === on)
241
+ return;
242
+ store.captureSync();
243
+ store.transact(() => {
244
+ if (on) {
245
+ this.model.props[key] = true;
246
+ }
247
+ else {
248
+ delete this.model.props[key];
208
249
  }
209
250
  });
210
251
  }
@@ -0,0 +1,14 @@
1
+ import type { ChromeWording } from '../affine-shared/services/index.js';
2
+ /**
3
+ * This package's own wordings, declared beside the code that renders them —
4
+ * the two header toggles of the row and column menus (ADR 0043). The menus'
5
+ * older labels ("Insert Left", "Delete"…) are still literals held by
6
+ * `literals.baseline.json`; they move here in their own pass.
7
+ */
8
+ export declare const TABLE_HEADER_ROW: ChromeWording;
9
+ export declare const TABLE_HEADER_COLUMN: ChromeWording;
10
+ /**
11
+ * Every wording declared above, in declaration order — walked by
12
+ * `PACKAGE_WORDINGS` in `packages/affine/all/src/translations.ts`.
13
+ */
14
+ export declare const TABLE_WORDINGS: readonly ChromeWording[];
@@ -0,0 +1,22 @@
1
+ /**
2
+ * This package's own wordings, declared beside the code that renders them —
3
+ * the two header toggles of the row and column menus (ADR 0043). The menus'
4
+ * older labels ("Insert Left", "Delete"…) are still literals held by
5
+ * `literals.baseline.json`; they move here in their own pass.
6
+ */
7
+ export const TABLE_HEADER_ROW = [
8
+ 'com.labre.table.header-row',
9
+ 'Header row',
10
+ ];
11
+ export const TABLE_HEADER_COLUMN = [
12
+ 'com.labre.table.header-column',
13
+ 'Header column',
14
+ ];
15
+ /**
16
+ * Every wording declared above, in declaration order — walked by
17
+ * `PACKAGE_WORDINGS` in `packages/affine/all/src/translations.ts`.
18
+ */
19
+ export const TABLE_WORDINGS = [
20
+ TABLE_HEADER_ROW,
21
+ TABLE_HEADER_COLUMN,
22
+ ];
@@ -1,4 +1,4 @@
1
- import { EmptyTool } from '../../affine-gfx-pointer/index.js';
1
+ import { TextTool } from '../../affine-gfx-text/index.js';
2
2
  import { EdgelessDraggableElementController } from '../../affine-widget-edgeless-toolbar/index.js';
3
3
  import { LitElement } from 'lit';
4
4
  import { type DraggableTool } from './basket-elements.js';
@@ -8,7 +8,7 @@ export declare class EdgelessMindmapToolButton extends EdgelessMindmapToolButton
8
8
  private readonly _style$;
9
9
  draggableController: EdgelessDraggableElementController<DraggableTool>;
10
10
  enableActiveBackground: boolean;
11
- type: (typeof EmptyTool)[];
11
+ type: (typeof TextTool)[];
12
12
  get draggableTools(): DraggableTool[];
13
13
  get mindmaps(): import("./assets.js").ToolbarMindmapItem[];
14
14
  get crud(): import("../../affine-block-surface/index.js").EdgelessCRUDExtension;
@@ -1,2 +1,6 @@
1
+ import { type ChromeWording, type TranslationParams } from '../../affine-shared/services/index.js';
2
+ import type { BlockStdScope } from '../../std/index.js';
1
3
  import type { TemplateCategory } from '../toolbar/template-type.js';
4
+ /** Resolve a wording through the host, or its English fallback with no host. */
5
+ export declare function tr(std: BlockStdScope | undefined, wording: ChromeWording, params?: TranslationParams): string;
2
6
  export declare const otherTemplateCategory: TemplateCategory;
@@ -66,7 +66,7 @@ function line(x1, y1, x2, y2, opts = {}) {
66
66
  };
67
67
  }
68
68
  /** Resolve a wording through the host, or its English fallback with no host. */
69
- function tr(std, wording, params) {
69
+ export function tr(std, wording, params) {
70
70
  return std
71
71
  ? translateKey(std, ...wording, params)
72
72
  : fillPlaceholders(wording[1], params);