@ecsplico/editor 2.1.2 → 3.1.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 (706) hide show
  1. package/CHANGELOG.md +78 -1
  2. package/README.md +39 -156
  3. package/dist/adapters/comments/drizzle.d.ts +1 -1
  4. package/dist/adapters/comments/record.d.ts +15 -0
  5. package/dist/adapters/comments/{client.js → rest-model.js} +3 -3
  6. package/dist/adapters/comments/rest-model.js.map +1 -0
  7. package/dist/adapters/comments/server.d.ts +2 -1
  8. package/dist/adapters/comments/server.js +2 -1
  9. package/dist/adapters/comments/server.js.map +1 -1
  10. package/dist/adapters/comments/types.d.ts +2 -2
  11. package/dist/adapters/document-state.d.ts +23 -0
  12. package/dist/adapters/document-state.js +66 -0
  13. package/dist/adapters/document-state.js.map +1 -0
  14. package/dist/adapters/documents.js +14 -11
  15. package/dist/adapters/documents.js.map +1 -1
  16. package/dist/adapters/drizzle.d.ts +2 -2
  17. package/dist/adapters/drizzle.js +97 -88
  18. package/dist/adapters/drizzle.js.map +1 -1
  19. package/dist/adapters/forge.d.ts +12 -7
  20. package/dist/adapters/forge.js +38 -45
  21. package/dist/adapters/forge.js.map +1 -1
  22. package/dist/adapters/http.d.ts +20 -0
  23. package/dist/adapters/http.js +68 -0
  24. package/dist/adapters/http.js.map +1 -0
  25. package/dist/adapters/index.d.ts +5 -5
  26. package/dist/adapters/json.d.ts +3 -3
  27. package/dist/adapters/json.js +58 -49
  28. package/dist/adapters/json.js.map +1 -1
  29. package/dist/adapters/memory.d.ts +21 -0
  30. package/dist/adapters/memory.js +53 -0
  31. package/dist/adapters/memory.js.map +1 -0
  32. package/dist/adapters/nitro.d.ts +27 -20
  33. package/dist/adapters/nitro.js +59 -163
  34. package/dist/adapters/nitro.js.map +1 -1
  35. package/dist/adapters/react.d.ts +55 -0
  36. package/dist/adapters/react.js +209 -0
  37. package/dist/adapters/react.js.map +1 -0
  38. package/dist/adapters/shared.d.ts +15 -21
  39. package/dist/adapters/shared.js +10 -8
  40. package/dist/adapters/shared.js.map +1 -1
  41. package/dist/adapters/vue.d.ts +15 -30
  42. package/dist/adapters/vue.js +36 -87
  43. package/dist/adapters/vue.js.map +1 -1
  44. package/dist/code/CodeSurface.vue.d.ts +2 -2
  45. package/dist/config/index.d.ts +105 -0
  46. package/dist/config/index.js +95 -0
  47. package/dist/config/index.js.map +1 -0
  48. package/dist/core/abilities.js +1 -0
  49. package/dist/core/abilities.js.map +1 -1
  50. package/dist/{adapters/routes.js → core/api-routes.js} +5 -3
  51. package/dist/core/api-routes.js.map +1 -0
  52. package/dist/core/backend-capability.d.ts +7 -0
  53. package/dist/core/backend-capability.js +17 -0
  54. package/dist/core/backend-capability.js.map +1 -0
  55. package/dist/core/backend-types.d.ts +245 -0
  56. package/dist/core/backend-types.js +17 -0
  57. package/dist/core/backend-types.js.map +1 -0
  58. package/dist/core/backend.d.ts +108 -0
  59. package/dist/core/backend.js +14 -0
  60. package/dist/core/backend.js.map +1 -0
  61. package/dist/core/block-convert.d.ts +7 -5
  62. package/dist/core/block-convert.js +28 -5
  63. package/dist/core/block-convert.js.map +1 -1
  64. package/dist/core/command-types.d.ts +96 -0
  65. package/dist/core/commands.d.ts +40 -0
  66. package/dist/core/commands.js +151 -0
  67. package/dist/core/commands.js.map +1 -0
  68. package/dist/core/context.d.ts +17 -20
  69. package/dist/core/context.js +24 -21
  70. package/dist/core/context.js.map +1 -1
  71. package/dist/core/core-feature.d.ts +22 -7
  72. package/dist/core/core-feature.js +51 -18
  73. package/dist/core/core-feature.js.map +1 -1
  74. package/dist/core/define-editor.d.ts +4 -3
  75. package/dist/core/define-editor.js +14 -7
  76. package/dist/core/define-editor.js.map +1 -1
  77. package/dist/core/document-markdown.js +12 -3
  78. package/dist/core/document-markdown.js.map +1 -1
  79. package/dist/core/editor-ui.d.ts +8 -1
  80. package/dist/core/editor-ui.js +9 -8
  81. package/dist/core/editor-ui.js.map +1 -1
  82. package/dist/core/extension-points.d.ts +3 -15
  83. package/dist/core/feature-context.d.ts +8 -7
  84. package/dist/core/feature-context.js +12 -11
  85. package/dist/core/feature-context.js.map +1 -1
  86. package/dist/core/feature.d.ts +41 -19
  87. package/dist/core/feature.js.map +1 -1
  88. package/dist/core/fences.d.ts +2 -1
  89. package/dist/core/fences.js +3 -2
  90. package/dist/core/fences.js.map +1 -1
  91. package/dist/core/fetch-error.d.ts +1 -1
  92. package/dist/core/fetch-error.js +3 -1
  93. package/dist/core/fetch-error.js.map +1 -1
  94. package/dist/core/hash.d.ts +5 -0
  95. package/dist/core/hash.js +11 -0
  96. package/dist/core/hash.js.map +1 -0
  97. package/dist/core/http-backend.d.ts +11 -0
  98. package/dist/core/http-backend.js +195 -0
  99. package/dist/core/http-backend.js.map +1 -0
  100. package/dist/core/index.d.ts +15 -9
  101. package/dist/core/index.js +13 -9
  102. package/dist/core/palette.d.ts +48 -0
  103. package/dist/core/palette.js +95 -0
  104. package/dist/core/palette.js.map +1 -0
  105. package/dist/core/schema/abilities.d.ts +2 -1
  106. package/dist/core/schema/abilities.js +5 -1
  107. package/dist/core/schema/abilities.js.map +1 -1
  108. package/dist/core/schema/index.d.ts +11 -5
  109. package/dist/core/schema/index.js +13 -8
  110. package/dist/core/schema/index.js.map +1 -1
  111. package/dist/core/schema/mark-flags.d.ts +8 -1
  112. package/dist/core/schema/of-features.d.ts +13 -0
  113. package/dist/core/schema/of-features.js +14 -0
  114. package/dist/core/schema/of-features.js.map +1 -0
  115. package/dist/core/slash.d.ts +8 -6
  116. package/dist/core/slash.js +24 -16
  117. package/dist/core/slash.js.map +1 -1
  118. package/dist/core/surface-session.js +15 -5
  119. package/dist/core/surface-session.js.map +1 -1
  120. package/dist/core/toolbar-items.d.ts +10 -4
  121. package/dist/core/toolbar-items.js +269 -195
  122. package/dist/core/toolbar-items.js.map +1 -1
  123. package/dist/core/transaction-guards.d.ts +21 -0
  124. package/dist/core/transaction-guards.js +49 -0
  125. package/dist/core/transaction-guards.js.map +1 -0
  126. package/dist/core/util.js +11 -0
  127. package/dist/core/util.js.map +1 -0
  128. package/dist/document/DocumentSurface.d.ts +1 -1
  129. package/dist/document/DocumentSurface.vue.d.ts +2 -2
  130. package/dist/features/ai/agent-op-review.d.ts +1 -1
  131. package/dist/features/ai/agent-op-review.js +1 -1
  132. package/dist/features/ai/agent-ops.js +1 -1
  133. package/dist/features/ai/ai-apply.d.ts +2 -2
  134. package/dist/features/ai/ai-apply.js +1 -1
  135. package/dist/features/ai/ai-review.js +1 -1
  136. package/dist/features/ai/ai-sse.d.ts +6 -6
  137. package/dist/features/ai/ai-sse.js +20 -63
  138. package/dist/features/ai/ai-sse.js.map +1 -1
  139. package/dist/features/ai/assistant.d.ts +8 -7
  140. package/dist/features/ai/assistant.js +3 -3
  141. package/dist/features/ai/assistant.js.map +1 -1
  142. package/dist/features/ai/block-actions.d.ts +3 -2
  143. package/dist/features/ai/block-actions.js +3 -2
  144. package/dist/features/ai/block-actions.js.map +1 -1
  145. package/dist/features/ai/components/AiSelectionMenu.js +1 -1
  146. package/dist/features/ai/components/DocumentChatAnswer.js +1 -1
  147. package/dist/features/ai/components/DocumentChatOps.vue.d.ts +1 -1
  148. package/dist/features/ai/components/SettingsModelProfiles.js +8 -8
  149. package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
  150. package/dist/features/ai/document-chat-model.d.ts +8 -7
  151. package/dist/features/ai/document-chat-model.js +5 -5
  152. package/dist/features/ai/document-chat-model.js.map +1 -1
  153. package/dist/features/ai/document-chat.js +1 -1
  154. package/dist/features/ai/feature.js +27 -14
  155. package/dist/features/ai/feature.js.map +1 -1
  156. package/dist/features/ai/ghost-autocomplete.d.ts +7 -6
  157. package/dist/features/ai/ghost-autocomplete.js +6 -9
  158. package/dist/features/ai/ghost-autocomplete.js.map +1 -1
  159. package/dist/features/ai/index.d.ts +4 -3
  160. package/dist/features/ai/index.js +10 -10
  161. package/dist/features/ai/model-profiles.d.ts +5 -4
  162. package/dist/features/ai/model-profiles.js +2 -2
  163. package/dist/features/ai/model-profiles.js.map +1 -1
  164. package/dist/features/ai/protocol/block-lines.js +1 -1
  165. package/dist/features/ai/protocol/block-lines.js.map +1 -1
  166. package/dist/features/ai/protocol/chat.js +6 -2
  167. package/dist/features/ai/protocol/chat.js.map +1 -1
  168. package/dist/features/ai/protocol/index.d.ts +3 -2
  169. package/dist/features/ai/protocol/models.d.ts +2 -16
  170. package/dist/features/ai/protocol/models.js.map +1 -1
  171. package/dist/features/ai/rate-limit.d.ts +1 -1
  172. package/dist/features/ai/rate-limit.js +3 -1
  173. package/dist/features/ai/rate-limit.js.map +1 -1
  174. package/dist/features/ai/react/AiSelectionMenu.js +2 -2
  175. package/dist/features/ai/react/AiSidebar.js +4 -4
  176. package/dist/features/ai/react/DocumentChatAnswer.js +1 -1
  177. package/dist/features/ai/react/DocumentChatOps.d.ts +1 -1
  178. package/dist/features/ai/react/DocumentChatOps.js +1 -1
  179. package/dist/features/ai/react/SettingsModelProfiles.js +8 -10
  180. package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
  181. package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
  182. package/dist/features/ai/react/use-ai-assistant.js +3 -3
  183. package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
  184. package/dist/features/ai/react/use-document-chat.js +2 -2
  185. package/dist/features/ai/react/use-document-chat.js.map +1 -1
  186. package/dist/features/ai/react/use-model-profiles.d.ts +2 -1
  187. package/dist/features/ai/selection-flow.d.ts +1 -1
  188. package/dist/features/ai/selection-flow.js +1 -1
  189. package/dist/features/ai/sidebar-flow.d.ts +1 -1
  190. package/dist/features/ai/sidebar-flow.js +1 -1
  191. package/dist/features/ai/use-ai-assistant.d.ts +1 -1
  192. package/dist/features/ai/use-ai-assistant.js +3 -3
  193. package/dist/features/ai/use-ai-assistant.js.map +1 -1
  194. package/dist/features/ai/use-document-chat.js +2 -2
  195. package/dist/features/ai/use-document-chat.js.map +1 -1
  196. package/dist/features/ai/use-model-profiles.d.ts +2 -1
  197. package/dist/features/authors/attribution.d.ts +1 -1
  198. package/dist/features/authors/feature.js +12 -11
  199. package/dist/features/authors/feature.js.map +1 -1
  200. package/dist/features/block-ui/block-actions.d.ts +1 -1
  201. package/dist/features/block-ui/block-actions.js +1 -1
  202. package/dist/features/block-ui/block-actions.js.map +1 -1
  203. package/dist/features/block-ui/components/BlockUi.js +1 -1
  204. package/dist/features/block-ui/feature.js +1 -0
  205. package/dist/features/block-ui/feature.js.map +1 -1
  206. package/dist/features/block-ui/react/BlockUi.js +1 -1
  207. package/dist/features/collab/anchor-resolver.js +1 -1
  208. package/dist/features/collab/feature.js +2 -0
  209. package/dist/features/collab/feature.js.map +1 -1
  210. package/dist/features/comments/components/CommentThreadView.vue.d.ts +2 -1
  211. package/dist/features/comments/feature.js +12 -11
  212. package/dist/features/comments/feature.js.map +1 -1
  213. package/dist/features/comments/index.d.ts +3 -2
  214. package/dist/features/comments/index.js +1 -1
  215. package/dist/features/comments/margin-layout.d.ts +3 -2
  216. package/dist/features/comments/model.d.ts +3 -67
  217. package/dist/features/comments/model.js +2 -2
  218. package/dist/features/comments/model.js.map +1 -1
  219. package/dist/features/comments/react/CommentThreadView.d.ts +3 -2
  220. package/dist/features/comments/react/use-comments.d.ts +2 -1
  221. package/dist/features/comments/react.d.ts +1 -1
  222. package/dist/features/comments/schema.d.ts +2 -52
  223. package/dist/features/comments/schema.js.map +1 -1
  224. package/dist/features/comments/snapshot-equality.js.map +1 -1
  225. package/dist/features/comments/use-comments.d.ts +3 -2
  226. package/dist/features/comments/vue.d.ts +1 -1
  227. package/dist/features/composites/accepted-children.d.ts +1 -0
  228. package/dist/features/composites/accepted-children.js +16 -1
  229. package/dist/features/composites/accepted-children.js.map +1 -1
  230. package/dist/features/composites/ai-brief.js +39 -0
  231. package/dist/features/composites/ai-brief.js.map +1 -1
  232. package/dist/features/composites/bibliography-command.d.ts +11 -0
  233. package/dist/features/composites/bibliography-form.js +90 -0
  234. package/dist/features/composites/bibliography-form.js.map +1 -0
  235. package/dist/features/composites/bibliography.d.ts +33 -0
  236. package/dist/features/composites/bibliography.js +120 -0
  237. package/dist/features/composites/bibliography.js.map +1 -0
  238. package/dist/features/composites/components/BibliographyEditor.js +261 -0
  239. package/dist/features/composites/components/BibliographyEditor.js.map +1 -0
  240. package/dist/features/composites/components/CompositeChrome.js +78 -29
  241. package/dist/features/composites/components/CompositeChrome.js.map +1 -1
  242. package/dist/features/composites/components/CompositeChrome.vue.d.ts +1 -1
  243. package/dist/features/composites/components/CompositeDetails.js +46 -11
  244. package/dist/features/composites/components/CompositeDetails.js.map +1 -1
  245. package/dist/features/composites/components/CompositeDetails.vue.d.ts +2 -1
  246. package/dist/features/composites/components/CompositeFieldEditor.js +64 -5
  247. package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
  248. package/dist/features/composites/components/CompositeInspector.js +20 -7
  249. package/dist/features/composites/components/CompositeInspector.js.map +1 -1
  250. package/dist/features/composites/components/CompositeTable.js +13 -4
  251. package/dist/features/composites/components/CompositeTable.js.map +1 -1
  252. package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
  253. package/dist/features/composites/components/CompositeView.js +11 -1
  254. package/dist/features/composites/components/CompositeView.js.map +1 -1
  255. package/dist/features/composites/components/DerivationBadge.js +103 -0
  256. package/dist/features/composites/components/DerivationBadge.js.map +1 -0
  257. package/dist/features/composites/components/ReferenceFieldSelect.js +60 -0
  258. package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -0
  259. package/dist/features/composites/components/ReferenceView.js +122 -0
  260. package/dist/features/composites/components/ReferenceView.js.map +1 -0
  261. package/dist/features/composites/components/ReferenceView.vue.d.ts +96 -0
  262. package/dist/features/composites/components/SettingsEditingTab.js +1 -1
  263. package/dist/features/composites/convert.js +2 -2
  264. package/dist/features/composites/convert.js.map +1 -1
  265. package/dist/features/composites/derivation.d.ts +61 -0
  266. package/dist/features/composites/derivation.js +98 -0
  267. package/dist/features/composites/derivation.js.map +1 -0
  268. package/dist/features/composites/derived-chrome.js +69 -0
  269. package/dist/features/composites/derived-chrome.js.map +1 -0
  270. package/dist/features/composites/feature.js +159 -109
  271. package/dist/features/composites/feature.js.map +1 -1
  272. package/dist/features/composites/fences.d.ts +4 -3
  273. package/dist/features/composites/fences.js +51 -7
  274. package/dist/features/composites/fences.js.map +1 -1
  275. package/dist/features/composites/index.d.ts +12 -3
  276. package/dist/features/composites/index.js +15 -6
  277. package/dist/features/composites/inspector-model.d.ts +4 -1
  278. package/dist/features/composites/inspector-model.js +8 -4
  279. package/dist/features/composites/inspector-model.js.map +1 -1
  280. package/dist/features/composites/kinds.d.ts +16 -2
  281. package/dist/features/composites/kinds.js +145 -6
  282. package/dist/features/composites/kinds.js.map +1 -1
  283. package/dist/features/composites/legacy.d.ts +4 -1
  284. package/dist/features/composites/legacy.js +56 -1
  285. package/dist/features/composites/legacy.js.map +1 -1
  286. package/dist/features/composites/meta-display.js +45 -2
  287. package/dist/features/composites/meta-display.js.map +1 -1
  288. package/dist/features/composites/meta-keys.d.ts +7 -0
  289. package/dist/features/composites/meta-keys.js +21 -0
  290. package/dist/features/composites/meta-keys.js.map +1 -0
  291. package/dist/features/composites/node-views.d.ts +6 -3
  292. package/dist/features/composites/node-views.js +7 -3
  293. package/dist/features/composites/node-views.js.map +1 -1
  294. package/dist/features/composites/nodes.d.ts +6 -1
  295. package/dist/features/composites/nodes.js +33 -7
  296. package/dist/features/composites/nodes.js.map +1 -1
  297. package/dist/features/composites/react/BibliographyEditor.js +229 -0
  298. package/dist/features/composites/react/BibliographyEditor.js.map +1 -0
  299. package/dist/features/composites/react/CompositeChrome.js +67 -19
  300. package/dist/features/composites/react/CompositeChrome.js.map +1 -1
  301. package/dist/features/composites/react/CompositeDetails.d.ts +2 -1
  302. package/dist/features/composites/react/CompositeDetails.js +45 -6
  303. package/dist/features/composites/react/CompositeDetails.js.map +1 -1
  304. package/dist/features/composites/react/CompositeFieldEditor.d.ts +1 -1
  305. package/dist/features/composites/react/CompositeFieldEditor.js +43 -1
  306. package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
  307. package/dist/features/composites/react/CompositeInspector.js +12 -6
  308. package/dist/features/composites/react/CompositeInspector.js.map +1 -1
  309. package/dist/features/composites/react/CompositeStatusMenu.js +1 -1
  310. package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
  311. package/dist/features/composites/react/CompositeTable.js +16 -2
  312. package/dist/features/composites/react/CompositeTable.js.map +1 -1
  313. package/dist/features/composites/react/CompositeTagsEditor.js +2 -2
  314. package/dist/features/composites/react/CompositeView.js +6 -1
  315. package/dist/features/composites/react/CompositeView.js.map +1 -1
  316. package/dist/features/composites/react/DerivationBadge.js +116 -0
  317. package/dist/features/composites/react/DerivationBadge.js.map +1 -0
  318. package/dist/features/composites/react/ReferenceFieldSelect.js +52 -0
  319. package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -0
  320. package/dist/features/composites/react/ReferenceView.d.ts +11 -0
  321. package/dist/features/composites/react/ReferenceView.js +115 -0
  322. package/dist/features/composites/react/ReferenceView.js.map +1 -0
  323. package/dist/features/composites/react/SettingsEditingTab.js +2 -2
  324. package/dist/features/composites/react.d.ts +2 -1
  325. package/dist/features/composites/react.js +7 -3
  326. package/dist/features/composites/react.js.map +1 -1
  327. package/dist/features/composites/reference-ai.js +16 -0
  328. package/dist/features/composites/reference-ai.js.map +1 -0
  329. package/dist/features/composites/reference-label.d.ts +19 -0
  330. package/dist/features/composites/reference-label.js +58 -0
  331. package/dist/features/composites/reference-label.js.map +1 -0
  332. package/dist/features/composites/reference-suggestion.d.ts +10 -0
  333. package/dist/features/composites/reference-suggestion.js +41 -0
  334. package/dist/features/composites/reference-suggestion.js.map +1 -0
  335. package/dist/features/composites/reference-text.d.ts +18 -0
  336. package/dist/features/composites/reference-text.js +89 -0
  337. package/dist/features/composites/reference-text.js.map +1 -0
  338. package/dist/features/composites/reference.d.ts +44 -0
  339. package/dist/features/composites/reference.js +148 -0
  340. package/dist/features/composites/reference.js.map +1 -0
  341. package/dist/features/composites/reveal-source.d.ts +32 -0
  342. package/dist/features/composites/reveal-source.js +89 -0
  343. package/dist/features/composites/reveal-source.js.map +1 -0
  344. package/dist/features/composites/rows.d.ts +25 -3
  345. package/dist/features/composites/rows.js +72 -10
  346. package/dist/features/composites/rows.js.map +1 -1
  347. package/dist/features/composites/schema.d.ts +9 -3
  348. package/dist/features/composites/schema.js +11 -4
  349. package/dist/features/composites/schema.js.map +1 -1
  350. package/dist/features/composites/table-model.js +12 -21
  351. package/dist/features/composites/table-model.js.map +1 -1
  352. package/dist/features/composites/vue.d.ts +3 -2
  353. package/dist/features/composites/vue.js +8 -4
  354. package/dist/features/composites/vue.js.map +1 -1
  355. package/dist/features/media/assets.d.ts +2 -0
  356. package/dist/features/media/assets.js +3 -2
  357. package/dist/features/media/assets.js.map +1 -1
  358. package/dist/features/media/components/FileView.js +13 -4
  359. package/dist/features/media/components/FileView.js.map +1 -1
  360. package/dist/features/media/feature.d.ts +3 -3
  361. package/dist/features/media/feature.js +21 -28
  362. package/dist/features/media/feature.js.map +1 -1
  363. package/dist/features/media/file-import.js +2 -2
  364. package/dist/features/media/file-import.js.map +1 -1
  365. package/dist/features/media/index.d.ts +2 -2
  366. package/dist/features/media/index.js +3 -3
  367. package/dist/features/media/react/AudioRecorderModal.js +1 -1
  368. package/dist/features/media/react/FileView.js +19 -2
  369. package/dist/features/media/react/FileView.js.map +1 -1
  370. package/dist/features/media/react.js +1 -1
  371. package/dist/features/media/schema.d.ts +8 -0
  372. package/dist/features/media/schema.js +126 -11
  373. package/dist/features/media/schema.js.map +1 -1
  374. package/dist/features/media/upload.d.ts +16 -14
  375. package/dist/features/media/upload.js +13 -19
  376. package/dist/features/media/upload.js.map +1 -1
  377. package/dist/features/mentions/index.d.ts +4 -3
  378. package/dist/features/mentions/index.js +4 -1
  379. package/dist/features/mentions/index.js.map +1 -1
  380. package/dist/features/mentions/mention-text.d.ts +1 -1
  381. package/dist/features/mentions/mention-text.js.map +1 -1
  382. package/dist/features/mentions/mention.d.ts +0 -6
  383. package/dist/features/mentions/mention.js.map +1 -1
  384. package/dist/features/mentions/metadata-defaults.d.ts +2 -2
  385. package/dist/features/mentions/metadata-defaults.js +3 -9
  386. package/dist/features/mentions/metadata-defaults.js.map +1 -1
  387. package/dist/features/mentions/schema.d.ts +2 -1
  388. package/dist/features/mentions/schema.js.map +1 -1
  389. package/dist/features/tables/feature.d.ts +2 -1
  390. package/dist/features/tables/feature.js +90 -70
  391. package/dist/features/tables/feature.js.map +1 -1
  392. package/dist/features/themes/components/SettingsAppearanceTab.js +6 -9
  393. package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
  394. package/dist/features/themes/feature.js +2 -0
  395. package/dist/features/themes/feature.js.map +1 -1
  396. package/dist/features/themes/index.d.ts +2 -1
  397. package/dist/features/themes/react/SettingsAppearanceTab.js +7 -10
  398. package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
  399. package/dist/features/themes/schema.d.ts +2 -6
  400. package/dist/features/themes/schema.js.map +1 -1
  401. package/dist/features/themes/theme-runtime.d.ts +1 -1
  402. package/dist/features/themes/theme-runtime.js +4 -2
  403. package/dist/features/themes/theme-runtime.js.map +1 -1
  404. package/dist/features/transcript/TranscriptSegmentView.js +48 -28
  405. package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
  406. package/dist/features/transcript/feature.js +21 -19
  407. package/dist/features/transcript/feature.js.map +1 -1
  408. package/dist/features/transcript/react/TranscriptSegmentView.js +55 -36
  409. package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
  410. package/dist/features/transcript/segment-node.d.ts +2 -0
  411. package/dist/features/transcript/segment-node.js +35 -7
  412. package/dist/features/transcript/segment-node.js.map +1 -1
  413. package/dist/i18n/de/composites.js +91 -1
  414. package/dist/i18n/de/composites.js.map +1 -1
  415. package/dist/i18n/de/integrations.js +49 -8
  416. package/dist/i18n/de/integrations.js.map +1 -1
  417. package/dist/i18n/de/media.js +0 -1
  418. package/dist/i18n/de/media.js.map +1 -1
  419. package/dist/i18n/de/palette.js +22 -0
  420. package/dist/i18n/de/palette.js.map +1 -0
  421. package/dist/i18n/de/tables.js +0 -1
  422. package/dist/i18n/de/tables.js.map +1 -1
  423. package/dist/i18n/de/transcript.js +2 -1
  424. package/dist/i18n/de/transcript.js.map +1 -1
  425. package/dist/i18n/de/tree.js +3 -0
  426. package/dist/i18n/de/tree.js.map +1 -1
  427. package/dist/i18n/de.d.ts +157 -11
  428. package/dist/i18n/de.js +3 -1
  429. package/dist/i18n/de.js.map +1 -1
  430. package/dist/i18n/en/composites.js +89 -1
  431. package/dist/i18n/en/composites.js.map +1 -1
  432. package/dist/i18n/en/integrations.js +49 -8
  433. package/dist/i18n/en/integrations.js.map +1 -1
  434. package/dist/i18n/en/media.js +0 -1
  435. package/dist/i18n/en/media.js.map +1 -1
  436. package/dist/i18n/en/palette.js +22 -0
  437. package/dist/i18n/en/palette.js.map +1 -0
  438. package/dist/i18n/en/tables.js +0 -1
  439. package/dist/i18n/en/tables.js.map +1 -1
  440. package/dist/i18n/en/transcript.js +2 -1
  441. package/dist/i18n/en/transcript.js.map +1 -1
  442. package/dist/i18n/en/tree.js +3 -0
  443. package/dist/i18n/en/tree.js.map +1 -1
  444. package/dist/i18n/en.js +3 -1
  445. package/dist/i18n/en.js.map +1 -1
  446. package/dist/index.d.ts +4 -3
  447. package/dist/integrations/composite-ai/bibliography-fetch.d.ts +31 -0
  448. package/dist/integrations/composite-ai/bibliography-fetch.js +159 -0
  449. package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -0
  450. package/dist/integrations/composite-ai/composite-fill.d.ts +30 -8
  451. package/dist/integrations/composite-ai/composite-fill.js +97 -56
  452. package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
  453. package/dist/integrations/composite-ai/composite-summary.d.ts +4 -12
  454. package/dist/integrations/composite-ai/composite-summary.js +7 -26
  455. package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
  456. package/dist/integrations/composite-ai/derive.d.ts +29 -0
  457. package/dist/integrations/composite-ai/derive.js +173 -0
  458. package/dist/integrations/composite-ai/derive.js.map +1 -0
  459. package/dist/integrations/composite-ai/index.d.ts +11 -7
  460. package/dist/integrations/composite-ai/index.js +72 -14
  461. package/dist/integrations/composite-ai/index.js.map +1 -1
  462. package/dist/integrations/composite-ai/rendition.d.ts +45 -0
  463. package/dist/integrations/composite-ai/rendition.js +314 -0
  464. package/dist/integrations/composite-ai/rendition.js.map +1 -0
  465. package/dist/integrations/composite-media/index.d.ts +7 -5
  466. package/dist/integrations/composite-media/index.js +86 -13
  467. package/dist/integrations/composite-media/index.js.map +1 -1
  468. package/dist/integrations/transcript-ai/index.d.ts +1 -1
  469. package/dist/integrations/transcript-ai/index.js +5 -2
  470. package/dist/integrations/transcript-ai/index.js.map +1 -1
  471. package/dist/integrations/transcript-ai/protocol.d.ts +2 -12
  472. package/dist/integrations/transcript-ai/protocol.js +0 -2
  473. package/dist/integrations/transcript-ai/protocol.js.map +1 -1
  474. package/dist/integrations/transcript-ai/transcript-cleanup.d.ts +5 -5
  475. package/dist/integrations/transcript-ai/transcript-cleanup.js +7 -10
  476. package/dist/integrations/transcript-ai/transcript-cleanup.js.map +1 -1
  477. package/dist/markdown/MarkdownSurface.vue.d.ts +12 -11
  478. package/dist/markdown/MarkdownSurface2.js +3 -6
  479. package/dist/markdown/MarkdownSurface2.js.map +1 -1
  480. package/dist/markdown/document.js +1 -1
  481. package/dist/markdown/source-mode.d.ts +1 -1
  482. package/dist/nuxt/module.d.ts +1402 -54
  483. package/dist/nuxt/module.js +6 -49
  484. package/dist/nuxt/module.js.map +1 -1
  485. package/dist/nuxt/runtime/install-context.d.ts +7 -3
  486. package/dist/nuxt/runtime/install-context.js +14 -8
  487. package/dist/nuxt/runtime/install-context.js.map +1 -1
  488. package/dist/nuxt/runtime/plugins/editor-context-nuxt-ui.client.ts +2 -2
  489. package/dist/nuxt/runtime/server/plugins/editor-server.js +20 -12
  490. package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
  491. package/dist/presets/compose.d.ts +94 -0
  492. package/dist/presets/compose.js +164 -0
  493. package/dist/presets/compose.js.map +1 -0
  494. package/dist/react/AdvancedEditor.d.ts +15 -15
  495. package/dist/react/AdvancedEditor.js +15 -13
  496. package/dist/react/AdvancedEditor.js.map +1 -1
  497. package/dist/react/EditorCommandPalette.d.ts +13 -0
  498. package/dist/react/EditorCommandPalette.js +118 -0
  499. package/dist/react/EditorCommandPalette.js.map +1 -0
  500. package/dist/react/EditorSettingsModal.d.ts +5 -5
  501. package/dist/react/EditorSettingsModal.js +7 -4
  502. package/dist/react/EditorSettingsModal.js.map +1 -1
  503. package/dist/react/EditorSettingsPanel.d.ts +7 -7
  504. package/dist/react/EditorSettingsPanel.js +8 -5
  505. package/dist/react/EditorSettingsPanel.js.map +1 -1
  506. package/dist/react/EditorSurface.d.ts +7 -7
  507. package/dist/react/EditorSurface.js +10 -6
  508. package/dist/react/EditorSurface.js.map +1 -1
  509. package/dist/react/EditorToolbar.d.ts +4 -6
  510. package/dist/react/EditorToolbar.js +29 -37
  511. package/dist/react/EditorToolbar.js.map +1 -1
  512. package/dist/react/SimpleEditor.d.ts +22 -23
  513. package/dist/react/SimpleEditor.js +21 -7
  514. package/dist/react/SimpleEditor.js.map +1 -1
  515. package/dist/react/advanced.d.ts +4 -3
  516. package/dist/react/advanced.js +2 -2
  517. package/dist/react/compose.d.ts +20 -0
  518. package/dist/react/compose.js +49 -0
  519. package/dist/react/compose.js.map +1 -0
  520. package/dist/react/composed-surface.d.ts +39 -0
  521. package/dist/react/composed-surface.js +71 -0
  522. package/dist/react/composed-surface.js.map +1 -0
  523. package/dist/react/context.js +6 -2
  524. package/dist/react/context.js.map +1 -1
  525. package/dist/react/index.d.ts +2 -1
  526. package/dist/react/index.js +2 -1
  527. package/dist/react/key-labels.js +15 -0
  528. package/dist/react/key-labels.js.map +1 -0
  529. package/dist/react/settings.d.ts +1 -1
  530. package/dist/react/simple.d.ts +2 -2
  531. package/dist/react/ui/command.js +36 -1
  532. package/dist/react/ui/command.js.map +1 -1
  533. package/dist/schema/advanced.d.ts +6 -6
  534. package/dist/schema/advanced.js +26 -29
  535. package/dist/schema/advanced.js.map +1 -1
  536. package/dist/server/ai.d.ts +5 -16
  537. package/dist/server/ai.js.map +1 -1
  538. package/dist/server/auth.d.ts +9 -0
  539. package/dist/server/collab-state.d.ts +1 -1
  540. package/dist/server/collab-state.js.map +1 -1
  541. package/dist/server/collab.d.ts +13 -13
  542. package/dist/server/collab.js +34 -18
  543. package/dist/server/collab.js.map +1 -1
  544. package/dist/server/crossref.js +78 -0
  545. package/dist/server/crossref.js.map +1 -0
  546. package/dist/server/errors.d.ts +1 -1
  547. package/dist/server/errors.js +1 -1
  548. package/dist/server/errors.js.map +1 -1
  549. package/dist/server/extract.js +308 -0
  550. package/dist/server/extract.js.map +1 -0
  551. package/dist/server/h3.d.ts +8 -0
  552. package/dist/{nuxt/runtime/server/utils/editor-route.js → server/h3.js} +8 -16
  553. package/dist/server/h3.js.map +1 -0
  554. package/dist/server/handlers/ai.d.ts +32 -10
  555. package/dist/server/handlers/ai.js +172 -37
  556. package/dist/server/handlers/ai.js.map +1 -1
  557. package/dist/server/handlers/context.d.ts +12 -5
  558. package/dist/server/handlers/context.js +10 -4
  559. package/dist/server/handlers/context.js.map +1 -1
  560. package/dist/server/handlers/editor.d.ts +19 -13
  561. package/dist/server/handlers/editor.js +49 -38
  562. package/dist/server/handlers/editor.js.map +1 -1
  563. package/dist/server/handlers/index.d.ts +4 -4
  564. package/dist/server/handlers/index.js +4 -4
  565. package/dist/server/host.d.ts +16 -25
  566. package/dist/server/host.js +58 -41
  567. package/dist/server/host.js.map +1 -1
  568. package/dist/server/index.d.ts +6 -4
  569. package/dist/server/index.js +3 -2
  570. package/dist/server/pdf.js +97 -0
  571. package/dist/server/pdf.js.map +1 -0
  572. package/dist/server/{adapter.d.ts → ports.d.ts} +81 -30
  573. package/dist/server/ports.js +29 -0
  574. package/dist/server/ports.js.map +1 -0
  575. package/dist/server/routes.d.ts +22 -0
  576. package/dist/server/routes.js +144 -0
  577. package/dist/server/routes.js.map +1 -0
  578. package/dist/settings/index.d.ts +1 -1
  579. package/dist/settings/index.js.map +1 -1
  580. package/dist/styles/composites.css +25 -0
  581. package/dist/tree/DocumentTree.js +56 -29
  582. package/dist/tree/DocumentTree.js.map +1 -1
  583. package/dist/tree/react/DocumentTree.js +23 -0
  584. package/dist/tree/react/DocumentTree.js.map +1 -1
  585. package/dist/tree/tree-host.js +2 -2
  586. package/dist/tree/tree-items.js +1 -1
  587. package/dist/vue/AdvancedEditor.js +30 -9
  588. package/dist/vue/AdvancedEditor.js.map +1 -1
  589. package/dist/vue/AdvancedEditor.vue.d.ts +32 -12
  590. package/dist/vue/SimpleEditor.js +62 -16
  591. package/dist/vue/SimpleEditor.js.map +1 -1
  592. package/dist/vue/SimpleEditor.vue.d.ts +39 -9
  593. package/dist/vue/advanced.d.ts +3 -2
  594. package/dist/vue/advanced.js +2 -2
  595. package/dist/vue/components/EditorCommandPalette.js +91 -0
  596. package/dist/vue/components/EditorCommandPalette.js.map +1 -0
  597. package/dist/vue/components/EditorCommandPalette.vue.d.ts +15 -0
  598. package/dist/vue/components/EditorSettingsModal.js +10 -6
  599. package/dist/vue/components/EditorSettingsModal.js.map +1 -1
  600. package/dist/vue/components/EditorSettingsModal.vue.d.ts +4 -4
  601. package/dist/vue/components/EditorSettingsPanel.js +10 -6
  602. package/dist/vue/components/EditorSettingsPanel.js.map +1 -1
  603. package/dist/vue/components/EditorSettingsPanel.vue.d.ts +6 -6
  604. package/dist/vue/components/EditorSurface.js +11 -6
  605. package/dist/vue/components/EditorSurface.js.map +1 -1
  606. package/dist/vue/components/EditorSurface.vue.d.ts +11 -11
  607. package/dist/vue/components/EditorToolbar.js +41 -49
  608. package/dist/vue/components/EditorToolbar.js.map +1 -1
  609. package/dist/vue/components/EditorToolbar.vue.d.ts +2 -4
  610. package/dist/vue/compose.d.ts +17 -0
  611. package/dist/vue/compose.js +51 -0
  612. package/dist/vue/compose.js.map +1 -0
  613. package/dist/vue/context-key.d.ts +6 -0
  614. package/dist/vue/context-key.js +6 -0
  615. package/dist/vue/context-key.js.map +1 -0
  616. package/dist/vue/context.d.ts +8 -6
  617. package/dist/vue/context.js +6 -5
  618. package/dist/vue/context.js.map +1 -1
  619. package/dist/vue/index.d.ts +10 -8
  620. package/dist/vue/index.js +10 -8
  621. package/dist/vue/kit/index.d.ts +2 -2
  622. package/dist/vue/kit/nuxt-ui.js +23 -0
  623. package/dist/vue/kit/nuxt-ui.js.map +1 -1
  624. package/dist/vue/kit/types.d.ts +40 -1
  625. package/package.json +30 -16
  626. package/dist/adapters/comments/client.d.ts +0 -64
  627. package/dist/adapters/comments/client.js.map +0 -1
  628. package/dist/adapters/routes.js.map +0 -1
  629. package/dist/core/toolbar.d.ts +0 -74
  630. package/dist/core/toolbar.js +0 -45
  631. package/dist/core/toolbar.js.map +0 -1
  632. package/dist/integrations/composite-ai/document-transcribe.d.ts +0 -14
  633. package/dist/integrations/composite-ai/document-transcribe.js +0 -89
  634. package/dist/integrations/composite-ai/document-transcribe.js.map +0 -1
  635. package/dist/nuxt/runtime/server/api/ai/chat.post.d.ts +0 -5
  636. package/dist/nuxt/runtime/server/api/ai/chat.post.js +0 -8
  637. package/dist/nuxt/runtime/server/api/ai/chat.post.js.map +0 -1
  638. package/dist/nuxt/runtime/server/api/ai/complete.post.d.ts +0 -5
  639. package/dist/nuxt/runtime/server/api/ai/complete.post.js +0 -8
  640. package/dist/nuxt/runtime/server/api/ai/complete.post.js.map +0 -1
  641. package/dist/nuxt/runtime/server/api/ai/generate.post.d.ts +0 -5
  642. package/dist/nuxt/runtime/server/api/ai/generate.post.js +0 -8
  643. package/dist/nuxt/runtime/server/api/ai/generate.post.js.map +0 -1
  644. package/dist/nuxt/runtime/server/api/ai/models.get.d.ts +0 -5
  645. package/dist/nuxt/runtime/server/api/ai/models.get.js +0 -8
  646. package/dist/nuxt/runtime/server/api/ai/models.get.js.map +0 -1
  647. package/dist/nuxt/runtime/server/api/ai/transcribe.post.d.ts +0 -5
  648. package/dist/nuxt/runtime/server/api/ai/transcribe.post.js +0 -8
  649. package/dist/nuxt/runtime/server/api/ai/transcribe.post.js.map +0 -1
  650. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.d.ts +0 -5
  651. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js +0 -8
  652. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js.map +0 -1
  653. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.d.ts +0 -5
  654. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js +0 -8
  655. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js.map +0 -1
  656. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.d.ts +0 -5
  657. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js +0 -8
  658. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js.map +0 -1
  659. package/dist/nuxt/runtime/server/api/editor/settings.get.d.ts +0 -5
  660. package/dist/nuxt/runtime/server/api/editor/settings.get.js +0 -8
  661. package/dist/nuxt/runtime/server/api/editor/settings.get.js.map +0 -1
  662. package/dist/nuxt/runtime/server/api/editor/settings.put.d.ts +0 -5
  663. package/dist/nuxt/runtime/server/api/editor/settings.put.js +0 -8
  664. package/dist/nuxt/runtime/server/api/editor/settings.put.js.map +0 -1
  665. package/dist/nuxt/runtime/server/api/editor/tags.get.d.ts +0 -5
  666. package/dist/nuxt/runtime/server/api/editor/tags.get.js +0 -8
  667. package/dist/nuxt/runtime/server/api/editor/tags.get.js.map +0 -1
  668. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.d.ts +0 -5
  669. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js +0 -8
  670. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js.map +0 -1
  671. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.d.ts +0 -5
  672. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js +0 -8
  673. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js.map +0 -1
  674. package/dist/nuxt/runtime/server/api/editor/themes/index.get.d.ts +0 -5
  675. package/dist/nuxt/runtime/server/api/editor/themes/index.get.js +0 -8
  676. package/dist/nuxt/runtime/server/api/editor/themes/index.get.js.map +0 -1
  677. package/dist/nuxt/runtime/server/api/editor/themes/index.post.d.ts +0 -5
  678. package/dist/nuxt/runtime/server/api/editor/themes/index.post.js +0 -8
  679. package/dist/nuxt/runtime/server/api/editor/themes/index.post.js.map +0 -1
  680. package/dist/nuxt/runtime/server/api/editor/users.get.d.ts +0 -5
  681. package/dist/nuxt/runtime/server/api/editor/users.get.js +0 -8
  682. package/dist/nuxt/runtime/server/api/editor/users.get.js.map +0 -1
  683. package/dist/nuxt/runtime/server/plugins/collab.d.ts +0 -5
  684. package/dist/nuxt/runtime/server/plugins/collab.js +0 -10
  685. package/dist/nuxt/runtime/server/plugins/collab.js.map +0 -1
  686. package/dist/nuxt/runtime/server/routes/collab/[id].d.ts +0 -5
  687. package/dist/nuxt/runtime/server/routes/collab/[id].js +0 -35
  688. package/dist/nuxt/runtime/server/routes/collab/[id].js.map +0 -1
  689. package/dist/nuxt/runtime/server/utils/editor-route.d.ts +0 -11
  690. package/dist/nuxt/runtime/server/utils/editor-route.js.map +0 -1
  691. package/dist/presets/advanced.d.ts +0 -33
  692. package/dist/presets/advanced.js +0 -50
  693. package/dist/presets/advanced.js.map +0 -1
  694. package/dist/presets/simple.d.ts +0 -9
  695. package/dist/presets/simple.js +0 -12
  696. package/dist/presets/simple.js.map +0 -1
  697. package/dist/react/advanced-preset.d.ts +0 -11
  698. package/dist/react/advanced-preset.js +0 -31
  699. package/dist/react/advanced-preset.js.map +0 -1
  700. package/dist/vue/advanced-preset.d.ts +0 -13
  701. package/dist/vue/advanced-preset.js +0 -33
  702. package/dist/vue/advanced-preset.js.map +0 -1
  703. package/docs/extending.md +0 -538
  704. package/docs/integration.md +0 -632
  705. package/docs/llms.md +0 -383
  706. package/docs/usage.md +0 -1076
