@coffer-org/web-ui 4.0.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 (387) hide show
  1. package/README.md +87 -0
  2. package/dist/Markdown.d.ts +4 -0
  3. package/dist/Markdown.js +13 -0
  4. package/dist/MarkdownEditor.d.ts +6 -0
  5. package/dist/MarkdownEditor.js +83 -0
  6. package/dist/actions/ActionButton.d.ts +7 -0
  7. package/dist/actions/ActionButton.js +54 -0
  8. package/dist/actions/PopupBody.d.ts +4 -0
  9. package/dist/actions/PopupBody.js +8 -0
  10. package/dist/actions/TemplateHost.d.ts +4 -0
  11. package/dist/actions/TemplateHost.js +36 -0
  12. package/dist/actions/registry.d.ts +20 -0
  13. package/dist/actions/registry.js +9 -0
  14. package/dist/components/ExtendReasonInfo.d.ts +6 -0
  15. package/dist/components/ExtendReasonInfo.js +12 -0
  16. package/dist/components/FavoriteButton.d.ts +8 -0
  17. package/dist/components/FavoriteButton.js +7 -0
  18. package/dist/components/Icon.d.ts +6 -0
  19. package/dist/components/Icon.js +12 -0
  20. package/dist/components/PageBody.d.ts +4 -0
  21. package/dist/components/PageBody.js +4 -0
  22. package/dist/components/RecordInline.d.ts +8 -0
  23. package/dist/components/RecordInline.js +29 -0
  24. package/dist/components/SaveStatus.d.ts +1 -0
  25. package/dist/components/SaveStatus.js +11 -0
  26. package/dist/components/Toolbar.d.ts +5 -0
  27. package/dist/components/Toolbar.js +4 -0
  28. package/dist/components/icons/color.d.ts +2 -0
  29. package/dist/components/icons/color.js +10 -0
  30. package/dist/components/icons/flag.d.ts +2 -0
  31. package/dist/components/icons/flag.js +6 -0
  32. package/dist/components/icons/lucide.d.ts +2 -0
  33. package/dist/components/icons/lucide.js +111 -0
  34. package/dist/components/icons/registry.d.ts +4 -0
  35. package/dist/components/icons/registry.js +22 -0
  36. package/dist/components/icons/simple.d.ts +2 -0
  37. package/dist/components/icons/simple.js +15 -0
  38. package/dist/components/icons/tabler.d.ts +2 -0
  39. package/dist/components/icons/tabler.js +11 -0
  40. package/dist/components/ui/FieldLabel.d.ts +9 -0
  41. package/dist/components/ui/FieldLabel.js +4 -0
  42. package/dist/components/ui/badge.d.ts +9 -0
  43. package/dist/components/ui/badge.js +19 -0
  44. package/dist/components/ui/button.d.ts +11 -0
  45. package/dist/components/ui/button.js +33 -0
  46. package/dist/components/ui/calendar.d.ts +8 -0
  47. package/dist/components/ui/calendar.js +72 -0
  48. package/dist/components/ui/card.d.ts +8 -0
  49. package/dist/components/ui/card.js +16 -0
  50. package/dist/components/ui/checkbox.d.ts +4 -0
  51. package/dist/components/ui/checkbox.js +8 -0
  52. package/dist/components/ui/chip-cls.d.ts +1 -0
  53. package/dist/components/ui/chip-cls.js +1 -0
  54. package/dist/components/ui/combobox.d.ts +24 -0
  55. package/dist/components/ui/combobox.js +58 -0
  56. package/dist/components/ui/confirm.d.ts +10 -0
  57. package/dist/components/ui/confirm.js +37 -0
  58. package/dist/components/ui/date-picker.d.ts +5 -0
  59. package/dist/components/ui/date-picker.js +16 -0
  60. package/dist/components/ui/dialog.d.ts +16 -0
  61. package/dist/components/ui/dialog.js +27 -0
  62. package/dist/components/ui/dropdown-menu.d.ts +15 -0
  63. package/dist/components/ui/dropdown-menu.js +18 -0
  64. package/dist/components/ui/input-group.d.ts +16 -0
  65. package/dist/components/ui/input-group.js +56 -0
  66. package/dist/components/ui/input.d.ts +3 -0
  67. package/dist/components/ui/input.js +6 -0
  68. package/dist/components/ui/label.d.ts +4 -0
  69. package/dist/components/ui/label.js +7 -0
  70. package/dist/components/ui/mask-input.d.ts +61 -0
  71. package/dist/components/ui/mask-input.js +1052 -0
  72. package/dist/components/ui/month-year-picker.d.ts +10 -0
  73. package/dist/components/ui/month-year-picker.js +46 -0
  74. package/dist/components/ui/option-icon.d.ts +15 -0
  75. package/dist/components/ui/option-icon.js +19 -0
  76. package/dist/components/ui/phone-input.d.ts +13 -0
  77. package/dist/components/ui/phone-input.js +53 -0
  78. package/dist/components/ui/popover.d.ts +11 -0
  79. package/dist/components/ui/popover.js +28 -0
  80. package/dist/components/ui/rating.d.ts +44 -0
  81. package/dist/components/ui/rating.js +501 -0
  82. package/dist/components/ui/scroll-area.d.ts +5 -0
  83. package/dist/components/ui/scroll-area.js +11 -0
  84. package/dist/components/ui/select-combobox.d.ts +25 -0
  85. package/dist/components/ui/select-combobox.js +36 -0
  86. package/dist/components/ui/select.d.ts +13 -0
  87. package/dist/components/ui/select.js +24 -0
  88. package/dist/components/ui/separator.d.ts +4 -0
  89. package/dist/components/ui/separator.js +7 -0
  90. package/dist/components/ui/switch.d.ts +4 -0
  91. package/dist/components/ui/switch.js +7 -0
  92. package/dist/components/ui/textarea.d.ts +3 -0
  93. package/dist/components/ui/textarea.js +6 -0
  94. package/dist/components/ui/time-picker.d.ts +84 -0
  95. package/dist/components/ui/time-picker.js +1258 -0
  96. package/dist/components/visually-hidden-input.d.ts +10 -0
  97. package/dist/components/visually-hidden-input.js +96 -0
  98. package/dist/hooks/use-as-ref.d.ts +3 -0
  99. package/dist/hooks/use-as-ref.js +10 -0
  100. package/dist/hooks/use-isomorphic-layout-effect.d.ts +3 -0
  101. package/dist/hooks/use-isomorphic-layout-effect.js +3 -0
  102. package/dist/hooks/use-lazy-ref.d.ts +3 -0
  103. package/dist/hooks/use-lazy-ref.js +9 -0
  104. package/dist/hooks/use-media-query.d.ts +3 -0
  105. package/dist/hooks/use-media-query.js +26 -0
  106. package/dist/host-services.d.ts +47 -0
  107. package/dist/host-services.js +35 -0
  108. package/dist/index.d.ts +70 -0
  109. package/dist/index.js +69 -0
  110. package/dist/layout.d.ts +29 -0
  111. package/dist/layout.js +323 -0
  112. package/dist/lib/cat-color.d.ts +1 -0
  113. package/dist/lib/cat-color.js +7 -0
  114. package/dist/lib/compose-refs.d.ts +5 -0
  115. package/dist/lib/compose-refs.js +38 -0
  116. package/dist/lib/date-format.d.ts +9 -0
  117. package/dist/lib/date-format.js +31 -0
  118. package/dist/lib/format.d.ts +14 -0
  119. package/dist/lib/format.js +34 -0
  120. package/dist/lib/json.d.ts +1 -0
  121. package/dist/lib/json.js +12 -0
  122. package/dist/lib/multi-value.d.ts +3 -0
  123. package/dist/lib/multi-value.js +22 -0
  124. package/dist/lib/record-option.d.ts +7 -0
  125. package/dist/lib/record-option.js +52 -0
  126. package/dist/lib/use-record-labels.d.ts +14 -0
  127. package/dist/lib/use-record-labels.js +130 -0
  128. package/dist/lib/utils.d.ts +2 -0
  129. package/dist/lib/utils.js +5 -0
  130. package/dist/list-view.d.ts +26 -0
  131. package/dist/list-view.js +11 -0
  132. package/dist/markdown/blocks.d.ts +10 -0
  133. package/dist/markdown/blocks.js +57 -0
  134. package/dist/markdown/extensions.d.ts +6 -0
  135. package/dist/markdown/extensions.js +25 -0
  136. package/dist/markdown/slash.d.ts +23 -0
  137. package/dist/markdown/slash.js +27 -0
  138. package/dist/markdown/toolbar.d.ts +13 -0
  139. package/dist/markdown/toolbar.js +119 -0
  140. package/dist/plugin-ui.d.ts +43 -0
  141. package/dist/plugin-ui.js +37 -0
  142. package/dist/registry.d.ts +26 -0
  143. package/dist/registry.js +169 -0
  144. package/dist/render/blocks/accordion.d.ts +1 -0
  145. package/dist/render/blocks/accordion.js +15 -0
  146. package/dist/render/blocks/aside.d.ts +1 -0
  147. package/dist/render/blocks/aside.js +14 -0
  148. package/dist/render/blocks/balance.d.ts +1 -0
  149. package/dist/render/blocks/balance.js +14 -0
  150. package/dist/render/blocks/bento.d.ts +1 -0
  151. package/dist/render/blocks/bento.js +24 -0
  152. package/dist/render/blocks/block-shell.d.ts +15 -0
  153. package/dist/render/blocks/block-shell.js +20 -0
  154. package/dist/render/blocks/calendar.d.ts +1 -0
  155. package/dist/render/blocks/calendar.js +142 -0
  156. package/dist/render/blocks/callout.d.ts +1 -0
  157. package/dist/render/blocks/callout.js +21 -0
  158. package/dist/render/blocks/chart.d.ts +1 -0
  159. package/dist/render/blocks/chart.js +46 -0
  160. package/dist/render/blocks/compare.d.ts +1 -0
  161. package/dist/render/blocks/compare.js +16 -0
  162. package/dist/render/blocks/countdown.d.ts +1 -0
  163. package/dist/render/blocks/countdown.js +36 -0
  164. package/dist/render/blocks/deck.d.ts +1 -0
  165. package/dist/render/blocks/deck.js +29 -0
  166. package/dist/render/blocks/epigraph.d.ts +1 -0
  167. package/dist/render/blocks/epigraph.js +13 -0
  168. package/dist/render/blocks/facets.d.ts +1 -0
  169. package/dist/render/blocks/facets.js +23 -0
  170. package/dist/render/blocks/figure.d.ts +1 -0
  171. package/dist/render/blocks/figure.js +13 -0
  172. package/dist/render/blocks/grid.d.ts +1 -0
  173. package/dist/render/blocks/grid.js +21 -0
  174. package/dist/render/blocks/heatmap.d.ts +1 -0
  175. package/dist/render/blocks/heatmap.js +135 -0
  176. package/dist/render/blocks/idcard.d.ts +1 -0
  177. package/dist/render/blocks/idcard.js +30 -0
  178. package/dist/render/blocks/identity.d.ts +1 -0
  179. package/dist/render/blocks/identity.js +46 -0
  180. package/dist/render/blocks/index.d.ts +40 -0
  181. package/dist/render/blocks/index.js +40 -0
  182. package/dist/render/blocks/journal.d.ts +1 -0
  183. package/dist/render/blocks/journal.js +50 -0
  184. package/dist/render/blocks/ledger.d.ts +1 -0
  185. package/dist/render/blocks/ledger.js +23 -0
  186. package/dist/render/blocks/manifest.d.ts +1 -0
  187. package/dist/render/blocks/manifest.js +50 -0
  188. package/dist/render/blocks/masthead.d.ts +1 -0
  189. package/dist/render/blocks/masthead.js +15 -0
  190. package/dist/render/blocks/meter.d.ts +1 -0
  191. package/dist/render/blocks/meter.js +32 -0
  192. package/dist/render/blocks/nutrition.d.ts +1 -0
  193. package/dist/render/blocks/nutrition.js +27 -0
  194. package/dist/render/blocks/people.d.ts +1 -0
  195. package/dist/render/blocks/people.js +35 -0
  196. package/dist/render/blocks/plaque.d.ts +1 -0
  197. package/dist/render/blocks/plaque.js +15 -0
  198. package/dist/render/blocks/properties.d.ts +1 -0
  199. package/dist/render/blocks/properties.js +22 -0
  200. package/dist/render/blocks/prose.d.ts +1 -0
  201. package/dist/render/blocks/prose.js +17 -0
  202. package/dist/render/blocks/receipt.d.ts +1 -0
  203. package/dist/render/blocks/receipt.js +23 -0
  204. package/dist/render/blocks/registry.d.ts +16 -0
  205. package/dist/render/blocks/registry.js +7 -0
  206. package/dist/render/blocks/relation-source.d.ts +2 -0
  207. package/dist/render/blocks/relation-source.js +6 -0
  208. package/dist/render/blocks/route.d.ts +1 -0
  209. package/dist/render/blocks/route.js +23 -0
  210. package/dist/render/blocks/score.d.ts +1 -0
  211. package/dist/render/blocks/score.js +15 -0
  212. package/dist/render/blocks/series.d.ts +23 -0
  213. package/dist/render/blocks/series.js +57 -0
  214. package/dist/render/blocks/specimen.d.ts +1 -0
  215. package/dist/render/blocks/specimen.js +19 -0
  216. package/dist/render/blocks/split.d.ts +1 -0
  217. package/dist/render/blocks/split.js +15 -0
  218. package/dist/render/blocks/spread.d.ts +1 -0
  219. package/dist/render/blocks/spread.js +15 -0
  220. package/dist/render/blocks/stack.d.ts +1 -0
  221. package/dist/render/blocks/stack.js +15 -0
  222. package/dist/render/blocks/stats.d.ts +1 -0
  223. package/dist/render/blocks/stats.js +23 -0
  224. package/dist/render/blocks/status.d.ts +1 -0
  225. package/dist/render/blocks/status.js +18 -0
  226. package/dist/render/blocks/table.d.ts +11 -0
  227. package/dist/render/blocks/table.js +136 -0
  228. package/dist/render/blocks/tabs.d.ts +1 -0
  229. package/dist/render/blocks/tabs.js +17 -0
  230. package/dist/render/blocks/terminal.d.ts +1 -0
  231. package/dist/render/blocks/terminal.js +18 -0
  232. package/dist/render/blocks/timeline.d.ts +1 -0
  233. package/dist/render/blocks/timeline.js +31 -0
  234. package/dist/render/box.d.ts +5 -0
  235. package/dist/render/box.js +23 -0
  236. package/dist/render/chrome.d.ts +64 -0
  237. package/dist/render/chrome.js +92 -0
  238. package/dist/render/core/amount.d.ts +1 -0
  239. package/dist/render/core/amount.js +19 -0
  240. package/dist/render/core/attachment.d.ts +29 -0
  241. package/dist/render/core/attachment.js +102 -0
  242. package/dist/render/core/choice.d.ts +1 -0
  243. package/dist/render/core/choice.js +40 -0
  244. package/dist/render/core/composite.d.ts +1 -0
  245. package/dist/render/core/composite.js +132 -0
  246. package/dist/render/core/datetime.d.ts +2 -0
  247. package/dist/render/core/datetime.js +215 -0
  248. package/dist/render/core/dimensions.d.ts +1 -0
  249. package/dist/render/core/dimensions.js +44 -0
  250. package/dist/render/core/embed.d.ts +11 -0
  251. package/dist/render/core/embed.js +99 -0
  252. package/dist/render/core/file.d.ts +12 -0
  253. package/dist/render/core/file.js +238 -0
  254. package/dist/render/core/illustrated.d.ts +39 -0
  255. package/dist/render/core/illustrated.js +113 -0
  256. package/dist/render/core/index.d.ts +23 -0
  257. package/dist/render/core/index.js +23 -0
  258. package/dist/render/core/layout-elements.d.ts +1 -0
  259. package/dist/render/core/layout-elements.js +78 -0
  260. package/dist/render/core/localpath.d.ts +6 -0
  261. package/dist/render/core/localpath.js +73 -0
  262. package/dist/render/core/money.d.ts +1 -0
  263. package/dist/render/core/money.js +39 -0
  264. package/dist/render/core/number.d.ts +17 -0
  265. package/dist/render/core/number.js +104 -0
  266. package/dist/render/core/period.d.ts +1 -0
  267. package/dist/render/core/period.js +60 -0
  268. package/dist/render/core/range.d.ts +1 -0
  269. package/dist/render/core/range.js +55 -0
  270. package/dist/render/core/reminder.d.ts +2 -0
  271. package/dist/render/core/reminder.js +56 -0
  272. package/dist/render/core/source.d.ts +3 -0
  273. package/dist/render/core/source.js +65 -0
  274. package/dist/render/core/stepper.d.ts +1 -0
  275. package/dist/render/core/stepper.js +81 -0
  276. package/dist/render/core/storage-group.d.ts +1 -0
  277. package/dist/render/core/storage-group.js +30 -0
  278. package/dist/render/core/text.d.ts +15 -0
  279. package/dist/render/core/text.js +370 -0
  280. package/dist/render/core/tristate.d.ts +1 -0
  281. package/dist/render/core/tristate.js +42 -0
  282. package/dist/render/core/weight.d.ts +4 -0
  283. package/dist/render/core/weight.js +38 -0
  284. package/dist/render/dispatch.d.ts +12 -0
  285. package/dist/render/dispatch.js +53 -0
  286. package/dist/render/display-override.d.ts +25 -0
  287. package/dist/render/display-override.js +23 -0
  288. package/dist/render/editor-mode.d.ts +4 -0
  289. package/dist/render/editor-mode.js +11 -0
  290. package/dist/render/field-address.d.ts +14 -0
  291. package/dist/render/field-address.js +10 -0
  292. package/dist/render/field-errors.d.ts +8 -0
  293. package/dist/render/field-errors.js +25 -0
  294. package/dist/render/field-frame.d.ts +20 -0
  295. package/dist/render/field-frame.js +78 -0
  296. package/dist/render/field-scope.d.ts +8 -0
  297. package/dist/render/field-scope.js +25 -0
  298. package/dist/render/field-width.d.ts +7 -0
  299. package/dist/render/field-width.js +12 -0
  300. package/dist/render/form-types.d.ts +12 -0
  301. package/dist/render/form-types.js +1 -0
  302. package/dist/render/hybrid-scope.d.ts +5 -0
  303. package/dist/render/hybrid-scope.js +9 -0
  304. package/dist/render/image.d.ts +64 -0
  305. package/dist/render/image.js +322 -0
  306. package/dist/render/live-kind.d.ts +7 -0
  307. package/dist/render/live-kind.js +104 -0
  308. package/dist/render/markdown-view.d.ts +5 -0
  309. package/dist/render/markdown-view.js +17 -0
  310. package/dist/render/multi.d.ts +10 -0
  311. package/dist/render/multi.js +26 -0
  312. package/dist/render/multiple-chips.d.ts +24 -0
  313. package/dist/render/multiple-chips.js +18 -0
  314. package/dist/render/option-list.d.ts +15 -0
  315. package/dist/render/option-list.js +47 -0
  316. package/dist/render/option-value.d.ts +20 -0
  317. package/dist/render/option-value.js +41 -0
  318. package/dist/render/picker-scrim.d.ts +7 -0
  319. package/dist/render/picker-scrim.js +32 -0
  320. package/dist/render/picker-surface.d.ts +5 -0
  321. package/dist/render/picker-surface.js +9 -0
  322. package/dist/render/popover-field.d.ts +16 -0
  323. package/dist/render/popover-field.js +153 -0
  324. package/dist/render/record-save-ctx.d.ts +11 -0
  325. package/dist/render/record-save-ctx.js +41 -0
  326. package/dist/render/shared.d.ts +92 -0
  327. package/dist/render/shared.js +182 -0
  328. package/dist/render/slot.d.ts +45 -0
  329. package/dist/render/slot.js +194 -0
  330. package/dist/render/sort-rows.d.ts +3 -0
  331. package/dist/render/sort-rows.js +38 -0
  332. package/dist/render/use-collection-rows.d.ts +10 -0
  333. package/dist/render/use-collection-rows.js +11 -0
  334. package/dist/render/use-field-edit.d.ts +28 -0
  335. package/dist/render/use-field-edit.js +50 -0
  336. package/dist/render/use-file-upload.d.ts +10 -0
  337. package/dist/render/use-file-upload.js +35 -0
  338. package/dist/render/use-form-bridge.d.ts +21 -0
  339. package/dist/render/use-form-bridge.js +53 -0
  340. package/dist/render/use-hybrid.d.ts +2 -0
  341. package/dist/render/use-hybrid.js +5 -0
  342. package/dist/render/widgets/attachment-group.d.ts +1 -0
  343. package/dist/render/widgets/attachment-group.js +35 -0
  344. package/dist/render/widgets/checklist-content.d.ts +15 -0
  345. package/dist/render/widgets/checklist-content.js +12 -0
  346. package/dist/render/widgets/checklist-group.d.ts +11 -0
  347. package/dist/render/widgets/checklist-group.js +47 -0
  348. package/dist/render/widgets/checklist-row.d.ts +14 -0
  349. package/dist/render/widgets/checklist-row.js +14 -0
  350. package/dist/render/widgets/display.d.ts +33 -0
  351. package/dist/render/widgets/display.js +97 -0
  352. package/dist/render/widgets/edit.d.ts +63 -0
  353. package/dist/render/widgets/edit.js +283 -0
  354. package/dist/render/widgets/fixed-collection.d.ts +11 -0
  355. package/dist/render/widgets/fixed-collection.js +34 -0
  356. package/dist/render/widgets/flow-row.d.ts +14 -0
  357. package/dist/render/widgets/flow-row.js +27 -0
  358. package/dist/render/widgets/group-edit.d.ts +9 -0
  359. package/dist/render/widgets/group-edit.js +23 -0
  360. package/dist/render/widgets/group-field.d.ts +9 -0
  361. package/dist/render/widgets/group-field.js +42 -0
  362. package/dist/render/widgets/group-widgets.d.ts +2 -0
  363. package/dist/render/widgets/group-widgets.js +41 -0
  364. package/dist/render/widgets/group.d.ts +26 -0
  365. package/dist/render/widgets/group.js +139 -0
  366. package/dist/render/widgets/illustrated-group.d.ts +1 -0
  367. package/dist/render/widgets/illustrated-group.js +41 -0
  368. package/dist/render/widgets/table-group.d.ts +11 -0
  369. package/dist/render/widgets/table-group.js +58 -0
  370. package/dist/render/widgets/two-cell-group.d.ts +21 -0
  371. package/dist/render/widgets/two-cell-group.js +42 -0
  372. package/dist/render/widgets/url-widget.d.ts +7 -0
  373. package/dist/render/widgets/url-widget.js +15 -0
  374. package/dist/render/widgets/weekday-grid.d.ts +13 -0
  375. package/dist/render/widgets/weekday-grid.js +47 -0
  376. package/dist/render/write.d.ts +5 -0
  377. package/dist/render/write.js +14 -0
  378. package/dist/schema-registry.d.ts +6 -0
  379. package/dist/schema-registry.js +25 -0
  380. package/dist/site-links.d.ts +13 -0
  381. package/dist/site-links.js +18 -0
  382. package/dist/strip-markdown.d.ts +1 -0
  383. package/dist/strip-markdown.js +11 -0
  384. package/dist/theme.css +189 -0
  385. package/dist/types.d.ts +84 -0
  386. package/dist/types.js +1 -0
  387. package/package.json +85 -0
