@formicoidea/labre-core 0.43.1 → 0.46.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 (300) hide show
  1. package/dist/_pkgs/affine-block-attachment/utils.js +4 -0
  2. package/dist/_pkgs/affine-block-bookmark/configs/toolbar.js +17 -4
  3. package/dist/_pkgs/affine-block-callout/commands/turn-callout-into.d.ts +43 -0
  4. package/dist/_pkgs/affine-block-callout/commands/turn-callout-into.js +109 -0
  5. package/dist/_pkgs/affine-block-callout/commands/turn-into-callout.d.ts +29 -0
  6. package/dist/_pkgs/affine-block-callout/commands/turn-into-callout.js +81 -0
  7. package/dist/_pkgs/affine-block-callout/configs/slash-menu.js +6 -4
  8. package/dist/_pkgs/affine-block-callout/configs/toolbar.d.ts +65 -0
  9. package/dist/_pkgs/affine-block-callout/configs/toolbar.js +178 -0
  10. package/dist/_pkgs/affine-block-callout/configs/turn-into.d.ts +8 -0
  11. package/dist/_pkgs/affine-block-callout/configs/turn-into.js +19 -0
  12. package/dist/_pkgs/affine-block-callout/translations.d.ts +4 -2
  13. package/dist/_pkgs/affine-block-callout/translations.js +4 -2
  14. package/dist/_pkgs/affine-block-callout/view.js +10 -1
  15. package/dist/_pkgs/affine-block-code/code-block-service.d.ts +13 -0
  16. package/dist/_pkgs/affine-block-code/code-block-service.js +26 -0
  17. package/dist/_pkgs/affine-block-code/code-block.d.ts +6 -0
  18. package/dist/_pkgs/affine-block-code/code-block.js +11 -2
  19. package/dist/_pkgs/affine-block-code/code-toolbar/components/lang-button.js +31 -8
  20. package/dist/_pkgs/affine-block-edgeless-text/edgeless-toolbar/config.d.ts +11 -0
  21. package/dist/_pkgs/affine-block-edgeless-text/svg-painter.d.ts +20 -0
  22. package/dist/_pkgs/affine-block-edgeless-text/svg-painter.js +76 -0
  23. package/dist/_pkgs/affine-block-edgeless-text/view.js +2 -0
  24. package/dist/_pkgs/affine-block-embed/configs/toolbar.js +11 -2
  25. package/dist/_pkgs/affine-block-embed/embed-iframe-block/configs/toolbar.js +11 -2
  26. package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/embed-edgeless-linked-doc-block.js +3 -1
  27. package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/configs/toolbar.js +7 -2
  28. package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/embed-edgeless-synced-doc-block.js +3 -1
  29. package/dist/_pkgs/affine-block-frame/commands.d.ts +27 -0
  30. package/dist/_pkgs/affine-block-frame/commands.js +49 -0
  31. package/dist/_pkgs/affine-block-frame/frame-manager.d.ts +16 -6
  32. package/dist/_pkgs/affine-block-frame/frame-manager.js +58 -22
  33. package/dist/_pkgs/affine-block-frame/frame-order.d.ts +43 -0
  34. package/dist/_pkgs/affine-block-frame/frame-order.js +93 -0
  35. package/dist/_pkgs/affine-block-frame/frame-tool.js +3 -1
  36. package/dist/_pkgs/affine-block-frame/index.d.ts +2 -0
  37. package/dist/_pkgs/affine-block-frame/index.js +2 -0
  38. package/dist/_pkgs/affine-block-frame/present/frame-order-menu.d.ts +10 -2
  39. package/dist/_pkgs/affine-block-frame/present/frame-order-menu.js +32 -18
  40. package/dist/_pkgs/affine-block-frame/view.js +6 -0
  41. package/dist/_pkgs/affine-block-image/utils.js +4 -1
  42. package/dist/_pkgs/affine-block-latex/adapters/markdown/preprocessor.d.ts +8 -0
  43. package/dist/_pkgs/affine-block-latex/adapters/markdown/preprocessor.js +9 -5
  44. package/dist/_pkgs/affine-block-note/configs/toolbar.d.ts +19 -0
  45. package/dist/_pkgs/affine-block-note/configs/toolbar.js +38 -23
  46. package/dist/_pkgs/affine-block-note/translations.d.ts +2 -1
  47. package/dist/_pkgs/affine-block-note/translations.js +14 -6
  48. package/dist/_pkgs/affine-block-root/configs/toolbar.js +48 -3
  49. package/dist/_pkgs/affine-block-root/edgeless/clipboard/clipboard.js +2 -1
  50. package/dist/_pkgs/affine-block-root/edgeless/clipboard/command.js +161 -83
  51. package/dist/_pkgs/affine-block-root/edgeless/clipboard/paste-order.d.ts +21 -0
  52. package/dist/_pkgs/affine-block-root/edgeless/clipboard/paste-order.js +85 -0
  53. package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.d.ts +6 -0
  54. package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.js +18 -1
  55. package/dist/_pkgs/affine-block-root/edgeless/utils/clone-utils.d.ts +9 -0
  56. package/dist/_pkgs/affine-block-root/edgeless/utils/clone-utils.js +28 -0
  57. package/dist/_pkgs/affine-block-root/keyboard/commands.js +9 -6
  58. package/dist/_pkgs/affine-block-root/preview/edgeless-root-preview-block.js +15 -2
  59. package/dist/_pkgs/affine-block-root/translations.d.ts +7 -2
  60. package/dist/_pkgs/affine-block-root/translations.js +10 -13
  61. package/dist/_pkgs/affine-block-surface/adapters/markdown/element-adapter/type.d.ts +1 -1
  62. package/dist/_pkgs/affine-block-surface/element-model/index.d.ts +1 -1
  63. package/dist/_pkgs/affine-block-surface/element-model/index.js +1 -1
  64. package/dist/_pkgs/affine-block-surface/extensions/audit.js +13 -61
  65. package/dist/_pkgs/affine-block-surface/extensions/canvas-grid/commands.d.ts +2 -0
  66. package/dist/_pkgs/affine-block-surface/extensions/canvas-grid/commands.js +71 -0
  67. package/dist/_pkgs/affine-block-surface/extensions/canvas-grid/index.d.ts +1 -0
  68. package/dist/_pkgs/affine-block-surface/extensions/canvas-grid/index.js +1 -0
  69. package/dist/_pkgs/affine-block-surface/extensions/clipboard-config.js +4 -0
  70. package/dist/_pkgs/affine-block-surface/extensions/crud-extension.js +4 -0
  71. package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.d.ts +12 -0
  72. package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.js +27 -7
  73. package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.d.ts +2 -1
  74. package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.js +22 -3
  75. package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.d.ts +6 -3
  76. package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.js +4 -2
  77. package/dist/_pkgs/affine-block-surface/extensions/export-svg/parts.d.ts +63 -0
  78. package/dist/_pkgs/affine-block-surface/extensions/export-svg/parts.js +67 -0
  79. package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.d.ts +62 -5
  80. package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.js +98 -18
  81. package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.d.ts +14 -0
  82. package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.js +82 -1
  83. package/dist/_pkgs/affine-block-surface/extensions/export-svg/toolbar.d.ts +2 -2
  84. package/dist/_pkgs/affine-block-surface/extensions/export-svg/toolbar.js +112 -10
  85. package/dist/_pkgs/affine-block-surface/extensions/export-svg/translations.d.ts +13 -0
  86. package/dist/_pkgs/affine-block-surface/extensions/export-svg/translations.js +33 -0
  87. package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +3 -0
  88. package/dist/_pkgs/affine-block-surface/extensions/index.js +3 -0
  89. package/dist/_pkgs/affine-block-surface/extensions/reading-widget.d.ts +13 -6
  90. package/dist/_pkgs/affine-block-surface/extensions/reading-widget.js +26 -10
  91. package/dist/_pkgs/affine-block-surface/extensions/reading.d.ts +82 -6
  92. package/dist/_pkgs/affine-block-surface/extensions/reading.js +99 -21
  93. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/actions.d.ts +91 -0
  94. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/actions.js +285 -0
  95. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/commands.d.ts +80 -0
  96. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/commands.js +355 -0
  97. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/index.d.ts +3 -0
  98. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/index.js +3 -0
  99. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/tree.d.ts +137 -0
  100. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/tree.js +323 -0
  101. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.d.ts +112 -4
  102. package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.js +86 -15
  103. package/dist/_pkgs/affine-block-surface/extensions/user-layers/actions.d.ts +76 -0
  104. package/dist/_pkgs/affine-block-surface/extensions/user-layers/actions.js +299 -0
  105. package/dist/_pkgs/affine-block-surface/extensions/user-layers/active-layer.d.ts +20 -0
  106. package/dist/_pkgs/affine-block-surface/extensions/user-layers/active-layer.js +34 -0
  107. package/dist/_pkgs/affine-block-surface/extensions/user-layers/commands.d.ts +67 -0
  108. package/dist/_pkgs/affine-block-surface/extensions/user-layers/commands.js +172 -0
  109. package/dist/_pkgs/affine-block-surface/extensions/user-layers/creation.d.ts +40 -0
  110. package/dist/_pkgs/affine-block-surface/extensions/user-layers/creation.js +69 -0
  111. package/dist/_pkgs/affine-block-surface/extensions/user-layers/index.d.ts +5 -0
  112. package/dist/_pkgs/affine-block-surface/extensions/user-layers/index.js +5 -0
  113. package/dist/_pkgs/affine-block-surface/extensions/user-layers/translations.d.ts +10 -0
  114. package/dist/_pkgs/affine-block-surface/extensions/user-layers/translations.js +14 -0
  115. package/dist/_pkgs/affine-block-surface/framework-background/facts.d.ts +55 -2
  116. package/dist/_pkgs/affine-block-surface/framework-background/facts.js +63 -1
  117. package/dist/_pkgs/affine-block-surface/framework-background/stacking.d.ts +16 -8
  118. package/dist/_pkgs/affine-block-surface/framework-background/stacking.js +26 -14
  119. package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.js +17 -3
  120. package/dist/_pkgs/affine-block-surface/renderer/dom-renderer.d.ts +3 -1
  121. package/dist/_pkgs/affine-block-surface/renderer/dom-renderer.js +22 -2
  122. package/dist/_pkgs/affine-block-surface/renderer/paint-predicate.d.ts +30 -0
  123. package/dist/_pkgs/affine-block-surface/renderer/paint-predicate.js +29 -0
  124. package/dist/_pkgs/affine-block-surface/surface-block.js +6 -0
  125. package/dist/_pkgs/affine-block-surface/surface-model.js +5 -0
  126. package/dist/_pkgs/affine-block-surface/surface-transformer.js +5 -0
  127. package/dist/_pkgs/affine-block-surface/tool/default-tool.js +28 -5
  128. package/dist/_pkgs/affine-block-surface/view.js +23 -1
  129. package/dist/_pkgs/affine-block-surface-ref/surface-ref-block.js +12 -2
  130. package/dist/_pkgs/affine-components/context-menu/button.js +14 -0
  131. package/dist/_pkgs/affine-components/filterable-list/index.js +30 -9
  132. package/dist/_pkgs/affine-components/icons/index.d.ts +0 -1
  133. package/dist/_pkgs/affine-components/icons/index.js +0 -1
  134. package/dist/_pkgs/affine-components/icons/text.d.ts +1 -0
  135. package/dist/_pkgs/affine-components/icons/text.js +11 -0
  136. package/dist/_pkgs/affine-components/portal/portal.d.ts +1 -1
  137. package/dist/_pkgs/affine-foundation/view.d.ts +8 -8
  138. package/dist/_pkgs/affine-fragment-adapter-panel/adapter-panel.d.ts +2 -2
  139. package/dist/_pkgs/affine-fragment-frame-panel/body/frame-panel-body.d.ts +34 -2
  140. package/dist/_pkgs/affine-fragment-frame-panel/body/frame-panel-body.js +194 -81
  141. package/dist/_pkgs/affine-fragment-frame-panel/card/frame-card.d.ts +7 -4
  142. package/dist/_pkgs/affine-fragment-frame-panel/card/frame-card.js +9 -24
  143. package/dist/_pkgs/affine-fragment-frame-panel/header/frame-panel-header.d.ts +1 -1
  144. package/dist/_pkgs/affine-fragment-frame-panel/header/frame-panel-header.js +8 -27
  145. package/dist/_pkgs/affine-fragment-frame-panel/index.d.ts +2 -0
  146. package/dist/_pkgs/affine-fragment-frame-panel/index.js +2 -0
  147. package/dist/_pkgs/affine-gfx-connector/element-renderer/connector-dom/index.js +3 -1
  148. package/dist/_pkgs/affine-gfx-connector/element-renderer/index.js +21 -4
  149. package/dist/_pkgs/affine-gfx-connector/text/edgeless-connector-label-editor.js +3 -2
  150. package/dist/_pkgs/affine-gfx-connector/toolbar/config.js +1 -1
  151. package/dist/_pkgs/affine-gfx-group/command/group-api.js +52 -1
  152. package/dist/_pkgs/affine-gfx-shape/element-renderer/shape/index.js +21 -3
  153. package/dist/_pkgs/affine-gfx-shape/text/edgeless-shape-text-editor.js +2 -0
  154. package/dist/_pkgs/affine-gfx-shape/toolbar/config.js +1 -1
  155. package/dist/_pkgs/affine-gfx-template/services/template-middlewares.d.ts +9 -0
  156. package/dist/_pkgs/affine-gfx-template/services/template-middlewares.js +23 -1
  157. package/dist/_pkgs/affine-gfx-template/services/template.js +2 -1
  158. package/dist/_pkgs/affine-gfx-text/edgeless-text-editor.js +2 -1
  159. package/dist/_pkgs/affine-gfx-text/element-renderer/index.js +20 -3
  160. package/dist/_pkgs/affine-gfx-text/element-renderer/utils.d.ts +67 -1
  161. package/dist/_pkgs/affine-gfx-text/element-renderer/utils.js +101 -0
  162. package/dist/_pkgs/affine-gfx-text/toolbar/actions.d.ts +11 -0
  163. package/dist/_pkgs/affine-gfx-text/toolbar/actions.js +53 -2
  164. package/dist/_pkgs/affine-gfx-text/toolbar/config.d.ts +11 -0
  165. package/dist/_pkgs/affine-gfx-text/toolbar/config.js +1 -1
  166. package/dist/_pkgs/affine-inline-preset/adapters/html/html-inline.d.ts +3 -0
  167. package/dist/_pkgs/affine-inline-preset/adapters/html/html-inline.js +31 -0
  168. package/dist/_pkgs/affine-inline-preset/adapters/html/inline-delta.d.ts +4 -0
  169. package/dist/_pkgs/affine-inline-preset/adapters/html/inline-delta.js +14 -0
  170. package/dist/_pkgs/affine-inline-preset/command/config.js +21 -3
  171. package/dist/_pkgs/affine-inline-preset/command/index.d.ts +1 -1
  172. package/dist/_pkgs/affine-inline-preset/command/index.js +1 -1
  173. package/dist/_pkgs/affine-inline-preset/command/text-style.d.ts +2 -1
  174. package/dist/_pkgs/affine-inline-preset/command/text-style.js +1 -0
  175. package/dist/_pkgs/affine-inline-preset/default-inline-manager.js +2 -1
  176. package/dist/_pkgs/affine-inline-preset/inline-spec.d.ts +4 -0
  177. package/dist/_pkgs/affine-inline-preset/inline-spec.js +14 -0
  178. package/dist/_pkgs/affine-inline-preset/translations.d.ts +2 -2
  179. package/dist/_pkgs/affine-inline-preset/translations.js +2 -2
  180. package/dist/_pkgs/affine-model/blocks/attachment/attachment-model.js +2 -0
  181. package/dist/_pkgs/affine-model/blocks/bookmark/bookmark-model.js +2 -0
  182. package/dist/_pkgs/affine-model/blocks/edgeless-text/edgeless-text-model.d.ts +1 -1
  183. package/dist/_pkgs/affine-model/blocks/edgeless-text/edgeless-text-model.js +2 -0
  184. package/dist/_pkgs/affine-model/blocks/embed/iframe/iframe-model.js +2 -0
  185. package/dist/_pkgs/affine-model/blocks/frame/frame-model.js +2 -0
  186. package/dist/_pkgs/affine-model/blocks/image/image-model.js +2 -0
  187. package/dist/_pkgs/affine-model/blocks/latex/latex-model.js +2 -0
  188. package/dist/_pkgs/affine-model/blocks/note/note-model.js +2 -0
  189. package/dist/_pkgs/affine-model/consts/text.d.ts +26 -0
  190. package/dist/_pkgs/affine-model/consts/text.js +25 -0
  191. package/dist/_pkgs/affine-model/elements/shape/shape.d.ts +6 -1
  192. package/dist/_pkgs/affine-model/elements/shape/shape.js +14 -1
  193. package/dist/_pkgs/affine-model/elements/text/text.d.ts +6 -1
  194. package/dist/_pkgs/affine-model/elements/text/text.js +13 -1
  195. package/dist/_pkgs/affine-model/utils/helper.js +2 -0
  196. package/dist/_pkgs/affine-model/utils/types.d.ts +2 -2
  197. package/dist/_pkgs/affine-rich-text/conversion.d.ts +25 -0
  198. package/dist/_pkgs/affine-rich-text/conversion.js +9 -0
  199. package/dist/_pkgs/affine-rich-text/index.d.ts +1 -1
  200. package/dist/_pkgs/affine-rich-text/index.js +1 -1
  201. package/dist/_pkgs/affine-shared/commands/model-crud/replace-selected-text-with-blocks.d.ts +1 -1
  202. package/dist/_pkgs/affine-shared/services/canvas-grid.d.ts +63 -0
  203. package/dist/_pkgs/affine-shared/services/canvas-grid.js +109 -0
  204. package/dist/_pkgs/affine-shared/services/canvas-local-visibility.d.ts +64 -0
  205. package/dist/_pkgs/affine-shared/services/canvas-local-visibility.js +192 -0
  206. package/dist/_pkgs/affine-shared/services/edit-props-store.d.ts +31 -4
  207. package/dist/_pkgs/affine-shared/services/edit-props-store.js +34 -0
  208. package/dist/_pkgs/affine-shared/services/editor-setting-service.d.ts +3 -0
  209. package/dist/_pkgs/affine-shared/services/editor-setting-service.js +7 -0
  210. package/dist/_pkgs/affine-shared/services/feature-flag-service.d.ts +4 -0
  211. package/dist/_pkgs/affine-shared/services/font-loader/config.d.ts +2 -2
  212. package/dist/_pkgs/affine-shared/services/font-loader/font-loader-service.d.ts +3 -3
  213. package/dist/_pkgs/affine-shared/services/index.d.ts +4 -1
  214. package/dist/_pkgs/affine-shared/services/index.js +4 -1
  215. package/dist/_pkgs/affine-shared/services/link-preview-service/link-preview-storage.d.ts +4 -4
  216. package/dist/_pkgs/affine-shared/services/outline-panel-service.d.ts +31 -0
  217. package/dist/_pkgs/affine-shared/services/outline-panel-service.js +17 -0
  218. package/dist/_pkgs/affine-shared/services/selection-pane-service.d.ts +44 -0
  219. package/dist/_pkgs/affine-shared/services/selection-pane-service.js +28 -0
  220. package/dist/_pkgs/affine-shared/services/telemetry-service/lifecycle.d.ts +69 -0
  221. package/dist/_pkgs/affine-shared/services/telemetry-service/telemetry-service.d.ts +2 -2
  222. package/dist/_pkgs/affine-shared/services/translation-service/chrome.d.ts +16 -0
  223. package/dist/_pkgs/affine-shared/services/translation-service/chrome.js +28 -0
  224. package/dist/_pkgs/affine-shared/styles/index.d.ts +1 -0
  225. package/dist/_pkgs/affine-shared/styles/index.js +1 -0
  226. package/dist/_pkgs/affine-shared/styles/panel-header.d.ts +31 -0
  227. package/dist/_pkgs/affine-shared/styles/panel-header.js +61 -0
  228. package/dist/_pkgs/affine-shared/styles/text.js +7 -7
  229. package/dist/_pkgs/affine-shared/types/index.d.ts +6 -0
  230. package/dist/_pkgs/affine-shared/utils/canvas-export-colors.d.ts +26 -0
  231. package/dist/_pkgs/affine-shared/utils/canvas-export-colors.js +127 -0
  232. package/dist/_pkgs/affine-shared/utils/file/filesys.d.ts +8 -11
  233. package/dist/_pkgs/affine-shared/utils/file/filesys.js +8 -11
  234. package/dist/_pkgs/affine-shared/utils/index.d.ts +3 -0
  235. package/dist/_pkgs/affine-shared/utils/index.js +3 -0
  236. package/dist/_pkgs/affine-shared/utils/label-mode.d.ts +47 -0
  237. package/dist/_pkgs/affine-shared/utils/label-mode.js +55 -0
  238. package/dist/_pkgs/affine-shared/utils/model/merge-to-code-model.js +7 -1
  239. package/dist/_pkgs/affine-shared/utils/model/transform-model.js +5 -0
  240. package/dist/_pkgs/affine-shared/utils/panel-reorder-drag.d.ts +85 -0
  241. package/dist/_pkgs/affine-shared/utils/panel-reorder-drag.js +162 -0
  242. package/dist/_pkgs/affine-widget-edgeless-selected-rect/utils.js +10 -3
  243. package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.js +25 -49
  244. package/dist/_pkgs/affine-widget-edgeless-toolbar/effects.d.ts +4 -0
  245. package/dist/_pkgs/affine-widget-edgeless-toolbar/effects.js +4 -0
  246. package/dist/_pkgs/affine-widget-edgeless-toolbar/index.d.ts +4 -0
  247. package/dist/_pkgs/affine-widget-edgeless-toolbar/index.js +4 -0
  248. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/drop.d.ts +62 -0
  249. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/drop.js +94 -0
  250. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/labels.d.ts +17 -0
  251. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/labels.js +95 -0
  252. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-default.d.ts +10 -0
  253. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-default.js +31 -0
  254. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-tool.d.ts +26 -0
  255. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-tool.js +82 -0
  256. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-widget.d.ts +186 -0
  257. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-widget.js +1417 -0
  258. package/dist/_pkgs/affine-widget-edgeless-toolbar/translations.d.ts +52 -0
  259. package/dist/_pkgs/affine-widget-edgeless-toolbar/translations.js +161 -1
  260. package/dist/_pkgs/affine-widget-edgeless-toolbar/view.js +10 -0
  261. package/dist/_pkgs/affine-widget-note-slicer/note-slicer.js +7 -3
  262. package/dist/_pkgs/std/gfx/controller.d.ts +13 -0
  263. package/dist/_pkgs/std/gfx/controller.js +22 -2
  264. package/dist/_pkgs/std/gfx/grid.d.ts +31 -2
  265. package/dist/_pkgs/std/gfx/index.d.ts +3 -1
  266. package/dist/_pkgs/std/gfx/index.js +3 -1
  267. package/dist/_pkgs/std/gfx/interactivity/manager.js +7 -0
  268. package/dist/_pkgs/std/gfx/layer.js +73 -5
  269. package/dist/_pkgs/std/gfx/local-visibility.d.ts +88 -0
  270. package/dist/_pkgs/std/gfx/local-visibility.js +217 -0
  271. package/dist/_pkgs/std/gfx/model/gfx-block-model.d.ts +13 -0
  272. package/dist/_pkgs/std/gfx/model/surface/element-model.d.ts +34 -0
  273. package/dist/_pkgs/std/gfx/model/surface/element-model.js +65 -1
  274. package/dist/_pkgs/std/gfx/model/surface/surface-model.d.ts +27 -0
  275. package/dist/_pkgs/std/gfx/model/surface/surface-model.js +43 -0
  276. package/dist/_pkgs/std/gfx/model/surface/user-layers.d.ts +68 -0
  277. package/dist/_pkgs/std/gfx/model/surface/user-layers.js +127 -0
  278. package/dist/_pkgs/std/scope/std-scope.d.ts +1 -1
  279. package/dist/_pkgs/std/utils/layer.d.ts +10 -0
  280. package/dist/_pkgs/std/utils/layer.js +64 -13
  281. package/dist/_pkgs/std/view/element/gfx-block-component.js +10 -2
  282. package/dist/commands.js +6 -1
  283. package/dist/host-panels.d.ts +90 -0
  284. package/dist/host-panels.js +111 -0
  285. package/dist/translations.js +10 -6
  286. package/package.json +13 -2
  287. package/dist/_pkgs/affine-components/icons/file-icons-rc.d.ts +0 -1
  288. package/dist/_pkgs/affine-components/icons/file-icons-rc.js +0 -130
  289. package/dist/_pkgs/affine-fragment-frame-panel/utils/drag.d.ts +0 -27
  290. package/dist/_pkgs/affine-fragment-frame-panel/utils/drag.js +0 -96
  291. package/dist/_pkgs/affine-shared/services/sidebar-service.d.ts +0 -8
  292. package/dist/_pkgs/affine-shared/services/sidebar-service.js +0 -7
  293. package/dist/_pkgs/affine-shared/test-utils/affine-template.d.ts +0 -6
  294. package/dist/_pkgs/affine-shared/test-utils/affine-template.js +0 -258
  295. package/dist/_pkgs/affine-shared/test-utils/affine-test-utils.d.ts +0 -8
  296. package/dist/_pkgs/affine-shared/test-utils/affine-test-utils.js +0 -81
  297. package/dist/_pkgs/affine-shared/test-utils/create-test-host.d.ts +0 -23
  298. package/dist/_pkgs/affine-shared/test-utils/create-test-host.js +0 -187
  299. package/dist/_pkgs/affine-shared/test-utils/index.d.ts +0 -3
  300. package/dist/_pkgs/affine-shared/test-utils/index.js +0 -3
