@btst/stack 1.10.0 → 1.12.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 (237) hide show
  1. package/dist/node_modules/.pnpm/@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@dnd-kit/core/dist/core.esm.cjs +1 -1
  2. package/dist/node_modules/.pnpm/@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@dnd-kit/core/dist/core.esm.mjs +1 -1
  3. package/dist/node_modules/.pnpm/@dnd-kit_sortable@10.0.0_@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0__react@19.2.0/node_modules/@dnd-kit/sortable/dist/sortable.esm.cjs +77 -0
  4. package/dist/node_modules/.pnpm/@dnd-kit_sortable@10.0.0_@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0__react@19.2.0/node_modules/@dnd-kit/sortable/dist/sortable.esm.mjs +79 -3
  5. package/dist/node_modules/.pnpm/@radix-ui_react-avatar@1.1.11_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react_850cfbef1935a6e49a6ad6c93c7ca70d/node_modules/@radix-ui/react-avatar/dist/index.cjs +140 -0
  6. package/dist/node_modules/.pnpm/@radix-ui_react-avatar@1.1.11_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react_850cfbef1935a6e49a6ad6c93c7ca70d/node_modules/@radix-ui/react-avatar/dist/index.mjs +119 -0
  7. package/dist/node_modules/.pnpm/@radix-ui_react-context@1.1.3_@types_react@19.2.6_react@19.2.0/node_modules/@radix-ui/react-context/dist/index.cjs +80 -0
  8. package/dist/node_modules/.pnpm/@radix-ui_react-context@1.1.3_@types_react@19.2.6_react@19.2.0/node_modules/@radix-ui/react-context/dist/index.mjs +64 -0
  9. package/dist/node_modules/.pnpm/@radix-ui_react-use-is-hydrated@0.1.0_@types_react@19.2.6_react@19.2.0/node_modules/@radix-ui/react-use-is-hydrated/dist/index.cjs +18 -0
  10. package/dist/node_modules/.pnpm/@radix-ui_react-use-is-hydrated@0.1.0_@types_react@19.2.6_react@19.2.0/node_modules/@radix-ui/react-use-is-hydrated/dist/index.mjs +16 -0
  11. package/dist/packages/better-stack/src/plugins/kanban/api/plugin.cjs +846 -0
  12. package/dist/packages/better-stack/src/plugins/kanban/api/plugin.mjs +844 -0
  13. package/dist/packages/better-stack/src/plugins/kanban/client/components/forms/board-form.cjs +85 -0
  14. package/dist/packages/better-stack/src/plugins/kanban/client/components/forms/board-form.mjs +83 -0
  15. package/dist/packages/better-stack/src/plugins/kanban/client/components/forms/column-form.cjs +72 -0
  16. package/dist/packages/better-stack/src/plugins/kanban/client/components/forms/column-form.mjs +70 -0
  17. package/dist/packages/better-stack/src/plugins/kanban/client/components/forms/task-form.cjs +200 -0
  18. package/dist/packages/better-stack/src/plugins/kanban/client/components/forms/task-form.mjs +198 -0
  19. package/dist/packages/better-stack/src/plugins/kanban/client/components/loading/board-skeleton.cjs +47 -0
  20. package/dist/packages/better-stack/src/plugins/kanban/client/components/loading/board-skeleton.mjs +45 -0
  21. package/dist/packages/better-stack/src/plugins/kanban/client/components/loading/boards-list-skeleton.cjs +30 -0
  22. package/dist/packages/better-stack/src/plugins/kanban/client/components/loading/boards-list-skeleton.mjs +28 -0
  23. package/dist/packages/better-stack/src/plugins/kanban/client/components/pages/404-page.cjs +27 -0
  24. package/dist/packages/better-stack/src/plugins/kanban/client/components/pages/404-page.mjs +25 -0
  25. package/dist/packages/better-stack/src/plugins/kanban/client/components/pages/board-page.cjs +31 -0
  26. package/dist/packages/better-stack/src/plugins/kanban/client/components/pages/board-page.internal.cjs +458 -0
  27. package/dist/packages/better-stack/src/plugins/kanban/client/components/pages/board-page.internal.mjs +456 -0
  28. package/dist/packages/better-stack/src/plugins/kanban/client/components/pages/board-page.mjs +29 -0
  29. package/dist/packages/better-stack/src/plugins/kanban/client/components/pages/boards-list-page.cjs +30 -0
  30. package/dist/packages/better-stack/src/plugins/kanban/client/components/pages/boards-list-page.internal.cjs +72 -0
  31. package/dist/packages/better-stack/src/plugins/kanban/client/components/pages/boards-list-page.internal.mjs +70 -0
  32. package/dist/packages/better-stack/src/plugins/kanban/client/components/pages/boards-list-page.mjs +28 -0
  33. package/dist/packages/better-stack/src/plugins/kanban/client/components/pages/new-board-page.cjs +30 -0
  34. package/dist/packages/better-stack/src/plugins/kanban/client/components/pages/new-board-page.internal.cjs +51 -0
  35. package/dist/packages/better-stack/src/plugins/kanban/client/components/pages/new-board-page.internal.mjs +49 -0
  36. package/dist/packages/better-stack/src/plugins/kanban/client/components/pages/new-board-page.mjs +28 -0
  37. package/dist/packages/better-stack/src/plugins/kanban/client/components/shared/column-content.cjs +76 -0
  38. package/dist/packages/better-stack/src/plugins/kanban/client/components/shared/column-content.mjs +74 -0
  39. package/dist/packages/better-stack/src/plugins/kanban/client/components/shared/default-error.cjs +27 -0
  40. package/dist/packages/better-stack/src/plugins/kanban/client/components/shared/default-error.mjs +25 -0
  41. package/dist/packages/better-stack/src/plugins/kanban/client/components/shared/empty-state.cjs +32 -0
  42. package/dist/packages/better-stack/src/plugins/kanban/client/components/shared/empty-state.mjs +30 -0
  43. package/dist/packages/better-stack/src/plugins/kanban/client/components/shared/kanban-board.cjs +78 -0
  44. package/dist/packages/better-stack/src/plugins/kanban/client/components/shared/kanban-board.mjs +76 -0
  45. package/dist/packages/better-stack/src/plugins/kanban/client/components/shared/page-wrapper.cjs +15 -0
  46. package/dist/packages/better-stack/src/plugins/kanban/client/components/shared/page-wrapper.mjs +13 -0
  47. package/dist/packages/better-stack/src/plugins/kanban/client/components/shared/task-card.cjs +68 -0
  48. package/dist/packages/better-stack/src/plugins/kanban/client/components/shared/task-card.mjs +66 -0
  49. package/dist/packages/better-stack/src/plugins/kanban/client/components/shared/user-avatar.cjs +32 -0
  50. package/dist/packages/better-stack/src/plugins/kanban/client/components/shared/user-avatar.mjs +30 -0
  51. package/dist/packages/better-stack/src/plugins/kanban/client/hooks/kanban-hooks.cjs +391 -0
  52. package/dist/packages/better-stack/src/plugins/kanban/client/hooks/kanban-hooks.mjs +381 -0
  53. package/dist/packages/better-stack/src/plugins/kanban/client/plugin.cjs +290 -0
  54. package/dist/packages/better-stack/src/plugins/kanban/client/plugin.mjs +288 -0
  55. package/dist/packages/better-stack/src/plugins/kanban/db.cjs +125 -0
  56. package/dist/packages/better-stack/src/plugins/kanban/db.mjs +123 -0
  57. package/dist/packages/better-stack/src/plugins/kanban/schemas.cjs +117 -0
  58. package/dist/packages/better-stack/src/plugins/kanban/schemas.mjs +102 -0
  59. package/dist/packages/better-stack/src/plugins/kanban/utils.cjs +49 -0
  60. package/dist/packages/better-stack/src/plugins/kanban/utils.mjs +45 -0
  61. package/dist/packages/ui/src/components/avatar.cjs +58 -0
  62. package/dist/packages/ui/src/components/avatar.mjs +54 -0
  63. package/dist/packages/ui/src/components/command.cjs +3 -3
  64. package/dist/packages/ui/src/components/command.mjs +3 -3
  65. package/dist/packages/ui/src/components/form-builder/index.mjs +2 -2
  66. package/dist/packages/ui/src/components/kanban.cjs +835 -0
  67. package/dist/packages/ui/src/components/kanban.mjs +805 -0
  68. package/dist/packages/ui/src/components/minimal-tiptap/utils.cjs +15 -11
  69. package/dist/packages/ui/src/components/minimal-tiptap/utils.mjs +15 -11
  70. package/dist/packages/ui/src/components/popover.cjs +8 -3
  71. package/dist/packages/ui/src/components/popover.mjs +9 -4
  72. package/dist/packages/ui/src/components/search-select.cjs +75 -0
  73. package/dist/packages/ui/src/components/search-select.mjs +73 -0
  74. package/dist/packages/ui/src/components/ui-builder/index.cjs +9 -7
  75. package/dist/packages/ui/src/components/ui-builder/index.mjs +9 -7
  76. package/dist/packages/ui/src/components/ui-builder/internal/canvas/auto-frame.cjs +6 -3
  77. package/dist/packages/ui/src/components/ui-builder/internal/canvas/auto-frame.mjs +6 -3
  78. package/dist/packages/ui/src/components/ui-builder/internal/components/add-component-popover.cjs +228 -48
  79. package/dist/packages/ui/src/components/ui-builder/internal/components/add-component-popover.mjs +228 -48
  80. package/dist/packages/ui/src/components/ui-builder/internal/components/element-selector.cjs +1 -1
  81. package/dist/packages/ui/src/components/ui-builder/internal/components/element-selector.mjs +1 -1
  82. package/dist/packages/ui/src/components/ui-builder/internal/components/error-fallback.cjs +4 -2
  83. package/dist/packages/ui/src/components/ui-builder/internal/components/error-fallback.mjs +4 -2
  84. package/dist/packages/ui/src/components/ui-builder/internal/components/multi-select.cjs +6 -3
  85. package/dist/packages/ui/src/components/ui-builder/internal/components/multi-select.mjs +6 -3
  86. package/dist/packages/ui/src/components/ui-builder/internal/dnd/draggable-new-component.cjs +67 -0
  87. package/dist/packages/ui/src/components/ui-builder/internal/dnd/draggable-new-component.mjs +62 -0
  88. package/dist/packages/ui/src/components/ui-builder/internal/dnd/drop-zone.cjs +181 -37
  89. package/dist/packages/ui/src/components/ui-builder/internal/dnd/drop-zone.mjs +181 -38
  90. package/dist/packages/ui/src/components/ui-builder/internal/editor-panel.cjs +1 -1
  91. package/dist/packages/ui/src/components/ui-builder/internal/editor-panel.mjs +1 -1
  92. package/dist/packages/ui/src/components/ui-builder/internal/form-fields/classname-control/classname-group-control.cjs +1 -1
  93. package/dist/packages/ui/src/components/ui-builder/internal/form-fields/classname-control/classname-group-control.mjs +1 -1
  94. package/dist/packages/ui/src/components/ui-builder/internal/form-fields/classname-control/classname-item-control.cjs +9 -2
  95. package/dist/packages/ui/src/components/ui-builder/internal/form-fields/classname-control/classname-item-control.mjs +9 -2
  96. package/dist/packages/ui/src/components/ui-builder/internal/form-fields/iconname-field.cjs +3 -2
  97. package/dist/packages/ui/src/components/ui-builder/internal/form-fields/iconname-field.mjs +3 -2
  98. package/dist/packages/ui/src/components/ui-builder/internal/layers-panel.cjs +1 -1
  99. package/dist/packages/ui/src/components/ui-builder/internal/layers-panel.mjs +1 -1
  100. package/dist/packages/ui/src/components/ui-builder/internal/props-panel.cjs +17 -5
  101. package/dist/packages/ui/src/components/ui-builder/internal/props-panel.mjs +17 -5
  102. package/dist/packages/ui/src/components/ui-builder/internal/utils/render-utils.cjs +70 -16
  103. package/dist/packages/ui/src/components/ui-builder/internal/utils/render-utils.mjs +73 -20
  104. package/dist/packages/ui/src/lib/compose-refs.cjs +56 -0
  105. package/dist/packages/ui/src/lib/compose-refs.mjs +39 -0
  106. package/dist/packages/ui/src/lib/ui-builder/context/dnd-context-colission-utils.cjs +14 -9
  107. package/dist/packages/ui/src/lib/ui-builder/context/dnd-context-colission-utils.mjs +14 -9
  108. package/dist/packages/ui/src/lib/ui-builder/context/dnd-context.cjs +38 -10
  109. package/dist/packages/ui/src/lib/ui-builder/context/dnd-context.mjs +35 -11
  110. package/dist/packages/ui/src/lib/ui-builder/context/dnd-contexts.cjs +1 -0
  111. package/dist/packages/ui/src/lib/ui-builder/context/dnd-contexts.mjs +1 -0
  112. package/dist/packages/ui/src/lib/ui-builder/context/drag-overlay.cjs +7 -4
  113. package/dist/packages/ui/src/lib/ui-builder/context/drag-overlay.mjs +7 -4
  114. package/dist/packages/ui/src/lib/ui-builder/hooks/use-auto-scroll.cjs +4 -4
  115. package/dist/packages/ui/src/lib/ui-builder/hooks/use-auto-scroll.mjs +4 -4
  116. package/dist/packages/ui/src/lib/ui-builder/hooks/use-dnd-event-handlers.cjs +53 -16
  117. package/dist/packages/ui/src/lib/ui-builder/hooks/use-dnd-event-handlers.mjs +53 -16
  118. package/dist/packages/ui/src/lib/ui-builder/hooks/use-drop-validation.cjs +23 -7
  119. package/dist/packages/ui/src/lib/ui-builder/hooks/use-drop-validation.mjs +23 -7
  120. package/dist/packages/ui/src/lib/ui-builder/registry/form-field-overrides.cjs +110 -11
  121. package/dist/packages/ui/src/lib/ui-builder/registry/form-field-overrides.mjs +111 -13
  122. package/dist/packages/ui/src/lib/ui-builder/store/editor-store.cjs +3 -2
  123. package/dist/packages/ui/src/lib/ui-builder/store/editor-store.mjs +3 -2
  124. package/dist/packages/ui/src/lib/ui-builder/store/layer-store.cjs +53 -7
  125. package/dist/packages/ui/src/lib/ui-builder/store/layer-store.mjs +54 -8
  126. package/dist/packages/ui/src/lib/ui-builder/store/layer-utils.cjs +4 -3
  127. package/dist/packages/ui/src/lib/ui-builder/store/layer-utils.mjs +4 -3
  128. package/dist/packages/ui/src/lib/ui-builder/utils/variable-resolver.cjs +12 -0
  129. package/dist/packages/ui/src/lib/ui-builder/utils/variable-resolver.mjs +12 -1
  130. package/dist/plugins/blog/api/index.d.cts +1 -1
  131. package/dist/plugins/blog/api/index.d.mts +1 -1
  132. package/dist/plugins/blog/api/index.d.ts +1 -1
  133. package/dist/plugins/blog/client/hooks/index.d.cts +2 -2
  134. package/dist/plugins/blog/client/hooks/index.d.mts +2 -2
  135. package/dist/plugins/blog/client/hooks/index.d.ts +2 -2
  136. package/dist/plugins/blog/client/index.d.cts +1 -1
  137. package/dist/plugins/blog/client/index.d.mts +1 -1
  138. package/dist/plugins/blog/client/index.d.ts +1 -1
  139. package/dist/plugins/blog/query-keys.d.cts +2 -2
  140. package/dist/plugins/blog/query-keys.d.mts +2 -2
  141. package/dist/plugins/blog/query-keys.d.ts +2 -2
  142. package/dist/plugins/kanban/api/index.cjs +7 -0
  143. package/dist/plugins/kanban/api/index.d.cts +403 -0
  144. package/dist/plugins/kanban/api/index.d.mts +403 -0
  145. package/dist/plugins/kanban/api/index.d.ts +403 -0
  146. package/dist/plugins/kanban/api/index.mjs +1 -0
  147. package/dist/plugins/kanban/client/components/index.cjs +35 -0
  148. package/dist/plugins/kanban/client/components/index.d.cts +102 -0
  149. package/dist/plugins/kanban/client/components/index.d.mts +102 -0
  150. package/dist/plugins/kanban/client/components/index.d.ts +102 -0
  151. package/dist/plugins/kanban/client/components/index.mjs +15 -0
  152. package/dist/plugins/kanban/client/hooks/index.cjs +15 -0
  153. package/dist/plugins/kanban/client/hooks/index.d.cts +143 -0
  154. package/dist/plugins/kanban/client/hooks/index.d.mts +143 -0
  155. package/dist/plugins/kanban/client/hooks/index.d.ts +143 -0
  156. package/dist/plugins/kanban/client/hooks/index.mjs +1 -0
  157. package/dist/plugins/kanban/client/index.cjs +7 -0
  158. package/dist/plugins/kanban/client/index.d.cts +196 -0
  159. package/dist/plugins/kanban/client/index.d.mts +196 -0
  160. package/dist/plugins/kanban/client/index.d.ts +196 -0
  161. package/dist/plugins/kanban/client/index.mjs +1 -0
  162. package/dist/plugins/kanban/client.css +68 -0
  163. package/dist/plugins/kanban/query-keys.cjs +105 -0
  164. package/dist/plugins/kanban/query-keys.d.cts +59 -0
  165. package/dist/plugins/kanban/query-keys.d.mts +59 -0
  166. package/dist/plugins/kanban/query-keys.d.ts +59 -0
  167. package/dist/plugins/kanban/query-keys.mjs +103 -0
  168. package/dist/plugins/kanban/style.css +7 -0
  169. package/dist/plugins/ui-builder/client/components/index.d.cts +1 -1
  170. package/dist/plugins/ui-builder/client/components/index.d.mts +1 -1
  171. package/dist/plugins/ui-builder/client/components/index.d.ts +1 -1
  172. package/dist/plugins/ui-builder/client/hooks/index.d.cts +2 -2
  173. package/dist/plugins/ui-builder/client/hooks/index.d.mts +2 -2
  174. package/dist/plugins/ui-builder/client/hooks/index.d.ts +2 -2
  175. package/dist/plugins/ui-builder/client/index.d.cts +17 -7
  176. package/dist/plugins/ui-builder/client/index.d.mts +17 -7
  177. package/dist/plugins/ui-builder/client/index.d.ts +17 -7
  178. package/dist/plugins/ui-builder/index.d.cts +2 -2
  179. package/dist/plugins/ui-builder/index.d.mts +2 -2
  180. package/dist/plugins/ui-builder/index.d.ts +2 -2
  181. package/dist/plugins/ui-builder/style.css +6 -0
  182. package/dist/shared/{stack.BSM2cgoq.d.cts → stack.BYysGdHl.d.cts} +1 -1
  183. package/dist/shared/{stack.CqfZWfjJ.d.cts → stack.BdJFrdyt.d.cts} +8 -2
  184. package/dist/shared/{stack.e1FN86dE.d.mts → stack.ChVuHi5e.d.mts} +8 -2
  185. package/dist/shared/stack.DKDMI-QO.d.cts +70 -0
  186. package/dist/shared/stack.DKDMI-QO.d.mts +70 -0
  187. package/dist/shared/stack.DKDMI-QO.d.ts +70 -0
  188. package/dist/shared/{stack.CLtOoAqF.d.mts → stack.DYCFcnkL.d.mts} +1 -1
  189. package/dist/shared/{stack.MMntCVZZ.d.ts → stack.EhM4pmtN.d.ts} +8 -2
  190. package/dist/shared/stack.FeaWkglm.d.cts +190 -0
  191. package/dist/shared/stack.FeaWkglm.d.mts +190 -0
  192. package/dist/shared/stack.FeaWkglm.d.ts +190 -0
  193. package/dist/shared/{stack.BD1m-4yB.d.ts → stack.kFbDspnF.d.ts} +1 -1
  194. package/package.json +56 -2
  195. package/src/plugins/kanban/api/index.ts +6 -0
  196. package/src/plugins/kanban/api/plugin.ts +1245 -0
  197. package/src/plugins/kanban/client/components/forms/board-form.tsx +108 -0
  198. package/src/plugins/kanban/client/components/forms/column-form.tsx +97 -0
  199. package/src/plugins/kanban/client/components/forms/task-form.tsx +274 -0
  200. package/src/plugins/kanban/client/components/index.tsx +21 -0
  201. package/src/plugins/kanban/client/components/loading/board-skeleton.tsx +49 -0
  202. package/src/plugins/kanban/client/components/loading/boards-list-skeleton.tsx +34 -0
  203. package/src/plugins/kanban/client/components/loading/index.tsx +2 -0
  204. package/src/plugins/kanban/client/components/pages/404-page.tsx +28 -0
  205. package/src/plugins/kanban/client/components/pages/board-page.internal.tsx +575 -0
  206. package/src/plugins/kanban/client/components/pages/board-page.tsx +31 -0
  207. package/src/plugins/kanban/client/components/pages/boards-list-page.internal.tsx +101 -0
  208. package/src/plugins/kanban/client/components/pages/boards-list-page.tsx +26 -0
  209. package/src/plugins/kanban/client/components/pages/new-board-page.internal.tsx +65 -0
  210. package/src/plugins/kanban/client/components/pages/new-board-page.tsx +26 -0
  211. package/src/plugins/kanban/client/components/shared/column-content.tsx +108 -0
  212. package/src/plugins/kanban/client/components/shared/default-error.tsx +32 -0
  213. package/src/plugins/kanban/client/components/shared/empty-state.tsx +37 -0
  214. package/src/plugins/kanban/client/components/shared/kanban-board.tsx +87 -0
  215. package/src/plugins/kanban/client/components/shared/page-wrapper.tsx +20 -0
  216. package/src/plugins/kanban/client/components/shared/task-card.tsx +79 -0
  217. package/src/plugins/kanban/client/components/shared/user-avatar.tsx +63 -0
  218. package/src/plugins/kanban/client/hooks/index.tsx +11 -0
  219. package/src/plugins/kanban/client/hooks/kanban-hooks.tsx +560 -0
  220. package/src/plugins/kanban/client/index.ts +8 -0
  221. package/src/plugins/kanban/client/localization/index.ts +28 -0
  222. package/src/plugins/kanban/client/localization/kanban-common.ts +69 -0
  223. package/src/plugins/kanban/client/localization/kanban-forms.ts +70 -0
  224. package/src/plugins/kanban/client/localization/kanban-list.ts +36 -0
  225. package/src/plugins/kanban/client/overrides.ts +145 -0
  226. package/src/plugins/kanban/client/plugin.tsx +463 -0
  227. package/src/plugins/kanban/client.css +68 -0
  228. package/src/plugins/kanban/db.ts +125 -0
  229. package/src/plugins/kanban/query-keys.ts +154 -0
  230. package/src/plugins/kanban/schemas.ts +143 -0
  231. package/src/plugins/kanban/style.css +7 -0
  232. package/src/plugins/kanban/types.ts +106 -0
  233. package/src/plugins/kanban/utils.ts +107 -0
  234. package/src/plugins/ui-builder/style.css +6 -0
  235. package/dist/shared/{stack.DLhzx1-D.d.mts → stack.CcI4sYJP.d.cts} +1 -1
  236. package/dist/shared/{stack.DLhzx1-D.d.ts → stack.CcI4sYJP.d.mts} +1 -1
  237. package/dist/shared/{stack.DLhzx1-D.d.cts → stack.CcI4sYJP.d.ts} +1 -1
