@formicoidea/labre-core 0.53.0 → 0.55.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 (104) hide show
  1. package/dist/_pkgs/affine-block-data-view/data-view-block.js +1 -1
  2. package/dist/_pkgs/affine-block-database/components/title/index.js +7 -2
  3. package/dist/_pkgs/affine-block-database/database-block-styles.js +9 -1
  4. package/dist/_pkgs/affine-block-embed-doc/page-drop/page-drop.d.ts +70 -0
  5. package/dist/_pkgs/affine-block-embed-doc/page-drop/page-drop.js +196 -0
  6. package/dist/_pkgs/affine-block-embed-doc/view.js +3 -0
  7. package/dist/_pkgs/affine-block-frame/frame-template.d.ts +11 -0
  8. package/dist/_pkgs/affine-block-frame/frame-template.js +24 -4
  9. package/dist/_pkgs/affine-block-frame/translations.d.ts +3 -0
  10. package/dist/_pkgs/affine-block-frame/translations.js +7 -0
  11. package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.js +9 -3
  12. package/dist/_pkgs/affine-block-surface/framework-background/renderer.js +9 -5
  13. package/dist/_pkgs/affine-block-surface/index.d.ts +1 -0
  14. package/dist/_pkgs/affine-block-surface/index.js +1 -0
  15. package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.d.ts +55 -3
  16. package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.js +139 -6
  17. package/dist/_pkgs/affine-block-surface/renderer/notation-tint.d.ts +92 -0
  18. package/dist/_pkgs/affine-block-surface/renderer/notation-tint.js +113 -0
  19. package/dist/_pkgs/affine-block-surface/surface-block.js +2 -2
  20. package/dist/_pkgs/affine-components/color-picker/styles.js +1 -1
  21. package/dist/_pkgs/affine-components/context-menu/input.js +2 -1
  22. package/dist/_pkgs/affine-components/context-menu/menu-renderer.d.ts +7 -0
  23. package/dist/_pkgs/affine-components/context-menu/menu-renderer.js +53 -13
  24. package/dist/_pkgs/affine-components/drop-indicator/file-drop-manager.js +15 -0
  25. package/dist/_pkgs/affine-gfx-shape/element-renderer/shape/index.js +4 -2
  26. package/dist/_pkgs/affine-inline-link/link-node/link-popup/styles.js +1 -1
  27. package/dist/_pkgs/affine-inline-reference/reference-node/reference-popup/reference-popup.js +9 -9
  28. package/dist/_pkgs/affine-shared/consts/notation.d.ts +1 -0
  29. package/dist/_pkgs/affine-shared/consts/notation.js +29 -0
  30. package/dist/_pkgs/affine-shared/services/frame-template-service.d.ts +5 -0
  31. package/dist/_pkgs/affine-shared/services/index.d.ts +1 -0
  32. package/dist/_pkgs/affine-shared/services/index.js +1 -0
  33. package/dist/_pkgs/affine-shared/services/page-drop-service.d.ts +61 -0
  34. package/dist/_pkgs/affine-shared/services/page-drop-service.js +30 -0
  35. package/dist/_pkgs/affine-shared/styles/scrollbar-style.js +1 -1
  36. package/dist/_pkgs/affine-widget-edgeless-auto-connect/index.js +5 -5
  37. package/dist/_pkgs/affine-widget-edgeless-selected-rect/edgeless-auto-complete.js +2 -2
  38. package/dist/_pkgs/affine-widget-keyboard-toolbar/config.js +6 -6
  39. package/dist/_pkgs/affine-widget-keyboard-toolbar/styles.js +1 -1
  40. package/dist/_pkgs/affine-widget-linked-doc/config.d.ts +8 -0
  41. package/dist/_pkgs/affine-widget-linked-doc/config.js +8 -1
  42. package/dist/_pkgs/affine-widget-linked-doc/linked-doc-popover.js +40 -32
  43. package/dist/_pkgs/affine-widget-linked-doc/styles.js +1 -1
  44. package/dist/_pkgs/affine-widget-linked-doc/translations.d.ts +2 -0
  45. package/dist/_pkgs/affine-widget-linked-doc/translations.js +6 -0
  46. package/dist/_pkgs/affine-widget-thread-marks/widget.d.ts +3 -1
  47. package/dist/_pkgs/affine-widget-thread-marks/widget.js +6 -1
  48. package/dist/_pkgs/affine-widget-toolbar/utils.d.ts +2 -1
  49. package/dist/_pkgs/affine-widget-toolbar/utils.js +5 -2
  50. package/dist/_pkgs/data-view/core/common/properties.js +2 -2
  51. package/dist/_pkgs/data-view/core/common/property-menu.d.ts +3 -3
  52. package/dist/_pkgs/data-view/core/common/property-menu.js +7 -7
  53. package/dist/_pkgs/data-view/core/component/overflow/overflow.js +4 -1
  54. package/dist/_pkgs/data-view/core/group-by/renderer/base.d.ts +4 -1
  55. package/dist/_pkgs/data-view/core/group-by/renderer/base.js +17 -2
  56. package/dist/_pkgs/data-view/core/group-by/renderer/number-group.js +1 -1
  57. package/dist/_pkgs/data-view/core/group-by/renderer/select-group.d.ts +0 -3
  58. package/dist/_pkgs/data-view/core/group-by/renderer/select-group.js +63 -118
  59. package/dist/_pkgs/data-view/core/group-by/renderer/string-group.js +1 -1
  60. package/dist/_pkgs/data-view/core/group-by/setting.js +2 -2
  61. package/dist/_pkgs/data-view/core/utils/wording.d.ts +6 -2
  62. package/dist/_pkgs/data-view/core/utils/wording.js +5 -3
  63. package/dist/_pkgs/data-view/core/view/default-name.d.ts +6 -0
  64. package/dist/_pkgs/data-view/core/view/default-name.js +8 -0
  65. package/dist/_pkgs/data-view/translations.d.ts +45 -0
  66. package/dist/_pkgs/data-view/translations.js +118 -0
  67. package/dist/_pkgs/data-view/view-presets/flat/flat-view-ui.d.ts +3 -1
  68. package/dist/_pkgs/data-view/view-presets/flat/flat-view-ui.js +5 -1
  69. package/dist/_pkgs/data-view/view-presets/kanban/mobile/card.d.ts +6 -0
  70. package/dist/_pkgs/data-view/view-presets/kanban/mobile/card.js +11 -0
  71. package/dist/_pkgs/data-view/view-presets/kanban/mobile/cell.js +9 -10
  72. package/dist/_pkgs/data-view/view-presets/kanban/mobile/kanban-view-ui-logic.js +3 -0
  73. package/dist/_pkgs/data-view/view-presets/table/mobile/cell.js +7 -4
  74. package/dist/_pkgs/data-view/view-presets/table/mobile/column-header.d.ts +3 -1
  75. package/dist/_pkgs/data-view/view-presets/table/mobile/column-header.js +102 -124
  76. package/dist/_pkgs/data-view/view-presets/table/mobile/group.js +12 -7
  77. package/dist/_pkgs/data-view/view-presets/table/mobile/header.d.ts +8 -2
  78. package/dist/_pkgs/data-view/view-presets/table/mobile/header.js +64 -24
  79. package/dist/_pkgs/data-view/view-presets/table/mobile/menu.d.ts +3 -1
  80. package/dist/_pkgs/data-view/view-presets/table/mobile/menu.js +7 -3
  81. package/dist/_pkgs/data-view/view-presets/table/mobile/row.d.ts +23 -1
  82. package/dist/_pkgs/data-view/view-presets/table/mobile/row.js +138 -55
  83. package/dist/_pkgs/data-view/view-presets/table/mobile/table-view-style.d.ts +17 -0
  84. package/dist/_pkgs/data-view/view-presets/table/mobile/table-view-style.js +31 -6
  85. package/dist/_pkgs/data-view/view-presets/table/mobile/table-view-ui-logic.d.ts +5 -1
  86. package/dist/_pkgs/data-view/view-presets/table/mobile/table-view-ui-logic.js +11 -4
  87. package/dist/_pkgs/data-view/view-presets/table/pc/group.js +4 -2
  88. package/dist/_pkgs/data-view/view-presets/table/pc/row/row.js +5 -1
  89. package/dist/_pkgs/data-view/widget-presets/quick-setting-bar/filter/index.js +1 -2
  90. package/dist/_pkgs/data-view/widget-presets/quick-setting-bar/filter/list-view.d.ts +3 -1
  91. package/dist/_pkgs/data-view/widget-presets/quick-setting-bar/filter/list-view.js +23 -3
  92. package/dist/_pkgs/data-view/widget-presets/quick-setting-bar/index.js +8 -8
  93. package/dist/_pkgs/data-view/widget-presets/tools/presets/filter/filter.d.ts +3 -0
  94. package/dist/_pkgs/data-view/widget-presets/tools/presets/filter/filter.js +125 -60
  95. package/dist/_pkgs/data-view/widget-presets/tools/presets/search/search.d.ts +3 -0
  96. package/dist/_pkgs/data-view/widget-presets/tools/presets/search/search.js +37 -5
  97. package/dist/_pkgs/data-view/widget-presets/tools/presets/sort/sort.d.ts +3 -0
  98. package/dist/_pkgs/data-view/widget-presets/tools/presets/sort/sort.js +131 -66
  99. package/dist/_pkgs/data-view/widget-presets/tools/presets/table-add-row/add-row.d.ts +3 -0
  100. package/dist/_pkgs/data-view/widget-presets/tools/presets/table-add-row/add-row.js +143 -40
  101. package/dist/_pkgs/data-view/widget-presets/tools/presets/view-options/view-options.js +30 -22
  102. package/dist/_pkgs/data-view/widget-presets/tools/presets/view-options/view-settings.js +8 -6
  103. package/dist/_pkgs/data-view/widget-presets/views-bar/views-view.js +15 -0
  104. package/package.json +1 -1