@@ -0,0 +1,1417 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { CanvasActiveLayer, EDITOR_ANCHORED_PANEL_Z_INDEX, filterSelectionPaneTree, SelectionPaneModel, selectionPaneCommands, selectionPaneFilterMembers, selectionPaneFilterTargets, selectionPaneTree, userLayerCommands, userLayerName, } from '../../affine-block-surface/index.js';
36
+ import { menu, popMenu, popupTargetFromElement, } from '../../affine-components/context-menu/index.js';
37
+ import { FrameBlockModel, MindmapElementModel, } from '../../affine-model/index.js';
38
+ import { TOOLBAR_LOCK, TOOLBAR_RENAME, translateKey, } from '../../affine-shared/services/index.js';
39
+ import { panelHeaderStyles } from '../../affine-shared/styles/index.js';
40
+ import { createPanelReorderDrag, } from '../../affine-shared/utils/index.js';
41
+ import { runCommand, WidgetComponent, WidgetViewExtension, } from '../../std/index.js';
42
+ import { DEFAULT_LAYER_ID, GfxBlockElementModel, GfxControllerIdentifier, } from '../../std/gfx/index.js';
43
+ import { ArrowDownSmallIcon, ArrowRightSmallIcon, CloseIcon, DeleteIcon, FilterIcon, InvisibleIcon, LayerIcon, LockIcon, MoreHorizontalIcon, PlusIcon, UnlockIcon, ViewIcon, } from '@blocksuite/icons/lit';
44
+ import { css, html, nothing, unsafeCSS } from 'lit';
45
+ import { state } from 'lit/decorators.js';
46
+ import { repeat } from 'lit/directives/repeat.js';
47
+ import { styleMap } from 'lit/directives/style-map.js';
48
+ import { literal, unsafeStatic } from 'lit/static-html.js';
49
+ import { SELECTION_PANE_ACTIVE_LAYER, SELECTION_PANE_CLOSE, SELECTION_PANE_COLLAPSE, SELECTION_PANE_DELETE_LAYER, SELECTION_PANE_EMPTY, SELECTION_PANE_EXPAND, SELECTION_PANE_FILTER, SELECTION_PANE_FILTER_ALL, SELECTION_PANE_FILTER_FRAME, SELECTION_PANE_LAYER_FILTERED, SELECTION_PANE_TITLE, SELECTION_PANE_HIDE, SELECTION_PANE_HIDE_FOR_EVERYONE, SELECTION_PANE_NEW_LAYER, SELECTION_PANE_ROW_MENU, SELECTION_PANE_SHOW, SELECTION_PANE_SHOW_FOR_EVERYONE, SELECTION_PANE_UNLOCK, } from '../translations.js';
50
+ import { paneDropAbove, paneLists, paneSlotAtGap, } from './drop.js';
51
+ import { selectionPaneRowIcon, selectionPaneRowLabel } from './labels.js';
52
+ export const EDGELESS_SELECTION_PANE_WIDGET = 'edgeless-selection-pane-widget';
53
+ /** The catalogue's measure: an icon, a label and a toggle, never most of a phone. */
54
+ const PANEL_WIDTH = 'min(320px, 85vw)';
55
+ /** Indent per nesting level, in px. */
56
+ const INDENT_PX = 16;
57
+ /**
58
+ * How the pane invokes the registry. The pane is not one of the registry's
59
+ * surfaces (a designed panel, not an enumeration of commands): like the
60
+ * contextual toolbar it acts on ONE element, the row's, and `source` says it
61
+ * came from the editor's chrome.
62
+ */
63
+ const PANE_INVOCATION = {
64
+ surface: 'contextual-toolbar',
65
+ source: 'toolbar:general',
66
+ };
67
+ function paneCommand(id) {
68
+ const command = [...selectionPaneCommands, ...userLayerCommands].find(c => c.id === id);
69
+ if (!command)
70
+ throw new Error(`selection pane: no command ${id}`);
71
+ return command;
72
+ }
73
+ /** `model.group`, or `null` where the getter throws (no surface holds it). */
74
+ function rawGroupOf(model) {
75
+ try {
76
+ return model.group ?? null;
77
+ }
78
+ catch {
79
+ return null;
80
+ }
81
+ }
82
+ /**
83
+ * The **selection pane** (ADR 0031, stage 2): the canvas elements by z-order,
84
+ * top first, the library's own panel behind `SelectionPaneProvider`.
85
+ *
86
+ * ## Docked like the artefact catalogue
87
+ *
88
+ * A full-height column down the left edge of the editor, inside it — the
89
+ * geometry, layer, zero-width host and wheel capture are the catalogue's, for
90
+ * the catalogue's reasons (see `artefact-catalogue-widget.ts`). What differs
91
+ * is the dismissal: the pane is a place you WORK from, its selection mirrors
92
+ * the canvas both ways, so a click on the canvas does not put it away. × and
93
+ * Escape (with the pointer or focus in the pane) do.
94
+ *
95
+ * ## Rows
96
+ *
97
+ * Drawn from `selectionPaneTree(std)` — the same headless tree a host pane
98
+ * would draw — and labelled at render time ({@link selectionPaneRowLabel}).
99
+ * A group or a mindmap is a collapsible row; collapse is this panel's state,
100
+ * never stored. Hover highlights the element on the canvas, click selects it
101
+ * (shift / ctrl / cmd adds or removes it, like on the canvas), the padlock
102
+ * locks that row alone, a double-click renames a group or a frame (a frame is
103
+ * a row at its place in the stack, ADR 0031 amendments), and a drag moves a row
104
+ * — or, pressed on a selected row, the whole selection of one stack — among
105
+ * its siblings (the side panels' one drag, ADR 0034). Every write goes through
106
+ * `runCommand`, so the read-only refusal and the undo step live in one place.
107
+ */
108
+ let EdgelessSelectionPaneWidget = (() => {
109
+ let _classSuper = WidgetComponent;
110
+ let __open_decorators;
111
+ let __open_initializers = [];
112
+ let __open_extraInitializers = [];
113
+ let __collapsed_decorators;
114
+ let __collapsed_initializers = [];
115
+ let __collapsed_extraInitializers = [];
116
+ let __filter_decorators;
117
+ let __filter_initializers = [];
118
+ let __filter_extraInitializers = [];
119
+ let __renaming_decorators;
120
+ let __renaming_initializers = [];
121
+ let __renaming_extraInitializers = [];
122
+ let __drop_decorators;
123
+ let __drop_initializers = [];
124
+ let __drop_extraInitializers = [];
125
+ let __ghost_decorators;
126
+ let __ghost_initializers = [];
127
+ let __ghost_extraInitializers = [];
128
+ let __selectionRevision_decorators;
129
+ let __selectionRevision_initializers = [];
130
+ let __selectionRevision_extraInitializers = [];
131
+ let __drag_decorators;
132
+ let __drag_initializers = [];
133
+ let __drag_extraInitializers = [];
134
+ return class EdgelessSelectionPaneWidget extends _classSuper {
135
+ constructor() {
136
+ super(...arguments);
137
+ this.#_open_accessor_storage = __runInitializers(this, __open_initializers, false);
138
+ this.#_collapsed_accessor_storage = (__runInitializers(this, __open_extraInitializers), __runInitializers(this, __collapsed_initializers, new Set()));
139
+ this.#_filter_accessor_storage = (__runInitializers(this, __collapsed_extraInitializers), __runInitializers(this, __filter_initializers, null));
140
+ this.#_renaming_accessor_storage = (__runInitializers(this, __filter_extraInitializers), __runInitializers(this, __renaming_initializers, null));
141
+ this.#_drop_accessor_storage = (__runInitializers(this, __renaming_extraInitializers), __runInitializers(this, __drop_initializers, null));
142
+ this.#_ghost_accessor_storage = (__runInitializers(this, __drop_extraInitializers), __runInitializers(this, __ghost_initializers, null));
143
+ this.#_selectionRevision_accessor_storage = (__runInitializers(this, __ghost_extraInitializers), __runInitializers(this, __selectionRevision_initializers, 0));
144
+ this.#_drag_accessor_storage = (__runInitializers(this, __selectionRevision_extraInitializers), __runInitializers(this, __drag_initializers, null));
145
+ /** The last row pressed: what a pick-up picks up. */
146
+ this._pressed = (__runInitializers(this, __drag_extraInitializers), null);
147
+ /** The side panels' one reorder gesture, wired in `_wire()`. */
148
+ this._reorder = null;
149
+ /** The rows of the last render, top first: what a drag hit-tests. */
150
+ this._visibleRows = [];
151
+ /** The sibling lists before the filter: what a drop is computed in. */
152
+ this._lists = paneLists([]);
153
+ /** Put the pane away. Writes nothing but its own state. */
154
+ this.closePanel = () => {
155
+ this._setOpen(false);
156
+ };
157
+ this._swallow = (event) => {
158
+ event.stopPropagation();
159
+ };
160
+ this._onHostKeydown = (event) => {
161
+ if (!this._open || event.key !== 'Escape')
162
+ return;
163
+ if (!event.composedPath().includes(this))
164
+ return;
165
+ if (this._renaming)
166
+ return;
167
+ event.stopPropagation();
168
+ // Escape during a drag never gets here: the drag controller cancels the
169
+ // drag and stops it in the capture phase, so the pane stays open.
170
+ this.closePanel();
171
+ };
172
+ /** Same capture as the catalogue: a wheel over the pane scrolls the pane. */
173
+ this._onHostWheel = (event) => {
174
+ if (!this._open)
175
+ return;
176
+ if (!event.composedPath().includes(this))
177
+ return;
178
+ event.stopPropagation();
179
+ };
180
+ this._onRenameKeydown = (event, id) => {
181
+ // The canvas behind binds Backspace, Delete and every letter: a key typed
182
+ // into the title must never reach it.
183
+ event.stopPropagation();
184
+ if (event.isComposing)
185
+ return;
186
+ if (event.key === 'Enter') {
187
+ event.preventDefault();
188
+ this._commitRename(id, event.currentTarget);
189
+ }
190
+ else if (event.key === 'Escape') {
191
+ event.preventDefault();
192
+ this._renaming = null;
193
+ }
194
+ };
195
+ this._openFilterMenu = (event) => {
196
+ const targets = selectionPaneFilterTargets(this.std);
197
+ popMenu(popupTargetFromElement(event.currentTarget), {
198
+ options: {
199
+ items: [
200
+ menu.action({
201
+ name: translateKey(this.std, ...SELECTION_PANE_FILTER_ALL),
202
+ isSelected: this._filter === null,
203
+ select: () => {
204
+ this._filter = null;
205
+ },
206
+ }),
207
+ ...targets.map(target => menu.action({
208
+ name: this._filterWording(target.id),
209
+ isSelected: this._filter === target.id,
210
+ select: () => {
211
+ this._filter = target.id;
212
+ },
213
+ })),
214
+ ],
215
+ },
216
+ });
217
+ };
218
+ /**
219
+ * "New layer": create it, then open its name for editing — the frame
220
+ * panel's inline title editor, as a double-click does — so the creation is
221
+ * unmistakable even under a filter (ADR 0031, amendments).
222
+ */
223
+ this._createLayer = () => {
224
+ const before = new Set(Object.keys(this._gfx.surface?.props.layers ?? {}));
225
+ this._run('canvas.layer.create', {});
226
+ const created = Object.keys(this._gfx.surface?.props.layers ?? {}).find(id => id !== DEFAULT_LAYER_ID && !before.has(id));
227
+ if (created)
228
+ this._renaming = created;
229
+ };
230
+ }
231
+ static {
232
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
233
+ __open_decorators = [state()];
234
+ __collapsed_decorators = [state()];
235
+ __filter_decorators = [state()];
236
+ __renaming_decorators = [state()];
237
+ __drop_decorators = [state()];
238
+ __ghost_decorators = [state()];
239
+ __selectionRevision_decorators = [state()];
240
+ __drag_decorators = [state()];
241
+ __esDecorate(this, null, __open_decorators, { kind: "accessor", name: "_open", static: false, private: false, access: { has: obj => "_open" in obj, get: obj => obj._open, set: (obj, value) => { obj._open = value; } }, metadata: _metadata }, __open_initializers, __open_extraInitializers);
242
+ __esDecorate(this, null, __collapsed_decorators, { kind: "accessor", name: "_collapsed", static: false, private: false, access: { has: obj => "_collapsed" in obj, get: obj => obj._collapsed, set: (obj, value) => { obj._collapsed = value; } }, metadata: _metadata }, __collapsed_initializers, __collapsed_extraInitializers);
243
+ __esDecorate(this, null, __filter_decorators, { kind: "accessor", name: "_filter", static: false, private: false, access: { has: obj => "_filter" in obj, get: obj => obj._filter, set: (obj, value) => { obj._filter = value; } }, metadata: _metadata }, __filter_initializers, __filter_extraInitializers);
244
+ __esDecorate(this, null, __renaming_decorators, { kind: "accessor", name: "_renaming", static: false, private: false, access: { has: obj => "_renaming" in obj, get: obj => obj._renaming, set: (obj, value) => { obj._renaming = value; } }, metadata: _metadata }, __renaming_initializers, __renaming_extraInitializers);
245
+ __esDecorate(this, null, __drop_decorators, { kind: "accessor", name: "_drop", static: false, private: false, access: { has: obj => "_drop" in obj, get: obj => obj._drop, set: (obj, value) => { obj._drop = value; } }, metadata: _metadata }, __drop_initializers, __drop_extraInitializers);
246
+ __esDecorate(this, null, __ghost_decorators, { kind: "accessor", name: "_ghost", static: false, private: false, access: { has: obj => "_ghost" in obj, get: obj => obj._ghost, set: (obj, value) => { obj._ghost = value; } }, metadata: _metadata }, __ghost_initializers, __ghost_extraInitializers);
247
+ __esDecorate(this, null, __selectionRevision_decorators, { kind: "accessor", name: "_selectionRevision", static: false, private: false, access: { has: obj => "_selectionRevision" in obj, get: obj => obj._selectionRevision, set: (obj, value) => { obj._selectionRevision = value; } }, metadata: _metadata }, __selectionRevision_initializers, __selectionRevision_extraInitializers);
248
+ __esDecorate(this, null, __drag_decorators, { kind: "accessor", name: "_drag", static: false, private: false, access: { has: obj => "_drag" in obj, get: obj => obj._drag, set: (obj, value) => { obj._drag = value; } }, metadata: _metadata }, __drag_initializers, __drag_extraInitializers);
249
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
250
+ }
251
+ static { this.styles = css `
252
+ ${panelHeaderStyles}
253
+
254
+ :host {
255
+ position: absolute;
256
+ left: 0;
257
+ top: 0;
258
+ bottom: 0;
259
+ width: 0;
260
+ z-index: ${unsafeCSS(EDITOR_ANCHORED_PANEL_Z_INDEX)};
261
+ pointer-events: none;
262
+ font-family: var(--affine-font-family);
263
+ }
264
+
265
+ .selection-pane-panel {
266
+ position: absolute;
267
+ left: 0;
268
+ top: 0;
269
+ bottom: 0;
270
+ width: ${unsafeCSS(PANEL_WIDTH)};
271
+ box-sizing: border-box;
272
+ display: flex;
273
+ flex-direction: column;
274
+ background: var(--affine-background-overlay-panel-color, #fff);
275
+ border-right: 1px solid var(--affine-border-color);
276
+ box-shadow: var(--affine-shadow-2);
277
+ color: var(--affine-text-primary-color);
278
+ font-size: 14px;
279
+ line-height: 1.4;
280
+ pointer-events: auto;
281
+ user-select: none;
282
+ }
283
+
284
+ .selection-pane-panel:focus-visible {
285
+ outline: 2px solid var(--affine-primary-color);
286
+ outline-offset: -2px;
287
+ }
288
+
289
+ /* The header row itself is the frame panel's (panelHeaderStyles). */
290
+ .selection-pane-actions {
291
+ flex: none;
292
+ display: flex;
293
+ align-items: center;
294
+ gap: 8px;
295
+ }
296
+
297
+ /* The pane's secondary text: the filter's name, a layer's filtered count. */
298
+ .selection-pane-filter-label,
299
+ .selection-pane-layer-note {
300
+ color: var(--affine-text-secondary-color);
301
+ font-size: 12px;
302
+ overflow: hidden;
303
+ text-overflow: ellipsis;
304
+ white-space: nowrap;
305
+ }
306
+
307
+ .selection-pane-filter-label {
308
+ padding: 6px 16px;
309
+ border-bottom: 1px solid var(--affine-border-color);
310
+ }
311
+
312
+ .selection-pane-layer-note {
313
+ padding-top: 2px;
314
+ padding-bottom: 4px;
315
+ }
316
+
317
+ .selection-pane-body {
318
+ position: relative;
319
+ flex: 1;
320
+ min-height: 0;
321
+ overflow-y: auto;
322
+ overflow-x: hidden;
323
+ overscroll-behavior: contain;
324
+ -webkit-overflow-scrolling: touch;
325
+ padding: 4px 0 16px;
326
+ }
327
+
328
+ .selection-pane-empty {
329
+ padding: 16px;
330
+ color: var(--affine-text-secondary-color);
331
+ }
332
+
333
+ .selection-pane-row {
334
+ display: flex;
335
+ align-items: center;
336
+ gap: 4px;
337
+ min-height: 32px;
338
+ box-sizing: border-box;
339
+ padding-right: 8px;
340
+ border-top: 2px solid transparent;
341
+ border-bottom: 2px solid transparent;
342
+ cursor: pointer;
343
+ }
344
+
345
+ @media (hover: hover) {
346
+ .selection-pane-row:hover {
347
+ background: var(--affine-hover-color);
348
+ }
349
+ }
350
+
351
+ .selection-pane-row[data-selected] {
352
+ background: var(--affine-hover-color);
353
+ color: var(--affine-primary-color);
354
+ }
355
+
356
+ /* The rows being dragged stay in place, dimmed, like the frame panel's
357
+ placeholder cards; the pressed row's ghost follows the pointer. */
358
+ .selection-pane-row[data-dragging] {
359
+ opacity: 0.5;
360
+ }
361
+
362
+ /* While dragging, the pane says whether a drop here would land. */
363
+ .selection-pane-panel[data-drag='valid'] {
364
+ cursor: grabbing;
365
+ }
366
+
367
+ .selection-pane-panel[data-drag='invalid'] {
368
+ cursor: not-allowed;
369
+ }
370
+
371
+ .selection-pane-panel[data-drag] * {
372
+ cursor: inherit;
373
+ }
374
+
375
+ /* The frame panel's insert indicator: a line at the gap a drop lands in. */
376
+ .selection-pane-drop-indicator {
377
+ position: absolute;
378
+ right: 8px;
379
+ height: 2px;
380
+ border-radius: 1px;
381
+ background: var(--affine-primary-color);
382
+ transform: translateY(-1px);
383
+ pointer-events: none;
384
+ }
385
+
386
+ /*
387
+ The drag mask, created by the drag controller (createPanelReorderDrag):
388
+ over the whole viewport for the length of the drag, so the cursor —
389
+ set inline by the controller, "grabbing" or "not-allowed" — speaks
390
+ wherever the pointer is, and the canvas under it takes no hover.
391
+ */
392
+ .selection-pane-drag-mask {
393
+ position: fixed;
394
+ inset: 0;
395
+ z-index: 1;
396
+ }
397
+
398
+ /* The row itself at its own width, like the frame panel's dragged card. */
399
+ .selection-pane-drag-ghost {
400
+ position: absolute;
401
+ top: 0;
402
+ left: 0;
403
+ z-index: 2;
404
+ display: flex;
405
+ align-items: center;
406
+ gap: 4px;
407
+ min-height: 32px;
408
+ box-sizing: border-box;
409
+ padding: 4px 8px;
410
+ border: 1px solid var(--affine-border-color);
411
+ border-radius: 4px;
412
+ background: var(--affine-background-overlay-panel-color);
413
+ box-shadow: var(--affine-shadow-2);
414
+ white-space: nowrap;
415
+ overflow: hidden;
416
+ pointer-events: none;
417
+ }
418
+
419
+ .selection-pane-drag-ghost .selection-pane-label {
420
+ flex: initial;
421
+ }
422
+
423
+ /* How many rows move with the ghost: the frame panel's card count. */
424
+ .selection-pane-drag-count {
425
+ flex: none;
426
+ margin-left: auto;
427
+ display: flex;
428
+ align-items: center;
429
+ justify-content: center;
430
+ min-width: 20px;
431
+ height: 20px;
432
+ padding: 0 4px;
433
+ box-sizing: border-box;
434
+ border-radius: 10px;
435
+ background: var(--affine-black);
436
+ color: var(--affine-white);
437
+ font-size: 12px;
438
+ line-height: 20px;
439
+ }
440
+
441
+ /* A row dragged onto a layer moves into it (ADR 0031 §5). */
442
+ .selection-pane-row[data-drop='into'] {
443
+ outline: 2px solid var(--affine-primary-color);
444
+ outline-offset: -2px;
445
+ }
446
+
447
+ .selection-pane-layer-row {
448
+ font-weight: 600;
449
+ }
450
+
451
+ /* The active layer: where this viewer's new elements land. */
452
+ .selection-pane-layer-row[data-active] .selection-pane-label,
453
+ .selection-pane-layer-row[data-active] .selection-pane-icon {
454
+ color: var(--affine-primary-color);
455
+ }
456
+
457
+ .selection-pane-chevron,
458
+ .selection-pane-eye,
459
+ .selection-pane-lock,
460
+ .selection-pane-more {
461
+ flex: none;
462
+ display: flex;
463
+ align-items: center;
464
+ justify-content: center;
465
+ width: 24px;
466
+ height: 24px;
467
+ padding: 0;
468
+ border: none;
469
+ border-radius: 4px;
470
+ background: transparent;
471
+ color: var(--affine-icon-color);
472
+ cursor: pointer;
473
+ }
474
+
475
+ .selection-pane-chevron svg,
476
+ .selection-pane-eye svg,
477
+ .selection-pane-lock svg,
478
+ .selection-pane-more svg,
479
+ .selection-pane-icon svg {
480
+ width: 16px;
481
+ height: 16px;
482
+ }
483
+
484
+ .selection-pane-chevron:hover,
485
+ .selection-pane-eye:hover,
486
+ .selection-pane-lock:hover,
487
+ .selection-pane-more:hover {
488
+ background: var(--affine-hover-color);
489
+ }
490
+
491
+ .selection-pane-chevron[hidden] {
492
+ visibility: hidden;
493
+ }
494
+
495
+ /*
496
+ Off states show on hover only, like PowerPoint's pane: a column of open
497
+ eyes and open padlocks on every row would be noise. A hidden or locked
498
+ row keeps its mark visible, which is what makes it findable.
499
+ */
500
+ .selection-pane-eye[aria-pressed='false'],
501
+ .selection-pane-lock[aria-pressed='false'],
502
+ .selection-pane-more {
503
+ opacity: 0;
504
+ }
505
+
506
+ .selection-pane-row:hover .selection-pane-eye,
507
+ .selection-pane-row:hover .selection-pane-lock,
508
+ .selection-pane-row:hover .selection-pane-more,
509
+ .selection-pane-eye:focus-visible,
510
+ .selection-pane-lock:focus-visible,
511
+ .selection-pane-more:focus-visible {
512
+ opacity: 1;
513
+ }
514
+
515
+ .selection-pane-row[data-hidden-local] .selection-pane-label,
516
+ .selection-pane-row[data-hidden-local] .selection-pane-icon {
517
+ opacity: 0.5;
518
+ }
519
+
520
+ .selection-pane-row[data-hidden-everyone] .selection-pane-label,
521
+ .selection-pane-layer-row[data-hidden-local] .selection-pane-label {
522
+ opacity: 0.5;
523
+ }
524
+
525
+ /* Hidden for everyone: the theme warning token marks what others cannot see. */
526
+ .selection-pane-row[data-hidden-everyone] .selection-pane-icon {
527
+ color: var(--affine-warning-color);
528
+ }
529
+
530
+ .selection-pane-lock:disabled {
531
+ cursor: default;
532
+ color: var(--affine-text-disable-color);
533
+ }
534
+
535
+ .selection-pane-icon {
536
+ flex: none;
537
+ display: flex;
538
+ align-items: center;
539
+ color: var(--affine-icon-color);
540
+ }
541
+
542
+ .selection-pane-label {
543
+ flex: 1;
544
+ min-width: 0;
545
+ overflow: hidden;
546
+ text-overflow: ellipsis;
547
+ white-space: nowrap;
548
+ }
549
+
550
+ .selection-pane-rename {
551
+ flex: 1;
552
+ min-width: 0;
553
+ padding: 2px 6px;
554
+ border: 1px solid var(--affine-border-color);
555
+ border-radius: 4px;
556
+ background: var(--affine-background-primary-color);
557
+ color: inherit;
558
+ font: inherit;
559
+ outline: none;
560
+ }
561
+
562
+ .selection-pane-rename:focus {
563
+ box-shadow: var(--affine-active-shadow);
564
+ border-color: var(--affine-primary-color);
565
+ }
566
+ `; }
567
+ #_open_accessor_storage;
568
+ get _open() { return this.#_open_accessor_storage; }
569
+ set _open(value) { this.#_open_accessor_storage = value; }
570
+ #_collapsed_accessor_storage;
571
+ /** Group rows the user folded. UI state, never stored. */
572
+ get _collapsed() { return this.#_collapsed_accessor_storage; }
573
+ set _collapsed(value) { this.#_collapsed_accessor_storage = value; }
574
+ #_filter_accessor_storage;
575
+ /** The frame the list is narrowed to, or `null`. */
576
+ get _filter() { return this.#_filter_accessor_storage; }
577
+ set _filter(value) { this.#_filter_accessor_storage = value; }
578
+ #_renaming_accessor_storage;
579
+ /** The group row being renamed, or `null`. */
580
+ get _renaming() { return this.#_renaming_accessor_storage; }
581
+ set _renaming(value) { this.#_renaming_accessor_storage = value; }
582
+ #_drop_accessor_storage;
583
+ /** Where the dragged rows would land; `null` while refused. */
584
+ get _drop() { return this.#_drop_accessor_storage; }
585
+ set _drop(value) { this.#_drop_accessor_storage = value; }
586
+ #_ghost_accessor_storage;
587
+ /** Where the dragged row's ghost is drawn, in the panel's own box. */
588
+ get _ghost() { return this.#_ghost_accessor_storage; }
589
+ set _ghost(value) { this.#_ghost_accessor_storage = value; }
590
+ #_selectionRevision_accessor_storage;
591
+ /** Bumped when the canvas selection changes, so the rows repaint. */
592
+ get _selectionRevision() { return this.#_selectionRevision_accessor_storage; }
593
+ set _selectionRevision(value) { this.#_selectionRevision_accessor_storage = value; }
594
+ #_drag_accessor_storage;
595
+ /** The drag under way, from its pick-up to its end. */
596
+ get _drag() { return this.#_drag_accessor_storage; }
597
+ set _drag(value) { this.#_drag_accessor_storage = value; }
598
+ get paneOpen() {
599
+ return this._open;
600
+ }
601
+ get _gfx() {
602
+ return this.std.get(GfxControllerIdentifier);
603
+ }
604
+ _setOpen(open) {
605
+ this._open = open;
606
+ const model = this.std.getOptional(SelectionPaneModel);
607
+ if (model)
608
+ model.open$.value = open;
609
+ if (!open) {
610
+ this._renaming = null;
611
+ this._clearHighlight();
612
+ }
613
+ }
614
+ /** Show the pane. Called through `SelectionPaneProvider` only. */
615
+ openPanel() {
616
+ this._setOpen(true);
617
+ }
618
+ _wire() {
619
+ const host = this.std.host;
620
+ host.addEventListener('keydown', this._onHostKeydown, true);
621
+ host.addEventListener('wheel', this._onHostWheel, true);
622
+ const subscription = this._gfx.selection.slots.updated.subscribe(() => {
623
+ this._selectionRevision++;
624
+ });
625
+ const reorder = this._createReorderDrag();
626
+ this._reorder = reorder;
627
+ this._disposables.add(() => {
628
+ host.removeEventListener('keydown', this._onHostKeydown, true);
629
+ host.removeEventListener('wheel', this._onHostWheel, true);
630
+ subscription.unsubscribe();
631
+ reorder.dispose();
632
+ if (this._reorder === reorder)
633
+ this._reorder = null;
634
+ });
635
+ }
636
+ connectedCallback() {
637
+ super.connectedCallback();
638
+ if (this.hasUpdated)
639
+ this._wire();
640
+ }
641
+ firstUpdated() {
642
+ this._wire();
643
+ }
644
+ disconnectedCallback() {
645
+ super.disconnectedCallback();
646
+ const model = this.std.getOptional(SelectionPaneModel);
647
+ if (model)
648
+ model.open$.value = false;
649
+ }
650
+ /* ── Canvas mirrors ─────────────────────────────────────────────────── */
651
+ _highlight(id) {
652
+ this._gfx.highlightElements([id], { duration: 0 });
653
+ }
654
+ _clearHighlight() {
655
+ this._gfx.highlight.clear();
656
+ }
657
+ _select(event, node) {
658
+ const { selection } = this._gfx;
659
+ if (event.shiftKey || event.metaKey || event.ctrlKey) {
660
+ const ids = new Set(selection.selectedIds);
661
+ if (ids.has(node.id))
662
+ ids.delete(node.id);
663
+ else
664
+ ids.add(node.id);
665
+ selection.set({ elements: [...ids], editing: false });
666
+ return;
667
+ }
668
+ selection.set({ elements: [node.id], editing: false });
669
+ }
670
+ _run(id, params) {
671
+ runCommand(this.std, paneCommand(id), PANE_INVOCATION, params);
672
+ }
673
+ /* ── Rows ───────────────────────────────────────────────────────────── */
674
+ /**
675
+ * The visible rows of `nodes` (the tree as filtered), with `full` the tree
676
+ * before the filter: what tells a layer emptied by the filter from an empty
677
+ * one.
678
+ */
679
+ _rows(nodes, full = nodes) {
680
+ const membersOf = new Map(full
681
+ .filter(node => node.kind === 'layer')
682
+ .map(node => [node.id, node.children?.length ?? 0]));
683
+ const rows = [];
684
+ const walk = (list, depth, parent) => {
685
+ for (const node of list) {
686
+ const row = { node, depth, parent };
687
+ if (node.kind === 'layer' && node.children?.length === 0) {
688
+ const members = membersOf.get(node.id) ?? 0;
689
+ if (members > 0)
690
+ row.hiddenByFilter = members;
691
+ }
692
+ rows.push(row);
693
+ if (node.children && !this._collapsed.has(node.id)) {
694
+ walk(node.children, depth + 1, node.id);
695
+ }
696
+ }
697
+ };
698
+ walk(nodes, 0, '');
699
+ return rows;
700
+ }
701
+ _toggleCollapsed(id) {
702
+ const next = new Set(this._collapsed);
703
+ if (next.has(id))
704
+ next.delete(id);
705
+ else
706
+ next.add(id);
707
+ this._collapsed = next;
708
+ }
709
+ _onRowClick(event, node) {
710
+ // A drag ends with a click on the row it started on; that click is not one.
711
+ if (this._reorder?.consumeSwallowedClick())
712
+ return;
713
+ // A layer row is not on the canvas: a click makes it the active layer,
714
+ // where this viewer's new elements land (session only, never stored).
715
+ if (node.kind === 'layer') {
716
+ this.std.getOptional(CanvasActiveLayer)?.choose(node.id);
717
+ return;
718
+ }
719
+ this._select(event, node);
720
+ }
721
+ _onRowDblClick(node) {
722
+ if (this.std.store.readonly)
723
+ return;
724
+ if (node.type !== 'group' &&
725
+ node.type !== 'affine:frame' &&
726
+ node.kind !== 'layer') {
727
+ return;
728
+ }
729
+ this._renaming = node.id;
730
+ }
731
+ /** A layer's name — the default layer's seed while it has no record. */
732
+ _layerName(id) {
733
+ return userLayerName(this.std, id);
734
+ }
735
+ _onLockClick(event, node) {
736
+ event.stopPropagation();
737
+ this._run(node.locked ? 'canvas.element.unlock' : 'canvas.element.lock', {
738
+ ids: [node.id],
739
+ });
740
+ }
741
+ /**
742
+ * Hide this row for this viewer, or show it again. Not refused on a
743
+ * read-only document: nothing reaches the document (ADR 0031 §8).
744
+ */
745
+ _onEyeClick(event, node) {
746
+ event.stopPropagation();
747
+ // A layer's eye hides the whole layer for this viewer (stage 7).
748
+ const target = node.kind === 'layer' ? { layerIds: [node.id] } : { ids: [node.id] };
749
+ this._run('canvas.visibility.hideLocal', {
750
+ ...target,
751
+ hidden: !node.hiddenLocal,
752
+ });
753
+ }
754
+ /**
755
+ * The row's menu: the actions that write to the DOCUMENT for every viewer,
756
+ * kept off the row's quick toggles so they are never one stray click away.
757
+ * "Hide for everyone" is painted with the theme warning tokens (ADR 0031,
758
+ * resolved at acceptance). A read-only document offers none of them, so the
759
+ * menu does not open there.
760
+ */
761
+ _openRowMenu(anchor, node) {
762
+ if (this.std.store.readonly)
763
+ return;
764
+ if (node.kind === 'layer') {
765
+ this._openLayerMenu(anchor, node);
766
+ return;
767
+ }
768
+ popMenu(popupTargetFromElement(anchor), {
769
+ options: { items: [this._hideForEveryoneItem(node)] },
770
+ });
771
+ }
772
+ /**
773
+ * "Hide for everyone" (or "Show for everyone"), in a row's or a layer's
774
+ * menu alike: painted with the warning tokens, and written on the element
775
+ * or on the layer's record (`hidden: true`) depending on the row.
776
+ */
777
+ _hideForEveryoneItem(node) {
778
+ const wording = node.hiddenForEveryone
779
+ ? SELECTION_PANE_SHOW_FOR_EVERYONE
780
+ : SELECTION_PANE_HIDE_FOR_EVERYONE;
781
+ const target = node.kind === 'layer' ? { layerIds: [node.id] } : { ids: [node.id] };
782
+ return menu.action({
783
+ name: translateKey(this.std, ...wording),
784
+ prefix: node.hiddenForEveryone ? ViewIcon() : InvisibleIcon(),
785
+ class: { 'warning-item': true },
786
+ testId: 'selection-pane-hide-for-everyone',
787
+ select: () => {
788
+ this._run('canvas.visibility.hideForEveryone', {
789
+ ...target,
790
+ hidden: !node.hiddenForEveryone,
791
+ });
792
+ },
793
+ });
794
+ }
795
+ /**
796
+ * A layer's menu (ADR 0031 stage 7): "Hide for everyone" — `hidden: true`
797
+ * on the record, painted with the warning tokens like the element entry —
798
+ * and "Delete layer", which takes the members with it in one undo step.
799
+ * The default layer cannot be deleted, so its menu has no such entry.
800
+ */
801
+ _openLayerMenu(anchor, node) {
802
+ popMenu(popupTargetFromElement(anchor), {
803
+ options: {
804
+ items: [
805
+ this._hideForEveryoneItem(node),
806
+ menu.action({
807
+ name: translateKey(this.std, ...SELECTION_PANE_DELETE_LAYER),
808
+ prefix: DeleteIcon(),
809
+ class: { 'delete-item': true },
810
+ testId: 'selection-pane-delete-layer',
811
+ hide: () => node.id === DEFAULT_LAYER_ID,
812
+ select: () => {
813
+ this._run('canvas.layer.delete', { id: node.id });
814
+ },
815
+ }),
816
+ ],
817
+ },
818
+ });
819
+ }
820
+ _onRowContextMenu(event, node) {
821
+ event.preventDefault();
822
+ event.stopPropagation();
823
+ this._openRowMenu(event.currentTarget, node);
824
+ }
825
+ _commitRename(id, input) {
826
+ if (this._renaming !== id)
827
+ return;
828
+ this._renaming = null;
829
+ if (this._layerName(id) !== null) {
830
+ this._run('canvas.layer.rename', { id, name: input.value });
831
+ return;
832
+ }
833
+ const frame = this._gfx.getElementById(id) instanceof FrameBlockModel;
834
+ this._run(frame ? 'canvas.frame.rename' : 'canvas.group.rename', {
835
+ id,
836
+ title: input.value,
837
+ });
838
+ }
839
+ /* ── Drag to reorder ────────────────────────────────────────────────── */
840
+ /*
841
+ * The gesture is the side panels' one controller (`createPanelReorderDrag`,
842
+ * `@labre/affine-shared/utils`, ADR 0034), shared with the frame panel:
843
+ * threshold, read-only refusal, mask and cursor, Escape and `pointercancel`
844
+ * as cancels, the swallowed click. What is the pane's own is below: which
845
+ * rows move (the pressed row, or the whole selection of one stack), where a
846
+ * gap lands them in their stack, the ghost and the line, and the write.
847
+ */
848
+ _createReorderDrag() {
849
+ return createPanelReorderDrag({
850
+ readonly: () => this.std.store.readonly,
851
+ rows: () => this._shownRows().map(({ element }) => element),
852
+ bounds: () => this._paneBody(),
853
+ onPickUp: () => this._pickUp(),
854
+ dropAt: (gap, point) => this._dropAt(gap, point.clientY),
855
+ onMove: (drop, point) => {
856
+ this._drop = drop;
857
+ const panel = this._panel();
858
+ if (!panel)
859
+ return;
860
+ const box = panel.getBoundingClientRect();
861
+ this._ghost = {
862
+ x: point.clientX - box.left,
863
+ y: point.clientY - box.top,
864
+ };
865
+ },
866
+ onDrop: drop => this._commitDrop(drop),
867
+ onEnd: () => {
868
+ this._drag = null;
869
+ this._drop = null;
870
+ this._ghost = null;
871
+ },
872
+ mask: {
873
+ host: () => this._panel(),
874
+ className: 'selection-pane-drag-mask',
875
+ testId: 'selection-pane-drag-mask',
876
+ },
877
+ stateHost: () => this._panel(),
878
+ });
879
+ }
880
+ _panel() {
881
+ return (this.shadowRoot?.querySelector('[data-testid="selection-pane-panel"]') ?? null);
882
+ }
883
+ _paneBody() {
884
+ return (this.shadowRoot?.querySelector('[data-testid="selection-pane-body"]') ?? null);
885
+ }
886
+ /** The rows on screen, top first, with the rows they draw. */
887
+ _shownRows() {
888
+ const body = this._paneBody();
889
+ if (!body)
890
+ return [];
891
+ const byId = new Map(this._visibleRows.map(row => [row.node.id, row]));
892
+ return Array.from(body.querySelectorAll('[data-testid="selection-pane-row"], [data-testid="selection-pane-layer"]')).flatMap(element => {
893
+ const row = byId.get(element.dataset.id ?? '');
894
+ return row ? [{ element, row }] : [];
895
+ });
896
+ }
897
+ _onRowPointerDown(event, row) {
898
+ const target = event.target;
899
+ if (target.closest('button, input'))
900
+ return;
901
+ this._pressed = {
902
+ row,
903
+ width: event.currentTarget.getBoundingClientRect().width,
904
+ };
905
+ this._reorder?.press(event);
906
+ }
907
+ /**
908
+ * The press became a drag. A canvas row picked up is selected, as the frame
909
+ * panel selects a card — unless it already is, and then the whole selection
910
+ * moves with it, as in the frame panel: every selected row the pane lists.
911
+ * Rows that are not all in the pressed row's stack and list have no one
912
+ * place to land, so every drop of theirs is refused, honestly, with a
913
+ * `not-allowed` cursor rather than a line that would write nothing.
914
+ */
915
+ _pickUp() {
916
+ const pressed = this._pressed;
917
+ if (!pressed)
918
+ return;
919
+ const { node, parent } = pressed.row;
920
+ const drag = {
921
+ id: node.id,
922
+ kind: node.kind,
923
+ parent,
924
+ width: pressed.width,
925
+ moving: new Set([node.id]),
926
+ refused: false,
927
+ };
928
+ if (node.kind !== 'layer') {
929
+ const { selection } = this._gfx;
930
+ if (selection.selectedIds.includes(node.id)) {
931
+ const listed = selection.selectedIds.filter(id => this._lists.parentOf.has(id));
932
+ drag.moving = new Set([node.id, ...listed]);
933
+ const stackOf = this._stackOf(drag);
934
+ drag.refused = [...drag.moving].some(id => this._lists.parentOf.get(id) !== parent || stackOf?.(id) !== id);
935
+ }
936
+ else {
937
+ selection.set({ elements: [node.id], editing: false });
938
+ }
939
+ }
940
+ this._drag = drag;
941
+ }
942
+ /**
943
+ * Which model stands for a row in the dragged row's own stack — the stack
944
+ * `canvas.element.reorder` restacks it in, the models sharing its raw
945
+ * `group` — or `undefined` for a row outside it. A frame's members paint
946
+ * together right above the frame, so for a loose element they stand for
947
+ * their frame. `null` when the dragged row cannot be restacked at all (a
948
+ * mindmap node moves with its mindmap).
949
+ */
950
+ _stackOf(drag) {
951
+ if (drag.kind === 'layer')
952
+ return id => id;
953
+ const gfx = this._gfx;
954
+ const dragged = gfx.getElementById(drag.id);
955
+ if (!dragged)
956
+ return null;
957
+ const stack = rawGroupOf(dragged);
958
+ if (stack instanceof MindmapElementModel)
959
+ return null;
960
+ return id => {
961
+ let model = gfx.getElementById(id);
962
+ for (let hops = 0; model && hops < 32; hops++) {
963
+ const group = rawGroupOf(model);
964
+ if (group === stack)
965
+ return model.id;
966
+ model = group;
967
+ }
968
+ return undefined;
969
+ };
970
+ }
971
+ /**
972
+ * Where a release over the gap `gap` (the controller's count of rows whose
973
+ * middle is above the pointer, at `clientY`) would land the dragged rows,
974
+ * or `null` to refuse it.
975
+ */
976
+ _dropAt(gap, clientY) {
977
+ const drag = this._drag;
978
+ if (!drag || drag.refused)
979
+ return null;
980
+ const shown = this._shownRows();
981
+ // A canvas row over a layer's header moves INTO that layer (§5).
982
+ if (drag.kind !== 'layer') {
983
+ const header = shown.find(({ element, row }) => {
984
+ if (row.node.kind !== 'layer')
985
+ return false;
986
+ const rect = element.getBoundingClientRect();
987
+ return clientY >= rect.top && clientY <= rect.bottom;
988
+ });
989
+ if (header)
990
+ return { kind: 'into', id: header.row.node.id };
991
+ }
992
+ const stackOf = this._stackOf(drag);
993
+ const slot = stackOf
994
+ ? paneSlotAtGap(shown.map(({ row }) => row), gap, drag.parent, this._lists)
995
+ : null;
996
+ const list = slot ? this._lists.lists.get(slot.parent) : undefined;
997
+ const landing = slot && list && stackOf
998
+ ? paneDropAbove(list, slot.index, drag.moving, stackOf)
999
+ : null;
1000
+ if (!slot || !landing)
1001
+ return null;
1002
+ const under = shown[gap]?.element;
1003
+ const last = shown[shown.length - 1]?.element;
1004
+ const top = under
1005
+ ? under.offsetTop
1006
+ : last
1007
+ ? last.offsetTop + last.offsetHeight
1008
+ : 0;
1009
+ return {
1010
+ kind: 'slot',
1011
+ above: landing.above,
1012
+ top,
1013
+ left: 8 + slot.depth * INDENT_PX,
1014
+ };
1015
+ }
1016
+ /**
1017
+ * One write per gesture, through the command: `layer` for a drop into a
1018
+ * layer, one restack for a slot. The command writes nothing when the slot
1019
+ * is where the rows already are, and a refused drop never reaches it.
1020
+ */
1021
+ _commitDrop(drop) {
1022
+ const drag = this._drag;
1023
+ if (!drag)
1024
+ return;
1025
+ const ids = [...drag.moving];
1026
+ if (drop.kind === 'into') {
1027
+ this._run('canvas.layer.moveElements', { ids, layerId: drop.id });
1028
+ return;
1029
+ }
1030
+ if (drag.kind === 'layer') {
1031
+ this._run('canvas.layer.reorder', { id: drag.id, above: drop.above });
1032
+ return;
1033
+ }
1034
+ this._run('canvas.element.reorder', { ids, above: drop.above });
1035
+ }
1036
+ _renderGhost() {
1037
+ const drag = this._drag;
1038
+ const at = this._ghost;
1039
+ if (!drag || !at)
1040
+ return nothing;
1041
+ const style = styleMap({
1042
+ transform: `translate(${at.x - 16}px, ${at.y - 8}px)`,
1043
+ width: `${drag.width}px`,
1044
+ });
1045
+ if (drag.kind === 'layer') {
1046
+ return html `<div
1047
+ class="selection-pane-drag-ghost"
1048
+ data-testid="selection-pane-drag-ghost"
1049
+ style=${style}
1050
+ >
1051
+ <span class="selection-pane-icon">${LayerIcon()}</span>
1052
+ <span class="selection-pane-label"
1053
+ >${this._layerName(drag.id) ?? ''}</span
1054
+ >
1055
+ </div>`;
1056
+ }
1057
+ const model = this._gfx.getElementById(drag.id);
1058
+ if (!model)
1059
+ return nothing;
1060
+ const type = model instanceof GfxBlockElementModel
1061
+ ? model.flavour
1062
+ : model.type;
1063
+ const count = drag.moving.size;
1064
+ return html `<div
1065
+ class="selection-pane-drag-ghost"
1066
+ data-testid="selection-pane-drag-ghost"
1067
+ style=${style}
1068
+ >
1069
+ <span class="selection-pane-icon">${selectionPaneRowIcon(type)}</span>
1070
+ <span class="selection-pane-label"
1071
+ >${selectionPaneRowLabel(this.std, model)}</span
1072
+ >
1073
+ ${count > 1
1074
+ ? html `<span
1075
+ class="selection-pane-drag-count"
1076
+ data-testid="selection-pane-drag-count"
1077
+ >${count}</span
1078
+ >`
1079
+ : nothing}
1080
+ </div>`;
1081
+ }
1082
+ _renderDropIndicator() {
1083
+ const drop = this._drop;
1084
+ if (!this._drag || drop?.kind !== 'slot')
1085
+ return nothing;
1086
+ return html `<div
1087
+ class="selection-pane-drop-indicator"
1088
+ data-testid="selection-pane-drop-indicator"
1089
+ style=${styleMap({ top: `${drop.top}px`, left: `${drop.left}px` })}
1090
+ ></div>`;
1091
+ }
1092
+ /* ── Filter ─────────────────────────────────────────────────────────── */
1093
+ _filterName(id) {
1094
+ const model = this._gfx.getElementById(id);
1095
+ return model ? selectionPaneRowLabel(this.std, model) : id;
1096
+ }
1097
+ _filterWording(id) {
1098
+ return translateKey(this.std, ...SELECTION_PANE_FILTER_FRAME, {
1099
+ name: this._filterName(id),
1100
+ });
1101
+ }
1102
+ /* ── Render ─────────────────────────────────────────────────────────── */
1103
+ /**
1104
+ * A user layer's row (ADR 0031 §2): its name, renamed in place with a
1105
+ * double-click; a click makes it the active layer; collapsible like a
1106
+ * group (UI state, never stored); dragged among the layers to reorder, and
1107
+ * the drop target of a canvas row dragged onto it. The default layer's row
1108
+ * is drawn the same before it has a record (ADR 0031 amendments): its
1109
+ * rename or "hide for everyone" is what records it.
1110
+ */
1111
+ _renderLayerRow(row) {
1112
+ const { node, depth } = row;
1113
+ const std = this.std;
1114
+ const name = this._layerName(node.id) ?? '';
1115
+ const collapsed = this._collapsed.has(node.id);
1116
+ const active = (std.getOptional(CanvasActiveLayer)?.resolve() ?? null) === node.id;
1117
+ const drop = this._drop?.kind === 'into' && this._drop.id === node.id
1118
+ ? 'into'
1119
+ : undefined;
1120
+ const dragging = this._drag?.moving.has(node.id) ?? false;
1121
+ return html `<div
1122
+ class="selection-pane-row selection-pane-layer-row"
1123
+ role="treeitem"
1124
+ data-testid="selection-pane-layer"
1125
+ data-id=${node.id}
1126
+ data-kind="layer"
1127
+ aria-level=${depth + 1}
1128
+ aria-expanded=${collapsed ? 'false' : 'true'}
1129
+ title=${active
1130
+ ? translateKey(std, ...SELECTION_PANE_ACTIVE_LAYER)
1131
+ : nothing}
1132
+ ?data-active=${active}
1133
+ ?data-hidden-local=${node.hiddenLocal}
1134
+ ?data-hidden-everyone=${node.hiddenForEveryone}
1135
+ ?data-dragging=${dragging}
1136
+ data-drop=${drop ?? nothing}
1137
+ style=${styleMap({ paddingLeft: `${8 + depth * INDENT_PX}px` })}
1138
+ @click=${(event) => this._onRowClick(event, node)}
1139
+ @dblclick=${() => this._onRowDblClick(node)}
1140
+ @contextmenu=${(event) => this._onRowContextMenu(event, node)}
1141
+ @pointerdown=${(event) => this._onRowPointerDown(event, row)}
1142
+ >
1143
+ <button
1144
+ class="selection-pane-chevron"
1145
+ type="button"
1146
+ data-testid="selection-pane-collapse"
1147
+ aria-label=${translateKey(std, ...(collapsed ? SELECTION_PANE_EXPAND : SELECTION_PANE_COLLAPSE))}
1148
+ @click=${(event) => {
1149
+ event.stopPropagation();
1150
+ this._toggleCollapsed(node.id);
1151
+ }}
1152
+ >
1153
+ ${collapsed ? ArrowRightSmallIcon() : ArrowDownSmallIcon()}
1154
+ </button>
1155
+ <span class="selection-pane-icon">${LayerIcon()}</span>
1156
+ ${this._renderName(node.id, name)} ${this._renderEye(node)}
1157
+ ${std.store.readonly
1158
+ ? nothing
1159
+ : html `<button
1160
+ class="selection-pane-more"
1161
+ type="button"
1162
+ data-testid="selection-pane-more"
1163
+ aria-haspopup="menu"
1164
+ aria-label=${translateKey(std, ...SELECTION_PANE_ROW_MENU)}
1165
+ @click=${(event) => {
1166
+ event.stopPropagation();
1167
+ this._openRowMenu(event.currentTarget, node);
1168
+ }}
1169
+ >
1170
+ ${MoreHorizontalIcon()}
1171
+ </button>`}
1172
+ </div>
1173
+ ${row.hiddenByFilter && !collapsed
1174
+ ? html `<div
1175
+ class="selection-pane-layer-note"
1176
+ data-testid="selection-pane-layer-filtered"
1177
+ data-id=${node.id}
1178
+ style=${styleMap({
1179
+ paddingLeft: `${8 + (depth + 1) * INDENT_PX + 28}px`,
1180
+ })}
1181
+ >
1182
+ ${translateKey(std, ...SELECTION_PANE_LAYER_FILTERED, {
1183
+ count: row.hiddenByFilter,
1184
+ })}
1185
+ </div>`
1186
+ : nothing}`;
1187
+ }
1188
+ /** A row's name, or the field that renames it in place. */
1189
+ _renderName(id, name) {
1190
+ if (this._renaming !== id) {
1191
+ return html `<span class="selection-pane-label" title=${name}
1192
+ >${name}</span
1193
+ >`;
1194
+ }
1195
+ return html `<input
1196
+ class="selection-pane-rename"
1197
+ data-testid="selection-pane-rename"
1198
+ aria-label=${translateKey(this.std, ...TOOLBAR_RENAME)}
1199
+ .value=${name}
1200
+ @click=${this._swallow}
1201
+ @dblclick=${this._swallow}
1202
+ @keydown=${(event) => this._onRenameKeydown(event, id)}
1203
+ @blur=${(event) => this._commitRename(id, event.target)}
1204
+ />`;
1205
+ }
1206
+ /** A row's eye: hide it, or the whole layer, for this viewer only. */
1207
+ _renderEye(node) {
1208
+ return html `<button
1209
+ class="selection-pane-eye"
1210
+ type="button"
1211
+ data-testid="selection-pane-eye"
1212
+ aria-pressed=${node.hiddenLocal ? 'true' : 'false'}
1213
+ aria-label=${translateKey(this.std, ...(node.hiddenLocal ? SELECTION_PANE_SHOW : SELECTION_PANE_HIDE))}
1214
+ @click=${(event) => this._onEyeClick(event, node)}
1215
+ >
1216
+ ${node.hiddenLocal ? InvisibleIcon() : ViewIcon()}
1217
+ </button>`;
1218
+ }
1219
+ _renderRow(row) {
1220
+ const { node, depth } = row;
1221
+ if (node.kind === 'layer')
1222
+ return this._renderLayerRow(row);
1223
+ const std = this.std;
1224
+ const model = this._gfx.getElementById(node.id);
1225
+ if (!model)
1226
+ return nothing;
1227
+ const label = selectionPaneRowLabel(std, model);
1228
+ const selected = this._gfx.selection.has(node.id);
1229
+ const container = node.children !== undefined;
1230
+ const collapsed = this._collapsed.has(node.id);
1231
+ const readonly = std.store.readonly;
1232
+ const drop = this._drop?.kind === 'into' && this._drop.id === node.id
1233
+ ? 'into'
1234
+ : undefined;
1235
+ const dragging = this._drag?.moving.has(node.id) ?? false;
1236
+ return html `<div
1237
+ class="selection-pane-row"
1238
+ role="treeitem"
1239
+ data-testid="selection-pane-row"
1240
+ data-id=${node.id}
1241
+ data-type=${node.type}
1242
+ data-kind=${node.kind}
1243
+ aria-level=${depth + 1}
1244
+ aria-selected=${selected ? 'true' : 'false'}
1245
+ aria-expanded=${container ? (collapsed ? 'false' : 'true') : nothing}
1246
+ ?data-selected=${selected}
1247
+ ?data-locked=${node.locked}
1248
+ ?data-hidden-local=${node.hiddenLocal}
1249
+ ?data-hidden-everyone=${node.hiddenForEveryone}
1250
+ ?data-dragging=${dragging}
1251
+ data-drop=${drop ?? nothing}
1252
+ style=${styleMap({ paddingLeft: `${8 + depth * INDENT_PX}px` })}
1253
+ @click=${(event) => this._onRowClick(event, node)}
1254
+ @contextmenu=${(event) => this._onRowContextMenu(event, node)}
1255
+ @dblclick=${() => this._onRowDblClick(node)}
1256
+ @pointerenter=${() => this._highlight(node.id)}
1257
+ @pointerdown=${(event) => this._onRowPointerDown(event, row)}
1258
+ >
1259
+ <button
1260
+ class="selection-pane-chevron"
1261
+ type="button"
1262
+ data-testid="selection-pane-collapse"
1263
+ ?hidden=${!container}
1264
+ aria-label=${translateKey(std, ...(collapsed ? SELECTION_PANE_EXPAND : SELECTION_PANE_COLLAPSE))}
1265
+ @click=${(event) => {
1266
+ event.stopPropagation();
1267
+ this._toggleCollapsed(node.id);
1268
+ }}
1269
+ >
1270
+ ${collapsed ? ArrowRightSmallIcon() : ArrowDownSmallIcon()}
1271
+ </button>
1272
+ <span class="selection-pane-icon"
1273
+ >${selectionPaneRowIcon(node.type)}</span
1274
+ >
1275
+ ${this._renderName(node.id, label)} ${this._renderEye(node)}
1276
+ <button
1277
+ class="selection-pane-lock"
1278
+ type="button"
1279
+ data-testid="selection-pane-lock"
1280
+ aria-pressed=${node.locked ? 'true' : 'false'}
1281
+ aria-label=${translateKey(std, ...(node.locked ? SELECTION_PANE_UNLOCK : TOOLBAR_LOCK))}
1282
+ ?disabled=${readonly}
1283
+ @click=${(event) => this._onLockClick(event, node)}
1284
+ >
1285
+ ${node.locked ? LockIcon() : UnlockIcon()}
1286
+ </button>
1287
+ ${readonly
1288
+ ? nothing
1289
+ : html `<button
1290
+ class="selection-pane-more"
1291
+ type="button"
1292
+ data-testid="selection-pane-more"
1293
+ aria-haspopup="menu"
1294
+ aria-label=${translateKey(std, ...SELECTION_PANE_ROW_MENU)}
1295
+ @click=${(event) => {
1296
+ event.stopPropagation();
1297
+ this._openRowMenu(event.currentTarget, node);
1298
+ }}
1299
+ >
1300
+ ${MoreHorizontalIcon()}
1301
+ </button>`}
1302
+ </div>`;
1303
+ }
1304
+ updated() {
1305
+ const input = this.shadowRoot?.querySelector('[data-testid="selection-pane-rename"]');
1306
+ if (input && this.shadowRoot?.activeElement !== input) {
1307
+ input.focus();
1308
+ input.select();
1309
+ // A layer just created may sit above the scrolled-to rows: bring its
1310
+ // field into view, so the creation is seen where it happened.
1311
+ input.scrollIntoView({ block: 'nearest' });
1312
+ }
1313
+ }
1314
+ /**
1315
+ * One header action, in the frame panel's icon button
1316
+ * (`header/frame-panel-header.ts`): a 20px glyph in `edgeless-tool-icon-button`,
1317
+ * secondary until hovered, its tooltip above it, a wash while active.
1318
+ */
1319
+ _renderHeadButton(testId, label, icon, onClick, active = false) {
1320
+ return html `<edgeless-tool-icon-button
1321
+ class="affine-panel-header-button ${active ? 'active' : ''}"
1322
+ data-testid=${testId}
1323
+ aria-label=${label}
1324
+ .tooltip=${label}
1325
+ .tipPosition=${'top'}
1326
+ .active=${active}
1327
+ .activeMode=${'background'}
1328
+ @click=${onClick}
1329
+ >
1330
+ ${icon({ width: '20px', height: '20px' })}
1331
+ </edgeless-tool-icon-button>`;
1332
+ }
1333
+ render() {
1334
+ if (!this._open)
1335
+ return nothing;
1336
+ // Read for its dependency: the rows repaint when the canvas selection does.
1337
+ this._selectionRevision;
1338
+ const full = selectionPaneTree(this.std).value;
1339
+ let tree = full;
1340
+ let filterLabel = null;
1341
+ if (this._filter !== null) {
1342
+ const members = selectionPaneFilterMembers(this.std, this._filter);
1343
+ const target = selectionPaneFilterTargets(this.std).find(candidate => candidate.id === this._filter);
1344
+ if (members && target) {
1345
+ tree = filterSelectionPaneTree(tree, members);
1346
+ filterLabel = this._filterWording(target.id);
1347
+ }
1348
+ }
1349
+ const rows = this._rows(tree, full);
1350
+ this._visibleRows = rows;
1351
+ this._lists = paneLists(full);
1352
+ const title = translateKey(this.std, ...SELECTION_PANE_TITLE);
1353
+ // `pointermove` too: the editor turns every move over the host into a
1354
+ // cursor selection, and a selection with nothing recoverable in it makes
1355
+ // the range binding focus the host — which blurred a layer's rename field
1356
+ // the moment the pointer moved (a group's survived only because its click
1357
+ // had selected it). The pane's own drag listens on the document, in the
1358
+ // capture phase, so it still sees every move. Its `data-drag` and its
1359
+ // mask are the drag controller's, set outside this template.
1360
+ return html `<div
1361
+ class="selection-pane-panel"
1362
+ role="dialog"
1363
+ tabindex="-1"
1364
+ aria-label=${title}
1365
+ data-testid="selection-pane-panel"
1366
+ @pointerdown=${this._swallow}
1367
+ @pointerup=${this._swallow}
1368
+ @pointermove=${this._swallow}
1369
+ @click=${this._swallow}
1370
+ @dblclick=${this._swallow}
1371
+ >
1372
+ <div
1373
+ class="selection-pane-head affine-panel-header"
1374
+ data-testid="selection-pane-header"
1375
+ >
1376
+ <span
1377
+ class="affine-panel-header-title"
1378
+ data-testid="selection-pane-title"
1379
+ >${title}</span
1380
+ >
1381
+ <div class="selection-pane-actions">
1382
+ ${this.std.store.readonly
1383
+ ? nothing
1384
+ : this._renderHeadButton('selection-pane-new-layer', translateKey(this.std, ...SELECTION_PANE_NEW_LAYER), PlusIcon, this._createLayer)}
1385
+ ${this._renderHeadButton('selection-pane-filter', translateKey(this.std, ...SELECTION_PANE_FILTER), FilterIcon, this._openFilterMenu, filterLabel !== null)}
1386
+ ${this._renderHeadButton('selection-pane-close', translateKey(this.std, ...SELECTION_PANE_CLOSE), CloseIcon, this.closePanel)}
1387
+ </div>
1388
+ </div>
1389
+ ${filterLabel !== null
1390
+ ? html `<div
1391
+ class="selection-pane-filter-label"
1392
+ data-testid="selection-pane-filter-label"
1393
+ >
1394
+ ${filterLabel}
1395
+ </div>`
1396
+ : nothing}
1397
+ <div
1398
+ class="selection-pane-body"
1399
+ role="tree"
1400
+ aria-label=${title}
1401
+ data-testid="selection-pane-body"
1402
+ @pointerleave=${() => this._clearHighlight()}
1403
+ >
1404
+ ${rows.length
1405
+ ? repeat(rows, row => row.node.id, row => this._renderRow(row))
1406
+ : html `<div class="selection-pane-empty">
1407
+ ${translateKey(this.std, ...SELECTION_PANE_EMPTY)}
1408
+ </div>`}
1409
+ ${this._renderDropIndicator()}
1410
+ </div>
1411
+ ${this._renderGhost()}
1412
+ </div>`;
1413
+ }
1414
+ };
1415
+ })();
1416
+ export { EdgelessSelectionPaneWidget };
1417
+ export const edgelessSelectionPaneWidget = WidgetViewExtension('affine:page', EDGELESS_SELECTION_PANE_WIDGET, literal `${unsafeStatic(EDGELESS_SELECTION_PANE_WIDGET)}`);