@hiroleague/taskmanager 0.0.1 → 0.0.3

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 (196) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +41 -52
  3. package/dist/assets/architecture-YZFGNWBL-DoE0KxgG.js +1 -0
  4. package/dist/assets/architectureDiagram-Q4EWVU46-DeuBhy7X.js +36 -0
  5. package/dist/assets/{blockDiagram-DXYQGD6D-DfOGNphI.js → blockDiagram-DXYQGD6D-BDBy9ns9.js} +1 -1
  6. package/dist/assets/{c4Diagram-AHTNJAMY-B2Yfcwbo.js → c4Diagram-AHTNJAMY-CpqJj_8a.js} +1 -1
  7. package/dist/assets/channel-PHRyjspt.js +1 -0
  8. package/dist/assets/{chunk-2KRD3SAO-9yt00aGC.js → chunk-2KRD3SAO-DEpUsxdZ.js} +1 -1
  9. package/dist/assets/chunk-336JU56O-BGQvSwLk.js +2 -0
  10. package/dist/assets/chunk-426QAEUC-Cl9nQN9c.js +1 -0
  11. package/dist/assets/{chunk-4TB4RGXK-DF8yJBFl.js → chunk-4TB4RGXK-Dq7aiIrZ.js} +2 -2
  12. package/dist/assets/{chunk-5FUZZQ4R-XEga0hMC.js → chunk-5FUZZQ4R-B_HuuUjf.js} +1 -1
  13. package/dist/assets/{chunk-5PVQY5BW-BrmXs2Gs.js → chunk-5PVQY5BW-cGfZCZGU.js} +2 -2
  14. package/dist/assets/{chunk-67CJDMHE-5wFKo04G.js → chunk-67CJDMHE-BMYAVZfw.js} +1 -1
  15. package/dist/assets/{chunk-7N4EOEYR-BRRGX_NC.js → chunk-7N4EOEYR-Ct-EY7Nc.js} +1 -1
  16. package/dist/assets/{chunk-AA7GKIK3-DUZv_pNI.js → chunk-AA7GKIK3-Bd4HFpeo.js} +1 -1
  17. package/dist/assets/{chunk-CIAEETIT-mA5aM_d7.js → chunk-CIAEETIT-CrFUkPMT.js} +1 -1
  18. package/dist/assets/{chunk-EDXVE4YY-DxUqDyxy.js → chunk-EDXVE4YY-DMDyt0NF.js} +1 -1
  19. package/dist/assets/{chunk-ENJZ2VHE-BgZKYo1l.js → chunk-ENJZ2VHE-DrWzOrpd.js} +1 -1
  20. package/dist/assets/{chunk-FOC6F5B3-B-cqGCPC.js → chunk-FOC6F5B3-Bemzq96j.js} +1 -1
  21. package/dist/assets/{chunk-ICPOFSXX-BNR1V8rT.js → chunk-ICPOFSXX-DkUVjrLw.js} +5 -5
  22. package/dist/assets/{chunk-K5T4RW27-BLRDzioh.js → chunk-K5T4RW27-ALKIf000.js} +5 -5
  23. package/dist/assets/{chunk-KGLVRYIC-CTkQSeKy.js → chunk-KGLVRYIC-Bg6HNTZ-.js} +1 -1
  24. package/dist/assets/{chunk-LIHQZDEY-Cf34Nu3J.js → chunk-LIHQZDEY-DeyGongE.js} +1 -1
  25. package/dist/assets/{chunk-ORNJ4GCN-D3uXgbay.js → chunk-ORNJ4GCN-Bx83s1bJ.js} +1 -1
  26. package/dist/assets/{chunk-OYMX7WX6-syQho5jf.js → chunk-OYMX7WX6-BqRUtRpL.js} +1 -1
  27. package/dist/assets/{chunk-U2HBQHQK-DTJPeU7W.js → chunk-U2HBQHQK-DogcerR6.js} +1 -1
  28. package/dist/assets/{chunk-X2U36JSP-CrTnmMqG.js → chunk-X2U36JSP-CwVWdmZV.js} +1 -1
  29. package/dist/assets/chunk-XPW4576I-DQpNCogT.js +32 -0
  30. package/dist/assets/{chunk-YZCP3GAM-9wq0QKUn.js → chunk-YZCP3GAM-crQSbji9.js} +1 -1
  31. package/dist/assets/{chunk-ZZ45TVLE-D3I1kLlo.js → chunk-ZZ45TVLE-Bk1S1YtS.js} +1 -1
  32. package/dist/assets/classDiagram-6PBFFD2Q-B_TabGaU.js +1 -0
  33. package/dist/assets/classDiagram-v2-HSJHXN6E-CGnZkUWw.js +1 -0
  34. package/dist/assets/clone-D4ka472w.js +1 -0
  35. package/dist/assets/{cose-bilkent-S5V4N54A-BygGvZGW.js → cose-bilkent-S5V4N54A-RBTHUit8.js} +1 -1
  36. package/dist/assets/cytoscape.esm-BGJwlmkf.js +321 -0
  37. package/dist/assets/dagre-B32eYLtm.js +1 -0
  38. package/dist/assets/{dagre-KV5264BT-BBqulDtd.js → dagre-KV5264BT-nX7tuXXn.js} +1 -1
  39. package/dist/assets/diagram-5BDNPKRD-DRxMXlQr.js +10 -0
  40. package/dist/assets/diagram-G4DWMVQ6-CoojevGm.js +24 -0
  41. package/dist/assets/diagram-MMDJMWI5-CWtJyfVW.js +43 -0
  42. package/dist/assets/diagram-TYMM5635-CsDJC4Hq.js +24 -0
  43. package/dist/assets/{erDiagram-SMLLAGMA-BN5eJerP.js → erDiagram-SMLLAGMA-Cf7Xtd9A.js} +2 -2
  44. package/dist/assets/{flatten-C5NL-f24.js → flatten-CYX_pHZ7.js} +1 -1
  45. package/dist/assets/{flowDiagram-DWJPFMVM-CbFskc8S.js → flowDiagram-DWJPFMVM-DQaeR16a.js} +3 -3
  46. package/dist/assets/{ganttDiagram-T4ZO3ILL-OCTvbRxF.js → ganttDiagram-T4ZO3ILL-8EIcztcH.js} +1 -1
  47. package/dist/assets/gitGraph-7Q5UKJZL-BH9A1SAZ.js +1 -0
  48. package/dist/assets/{gitGraphDiagram-UUTBAWPF-wpqI2kyI.js → gitGraphDiagram-UUTBAWPF-DO9ODqYw.js} +1 -1
  49. package/dist/assets/graphlib-bPBqlJKT.js +1 -0
  50. package/dist/assets/identity-Me9aart9.js +1 -0
  51. package/dist/assets/index-oKG1C41_.js +273 -0
  52. package/dist/assets/info-OMHHGYJF-BvKR-zWh.js +1 -0
  53. package/dist/assets/infoDiagram-42DDH7IO-pRTXCm5C.js +2 -0
  54. package/dist/assets/isEmpty-Cu0k-j1j.js +1 -0
  55. package/dist/assets/{ishikawaDiagram-UXIWVN3A-Epc23N_0.js → ishikawaDiagram-UXIWVN3A-BP2YE5QI.js} +2 -2
  56. package/dist/assets/{journeyDiagram-VCZTEJTY-BkMxoaPq.js → journeyDiagram-VCZTEJTY-B3l2juoL.js} +1 -1
  57. package/dist/assets/{kanban-definition-6JOO6SKY-C8dW_26n.js → kanban-definition-6JOO6SKY-BpIpEOZZ.js} +4 -4
  58. package/dist/assets/{line-DNzQATGr.js → line-otOkzGl8.js} +1 -1
  59. package/dist/assets/mermaid-parser.core-xWsW24Gq.js +4 -0
  60. package/dist/assets/{mindmap-definition-QFDTVHPH-CvpNtrKT.js → mindmap-definition-QFDTVHPH-B9khyC7X.js} +3 -3
  61. package/dist/assets/packet-4T2RLAQJ-D8Dw3nmf.js +1 -0
  62. package/dist/assets/pie-ZZUOXDRM-ZghowlAE.js +1 -0
  63. package/dist/assets/{pieDiagram-DEJITSTG-eENymoXZ.js → pieDiagram-DEJITSTG-v32hL3i7.js} +1 -1
  64. package/dist/assets/{quadrantDiagram-34T5L4WZ-c0iZxo2I.js → quadrantDiagram-34T5L4WZ-DIL3GDFt.js} +1 -1
  65. package/dist/assets/radar-PYXPWWZC-D-PK3JOd.js +1 -0
  66. package/dist/assets/reduce-CImcgAcU.js +1 -0
  67. package/dist/assets/{requirementDiagram-MS252O5E-CmRO3hLp.js → requirementDiagram-MS252O5E-D8os2-4y.js} +2 -2
  68. package/dist/assets/{sankeyDiagram-XADWPNL6-woJZoQ58.js → sankeyDiagram-XADWPNL6-BV70D4l5.js} +1 -1
  69. package/dist/assets/{sequenceDiagram-FGHM5R23-B7qNcwNo.js → sequenceDiagram-FGHM5R23-Cwu8hQW1.js} +1 -1
  70. package/dist/assets/stateDiagram-FHFEXIEX-oYUWv7Fb.js +1 -0
  71. package/dist/assets/stateDiagram-v2-QKLJ7IA2-CFUTpFu-.js +1 -0
  72. package/dist/assets/{timeline-definition-GMOUNBTQ-CQWqDPGG.js → timeline-definition-GMOUNBTQ-CxSdKxpL.js} +1 -1
  73. package/dist/assets/treeView-SZITEDCU-uVgaJQzG.js +1 -0
  74. package/dist/assets/treemap-W4RFUUIX-Dcad_9AN.js +1 -0
  75. package/dist/assets/vennDiagram-DHZGUBPP-D4wgD7QI.js +34 -0
  76. package/dist/assets/wardley-RL74JXVD-CFXrK8mx.js +1 -0
  77. package/dist/assets/{wardleyDiagram-NUSXRM2D-DNhPIFCg.js → wardleyDiagram-NUSXRM2D-5Q201ea3.js} +1 -1
  78. package/dist/assets/{xychartDiagram-5P7HB3ND-BDblAZ11.js → xychartDiagram-5P7HB3ND-BPZv_axd.js} +3 -3
  79. package/dist/index.html +16 -12
  80. package/package.json +99 -92
  81. package/scripts/stubs/node-domexception/index.cjs +18 -0
  82. package/scripts/stubs/node-domexception/package.json +7 -0
  83. package/skills/hiro-task-manager-cli/SKILL.md +97 -0
  84. package/skills/hiro-task-manager-cli/reference/boards.md +143 -0
  85. package/skills/hiro-task-manager-cli/reference/cli-access-policy.md +72 -0
  86. package/skills/hiro-task-manager-cli/reference/errors.md +85 -0
  87. package/skills/hiro-task-manager-cli/reference/lists.md +106 -0
  88. package/skills/hiro-task-manager-cli/reference/releases.md +87 -0
  89. package/skills/hiro-task-manager-cli/reference/search.md +38 -0
  90. package/skills/hiro-task-manager-cli/reference/statuses.md +25 -0
  91. package/skills/hiro-task-manager-cli/reference/tasks.md +144 -0
  92. package/skills/hiro-task-manager-cli/reference/trash.md +50 -0
  93. package/src/cli/bootstrap/launcher.test.ts +66 -0
  94. package/src/cli/bootstrap/launcher.ts +389 -35
  95. package/src/cli/bootstrap/program.test.ts +46 -0
  96. package/src/cli/bootstrap/program.ts +54 -1
  97. package/src/cli/bootstrap/runtime.test.ts +15 -0
  98. package/src/cli/bootstrap/runtime.ts +27 -1
  99. package/src/cli/commands/query.ts +56 -56
  100. package/src/cli/commands/server.ts +27 -19
  101. package/src/cli/handlers/boards.test.ts +669 -669
  102. package/src/cli/handlers/cli-wiring.test.ts +1 -1
  103. package/src/cli/handlers/search.test.ts +374 -374
  104. package/src/cli/handlers/search.ts +17 -17
  105. package/src/cli/handlers/server.test.ts +55 -13
  106. package/src/cli/handlers/server.ts +16 -3
  107. package/src/cli/lib/api-client.test.ts +35 -2
  108. package/src/cli/lib/api-client.ts +43 -10
  109. package/src/cli/lib/cli-http-errors.test.ts +85 -85
  110. package/src/cli/lib/command-helpers.ts +161 -154
  111. package/src/cli/lib/config.ts +4 -0
  112. package/src/cli/lib/launcherUi.test.ts +74 -0
  113. package/src/cli/lib/launcherUi.ts +213 -0
  114. package/src/cli/lib/process.test.ts +24 -5
  115. package/src/cli/lib/process.ts +86 -55
  116. package/src/cli/ports/process.ts +8 -2
  117. package/src/cli/subprocess.real-stack.test.ts +611 -598
  118. package/src/cli/subprocess.smoke.test.ts +954 -969
  119. package/src/cli/types/config.ts +2 -6
  120. package/src/client/components/auth/AuthScreen.tsx +3 -3
  121. package/src/client/components/board/BoardStatsChips.tsx +233 -233
  122. package/src/client/components/board/BoardStatsContext.tsx +41 -41
  123. package/src/client/components/board/boardHeaderButtonStyles.ts +38 -38
  124. package/src/client/components/board/shortcuts/useBoardShortcutKeydown.ts +49 -49
  125. package/src/client/components/board/useBoardCanvasPanScroll.ts +108 -108
  126. package/src/client/components/board/useBoardTaskContainerDroppableReact.ts +33 -33
  127. package/src/client/components/board/useBoardTaskSortableReact.ts +26 -26
  128. package/src/client/components/multi-select.tsx +1206 -1206
  129. package/src/client/components/routing/BoardPage.tsx +20 -20
  130. package/src/client/components/routing/NavigationRegistrar.tsx +13 -13
  131. package/src/client/components/settings/SettingsPage.tsx +1 -1
  132. package/src/client/components/task/TaskCard.tsx +643 -643
  133. package/src/client/components/ui/badge.tsx +49 -49
  134. package/src/client/components/ui/button.tsx +65 -65
  135. package/src/client/components/ui/command.tsx +193 -193
  136. package/src/client/components/ui/dialog.tsx +163 -163
  137. package/src/client/components/ui/input-group.tsx +155 -155
  138. package/src/client/components/ui/input.tsx +19 -19
  139. package/src/client/components/ui/popover.tsx +87 -87
  140. package/src/client/components/ui/separator.tsx +28 -28
  141. package/src/client/components/ui/textarea.tsx +18 -18
  142. package/src/client/index.css +248 -248
  143. package/src/client/lib/appNavigate.ts +16 -16
  144. package/src/client/lib/taskCardDate.ts +111 -111
  145. package/src/client/lib/utils.ts +6 -6
  146. package/src/server/auth.ts +351 -302
  147. package/src/server/bootstrapDev.ts +11 -2
  148. package/src/server/bootstrapInstalled.ts +6 -1
  149. package/src/server/index.ts +33 -7
  150. package/src/server/migrations/013_cli_policy_and_provenance.ts +2 -2
  151. package/src/server/migrations/019_cli_global_create_board_default_on.ts +14 -0
  152. package/src/server/migrations/registry.ts +43 -41
  153. package/src/server/parseBootstrapProfile.ts +42 -0
  154. package/src/server/storage/cliPolicy.ts +2 -1
  155. package/src/shared/runtimeConfig.ts +256 -237
  156. package/src/shared/runtimeIdentity.test.ts +47 -0
  157. package/src/shared/runtimeIdentity.ts +35 -0
  158. package/src/shared/serverStatus.ts +21 -0
  159. package/src/shared/skillsInstall.ts +70 -0
  160. package/src/shared/terminalColors.ts +24 -0
  161. package/dist/assets/architecture-YZFGNWBL-3h1eIYfB.js +0 -1
  162. package/dist/assets/architectureDiagram-Q4EWVU46-DSQ1_74_.js +0 -36
  163. package/dist/assets/channel-yBmN_ln0.js +0 -1
  164. package/dist/assets/classDiagram-6PBFFD2Q-CotFZI8-.js +0 -1
  165. package/dist/assets/classDiagram-v2-HSJHXN6E-DAPzeDGn.js +0 -1
  166. package/dist/assets/clone-BRQpYu_n.js +0 -1
  167. package/dist/assets/cytoscape.esm-BIYWHPG0.js +0 -321
  168. package/dist/assets/dagre-rhyPjnsQ.js +0 -1
  169. package/dist/assets/diagram-5BDNPKRD-Ky3EXXj0.js +0 -10
  170. package/dist/assets/diagram-G4DWMVQ6-t7LbT0Uz.js +0 -24
  171. package/dist/assets/diagram-MMDJMWI5-CdnLXEMx.js +0 -43
  172. package/dist/assets/diagram-TYMM5635-CnzTqJBM.js +0 -24
  173. package/dist/assets/gitGraph-7Q5UKJZL-CG8f8JF7.js +0 -1
  174. package/dist/assets/graphlib-COiJG5Qv.js +0 -1
  175. package/dist/assets/identity-D4WOnl_h.js +0 -1
  176. package/dist/assets/index-lyyIVcc_.js +0 -304
  177. package/dist/assets/info-OMHHGYJF-C8_SHoRO.js +0 -1
  178. package/dist/assets/infoDiagram-42DDH7IO-BbvTdpSV.js +0 -2
  179. package/dist/assets/mermaid-parser.core-6Tn8epr_.js +0 -4
  180. package/dist/assets/packet-4T2RLAQJ-BvpAX0kJ.js +0 -1
  181. package/dist/assets/pie-ZZUOXDRM-Ow26Yf-E.js +0 -1
  182. package/dist/assets/radar-PYXPWWZC-e_ron5jQ.js +0 -1
  183. package/dist/assets/reduce-BDOBPIXr.js +0 -1
  184. package/dist/assets/stateDiagram-FHFEXIEX-CYfGMoR8.js +0 -1
  185. package/dist/assets/stateDiagram-v2-QKLJ7IA2-CO1W_n55.js +0 -1
  186. package/dist/assets/treeView-SZITEDCU-DsEr3xeq.js +0 -1
  187. package/dist/assets/treemap-W4RFUUIX-DV7nk2AB.js +0 -1
  188. package/dist/assets/vennDiagram-DHZGUBPP-BjTbuhcb.js +0 -34
  189. package/dist/assets/wardley-RL74JXVD-CrrFU9AE.js +0 -1
  190. /package/dist/assets/{chunk-4BX2VUAB-ean5NKtU.js → chunk-4BX2VUAB-C70mcfQR.js} +0 -0
  191. /package/dist/assets/{chunk-55IACEB6-CvSRyJqy.js → chunk-55IACEB6-CWfnqcLM.js} +0 -0
  192. /package/dist/assets/{chunk-BSJP7CBP-D8kBlJsf.js → chunk-BSJP7CBP-B0LrXV9y.js} +0 -0
  193. /package/dist/assets/{chunk-FMBD7UC4-DrNhFt1N.js → chunk-FMBD7UC4-_mV71Mwu.js} +0 -0
  194. /package/dist/assets/{chunk-QZHKN3VN-Csp3OYJY.js → chunk-QZHKN3VN-t2nrsegL.js} +0 -0
  195. /package/dist/assets/{katex-8mXVa4k3.js → katex-B2dtGfSp.js} +0 -0
  196. /package/dist/assets/{rough.esm-DtEqI08j.js → rough.esm-DEh6Frf9.js} +0 -0