@@ -35,15 +35,22 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
35
35
  import { unsafeCSSVarV2 } from '../../../../affine-shared/theme/index.js';
36
36
  import { SignalWatcher, WithDisposable } from '../../../../global/lit/index.js';
37
37
  import { PlusIcon } from '@blocksuite/icons/lit';
38
- import { ShadowlessElement } from '../../../../std/index.js';
39
- import { css } from 'lit';
38
+ import { ShadowlessElement, stdContext } from '../../../../std/index.js';
39
+ import { consume } from '@lit/context';
40
+ import { css, nothing } from 'lit';
40
41
  import { property, query } from 'lit/decorators.js';
41
42
  import { repeat } from 'lit/directives/repeat.js';
42
43
  import { styleMap } from 'lit/directives/style-map.js';
43
44
  import { html } from 'lit/static-html.js';
45
+ import { wordingOf } from '../../../core/utils/wording.js';
46
+ import { DATA_VIEW_NEW_PROPERTY } from '../../../translations.js';
44
47
  import { cellDivider } from '../styles.js';
48
+ import { mobileStickyTitle } from './table-view-style.js';
45
49
  let MobileTableHeader = (() => {
46
50
  let _classSuper = SignalWatcher(WithDisposable(ShadowlessElement));
51
+ let _std_decorators;
52
+ let _std_initializers = [];
53
+ let _std_extraInitializers = [];
47
54
  let _renderGroupHeader_decorators;
48
55
  let _renderGroupHeader_initializers = [];
49
56
  let _renderGroupHeader_extraInitializers = [];
@@ -56,9 +63,11 @@ let MobileTableHeader = (() => {
56
63
  return class MobileTableHeader extends _classSuper {
57
64
  static {
58
65
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
66
+ _std_decorators = [consume({ context: stdContext })];
59
67
  _renderGroupHeader_decorators = [property({ attribute: false })];
60
68
  _scaleDiv_decorators = [query('.scale-div')];
61
69
  _tableViewManager_decorators = [property({ attribute: false })];
70
+ __esDecorate(this, null, _std_decorators, { kind: "accessor", name: "std", static: false, private: false, access: { has: obj => "std" in obj, get: obj => obj.std, set: (obj, value) => { obj.std = value; } }, metadata: _metadata }, _std_initializers, _std_extraInitializers);
62
71
  __esDecorate(this, null, _renderGroupHeader_decorators, { kind: "accessor", name: "renderGroupHeader", static: false, private: false, access: { has: obj => "renderGroupHeader" in obj, get: obj => obj.renderGroupHeader, set: (obj, value) => { obj.renderGroupHeader = value; } }, metadata: _metadata }, _renderGroupHeader_initializers, _renderGroupHeader_extraInitializers);
63
72
  __esDecorate(this, null, _scaleDiv_decorators, { kind: "accessor", name: "scaleDiv", static: false, private: false, access: { has: obj => "scaleDiv" in obj, get: obj => obj.scaleDiv, set: (obj, value) => { obj.scaleDiv = value; } }, metadata: _metadata }, _scaleDiv_initializers, _scaleDiv_extraInitializers);
64
73
  __esDecorate(this, null, _tableViewManager_decorators, { kind: "accessor", name: "tableViewManager", static: false, private: false, access: { has: obj => "tableViewManager" in obj, get: obj => obj.tableViewManager, set: (obj, value) => { obj.tableViewManager = value; } }, metadata: _metadata }, _tableViewManager_initializers, _tableViewManager_extraInitializers);
@@ -68,11 +77,18 @@ let MobileTableHeader = (() => {
68
77
  .mobile-table-add-column {
69
78
  font-size: 18px;
70
79
  color: ${unsafeCSSVarV2('icon/primary')};
71
- margin-left: 8px;
72
80
  display: flex;
73
81
  align-items: center;
82
+ justify-content: center;
83
+ min-width: 44px;
84
+ min-height: 44px;
85
+ cursor: pointer;
74
86
  }
75
87
  `; }
88
+ #std_accessor_storage;
89
+ /** Absent outside an editor host: the wordings read English. */
90
+ get std() { return this.#std_accessor_storage; }
91
+ set std(value) { this.#std_accessor_storage = value; }
76
92
  get readonly() {
77
93
  return this.tableViewManager.readonly$.value;
78
94
  }
@@ -85,21 +101,36 @@ let MobileTableHeader = (() => {
85
101
  width: `${column.width$.value}px`,
86
102
  border: index === 0 ? 'none' : undefined,
87
103
  });
104
+ const isTitle = this.tableViewManager.mainProperties$.value.titleColumn ===
105
+ column.id;
88
106
  return html `
89
- <mobile-table-column-header
90
- style="${style}"
91
- data-column-id="${column.id}"
92
- data-column-index="${index}"
93
- class="mobile-table-cell"
94
- .column="${column}"
95
- .tableViewManager="${this.tableViewManager}"
96
- ></mobile-table-column-header>
97
- <div class="${cellDivider}" style="height: auto;"></div>
107
+ <div
108
+ class="${isTitle ? mobileStickyTitle : ''}"
109
+ style="display: flex;"
110
+ >
111
+ <mobile-table-column-header
112
+ style="${style}"
113
+ data-column-id="${column.id}"
114
+ data-column-index="${index}"
115
+ class="mobile-table-cell"
116
+ .column="${column}"
117
+ .tableViewManager="${this.tableViewManager}"
118
+ ></mobile-table-column-header>
119
+ <div class="${cellDivider}" style="height: auto;"></div>
120
+ </div>
98
121
  `;
99
122
  })}
100
- <div @click="${this._onAddColumn}" class="mobile-table-add-column">
101
- ${PlusIcon()}
102
- </div>
123
+ ${this.readonly
124
+ ? nothing
125
+ : html `<div
126
+ @click="${this._onAddColumn}"
127
+ class="mobile-table-add-column"
128
+ data-testid="dv-table-add-property"
129
+ role="button"
130
+ aria-label="${wordingOf(this.std)(DATA_VIEW_NEW_PROPERTY)}"
131
+ >
132
+ ${PlusIcon()}
133
+ </div>`}
103
134
  <div class="scale-div" style="width: 1px;height: 1px;"></div>
104
135
  </div>
105
136
  `;
@@ -115,17 +146,26 @@ let MobileTableHeader = (() => {
115
146
  set tableViewManager(value) { this.#tableViewManager_accessor_storage = value; }
116
147
  constructor() {
117
148
  super(...arguments);
118
- this._onAddColumn = () => {
149
+ this.#std_accessor_storage = __runInitializers(this, _std_initializers, void 0);
150
+ /**
151
+ * "+" adds a property and opens ITS "Property settings" sheet. Up to 0.54
152
+ * the last header was looked up in the same tick, before the header had
153
+ * drawn the new column, so the sheet opened on the previous last property.
154
+ */
155
+ this._onAddColumn = (__runInitializers(this, _std_extraInitializers), () => {
119
156
  if (this.readonly)
120
157
  return;
121
- this.tableViewManager.propertyAdd('end');
122
- this.editLastColumnTitle();
123
- };
124
- this.editLastColumnTitle = () => {
125
- const columns = this.querySelectorAll('mobile-table-column-header');
126
- const column = columns.item(columns.length - 1);
127
- column.editTitle();
128
- };
158
+ const id = this.tableViewManager.propertyAdd('end');
159
+ if (!id)
160
+ return;
161
+ this.updateComplete
162
+ .then(() => {
163
+ Array.from(this.querySelectorAll('mobile-table-column-header'))
164
+ .find(header => header.column.id === id)
165
+ ?.editTitle();
166
+ })
167
+ .catch(console.error);
168
+ });
129
169
  this.#renderGroupHeader_accessor_storage = __runInitializers(this, _renderGroupHeader_initializers, void 0);
130
170
  this.#scaleDiv_accessor_storage = (__runInitializers(this, _renderGroupHeader_extraInitializers), __runInitializers(this, _scaleDiv_initializers, void 0));
131
171
  this.#tableViewManager_accessor_storage = (__runInitializers(this, _scaleDiv_extraInitializers), __runInitializers(this, _tableViewManager_initializers, void 0));
@@ -1,4 +1,6 @@
1
1
  import { type PopupTarget } from '../../../../affine-components/context-menu/index.js';
2
2
  import type { SingleView } from '../../../core/index.js';
3
+ import { type Wording } from '../../../core/utils/wording.js';
3
4
  import type { MobileTableViewUILogic } from './table-view-ui-logic.js';
4
- export declare const popMobileRowMenu: (target: PopupTarget, rowId: string, tableViewLogic: MobileTableViewUILogic, view: SingleView) => void;
5
+ /** A row's menu on a phone, opened by a long press on the row. */
6
+ export declare const popMobileRowMenu: (target: PopupTarget, rowId: string, tableViewLogic: MobileTableViewUILogic, view: SingleView, wording?: Wording) => void;
@@ -1,11 +1,15 @@
1
1
  import { menu, popFilterableSimpleMenu, } from '../../../../affine-components/context-menu/index.js';
2
+ import { OPEN_LABEL } from '../../../../affine-components/translations.js';
3
+ import { TOOLBAR_DELETE } from '../../../../affine-shared/services/index.js';
2
4
  import { DeleteIcon, ExpandFullIcon } from '@blocksuite/icons/lit';
3
- export const popMobileRowMenu = (target, rowId, tableViewLogic, view) => {
5
+ import { englishWording } from '../../../core/utils/wording.js';
6
+ /** A row's menu on a phone, opened by a long press on the row. */
7
+ export const popMobileRowMenu = (target, rowId, tableViewLogic, view, wording = englishWording) => {
4
8
  popFilterableSimpleMenu(target, [
5
9
  menu.group({
6
10
  items: [
7
11
  menu.action({
8
- name: 'Expand Row',
12
+ name: wording(OPEN_LABEL),
9
13
  prefix: ExpandFullIcon(),
10
14
  select: () => {
11
15
  tableViewLogic.root.openDetailPanel({
@@ -20,7 +24,7 @@ export const popMobileRowMenu = (target, rowId, tableViewLogic, view) => {
20
24
  name: '',
21
25
  items: [
22
26
  menu.action({
23
- name: 'Delete Row',
27
+ name: wording(TOOLBAR_DELETE),
24
28
  class: { 'delete-item': true },
25
29
  prefix: DeleteIcon(),
26
30
  select: () => {
@@ -1,8 +1,30 @@
1
- import { ShadowlessElement } from '../../../../std/index.js';
1
+ import { type BlockStdScope, ShadowlessElement } from '../../../../std/index.js';
2
2
  import type { MobileTableViewUILogic } from './table-view-ui-logic.js';
3
+ /** The "Open" chip's widest drawing, its 8px inset and 4px of air. */
4
+ export declare const ROW_OPEN_WIDTH: number;
5
+ /** How long a finger rests on a row before its menu opens. */
6
+ export declare const ROW_LONG_PRESS_MS = 500;
3
7
  declare const MobileTableRow_base: typeof ShadowlessElement & import("../../../../global/utils/types.js").Constructor<import("../../../../global/lit/with-disposable.js").DisposableClass>;
8
+ /**
9
+ * A row of the phone table (P7, "Bases éditables sur mobile", after Notion's
10
+ * phone table). A tap on a cell edits it; the title column carries an "Open"
11
+ * chip that opens the row through the root's detail panel, the path of the
12
+ * desktop row's open button; a long press opens the row menu (open, delete).
13
+ *
14
+ * Up to 0.54 the title cell carried two floating ops (open and "...") drawn
15
+ * over the end of the title. The chip reserves its room instead, and the
16
+ * "..." moved to the long press so deleting a row stays possible on a phone.
17
+ */
4
18
  export declare class MobileTableRow extends MobileTableRow_base {
5
19
  static styles: import("lit").CSSResult;
20
+ /** Absent outside an editor host: the wordings read English. */
21
+ accessor std: BlockStdScope;
22
+ private pressTimer;
23
+ private pressOrigin;
24
+ /** A long press fired: the click the finger's release makes is eaten. */
25
+ private pressFired;
26
+ private readonly cancelPress;
27
+ private readonly openRow;
6
28
  get groupKey(): string | undefined;
7
29
  connectedCallback(): void;
8
30
  protected render(): unknown;
@@ -33,21 +33,42 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
33
33
  return useValue ? value : void 0;
34
34
  };
35
35
  import { popupTargetFromElement } from '../../../../affine-components/context-menu/index.js';
36
- import { unsafeCSSVarV2 } from '../../../../affine-shared/theme/index.js';
36
+ import { OPEN_LABEL } from '../../../../affine-components/translations.js';
37
37
  import { SignalWatcher, WithDisposable } from '../../../../global/lit/index.js';
38
- import { CenterPeekIcon, MoreHorizontalIcon } from '@blocksuite/icons/lit';
39
- import { ShadowlessElement } from '../../../../std/index.js';
38
+ import { ShadowlessElement, stdContext } from '../../../../std/index.js';
39
+ import { consume } from '@lit/context';
40
40
  import { cssVarV2 } from '@toeverything/theme/v2';
41
41
  import { css, nothing, unsafeCSS } from 'lit';
42
42
  import { property } from 'lit/decorators.js';
43
43
  import { repeat } from 'lit/directives/repeat.js';
44
44
  import { styleMap } from 'lit/directives/style-map.js';
45
45
  import { html } from 'lit/static-html.js';
46
+ import { wordingOf } from '../../../core/utils/wording.js';
46
47
  import { paintRowColor, ROW_COLOR_PROPERTY, viewRowColor, } from '../../../core/view/color-rules.js';
47
48
  import { cellDivider } from '../styles.js';
48
49
  import { popMobileRowMenu } from './menu.js';
50
+ import { mobileStickyTitle } from './table-view-style.js';
51
+ /** The "Open" chip's widest drawing, its 8px inset and 4px of air. */
52
+ export const ROW_OPEN_WIDTH = 60 + 8 + 4;
53
+ /** How long a finger rests on a row before its menu opens. */
54
+ export const ROW_LONG_PRESS_MS = 500;
55
+ /** A finger that travels further is scrolling, not pressing. */
56
+ const LONG_PRESS_SLOP = 8;
57
+ /**
58
+ * A row of the phone table (P7, "Bases éditables sur mobile", after Notion's
59
+ * phone table). A tap on a cell edits it; the title column carries an "Open"
60
+ * chip that opens the row through the root's detail panel, the path of the
61
+ * desktop row's open button; a long press opens the row menu (open, delete).
62
+ *
63
+ * Up to 0.54 the title cell carried two floating ops (open and "...") drawn
64
+ * over the end of the title. The chip reserves its room instead, and the
65
+ * "..." moved to the long press so deleting a row stays possible on a phone.
66
+ */
49
67
  let MobileTableRow = (() => {
50
68
  let _classSuper = SignalWatcher(WithDisposable(ShadowlessElement));
69
+ let _std_decorators;
70
+ let _std_initializers = [];
71
+ let _std_extraInitializers = [];
51
72
  let _tableViewLogic_decorators;
52
73
  let _tableViewLogic_initializers = [];
53
74
  let _tableViewLogic_extraInitializers = [];
@@ -60,16 +81,18 @@ let MobileTableRow = (() => {
60
81
  return class MobileTableRow extends _classSuper {
61
82
  static {
62
83
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
84
+ _std_decorators = [consume({ context: stdContext })];
63
85
  _tableViewLogic_decorators = [property({ attribute: false })];
64
86
  _rowId_decorators = [property({ attribute: false })];
65
87
  _rowIndex_decorators = [property({ attribute: false })];
88
+ __esDecorate(this, null, _std_decorators, { kind: "accessor", name: "std", static: false, private: false, access: { has: obj => "std" in obj, get: obj => obj.std, set: (obj, value) => { obj.std = value; } }, metadata: _metadata }, _std_initializers, _std_extraInitializers);
66
89
  __esDecorate(this, null, _tableViewLogic_decorators, { kind: "accessor", name: "tableViewLogic", static: false, private: false, access: { has: obj => "tableViewLogic" in obj, get: obj => obj.tableViewLogic, set: (obj, value) => { obj.tableViewLogic = value; } }, metadata: _metadata }, _tableViewLogic_initializers, _tableViewLogic_extraInitializers);
67
90
  __esDecorate(this, null, _rowId_decorators, { kind: "accessor", name: "rowId", static: false, private: false, access: { has: obj => "rowId" in obj, get: obj => obj.rowId, set: (obj, value) => { obj.rowId = value; } }, metadata: _metadata }, _rowId_initializers, _rowId_extraInitializers);
68
91
  __esDecorate(this, null, _rowIndex_decorators, { kind: "accessor", name: "rowIndex", static: false, private: false, access: { has: obj => "rowIndex" in obj, get: obj => obj.rowIndex, set: (obj, value) => { obj.rowIndex = value; } }, metadata: _metadata }, _rowIndex_initializers, _rowIndex_extraInitializers);
69
92
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
70
93
  }
71
- // Touch targets are 44px tall (B5, ADR 0035 §1): the row, and each row op
72
- // through an invisible hit area, so the ops keep their drawn size.
94
+ // Touch targets are 44px tall (B5, ADR 0035 §1): the row, and the chip
95
+ // through an invisible hit area, so it keeps its drawn size.
73
96
  static { this.styles = css `
74
97
  .mobile-table-row {
75
98
  width: 100%;
@@ -79,71 +102,114 @@ let MobileTableRow = (() => {
79
102
  position: relative;
80
103
  min-height: 44px;
81
104
  background-color: var(${unsafeCSS(ROW_COLOR_PROPERTY)}, transparent);
105
+ -webkit-touch-callout: none;
82
106
  }
83
107
 
84
- .mobile-row-ops {
85
- position: relative;
86
- width: 0;
87
- margin-top: 5px;
88
- height: max-content;
89
- display: flex;
90
- gap: 20px;
91
- cursor: pointer;
92
- justify-content: end;
93
- right: 8px;
108
+ /* A long press opens the row menu, not a text selection; an edited cell
109
+ keeps its own. */
110
+ .mobile-table-row mobile-table-cell:not([data-editing='true']) {
111
+ -webkit-user-select: none;
112
+ user-select: none;
94
113
  }
95
114
 
96
- .affine-database-block-row:has([data-editing='true']) .mobile-row-ops {
97
- visibility: hidden;
98
- opacity: 0;
99
- }
100
-
101
- .mobile-row-op {
115
+ .mobile-row-open {
116
+ position: absolute;
117
+ top: 10px;
118
+ right: 8px;
102
119
  display: flex;
103
- padding: 4px;
120
+ align-items: center;
121
+ height: 24px;
122
+ max-width: 60px;
123
+ padding: 0 6px;
124
+ box-sizing: border-box;
125
+ border: 1px solid ${unsafeCSS(cssVarV2.layer.insideBorder.border)};
104
126
  border-radius: 4px;
105
- box-shadow: 0px 0px 4px 0px rgba(66, 65, 73, 0.14);
106
127
  background-color: var(--affine-background-primary-color);
107
- position: relative;
108
- font-size: 16px;
109
- color: ${unsafeCSSVarV2('icon/primary')};
128
+ color: ${unsafeCSS(cssVarV2.text.secondary)};
129
+ font-size: 12px;
130
+ font-weight: 500;
131
+ line-height: 20px;
132
+ white-space: nowrap;
133
+ overflow: hidden;
134
+ text-overflow: ellipsis;
135
+ cursor: pointer;
110
136
  }
111
137
 
112
- .mobile-row-op::after {
138
+ .mobile-row-open::after {
113
139
  content: '';
114
140
  position: absolute;
115
- inset: -10px;
141
+ inset: -10px -4px;
142
+ }
143
+
144
+ .mobile-row-title:has(mobile-table-cell[data-editing='true'])
145
+ .mobile-row-open {
146
+ display: none;
116
147
  }
117
148
  `; }
149
+ #std_accessor_storage;
150
+ /** Absent outside an editor host: the wordings read English. */
151
+ get std() { return this.#std_accessor_storage; }
152
+ set std(value) { this.#std_accessor_storage = value; }
118
153
  get groupKey() {
119
154
  return this.closest('affine-data-view-table-group')?.group?.key;
120
155
  }
121
156
  connectedCallback() {
122
157
  super.connectedCallback();
123
158
  this.classList.add('mobile-table-row');
159
+ this.disposables.add(this.cancelPress);
160
+ this.disposables.addFromEvent(this, 'pointerdown', (e) => {
161
+ this.pressFired = false;
162
+ this.cancelPress();
163
+ if (this.view.readonly$.value)
164
+ return;
165
+ this.pressOrigin = { x: e.clientX, y: e.clientY };
166
+ this.pressTimer = setTimeout(() => {
167
+ this.cancelPress();
168
+ this.pressFired = true;
169
+ popMobileRowMenu(popupTargetFromElement(this), this.rowId, this.tableViewLogic, this.view, wordingOf(this.std));
170
+ }, ROW_LONG_PRESS_MS);
171
+ });
172
+ this.disposables.addFromEvent(this, 'pointermove', (e) => {
173
+ const origin = this.pressOrigin;
174
+ if (!origin)
175
+ return;
176
+ const moved = Math.hypot(e.clientX - origin.x, e.clientY - origin.y);
177
+ if (moved > LONG_PRESS_SLOP)
178
+ this.cancelPress();
179
+ });
180
+ this.disposables.addFromEvent(this, 'pointerup', this.cancelPress);
181
+ this.disposables.addFromEvent(this, 'pointercancel', this.cancelPress);
182
+ // Android opens its own menu on a long press; the row's is the one.
183
+ this.disposables.addFromEvent(this, 'contextmenu', (e) => {
184
+ e.preventDefault();
185
+ });
186
+ this.disposables.addFromEvent(this, 'click', (e) => {
187
+ if (!this.pressFired)
188
+ return;
189
+ this.pressFired = false;
190
+ e.stopPropagation();
191
+ e.preventDefault();
192
+ }, { capture: true });
124
193
  }
125
194
  render() {
126
195
  const view = this.view;
127
196
  paintRowColor(this, viewRowColor(view, this.rowId));
197
+ const openLabel = wordingOf(this.std)(OPEN_LABEL);
128
198
  return html `
129
199
  ${repeat(view.properties$.value, v => v.id, (column, i) => {
130
- const clickDetail = () => {
131
- this.tableViewLogic.root.openDetailPanel({
132
- view: this.view,
133
- rowId: this.rowId,
134
- });
135
- };
136
- const openMenu = (e) => {
137
- const ele = e.currentTarget;
138
- popMobileRowMenu(popupTargetFromElement(ele), this.rowId, this.tableViewLogic, this.view);
139
- };
200
+ const isTitle = column.view.mainProperties$.value.titleColumn === column.id;
140
201
  return html `
141
- <div style="display: flex;">
202
+ <div
203
+ class="${isTitle ? `${mobileStickyTitle} mobile-row-title` : ''}"
204
+ style="display: flex;"
205
+ >
142
206
  <mobile-table-cell
143
207
  class="mobile-table-cell"
144
208
  style=${styleMap({
145
209
  width: `${column.width$.value}px`,
146
210
  border: i === 0 ? 'none' : undefined,
211
+ // Room for the "Open" chip drawn over its right end.
212
+ paddingRight: isTitle ? `${ROW_OPEN_WIDTH}px` : undefined,
147
213
  })}
148
214
  .tableViewLogic="${this.tableViewLogic}"
149
215
  .column="${column}"
@@ -158,32 +224,30 @@ let MobileTableRow = (() => {
158
224
  >
159
225
  </mobile-table-cell>
160
226
  <div class="${cellDivider}"></div>
161
- </div>
162
- ${!column.readonly$.value &&
163
- column.view.mainProperties$.value.titleColumn === column.id
164
- ? html ` <div class="mobile-row-ops">
165
- <div class="mobile-row-op" @click="${clickDetail}">
166
- ${CenterPeekIcon()}
167
- </div>
168
- ${!view.readonly$.value
169
- ? html ` <div class="mobile-row-op" @click="${openMenu}">
170
- ${MoreHorizontalIcon()}
171
- </div>`
172
- : nothing}
173
- </div>`
227
+ ${isTitle
228
+ ? html `<div
229
+ class="mobile-row-open"
230
+ data-testid="dv-row-open"
231
+ role="button"
232
+ aria-label="${openLabel}"
233
+ @click="${this.openRow}"
234
+ >
235
+ ${openLabel}
236
+ </div>`
174
237
  : nothing}
238
+ </div>
175
239
  `;
176
240
  })}
177
241
  <div class="database-cell add-column-button"></div>
178
242
  `;
179
243
  }
180
- #tableViewLogic_accessor_storage = __runInitializers(this, _tableViewLogic_initializers, void 0);
244
+ #tableViewLogic_accessor_storage;
181
245
  get tableViewLogic() { return this.#tableViewLogic_accessor_storage; }
182
246
  set tableViewLogic(value) { this.#tableViewLogic_accessor_storage = value; }
183
- #rowId_accessor_storage = (__runInitializers(this, _tableViewLogic_extraInitializers), __runInitializers(this, _rowId_initializers, void 0));
247
+ #rowId_accessor_storage;
184
248
  get rowId() { return this.#rowId_accessor_storage; }
185
249
  set rowId(value) { this.#rowId_accessor_storage = value; }
186
- #rowIndex_accessor_storage = (__runInitializers(this, _rowId_extraInitializers), __runInitializers(this, _rowIndex_initializers, void 0));
250
+ #rowIndex_accessor_storage;
187
251
  get rowIndex() { return this.#rowIndex_accessor_storage; }
188
252
  set rowIndex(value) { this.#rowIndex_accessor_storage = value; }
189
253
  get view() {
@@ -191,6 +255,25 @@ let MobileTableRow = (() => {
191
255
  }
192
256
  constructor() {
193
257
  super(...arguments);
258
+ this.#std_accessor_storage = __runInitializers(this, _std_initializers, void 0);
259
+ this.pressTimer = __runInitializers(this, _std_extraInitializers);
260
+ /** A long press fired: the click the finger's release makes is eaten. */
261
+ this.pressFired = false;
262
+ this.cancelPress = () => {
263
+ clearTimeout(this.pressTimer);
264
+ this.pressTimer = undefined;
265
+ this.pressOrigin = undefined;
266
+ };
267
+ this.openRow = (e) => {
268
+ e.stopPropagation();
269
+ this.tableViewLogic.root.openDetailPanel({
270
+ view: this.view,
271
+ rowId: this.rowId,
272
+ });
273
+ };
274
+ this.#tableViewLogic_accessor_storage = __runInitializers(this, _tableViewLogic_initializers, void 0);
275
+ this.#rowId_accessor_storage = (__runInitializers(this, _tableViewLogic_extraInitializers), __runInitializers(this, _rowId_initializers, void 0));
276
+ this.#rowIndex_accessor_storage = (__runInitializers(this, _rowId_extraInitializers), __runInitializers(this, _rowIndex_initializers, void 0));
194
277
  __runInitializers(this, _rowIndex_extraInitializers);
195
278
  }
196
279
  };
@@ -1,3 +1,20 @@
1
+ /**
2
+ * The view element itself never scrolls: the inner wrapper does.
3
+ *
4
+ * Upstream disabled horizontal scrolling of the mobile table altogether "to
5
+ * prevent crashes on iOS Safari" (AFFiNE#12203, blocksuite#8784), which left
6
+ * every column past the first unreachable on a phone. The scroll now lives on
7
+ * ONE inner element, contained (`overscroll-behavior`) so it never chains into
8
+ * the page; the host stays clipped as before.
9
+ * ponytail: unverified on a real iOS Safari here; if the crash comes back, the
10
+ * fallback is a paged column switcher, not `hidden` again.
11
+ */
12
+ export declare const mobileTableViewHost: string;
1
13
  export declare const mobileTableViewWrapper: string;
14
+ /**
15
+ * The title column stays in view while the others scroll under it: opaque,
16
+ * with the row's colour painted over the page colour.
17
+ */
18
+ export declare const mobileStickyTitle: string;
2
19
  export declare const mobileTableViewContainer: string;
3
20
  export declare const mobileCellDivider: string;
@@ -1,16 +1,41 @@
1
1
  import { css } from '@emotion/css';
2
2
  import { cssVarV2 } from '@toeverything/theme/v2';
3
+ import { ROW_COLOR_PROPERTY } from '../../../core/view/color-rules.js';
4
+ /**
5
+ * The view element itself never scrolls: the inner wrapper does.
6
+ *
7
+ * Upstream disabled horizontal scrolling of the mobile table altogether "to
8
+ * prevent crashes on iOS Safari" (AFFiNE#12203, blocksuite#8784), which left
9
+ * every column past the first unreachable on a phone. The scroll now lives on
10
+ * ONE inner element, contained (`overscroll-behavior`) so it never chains into
11
+ * the page; the host stays clipped as before.
12
+ * ponytail: unverified on a real iOS Safari here; if the crash comes back, the
13
+ * fallback is a paged column switcher, not `hidden` again.
14
+ */
15
+ export const mobileTableViewHost = css({
16
+ position: 'relative',
17
+ width: '100%',
18
+ overflowX: 'hidden',
19
+ overflowY: 'hidden',
20
+ });
3
21
  export const mobileTableViewWrapper = css({
4
22
  position: 'relative',
5
23
  width: '100%',
6
24
  paddingBottom: '4px',
7
- /**
8
- * Disable horizontal scrolling to prevent crashes on iOS Safari
9
- * See https://github.com/toeverything/AFFiNE/pull/12203
10
- * and https://github.com/toeverything/blocksuite/pull/8784
11
- */
12
- overflowX: 'hidden',
25
+ overflowX: 'auto',
13
26
  overflowY: 'hidden',
27
+ overscrollBehaviorX: 'contain',
28
+ });
29
+ /**
30
+ * The title column stays in view while the others scroll under it: opaque,
31
+ * with the row's colour painted over the page colour.
32
+ */
33
+ export const mobileStickyTitle = css({
34
+ position: 'sticky',
35
+ left: 0,
36
+ zIndex: 1,
37
+ backgroundColor: 'var(--affine-background-primary-color)',
38
+ backgroundImage: `linear-gradient(var(${ROW_COLOR_PROPERTY}, transparent), var(${ROW_COLOR_PROPERTY}, transparent))`,
14
39
  });
15
40
  export const mobileTableViewContainer = css({
16
41
  position: 'relative',
@@ -8,7 +8,11 @@ export declare class MobileTableViewUILogic extends DataViewUILogicBase<TableSin
8
8
  ui$: import("@preact/signals-core").Signal<MobileTableViewUI | undefined>;
9
9
  private get readonly();
10
10
  clearSelection: () => void;
11
- addRow: (position: InsertToPosition) => string | undefined;
11
+ /**
12
+ * A new row opens at once, as on the desktop table and the flat views: on a
13
+ * phone its title and properties are typed in the row page.
14
+ */
15
+ addRow: (position: InsertToPosition, groupKey?: string) => string | undefined;
12
16
  focusFirstCell: () => void;
13
17
  showIndicator: (_evt: MouseEvent) => boolean;
14
18
  hideIndicator: () => void;
@@ -7,16 +7,23 @@ import { html } from 'lit/static-html.js';
7
7
  import { createUniComponentFromWebComponent, renderUniLit, } from '../../../core/index.js';
8
8
  import { DataViewUIBase, DataViewUILogicBase, } from '../../../core/view/data-view-base.js';
9
9
  import { LEFT_TOOL_BAR_WIDTH } from '../consts.js';
10
- import { mobileTableViewContainer, mobileTableViewWrapper, } from './table-view-style.js';
10
+ import { mobileTableViewContainer, mobileTableViewHost, mobileTableViewWrapper, } from './table-view-style.js';
11
11
  export class MobileTableViewUILogic extends DataViewUILogicBase {
12
12
  constructor() {
13
13
  super(...arguments);
14
14
  this.ui$ = signal(undefined);
15
15
  this.clearSelection = () => { };
16
- this.addRow = (position) => {
16
+ /**
17
+ * A new row opens at once, as on the desktop table and the flat views: on a
18
+ * phone its title and properties are typed in the row page.
19
+ */
20
+ this.addRow = (position, groupKey) => {
17
21
  if (this.readonly)
18
22
  return;
19
- return this.view.rowAdd(position);
23
+ const rowId = this.view.rowAdd(position, groupKey);
24
+ if (rowId)
25
+ this.root.openDetailPanel({ view: this.view, rowId });
26
+ return rowId;
20
27
  };
21
28
  this.focusFirstCell = () => { };
22
29
  this.showIndicator = (_evt) => {
@@ -71,7 +78,7 @@ export class MobileTableViewUI extends DataViewUIBase {
71
78
  connectedCallback() {
72
79
  super.connectedCallback();
73
80
  this.logic.ui$.value = this;
74
- this.classList.add(mobileTableViewWrapper);
81
+ this.classList.add(mobileTableViewHost);
75
82
  }
76
83
  renderTable() {
77
84
  const groups = this.logic.view.groupTrait.visibleGroups$.value;
@@ -48,7 +48,7 @@ import { createDndContext } from '../../../core/utils/wc-dnd/dnd-context.js';
48
48
  import { defaultActivators } from '../../../core/utils/wc-dnd/sensors/index.js';
49
49
  import { linearMove } from '../../../core/utils/wc-dnd/utils/linear-move.js';
50
50
  import { wordingOf } from '../../../core/utils/wording.js';
51
- import { DATA_VIEW_GROUP_COLLAPSE, DATA_VIEW_GROUP_EXPAND, } from '../../../translations.js';
51
+ import { DATA_VIEW_GROUP_COLLAPSE, DATA_VIEW_GROUP_EXPAND, DATA_VIEW_NEW_RECORD, } from '../../../translations.js';
52
52
  import { getCollapsedState, setCollapsedState } from '../collapsed-state.js';
53
53
  import { LEFT_TOOL_BAR_WIDTH } from '../consts.js';
54
54
  import { TableViewAreaSelection } from '../selection.js';
@@ -193,7 +193,9 @@ let TableGroup = (() => {
193
193
  data-test-id="affine-database-add-row-button"
194
194
  role="button"
195
195
  >
196
- ${PlusIcon()}<span style="font-size: 12px">New Record</span>
196
+ ${PlusIcon()}<span style="font-size: 12px"
197
+ >${wordingOf(this.std)(DATA_VIEW_NEW_RECORD)}</span
198
+ >
197
199
  </div>
198
200
  </div>`}
199
201
  <affine-database-column-stats