@@ -1 +1 @@
1
- {"version":3,"file":"CompositeDetails.js","names":[],"sources":["../../../../src/features/composites/react/CompositeDetails.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useEffect, useMemo, useState } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { Button } from '../../../react/ui/button'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { compositeKindsOf } from '../nodes'\nimport { compositeOfRow, type CompositeRow } from '../rows'\nimport { CompositeFieldEditor } from './CompositeFieldEditor'\nimport { CompositeSummaryEditor } from './CompositeSummaryEditor'\n\n/**\n * Content of the popover on a composite's front icon: the kind (a select, plain text while read-only), every field of\n * the kind except the status (its chip edits it) and the summary. Choosing another kind first shows an inline warning\n * that names the field values the switch drops (`setCompositeKind` keeps only meta keys the new kind declares) and\n * applies the change on „Ändern“.\n */\nexport function CompositeDetails({ editor, row, editable }: { editor: Editor, row: CompositeRow, editable: boolean }) {\n const { t } = useEditorI18n()\n const kinds = useMemo(() => compositeKindsOf(editor), [editor])\n const fields = row.fields.filter(field => field.key !== 'status')\n\n /** The kind chosen in the select, waiting for the confirmation. */\n const [pending, setPending] = useState<string | null>(null)\n // The kind changed some other way (undo, inspector, another select): a stale confirmation would be misleading.\n useEffect(() => {\n setPending(null)\n }, [row.kind])\n\n const pendingLabel = kinds.find(kind => kind.id === pending)?.label ?? ''\n\n /** Field values of the row that the pending kind does not declare, as „Label: value“. */\n const lost = useMemo(() => {\n const target = kinds.find(kind => kind.id === pending)\n if (!target) return []\n const kept = new Set(target.fields.map(field => field.key))\n return Object.entries(row.meta)\n .filter(([key, value]) => !kept.has(key) && value != null && value !== '')\n .map(([key, value]) => {\n const field = row.fields.find(candidate => candidate.key === key)\n const text = typeof value === 'object' ? JSON.stringify(value) : String(value)\n return { key, label: field?.label ?? key, text: field?.options?.find(option => option.value === text)?.label ?? text }\n })\n }, [kinds, pending, row.meta, row.fields])\n\n function onKind(kind: string) {\n setPending(kind !== row.kind ? kind : null)\n }\n\n function apply() {\n const kind = pending\n setPending(null)\n const found = compositeOfRow(editor.state.doc, row)\n if (kind && found) editor.commands.setCompositeKind(kind, found.pos)\n }\n\n return (\n <div className=\"flex w-72 flex-col gap-2.5 p-3 text-sm\">\n {editable\n ? (\n <Select value={row.kind} onValueChange={onKind}>\n <SelectTrigger size=\"sm\" className=\"w-full text-xs data-[size=sm]:h-6\" aria-label={t('composites.kind.select')}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {kinds.map(kind => (\n <SelectItem key={kind.id} value={kind.id}>\n <Icon name={kind.icon} />\n {kind.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )\n : (\n <p className=\"flex min-w-0 items-center gap-1.5 text-foreground\">\n <Icon key={row.icon} name={row.icon} className=\"size-4 shrink-0 text-muted-foreground\" />\n <span className=\"truncate\">{row.kindLabel}</span>\n </p>\n )}\n\n {pending && (\n <div role=\"alert\" className=\"flex flex-col gap-2 rounded-md bg-(--sk-warning)/10 p-2 text-xs text-foreground ring-1 ring-(--sk-warning)/40\">\n {lost.length > 0\n ? (\n <>\n <p className=\"font-medium\">\n {t('composites.details.confirmLost', { kind: pendingLabel })}\n </p>\n <ul className=\"flex flex-col gap-0.5\">\n {lost.map(item => (\n <li key={item.key} className=\"flex min-w-0 gap-1\">\n <span className=\"shrink-0 text-muted-foreground\">{item.label}:</span>\n <span className=\"truncate\" title={item.text}>{item.text}</span>\n </li>\n ))}\n </ul>\n </>\n )\n : (\n <p className=\"font-medium\">\n {t('composites.details.confirm')}\n </p>\n )}\n <div className=\"flex justify-end gap-1.5\">\n <Button size=\"xs\" variant=\"ghost\" onClick={() => setPending(null)}>{t('composites.details.cancel')}</Button>\n <Button size=\"xs\" className=\"bg-(--sk-warning) text-background hover:bg-(--sk-warning)/80\" onClick={apply}>{t('composites.details.change')}</Button>\n </div>\n </div>\n )}\n\n {fields.map(field => (\n <div key={field.key} className=\"flex flex-col gap-1\">\n <span className=\"text-xs text-muted-foreground\">{field.label}</span>\n <CompositeFieldEditor editor={editor} row={row} field={field} disabled={!editable} size=\"xs\" />\n </div>\n ))}\n\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-xs text-muted-foreground\">{t('composites.details.summary')}</span>\n <CompositeSummaryEditor editor={editor} row={row} readonly={!editable} />\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CompositeDetails.js","names":[],"sources":["../../../../src/features/composites/react/CompositeDetails.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useEffect, useMemo, useState } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { Button } from '../../../react/ui/button'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { derivationOf } from '../derivation'\nimport { keepsMetaKey } from '../meta-keys'\nimport { compositeKindsOf } from '../nodes'\nimport { compositeBacklinks, compositeOfRow, type CompositeRow } from '../rows'\nimport { CompositeFieldEditor } from './CompositeFieldEditor'\nimport { DerivationBadge } from './DerivationBadge'\nimport { CompositeSummaryEditor } from './CompositeSummaryEditor'\n\n/**\n * Content of the popover on a composite's front icon: the kind (a select, plain text while read-only), every field of\n * the kind except the status (its chip edits it) and the summary. Choosing another kind first shows an inline warning\n * that names the field values the switch drops (`setCompositeKind` keeps the meta keys the new kind declares, plus\n * `derivation` and `bib`, see `keepsMetaKey`) and\n * applies the change on „Ändern“.\n */\nexport function CompositeDetails({ editor, row, editable }: { editor: Editor, row: CompositeRow, editable: boolean }) {\n const { t } = useEditorI18n()\n const kinds = useMemo(() => compositeKindsOf(editor), [editor])\n // The `derivation` field is shown by the details badge below, with the checks a field display cannot do.\n const fields = row.fields.filter(field => field.key !== 'status' && field.type !== 'derivation')\n const derivedNode = useMemo(() => {\n const found = compositeOfRow(editor.state.doc, row)\n return found && derivationOf(found.node) ? found.node : null\n }, [editor, row])\n /** The places that refer to the row's Baustein (chips in other blocks, `reference` fields), for the „Verweise“ list. */\n const backlinks = useMemo(() => row.id ? compositeBacklinks(editor.state.doc, kinds, row.id) : [], [editor, kinds, row])\n\n /** The kind chosen in the select, waiting for the confirmation. */\n const [pending, setPending] = useState<string | null>(null)\n // The kind changed some other way (undo, inspector, another select): a stale confirmation would be misleading.\n useEffect(() => {\n setPending(null)\n }, [row.kind])\n\n const pendingLabel = kinds.find(kind => kind.id === pending)?.label ?? ''\n\n /** Field values of the row that the pending kind does not keep (`keepsMetaKey`), as „Label: value“. */\n const lost = useMemo(() => {\n const target = kinds.find(kind => kind.id === pending)\n if (!target) return []\n return Object.entries(row.meta)\n .filter(([key, value]) => !keepsMetaKey(target, key) && value != null && value !== '')\n .map(([key, value]) => {\n const field = row.fields.find(candidate => candidate.key === key)\n const text = typeof value === 'object' ? JSON.stringify(value) : String(value)\n return { key, label: field?.label ?? key, text: field?.options?.find(option => option.value === text)?.label ?? text }\n })\n }, [kinds, pending, row.meta, row.fields])\n\n function onKind(kind: string) {\n setPending(kind !== row.kind ? kind : null)\n }\n\n function apply() {\n const kind = pending\n setPending(null)\n const found = compositeOfRow(editor.state.doc, row)\n if (kind && found) editor.commands.setCompositeKind(kind, found.pos)\n }\n\n return (\n <div className=\"flex w-72 flex-col gap-2.5 p-3 text-sm\">\n {editable\n ? (\n <Select value={row.kind} onValueChange={onKind}>\n <SelectTrigger size=\"sm\" className=\"w-full text-xs data-[size=sm]:h-6\" aria-label={t('composites.kind.select')}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {kinds.map(kind => (\n <SelectItem key={kind.id} value={kind.id}>\n <Icon name={kind.icon} />\n {kind.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )\n : (\n <p className=\"flex min-w-0 items-center gap-1.5 text-foreground\">\n <Icon key={row.icon} name={row.icon} className=\"size-4 shrink-0 text-muted-foreground\" />\n <span className=\"truncate\">{row.kindLabel}</span>\n </p>\n )}\n\n {pending && (\n <div role=\"alert\" className=\"flex flex-col gap-2 rounded-md bg-(--sk-warning)/10 p-2 text-xs text-foreground ring-1 ring-(--sk-warning)/40\">\n {lost.length > 0\n ? (\n <>\n <p className=\"font-medium\">\n {t('composites.details.confirmLost', { kind: pendingLabel })}\n </p>\n <ul className=\"flex flex-col gap-0.5\">\n {lost.map(item => (\n <li key={item.key} className=\"flex min-w-0 gap-1\">\n <span className=\"shrink-0 text-muted-foreground\">{item.label}:</span>\n <span className=\"truncate\" title={item.text}>{item.text}</span>\n </li>\n ))}\n </ul>\n </>\n )\n : (\n <p className=\"font-medium\">\n {t('composites.details.confirm')}\n </p>\n )}\n <div className=\"flex justify-end gap-1.5\">\n <Button size=\"xs\" variant=\"ghost\" onClick={() => setPending(null)}>{t('composites.details.cancel')}</Button>\n <Button size=\"xs\" className=\"bg-(--sk-warning) text-background hover:bg-(--sk-warning)/80\" onClick={apply}>{t('composites.details.change')}</Button>\n </div>\n </div>\n )}\n\n {derivedNode && <DerivationBadge editor={editor} node={derivedNode} detailed />}\n\n {fields.map(field => (\n <div key={field.key} className=\"flex flex-col gap-1\">\n <span className=\"text-xs text-muted-foreground\">{field.label}</span>\n <CompositeFieldEditor editor={editor} row={row} field={field} disabled={!editable} size=\"xs\" />\n </div>\n ))}\n\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-xs text-muted-foreground\">{t('composites.details.summary')}</span>\n <CompositeSummaryEditor editor={editor} row={row} readonly={!editable} />\n </div>\n\n {backlinks.length > 0 && (\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-xs text-muted-foreground\">{t('composites.reference.backlinks')}</span>\n <ul className=\"flex flex-col gap-0.5\">\n {backlinks.map((link, index) => (\n <li key={`${link.from}:${index}`}>\n <button\n type=\"button\"\n className=\"flex w-full min-w-0 items-baseline gap-1 rounded-sm text-left text-xs text-foreground hover:text-primary focus-visible:outline-2 focus-visible:outline-primary\"\n onClick={() => editor.commands.revealBlock(link.from)}\n >\n <span className=\"truncate\">{link.excerpt || '…'}</span>\n {link.locator && <span className=\"shrink-0 text-muted-foreground\">{link.locator}</span>}\n </button>\n </li>\n ))}\n </ul>\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
@@ -13,6 +13,6 @@ export declare function CompositeFieldEditor({ editor, row, field, disabled, siz
13
13
  field: CompositeMetaField;
14
14
  disabled?: boolean;
15
15
  size?: 'xs' | 'sm' | 'md';
16
- }): import("react").JSX.Element;
16
+ }): import("react").JSX.Element | null;
17
17
  //#endregion
18
18
  //# sourceMappingURL=CompositeFieldEditor.d.ts.map
@@ -1,10 +1,13 @@
1
1
  import { useEditorI18n } from "../../../react/use-editor-i18n.js";
2
2
  import { cn } from "../../../react/ui/utils.js";
3
- import { setCompositeMetaField } from "../rows.js";
4
3
  import { Input } from "../../../react/ui/input.js";
5
4
  import { Textarea } from "../../../react/ui/textarea.js";
6
5
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../../react/ui/select.js";
6
+ import { compositeOfRow, setCompositeMetaField } from "../rows.js";
7
7
  import { metaText } from "../meta-display.js";
8
+ import { BibliographyEditor } from "./BibliographyEditor.js";
9
+ import { DerivationBadge } from "./DerivationBadge.js";
10
+ import { ReferenceFieldSelect } from "./ReferenceFieldSelect.js";
8
11
  import { useCallback, useEffect, useRef, useState } from "react";
9
12
  import { jsx, jsxs } from "react/jsx-runtime";
10
13
  //#region src/features/composites/react/CompositeFieldEditor.tsx
@@ -97,6 +100,45 @@ function CompositeFieldEditor({ editor, row, field, disabled, size = "sm" }) {
97
100
  children: option.label
98
101
  }, option.value)) })]