@@ -0,0 +1,130 @@
1
+ import { useEffect, useMemo, useState } from 'react';
2
+ import { inlineText } from '@coffer-org/sdk/shelf';
3
+ import { getShelf } from "../schema-registry.js";
4
+ import { listRecords } from "../host-services.js";
5
+ const inFlight = new Map();
6
+ const byIdCache = new Map();
7
+ const listCache = new Map();
8
+ function cacheRows(library, shelf, rows) {
9
+ for (const r of rows)
10
+ byIdCache.set(`${library}/${shelf}/${String(r['id'])}`, r);
11
+ }
12
+ const inFlightById = new Map();
13
+ function fetchByIds(library, shelf, idsCsv) {
14
+ const key = `${library}/${shelf}/${idsCsv}`;
15
+ const existing = inFlightById.get(key);
16
+ if (existing)
17
+ return existing;
18
+ const p = listRecords(library, shelf, { id: idsCsv })
19
+ .then((rows) => {
20
+ cacheRows(library, shelf, rows);
21
+ return rows;
22
+ })
23
+ .finally(() => inFlightById.delete(key));
24
+ inFlightById.set(key, p);
25
+ return p;
26
+ }
27
+ export function clearRecordByIdCache() {
28
+ byIdCache.clear();
29
+ listCache.clear();
30
+ }
31
+ function filterKey(filter) {
32
+ if (!filter)
33
+ return '';
34
+ const keys = Object.keys(filter).sort();
35
+ return keys.length ? '?' + keys.map((k) => `${k}=${filter[k]}`).join('&') : '';
36
+ }
37
+ function fetchRows(library, shelf, filter) {
38
+ const key = `${library}/${shelf}${filterKey(filter)}`;
39
+ const cached = listCache.get(key);
40
+ if (cached)
41
+ return Promise.resolve(cached);
42
+ const existing = inFlight.get(key);
43
+ if (existing)
44
+ return existing;
45
+ const p = listRecords(library, shelf, filter)
46
+ .then((rows) => {
47
+ cacheRows(library, shelf, rows);
48
+ listCache.set(key, rows);
49
+ return rows;
50
+ })
51
+ .finally(() => inFlight.delete(key));
52
+ inFlight.set(key, p);
53
+ return p;
54
+ }
55
+ export function useRecordLabels(library, shelf, displayKey = 'name', filter) {
56
+ const [records, setRecords] = useState([]);
57
+ const [loadState, setLoadState] = useState('loading');
58
+ const filterDeps = filterKey(filter);
59
+ useEffect(() => {
60
+ if (!library || !shelf) {
61
+ setLoadState('idle');
62
+ return;
63
+ }
64
+ let alive = true;
65
+ setLoadState('loading');
66
+ fetchRows(library, shelf, filter)
67
+ .then((r) => {
68
+ if (!alive)
69
+ return;
70
+ setRecords(r);
71
+ setLoadState('idle');
72
+ })
73
+ .catch(() => {
74
+ if (alive)
75
+ setLoadState('error');
76
+ });
77
+ return () => {
78
+ alive = false;
79
+ };
80
+ }, [library, shelf, filterDeps]);
81
+ const rows = useMemo(() => {
82
+ const m = getShelf(library, shelf);
83
+ return records.map((x) => ({
84
+ id: String(x['id']),
85
+ label: m ? inlineText(m, x) : String(x[displayKey] ?? x['name'] ?? x['id']),
86
+ }));
87
+ }, [records, library, shelf, displayKey]);
88
+ const labelMap = useMemo(() => new Map(rows.map((r) => [r.id, r.label])), [rows]);
89
+ const recordMap = useMemo(() => new Map(records.map((r) => [String(r['id']), r])), [records]);
90
+ return { rows, labelMap, records, recordMap, loadState };
91
+ }
92
+ export function useRecordsByIds(library, shelf, ids) {
93
+ const key = useMemo(() => [...new Set(ids)].sort().join(','), [ids]);
94
+ const [map, setMap] = useState(new Map());
95
+ useEffect(() => {
96
+ if (!library || !shelf || !key) {
97
+ setMap(new Map());
98
+ return;
99
+ }
100
+ const resolved = new Map();
101
+ const missing = [];
102
+ for (const id of key.split(',')) {
103
+ const hit = byIdCache.get(`${library}/${shelf}/${id}`);
104
+ if (hit)
105
+ resolved.set(id, hit);
106
+ else
107
+ missing.push(id);
108
+ }
109
+ if (!missing.length) {
110
+ setMap(resolved);
111
+ return;
112
+ }
113
+ let alive = true;
114
+ fetchByIds(library, shelf, missing.join(','))
115
+ .then((rows) => {
116
+ for (const r of rows)
117
+ resolved.set(String(r['id']), r);
118
+ if (alive)
119
+ setMap(new Map(resolved));
120
+ })
121
+ .catch(() => {
122
+ if (alive)
123
+ setMap(resolved);
124
+ });
125
+ return () => {
126
+ alive = false;
127
+ };
128
+ }, [library, shelf, key]);
129
+ return map;
130
+ }
@@ -0,0 +1,2 @@
1
+ import { type ClassValue } from 'clsx';
2
+ export declare function cn(...inputs: ClassValue[]): string;
@@ -0,0 +1,5 @@
1
+ import { clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+ export function cn(...inputs) {
4
+ return twMerge(clsx(inputs));
5
+ }
@@ -0,0 +1,26 @@
1
+ import type { FC } from 'react';
2
+ import type { ShelfDef } from '@coffer-org/sdk/shelf';
3
+ export interface ListViewProps {
4
+ rows: Record<string, unknown>[];
5
+ shelf: ShelfDef;
6
+ keys: string[];
7
+ hrefBase: string;
8
+ onDelete: (id: string) => void;
9
+ deletingId: string | null;
10
+ onToggleFavorite?: (id: string) => void;
11
+ favoriteBusyId?: string | null;
12
+ sort: {
13
+ key: string;
14
+ dir: 'asc' | 'desc';
15
+ } | null;
16
+ onToggleSort: (key: string) => void;
17
+ scrollKey?: string;
18
+ }
19
+ export interface ListViewDef {
20
+ kind: string;
21
+ View: FC<ListViewProps>;
22
+ check?: (shelf: ShelfDef, keys: string[]) => string | null;
23
+ }
24
+ export declare const listViewRegistry: Record<string, ListViewDef>;
25
+ export declare function registerListView(def: ListViewDef): void;
26
+ export declare function resolveListView(kind: string): ListViewDef | undefined;
@@ -0,0 +1,11 @@
1
+ export const listViewRegistry = {};
2
+ export function registerListView(def) {
3
+ if (!def.kind)
4
+ throw new Error('[list-view] view without kind');
5
+ if (listViewRegistry[def.kind])
6
+ throw new Error(`[list-view] kind '${def.kind}' already registered`);
7
+ listViewRegistry[def.kind] = def;
8
+ }
9
+ export function resolveListView(kind) {
10
+ return listViewRegistry[kind];
11
+ }
@@ -0,0 +1,10 @@
1
+ import type { Editor } from '@tiptap/core';
2
+ import { type LucideIcon } from 'lucide-react';
3
+ import type { SlashRange } from './slash.tsx';
4
+ export type BlockAction = {
5
+ key: string;
6
+ icon: LucideIcon;
7
+ run: (editor: Editor, range?: SlashRange) => void;
8
+ active?: (editor: Editor) => boolean;
9
+ };
10
+ export declare const BLOCKS: BlockAction[];
@@ -0,0 +1,57 @@
1
+ import { Heading1, Heading2, Heading3, List, ListOrdered, ListChecks, Quote, Code2, Minus, Table as TableIcon, } from 'lucide-react';
2
+ const at = (editor, range) => {
3
+ const chain = editor.chain().focus();
4
+ return range ? chain.deleteRange(range) : chain;
5
+ };
6
+ const heading = (level, icon) => ({
7
+ key: `h${level}`,
8
+ icon,
9
+ run: (editor, range) => at(editor, range).toggleHeading({ level }).run(),
10
+ active: (editor) => editor.isActive('heading', { level }),
11
+ });
12
+ export const BLOCKS = [
13
+ heading(1, Heading1),
14
+ heading(2, Heading2),
15
+ heading(3, Heading3),
16
+ {
17
+ key: 'bulletList',
18
+ icon: List,
19
+ run: (editor, range) => at(editor, range).toggleBulletList().run(),
20
+ active: (editor) => editor.isActive('bulletList'),
21
+ },
22
+ {
23
+ key: 'orderedList',
24
+ icon: ListOrdered,
25
+ run: (editor, range) => at(editor, range).toggleOrderedList().run(),
26
+ active: (editor) => editor.isActive('orderedList'),
27
+ },
28
+ {
29
+ key: 'taskList',
30
+ icon: ListChecks,
31
+ run: (editor, range) => at(editor, range).toggleTaskList().run(),
32
+ active: (editor) => editor.isActive('taskList'),
33
+ },
34
+ {
35
+ key: 'blockquote',
36
+ icon: Quote,
37
+ run: (editor, range) => at(editor, range).toggleBlockquote().run(),
38
+ active: (editor) => editor.isActive('blockquote'),
39
+ },
40
+ {
41
+ key: 'codeBlock',
42
+ icon: Code2,
43
+ run: (editor, range) => at(editor, range).toggleCodeBlock().run(),
44
+ active: (editor) => editor.isActive('codeBlock'),
45
+ },
46
+ {
47
+ key: 'horizontalRule',
48
+ icon: Minus,
49
+ run: (editor, range) => at(editor, range).setHorizontalRule().run(),
50
+ },
51
+ {
52
+ key: 'table',
53
+ icon: TableIcon,
54
+ run: (editor, range) => at(editor, range).insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(),
55
+ active: (editor) => editor.isActive('table'),
56
+ },
57
+ ];
@@ -0,0 +1,6 @@
1
+ import type { Extensions } from '@tiptap/core';
2
+ import { type SlashHandlers } from './slash.tsx';
3
+ export declare function markdownExtensions(opts: {
4
+ placeholder?: string;
5
+ slash?: SlashHandlers;
6
+ }): Extensions;
@@ -0,0 +1,25 @@
1
+ import StarterKit from '@tiptap/starter-kit';
2
+ import { Placeholder } from '@tiptap/extensions';
3
+ import { TaskList, TaskItem } from '@tiptap/extension-list';
4
+ import { Table, TableRow, TableHeader, TableCell } from '@tiptap/extension-table';
5
+ import Image from '@tiptap/extension-image';
6
+ import { Markdown } from 'tiptap-markdown';
7
+ import { slashMenu } from "./slash.js";
8
+ export function markdownExtensions(opts) {
9
+ return [
10
+ StarterKit.configure({
11
+ link: { openOnClick: false },
12
+ underline: false,
13
+ }),
14
+ TaskList,
15
+ TaskItem.configure({ nested: true }),
16
+ Table,
17
+ TableRow,
18
+ TableHeader,
19
+ TableCell,
20
+ Image.configure({ inline: false }),
21
+ Markdown.configure({ transformPastedText: true, linkify: false }),
22
+ ...(opts.placeholder ? [Placeholder.configure({ placeholder: opts.placeholder })] : []),
23
+ ...(opts.slash ? [slashMenu(opts.slash)] : []),
24
+ ];
25
+ }
@@ -0,0 +1,23 @@
1
+ import { Extension, type Editor } from '@tiptap/core';
2
+ export type SlashRange = {
3
+ from: number;
4
+ to: number;
5
+ };
6
+ export type SlashItem = {
7
+ key: string;
8
+ run: (ctx: {
9
+ editor: Editor;
10
+ range: SlashRange;
11
+ }) => void;
12
+ };
13
+ export type SlashHandlers = {
14
+ filter: (query: string) => SlashItem[];
15
+ open: (state: {
16
+ rect: DOMRect | null;
17
+ items: SlashItem[];
18
+ pick: (item: SlashItem) => void;
19
+ }) => void;
20
+ close: () => void;
21
+ keyDown: (event: KeyboardEvent) => boolean;
22
+ };
23
+ export declare function slashMenu(handlers: SlashHandlers): Extension;
@@ -0,0 +1,27 @@
1
+ import { Extension } from '@tiptap/core';
2
+ import Suggestion from '@tiptap/suggestion';
3
+ export function slashMenu(handlers) {
4
+ return Extension.create({
5
+ name: 'slashMenu',
6
+ addProseMirrorPlugins() {
7
+ return [
8
+ Suggestion({
9
+ editor: this.editor,
10
+ char: '/',
11
+ allowedPrefixes: [' ', '\n'],
12
+ items: ({ query }) => handlers.filter(query),
13
+ command: ({ editor, range, props }) => props.run({ editor, range }),
14
+ render: () => {
15
+ const show = (props) => handlers.open({ rect: props.clientRect?.() ?? null, items: props.items, pick: props.command });
16
+ return {
17
+ onStart: show,
18
+ onUpdate: show,
19
+ onKeyDown: ({ event }) => handlers.keyDown(event),
20
+ onExit: () => handlers.close(),
21
+ };
22
+ },
23
+ }),
24
+ ];
25
+ },
26
+ });
27
+ }
@@ -0,0 +1,13 @@
1
+ import type { Editor } from '@tiptap/core';
2
+ import { type LucideIcon } from 'lucide-react';
3
+ export declare const ToolButton: import("react").ForwardRefExoticComponent<{
4
+ icon: LucideIcon;
5
+ label: string;
6
+ active?: boolean;
7
+ disabled?: boolean;
8
+ tone?: "danger";
9
+ onClick?: () => void;
10
+ } & Omit<Omit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref">, "onClick"> & import("react").RefAttributes<HTMLButtonElement>>;
11
+ export declare function Toolbar({ editor }: {
12
+ editor: Editor;
13
+ }): import("react").JSX.Element;
@@ -0,0 +1,119 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState, forwardRef } from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { useEditorState } from '@tiptap/react';
5
+ import { Bold, Italic, Strikethrough, Code, Link as LinkIcon, Unlink, ImagePlus, Undo2, Redo2, Check, BetweenVerticalEnd, BetweenHorizontalEnd, Rows3, Columns3, Grid2x2X, } from 'lucide-react';
6
+ import { Input } from "../components/ui/input.js";
7
+ import { Popover, PopoverContent, PopoverTrigger } from "../components/ui/popover.js";
8
+ import { BLOCKS } from "./blocks.js";
9
+ export const ToolButton = forwardRef(({ icon: Icon, label, active, disabled, tone, onClick, ...rest }, ref) => (_jsx("button", { ref: ref, type: "button", "aria-label": label, title: label, "aria-pressed": active ?? false, disabled: disabled, onClick: onClick, ...rest, className: `flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent disabled:opacity-40 ${tone === 'danger' ? 'hover:bg-danger/10 hover:text-danger' : 'hover:bg-elevated hover:text-text'} ${active ? 'bg-elevated text-accent' : ''}`, children: _jsx(Icon, { size: 15 }) })));
10
+ ToolButton.displayName = 'ToolButton';
11
+ const Divider = () => _jsx("span", { className: "mx-0.5 h-5 w-px shrink-0 bg-border", "aria-hidden": true });
12
+ const MARKS = [
13
+ { key: 'bold', icon: Bold, run: (e) => e.chain().focus().toggleBold().run(), active: (e) => e.isActive('bold') },
14
+ {
15
+ key: 'italic',
16
+ icon: Italic,
17
+ run: (e) => e.chain().focus().toggleItalic().run(),
18
+ active: (e) => e.isActive('italic'),
19
+ },
20
+ {
21
+ key: 'strike',
22
+ icon: Strikethrough,
23
+ run: (e) => e.chain().focus().toggleStrike().run(),
24
+ active: (e) => e.isActive('strike'),
25
+ },
26
+ { key: 'code', icon: Code, run: (e) => e.chain().focus().toggleCode().run(), active: (e) => e.isActive('code') },
27
+ ];
28
+ function LinkForm({ editor, onDone }) {
29
+ const { t } = useTranslation();
30
+ const [href, setHref] = useState(editor.getAttributes('link').href ?? '');
31
+ const apply = () => {
32
+ const chain = editor.chain().focus().extendMarkRange('link');
33
+ if (href.trim() === '')
34
+ chain.unsetLink().run();
35
+ else
36
+ chain.setLink({ href: href.trim() }).run();
37
+ onDone();
38
+ };
39
+ return (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Input, { autoFocus: true, value: href, placeholder: "https://", "aria-label": t('form.mdLink'), onChange: (e) => setHref(e.target.value), onKeyDown: (e) => {
40
+ if (e.key === 'Enter') {
41
+ e.preventDefault();
42
+ apply();
43
+ }
44
+ if (e.key === 'Escape') {
45
+ e.preventDefault();
46
+ onDone();
47
+ }
48
+ }, className: "h-7 flex-1 text-sm" }), _jsx(ToolButton, { icon: Check, label: t('actions.save'), onClick: apply }), _jsx(ToolButton, { icon: Unlink, label: t('form.md.unlink'), onClick: () => {
49
+ editor.chain().focus().extendMarkRange('link').unsetLink().run();
50
+ onDone();
51
+ } })] }));
52
+ }
53
+ function ImageForm({ editor, onDone }) {
54
+ const { t } = useTranslation();
55
+ const [src, setSrc] = useState('');
56
+ const [alt, setAlt] = useState('');
57
+ const apply = () => {
58
+ const address = src.trim();
59
+ if (address)
60
+ editor
61
+ .chain()
62
+ .focus()
63
+ .setImage({ src: address, alt: alt.trim() || undefined })
64
+ .run();
65
+ onDone();
66
+ };
67
+ return (_jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [_jsx(Input, { autoFocus: true, value: src, placeholder: "https://\u2026 /uploads/\u2026", "aria-label": t('form.md.imageUrl'), onChange: (e) => setSrc(e.target.value), onKeyDown: (e) => {
68
+ if (e.key === 'Enter') {
69
+ e.preventDefault();
70
+ apply();
71
+ }
72
+ if (e.key === 'Escape') {
73
+ e.preventDefault();
74
+ onDone();
75
+ }
76
+ }, className: "h-7 min-w-0 flex-1 text-sm" }), _jsx(Input, { value: alt, placeholder: t('form.md.imageAlt'), "aria-label": t('form.md.imageAlt'), onChange: (e) => setAlt(e.target.value), onKeyDown: (e) => {
77
+ if (e.key === 'Enter') {
78
+ e.preventDefault();
79
+ apply();
80
+ }
81
+ if (e.key === 'Escape') {
82
+ e.preventDefault();
83
+ onDone();
84
+ }
85
+ }, className: "h-7 w-32 text-sm" }), _jsx(ToolButton, { icon: Check, label: t('actions.save'), disabled: !src.trim(), onClick: apply })] }));
86
+ }
87
+ function TableTools({ editor }) {
88
+ const { t } = useTranslation();
89
+ return (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(ToolButton, { icon: BetweenVerticalEnd, label: t('form.md.addRow'), onClick: () => editor.chain().focus().addRowAfter().run() }), _jsx(ToolButton, { icon: BetweenHorizontalEnd, label: t('form.md.addColumn'), onClick: () => editor.chain().focus().addColumnAfter().run() }), _jsx(ToolButton, { icon: Rows3, tone: "danger", label: t('form.md.deleteRow'), onClick: () => editor.chain().focus().deleteRow().run() }), _jsx(ToolButton, { icon: Columns3, tone: "danger", label: t('form.md.deleteColumn'), onClick: () => editor.chain().focus().deleteColumn().run() }), _jsx(ToolButton, { icon: Grid2x2X, tone: "danger", label: t('form.md.deleteTable'), onClick: () => editor.chain().focus().deleteTable().run() })] }));
90
+ }
91
+ function AddressButton({ icon, label, active, open, onOpenChange, children, }) {
92
+ return (_jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(ToolButton, { icon: icon, label: label, active: active || open }) }), _jsx(PopoverContent, { align: "start", className: "w-80 p-2", children: children })] }));
93
+ }
94
+ export function Toolbar({ editor }) {
95
+ const { t } = useTranslation();
96
+ const [form, setForm] = useState(null);
97
+ const state = useEditorState({
98
+ editor,
99
+ selector: ({ editor: e }) => e && !e.isDestroyed
100
+ ? {
101
+ marks: MARKS.map((m) => m.active(e)),
102
+ blocks: BLOCKS.map((b) => b.active?.(e) ?? false),
103
+ link: e.isActive('link'),
104
+ table: e.isActive('table'),
105
+ canUndo: e.can().undo(),
106
+ canRedo: e.can().redo(),
107
+ }
108
+ : {
109
+ marks: MARKS.map(() => false),
110
+ blocks: BLOCKS.map(() => false),
111
+ link: false,
112
+ table: false,
113
+ canUndo: false,
114
+ canRedo: false,
115
+ },
116
+ });
117
+ const group = (children) => _jsx("div", { className: "flex items-center gap-0.5", children: children });
118
+ return (_jsx("div", { className: "flex flex-col gap-1.5", children: _jsxs("div", { className: "-mx-0.5 flex items-center gap-0.5 overflow-x-auto overscroll-x-contain border-b border-border px-0.5 pb-1.5 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: [group(_jsxs(_Fragment, { children: [_jsx(ToolButton, { icon: Undo2, label: t('form.md.undo'), disabled: !state.canUndo, onClick: () => editor.chain().focus().undo().run() }), _jsx(ToolButton, { icon: Redo2, label: t('form.md.redo'), disabled: !state.canRedo, onClick: () => editor.chain().focus().redo().run() })] })), _jsx(Divider, {}), group(MARKS.map((m, i) => (_jsx(ToolButton, { icon: m.icon, label: t(`form.md.${m.key}`), active: state.marks[i], onClick: () => m.run(editor) }, m.key)))), _jsx(Divider, {}), group(BLOCKS.map((b, i) => (_jsx(ToolButton, { icon: b.icon, label: t(`form.md.${b.key}`), active: state.blocks[i], onClick: () => b.run(editor) }, b.key)))), _jsx(Divider, {}), group(_jsxs(_Fragment, { children: [_jsx(AddressButton, { icon: LinkIcon, label: t('form.md.link'), active: state.link, open: form === 'link', onOpenChange: (o) => setForm(o ? 'link' : null), children: _jsx(LinkForm, { editor: editor, onDone: () => setForm(null) }) }), _jsx(AddressButton, { icon: ImagePlus, label: t('form.md.image'), open: form === 'image', onOpenChange: (o) => setForm(o ? 'image' : null), children: _jsx(ImageForm, { editor: editor, onDone: () => setForm(null) }) })] })), state.table && _jsx(TableTools, { editor: editor })] }) }));
119
+ }
@@ -0,0 +1,43 @@
1
+ import type { FC, ComponentType } from 'react';
2
+ import type { FieldRenderer, TemplateImporter, RecordViewProps } from './types.ts';
3
+ import type { ListViewDef } from './list-view.ts';
4
+ export interface SlotEntry {
5
+ slot: string;
6
+ id: string;
7
+ load: () => Promise<{
8
+ default: ComponentType;
9
+ }>;
10
+ order?: number;
11
+ }
12
+ export interface RouteEntry {
13
+ path: string;
14
+ load: () => Promise<{
15
+ default: ComponentType;
16
+ }>;
17
+ }
18
+ export interface NavEntry {
19
+ to: string;
20
+ labelKey: string;
21
+ icon?: string;
22
+ order?: number;
23
+ }
24
+ export interface PluginUIBundle {
25
+ shelf?: {
26
+ library: string;
27
+ shelf: string;
28
+ RecordView?: FC<RecordViewProps>;
29
+ };
30
+ renderers?: FieldRenderer[];
31
+ listViews?: ListViewDef[];
32
+ templates?: Record<string, TemplateImporter<any>>;
33
+ translations?: Partial<Record<'uk' | 'ru' | 'en', Record<string, unknown>>>;
34
+ slots?: SlotEntry[];
35
+ routes?: RouteEntry[];
36
+ nav?: NavEntry[];
37
+ }
38
+ export declare function definePluginUI(b: PluginUIBundle): PluginUIBundle;
39
+ export declare function applyAppUI(b: PluginUIBundle): void;
40
+ export declare function getSlotEntries(slot: string): SlotEntry[];
41
+ export declare function getPluginRoutes(): RouteEntry[];
42
+ export declare function getPluginNav(): NavEntry[];
43
+ export declare function resetAppUI(): void;
@@ -0,0 +1,37 @@
1
+ export function definePluginUI(b) {
2
+ return b;
3
+ }
4
+ const slotRegistry = new Map();
5
+ const routeRegistry = new Map();
6
+ const navRegistry = new Map();
7
+ export function applyAppUI(b) {
8
+ for (const s of b.slots ?? []) {
9
+ let bucket = slotRegistry.get(s.slot);
10
+ if (!bucket) {
11
+ bucket = new Map();
12
+ slotRegistry.set(s.slot, bucket);
13
+ }
14
+ bucket.set(s.id, s);
15
+ }
16
+ for (const r of b.routes ?? [])
17
+ routeRegistry.set(r.path, r);
18
+ for (const n of b.nav ?? [])
19
+ navRegistry.set(n.to, n);
20
+ }
21
+ function byOrder(key) {
22
+ return (a, b) => (a.order ?? 0) - (b.order ?? 0) || key(a).localeCompare(key(b));
23
+ }
24
+ export function getSlotEntries(slot) {
25
+ return [...(slotRegistry.get(slot)?.values() ?? [])].sort(byOrder((e) => e.id));
26
+ }
27
+ export function getPluginRoutes() {
28
+ return [...routeRegistry.values()];
29
+ }
30
+ export function getPluginNav() {
31
+ return [...navRegistry.values()].sort(byOrder((n) => n.to));
32
+ }
33
+ export function resetAppUI() {
34
+ slotRegistry.clear();
35
+ routeRegistry.clear();
36
+ navRegistry.clear();
37
+ }
@@ -0,0 +1,26 @@
1
+ import type { FieldClient, FieldMeta, LayoutEl } from '@coffer-org/sdk/fields';
2
+ import type { FieldRenderer, ElementRenderProps, FieldInlineProps, FieldValueProps, FieldPickerProps, PickerSize, EditorMode, BoxGeom, TemplateImporter } from './types.ts';
3
+ import type { FC } from 'react';
4
+ export declare const rendererRegistry: Record<string, FieldRenderer>;
5
+ type NoWidenedProps<P> = Exclude<keyof P, keyof ElementRenderProps> extends never ? unknown : never;
6
+ export declare function registerRenderer<P extends ElementRenderProps>(r: {
7
+ kinds: string[];
8
+ layout?: 'block' | 'scalar' | ((field: FieldMeta) => 'block' | 'scalar');
9
+ childWidth?: string;
10
+ box?: BoxGeom;
11
+ Page: FC<P>;
12
+ Inline?: FC<FieldInlineProps>;
13
+ Value?: FC<FieldValueProps>;
14
+ pickerSize?: PickerSize | ((field: FieldMeta) => PickerSize);
15
+ Picker?: FC<FieldPickerProps>;
16
+ editor?: EditorMode;
17
+ keys?: FieldRenderer['keys'];
18
+ } & NoWidenedProps<P>): void;
19
+ export declare function resolveRenderer(field: Pick<FieldClient, 'kind'>): FieldRenderer | undefined;
20
+ export declare function elementKind(el: LayoutEl): string;
21
+ export declare function fieldLayout(field: FieldMeta): 'block' | 'scalar';
22
+ export declare const multiBlock: (field: FieldMeta) => "block" | "scalar";
23
+ export declare function resolveFieldSpan(field: FieldMeta): number;
24
+ export declare function registerTemplate(name: string, importer: TemplateImporter<any>): void;
25
+ export declare function resolveTemplate(name: string): TemplateImporter | undefined;
26
+ export {};