@@ -0,0 +1,560 @@
1
+ "use client";
2
+
3
+ import {
4
+ useMutation,
5
+ useQuery,
6
+ useQueryClient,
7
+ useSuspenseQuery,
8
+ } from "@tanstack/react-query";
9
+ import { createApiClient } from "@btst/stack/plugins/client";
10
+ import { usePluginOverrides } from "@btst/stack/context";
11
+ import type { KanbanApiRouter } from "../../api";
12
+ import { createKanbanQueryKeys } from "../../query-keys";
13
+ import type { KanbanPluginOverrides, KanbanUser } from "../overrides";
14
+ import type {
15
+ SerializedBoard,
16
+ SerializedBoardWithColumns,
17
+ SerializedColumn,
18
+ SerializedTask,
19
+ Priority,
20
+ } from "../../types";
21
+
22
+ // ============ Error Handling ============
23
+
24
+ // Type guard for better-call error responses
25
+ function isErrorResponse(
26
+ response: unknown,
27
+ ): response is { error: unknown; data?: never } {
28
+ return (
29
+ typeof response === "object" &&
30
+ response !== null &&
31
+ "error" in response &&
32
+ response.error !== null &&
33
+ response.error !== undefined
34
+ );
35
+ }
36
+
37
+ // Helper to convert error to a proper Error object with meaningful message
38
+ function toError(error: unknown): Error {
39
+ if (error instanceof Error) {
40
+ return error;
41
+ }
42
+
43
+ if (typeof error === "object" && error !== null) {
44
+ const errorObj = error as Record<string, unknown>;
45
+ const message =
46
+ (typeof errorObj.message === "string" ? errorObj.message : null) ||
47
+ (typeof errorObj.error === "string" ? errorObj.error : null) ||
48
+ JSON.stringify(error);
49
+
50
+ const err = new Error(message);
51
+ Object.assign(err, error);
52
+ return err;
53
+ }
54
+
55
+ return new Error(String(error));
56
+ }
57
+
58
+ // ============ API Client Hook ============
59
+
60
+ function useKanbanClient() {
61
+ const { apiBaseURL, apiBasePath, headers } =
62
+ usePluginOverrides<KanbanPluginOverrides>("kanban");
63
+
64
+ const client = createApiClient<KanbanApiRouter>({
65
+ baseURL: apiBaseURL,
66
+ basePath: apiBasePath,
67
+ });
68
+
69
+ return { client, headers };
70
+ }
71
+
72
+ // ============ Board Hooks ============
73
+
74
+ /**
75
+ * Hook to fetch list of boards
76
+ */
77
+ export function useBoards(params?: {
78
+ slug?: string;
79
+ ownerId?: string;
80
+ organizationId?: string;
81
+ }) {
82
+ const { client, headers } = useKanbanClient();
83
+ const queries = createKanbanQueryKeys(client, headers);
84
+
85
+ return useQuery({
86
+ ...queries.boards.list(params),
87
+ staleTime: 30_000,
88
+ });
89
+ }
90
+
91
+ /**
92
+ * Hook to fetch list of boards with suspense
93
+ */
94
+ export function useSuspenseBoards(params?: {
95
+ slug?: string;
96
+ ownerId?: string;
97
+ organizationId?: string;
98
+ }) {
99
+ const { client, headers } = useKanbanClient();
100
+ const queries = createKanbanQueryKeys(client, headers);
101
+
102
+ const result = useSuspenseQuery({
103
+ ...queries.boards.list(params),
104
+ staleTime: 30_000,
105
+ });
106
+
107
+ if (result.error && !result.isFetching) {
108
+ throw result.error;
109
+ }
110
+
111
+ return result;
112
+ }
113
+
114
+ /**
115
+ * Hook to fetch a single board by ID
116
+ */
117
+ export function useBoard(boardId: string) {
118
+ const { client, headers } = useKanbanClient();
119
+ const queries = createKanbanQueryKeys(client, headers);
120
+
121
+ return useQuery({
122
+ ...queries.boards.detail(boardId),
123
+ staleTime: 30_000,
124
+ enabled: !!boardId,
125
+ });
126
+ }
127
+
128
+ /**
129
+ * Hook to fetch a single board with suspense
130
+ */
131
+ export function useSuspenseBoard(boardId: string) {
132
+ const { client, headers } = useKanbanClient();
133
+ const queries = createKanbanQueryKeys(client, headers);
134
+
135
+ const result = useSuspenseQuery({
136
+ ...queries.boards.detail(boardId),
137
+ staleTime: 30_000,
138
+ });
139
+
140
+ if (result.error && !result.isFetching) {
141
+ throw result.error;
142
+ }
143
+
144
+ return result;
145
+ }
146
+
147
+ // ============ Board Mutations ============
148
+
149
+ /**
150
+ * Hook for board CRUD mutations
151
+ */
152
+ export function useBoardMutations() {
153
+ const { client, headers } = useKanbanClient();
154
+ const queryClient = useQueryClient();
155
+
156
+ const createMutation = useMutation({
157
+ mutationFn: async (data: {
158
+ name: string;
159
+ description?: string;
160
+ ownerId?: string;
161
+ organizationId?: string;
162
+ }) => {
163
+ const response = await client("@post/boards", {
164
+ method: "POST",
165
+ body: data,
166
+ headers,
167
+ });
168
+ if (isErrorResponse(response)) {
169
+ const errorResponse = response as { error: unknown };
170
+ throw toError(errorResponse.error);
171
+ }
172
+ return response.data as unknown as SerializedBoardWithColumns;
173
+ },
174
+ onSuccess: () => {
175
+ queryClient.invalidateQueries({ queryKey: ["boards"] });
176
+ },
177
+ });
178
+
179
+ const updateMutation = useMutation({
180
+ mutationFn: async ({
181
+ id,
182
+ data,
183
+ }: {
184
+ id: string;
185
+ data: Partial<{
186
+ name: string;
187
+ description: string;
188
+ slug: string;
189
+ }>;
190
+ }) => {
191
+ const response = await client("@put/boards/:id", {
192
+ method: "PUT",
193
+ params: { id },
194
+ body: data,
195
+ headers,
196
+ });
197
+ if (isErrorResponse(response)) {
198
+ const errorResponse = response as { error: unknown };
199
+ throw toError(errorResponse.error);
200
+ }
201
+ return response.data as unknown as SerializedBoard;
202
+ },
203
+ onSuccess: () => {
204
+ queryClient.invalidateQueries({ queryKey: ["boards"] });
205
+ },
206
+ });
207
+
208
+ const deleteMutation = useMutation({
209
+ mutationFn: async (id: string) => {
210
+ const response = await client("@delete/boards/:id", {
211
+ method: "DELETE",
212
+ params: { id },
213
+ headers,
214
+ });
215
+ if (isErrorResponse(response)) {
216
+ const errorResponse = response as { error: unknown };
217
+ throw toError(errorResponse.error);
218
+ }
219
+ return response.data as unknown as { success: boolean };
220
+ },
221
+ onSuccess: () => {
222
+ queryClient.invalidateQueries({ queryKey: ["boards"] });
223
+ },
224
+ });
225
+
226
+ return {
227
+ createBoard: createMutation.mutateAsync,
228
+ updateBoard: (
229
+ id: string,
230
+ data: Parameters<typeof updateMutation.mutateAsync>[0]["data"],
231
+ ) => updateMutation.mutateAsync({ id, data }),
232
+ deleteBoard: deleteMutation.mutateAsync,
233
+ isCreating: createMutation.isPending,
234
+ isUpdating: updateMutation.isPending,
235
+ isDeleting: deleteMutation.isPending,
236
+ createError: createMutation.error,
237
+ updateError: updateMutation.error,
238
+ deleteError: deleteMutation.error,
239
+ };
240
+ }
241
+
242
+ // ============ Column Mutations ============
243
+
244
+ /**
245
+ * Hook for column CRUD mutations
246
+ */
247
+ export function useColumnMutations() {
248
+ const { client, headers } = useKanbanClient();
249
+ const queryClient = useQueryClient();
250
+
251
+ const createMutation = useMutation({
252
+ mutationFn: async (data: {
253
+ title: string;
254
+ boardId: string;
255
+ order?: number;
256
+ }) => {
257
+ const response = await client("@post/columns", {
258
+ method: "POST",
259
+ body: data,
260
+ headers,
261
+ });
262
+ if (isErrorResponse(response)) {
263
+ const errorResponse = response as { error: unknown };
264
+ throw toError(errorResponse.error);
265
+ }
266
+ return response.data as unknown as SerializedColumn;
267
+ },
268
+ onSuccess: () => {
269
+ queryClient.invalidateQueries({ queryKey: ["boards"] });
270
+ },
271
+ });
272
+
273
+ const updateMutation = useMutation({
274
+ mutationFn: async ({
275
+ id,
276
+ data,
277
+ }: {
278
+ id: string;
279
+ data: Partial<{
280
+ title: string;
281
+ order: number;
282
+ }>;
283
+ }) => {
284
+ const response = await client("@put/columns/:id", {
285
+ method: "PUT",
286
+ params: { id },
287
+ body: data,
288
+ headers,
289
+ });
290
+ if (isErrorResponse(response)) {
291
+ const errorResponse = response as { error: unknown };
292
+ throw toError(errorResponse.error);
293
+ }
294
+ return response.data as unknown as SerializedColumn;
295
+ },
296
+ onSuccess: () => {
297
+ queryClient.invalidateQueries({ queryKey: ["boards"] });
298
+ },
299
+ });
300
+
301
+ const deleteMutation = useMutation({
302
+ mutationFn: async (id: string) => {
303
+ const response = await client("@delete/columns/:id", {
304
+ method: "DELETE",
305
+ params: { id },
306
+ headers,
307
+ });
308
+ if (isErrorResponse(response)) {
309
+ const errorResponse = response as { error: unknown };
310
+ throw toError(errorResponse.error);
311
+ }
312
+ return response.data as unknown as { success: boolean };
313
+ },
314
+ onSuccess: () => {
315
+ queryClient.invalidateQueries({ queryKey: ["boards"] });
316
+ },
317
+ });
318
+
319
+ const reorderMutation = useMutation({
320
+ mutationFn: async ({
321
+ boardId,
322
+ columnIds,
323
+ }: {
324
+ boardId: string;
325
+ columnIds: string[];
326
+ }) => {
327
+ const response = await client("@post/columns/reorder", {
328
+ method: "POST",
329
+ body: { boardId, columnIds },
330
+ headers,
331
+ });
332
+ if (isErrorResponse(response)) {
333
+ const errorResponse = response as { error: unknown };
334
+ throw toError(errorResponse.error);
335
+ }
336
+ return response.data as unknown as { success: boolean };
337
+ },
338
+ onSuccess: () => {
339
+ queryClient.invalidateQueries({ queryKey: ["boards"] });
340
+ },
341
+ });
342
+
343
+ return {
344
+ createColumn: createMutation.mutateAsync,
345
+ updateColumn: (
346
+ id: string,
347
+ data: Parameters<typeof updateMutation.mutateAsync>[0]["data"],
348
+ ) => updateMutation.mutateAsync({ id, data }),
349
+ deleteColumn: deleteMutation.mutateAsync,
350
+ reorderColumns: (boardId: string, columnIds: string[]) =>
351
+ reorderMutation.mutateAsync({ boardId, columnIds }),
352
+ isCreating: createMutation.isPending,
353
+ isUpdating: updateMutation.isPending,
354
+ isDeleting: deleteMutation.isPending,
355
+ isReordering: reorderMutation.isPending,
356
+ createError: createMutation.error,
357
+ updateError: updateMutation.error,
358
+ deleteError: deleteMutation.error,
359
+ reorderError: reorderMutation.error,
360
+ };
361
+ }
362
+
363
+ // ============ Task Mutations ============
364
+
365
+ /**
366
+ * Hook for task CRUD mutations
367
+ */
368
+ export function useTaskMutations() {
369
+ const { client, headers } = useKanbanClient();
370
+ const queryClient = useQueryClient();
371
+
372
+ const createMutation = useMutation({
373
+ mutationFn: async (data: {
374
+ title: string;
375
+ description?: string;
376
+ priority?: Priority;
377
+ columnId: string;
378
+ assigneeId?: string;
379
+ order?: number;
380
+ }) => {
381
+ const response = await client("@post/tasks", {
382
+ method: "POST",
383
+ body: data,
384
+ headers,
385
+ });
386
+ if (isErrorResponse(response)) {
387
+ const errorResponse = response as { error: unknown };
388
+ throw toError(errorResponse.error);
389
+ }
390
+ return response.data as unknown as SerializedTask;
391
+ },
392
+ onSuccess: () => {
393
+ queryClient.invalidateQueries({ queryKey: ["boards"] });
394
+ },
395
+ });
396
+
397
+ const updateMutation = useMutation({
398
+ mutationFn: async ({
399
+ id,
400
+ data,
401
+ }: {
402
+ id: string;
403
+ data: Partial<{
404
+ title: string;
405
+ description: string;
406
+ priority: Priority;
407
+ columnId: string;
408
+ assigneeId: string | null;
409
+ order: number;
410
+ isArchived: boolean;
411
+ }>;
412
+ }) => {
413
+ const response = await client("@put/tasks/:id", {
414
+ method: "PUT",
415
+ params: { id },
416
+ body: data,
417
+ headers,
418
+ });
419
+ if (isErrorResponse(response)) {
420
+ const errorResponse = response as { error: unknown };
421
+ throw toError(errorResponse.error);
422
+ }
423
+ return response.data as unknown as SerializedTask;
424
+ },
425
+ onSuccess: () => {
426
+ queryClient.invalidateQueries({ queryKey: ["boards"] });
427
+ },
428
+ });
429
+
430
+ const deleteMutation = useMutation({
431
+ mutationFn: async (id: string) => {
432
+ const response = await client("@delete/tasks/:id", {
433
+ method: "DELETE",
434
+ params: { id },
435
+ headers,
436
+ });
437
+ if (isErrorResponse(response)) {
438
+ const errorResponse = response as { error: unknown };
439
+ throw toError(errorResponse.error);
440
+ }
441
+ return response.data as unknown as { success: boolean };
442
+ },
443
+ onSuccess: () => {
444
+ queryClient.invalidateQueries({ queryKey: ["boards"] });
445
+ },
446
+ });
447
+
448
+ const moveMutation = useMutation({
449
+ mutationFn: async ({
450
+ taskId,
451
+ targetColumnId,
452
+ targetOrder,
453
+ }: {
454
+ taskId: string;
455
+ targetColumnId: string;
456
+ targetOrder: number;
457
+ }) => {
458
+ const response = await client("@post/tasks/move", {
459
+ method: "POST",
460
+ body: { taskId, targetColumnId, targetOrder },
461
+ headers,
462
+ });
463
+ if (isErrorResponse(response)) {
464
+ const errorResponse = response as { error: unknown };
465
+ throw toError(errorResponse.error);
466
+ }
467
+ return response.data as unknown as SerializedTask;
468
+ },
469
+ onSuccess: () => {
470
+ queryClient.invalidateQueries({ queryKey: ["boards"] });
471
+ },
472
+ });
473
+
474
+ const reorderMutation = useMutation({
475
+ mutationFn: async ({
476
+ columnId,
477
+ taskIds,
478
+ }: {
479
+ columnId: string;
480
+ taskIds: string[];
481
+ }) => {
482
+ const response = await client("@post/tasks/reorder", {
483
+ method: "POST",
484
+ body: { columnId, taskIds },
485
+ headers,
486
+ });
487
+ if (isErrorResponse(response)) {
488
+ const errorResponse = response as { error: unknown };
489
+ throw toError(errorResponse.error);
490
+ }
491
+ return response.data as unknown as { success: boolean };
492
+ },
493
+ onSuccess: () => {
494
+ queryClient.invalidateQueries({ queryKey: ["boards"] });
495
+ },
496
+ });
497
+
498
+ return {
499
+ createTask: createMutation.mutateAsync,
500
+ updateTask: (
501
+ id: string,
502
+ data: Parameters<typeof updateMutation.mutateAsync>[0]["data"],
503
+ ) => updateMutation.mutateAsync({ id, data }),
504
+ deleteTask: deleteMutation.mutateAsync,
505
+ moveTask: (taskId: string, targetColumnId: string, targetOrder: number) =>
506
+ moveMutation.mutateAsync({ taskId, targetColumnId, targetOrder }),
507
+ reorderTasks: (columnId: string, taskIds: string[]) =>
508
+ reorderMutation.mutateAsync({ columnId, taskIds }),
509
+ isCreating: createMutation.isPending,
510
+ isUpdating: updateMutation.isPending,
511
+ isDeleting: deleteMutation.isPending,
512
+ isMoving: moveMutation.isPending,
513
+ isReordering: reorderMutation.isPending,
514
+ createError: createMutation.error,
515
+ updateError: updateMutation.error,
516
+ deleteError: deleteMutation.error,
517
+ moveError: moveMutation.error,
518
+ reorderError: reorderMutation.error,
519
+ };
520
+ }
521
+
522
+ // ============ User Resolution Hooks ============
523
+
524
+ /**
525
+ * Hook to resolve a user from their ID
526
+ * Caches results to avoid repeated lookups
527
+ */
528
+ export function useResolveUser(userId: string | undefined | null) {
529
+ const { resolveUser } = usePluginOverrides<KanbanPluginOverrides>("kanban");
530
+
531
+ return useQuery<KanbanUser | null>({
532
+ queryKey: ["kanban", "users", userId],
533
+ queryFn: async () => {
534
+ if (!userId) return null;
535
+ const result = await resolveUser(userId);
536
+ return result;
537
+ },
538
+ enabled: !!userId,
539
+ staleTime: 5 * 60 * 1000, // Cache user info for 5 minutes
540
+ gcTime: 10 * 60 * 1000, // Keep in cache for 10 minutes
541
+ });
542
+ }
543
+
544
+ /**
545
+ * Hook to search for users available for assignment
546
+ * @param query - Search query (empty string for all users)
547
+ * @param boardId - Optional board context for scoped user lists
548
+ */
549
+ export function useSearchUsers(query: string, boardId?: string) {
550
+ const { searchUsers } = usePluginOverrides<KanbanPluginOverrides>("kanban");
551
+
552
+ return useQuery<KanbanUser[]>({
553
+ queryKey: ["kanban", "users", "search", query, boardId],
554
+ queryFn: async () => {
555
+ const result = await searchUsers(query, boardId);
556
+ return result;
557
+ },
558
+ staleTime: 30_000, // Cache search results for 30 seconds
559
+ });
560
+ }
@@ -0,0 +1,8 @@
1
+ export {
2
+ kanbanClientPlugin,
3
+ type KanbanClientConfig,
4
+ type KanbanClientHooks,
5
+ type RouteContext,
6
+ type LoaderContext,
7
+ } from "./plugin";
8
+ export { type KanbanPluginOverrides, type KanbanUser } from "./overrides";
@@ -0,0 +1,28 @@
1
+ import {
2
+ type KanbanCommonLocalization,
3
+ defaultKanbanCommonLocalization,
4
+ } from "./kanban-common";
5
+ import {
6
+ type KanbanFormsLocalization,
7
+ defaultKanbanFormsLocalization,
8
+ } from "./kanban-forms";
9
+ import {
10
+ type KanbanListLocalization,
11
+ defaultKanbanListLocalization,
12
+ } from "./kanban-list";
13
+
14
+ export type KanbanLocalization = Partial<
15
+ KanbanCommonLocalization & KanbanFormsLocalization & KanbanListLocalization
16
+ >;
17
+
18
+ export const defaultKanbanLocalization: Required<KanbanLocalization> = {
19
+ ...defaultKanbanCommonLocalization,
20
+ ...defaultKanbanFormsLocalization,
21
+ ...defaultKanbanListLocalization,
22
+ };
23
+
24
+ export type {
25
+ KanbanCommonLocalization,
26
+ KanbanFormsLocalization,
27
+ KanbanListLocalization,
28
+ };
@@ -0,0 +1,69 @@
1
+ export interface KanbanCommonLocalization {
2
+ // Navigation
3
+ backToBoards: string;
4
+ // Actions
5
+ actions: string;
6
+ create: string;
7
+ edit: string;
8
+ delete: string;
9
+ cancel: string;
10
+ save: string;
11
+ // Status
12
+ loading: string;
13
+ saving: string;
14
+ deleting: string;
15
+ // Labels
16
+ board: string;
17
+ boards: string;
18
+ column: string;
19
+ columns: string;
20
+ task: string;
21
+ tasks: string;
22
+ // Priorities
23
+ priorityLow: string;
24
+ priorityMedium: string;
25
+ priorityHigh: string;
26
+ priorityUrgent: string;
27
+ // Empty states
28
+ noBoards: string;
29
+ noColumns: string;
30
+ noTasks: string;
31
+ // Errors
32
+ errorGeneric: string;
33
+ errorNotFound: string;
34
+ }
35
+
36
+ export const defaultKanbanCommonLocalization: KanbanCommonLocalization = {
37
+ // Navigation
38
+ backToBoards: "Back to Boards",
39
+ // Actions
40
+ actions: "Actions",
41
+ create: "Create",
42
+ edit: "Edit",
43
+ delete: "Delete",
44
+ cancel: "Cancel",
45
+ save: "Save",
46
+ // Status
47
+ loading: "Loading...",
48
+ saving: "Saving...",
49
+ deleting: "Deleting...",
50
+ // Labels
51
+ board: "Board",
52
+ boards: "Boards",
53
+ column: "Column",
54
+ columns: "Columns",
55
+ task: "Task",
56
+ tasks: "Tasks",
57
+ // Priorities
58
+ priorityLow: "Low",
59
+ priorityMedium: "Medium",
60
+ priorityHigh: "High",
61
+ priorityUrgent: "Urgent",
62
+ // Empty states
63
+ noBoards: "No boards yet",
64
+ noColumns: "No columns yet",
65
+ noTasks: "No tasks yet",
66
+ // Errors
67
+ errorGeneric: "Something went wrong",
68
+ errorNotFound: "Not found",
69
+ };