@@ -1,49 +1,49 @@
1
- import { useEffect, useRef } from "react";
2
- import type { Board } from "../../../../shared/models";
3
- import { boardShortcutRegistry } from "./boardShortcutRegistry";
4
- import type { BoardShortcutActions } from "./boardShortcutTypes";
5
- import { isEditableKeyboardTarget } from "./isEditableKeyboardTarget";
6
- import { useShortcutScope } from "./ShortcutScopeContext";
7
-
8
- interface UseBoardShortcutKeydownOptions {
9
- board: Board | null;
10
- actions: BoardShortcutActions;
11
- }
12
-
13
- /**
14
- * Registers the board shortcut dispatcher with {@link ShortcutScopeProvider}.
15
- * The global listener only invokes it when the scope stack is empty (board is active).
16
- */
17
- export function useBoardShortcutKeydown({
18
- board,
19
- actions,
20
- }: UseBoardShortcutKeydownOptions): void {
21
- const { registerBoardKeyHandler } = useShortcutScope();
22
- const actionsRef = useRef(actions);
23
- actionsRef.current = actions;
24
-
25
- useEffect(() => {
26
- if (!board) {
27
- return registerBoardKeyHandler(() => {});
28
- }
29
-
30
- const onKeyDown = (e: KeyboardEvent) => {
31
- if (!board) return;
32
- if (isEditableKeyboardTarget(e.target)) return;
33
- if (e.ctrlKey || e.metaKey || e.altKey) return;
34
- // Shift+Tab keeps native reverse tab order; unmodified Tab establishes board highlight.
35
- if (e.key === "Tab" && e.shiftKey) return;
36
-
37
- for (const def of boardShortcutRegistry) {
38
- if (def.helpOnly) continue;
39
- if (!def.matchKey(e.key)) continue;
40
- if (def.enabled && !def.enabled(board)) continue;
41
- if (def.preventDefault) e.preventDefault();
42
- def.run(board, actionsRef.current);
43
- return;
44
- }
45
- };
46
-
47
- return registerBoardKeyHandler(onKeyDown);
48
- }, [board, registerBoardKeyHandler]);
49
- }
1
+ import { useEffect, useRef } from "react";
2
+ import type { Board } from "../../../../shared/models";
3
+ import { boardShortcutRegistry } from "./boardShortcutRegistry";
4
+ import type { BoardShortcutActions } from "./boardShortcutTypes";
5
+ import { isEditableKeyboardTarget } from "./isEditableKeyboardTarget";
6
+ import { useShortcutScope } from "./ShortcutScopeContext";
7
+
8
+ interface UseBoardShortcutKeydownOptions {
9
+ board: Board | null;
10
+ actions: BoardShortcutActions;
11
+ }
12
+
13
+ /**
14
+ * Registers the board shortcut dispatcher with {@link ShortcutScopeProvider}.
15
+ * The global listener only invokes it when the scope stack is empty (board is active).
16
+ */
17
+ export function useBoardShortcutKeydown({
18
+ board,
19
+ actions,
20
+ }: UseBoardShortcutKeydownOptions): void {
21
+ const { registerBoardKeyHandler } = useShortcutScope();
22
+ const actionsRef = useRef(actions);
23
+ actionsRef.current = actions;
24
+
25
+ useEffect(() => {
26
+ if (!board) {
27
+ return registerBoardKeyHandler(() => {});
28
+ }
29
+
30
+ const onKeyDown = (e: KeyboardEvent) => {
31
+ if (!board) return;
32
+ if (isEditableKeyboardTarget(e.target)) return;
33
+ if (e.ctrlKey || e.metaKey || e.altKey) return;
34
+ // Shift+Tab keeps native reverse tab order; unmodified Tab establishes board highlight.
35
+ if (e.key === "Tab" && e.shiftKey) return;
36
+
37
+ for (const def of boardShortcutRegistry) {
38
+ if (def.helpOnly) continue;
39
+ if (!def.matchKey(e.key)) continue;
40
+ if (def.enabled && !def.enabled(board)) continue;
41
+ if (def.preventDefault) e.preventDefault();
42
+ def.run(board, actionsRef.current);
43
+ return;
44
+ }
45
+ };
46
+
47
+ return registerBoardKeyHandler(onKeyDown);
48
+ }, [board, registerBoardKeyHandler]);
49
+ }
@@ -1,108 +1,108 @@
1
- import { useCallback, useRef, useState } from "react";
2
-
3
- const ACTIVATION_PX = 6;
4
-
5
- /** Selectors for elements that must not start horizontal board pan (columns, chrome, controls). */
6
- const NO_PAN =
7
- "[data-board-no-pan],button,a[href],input,textarea,select,option,label,[role='button'],[contenteditable='true']";
8
-
9
- function targetStartsPan(target: EventTarget | null): boolean {
10
- if (!(target instanceof Element)) return false;
11
- return target.closest(NO_PAN) == null;
12
- }
13
-
14
- type PanMode = "undecided" | "horizontal" | "none";
15
-
16
- export function useBoardCanvasPanScroll() {
17
- const scrollRef = useRef<HTMLDivElement>(null);
18
- const panRef = useRef<{
19
- pointerId: number;
20
- startX: number;
21
- startY: number;
22
- startScrollLeft: number;
23
- mode: PanMode;
24
- } | null>(null);
25
-
26
- const [panning, setPanning] = useState(false);
27
-
28
- const onPointerDown = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
29
- if (e.button !== 0) return;
30
- if (!targetStartsPan(e.target)) return;
31
- const scroller = scrollRef.current;
32
- if (!scroller) return;
33
-
34
- panRef.current = {
35
- pointerId: e.pointerId,
36
- startX: e.clientX,
37
- startY: e.clientY,
38
- startScrollLeft: scroller.scrollLeft,
39
- mode: "undecided",
40
- };
41
- }, []);
42
-
43
- const onPointerMove = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
44
- const pan = panRef.current;
45
- const scroller = scrollRef.current;
46
- if (!pan || !scroller || e.pointerId !== pan.pointerId) return;
47
-
48
- if (pan.mode === "none") return;
49
-
50
- if (pan.mode === "undecided") {
51
- const dx = e.clientX - pan.startX;
52
- const dy = e.clientY - pan.startY;
53
- if (
54
- Math.abs(dx) < ACTIVATION_PX &&
55
- Math.abs(dy) < ACTIVATION_PX
56
- ) {
57
- return;
58
- }
59
- if (Math.abs(dx) >= Math.abs(dy)) {
60
- pan.mode = "horizontal";
61
- try {
62
- scroller.setPointerCapture(e.pointerId);
63
- } catch {
64
- /* already captured or unsupported */
65
- }
66
- e.preventDefault();
67
- setPanning(true);
68
- } else {
69
- pan.mode = "none";
70
- panRef.current = null;
71
- return;
72
- }
73
- }
74
-
75
- if (pan.mode === "horizontal") {
76
- const dx = e.clientX - pan.startX;
77
- scroller.scrollLeft = pan.startScrollLeft - dx;
78
- e.preventDefault();
79
- }
80
- }, []);
81
-
82
- const endPan = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
83
- const pan = panRef.current;
84
- const scroller = scrollRef.current;
85
- if (!pan || e.pointerId !== pan.pointerId) return;
86
-
87
- if (pan.mode === "horizontal" && scroller) {
88
- try {
89
- scroller.releasePointerCapture(e.pointerId);
90
- } catch {
91
- /* not captured */
92
- }
93
- setPanning(false);
94
- }
95
- panRef.current = null;
96
- }, []);
97
-
98
- return {
99
- scrollRef,
100
- panning,
101
- boardCanvasPanHandlers: {
102
- onPointerDown,
103
- onPointerMove,
104
- onPointerUp: endPan,
105
- onPointerCancel: endPan,
106
- },
107
- };
108
- }
1
+ import { useCallback, useRef, useState } from "react";
2
+
3
+ const ACTIVATION_PX = 6;
4
+
5
+ /** Selectors for elements that must not start horizontal board pan (columns, chrome, controls). */
6
+ const NO_PAN =
7
+ "[data-board-no-pan],button,a[href],input,textarea,select,option,label,[role='button'],[contenteditable='true']";
8
+
9
+ function targetStartsPan(target: EventTarget | null): boolean {
10
+ if (!(target instanceof Element)) return false;
11
+ return target.closest(NO_PAN) == null;
12
+ }
13
+
14
+ type PanMode = "undecided" | "horizontal" | "none";
15
+
16
+ export function useBoardCanvasPanScroll() {
17
+ const scrollRef = useRef<HTMLDivElement>(null);
18
+ const panRef = useRef<{
19
+ pointerId: number;
20
+ startX: number;
21
+ startY: number;
22
+ startScrollLeft: number;
23
+ mode: PanMode;
24
+ } | null>(null);
25
+
26
+ const [panning, setPanning] = useState(false);
27
+
28
+ const onPointerDown = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
29
+ if (e.button !== 0) return;
30
+ if (!targetStartsPan(e.target)) return;
31
+ const scroller = scrollRef.current;
32
+ if (!scroller) return;
33
+
34
+ panRef.current = {
35
+ pointerId: e.pointerId,
36
+ startX: e.clientX,
37
+ startY: e.clientY,
38
+ startScrollLeft: scroller.scrollLeft,
39
+ mode: "undecided",
40
+ };
41
+ }, []);
42
+
43
+ const onPointerMove = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
44
+ const pan = panRef.current;
45
+ const scroller = scrollRef.current;
46
+ if (!pan || !scroller || e.pointerId !== pan.pointerId) return;
47
+
48
+ if (pan.mode === "none") return;
49
+
50
+ if (pan.mode === "undecided") {
51
+ const dx = e.clientX - pan.startX;
52
+ const dy = e.clientY - pan.startY;
53
+ if (
54
+ Math.abs(dx) < ACTIVATION_PX &&
55
+ Math.abs(dy) < ACTIVATION_PX
56
+ ) {
57
+ return;
58
+ }
59
+ if (Math.abs(dx) >= Math.abs(dy)) {
60
+ pan.mode = "horizontal";
61
+ try {
62
+ scroller.setPointerCapture(e.pointerId);
63
+ } catch {
64
+ /* already captured or unsupported */
65
+ }
66
+ e.preventDefault();
67
+ setPanning(true);
68
+ } else {
69
+ pan.mode = "none";
70
+ panRef.current = null;
71
+ return;
72
+ }
73
+ }
74
+
75
+ if (pan.mode === "horizontal") {
76
+ const dx = e.clientX - pan.startX;
77
+ scroller.scrollLeft = pan.startScrollLeft - dx;
78
+ e.preventDefault();
79
+ }
80
+ }, []);
81
+
82
+ const endPan = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
83
+ const pan = panRef.current;
84
+ const scroller = scrollRef.current;
85
+ if (!pan || e.pointerId !== pan.pointerId) return;
86
+
87
+ if (pan.mode === "horizontal" && scroller) {
88
+ try {
89
+ scroller.releasePointerCapture(e.pointerId);
90
+ } catch {
91
+ /* not captured */
92
+ }
93
+ setPanning(false);
94
+ }
95
+ panRef.current = null;
96
+ }, []);
97
+
98
+ return {
99
+ scrollRef,
100
+ panning,
101
+ boardCanvasPanHandlers: {
102
+ onPointerDown,
103
+ onPointerMove,
104
+ onPointerUp: endPan,
105
+ onPointerCancel: endPan,
106
+ },
107
+ };
108
+ }
@@ -1,33 +1,33 @@
1
- import { CollisionPriority } from "@dnd-kit/abstract";
2
- import { useDroppable } from "@dnd-kit/react";
3
- import {
4
- BOARD_TASK_CONTAINER_DND_TYPE,
5
- BOARD_TASK_DND_TYPE,
6
- type BoardDndLayout,
7
- boardTaskContainerData,
8
- } from "./dndReactModel";
9
-
10
- /**
11
- * Phase 1 React-first wrapper for task drop containers.
12
- * This encodes the board's container metadata once so stacked lists and lane
13
- * bands can share the same droppable configuration in later phases.
14
- */
15
- export function useBoardTaskContainerDroppableReact({
16
- containerId,
17
- layout,
18
- listId,
19
- status,
20
- }: {
21
- containerId: string;
22
- layout: BoardDndLayout;
23
- listId: number;
24
- status?: string;
25
- }) {
26
- return useDroppable({
27
- id: containerId,
28
- type: BOARD_TASK_CONTAINER_DND_TYPE,
29
- accept: BOARD_TASK_DND_TYPE,
30
- collisionPriority: CollisionPriority.Low,
31
- data: boardTaskContainerData(containerId, layout, listId, status),
32
- });
33
- }
1
+ import { CollisionPriority } from "@dnd-kit/abstract";
2
+ import { useDroppable } from "@dnd-kit/react";
3
+ import {
4
+ BOARD_TASK_CONTAINER_DND_TYPE,
5
+ BOARD_TASK_DND_TYPE,
6
+ type BoardDndLayout,
7
+ boardTaskContainerData,
8
+ } from "./dndReactModel";
9
+
10
+ /**
11
+ * Phase 1 React-first wrapper for task drop containers.
12
+ * This encodes the board's container metadata once so stacked lists and lane
13
+ * bands can share the same droppable configuration in later phases.
14
+ */
15
+ export function useBoardTaskContainerDroppableReact({
16
+ containerId,
17
+ layout,
18
+ listId,
19
+ status,
20
+ }: {
21
+ containerId: string;
22
+ layout: BoardDndLayout;
23
+ listId: number;
24
+ status?: string;
25
+ }) {
26
+ return useDroppable({
27
+ id: containerId,
28
+ type: BOARD_TASK_CONTAINER_DND_TYPE,
29
+ accept: BOARD_TASK_DND_TYPE,
30
+ collisionPriority: CollisionPriority.Low,
31
+ data: boardTaskContainerData(containerId, layout, listId, status),
32
+ });
33
+ }
@@ -1,26 +1,26 @@
1
- import { useSortable } from "@dnd-kit/react/sortable";
2
- import { BOARD_TASK_DND_TYPE, boardTaskDragData } from "./dndReactModel";
3
-
4
- /**
5
- * Phase 1 React-first wrapper for sortable task rows.
6
- * Group and index are explicit so grouped multi-list movement can follow the
7
- * official multiple-sortable-lists approach during later phases.
8
- */
9
- export function useBoardTaskSortableReact(
10
- taskId: number,
11
- sortableId: string,
12
- containerId: string,
13
- index: number,
14
- ) {
15
- return useSortable({
16
- id: sortableId,
17
- index,
18
- group: containerId,
19
- type: BOARD_TASK_DND_TYPE,
20
- accept: BOARD_TASK_DND_TYPE,
21
- // Mirror the working board-list route so task drags use the same
22
- // React-first feedback clone behavior as columns.
23
- feedback: "clone",
24
- data: boardTaskDragData(taskId, containerId),
25
- });
26
- }
1
+ import { useSortable } from "@dnd-kit/react/sortable";
2
+ import { BOARD_TASK_DND_TYPE, boardTaskDragData } from "./dndReactModel";
3
+
4
+ /**
5
+ * Phase 1 React-first wrapper for sortable task rows.
6
+ * Group and index are explicit so grouped multi-list movement can follow the
7
+ * official multiple-sortable-lists approach during later phases.
8
+ */
9
+ export function useBoardTaskSortableReact(
10
+ taskId: number,
11
+ sortableId: string,
12
+ containerId: string,
13
+ index: number,
14
+ ) {
15
+ return useSortable({
16
+ id: sortableId,
17
+ index,
18
+ group: containerId,
19
+ type: BOARD_TASK_DND_TYPE,
20
+ accept: BOARD_TASK_DND_TYPE,
21
+ // Mirror the working board-list route so task drags use the same
22
+ // React-first feedback clone behavior as columns.
23
+ feedback: "clone",
24
+ data: boardTaskDragData(taskId, containerId),
25
+ });
26
+ }