99
102
  });
103
+ if (field.type === "multiselect") {
104
+ const value = row.meta[field.key];
105
+ const chosen = Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
106
+ return /* @__PURE__ */ jsx("div", {
107
+ role: "group",
108
+ "aria-label": field.label,
109
+ className: "flex w-full flex-col gap-1",
110
+ children: (field.options ?? []).map((option) => /* @__PURE__ */ jsxs("label", {
111
+ className: cn("flex items-center gap-2", size === "md" ? "text-sm" : "text-xs"),
112
+ children: [/* @__PURE__ */ jsx("input", {
113
+ type: "checkbox",
114
+ className: "size-3.5 shrink-0 accent-(--sk-primary)",
115
+ checked: chosen.includes(option.value),
116
+ disabled,
117
+ onChange: (event) => setCompositeMetaField(editor, row, field.key, event.target.checked ? [...chosen, option.value] : chosen.filter((item) => item !== option.value))
118
+ }), option.label]
119
+ }, option.value))
120
+ });
121
+ }
122
+ if (field.type === "reference") return /* @__PURE__ */ jsx(ReferenceFieldSelect, {
123
+ editor,
124
+ row,
125
+ field,
126
+ disabled,
127
+ size
128
+ });
129
+ if (field.type === "bibliography") return /* @__PURE__ */ jsx(BibliographyEditor, {
130
+ editor,
131
+ row,
132
+ field,
133
+ disabled
134
+ });
135
+ if (field.type === "derivation") {
136
+ const derived = compositeOfRow(editor.state.doc, row)?.node;
137
+ return derived ? /* @__PURE__ */ jsx(DerivationBadge, {
138
+ editor,
139
+ node: derived
140
+ }) : null;
141
+ }
100
142
  if (field.type === "textarea") return /* @__PURE__ */ jsx(Textarea, {
101
143
  value: draft,
102
144
  "aria-label": field.label,
@@ -1 +1 @@
1
- {"version":3,"file":"CompositeFieldEditor.js","names":[],"sources":["../../../../src/features/composites/react/CompositeFieldEditor.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { Input } from '../../../react/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { Textarea } from '../../../react/ui/textarea'\nimport { cn } from '../../../react/ui/utils'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport type { CompositeMetaField } from '../kinds'\nimport { metaText } from '../meta-display'\nimport { type CompositeRow, setCompositeMetaField } from '../rows'\n\n/** Radix Select has no empty-string value: an option with an empty value travels as this sentinel. */\nconst EMPTY = '__empty__'\n\nconst INPUT_SIZE = {\n xs: 'h-6 px-2 text-xs md:text-xs',\n sm: 'h-7 px-2.5 text-sm md:text-sm',\n md: '',\n}\nconst TEXTAREA_SIZE = {\n xs: 'px-2 py-1 text-xs md:text-xs',\n sm: 'px-2.5 py-1.5 text-sm md:text-sm',\n md: '',\n}\nconst SELECT_SIZE = {\n xs: 'data-[size=sm]:h-6 text-xs',\n sm: 'data-[size=sm]:h-7',\n md: '',\n}\n\n/**\n * One meta field of a Baustein as an input that writes through `setCompositeMetaField`. Text-like inputs keep a local\n * draft and commit after typing pauses, on blur and on unmount, so the one-frame-late re-read of the rows never\n * overwrites what is being typed.\n */\nexport function CompositeFieldEditor({ editor, row, field, disabled, size = 'sm' }: {\n editor: Editor\n row: CompositeRow\n field: CompositeMetaField\n disabled?: boolean\n size?: 'xs' | 'sm' | 'md'\n}) {\n const { t } = useEditorI18n()\n const stored = metaText(row, field)\n const [draft, setDraft] = useState(stored)\n const draftRef = useRef(draft)\n const typing = useRef(false)\n const dirty = useRef(false)\n const timer = useRef<number | undefined>(undefined)\n // The latest props for the debounced commit and the flush on unmount; updated after every render, so the cleanup of a\n // changed `row.key` still sees the previous row.\n const target = useRef({ editor, row, field })\n useEffect(() => {\n target.current = { editor, row, field }\n })\n\n useEffect(() => {\n if (!typing.current && !dirty.current) {\n draftRef.current = stored\n setDraft(stored)\n }\n }, [stored, row.key])\n\n const commit = useCallback(() => {\n clearTimeout(timer.current)\n if (!dirty.current) return\n dirty.current = false\n const current = target.current\n if (!current.editor.isDestroyed) setCompositeMetaField(current.editor, current.row, current.field.key, draftRef.current)\n }, [])\n\n // Flush on unmount and when the field is bound to another row.\n useEffect(() => commit, [commit, editor, row.key, field.key])\n\n function onInput(value: string) {\n draftRef.current = value\n setDraft(value)\n dirty.current = true\n clearTimeout(timer.current)\n timer.current = window.setTimeout(commit, 400)\n }\n\n function onBlur() {\n typing.current = false\n commit()\n }\n\n function onChoice(value: string) {\n setCompositeMetaField(editor, row, field.key, value === EMPTY ? '' : value)\n }\n\n if (field.type === 'select') {\n return (\n <Select value={stored} onValueChange={onChoice} disabled={disabled}>\n <SelectTrigger size=\"sm\" className={cn('w-full', SELECT_SIZE[size])} aria-label={field.label}>\n <SelectValue placeholder={t('composites.field.choose', { field: field.label })} />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map(option => (\n <SelectItem key={option.value} value={option.value || EMPTY}>{option.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n )\n }\n\n if (field.type === 'textarea') {\n return (\n <Textarea\n value={draft}\n aria-label={field.label}\n disabled={disabled}\n rows={2}\n className={cn('max-h-[8.5rem] min-h-0 w-full', TEXTAREA_SIZE[size])}\n onFocus={() => {\n typing.current = true\n }}\n onBlur={onBlur}\n onChange={event => onInput(event.target.value)}\n />\n )\n }\n\n return (\n <Input\n value={draft}\n type={field.type}\n aria-label={field.label}\n disabled={disabled}\n className={cn('w-full', INPUT_SIZE[size])}\n onFocus={() => {\n typing.current = true\n }}\n onBlur={onBlur}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commit()\n }}\n onChange={event => onInput(event.target.value)}\n />\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CompositeFieldEditor.js","names":[],"sources":["../../../../src/features/composites/react/CompositeFieldEditor.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { Input } from '../../../react/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { Textarea } from '../../../react/ui/textarea'\nimport { cn } from '../../../react/ui/utils'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport type { CompositeMetaField } from '../kinds'\nimport { metaText } from '../meta-display'\nimport { compositeOfRow, type CompositeRow, setCompositeMetaField } from '../rows'\nimport { BibliographyEditor } from './BibliographyEditor'\nimport { DerivationBadge } from './DerivationBadge'\nimport { ReferenceFieldSelect } from './ReferenceFieldSelect'\n\n/** Radix Select has no empty-string value: an option with an empty value travels as this sentinel. */\nconst EMPTY = '__empty__'\n\nconst INPUT_SIZE = {\n xs: 'h-6 px-2 text-xs md:text-xs',\n sm: 'h-7 px-2.5 text-sm md:text-sm',\n md: '',\n}\nconst TEXTAREA_SIZE = {\n xs: 'px-2 py-1 text-xs md:text-xs',\n sm: 'px-2.5 py-1.5 text-sm md:text-sm',\n md: '',\n}\nconst SELECT_SIZE = {\n xs: 'data-[size=sm]:h-6 text-xs',\n sm: 'data-[size=sm]:h-7',\n md: '',\n}\n\n/**\n * One meta field of a Baustein as an input that writes through `setCompositeMetaField`. Text-like inputs keep a local\n * draft and commit after typing pauses, on blur and on unmount, so the one-frame-late re-read of the rows never\n * overwrites what is being typed.\n */\nexport function CompositeFieldEditor({ editor, row, field, disabled, size = 'sm' }: {\n editor: Editor\n row: CompositeRow\n field: CompositeMetaField\n disabled?: boolean\n size?: 'xs' | 'sm' | 'md'\n}) {\n const { t } = useEditorI18n()\n const stored = metaText(row, field)\n const [draft, setDraft] = useState(stored)\n const draftRef = useRef(draft)\n const typing = useRef(false)\n const dirty = useRef(false)\n const timer = useRef<number | undefined>(undefined)\n // The latest props for the debounced commit and the flush on unmount; updated after every render, so the cleanup of a\n // changed `row.key` still sees the previous row.\n const target = useRef({ editor, row, field })\n useEffect(() => {\n target.current = { editor, row, field }\n })\n\n useEffect(() => {\n if (!typing.current && !dirty.current) {\n draftRef.current = stored\n setDraft(stored)\n }\n }, [stored, row.key])\n\n const commit = useCallback(() => {\n clearTimeout(timer.current)\n if (!dirty.current) return\n dirty.current = false\n const current = target.current\n if (!current.editor.isDestroyed) setCompositeMetaField(current.editor, current.row, current.field.key, draftRef.current)\n }, [])\n\n // Flush on unmount and when the field is bound to another row.\n useEffect(() => commit, [commit, editor, row.key, field.key])\n\n function onInput(value: string) {\n draftRef.current = value\n setDraft(value)\n dirty.current = true\n clearTimeout(timer.current)\n timer.current = window.setTimeout(commit, 400)\n }\n\n function onBlur() {\n typing.current = false\n commit()\n }\n\n function onChoice(value: string) {\n setCompositeMetaField(editor, row, field.key, value === EMPTY ? '' : value)\n }\n\n if (field.type === 'select') {\n return (\n <Select value={stored} onValueChange={onChoice} disabled={disabled}>\n <SelectTrigger size=\"sm\" className={cn('w-full', SELECT_SIZE[size])} aria-label={field.label}>\n <SelectValue placeholder={t('composites.field.choose', { field: field.label })} />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map(option => (\n <SelectItem key={option.value} value={option.value || EMPTY}>{option.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n )\n }\n\n if (field.type === 'multiselect') {\n const value = row.meta[field.key]\n const chosen = Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : []\n return (\n <div role=\"group\" aria-label={field.label} className=\"flex w-full flex-col gap-1\">\n {(field.options ?? []).map(option => (\n <label key={option.value} className={cn('flex items-center gap-2', size === 'md' ? 'text-sm' : 'text-xs')}>\n <input\n type=\"checkbox\"\n className=\"size-3.5 shrink-0 accent-(--sk-primary)\"\n checked={chosen.includes(option.value)}\n disabled={disabled}\n onChange={event => setCompositeMetaField(editor, row, field.key, event.target.checked ? [...chosen, option.value] : chosen.filter(item => item !== option.value))}\n />\n {option.label}\n </label>\n ))}\n </div>\n )\n }\n\n if (field.type === 'reference') {\n return <ReferenceFieldSelect editor={editor} row={row} field={field} disabled={disabled} size={size} />\n }\n\n if (field.type === 'bibliography') {\n return <BibliographyEditor editor={editor} row={row} field={field} disabled={disabled} />\n }\n\n if (field.type === 'derivation') {\n const derived = compositeOfRow(editor.state.doc, row)?.node\n return derived ? <DerivationBadge editor={editor} node={derived} /> : null\n }\n\n if (field.type === 'textarea') {\n return (\n <Textarea\n value={draft}\n aria-label={field.label}\n disabled={disabled}\n rows={2}\n className={cn('max-h-[8.5rem] min-h-0 w-full', TEXTAREA_SIZE[size])}\n onFocus={() => {\n typing.current = true\n }}\n onBlur={onBlur}\n onChange={event => onInput(event.target.value)}\n />\n )\n }\n\n return (\n <Input\n value={draft}\n type={field.type}\n aria-label={field.label}\n disabled={disabled}\n className={cn('w-full', INPUT_SIZE[size])}\n onFocus={() => {\n typing.current = true\n }}\n onBlur={onBlur}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commit()\n }}\n onChange={event => onInput(event.target.value)}\n />\n )\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,MAAM,QAAQ;AAEd,MAAM,aAAa;CACjB,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AACA,MAAM,gBAAgB;CACpB,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AACA,MAAM,cAAc;CAClB,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;;;;;;AAOA,SAAgB,qBAAqB,EAAE,QAAQ,KAAK,OAAO,UAAU,OAAO,QAMzE;CACD,MAAM,EAAE,MAAM,cAAc;CAC5B,MAAM,SAAS,SAAS,KAAK,KAAK;CAClC,MAAM,CAAC,OAAO,YAAY,SAAS,MAAM;CACzC,MAAM,WAAW,OAAO,KAAK;CAC7B,MAAM,SAAS,OAAO,KAAK;CAC3B,MAAM,QAAQ,OAAO,KAAK;CAC1B,MAAM,QAAQ,OAA2B,KAAA,CAAS;CAGlD,MAAM,SAAS,OAAO;EAAE;EAAQ;EAAK;CAAM,CAAC;CAC5C,gBAAgB;EACd,OAAO,UAAU;GAAE;GAAQ;GAAK;EAAM;CACxC,CAAC;CAED,gBAAgB;EACd,IAAI,CAAC,OAAO,WAAW,CAAC,MAAM,SAAS;GACrC,SAAS,UAAU;GACnB,SAAS,MAAM;EACjB;CACF,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC;CAEpB,MAAM,SAAS,kBAAkB;EAC/B,aAAa,MAAM,OAAO;EAC1B,IAAI,CAAC,MAAM,SAAS;EACpB,MAAM,UAAU;EAChB,MAAM,UAAU,OAAO;EACvB,IAAI,CAAC,QAAQ,OAAO,aAAa,sBAAsB,QAAQ,QAAQ,QAAQ,KAAK,QAAQ,MAAM,KAAK,SAAS,OAAO;CACzH,GAAG,CAAC,CAAC;CAGL,gBAAgB,QAAQ;EAAC;EAAQ;EAAQ,IAAI;EAAK,MAAM;CAAG,CAAC;CAE5D,SAAS,QAAQ,OAAe;EAC9B,SAAS,UAAU;EACnB,SAAS,KAAK;EACd,MAAM,UAAU;EAChB,aAAa,MAAM,OAAO;EAC1B,MAAM,UAAU,OAAO,WAAW,QAAQ,GAAG;CAC/C;CAEA,SAAS,SAAS;EAChB,OAAO,UAAU;EACjB,OAAO;CACT;CAEA,SAAS,SAAS,OAAe;EAC/B,sBAAsB,QAAQ,KAAK,MAAM,KAAK,UAAU,QAAQ,KAAK,KAAK;CAC5E;CAEA,IAAI,MAAM,SAAS,UACjB,OACE,qBAAC,QAAD;EAAQ,OAAO;EAAQ,eAAe;EAAoB;EAA1D,UAAA,CACE,oBAAC,eAAD;GAAe,MAAK;GAAK,WAAW,GAAG,UAAU,YAAY,KAAK;GAAG,cAAY,MAAM;GACrF,UAAA,oBAAC,aAAD,EAAa,aAAa,EAAE,2BAA2B,EAAE,OAAO,MAAM,MAAM,CAAC,EAAI,CAAA;EACpE,CAAA,GACf,oBAAC,eAAD,EAAA,WACI,MAAM,WAAW,CAAC,EAAA,CAAG,KAAI,WACzB,oBAAC,YAAD;GAA+B,OAAO,OAAO,SAAS;GAAQ,UAAA,OAAO;EAAkB,GAAtE,OAAO,KAA+D,CACxF,EACY,CAAA,CACT;;CAIZ,IAAI,MAAM,SAAS,eAAe;EAChC,MAAM,QAAQ,IAAI,KAAK,MAAM;EAC7B,MAAM,SAAS,MAAM,QAAQ,KAAK,IAAI,MAAM,QAAQ,SAAyB,OAAO,SAAS,QAAQ,IAAI,CAAC;EAC1G,OACE,oBAAC,OAAD;GAAK,MAAK;GAAQ,cAAY,MAAM;GAAO,WAAU;GACjD,WAAA,MAAM,WAAW,CAAC,EAAA,CAAG,KAAI,WACzB,qBAAC,SAAD;IAA0B,WAAW,GAAG,2BAA2B,SAAS,OAAO,YAAY,SAAS;IAAxG,UAAA,CACE,oBAAC,SAAD;KACE,MAAK;KACL,WAAU;KACV,SAAS,OAAO,SAAS,OAAO,KAAK;KAC3B;KACV,WAAU,UAAS,sBAAsB,QAAQ,KAAK,MAAM,KAAK,MAAM,OAAO,UAAU,CAAC,GAAG,QAAQ,OAAO,KAAK,IAAI,OAAO,QAAO,SAAQ,SAAS,OAAO,KAAK,CAAC;IACjK,CAAA,GACA,OAAO,KACH;GATK,GAAA,OAAO,KASZ,CACR;EACE,CAAA;CAET;CAEA,IAAI,MAAM,SAAS,aACjB,OAAO,oBAAC,sBAAD;EAA8B;EAAa;EAAY;EAAiB;EAAgB;CAAO,CAAA;CAGxG,IAAI,MAAM,SAAS,gBACjB,OAAO,oBAAC,oBAAD;EAA4B;EAAa;EAAY;EAAiB;CAAW,CAAA;CAG1F,IAAI,MAAM,SAAS,cAAc;EAC/B,MAAM,UAAU,eAAe,OAAO,MAAM,KAAK,GAAG,CAAC,EAAE;EACvD,OAAO,UAAU,oBAAC,iBAAD;GAAyB;GAAQ,MAAM;EAAU,CAAA,IAAI;CACxE;CAEA,IAAI,MAAM,SAAS,YACjB,OACE,oBAAC,UAAD;EACE,OAAO;EACP,cAAY,MAAM;EACR;EACV,MAAM;EACN,WAAW,GAAG,iCAAiC,cAAc,KAAK;EAClE,eAAe;GACb,OAAO,UAAU;EACnB;EACQ;EACR,WAAU,UAAS,QAAQ,MAAM,OAAO,KAAK;CAC9C,CAAA;CAIL,OACE,oBAAC,OAAD;EACE,OAAO;EACP,MAAM,MAAM;EACZ,cAAY,MAAM;EACR;EACV,WAAW,GAAG,UAAU,WAAW,KAAK;EACxC,eAAe;GACb,OAAO,UAAU;EACnB;EACQ;EACR,YAAY,UAAU;GACpB,IAAI,MAAM,QAAQ,SAAS,OAAO;EACpC;EACA,WAAU,UAAS,QAAQ,MAAM,OAAO,KAAK;CAC9C,CAAA;AAEL"}
@@ -1,15 +1,16 @@
1
+ import { normalizeTagName } from "../../../core/tag-name.js";
1
2
  import { useEditorI18n } from "../../../react/use-editor-i18n.js";
2
3
  import { cn } from "../../../react/ui/utils.js";
3
4
  import { Icon } from "../../../react/Icon.js";
4
- import { normalizeTagName } from "../../../core/tag-name.js";
5
- import { compositeFieldText } from "../inspector-model.js";
6
- import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../../../react/ui/popover.js";
7
5
  import { Input } from "../../../react/ui/input.js";
8
6
  import { Textarea } from "../../../react/ui/textarea.js";
7
+ import { Command, CommandInput, CommandItem, CommandList } from "../../../react/ui/command.js";
8
+ import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../../../react/ui/popover.js";
9
9
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../../react/ui/select.js";
10
10
  import { Label } from "../../../react/ui/label.js";
11
11
  import { Badge } from "../../../react/ui/badge.js";
12
- import { Command, CommandInput, CommandItem, CommandList } from "../../../react/ui/command.js";
12
+ import { CompositeFieldEditor } from "./CompositeFieldEditor.js";
13
+ import { compositeFieldText, isStructuredField } from "../inspector-model.js";
13
14
  import { useCompositeInspector } from "./use-composite-inspector.js";
14
15
  import { useEffect, useId, useState } from "react";
15
16
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -218,7 +219,7 @@ function CompositeInspector({ editor, documentFocused, document, className }) {
218
219
  onBlur: inspector.blurDescription
219
220
  })
220
221
  }),
221
- /* @__PURE__ */ jsx(FormField, {
222
+ focused.tagsVisible && /* @__PURE__ */ jsx(FormField, {
222
223
  label: t("composites.tags.label"),
223
224
  children: /* @__PURE__ */ jsxs(Popover, {
224
225
  open: tagsOpen,
@@ -299,7 +300,12 @@ function CompositeInspector({ editor, documentFocused, document, className }) {
299
300
  }),
300
301
  focused.fields.map((field) => /* @__PURE__ */ jsx(FormField, {
301
302
  label: field.label,
302
- children: field.type === "select" ? /* @__PURE__ */ jsxs(Select, {
303
+ children: isStructuredField(field) ? editor && /* @__PURE__ */ jsx(CompositeFieldEditor, {
304
+ editor,
305
+ row: focused,
306
+ field,
307
+ disabled: !editable
308
+ }) : field.type === "select" ? /* @__PURE__ */ jsxs(Select, {
303
309
  value: compositeFieldText(focused, field),
304
310
  onValueChange: (value) => inspector.setField(field, value),
305
311
  disabled: !editable,
@@ -1 +1 @@
1
- {"version":3,"file":"CompositeInspector.js","names":[],"sources":["../../../../src/features/composites/react/CompositeInspector.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { type CSSProperties, type ReactNode, useEffect, useId, useState } from 'react'\nimport { normalizeTagName } from '../../../core/tag-name'\nimport { Icon } from '../../../react/Icon'\nimport { Badge } from '../../../react/ui/badge'\nimport { Command, CommandInput, CommandItem, CommandList } from '../../../react/ui/command'\nimport { Input } from '../../../react/ui/input'\nimport { Label } from '../../../react/ui/label'\nimport { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from '../../../react/ui/popover'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { Textarea } from '../../../react/ui/textarea'\nimport { cn } from '../../../react/ui/utils'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport type { CompositeMetaField } from '../kinds'\nimport { compositeFieldText } from '../inspector-model'\nimport { useCompositeInspector } from './use-composite-inspector'\n\nconst HEX_COLOR = /^#[0-9a-f]{3,8}$/i\n// Same tint as the chip in the document (`--mention-color`), only invalid colors fall back to the primary color.\nconst mentionStyle = (color: string | null) => ({ '--mention-color': color && HEX_COLOR.test(color) ? color : 'var(--sk-primary)' }) as CSSProperties\n\n/** A label (+ help) above its control; the counterpart of Nuxt UI's `UFormField` (size `sm`). */\nfunction FormField({ label, help, children }: { label: string, help?: string, children: ReactNode }) {\n return (\n <div className=\"flex flex-col gap-1.5\">\n <Label className=\"text-xs font-medium text-foreground\">{label}</Label>\n {children}\n {help && <p className=\"text-xs text-muted-foreground\">{help}</p>}\n </div>\n )\n}\n\n/**\n * A meta field input that writes through on every change like the Vue `UInput`/`UTextarea` bound to the row. The\n * document is re-read asynchronously (once per frame), so a purely controlled input would snap back while typing:\n * it keeps the typed value locally and follows the document whenever the document's value changes.\n */\nfunction MetaFieldInput({ field, value, readOnly, onChange }: {\n field: CompositeMetaField\n value: string\n readOnly: boolean\n onChange: (value: string) => void\n}) {\n const [local, setLocal] = useState(value)\n useEffect(() => setLocal(value), [value])\n const set = (next: string) => {\n setLocal(next)\n onChange(next)\n }\n return field.type === 'textarea'\n ? (\n <Textarea\n value={local}\n aria-label={field.label}\n rows={2}\n className=\"max-h-40 min-h-12 w-full resize-none overflow-y-auto text-sm md:text-sm\"\n readOnly={readOnly}\n onChange={event => set(event.target.value)}\n />\n )\n : (\n <Input\n value={local}\n type={field.type}\n aria-label={field.label}\n className=\"h-7 w-full text-sm md:text-sm\"\n readOnly={readOnly}\n onChange={event => set(event.target.value)}\n />\n )\n}\n\n/**\n * Side panel with the metadata of the document *or* of the Baustein under the caret — one at a time — connected to\n * `editor`. Fills the height of its container and scrolls on its own; the width comes from the host. Open/close is\n * the host's business. The `document` prop carries host-provided document facts (title, folder, dates, presence) at\n * the top of the „Dokument“ section: render them as a `<dl>` with the same grid as below to look native.\n *\n * The „Baustein“ section shows while the caret is in a Baustein of the editor; the „Dokument“ section shows before\n * the editor was ever focused, while the caret is in editor text outside any Baustein, and while `documentFocused`.\n * `documentFocused`: the host's document-level input (its title field) has the focus. While it is true the panel\n * shows the „Dokument“ section and keeps showing it after the input blurs, until the caret returns to the editor.\n */\nexport function CompositeInspector({ editor, documentFocused, document, className }: {\n editor?: Editor\n documentFocused?: boolean\n /** Document facts known to the host only, rendered above the facts derived from the editor. */\n document?: ReactNode\n className?: string\n}) {\n const { t } = useEditorI18n()\n const { state, inspector } = useCompositeInspector(editor, documentFocused)\n const { section, editable, draft, searchTerm: term, tagItems, kindOptions, summarized, hasSummary, rows, tags, kinds, mentions, focused } = state\n const [tagsOpen, setTagsOpen] = useState(false)\n const uid = useId()\n\n return (\n <aside className={cn('flex h-full min-h-0 flex-col overflow-y-auto text-sm', className)} aria-label={t('composites.inspector.label')}>\n {section === 'document'\n ? (\n <section className=\"flex-1 p-4\" aria-labelledby={`${uid}-document`}>\n <h2 id={`${uid}-document`} className=\"mb-3 text-sm font-semibold text-foreground\">\n {t('composites.inspector.document')}\n </h2>\n <div className=\"flex flex-col gap-y-2\">\n {document}\n <dl className=\"grid grid-cols-[6.5rem_minmax(0,1fr)] items-start gap-x-3 gap-y-2\">\n <dt className=\"min-h-6 leading-6 text-muted-foreground\">\n {t('composites.inspector.composites')}\n </dt>\n {kinds.length\n ? (\n <dd className=\"m-0 flex min-w-0 flex-col gap-y-1\">\n {kinds.map(kind => (\n <span key={kind.id} className=\"flex min-h-6 min-w-0 items-center gap-2\">\n <Icon name={kind.icon} className=\"size-4 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate text-foreground\">{kind.label}</span>\n <span className=\"text-muted-foreground tabular-nums\">{kind.count}</span>\n </span>\n ))}\n <span className=\"min-h-6 leading-6 text-muted-foreground tabular-nums\">\n {t('composites.inspector.summarized', { n: summarized, total: rows.length })}\n </span>\n </dd>\n )\n : (\n <dd className=\"m-0 min-h-6 leading-6 text-muted-foreground/70\">\n {t('composites.inspector.none')}\n </dd>\n )}\n\n <dt className=\"min-h-6 leading-6 text-muted-foreground\">\n {t('composites.tags.label')}\n </dt>\n {tags.length\n ? (\n <dd className=\"m-0 flex min-w-0 flex-wrap items-center gap-1\">\n {tags.map(tag => <Badge key={tag} variant=\"secondary\" className=\"max-w-full\">{`#${tag}`}</Badge>)}\n </dd>\n )\n : (\n <dd className=\"m-0 min-h-6 leading-6 text-muted-foreground/70\">\n {t('composites.inspector.none')}\n </dd>\n )}\n\n <dt className=\"min-h-6 leading-6 text-muted-foreground\">\n {t('composites.inspector.mentions')}\n </dt>\n {mentions.length\n ? (\n <dd className=\"m-0 flex min-w-0 flex-wrap items-center gap-1\">\n {mentions.map(mention => (\n <span\n key={mention.id}\n className=\"inline-flex max-w-full items-center gap-1.5 truncate rounded-sm px-1.5 py-0.5 text-xs font-medium text-foreground\"\n style={{ ...mentionStyle(mention.color), background: 'color-mix(in oklab, var(--mention-color) 15%, transparent)' }}\n >\n <span className=\"size-1.5 shrink-0 rounded-full\" style={{ background: 'var(--mention-color)' }} />\n <span className=\"truncate\">@{mention.label}</span>\n </span>\n ))}\n </dd>\n )\n : (\n <dd className=\"m-0 min-h-6 leading-6 text-muted-foreground/70\">\n {t('composites.inspector.none')}\n </dd>\n )}\n </dl>\n </div>\n </section>\n )\n : focused && (\n <section className=\"flex-1 p-4\" aria-labelledby={`${uid}-composite`}>\n <h2 id={`${uid}-composite`} className=\"mb-3 text-sm font-semibold text-foreground\">\n {t('composites.inspector.composite')}\n </h2>\n\n <div key={focused.key} className=\"flex flex-col gap-3\">\n <FormField label={t('composites.inspector.kind')}>\n <Select value={focused.kind} onValueChange={inspector.setKind} disabled={!editable}>\n <SelectTrigger size=\"sm\" className=\"w-full\" aria-label={t('composites.kind.select')}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {kindOptions.map(item => (\n <SelectItem key={item.value} value={item.value}>\n <Icon name={item.icon} />\n {item.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </FormField>\n\n <FormField label={t('composites.inspector.title')} help={editable ? t('composites.inspector.titleHelp') : undefined}>\n <p className={cn('min-h-6 truncate leading-6', focused.title ? 'text-foreground' : 'text-muted-foreground/70')} title={focused.title}>\n {focused.title || t('composites.inspector.untitled')}\n </p>\n </FormField>\n\n <FormField\n label={t('composites.inspector.description')}\n help={focused.descriptionTextOnly ? undefined : t('composites.inspector.descriptionHelp')}\n >\n <Textarea\n value={draft}\n rows={3}\n className=\"max-h-52 min-h-[4.5rem] w-full resize-none overflow-y-auto text-sm md:text-sm\"\n placeholder={t('composites.inspector.description')}\n aria-label={t('composites.inspector.description')}\n readOnly={!editable || !focused.descriptionTextOnly}\n onChange={event => inspector.inputDescription(event.target.value)}\n onBlur={inspector.blurDescription}\n />\n </FormField>\n\n <FormField label={t('composites.tags.label')}>\n <Popover\n open={tagsOpen}\n onOpenChange={(isOpen) => {\n setTagsOpen(isOpen)\n if (isOpen) inspector.searchTags()\n }}\n >\n <PopoverAnchor asChild>\n <div className={cn('flex min-h-7 w-full flex-wrap items-center gap-1 rounded-lg border border-input px-2 py-1 dark:bg-input/30', !editable && 'opacity-50')}>\n <Icon name=\"i-lucide-hash\" className=\"size-3.5 text-muted-foreground\" />\n {focused.tags.map(tag => (\n <Badge key={tag} variant=\"secondary\" className=\"max-w-full gap-0.5 pr-1\">\n <span className=\"truncate\">{tag}</span>\n <button\n type=\"button\"\n className=\"inline-flex cursor-pointer items-center rounded-full outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/50 disabled:cursor-not-allowed\"\n aria-label={t('composites.tag.remove', { tag })}\n disabled={!editable}\n onClick={() => inspector.setTags(focused.tags.filter(item => item !== tag))}\n >\n <Icon name=\"i-lucide-x\" className=\"size-3\" />\n </button>\n </Badge>\n ))}\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n role=\"combobox\"\n aria-expanded={tagsOpen}\n aria-label={t('composites.tags.label')}\n disabled={!editable}\n className=\"min-w-12 flex-1 cursor-text self-stretch rounded text-left text-sm text-muted-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring/50 disabled:cursor-not-allowed\"\n >\n {focused.tags.length ? '' : t('composites.tags.label')}\n </button>\n </PopoverTrigger>\n </div>\n </PopoverAnchor>\n <PopoverContent align=\"start\" className=\"w-64 gap-0 p-0\">\n {/* `shouldFilter` off: the list is the metadata source's answer to the search term. */}\n <Command shouldFilter={false}>\n <CommandInput\n value={term}\n onValueChange={inspector.setSearchTerm}\n placeholder={t('composites.tags.label')}\n aria-label={t('composites.tags.label')}\n onKeyDown={(event) => {\n if (event.key === 'Backspace' && !term && focused.tags.length) inspector.setTags(focused.tags.slice(0, -1))\n }}\n />\n <CommandList>\n {tagItems.map((tag) => {\n const selected = focused.tags.includes(tag)\n return (\n <CommandItem\n key={tag}\n value={tag}\n data-checked={selected}\n onSelect={() => inspector.setTags(selected ? focused.tags.filter(item => item !== tag) : [...focused.tags, tag])}\n >\n {tag}\n </CommandItem>\n )\n })}\n {term.trim() && (\n <CommandItem value={`__create__:${term}`} onSelect={() => inspector.createTag(term)}>\n <Icon name=\"i-lucide-plus\" />\n {t('composites.tags.create', { tag: normalizeTagName(term) || term })}\n </CommandItem>\n )}\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n </FormField>\n\n {focused.fields.map(field => (\n <FormField key={field.key} label={field.label}>\n {field.type === 'select'\n ? (\n <Select value={compositeFieldText(focused, field)} onValueChange={value => inspector.setField(field, value)} disabled={!editable}>\n <SelectTrigger size=\"sm\" className=\"w-full\" aria-label={field.label}>\n <SelectValue placeholder=\"–\" />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map(option => <SelectItem key={option.value} value={option.value}>{option.label}</SelectItem>)}\n </SelectContent>\n </Select>\n )\n : (\n <MetaFieldInput\n field={field}\n value={compositeFieldText(focused, field)}\n readOnly={!editable}\n onChange={value => inspector.setField(field, value)}\n />\n )}\n </FormField>\n ))}\n\n <div className=\"flex items-center gap-2 border-t border-border pt-3\">\n <Icon name=\"i-lucide-sparkles\" className=\"size-4 shrink-0 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">{t('composites.inspector.aiStatus')}</span>\n <span className={cn('ml-auto inline-flex items-center gap-1.5', hasSummary ? 'text-foreground' : 'text-muted-foreground/70')}>\n <span className={cn('size-2 rounded-full', hasSummary ? 'bg-(--sk-success)' : 'bg-border')} />\n {hasSummary ? t('composites.inspector.summaryPresent') : t('composites.inspector.summaryMissing')}\n </span>\n </div>\n </div>\n </section>\n )}\n </aside>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CompositeInspector.js","names":[],"sources":["../../../../src/features/composites/react/CompositeInspector.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { type CSSProperties, type ReactNode, useEffect, useId, useState } from 'react'\nimport { normalizeTagName } from '../../../core/tag-name'\nimport { Icon } from '../../../react/Icon'\nimport { Badge } from '../../../react/ui/badge'\nimport { Command, CommandInput, CommandItem, CommandList } from '../../../react/ui/command'\nimport { Input } from '../../../react/ui/input'\nimport { Label } from '../../../react/ui/label'\nimport { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from '../../../react/ui/popover'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { Textarea } from '../../../react/ui/textarea'\nimport { cn } from '../../../react/ui/utils'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport type { CompositeMetaField } from '../kinds'\nimport { compositeFieldText, isStructuredField } from '../inspector-model'\nimport { CompositeFieldEditor } from './CompositeFieldEditor'\nimport { useCompositeInspector } from './use-composite-inspector'\n\nconst HEX_COLOR = /^#[0-9a-f]{3,8}$/i\n// Same tint as the chip in the document (`--mention-color`), only invalid colors fall back to the primary color.\nconst mentionStyle = (color: string | null) => ({ '--mention-color': color && HEX_COLOR.test(color) ? color : 'var(--sk-primary)' }) as CSSProperties\n\n/** A label (+ help) above its control; the counterpart of Nuxt UI's `UFormField` (size `sm`). */\nfunction FormField({ label, help, children }: { label: string, help?: string, children: ReactNode }) {\n return (\n <div className=\"flex flex-col gap-1.5\">\n <Label className=\"text-xs font-medium text-foreground\">{label}</Label>\n {children}\n {help && <p className=\"text-xs text-muted-foreground\">{help}</p>}\n </div>\n )\n}\n\n/**\n * A meta field input that writes through on every change like the Vue `UInput`/`UTextarea` bound to the row. The\n * document is re-read asynchronously (once per frame), so a purely controlled input would snap back while typing:\n * it keeps the typed value locally and follows the document whenever the document's value changes.\n */\nfunction MetaFieldInput({ field, value, readOnly, onChange }: {\n field: CompositeMetaField\n value: string\n readOnly: boolean\n onChange: (value: string) => void\n}) {\n const [local, setLocal] = useState(value)\n useEffect(() => setLocal(value), [value])\n const set = (next: string) => {\n setLocal(next)\n onChange(next)\n }\n return field.type === 'textarea'\n ? (\n <Textarea\n value={local}\n aria-label={field.label}\n rows={2}\n className=\"max-h-40 min-h-12 w-full resize-none overflow-y-auto text-sm md:text-sm\"\n readOnly={readOnly}\n onChange={event => set(event.target.value)}\n />\n )\n : (\n <Input\n value={local}\n type={field.type}\n aria-label={field.label}\n className=\"h-7 w-full text-sm md:text-sm\"\n readOnly={readOnly}\n onChange={event => set(event.target.value)}\n />\n )\n}\n\n/**\n * Side panel with the metadata of the document *or* of the Baustein under the caret — one at a time — connected to\n * `editor`. Fills the height of its container and scrolls on its own; the width comes from the host. Open/close is\n * the host's business. The `document` prop carries host-provided document facts (title, folder, dates, presence) at\n * the top of the „Dokument“ section: render them as a `<dl>` with the same grid as below to look native.\n *\n * The „Baustein“ section shows while the caret is in a Baustein of the editor; the „Dokument“ section shows before\n * the editor was ever focused, while the caret is in editor text outside any Baustein, and while `documentFocused`.\n * `documentFocused`: the host's document-level input (its title field) has the focus. While it is true the panel\n * shows the „Dokument“ section and keeps showing it after the input blurs, until the caret returns to the editor.\n */\nexport function CompositeInspector({ editor, documentFocused, document, className }: {\n editor?: Editor\n documentFocused?: boolean\n /** Document facts known to the host only, rendered above the facts derived from the editor. */\n document?: ReactNode\n className?: string\n}) {\n const { t } = useEditorI18n()\n const { state, inspector } = useCompositeInspector(editor, documentFocused)\n const { section, editable, draft, searchTerm: term, tagItems, kindOptions, summarized, hasSummary, rows, tags, kinds, mentions, focused } = state\n const [tagsOpen, setTagsOpen] = useState(false)\n const uid = useId()\n\n return (\n <aside className={cn('flex h-full min-h-0 flex-col overflow-y-auto text-sm', className)} aria-label={t('composites.inspector.label')}>\n {section === 'document'\n ? (\n <section className=\"flex-1 p-4\" aria-labelledby={`${uid}-document`}>\n <h2 id={`${uid}-document`} className=\"mb-3 text-sm font-semibold text-foreground\">\n {t('composites.inspector.document')}\n </h2>\n <div className=\"flex flex-col gap-y-2\">\n {document}\n <dl className=\"grid grid-cols-[6.5rem_minmax(0,1fr)] items-start gap-x-3 gap-y-2\">\n <dt className=\"min-h-6 leading-6 text-muted-foreground\">\n {t('composites.inspector.composites')}\n </dt>\n {kinds.length\n ? (\n <dd className=\"m-0 flex min-w-0 flex-col gap-y-1\">\n {kinds.map(kind => (\n <span key={kind.id} className=\"flex min-h-6 min-w-0 items-center gap-2\">\n <Icon name={kind.icon} className=\"size-4 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate text-foreground\">{kind.label}</span>\n <span className=\"text-muted-foreground tabular-nums\">{kind.count}</span>\n </span>\n ))}\n <span className=\"min-h-6 leading-6 text-muted-foreground tabular-nums\">\n {t('composites.inspector.summarized', { n: summarized, total: rows.length })}\n </span>\n </dd>\n )\n : (\n <dd className=\"m-0 min-h-6 leading-6 text-muted-foreground/70\">\n {t('composites.inspector.none')}\n </dd>\n )}\n\n <dt className=\"min-h-6 leading-6 text-muted-foreground\">\n {t('composites.tags.label')}\n </dt>\n {tags.length\n ? (\n <dd className=\"m-0 flex min-w-0 flex-wrap items-center gap-1\">\n {tags.map(tag => <Badge key={tag} variant=\"secondary\" className=\"max-w-full\">{`#${tag}`}</Badge>)}\n </dd>\n )\n : (\n <dd className=\"m-0 min-h-6 leading-6 text-muted-foreground/70\">\n {t('composites.inspector.none')}\n </dd>\n )}\n\n <dt className=\"min-h-6 leading-6 text-muted-foreground\">\n {t('composites.inspector.mentions')}\n </dt>\n {mentions.length\n ? (\n <dd className=\"m-0 flex min-w-0 flex-wrap items-center gap-1\">\n {mentions.map(mention => (\n <span\n key={mention.id}\n className=\"inline-flex max-w-full items-center gap-1.5 truncate rounded-sm px-1.5 py-0.5 text-xs font-medium text-foreground\"\n style={{ ...mentionStyle(mention.color), background: 'color-mix(in oklab, var(--mention-color) 15%, transparent)' }}\n >\n <span className=\"size-1.5 shrink-0 rounded-full\" style={{ background: 'var(--mention-color)' }} />\n <span className=\"truncate\">@{mention.label}</span>\n </span>\n ))}\n </dd>\n )\n : (\n <dd className=\"m-0 min-h-6 leading-6 text-muted-foreground/70\">\n {t('composites.inspector.none')}\n </dd>\n )}\n </dl>\n </div>\n </section>\n )\n : focused && (\n <section className=\"flex-1 p-4\" aria-labelledby={`${uid}-composite`}>\n <h2 id={`${uid}-composite`} className=\"mb-3 text-sm font-semibold text-foreground\">\n {t('composites.inspector.composite')}\n </h2>\n\n <div key={focused.key} className=\"flex flex-col gap-3\">\n <FormField label={t('composites.inspector.kind')}>\n <Select value={focused.kind} onValueChange={inspector.setKind} disabled={!editable}>\n <SelectTrigger size=\"sm\" className=\"w-full\" aria-label={t('composites.kind.select')}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {kindOptions.map(item => (\n <SelectItem key={item.value} value={item.value}>\n <Icon name={item.icon} />\n {item.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </FormField>\n\n <FormField label={t('composites.inspector.title')} help={editable ? t('composites.inspector.titleHelp') : undefined}>\n <p className={cn('min-h-6 truncate leading-6', focused.title ? 'text-foreground' : 'text-muted-foreground/70')} title={focused.title}>\n {focused.title || t('composites.inspector.untitled')}\n </p>\n </FormField>\n\n <FormField\n label={t('composites.inspector.description')}\n help={focused.descriptionTextOnly ? undefined : t('composites.inspector.descriptionHelp')}\n >\n <Textarea\n value={draft}\n rows={3}\n className=\"max-h-52 min-h-[4.5rem] w-full resize-none overflow-y-auto text-sm md:text-sm\"\n placeholder={t('composites.inspector.description')}\n aria-label={t('composites.inspector.description')}\n readOnly={!editable || !focused.descriptionTextOnly}\n onChange={event => inspector.inputDescription(event.target.value)}\n onBlur={inspector.blurDescription}\n />\n </FormField>\n\n {focused.tagsVisible && <FormField label={t('composites.tags.label')}>\n <Popover\n open={tagsOpen}\n onOpenChange={(isOpen) => {\n setTagsOpen(isOpen)\n if (isOpen) inspector.searchTags()\n }}\n >\n <PopoverAnchor asChild>\n <div className={cn('flex min-h-7 w-full flex-wrap items-center gap-1 rounded-lg border border-input px-2 py-1 dark:bg-input/30', !editable && 'opacity-50')}>\n <Icon name=\"i-lucide-hash\" className=\"size-3.5 text-muted-foreground\" />\n {focused.tags.map(tag => (\n <Badge key={tag} variant=\"secondary\" className=\"max-w-full gap-0.5 pr-1\">\n <span className=\"truncate\">{tag}</span>\n <button\n type=\"button\"\n className=\"inline-flex cursor-pointer items-center rounded-full outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/50 disabled:cursor-not-allowed\"\n aria-label={t('composites.tag.remove', { tag })}\n disabled={!editable}\n onClick={() => inspector.setTags(focused.tags.filter(item => item !== tag))}\n >\n <Icon name=\"i-lucide-x\" className=\"size-3\" />\n </button>\n </Badge>\n ))}\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n role=\"combobox\"\n aria-expanded={tagsOpen}\n aria-label={t('composites.tags.label')}\n disabled={!editable}\n className=\"min-w-12 flex-1 cursor-text self-stretch rounded text-left text-sm text-muted-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring/50 disabled:cursor-not-allowed\"\n >\n {focused.tags.length ? '' : t('composites.tags.label')}\n </button>\n </PopoverTrigger>\n </div>\n </PopoverAnchor>\n <PopoverContent align=\"start\" className=\"w-64 gap-0 p-0\">\n {/* `shouldFilter` off: the list is the metadata source's answer to the search term. */}\n <Command shouldFilter={false}>\n <CommandInput\n value={term}\n onValueChange={inspector.setSearchTerm}\n placeholder={t('composites.tags.label')}\n aria-label={t('composites.tags.label')}\n onKeyDown={(event) => {\n if (event.key === 'Backspace' && !term && focused.tags.length) inspector.setTags(focused.tags.slice(0, -1))\n }}\n />\n <CommandList>\n {tagItems.map((tag) => {\n const selected = focused.tags.includes(tag)\n return (\n <CommandItem\n key={tag}\n value={tag}\n data-checked={selected}\n onSelect={() => inspector.setTags(selected ? focused.tags.filter(item => item !== tag) : [...focused.tags, tag])}\n >\n {tag}\n </CommandItem>\n )\n })}\n {term.trim() && (\n <CommandItem value={`__create__:${term}`} onSelect={() => inspector.createTag(term)}>\n <Icon name=\"i-lucide-plus\" />\n {t('composites.tags.create', { tag: normalizeTagName(term) || term })}\n </CommandItem>\n )}\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n </FormField>}\n\n {focused.fields.map(field => (\n <FormField key={field.key} label={field.label}>\n {isStructuredField(field)\n ? (\n // Not text (reference, bibliography, derivation): own editors as in the details card; a text input would overwrite the stored object with a string.\n editor && <CompositeFieldEditor editor={editor} row={focused} field={field} disabled={!editable} />\n )\n : field.type === 'select'\n ? (\n <Select value={compositeFieldText(focused, field)} onValueChange={value => inspector.setField(field, value)} disabled={!editable}>\n <SelectTrigger size=\"sm\" className=\"w-full\" aria-label={field.label}>\n <SelectValue placeholder=\"–\" />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map(option => <SelectItem key={option.value} value={option.value}>{option.label}</SelectItem>)}\n </SelectContent>\n </Select>\n )\n : (\n <MetaFieldInput\n field={field}\n value={compositeFieldText(focused, field)}\n readOnly={!editable}\n onChange={value => inspector.setField(field, value)}\n />\n )}\n </FormField>\n ))}\n\n <div className=\"flex items-center gap-2 border-t border-border pt-3\">\n <Icon name=\"i-lucide-sparkles\" className=\"size-4 shrink-0 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">{t('composites.inspector.aiStatus')}</span>\n <span className={cn('ml-auto inline-flex items-center gap-1.5', hasSummary ? 'text-foreground' : 'text-muted-foreground/70')}>\n <span className={cn('size-2 rounded-full', hasSummary ? 'bg-(--sk-success)' : 'bg-border')} />\n {hasSummary ? t('composites.inspector.summaryPresent') : t('composites.inspector.summaryMissing')}\n </span>\n </div>\n </div>\n </section>\n )}\n </aside>\n )\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { useEditorI18n } from "../../../react/use-editor-i18n.js";
2
2
  import { Icon } from "../../../react/Icon.js";
3
- import { setCompositeMetaField } from "../rows.js";
4
3
  import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuTrigger } from "../../../react/ui/dropdown-menu.js";
4
+ import { setCompositeMetaField } from "../rows.js";
5
5
  import { rowStatus, statusStyle } from "../meta-display.js";
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
7
  //#region src/features/composites/react/CompositeStatusMenu.tsx
@@ -1,6 +1,6 @@
1
1
  import { useEditorI18n } from "../../../react/use-editor-i18n.js";
2
- import { setCompositeDescription } from "../rows.js";
3
2
  import { Textarea } from "../../../react/ui/textarea.js";
3
+ import { setCompositeDescription } from "../rows.js";
4
4
  import { useCallback, useEffect, useRef, useState } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region src/features/composites/react/CompositeSummaryEditor.tsx
@@ -1,3 +1,4 @@
1
+ import { compositeKindsOf } from "../nodes.js";
1
2
  import { useEditorI18n } from "../../../react/use-editor-i18n.js";
2
3
  import { cn } from "../../../react/ui/utils.js";
3
4
  import { Icon } from "../../../react/Icon.js";
@@ -15,7 +16,20 @@ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
15
16
  function CompositeTable({ editor, onSelect, className }) {
16
17
  const { rows, tags, kinds } = useCompositeRows(editor);
17
18
  const { t } = useEditorI18n();
18
- const fieldColumns = useMemo(() => fieldColumnsOf(rows, kinds), [rows, kinds]);
19
+ const fieldContext = useMemo(() => editor ? {
20
+ doc: editor.state.doc,
21
+ kinds: compositeKindsOf(editor),
22
+ t
23
+ } : void 0, [
24
+ editor,
25
+ rows,
26
+ t
27
+ ]);
28
+ const fieldColumns = useMemo(() => fieldColumnsOf(rows, kinds, fieldContext), [
29
+ rows,
30
+ kinds,
31
+ fieldContext
32
+ ]);
19
33
  const specs = useMemo(() => columnSpecsOf(fieldColumns, t), [fieldColumns, t]);
20
34
  const [search, setSearch] = useState("");
21
35
  const [pickedKinds, setPickedKinds] = useState([]);
@@ -314,7 +328,7 @@ function CompositeTable({ editor, onSelect, className }) {
314
328
  }, spec.id);
315
329
  const column = fieldColumns.find((item) => item.id === spec.id);
316
330
  if (!column) return /* @__PURE__ */ jsx(TableCell, { className: cellClass }, spec.id);
317
- const text = fieldText(row, column.field.key);
331
+ const text = fieldText(row, column.field.key, fieldContext);
318
332
  return /* @__PURE__ */ jsx(TableCell, {
319
333
  className: cellClass,
320
334
  children: text ? /* @__PURE__ */ jsx("span", {
@@ -1 +1 @@
1
- {"version":3,"file":"CompositeTable.js","names":[],"sources":["../../../../src/features/composites/react/CompositeTable.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useMemo, useState } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { Badge } from '../../../react/ui/badge'\nimport { Button } from '../../../react/ui/button'\nimport { Input } from '../../../react/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { TableBody, TableCell, TableHead, TableHeader, TableRow } from '../../../react/ui/table'\nimport { cn } from '../../../react/ui/utils'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport type { CompositeRow } from '../rows'\nimport { columnSpecsOf, FILTER_ALL, fieldColumnsOf, fieldOf, fieldText, hasText, isLongText, sortRows, toggled } from '../table-model'\nimport { useCompositeRows } from './use-composite-rows'\n\n// All Bausteine of an editor's document as a sortable, filterable table. Columns beyond the fixed ones derive from the\n// meta fields of the kinds present in the document, so a host kind with fields gets its columns without code changes.\n// The column specs, cell text and sorting are the framework-free `table-model`, shared with the Vue table.\n\n/** The table of an editor's Bausteine: sortable columns, filters by kind, tag and select fields, a text search; `onSelect` receives the clicked row. */\nexport function CompositeTable({ editor, onSelect, className }: {\n editor?: Editor\n onSelect?: (row: CompositeRow) => void\n className?: string\n}) {\n const { rows, tags, kinds } = useCompositeRows(editor)\n\n const { t } = useEditorI18n()\n const fieldColumns = useMemo(() => fieldColumnsOf(rows, kinds), [rows, kinds])\n const specs = useMemo(() => columnSpecsOf(fieldColumns, t), [fieldColumns, t])\n\n const [search, setSearch] = useState('')\n const [pickedKinds, setPickedKinds] = useState<string[]>([])\n const [pickedTags, setPickedTags] = useState<string[]>([])\n const [pickedOptions, setPickedOptions] = useState<Record<string, string>>({})\n\n /** One select per `select` field in use; its choices are the union of the options of all kinds that have the key. */\n const selectFilters = useMemo(() => fieldColumns.flatMap((column) => {\n if (column.field.type !== 'select') return []\n const options = new Map<string, string>()\n for (const row of rows) {\n for (const option of fieldOf(row, column.field.key)?.options ?? []) if (!options.has(option.value)) options.set(option.value, option.label)\n }\n return [{\n key: column.field.key,\n label: column.field.label,\n items: [{ label: t('composites.table.filter.all'), value: FILTER_ALL }, ...[...options].map(([value, label]) => ({ label, value }))],\n }]\n }), [fieldColumns, rows, t])\n\n // A kind, tag or option that vanished from the document can no longer be unpicked in the UI, so it must not filter either.\n const activeKinds = useMemo(() => pickedKinds.filter(id => kinds.some(kind => kind.id === id)), [pickedKinds, kinds])\n const activeTags = useMemo(() => pickedTags.filter(tag => tags.includes(tag)), [pickedTags, tags])\n const activeOptions = useMemo(() => selectFilters.flatMap((filter) => {\n const value = pickedOptions[filter.key]\n return value && filter.items.some(item => item.value === value && value !== FILTER_ALL) ? [[filter.key, value] as const] : []\n }), [selectFilters, pickedOptions])\n const needle = search.trim().toLowerCase()\n const filterActive = activeKinds.length > 0 || activeTags.length > 0 || activeOptions.length > 0 || needle !== ''\n\n function resetFilters() {\n setSearch('')\n setPickedKinds([])\n setPickedTags([])\n setPickedOptions({})\n }\n\n const filtered = useMemo(() => rows.filter((row) => {\n if (activeKinds.length && !activeKinds.includes(row.kind)) return false\n if (activeTags.length && !activeTags.every(tag => row.tags.includes(tag))) return false\n if (activeOptions.some(([key, value]) => row.meta[key] !== value)) return false\n if (needle) {\n const haystack = `${row.title}\\n${row.description}\\n${row.tags.map(tag => `#${tag}`).join(' ')}`.toLowerCase()\n if (!haystack.includes(needle)) return false\n }\n return true\n }), [rows, activeKinds, activeTags, activeOptions, needle])\n\n // --- Sorting (client side, over the filtered rows) ---\n\n const [sorting, setSorting] = useState<{ id: string, desc: boolean } | null>(null)\n const activeSort = useMemo(() => {\n const spec = sorting && specs.find(item => item.id === sorting.id)\n return sorting && spec ? { id: sorting.id, desc: sorting.desc, sort: spec.sort } : null\n }, [sorting, specs])\n\n /** Header click cycles ascending → descending → unsorted. */\n function cycleSort(id: string) {\n setSorting(current => current?.id !== id ? { id, desc: false } : current.desc ? null : { id, desc: true })\n }\n const sortIcon = (id: string) => {\n if (sorting?.id !== id) return 'i-lucide-chevrons-up-down'\n return sorting.desc ? 'i-lucide-arrow-down' : 'i-lucide-arrow-up'\n }\n\n const sorted = useMemo(() => activeSort ? sortRows(filtered, activeSort.sort, activeSort.desc) : filtered, [filtered, activeSort])\n\n const countLabel = t(rows.length === 1 ? 'composites.table.count.one' : 'composites.table.count.other', { n: sorted.length, total: rows.length })\n const columnCount = specs.length\n\n return (\n <section className={cn('flex min-h-0 flex-col gap-3', className)} aria-label={t('composites.table.label')}>\n {!rows.length\n ? (\n <div className=\"mx-auto flex max-w-sm flex-1 flex-col items-center justify-center gap-2 py-16 text-center\">\n <Icon name=\"i-lucide-table-2\" className=\"size-8 text-muted-foreground/70\" />\n <p className=\"text-sm font-medium text-foreground\">\n {t('composites.table.emptyTitle')}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {t('composites.table.emptyText')}\n </p>\n </div>\n )\n : (\n <>\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"relative w-64\">\n <Icon name=\"i-lucide-search\" className=\"pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\" />\n <Input\n value={search}\n onChange={event => setSearch(event.target.value)}\n className={cn('h-7 pl-8 text-sm', search && 'pr-8')}\n placeholder={t('composites.table.search.placeholder')}\n aria-label={t('composites.table.search.label')}\n />\n {search && (\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n className=\"absolute top-1/2 right-1 -translate-y-1/2\"\n aria-label={t('composites.table.search.clear')}\n onClick={() => setSearch('')}\n >\n <Icon name=\"i-lucide-x\" />\n </Button>\n )}\n </div>\n\n {selectFilters.map(filter => (\n <div key={filter.key} className=\"flex items-center gap-1.5\">\n <span className=\"text-sm text-muted-foreground\" aria-hidden=\"true\">{filter.label}</span>\n <Select\n value={pickedOptions[filter.key] ?? FILTER_ALL}\n onValueChange={value => setPickedOptions({ ...pickedOptions, [filter.key]: String(value) })}\n >\n <SelectTrigger size=\"sm\" className=\"w-36\" aria-label={filter.label}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {filter.items.map(item => <SelectItem key={item.value} value={item.value}>{item.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n ))}\n\n {filterActive && (\n <Button size=\"sm\" variant=\"ghost\" onClick={resetFilters}>\n <Icon name=\"i-lucide-filter-x\" />\n {t('composites.table.filter.reset')}\n </Button>\n )}\n <span className=\"ml-auto text-xs text-muted-foreground tabular-nums\" role=\"status\">{countLabel}</span>\n </div>\n\n {kinds.length > 1 && (\n <div className=\"flex flex-wrap items-center gap-1\" role=\"group\" aria-label={t('composites.table.filter.byKind')}>\n {kinds.map(kind => (\n <Button\n key={kind.id}\n size=\"xs\"\n variant={activeKinds.includes(kind.id) ? 'default' : 'outline'}\n aria-pressed={activeKinds.includes(kind.id)}\n onClick={() => setPickedKinds(toggled(pickedKinds, kind.id))}\n >\n <Icon name={kind.icon} />\n {kind.label}\n </Button>\n ))}\n </div>\n )}\n\n {tags.length > 0 && (\n <div className=\"flex flex-wrap items-center gap-1\" role=\"group\" aria-label={t('composites.table.filter.byTag')}>\n {tags.map(tag => (\n <Button\n key={tag}\n size=\"xs\"\n variant={activeTags.includes(tag) ? 'default' : 'outline'}\n aria-pressed={activeTags.includes(tag)}\n onClick={() => setPickedTags(toggled(pickedTags, tag))}\n >\n {`#${tag}`}\n </Button>\n ))}\n </div>\n )}\n </div>\n\n {/* Own scroll container instead of `<Table>`'s: the sticky header needs the element that scrolls vertically. */}\n <div className=\"min-h-0 flex-1 overflow-auto rounded-md border border-border\">\n <table data-slot=\"table\" className=\"w-full caption-bottom text-sm\">\n <TableHeader className=\"sticky top-0 z-10 bg-background\">\n <TableRow className=\"hover:bg-transparent\">\n {specs.map(spec => (\n <TableHead\n key={spec.id}\n className={cn('h-auto px-3 py-2 text-sm', spec.id === 'title' && 'min-w-56', spec.align === 'end' && 'text-right')}\n aria-sort={activeSort?.id === spec.id ? (activeSort.desc ? 'descending' : 'ascending') : 'none'}\n >\n <button\n type=\"button\"\n className=\"-mx-1.5 inline-flex cursor-pointer items-center gap-1 rounded px-1.5 py-0.5 font-semibold hover:bg-muted focus-visible:outline-2 focus-visible:outline-primary\"\n onClick={() => cycleSort(spec.id)}\n >\n {spec.label}\n <Icon name={sortIcon(spec.id)} className={cn('size-3.5', activeSort?.id === spec.id ? 'text-foreground' : 'text-muted-foreground/70')} />\n </button>\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {sorted.length === 0\n ? (\n <TableRow className=\"hover:bg-transparent\">\n <TableCell colSpan={columnCount} className=\"px-3 py-2 text-muted-foreground\">\n <div className=\"flex flex-col items-center gap-2 py-6\">\n <p className=\"text-sm text-muted-foreground\">\n {t('composites.table.filter.noMatch')}\n </p>\n <Button size=\"sm\" variant=\"outline\" onClick={resetFilters}>\n <Icon name=\"i-lucide-filter-x\" />\n {t('composites.table.filter.reset')}\n </Button>\n </div>\n </TableCell>\n </TableRow>\n )\n : sorted.map(row => (\n <TableRow key={row.key} className=\"cursor-pointer\" onClick={() => onSelect?.(row)}>\n {specs.map((spec) => {\n const cellClass = cn('px-3 py-2 text-muted-foreground', spec.align === 'end' && 'text-right')\n if (spec.id === 'title') {\n return (\n <TableCell key={spec.id} className={cellClass}>\n <div className=\"flex min-w-0 items-center gap-1.5\" style={{ paddingLeft: `${row.depth * 1.25}rem` }}>\n <Icon name={row.icon} className=\"size-4 shrink-0 text-muted-foreground\" />\n {hasText(row.title)\n ? <span className=\"truncate font-medium text-foreground\">{row.title}</span>\n : <span className=\"truncate text-muted-foreground\">{t('composites.untitled')}</span>}\n </div>\n </TableCell>\n )\n }\n if (spec.id === 'kind') return <TableCell key={spec.id} className={cellClass}>{row.kindLabel}</TableCell>\n if (spec.id === 'tags') {\n return (\n <TableCell key={spec.id} className={cellClass}>\n {row.tags.length\n ? (\n <div className=\"flex flex-wrap gap-1\">\n {row.tags.map(tag => <Badge key={tag} variant=\"secondary\">{`#${tag}`}</Badge>)}\n </div>\n )\n : (\n <>\n <span className=\"text-muted-foreground/70\" aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">{t('composites.table.noTags')}</span>\n </>\n )}\n </TableCell>\n )\n }\n if (spec.id === 'summary') {\n return (\n <TableCell key={spec.id} className={cellClass}>\n {hasText(row.description)\n ? (\n <>\n <span className=\"inline-block size-2 rounded-full bg-primary\" aria-hidden=\"true\" title={row.description} />\n <span className=\"sr-only\">{t('composites.table.summaryPresent')}</span>\n </>\n )\n : (\n <>\n <span className=\"text-muted-foreground/70\" aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">{t('composites.summary.none')}</span>\n </>\n )}\n </TableCell>\n )\n }\n const column = fieldColumns.find(item => item.id === spec.id)\n if (!column) return <TableCell key={spec.id} className={cellClass} />\n const text = fieldText(row, column.field.key)\n return (\n <TableCell key={spec.id} className={cellClass}>\n {text\n ? (\n <span\n className={cn('block', (column.field.type === 'number' || column.field.type === 'date') && 'tabular-nums', isLongText(column.field) && 'max-w-64 truncate')}\n title={isLongText(column.field) ? text : undefined}\n >\n {text}\n </span>\n )\n : (\n <>\n <span className=\"text-muted-foreground/70\" aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">{t('composites.table.noValue')}</span>\n </>\n )}\n </TableCell>\n )\n })}\n </TableRow>\n ))}\n </TableBody>\n </table>\n </div>\n </>\n )}\n </section>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CompositeTable.js","names":[],"sources":["../../../../src/features/composites/react/CompositeTable.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useMemo, useState } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { Badge } from '../../../react/ui/badge'\nimport { Button } from '../../../react/ui/button'\nimport { Input } from '../../../react/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { TableBody, TableCell, TableHead, TableHeader, TableRow } from '../../../react/ui/table'\nimport { cn } from '../../../react/ui/utils'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { compositeKindsOf } from '../nodes'\nimport type { CompositeRow } from '../rows'\nimport { columnSpecsOf, type FieldContext, FILTER_ALL, fieldColumnsOf, fieldOf, fieldText, hasText, isLongText, sortRows, toggled } from '../table-model'\nimport { useCompositeRows } from './use-composite-rows'\n\n// All Bausteine of an editor's document as a sortable, filterable table. Columns beyond the fixed ones derive from the\n// meta fields of the kinds present in the document, so a host kind with fields gets its columns without code changes.\n// The column specs, cell text and sorting are the framework-free `table-model`, shared with the Vue table.\n\n/** The table of an editor's Bausteine: sortable columns, filters by kind, tag and select fields, a text search; `onSelect` receives the clicked row. */\nexport function CompositeTable({ editor, onSelect, className }: {\n editor?: Editor\n onSelect?: (row: CompositeRow) => void\n className?: string\n}) {\n const { rows, tags, kinds } = useCompositeRows(editor)\n\n const { t } = useEditorI18n()\n // `reference` cells resolve their target in the document; re-read whenever the rows change.\n const fieldContext = useMemo<FieldContext | undefined>(() => (editor ? { doc: editor.state.doc, kinds: compositeKindsOf(editor), t } : undefined), [editor, rows, t])\n const fieldColumns = useMemo(() => fieldColumnsOf(rows, kinds, fieldContext), [rows, kinds, fieldContext])\n const specs = useMemo(() => columnSpecsOf(fieldColumns, t), [fieldColumns, t])\n\n const [search, setSearch] = useState('')\n const [pickedKinds, setPickedKinds] = useState<string[]>([])\n const [pickedTags, setPickedTags] = useState<string[]>([])\n const [pickedOptions, setPickedOptions] = useState<Record<string, string>>({})\n\n /** One select per `select` field in use; its choices are the union of the options of all kinds that have the key. */\n const selectFilters = useMemo(() => fieldColumns.flatMap((column) => {\n if (column.field.type !== 'select') return []\n const options = new Map<string, string>()\n for (const row of rows) {\n for (const option of fieldOf(row, column.field.key)?.options ?? []) if (!options.has(option.value)) options.set(option.value, option.label)\n }\n return [{\n key: column.field.key,\n label: column.field.label,\n items: [{ label: t('composites.table.filter.all'), value: FILTER_ALL }, ...[...options].map(([value, label]) => ({ label, value }))],\n }]\n }), [fieldColumns, rows, t])\n\n // A kind, tag or option that vanished from the document can no longer be unpicked in the UI, so it must not filter either.\n const activeKinds = useMemo(() => pickedKinds.filter(id => kinds.some(kind => kind.id === id)), [pickedKinds, kinds])\n const activeTags = useMemo(() => pickedTags.filter(tag => tags.includes(tag)), [pickedTags, tags])\n const activeOptions = useMemo(() => selectFilters.flatMap((filter) => {\n const value = pickedOptions[filter.key]\n return value && filter.items.some(item => item.value === value && value !== FILTER_ALL) ? [[filter.key, value] as const] : []\n }), [selectFilters, pickedOptions])\n const needle = search.trim().toLowerCase()\n const filterActive = activeKinds.length > 0 || activeTags.length > 0 || activeOptions.length > 0 || needle !== ''\n\n function resetFilters() {\n setSearch('')\n setPickedKinds([])\n setPickedTags([])\n setPickedOptions({})\n }\n\n const filtered = useMemo(() => rows.filter((row) => {\n if (activeKinds.length && !activeKinds.includes(row.kind)) return false\n if (activeTags.length && !activeTags.every(tag => row.tags.includes(tag))) return false\n if (activeOptions.some(([key, value]) => row.meta[key] !== value)) return false\n if (needle) {\n const haystack = `${row.title}\\n${row.description}\\n${row.tags.map(tag => `#${tag}`).join(' ')}`.toLowerCase()\n if (!haystack.includes(needle)) return false\n }\n return true\n }), [rows, activeKinds, activeTags, activeOptions, needle])\n\n // --- Sorting (client side, over the filtered rows) ---\n\n const [sorting, setSorting] = useState<{ id: string, desc: boolean } | null>(null)\n const activeSort = useMemo(() => {\n const spec = sorting && specs.find(item => item.id === sorting.id)\n return sorting && spec ? { id: sorting.id, desc: sorting.desc, sort: spec.sort } : null\n }, [sorting, specs])\n\n /** Header click cycles ascending → descending → unsorted. */\n function cycleSort(id: string) {\n setSorting(current => current?.id !== id ? { id, desc: false } : current.desc ? null : { id, desc: true })\n }\n const sortIcon = (id: string) => {\n if (sorting?.id !== id) return 'i-lucide-chevrons-up-down'\n return sorting.desc ? 'i-lucide-arrow-down' : 'i-lucide-arrow-up'\n }\n\n const sorted = useMemo(() => activeSort ? sortRows(filtered, activeSort.sort, activeSort.desc) : filtered, [filtered, activeSort])\n\n const countLabel = t(rows.length === 1 ? 'composites.table.count.one' : 'composites.table.count.other', { n: sorted.length, total: rows.length })\n const columnCount = specs.length\n\n return (\n <section className={cn('flex min-h-0 flex-col gap-3', className)} aria-label={t('composites.table.label')}>\n {!rows.length\n ? (\n <div className=\"mx-auto flex max-w-sm flex-1 flex-col items-center justify-center gap-2 py-16 text-center\">\n <Icon name=\"i-lucide-table-2\" className=\"size-8 text-muted-foreground/70\" />\n <p className=\"text-sm font-medium text-foreground\">\n {t('composites.table.emptyTitle')}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {t('composites.table.emptyText')}\n </p>\n </div>\n )\n : (\n <>\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"relative w-64\">\n <Icon name=\"i-lucide-search\" className=\"pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\" />\n <Input\n value={search}\n onChange={event => setSearch(event.target.value)}\n className={cn('h-7 pl-8 text-sm', search && 'pr-8')}\n placeholder={t('composites.table.search.placeholder')}\n aria-label={t('composites.table.search.label')}\n />\n {search && (\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n className=\"absolute top-1/2 right-1 -translate-y-1/2\"\n aria-label={t('composites.table.search.clear')}\n onClick={() => setSearch('')}\n >\n <Icon name=\"i-lucide-x\" />\n </Button>\n )}\n </div>\n\n {selectFilters.map(filter => (\n <div key={filter.key} className=\"flex items-center gap-1.5\">\n <span className=\"text-sm text-muted-foreground\" aria-hidden=\"true\">{filter.label}</span>\n <Select\n value={pickedOptions[filter.key] ?? FILTER_ALL}\n onValueChange={value => setPickedOptions({ ...pickedOptions, [filter.key]: String(value) })}\n >\n <SelectTrigger size=\"sm\" className=\"w-36\" aria-label={filter.label}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {filter.items.map(item => <SelectItem key={item.value} value={item.value}>{item.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n ))}\n\n {filterActive && (\n <Button size=\"sm\" variant=\"ghost\" onClick={resetFilters}>\n <Icon name=\"i-lucide-filter-x\" />\n {t('composites.table.filter.reset')}\n </Button>\n )}\n <span className=\"ml-auto text-xs text-muted-foreground tabular-nums\" role=\"status\">{countLabel}</span>\n </div>\n\n {kinds.length > 1 && (\n <div className=\"flex flex-wrap items-center gap-1\" role=\"group\" aria-label={t('composites.table.filter.byKind')}>\n {kinds.map(kind => (\n <Button\n key={kind.id}\n size=\"xs\"\n variant={activeKinds.includes(kind.id) ? 'default' : 'outline'}\n aria-pressed={activeKinds.includes(kind.id)}\n onClick={() => setPickedKinds(toggled(pickedKinds, kind.id))}\n >\n <Icon name={kind.icon} />\n {kind.label}\n </Button>\n ))}\n </div>\n )}\n\n {tags.length > 0 && (\n <div className=\"flex flex-wrap items-center gap-1\" role=\"group\" aria-label={t('composites.table.filter.byTag')}>\n {tags.map(tag => (\n <Button\n key={tag}\n size=\"xs\"\n variant={activeTags.includes(tag) ? 'default' : 'outline'}\n aria-pressed={activeTags.includes(tag)}\n onClick={() => setPickedTags(toggled(pickedTags, tag))}\n >\n {`#${tag}`}\n </Button>\n ))}\n </div>\n )}\n </div>\n\n {/* Own scroll container instead of `<Table>`'s: the sticky header needs the element that scrolls vertically. */}\n <div className=\"min-h-0 flex-1 overflow-auto rounded-md border border-border\">\n <table data-slot=\"table\" className=\"w-full caption-bottom text-sm\">\n <TableHeader className=\"sticky top-0 z-10 bg-background\">\n <TableRow className=\"hover:bg-transparent\">\n {specs.map(spec => (\n <TableHead\n key={spec.id}\n className={cn('h-auto px-3 py-2 text-sm', spec.id === 'title' && 'min-w-56', spec.align === 'end' && 'text-right')}\n aria-sort={activeSort?.id === spec.id ? (activeSort.desc ? 'descending' : 'ascending') : 'none'}\n >\n <button\n type=\"button\"\n className=\"-mx-1.5 inline-flex cursor-pointer items-center gap-1 rounded px-1.5 py-0.5 font-semibold hover:bg-muted focus-visible:outline-2 focus-visible:outline-primary\"\n onClick={() => cycleSort(spec.id)}\n >\n {spec.label}\n <Icon name={sortIcon(spec.id)} className={cn('size-3.5', activeSort?.id === spec.id ? 'text-foreground' : 'text-muted-foreground/70')} />\n </button>\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {sorted.length === 0\n ? (\n <TableRow className=\"hover:bg-transparent\">\n <TableCell colSpan={columnCount} className=\"px-3 py-2 text-muted-foreground\">\n <div className=\"flex flex-col items-center gap-2 py-6\">\n <p className=\"text-sm text-muted-foreground\">\n {t('composites.table.filter.noMatch')}\n </p>\n <Button size=\"sm\" variant=\"outline\" onClick={resetFilters}>\n <Icon name=\"i-lucide-filter-x\" />\n {t('composites.table.filter.reset')}\n </Button>\n </div>\n </TableCell>\n </TableRow>\n )\n : sorted.map(row => (\n <TableRow key={row.key} className=\"cursor-pointer\" onClick={() => onSelect?.(row)}>\n {specs.map((spec) => {\n const cellClass = cn('px-3 py-2 text-muted-foreground', spec.align === 'end' && 'text-right')\n if (spec.id === 'title') {\n return (\n <TableCell key={spec.id} className={cellClass}>\n <div className=\"flex min-w-0 items-center gap-1.5\" style={{ paddingLeft: `${row.depth * 1.25}rem` }}>\n <Icon name={row.icon} className=\"size-4 shrink-0 text-muted-foreground\" />\n {hasText(row.title)\n ? <span className=\"truncate font-medium text-foreground\">{row.title}</span>\n : <span className=\"truncate text-muted-foreground\">{t('composites.untitled')}</span>}\n </div>\n </TableCell>\n )\n }\n if (spec.id === 'kind') return <TableCell key={spec.id} className={cellClass}>{row.kindLabel}</TableCell>\n if (spec.id === 'tags') {\n return (\n <TableCell key={spec.id} className={cellClass}>\n {row.tags.length\n ? (\n <div className=\"flex flex-wrap gap-1\">\n {row.tags.map(tag => <Badge key={tag} variant=\"secondary\">{`#${tag}`}</Badge>)}\n </div>\n )\n : (\n <>\n <span className=\"text-muted-foreground/70\" aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">{t('composites.table.noTags')}</span>\n </>\n )}\n </TableCell>\n )\n }\n if (spec.id === 'summary') {\n return (\n <TableCell key={spec.id} className={cellClass}>\n {hasText(row.description)\n ? (\n <>\n <span className=\"inline-block size-2 rounded-full bg-primary\" aria-hidden=\"true\" title={row.description} />\n <span className=\"sr-only\">{t('composites.table.summaryPresent')}</span>\n </>\n )\n : (\n <>\n <span className=\"text-muted-foreground/70\" aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">{t('composites.summary.none')}</span>\n </>\n )}\n </TableCell>\n )\n }\n const column = fieldColumns.find(item => item.id === spec.id)\n if (!column) return <TableCell key={spec.id} className={cellClass} />\n const text = fieldText(row, column.field.key, fieldContext)\n return (\n <TableCell key={spec.id} className={cellClass}>\n {text\n ? (\n <span\n className={cn('block', (column.field.type === 'number' || column.field.type === 'date') && 'tabular-nums', isLongText(column.field) && 'max-w-64 truncate')}\n title={isLongText(column.field) ? text : undefined}\n >\n {text}\n </span>\n )\n : (\n <>\n <span className=\"text-muted-foreground/70\" aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">{t('composites.table.noValue')}</span>\n </>\n )}\n </TableCell>\n )\n })}\n </TableRow>\n ))}\n </TableBody>\n </table>\n </div>\n </>\n )}\n </section>\n )\n}\n"],"mappings":"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"}
@@ -1,10 +1,10 @@
1
1
  import { metadataOf } from "../../../core/metadata.js";
2
2
  import { METADATA_LIST } from "../../../core/metadata-types.js";
3
+ import { normalizeTagName } from "../../../core/tag-name.js";
3
4
  import { useEditorI18n } from "../../../react/use-editor-i18n.js";
4
5
  import { Icon } from "../../../react/Icon.js";
5
- import { setCompositeTags } from "../rows.js";
6
- import { normalizeTagName } from "../../../core/tag-name.js";
7
6
  import { Command, CommandInput, CommandItem, CommandList } from "../../../react/ui/command.js";
7
+ import { setCompositeTags } from "../rows.js";
8
8
  import { useEffect, useRef, useState } from "react";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
10
  //#region src/features/composites/react/CompositeTagsEditor.tsx
@@ -1,6 +1,8 @@
1
1
  import { compositeKind } from "../kinds.js";
2
+ import { derivationOf } from "../derivation.js";
2
3
  import { compositeKindsOf } from "../nodes.js";
3
4
  import { cn } from "../../../react/ui/utils.js";
5
+ import { useStore } from "../../../react/use-store.js";
4
6
  import { jsx, jsxs } from "react/jsx-runtime";
5
7
  import { NodeViewContent, NodeViewWrapper } from "@tiptap/react";
6
8
  //#region src/features/composites/react/CompositeView.tsx
@@ -9,10 +11,13 @@ const cssString = (text) => `"${text.replace(/["\\]/g, "\\$&").replace(/\n/g, "\
9
11
  /** The composite block: the section with its content. The kind icon is drawn by the composite chrome overlay. */
10
12
  function CompositeView({ editor, node, selected }) {
11
13
  const kind = compositeKind(compositeKindsOf(editor), String(node.attrs.kind));
14
+ const expanded = useStore(editor.storage.composite.expanded);
15
+ const id = node.attrs.id;
16
+ const collapsed = typeof id === "string" && id !== "" && derivationOf(node) !== null && !expanded.has(id);
12
17
  const placeholderVars = { "--composite-title-placeholder": cssString(kind.titlePlaceholder) };
13
18
  return /* @__PURE__ */ jsxs(NodeViewWrapper, {
14
19
  as: "section",
15
- className: cn("composite", selected && "is-selected rounded-md ring-1 ring-primary"),
20
+ className: cn("composite", collapsed && "is-collapsed", selected && "is-selected rounded-md ring-1 ring-primary"),
16
21
  "data-type": "composite",
17
22
  "data-kind": node.attrs.kind,
18
23
  "data-id": node.attrs.id || void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"CompositeView.js","names":[],"sources":["../../../../src/features/composites/react/CompositeView.tsx"],"sourcesContent":["import { NodeViewContent, NodeViewWrapper, type NodeViewProps } from '@tiptap/react'\nimport type { CSSProperties } from 'react'\nimport { cn } from '../../../react/ui/utils'\nimport { compositeKind } from '../kinds'\nimport { compositeKindsOf } from '../nodes'\n\n/** `text` as a CSS string literal (for `content:`). */\nconst cssString = (text: string) => `\"${text.replace(/[\"\\\\]/g, '\\\\$&').replace(/\\n/g, '\\\\a ')}\"`\n\n/** The composite block: the section with its content. The kind icon is drawn by the composite chrome overlay. */\nexport function CompositeView({ editor, node, selected }: NodeViewProps) {\n const kind = compositeKind(compositeKindsOf(editor), String(node.attrs.kind))\n // Placeholder of the empty title (composites.css `content: var(…)`); a nested composite sets its own.\n const placeholderVars = { '--composite-title-placeholder': cssString(kind.titlePlaceholder) } as CSSProperties\n return (\n <NodeViewWrapper\n as=\"section\"\n className={cn('composite', selected && 'is-selected rounded-md ring-1 ring-primary')}\n data-type=\"composite\"\n data-kind={node.attrs.kind}\n data-id={node.attrs.id || undefined}\n style={placeholderVars}\n >\n {/* Anchor of the kind icon on the left border: it only takes the icon's place and size. The composite chrome overlay\n measures it and draws the icon as the button that opens the details popover and drags the composite. */}\n <span className=\"composite__toggle\" contentEditable={false} aria-hidden=\"true\" />\n <NodeViewContent className=\"composite__content\" />\n </NodeViewWrapper>\n )\n}\n"],"mappings":";;;;;;;AAOA,MAAM,aAAa,SAAiB,IAAI,KAAK,QAAQ,UAAU,MAAM,CAAC,CAAC,QAAQ,OAAO,MAAM,EAAE;;AAG9F,SAAgB,cAAc,EAAE,QAAQ,MAAM,YAA2B;CACvE,MAAM,OAAO,cAAc,iBAAiB,MAAM,GAAG,OAAO,KAAK,MAAM,IAAI,CAAC;CAE5E,MAAM,kBAAkB,EAAE,iCAAiC,UAAU,KAAK,gBAAgB,EAAE;CAC5F,OACE,qBAAC,iBAAD;EACE,IAAG;EACH,WAAW,GAAG,aAAa,YAAY,4CAA4C;EACnF,aAAU;EACV,aAAW,KAAK,MAAM;EACtB,WAAS,KAAK,MAAM,MAAM,KAAA;EAC1B,OAAO;EANT,UAAA,CAUE,oBAAC,QAAD;GAAM,WAAU;GAAoB,iBAAiB;GAAO,eAAY;EAAQ,CAAA,GAChF,oBAAC,iBAAD,EAAiB,WAAU,qBAAsB,CAAA,CAClC;;AAErB"}
1
+ {"version":3,"file":"CompositeView.js","names":[],"sources":["../../../../src/features/composites/react/CompositeView.tsx"],"sourcesContent":["import { NodeViewContent, NodeViewWrapper, type NodeViewProps } from '@tiptap/react'\nimport type { CSSProperties } from 'react'\nimport { cn } from '../../../react/ui/utils'\nimport { compositeKind } from '../kinds'\nimport { useStore } from '../../../react/use-store'\nimport { derivationOf } from '../derivation'\nimport { compositeKindsOf } from '../nodes'\n\n/** `text` as a CSS string literal (for `content:`). */\nconst cssString = (text: string) => `\"${text.replace(/[\"\\\\]/g, '\\\\$&').replace(/\\n/g, '\\\\a ')}\"`\n\n/** The composite block: the section with its content. The kind icon is drawn by the composite chrome overlay. */\nexport function CompositeView({ editor, node, selected }: NodeViewProps) {\n const kind = compositeKind(compositeKindsOf(editor), String(node.attrs.kind))\n // A derived Baustein (one with a `meta.derivation`) shows collapsed to a faded preview until it is opened; the content\n // stays laid out (CSS clips it), so editing positions are unaffected. The chrome's chevron and a caret inside open it.\n const expanded = useStore(editor.storage.composite.expanded)\n const id: unknown = node.attrs.id\n const collapsed = typeof id === 'string' && id !== '' && derivationOf(node) !== null && !expanded.has(id)\n // Placeholder of the empty title (composites.css `content: var(…)`); a nested composite sets its own.\n const placeholderVars = { '--composite-title-placeholder': cssString(kind.titlePlaceholder) } as CSSProperties\n return (\n <NodeViewWrapper\n as=\"section\"\n className={cn('composite', collapsed && 'is-collapsed', selected && 'is-selected rounded-md ring-1 ring-primary')}\n data-type=\"composite\"\n data-kind={node.attrs.kind}\n data-id={node.attrs.id || undefined}\n style={placeholderVars}\n >\n {/* Anchor of the kind icon on the left border: it only takes the icon's place and size. The composite chrome overlay\n measures it and draws the icon as the button that opens the details popover and drags the composite. */}\n <span className=\"composite__toggle\" contentEditable={false} aria-hidden=\"true\" />\n <NodeViewContent className=\"composite__content\" />\n </NodeViewWrapper>\n )\n}\n"],"mappings":";;;;;;;;;AASA,MAAM,aAAa,SAAiB,IAAI,KAAK,QAAQ,UAAU,MAAM,CAAC,CAAC,QAAQ,OAAO,MAAM,EAAE;;AAG9F,SAAgB,cAAc,EAAE,QAAQ,MAAM,YAA2B;CACvE,MAAM,OAAO,cAAc,iBAAiB,MAAM,GAAG,OAAO,KAAK,MAAM,IAAI,CAAC;CAG5E,MAAM,WAAW,SAAS,OAAO,QAAQ,UAAU,QAAQ;CAC3D,MAAM,KAAc,KAAK,MAAM;CAC/B,MAAM,YAAY,OAAO,OAAO,YAAY,OAAO,MAAM,aAAa,IAAI,MAAM,QAAQ,CAAC,SAAS,IAAI,EAAE;CAExG,MAAM,kBAAkB,EAAE,iCAAiC,UAAU,KAAK,gBAAgB,EAAE;CAC5F,OACE,qBAAC,iBAAD;EACE,IAAG;EACH,WAAW,GAAG,aAAa,aAAa,gBAAgB,YAAY,4CAA4C;EAChH,aAAU;EACV,aAAW,KAAK,MAAM;EACtB,WAAS,KAAK,MAAM,MAAM,KAAA;EAC1B,OAAO;EANT,UAAA,CAUE,oBAAC,QAAD;GAAM,WAAU;GAAoB,iBAAiB;GAAO,eAAY;EAAQ,CAAA,GAChF,oBAAC,iBAAD,EAAiB,WAAU,qBAAsB,CAAA,CAClC;;AAErB"}