@svgrid/enterprise 2.5.3 → 2.6.1

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 (624) hide show
  1. package/dist/SvAlertRuleEditor.svelte.d.ts +13 -0
  2. package/dist/SvAlertsManager.svelte.d.ts +14 -0
  3. package/dist/SvAlertsPanel.svelte.d.ts +9 -0
  4. package/dist/SvAuthGate.svelte.d.ts +22 -0
  5. package/dist/SvBoard.svelte.d.ts +35 -0
  6. package/dist/SvExportMenu.svelte.d.ts +61 -0
  7. package/{src → dist}/SvExpressionEditor.svelte +4 -1
  8. package/dist/SvExpressionEditor.svelte.d.ts +12 -0
  9. package/dist/SvFileInput.svelte.d.ts +20 -0
  10. package/dist/SvGridAlerts.svelte.d.ts +77 -0
  11. package/dist/SvGridBoard.svelte.d.ts +30 -0
  12. package/{src → dist}/SvGridEditPanel.svelte +173 -28
  13. package/dist/SvGridEditPanel.svelte.d.ts +75 -0
  14. package/dist/SvGridMasterDetail.svelte.d.ts +49 -0
  15. package/dist/SvGridScheduler.svelte.d.ts +30 -0
  16. package/dist/SvImportDialog.svelte.d.ts +88 -0
  17. package/dist/SvLookupInput.svelte.d.ts +21 -0
  18. package/dist/SvPivotDesigner.svelte.d.ts +176 -0
  19. package/dist/SvRecordDetail.svelte.d.ts +58 -0
  20. package/dist/SvSchedule.svelte.d.ts +29 -0
  21. package/dist/SvSchemaChart.svelte.d.ts +61 -0
  22. package/dist/SvSchemaDashboard.svelte.d.ts +46 -0
  23. package/dist/alerts/alert-engine-attach.d.ts +79 -0
  24. package/dist/alerts/alert-engine-attach.js +106 -0
  25. package/dist/alerts/alert-engine.d.ts +42 -0
  26. package/dist/alerts/alert-engine.js +196 -0
  27. package/dist/alerts/alert-formats.d.ts +26 -0
  28. package/dist/alerts/alert-formats.js +58 -0
  29. package/dist/alerts/alert-observer.d.ts +54 -0
  30. package/dist/alerts/alert-observer.js +156 -0
  31. package/dist/alerts/alert-scheduler.d.ts +30 -0
  32. package/dist/alerts/alert-scheduler.js +54 -0
  33. package/dist/alerts/alert-storage.d.ts +31 -0
  34. package/dist/alerts/alert-storage.js +92 -0
  35. package/dist/alerts/alert-store.svelte.d.ts +24 -0
  36. package/dist/alerts/alert-store.svelte.js +69 -0
  37. package/dist/alerts/alert-types.d.ts +86 -0
  38. package/dist/alerts/alert-types.js +1 -0
  39. package/dist/alerts.d.ts +2 -0
  40. package/{src/alerts.ts → dist/alerts.js} +9 -9
  41. package/dist/board.d.ts +7 -0
  42. package/{src/board.ts → dist/board.js} +13 -14
  43. package/dist/cdn/svgrid-enterprise.svelte-external.js +3220 -2607
  44. package/dist/designer/assets/index-BfzoL904.css +1 -0
  45. package/dist/designer/assets/{index-CBYU-KNn.js → index-CKdwDseq.js} +139 -139
  46. package/dist/designer/assets/src-DCKhP5Xy.css +1 -0
  47. package/dist/designer/assets/{src-i309BeJb.js → src-DLsSdh3J.js} +213 -193
  48. package/dist/designer/index.html +4 -4
  49. package/dist/edit-panel.d.ts +105 -0
  50. package/dist/edit-panel.js +350 -0
  51. package/dist/export-conditional.d.ts +31 -0
  52. package/dist/export-conditional.js +65 -0
  53. package/dist/export-ooxml.d.ts +93 -0
  54. package/dist/export-ooxml.js +385 -0
  55. package/dist/export-pdf.d.ts +107 -0
  56. package/dist/export-pdf.js +144 -0
  57. package/dist/export-print.d.ts +55 -0
  58. package/dist/export-print.js +91 -0
  59. package/{src/export-serialize.ts → dist/export-serialize.d.ts} +11 -24
  60. package/dist/export-serialize.js +11 -0
  61. package/dist/export-xls.d.ts +26 -0
  62. package/dist/export-xls.js +157 -0
  63. package/dist/export.d.ts +323 -0
  64. package/dist/export.js +1021 -0
  65. package/dist/expressions/evaluate.d.ts +17 -0
  66. package/dist/expressions/evaluate.js +214 -0
  67. package/dist/expressions/expression-columns.d.ts +61 -0
  68. package/dist/expressions/expression-columns.js +72 -0
  69. package/dist/expressions/expression-types.d.ts +125 -0
  70. package/dist/expressions/expression-types.js +1 -0
  71. package/dist/expressions/parse.d.ts +25 -0
  72. package/dist/expressions/parse.js +537 -0
  73. package/dist/import.d.ts +232 -0
  74. package/dist/import.js +846 -0
  75. package/dist/index.d.ts +66 -0
  76. package/dist/index.js +91 -0
  77. package/dist/install.d.ts +70 -0
  78. package/dist/install.js +61 -0
  79. package/dist/license-core.d.ts +37 -0
  80. package/dist/license-core.js +81 -0
  81. package/dist/license.d.ts +30 -0
  82. package/dist/license.js +139 -0
  83. package/dist/master-detail.d.ts +23 -0
  84. package/dist/master-detail.js +35 -0
  85. package/dist/node/studio.js +683 -13
  86. package/dist/pivot-chart.d.ts +28 -0
  87. package/dist/pivot-chart.js +71 -0
  88. package/dist/pivot-designer.d.ts +69 -0
  89. package/dist/pivot-designer.js +38 -0
  90. package/dist/pivot-enable.d.ts +6 -0
  91. package/{src/pivot-enable.ts → dist/pivot-enable.js} +13 -18
  92. package/dist/pivot.d.ts +111 -0
  93. package/dist/pivot.js +353 -0
  94. package/dist/print.d.ts +33 -0
  95. package/dist/print.js +61 -0
  96. package/dist/revoked.d.ts +1 -0
  97. package/{src/revoked.ts → dist/revoked.js} +5 -6
  98. package/dist/scheduler-assignments.d.ts +64 -0
  99. package/dist/scheduler-assignments.js +92 -0
  100. package/dist/scheduler-axis.d.ts +81 -0
  101. package/dist/scheduler-axis.js +180 -0
  102. package/{src/scheduler-booking.ts → dist/scheduler-booking.d.ts} +10 -43
  103. package/dist/scheduler-booking.js +50 -0
  104. package/dist/scheduler-config.d.ts +177 -0
  105. package/dist/scheduler-config.js +1 -0
  106. package/dist/scheduler-dependencies.d.ts +89 -0
  107. package/dist/scheduler-dependencies.js +179 -0
  108. package/dist/scheduler-freebusy.d.ts +19 -0
  109. package/{src/scheduler-freebusy.ts → dist/scheduler-freebusy.js} +9 -19
  110. package/{src/scheduler-heatmap.ts → dist/scheduler-heatmap.d.ts} +12 -35
  111. package/dist/scheduler-heatmap.js +41 -0
  112. package/dist/scheduler-resource-tree.d.ts +48 -0
  113. package/dist/scheduler-resource-tree.js +78 -0
  114. package/dist/scheduler-slots.d.ts +37 -0
  115. package/dist/scheduler-slots.js +80 -0
  116. package/dist/scheduler-summary.d.ts +41 -0
  117. package/dist/scheduler-summary.js +54 -0
  118. package/dist/scheduler.d.ts +7 -0
  119. package/{src/scheduler.ts → dist/scheduler.js} +13 -14
  120. package/dist/scheduling.d.ts +132 -0
  121. package/dist/scheduling.js +228 -0
  122. package/dist/schema-designer.d.ts +42 -0
  123. package/dist/schema-designer.js +117 -0
  124. package/dist/schema.d.ts +408 -0
  125. package/dist/schema.js +225 -0
  126. package/dist/smart-shim.d.ts +62 -0
  127. package/dist/smart-shim.js +34 -0
  128. package/dist/sources/aggregate.d.ts +43 -0
  129. package/dist/sources/aggregate.js +60 -0
  130. package/dist/sources/auth-supabase.d.ts +69 -0
  131. package/dist/sources/auth-supabase.js +39 -0
  132. package/dist/sources/dashboard.d.ts +65 -0
  133. package/dist/sources/dashboard.js +95 -0
  134. package/dist/sources/field-inference.d.ts +23 -0
  135. package/dist/sources/field-inference.js +52 -0
  136. package/dist/sources/filters.d.ts +35 -0
  137. package/dist/sources/filters.js +52 -0
  138. package/dist/sources/index.d.ts +18 -0
  139. package/dist/sources/index.js +18 -0
  140. package/dist/sources/introspect-supabase.d.ts +30 -0
  141. package/dist/sources/introspect-supabase.js +134 -0
  142. package/dist/sources/realtime-supabase.d.ts +37 -0
  143. package/dist/sources/realtime-supabase.js +52 -0
  144. package/dist/sources/relation-lookup.d.ts +50 -0
  145. package/dist/sources/relation-lookup.js +77 -0
  146. package/dist/sources/rest-adapters.d.ts +48 -0
  147. package/dist/sources/rest-adapters.js +85 -0
  148. package/dist/sources/rest.d.ts +38 -0
  149. package/dist/sources/rest.js +86 -0
  150. package/dist/sources/schema-from-columns.d.ts +37 -0
  151. package/dist/sources/schema-from-columns.js +48 -0
  152. package/dist/sources/supabase.d.ts +33 -0
  153. package/dist/sources/supabase.js +74 -0
  154. package/dist/sources/with-entity-rules.d.ts +25 -0
  155. package/dist/sources/with-entity-rules.js +47 -0
  156. package/dist/sources/with-relation-labels.d.ts +26 -0
  157. package/dist/sources/with-relation-labels.js +38 -0
  158. package/dist/staged-editing.d.ts +85 -0
  159. package/dist/staged-editing.js +0 -0
  160. package/dist/studio/bug-report.d.ts +61 -0
  161. package/dist/studio/bug-report.js +126 -0
  162. package/dist/studio/cli.d.ts +56 -0
  163. package/dist/studio/cli.js +70 -0
  164. package/dist/studio/copilot-core.d.ts +22 -0
  165. package/{src/studio/copilot-core.ts → dist/studio/copilot-core.js} +34 -38
  166. package/dist/studio/csv.d.ts +36 -0
  167. package/dist/studio/csv.js +173 -0
  168. package/dist/studio/db-connect-string.d.ts +45 -0
  169. package/dist/studio/db-connect-string.js +113 -0
  170. package/dist/studio/deploy-cli.d.ts +35 -0
  171. package/dist/studio/deploy-cli.js +81 -0
  172. package/dist/studio/emit-project.d.ts +77 -0
  173. package/dist/studio/emit-project.js +5463 -0
  174. package/dist/studio/emit-schema.d.ts +110 -0
  175. package/dist/studio/emit-schema.js +1128 -0
  176. package/dist/studio/index.d.ts +35 -0
  177. package/dist/studio/index.js +41 -0
  178. package/dist/studio/init-flow.d.ts +58 -0
  179. package/dist/studio/init-flow.js +451 -0
  180. package/dist/studio/introspect-db.d.ts +47 -0
  181. package/dist/studio/introspect-db.js +255 -0
  182. package/dist/studio/introspect-openapi.d.ts +19 -0
  183. package/dist/studio/introspect-openapi.js +244 -0
  184. package/dist/studio/introspect-prisma.d.ts +25 -0
  185. package/dist/studio/introspect-prisma.js +164 -0
  186. package/dist/studio/introspect.d.ts +35 -0
  187. package/dist/studio/introspect.js +306 -0
  188. package/dist/studio/project.d.ts +1448 -0
  189. package/dist/studio/project.js +2187 -0
  190. package/dist/studio/sample-data.d.ts +19 -0
  191. package/dist/studio/sample-data.js +207 -0
  192. package/dist/studio/samples/ats.d.ts +2 -0
  193. package/dist/studio/samples/ats.js +194 -0
  194. package/dist/studio/samples/clinic.d.ts +2 -0
  195. package/dist/studio/samples/clinic.js +171 -0
  196. package/dist/studio/samples/crm.d.ts +2 -0
  197. package/dist/studio/samples/crm.js +280 -0
  198. package/dist/studio/samples/datasets.d.ts +38 -0
  199. package/dist/studio/samples/datasets.js +296 -0
  200. package/dist/studio/samples/ecommerce.d.ts +2 -0
  201. package/dist/studio/samples/ecommerce.js +178 -0
  202. package/dist/studio/samples/events.d.ts +2 -0
  203. package/dist/studio/samples/events.js +192 -0
  204. package/dist/studio/samples/fleet.d.ts +2 -0
  205. package/dist/studio/samples/fleet.js +203 -0
  206. package/dist/studio/samples/gym.d.ts +2 -0
  207. package/dist/studio/samples/gym.js +205 -0
  208. package/dist/studio/samples/hr.d.ts +2 -0
  209. package/dist/studio/samples/hr.js +186 -0
  210. package/dist/studio/samples/index.d.ts +13 -0
  211. package/dist/studio/samples/index.js +44 -0
  212. package/dist/studio/samples/insurance.d.ts +2 -0
  213. package/dist/studio/samples/insurance.js +220 -0
  214. package/dist/studio/samples/inventory.d.ts +2 -0
  215. package/dist/studio/samples/inventory.js +204 -0
  216. package/dist/studio/samples/invoicing.d.ts +2 -0
  217. package/dist/studio/samples/invoicing.js +154 -0
  218. package/dist/studio/samples/library.d.ts +2 -0
  219. package/dist/studio/samples/library.js +171 -0
  220. package/dist/studio/samples/live-data.d.ts +5 -0
  221. package/dist/studio/samples/live-data.js +261 -0
  222. package/dist/studio/samples/projects.d.ts +2 -0
  223. package/dist/studio/samples/projects.js +203 -0
  224. package/dist/studio/samples/realestate.d.ts +2 -0
  225. package/dist/studio/samples/realestate.js +187 -0
  226. package/dist/studio/samples/restaurant.d.ts +2 -0
  227. package/dist/studio/samples/restaurant.js +180 -0
  228. package/dist/studio/samples/school.d.ts +2 -0
  229. package/dist/studio/samples/school.js +188 -0
  230. package/dist/studio/samples/shared.d.ts +142 -0
  231. package/dist/studio/samples/shared.js +164 -0
  232. package/dist/studio/samples/starter.d.ts +4 -0
  233. package/dist/studio/samples/starter.js +237 -0
  234. package/dist/studio/samples/subscriptions.d.ts +2 -0
  235. package/dist/studio/samples/subscriptions.js +175 -0
  236. package/dist/studio/samples/support.d.ts +2 -0
  237. package/dist/studio/samples/support.js +209 -0
  238. package/dist/studio/scaffold-app.d.ts +22 -0
  239. package/{src/studio/scaffold-app.ts → dist/studio/scaffold-app.js} +45 -63
  240. package/dist/studio/scaffold.d.ts +63 -0
  241. package/dist/studio/scaffold.js +346 -0
  242. package/dist/studio/screen-suites.d.ts +193 -0
  243. package/dist/studio/screen-suites.js +297 -0
  244. package/dist/studio/themes.d.ts +34 -0
  245. package/dist/studio/themes.js +41 -0
  246. package/dist/studio/ui-components.d.ts +89 -0
  247. package/dist/studio/ui-components.generated.d.ts +29 -0
  248. package/dist/studio/ui-components.generated.js +7319 -0
  249. package/dist/studio/ui-components.js +673 -0
  250. package/dist/studio/user-error.d.ts +23 -0
  251. package/{src/studio/user-error.ts → dist/studio/user-error.js} +10 -13
  252. package/dist/studio/verify.d.ts +34 -0
  253. package/dist/studio/verify.js +47 -0
  254. package/dist/sveltekit/in-memory.d.ts +14 -0
  255. package/dist/sveltekit/in-memory.js +113 -0
  256. package/dist/sveltekit/index.d.ts +6 -0
  257. package/dist/sveltekit/index.js +5 -0
  258. package/dist/sveltekit/query-plan.d.ts +44 -0
  259. package/dist/sveltekit/query-plan.js +76 -0
  260. package/dist/sveltekit/sql-source.d.ts +47 -0
  261. package/dist/sveltekit/sql-source.js +106 -0
  262. package/dist/sveltekit/sql.d.ts +48 -0
  263. package/dist/sveltekit/sql.js +73 -0
  264. package/dist/sveltekit/transport.d.ts +209 -0
  265. package/dist/sveltekit/transport.js +219 -0
  266. package/{src/sveltekit/types.ts → dist/sveltekit/types.d.ts} +8 -11
  267. package/dist/sveltekit/types.js +1 -0
  268. package/dist/upgrade-prompt.d.ts +16 -0
  269. package/dist/upgrade-prompt.js +141 -0
  270. package/dist/version.d.ts +13 -0
  271. package/{src/version.ts → dist/version.js} +1 -1
  272. package/dist/watermark.d.ts +2 -0
  273. package/dist/watermark.js +146 -0
  274. package/package.json +28 -26
  275. package/dist/designer/assets/index-oYok52zd.css +0 -1
  276. package/dist/designer/assets/src-D-O2F805.css +0 -1
  277. package/src/SvBoard.dom.test.ts +0 -67
  278. package/src/SvGridAlerts.dom.test.ts +0 -113
  279. package/src/SvGridEditPanel.dom.test.ts +0 -320
  280. package/src/SvRecordDetail.dom.test.ts +0 -137
  281. package/src/SvSchedule.dom.test.ts +0 -57
  282. package/src/ai-export-pdf.dom.test.ts +0 -77
  283. package/src/ai-export-xlsx.dom.test.ts +0 -90
  284. package/src/ai-export.dom.test.ts +0 -114
  285. package/src/alerts/alert-engine-attach.ts +0 -165
  286. package/src/alerts/alert-engine.test.ts +0 -135
  287. package/src/alerts/alert-engine.ts +0 -260
  288. package/src/alerts/alert-formats.test.ts +0 -87
  289. package/src/alerts/alert-formats.ts +0 -77
  290. package/src/alerts/alert-observer.test.ts +0 -189
  291. package/src/alerts/alert-observer.ts +0 -208
  292. package/src/alerts/alert-scheduler.ts +0 -96
  293. package/src/alerts/alert-storage.test.ts +0 -54
  294. package/src/alerts/alert-storage.ts +0 -116
  295. package/src/alerts/alert-store.svelte.ts +0 -80
  296. package/src/alerts/alert-types.ts +0 -94
  297. package/src/board.dom.test.ts +0 -941
  298. package/src/edit-panel.test.ts +0 -322
  299. package/src/edit-panel.ts +0 -379
  300. package/src/export-conditional.test.ts +0 -60
  301. package/src/export-conditional.ts +0 -94
  302. package/src/export-ooxml.test.ts +0 -152
  303. package/src/export-ooxml.ts +0 -489
  304. package/src/export-pdf.test.ts +0 -138
  305. package/src/export-pdf.ts +0 -245
  306. package/src/export-print.test.ts +0 -66
  307. package/src/export-print.ts +0 -132
  308. package/src/export-serialize.test.ts +0 -56
  309. package/src/export-xls.ts +0 -199
  310. package/src/export-xlsx-roundtrip.test.ts +0 -120
  311. package/src/export-xlsx.test.ts +0 -150
  312. package/src/export.test.ts +0 -349
  313. package/src/export.ts +0 -1464
  314. package/src/expressions/evaluate.test.ts +0 -111
  315. package/src/expressions/evaluate.ts +0 -237
  316. package/src/expressions/expression-columns.ts +0 -133
  317. package/src/expressions/expression-types.ts +0 -84
  318. package/src/expressions/parse.test.ts +0 -106
  319. package/src/expressions/parse.ts +0 -610
  320. package/src/import-automap.test.ts +0 -131
  321. package/src/import-hardening.test.ts +0 -158
  322. package/src/import.test.ts +0 -415
  323. package/src/import.ts +0 -1044
  324. package/src/index.ts +0 -569
  325. package/src/install.ts +0 -154
  326. package/src/license-core.test.ts +0 -23
  327. package/src/license-core.ts +0 -107
  328. package/src/license-expiry.test.ts +0 -144
  329. package/src/license.ts +0 -157
  330. package/src/master-detail.test.ts +0 -61
  331. package/src/master-detail.ts +0 -42
  332. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/_metadata.json +0 -178
  333. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/attachments-ZrPsKxob.js +0 -3875
  334. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/attachments-ZrPsKxob.js.map +0 -1
  335. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/constants-ACqvWGE2.js +0 -21
  336. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/constants-ACqvWGE2.js.map +0 -1
  337. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/dev-D3w5jt92.js +0 -1938
  338. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/dev-D3w5jt92.js.map +0 -1
  339. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/events-CC2V3H0y.js +0 -205
  340. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/events-CC2V3H0y.js.map +0 -1
  341. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/flags-BXP37tAa.js +0 -18
  342. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/flags-BXP37tAa.js.map +0 -1
  343. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/hydration-DwubnU5b.js +0 -264
  344. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/hydration-DwubnU5b.js.map +0 -1
  345. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/legacy-client-hD7f6PUz.js +0 -697
  346. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/legacy-client-hD7f6PUz.js.map +0 -1
  347. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte.js +0 -134
  348. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte.js.map +0 -1
  349. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_animate.js +0 -55
  350. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_animate.js.map +0 -1
  351. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_attachments.js +0 -2
  352. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_compiler.js +0 -46843
  353. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_compiler.js.map +0 -1
  354. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_easing.js +0 -237
  355. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_easing.js.map +0 -1
  356. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_events.js +0 -2
  357. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal.js +0 -4
  358. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal.js.map +0 -1
  359. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_client.js +0 -7
  360. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_disclose-version.js +0 -4
  361. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_disclose-version.js.map +0 -1
  362. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_async.js +0 -5
  363. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_async.js.map +0 -1
  364. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_legacy.js +0 -5
  365. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_legacy.js.map +0 -1
  366. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_tracing.js +0 -5
  367. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_tracing.js.map +0 -1
  368. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_server.js +0 -6
  369. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_legacy.js +0 -83
  370. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_legacy.js.map +0 -1
  371. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_motion.js +0 -559
  372. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_motion.js.map +0 -1
  373. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity.js +0 -24
  374. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity.js.map +0 -1
  375. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity_window.js +0 -122
  376. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity_window.js.map +0 -1
  377. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_server.js +0 -2
  378. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_store.js +0 -89
  379. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_store.js.map +0 -1
  380. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_transition.js +0 -241
  381. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_transition.js.map +0 -1
  382. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-DBx1SCN6.js +0 -4938
  383. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-DBx1SCN6.js.map +0 -1
  384. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-gjfpSTFS.js +0 -495
  385. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-gjfpSTFS.js.map +0 -1
  386. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/validate-DKoOKg8S.js +0 -190
  387. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/validate-DKoOKg8S.js.map +0 -1
  388. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/version-C0MiR7eR.js +0 -8
  389. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/version-C0MiR7eR.js.map +0 -1
  390. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/warnings-B6Y7P0Q-.js +0 -138
  391. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/warnings-B6Y7P0Q-.js.map +0 -1
  392. package/src/pivot-chart.test.ts +0 -86
  393. package/src/pivot-chart.ts +0 -112
  394. package/src/pivot-designer.ts +0 -101
  395. package/src/pivot.test.ts +0 -335
  396. package/src/pivot.ts +0 -578
  397. package/src/print.ts +0 -107
  398. package/src/scheduler-assignments.test.ts +0 -97
  399. package/src/scheduler-assignments.ts +0 -134
  400. package/src/scheduler-axis.test.ts +0 -108
  401. package/src/scheduler-axis.ts +0 -238
  402. package/src/scheduler-booking.test.ts +0 -57
  403. package/src/scheduler-config.ts +0 -179
  404. package/src/scheduler-dependencies.test.ts +0 -155
  405. package/src/scheduler-dependencies.ts +0 -223
  406. package/src/scheduler-freebusy.test.ts +0 -41
  407. package/src/scheduler-heatmap.test.ts +0 -39
  408. package/src/scheduler-resource-tree.test.ts +0 -84
  409. package/src/scheduler-resource-tree.ts +0 -107
  410. package/src/scheduler-slots.test.ts +0 -53
  411. package/src/scheduler-slots.ts +0 -94
  412. package/src/scheduler-summary.test.ts +0 -47
  413. package/src/scheduler-summary.ts +0 -81
  414. package/src/scheduling.test.ts +0 -194
  415. package/src/scheduling.ts +0 -293
  416. package/src/schema-designer.test.ts +0 -121
  417. package/src/schema-designer.ts +0 -142
  418. package/src/schema.test.ts +0 -268
  419. package/src/schema.ts +0 -562
  420. package/src/smart-shim.ts +0 -107
  421. package/src/sources/aggregate.test.ts +0 -79
  422. package/src/sources/aggregate.ts +0 -102
  423. package/src/sources/auth-supabase.test.ts +0 -80
  424. package/src/sources/auth-supabase.ts +0 -87
  425. package/src/sources/dashboard.kpi.test.ts +0 -50
  426. package/src/sources/dashboard.test.ts +0 -61
  427. package/src/sources/dashboard.ts +0 -136
  428. package/src/sources/field-inference.test.ts +0 -60
  429. package/src/sources/field-inference.ts +0 -63
  430. package/src/sources/filters.test.ts +0 -58
  431. package/src/sources/filters.ts +0 -70
  432. package/src/sources/index.ts +0 -67
  433. package/src/sources/introspect-supabase.test.ts +0 -112
  434. package/src/sources/introspect-supabase.ts +0 -139
  435. package/src/sources/realtime-supabase.test.ts +0 -93
  436. package/src/sources/realtime-supabase.ts +0 -99
  437. package/src/sources/relation-lookup.test.ts +0 -99
  438. package/src/sources/relation-lookup.ts +0 -128
  439. package/src/sources/rest-adapters.test.ts +0 -95
  440. package/src/sources/rest-adapters.ts +0 -120
  441. package/src/sources/rest.test.ts +0 -104
  442. package/src/sources/rest.ts +0 -129
  443. package/src/sources/schema-from-columns.test.ts +0 -106
  444. package/src/sources/schema-from-columns.ts +0 -88
  445. package/src/sources/supabase.test.ts +0 -110
  446. package/src/sources/supabase.ts +0 -99
  447. package/src/sources/with-entity-rules.test.ts +0 -104
  448. package/src/sources/with-entity-rules.ts +0 -78
  449. package/src/sources/with-relation-labels.test.ts +0 -75
  450. package/src/sources/with-relation-labels.ts +0 -73
  451. package/src/staged-editing.ts +0 -0
  452. package/src/studio/bug-report.test.ts +0 -101
  453. package/src/studio/bug-report.ts +0 -165
  454. package/src/studio/cli.test.ts +0 -187
  455. package/src/studio/cli.ts +0 -117
  456. package/src/studio/copilot-core.test.ts +0 -45
  457. package/src/studio/csv.test.ts +0 -90
  458. package/src/studio/csv.ts +0 -165
  459. package/src/studio/db-connect-string.test.ts +0 -94
  460. package/src/studio/db-connect-string.ts +0 -128
  461. package/src/studio/deploy-cli.test.ts +0 -56
  462. package/src/studio/deploy-cli.ts +0 -100
  463. package/src/studio/emit-project.test.ts +0 -3324
  464. package/src/studio/emit-project.ts +0 -5377
  465. package/src/studio/emit-schema.test.ts +0 -111
  466. package/src/studio/emit-schema.ts +0 -1181
  467. package/src/studio/index.ts +0 -380
  468. package/src/studio/init-flow.test.ts +0 -514
  469. package/src/studio/init-flow.ts +0 -556
  470. package/src/studio/introspect-db.test.ts +0 -186
  471. package/src/studio/introspect-db.ts +0 -312
  472. package/src/studio/introspect-openapi.test.ts +0 -84
  473. package/src/studio/introspect-openapi.ts +0 -252
  474. package/src/studio/introspect-prisma.test.ts +0 -99
  475. package/src/studio/introspect-prisma.ts +0 -175
  476. package/src/studio/introspect.test.ts +0 -172
  477. package/src/studio/introspect.ts +0 -310
  478. package/src/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/_svelte_metadata.json +0 -1
  479. package/src/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/package.json +0 -3
  480. package/src/studio/pipeline.test.ts +0 -42
  481. package/src/studio/project-robust.test.ts +0 -157
  482. package/src/studio/project.test.ts +0 -929
  483. package/src/studio/project.ts +0 -2394
  484. package/src/studio/sample-data.test.ts +0 -58
  485. package/src/studio/sample-data.ts +0 -203
  486. package/src/studio/samples/ats.ts +0 -202
  487. package/src/studio/samples/clinic.ts +0 -179
  488. package/src/studio/samples/crm.ts +0 -291
  489. package/src/studio/samples/datasets.test.ts +0 -84
  490. package/src/studio/samples/datasets.ts +0 -340
  491. package/src/studio/samples/ecommerce.ts +0 -187
  492. package/src/studio/samples/events.ts +0 -201
  493. package/src/studio/samples/fleet.ts +0 -213
  494. package/src/studio/samples/gym.ts +0 -215
  495. package/src/studio/samples/hr.ts +0 -195
  496. package/src/studio/samples/index.ts +0 -55
  497. package/src/studio/samples/insurance.ts +0 -229
  498. package/src/studio/samples/inventory.ts +0 -213
  499. package/src/studio/samples/invoicing.ts +0 -162
  500. package/src/studio/samples/library.ts +0 -180
  501. package/src/studio/samples/live-data.test.ts +0 -99
  502. package/src/studio/samples/live-data.ts +0 -306
  503. package/src/studio/samples/projects.ts +0 -212
  504. package/src/studio/samples/realestate.ts +0 -196
  505. package/src/studio/samples/restaurant.ts +0 -189
  506. package/src/studio/samples/samples.test.ts +0 -304
  507. package/src/studio/samples/school.ts +0 -197
  508. package/src/studio/samples/seed-floor.test.ts +0 -25
  509. package/src/studio/samples/shared.ts +0 -237
  510. package/src/studio/samples/starter.ts +0 -251
  511. package/src/studio/samples/subscriptions.ts +0 -183
  512. package/src/studio/samples/support.ts +0 -216
  513. package/src/studio/scaffold-app.test.ts +0 -91
  514. package/src/studio/scaffold.test.ts +0 -192
  515. package/src/studio/scaffold.ts +0 -390
  516. package/src/studio/screen-suites.test.ts +0 -269
  517. package/src/studio/screen-suites.ts +0 -448
  518. package/src/studio/themes.ts +0 -62
  519. package/src/studio/ui-components-surface.test.ts +0 -185
  520. package/src/studio/ui-components.generated.ts +0 -7154
  521. package/src/studio/ui-components.ts +0 -742
  522. package/src/studio/verify.test.ts +0 -47
  523. package/src/studio/verify.ts +0 -79
  524. package/src/sveltekit/in-memory.test.ts +0 -104
  525. package/src/sveltekit/in-memory.ts +0 -129
  526. package/src/sveltekit/index.ts +0 -24
  527. package/src/sveltekit/query-plan.test.ts +0 -109
  528. package/src/sveltekit/query-plan.ts +0 -125
  529. package/src/sveltekit/sql-source.test.ts +0 -198
  530. package/src/sveltekit/sql-source.ts +0 -171
  531. package/src/sveltekit/sql.test.ts +0 -80
  532. package/src/sveltekit/sql.ts +0 -131
  533. package/src/sveltekit/transport-scope.test.ts +0 -125
  534. package/src/sveltekit/transport.test.ts +0 -201
  535. package/src/sveltekit/transport.ts +0 -373
  536. package/src/upgrade-prompt.test.ts +0 -71
  537. package/src/upgrade-prompt.ts +0 -162
  538. package/src/version.test.ts +0 -17
  539. package/src/watermark.test.ts +0 -97
  540. package/src/watermark.ts +0 -156
  541. /package/{src → dist}/SvAlertRuleEditor.svelte +0 -0
  542. /package/{src → dist}/SvAlertsManager.svelte +0 -0
  543. /package/{src → dist}/SvAlertsPanel.svelte +0 -0
  544. /package/{src → dist}/SvAuthGate.svelte +0 -0
  545. /package/{src → dist}/SvBoard.svelte +0 -0
  546. /package/{src → dist}/SvExportMenu.svelte +0 -0
  547. /package/{src → dist}/SvFileInput.svelte +0 -0
  548. /package/{src → dist}/SvGridAlerts.svelte +0 -0
  549. /package/{src → dist}/SvGridBoard.svelte +0 -0
  550. /package/{src → dist}/SvGridMasterDetail.svelte +0 -0
  551. /package/{src → dist}/SvGridScheduler.svelte +0 -0
  552. /package/{src → dist}/SvImportDialog.svelte +0 -0
  553. /package/{src → dist}/SvLookupInput.svelte +0 -0
  554. /package/{src → dist}/SvPivotDesigner.svelte +0 -0
  555. /package/{src → dist}/SvRecordDetail.svelte +0 -0
  556. /package/{src → dist}/SvSchedule.svelte +0 -0
  557. /package/{src → dist}/SvSchemaChart.svelte +0 -0
  558. /package/{src → dist}/SvSchemaDashboard.svelte +0 -0
  559. /package/{src → dist}/pdfmake-shims.d.ts +0 -0
  560. /package/{src → dist}/smart.export.d.ts +0 -0
  561. /package/{src → dist}/smart.export.js +0 -0
  562. /package/{src → dist}/studio/HANDLERS-DESIGN.md +0 -0
  563. /package/{src → dist/studio}/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/_svelte_metadata.json +0 -0
  564. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/_metadata.json +0 -0
  565. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/attachments-BOv1rBKp.js +0 -0
  566. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/attachments-BOv1rBKp.js.map +0 -0
  567. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/constants-B9vgIdCd.js +0 -0
  568. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/constants-B9vgIdCd.js.map +0 -0
  569. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/dev-T1qbW_qD.js +0 -0
  570. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/dev-T1qbW_qD.js.map +0 -0
  571. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/events-Bo11SfVK.js +0 -0
  572. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/events-Bo11SfVK.js.map +0 -0
  573. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/flags-X7D4vfrZ.js +0 -0
  574. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/flags-X7D4vfrZ.js.map +0 -0
  575. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/hydration-oyUje5i1.js +0 -0
  576. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/hydration-oyUje5i1.js.map +0 -0
  577. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/legacy-client-DeSQgSFm.js +0 -0
  578. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/legacy-client-DeSQgSFm.js.map +0 -0
  579. /package/{src → dist/studio}/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/package.json +0 -0
  580. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte.js +0 -0
  581. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte.js.map +0 -0
  582. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_animate.js +0 -0
  583. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_animate.js.map +0 -0
  584. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_attachments.js +0 -0
  585. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_compiler.js +0 -0
  586. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_compiler.js.map +0 -0
  587. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_easing.js +0 -0
  588. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_easing.js.map +0 -0
  589. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_events.js +0 -0
  590. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal.js +0 -0
  591. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal.js.map +0 -0
  592. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_client.js +0 -0
  593. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_disclose-version.js +0 -0
  594. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_disclose-version.js.map +0 -0
  595. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_async.js +0 -0
  596. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_async.js.map +0 -0
  597. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_legacy.js +0 -0
  598. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_legacy.js.map +0 -0
  599. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_tracing.js +0 -0
  600. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_tracing.js.map +0 -0
  601. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_server.js +0 -0
  602. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_legacy.js +0 -0
  603. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_legacy.js.map +0 -0
  604. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_motion.js +0 -0
  605. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_motion.js.map +0 -0
  606. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity.js +0 -0
  607. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity.js.map +0 -0
  608. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity_window.js +0 -0
  609. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity_window.js.map +0 -0
  610. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_server.js +0 -0
  611. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_store.js +0 -0
  612. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_store.js.map +0 -0
  613. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_transition.js +0 -0
  614. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_transition.js.map +0 -0
  615. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-BbWyXNk1.js +0 -0
  616. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-BbWyXNk1.js.map +0 -0
  617. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-DI_fC7vt.js +0 -0
  618. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-DI_fC7vt.js.map +0 -0
  619. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/validate-Dyr3lQv9.js +0 -0
  620. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/validate-Dyr3lQv9.js.map +0 -0
  621. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/version-_9FHH-LF.js +0 -0
  622. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/version-_9FHH-LF.js.map +0 -0
  623. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/warnings-CUbSPnyP.js +0 -0
  624. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/warnings-CUbSPnyP.js.map +0 -0
@@ -1,941 +0,0 @@
1
- /**
2
- * Component tests for Kanban board mode (SvGridBoard): lane derivation,
3
- * card rendering, WIP counts, empty lanes, and drag-to-move (onCardMove).
4
- */
5
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
6
- import { mount, unmount, flushSync, createRawSnippet } from 'svelte'
7
- import SvGridBoard from './SvGridBoard.svelte'
8
- import { SvGrid, SvDropDownList, createDismissableLayer } from '@svgrid/grid'
9
- import { enableBoardView } from './board'
10
-
11
- // The board renderer is Pro: register it with the grid so `<SvGrid board={...}>`
12
- // mounts SvGridBoard (rather than the enterprise upsell placeholder).
13
- enableBoardView()
14
-
15
- // jsdom lacks ResizeObserver, which the card editor's dropdown touches on mount.
16
- // The grid's own suite polyfills this in test-setup.ts; the enterprise dom
17
- // project has no shared setup, so stub it here.
18
- if (typeof globalThis.ResizeObserver === 'undefined') {
19
- ;(globalThis as any).ResizeObserver = class {
20
- observe() {}
21
- unobserve() {}
22
- disconnect() {}
23
- }
24
- }
25
-
26
- function mountOn(props: Record<string, unknown>) {
27
- const target = document.createElement('div')
28
- document.body.appendChild(target)
29
- const app = mount(SvGridBoard as any, { target, props: props as any })
30
- flushSync()
31
- return { target, destroy: () => { unmount(app); target.remove() } }
32
- }
33
-
34
- afterEach(() => { document.body.innerHTML = '' })
35
-
36
- const data = [
37
- { id: 1, title: 'Design spec', status: 'todo', owner: 'Sam' },
38
- { id: 2, title: 'Write tests', status: 'todo', owner: 'Lee' },
39
- { id: 3, title: 'Ship it', status: 'done', owner: 'Sam' },
40
- ]
41
- const columns = [
42
- { field: 'title', header: 'Title' },
43
- { field: 'owner', header: 'Owner' },
44
- { field: 'status', header: 'Status' },
45
- ]
46
-
47
- function fire(el: Element, type: string) {
48
- el.dispatchEvent(new Event(type, { bubbles: true, cancelable: true }))
49
- flushSync()
50
- }
51
-
52
- describe('SvGridBoard lanes', () => {
53
- it('derives lanes from the distinct groupBy values (first-seen order)', () => {
54
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status' } })
55
- try {
56
- const lanes = target.querySelectorAll('.sv-board-lane')
57
- expect(lanes).toHaveLength(2)
58
- const titles = [...target.querySelectorAll('.sv-board-lane-title')].map((n) => n.textContent)
59
- expect(titles).toEqual(['todo', 'done'])
60
- } finally { destroy() }
61
- })
62
-
63
- it('buckets cards into their lane and shows a count', () => {
64
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status' } })
65
- try {
66
- const counts = [...target.querySelectorAll('.sv-board-lane-count')].map((n) => n.textContent?.trim())
67
- expect(counts).toEqual(['2', '1'])
68
- const firstLaneCards = target.querySelector('.sv-board-lane')!.querySelectorAll('.sv-board-card')
69
- expect(firstLaneCards).toHaveLength(2)
70
- } finally { destroy() }
71
- })
72
-
73
- it('honours explicit ordered lanes with titles, incl. an empty one', () => {
74
- const board = {
75
- groupBy: 'status',
76
- lanes: [
77
- { id: 'todo', title: 'To do' },
78
- { id: 'doing', title: 'In progress' },
79
- { id: 'done', title: 'Done' },
80
- ],
81
- }
82
- const { target, destroy } = mountOn({ data, columns, board })
83
- try {
84
- const titles = [...target.querySelectorAll('.sv-board-lane-title')].map((n) => n.textContent)
85
- expect(titles).toEqual(['To do', 'In progress', 'Done'])
86
- // The empty 'doing' lane shows a placeholder.
87
- expect(target.querySelectorAll('.sv-board-lane-empty')).toHaveLength(1)
88
- } finally { destroy() }
89
- })
90
-
91
- it('flags a lane that exceeds its WIP limit', () => {
92
- const board = { groupBy: 'status', lanes: [{ id: 'todo', title: 'To do', wipLimit: 1 }] }
93
- const { target, destroy } = mountOn({ data, columns, board })
94
- try {
95
- const count = target.querySelector('.sv-board-lane-count')!
96
- expect(count.textContent?.trim()).toBe('2/1')
97
- expect(count.classList.contains('is-over')).toBe(true)
98
- } finally { destroy() }
99
- })
100
- })
101
-
102
- describe('SvGridBoard default card', () => {
103
- it('renders the title field and meta rows', () => {
104
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status' } })
105
- try {
106
- const first = target.querySelector('.sv-board-card')!
107
- expect(first.querySelector('.sv-board-card-title')?.textContent).toBe('Design spec')
108
- // Owner is a meta row; status (the groupBy) and title are excluded.
109
- const labels = [...first.querySelectorAll('.sv-board-card-metarow dt')].map((n) => n.textContent)
110
- expect(labels).toContain('Owner')
111
- expect(labels).not.toContain('Status')
112
- expect(labels).not.toContain('Title')
113
- } finally { destroy() }
114
- })
115
-
116
- it('shows an add-card button only when onCardAdd is set', () => {
117
- const onCardAdd = vi.fn()
118
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', onCardAdd } })
119
- try {
120
- const add = target.querySelector<HTMLButtonElement>('.sv-board-lane-add')!
121
- expect(add).not.toBeNull()
122
- add.click()
123
- expect(onCardAdd).toHaveBeenCalledWith('todo')
124
- } finally { destroy() }
125
- })
126
- })
127
-
128
- describe('SvGridBoard drag to move (built-in)', () => {
129
- it('fires onCardMove with row + from/to lane when a card is dropped on another lane', () => {
130
- const onCardMove = vi.fn()
131
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', onCardMove } })
132
- try {
133
- const lanes = target.querySelectorAll('.sv-board-lane')
134
- const card = lanes[0]!.querySelector('.sv-board-card')! // "Design spec" in todo
135
- const targetBody = lanes[1]!.querySelector('.sv-board-lane-body')! // done lane
136
-
137
- fire(card, 'dragstart')
138
- fire(targetBody, 'dragover')
139
- fire(targetBody, 'drop')
140
-
141
- expect(onCardMove).toHaveBeenCalledTimes(1)
142
- const e = onCardMove.mock.calls[0]![0]
143
- expect(e.row.id).toBe(1)
144
- expect(e.fromLane).toBe('todo')
145
- expect(e.toLane).toBe('done')
146
- expect(typeof e.toIndex).toBe('number')
147
- } finally { destroy() }
148
- })
149
-
150
- it('actually moves the card into the target lane itself (no consumer code)', () => {
151
- // No onCardMove: the board applies the move via its own overlay.
152
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status' } })
153
- try {
154
- const lanes = target.querySelectorAll('.sv-board-lane')
155
- const card = lanes[0]!.querySelector('.sv-board-card')!
156
- const targetBody = lanes[1]!.querySelector('.sv-board-lane-body')!
157
-
158
- fire(card, 'dragstart')
159
- fire(targetBody, 'dragover')
160
- fire(targetBody, 'drop')
161
-
162
- const counts = [...target.querySelectorAll('.sv-board-lane-count')].map((n) => n.textContent?.trim())
163
- expect(counts).toEqual(['1', '2']) // todo 2->1, done 1->2
164
- // The moved card now lives in the done lane.
165
- const doneTitles = [...lanes[1]!.querySelectorAll('.sv-board-card-title')].map((n) => n.textContent)
166
- expect(doneTitles).toContain('Design spec')
167
- } finally { destroy() }
168
- })
169
-
170
- it('does not fire onCardMove for a no-op drop onto its own single-card lane', () => {
171
- const onCardMove = vi.fn()
172
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', onCardMove } })
173
- try {
174
- const lanes = target.querySelectorAll('.sv-board-lane')
175
- const doneBody = lanes[1]!.querySelector('.sv-board-lane-body')! // done: single card
176
- const card = doneBody.querySelector('.sv-board-card')!
177
- fire(card, 'dragstart')
178
- fire(doneBody, 'drop')
179
- expect(onCardMove).not.toHaveBeenCalled()
180
- } finally { destroy() }
181
- })
182
- })
183
-
184
- describe('SvGridBoard card editing (built-in)', () => {
185
- function dblclick(el: Element) {
186
- el.dispatchEvent(new MouseEvent('dblclick', { bubbles: true }))
187
- flushSync()
188
- }
189
-
190
- it('double-click opens the inline editor with a field per editable column', () => {
191
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', editable: true } })
192
- try {
193
- dblclick(target.querySelector('.sv-board-card')!)
194
- const form = target.querySelector('.sv-board-card-edit')
195
- expect(form).not.toBeNull()
196
- // title + owner (status is the groupBy field, excluded)
197
- expect(form!.querySelectorAll('input')).toHaveLength(2)
198
- } finally { destroy() }
199
- })
200
-
201
- it('saving commits the changed fields and updates the card', () => {
202
- const onCardCommit = vi.fn()
203
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', editable: true, onCardCommit } })
204
- try {
205
- dblclick(target.querySelector('.sv-board-card')!)
206
- const input = target.querySelector<HTMLInputElement>('.sv-board-card-edit input')!
207
- input.value = 'Renamed'
208
- input.dispatchEvent(new Event('input', { bubbles: true }))
209
- flushSync()
210
- const save = [...target.querySelectorAll('.sv-board-btn')].find((b) => b.textContent === 'Save')! as HTMLButtonElement
211
- save.click()
212
- flushSync()
213
- expect(onCardCommit).toHaveBeenCalledTimes(1)
214
- expect(onCardCommit.mock.calls[0]![0].changes.title).toBe('Renamed')
215
- expect(target.querySelector('.sv-board-card-edit')).toBeNull()
216
- expect(target.querySelector('.sv-board-card-title')?.textContent).toBe('Renamed')
217
- } finally { destroy() }
218
- })
219
-
220
- it('cancel closes the editor without committing', () => {
221
- const onCardCommit = vi.fn()
222
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', editable: true, onCardCommit } })
223
- try {
224
- dblclick(target.querySelector('.sv-board-card')!)
225
- const cancel = [...target.querySelectorAll('.sv-board-btn')].find((b) => b.textContent === 'Cancel')! as HTMLButtonElement
226
- cancel.click()
227
- flushSync()
228
- expect(onCardCommit).not.toHaveBeenCalled()
229
- expect(target.querySelector('.sv-board-card-edit')).toBeNull()
230
- } finally { destroy() }
231
- })
232
-
233
- it('onCardEdit is used instead of the built-in editor when provided', () => {
234
- const onCardEdit = vi.fn()
235
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', editable: true, onCardEdit } })
236
- try {
237
- dblclick(target.querySelector('.sv-board-card')!)
238
- expect(onCardEdit).toHaveBeenCalledTimes(1)
239
- expect(onCardEdit.mock.calls[0]![0].id).toBe(1)
240
- expect(target.querySelector('.sv-board-card-edit')).toBeNull()
241
- } finally { destroy() }
242
- })
243
- })
244
-
245
- describe('SvGridBoard keyboard navigation', () => {
246
- function keydown(el: Element, key: string) {
247
- el.dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true, cancelable: true }))
248
- flushSync()
249
- }
250
- const activeTitle = () =>
251
- (document.activeElement as HTMLElement | null)?.querySelector('.sv-board-card-title')?.textContent
252
-
253
- it('Arrow Down/Up moves focus between cards in a lane (not grabbed)', () => {
254
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status' } })
255
- try {
256
- const first = target.querySelector<HTMLElement>('.sv-board-card')! // Design spec (todo)
257
- first.focus()
258
- keydown(first, 'ArrowDown')
259
- expect(activeTitle()).toBe('Write tests')
260
- keydown(document.activeElement!, 'ArrowUp')
261
- expect(activeTitle()).toBe('Design spec')
262
- } finally { destroy() }
263
- })
264
-
265
- it('Arrow Right moves focus to the adjacent lane (not grabbed)', () => {
266
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status' } })
267
- try {
268
- const first = target.querySelector<HTMLElement>('.sv-board-card')! // todo
269
- first.focus()
270
- keydown(first, 'ArrowRight')
271
- expect(activeTitle()).toBe('Ship it') // the done lane's card
272
- } finally { destroy() }
273
- })
274
- })
275
-
276
- describe('SvGridBoard keyboard drag (built-in)', () => {
277
- function keydown(el: Element, key: string) {
278
- el.dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true, cancelable: true }))
279
- flushSync()
280
- }
281
-
282
- it('Space grabs a card and ArrowRight moves it to the next lane', () => {
283
- const onCardMove = vi.fn()
284
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', onCardMove } })
285
- try {
286
- const lanes = target.querySelectorAll('.sv-board-lane')
287
- const card = lanes[0]!.querySelector('.sv-board-card')! // todo
288
- keydown(card, ' ')
289
- expect(card.getAttribute('aria-grabbed')).toBe('true')
290
- keydown(card, 'ArrowRight')
291
- expect(onCardMove).toHaveBeenCalledTimes(1)
292
- expect(onCardMove.mock.calls[0]![0].toLane).toBe('done')
293
- const doneTitles = [...lanes[1]!.querySelectorAll('.sv-board-card-title')].map((n) => n.textContent)
294
- expect(doneTitles).toContain('Design spec')
295
- } finally { destroy() }
296
- })
297
-
298
- it('Escape cancels a grab and restores the card', () => {
299
- const onCardMove = vi.fn()
300
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', onCardMove } })
301
- try {
302
- const lanes = target.querySelectorAll('.sv-board-lane')
303
- const card = lanes[0]!.querySelector('.sv-board-card')!
304
- keydown(card, ' ')
305
- keydown(card, 'ArrowRight') // move to done -> the node is recreated in the new lane
306
- const moved = [...target.querySelectorAll('.sv-board-card')].find(
307
- (c) => c.querySelector('.sv-board-card-title')?.textContent === 'Design spec',
308
- )!
309
- keydown(moved, 'Escape') // cancel -> back to todo
310
- const todoTitles = [...target.querySelectorAll('.sv-board-lane')[0]!.querySelectorAll('.sv-board-card-title')].map((n) => n.textContent)
311
- expect(todoTitles).toContain('Design spec')
312
- } finally { destroy() }
313
- })
314
- })
315
-
316
- describe('SvGridBoard extensions', () => {
317
- it('swimlaneBy renders a band per value, each with the full lane set', () => {
318
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', swimlaneBy: 'owner' } })
319
- try {
320
- const bands = target.querySelectorAll('.sv-board-swim')
321
- expect(bands).toHaveLength(2) // Sam, Lee
322
- expect(bands[0]!.querySelectorAll('.sv-board-lane')).toHaveLength(2) // todo, done
323
- // Sam's todo lane holds "Design spec"; Lee's done lane is empty.
324
- const samTodo = bands[0]!.querySelectorAll('.sv-board-lane')[0]!
325
- expect(samTodo.querySelector('.sv-board-card-title')?.textContent).toBe('Design spec')
326
- } finally { destroy() }
327
- })
328
-
329
- it('dragging across bands reassigns both lane and swimlane', () => {
330
- const onCardMove = vi.fn()
331
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', swimlaneBy: 'owner', onCardMove } })
332
- try {
333
- const bands = target.querySelectorAll('.sv-board-swim')
334
- const samTodoCard = bands[0]!.querySelectorAll('.sv-board-lane')[0]!.querySelector('.sv-board-card')!
335
- const leeDoneBody = bands[1]!.querySelectorAll('.sv-board-lane')[1]!.querySelector('.sv-board-lane-body')!
336
- fire(samTodoCard, 'dragstart')
337
- fire(leeDoneBody, 'dragover')
338
- fire(leeDoneBody, 'drop')
339
- expect(onCardMove).toHaveBeenCalledTimes(1)
340
- const e = onCardMove.mock.calls[0]![0]
341
- expect(e.toLane).toBe('done')
342
- expect(e.fromSwimlane).toBe('Sam')
343
- expect(e.toSwimlane).toBe('Lee')
344
- } finally { destroy() }
345
- })
346
-
347
- it('enforceWip rejects a drop that would exceed a lane WIP limit', () => {
348
- const onCardMove = vi.fn()
349
- const board = {
350
- groupBy: 'status',
351
- enforceWip: true,
352
- lanes: [{ id: 'todo', title: 'To do' }, { id: 'done', title: 'Done', wipLimit: 1 }],
353
- onCardMove,
354
- }
355
- const { target, destroy } = mountOn({ data, columns, board })
356
- try {
357
- const lanes = target.querySelectorAll('.sv-board-lane')
358
- const card = lanes[0]!.querySelector('.sv-board-card')! // a todo card
359
- const doneBody = lanes[1]!.querySelector('.sv-board-lane-body')! // done: 1/1 already
360
- fire(card, 'dragstart')
361
- fire(doneBody, 'dragover')
362
- fire(doneBody, 'drop')
363
- expect(onCardMove).not.toHaveBeenCalled()
364
- const counts = [...target.querySelectorAll('.sv-board-lane-count')].map((n) => n.textContent?.trim())
365
- expect(counts).toEqual(['2', '1/1']) // nothing moved
366
- } finally { destroy() }
367
- })
368
-
369
- it('collapsibleLanes: clicking the toggle collapses the lane body', () => {
370
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', collapsibleLanes: true } })
371
- try {
372
- const lane = target.querySelector('.sv-board-lane')!
373
- expect(lane.querySelector('.sv-board-lane-body')).not.toBeNull()
374
- const toggle = lane.querySelector<HTMLButtonElement>('.sv-board-lane-toggle')!
375
- toggle.click()
376
- flushSync()
377
- expect(lane.classList.contains('is-collapsed')).toBe(true)
378
- expect(lane.querySelector('.sv-board-lane-body')).toBeNull()
379
- } finally { destroy() }
380
- })
381
- })
382
-
383
- describe('SvGrid board filter passthrough', () => {
384
- it('renders the grid filtered rows; the search box filters cards', () => {
385
- const target = document.createElement('div')
386
- document.body.appendChild(target)
387
- const app = mount(SvGrid as any, { target, props: { data, columns, board: { groupBy: 'status' } } as any })
388
- flushSync()
389
- try {
390
- expect(target.querySelectorAll('.sv-board-card')).toHaveLength(3)
391
- const input = target.querySelector<HTMLInputElement>('.sv-grid-board-search input')!
392
- input.value = 'Ship'
393
- input.dispatchEvent(new Event('input', { bubbles: true }))
394
- flushSync()
395
- expect(target.querySelectorAll('.sv-board-card')).toHaveLength(1)
396
- expect(target.querySelector('.sv-board-card-title')?.textContent).toBe('Ship it')
397
- } finally { unmount(app); target.remove() }
398
- })
399
- })
400
-
401
- describe('SvGridBoard virtualization', () => {
402
- it('renders only a window of cards per lane when virtualized', () => {
403
- const many = Array.from({ length: 100 }, (_, i) => ({
404
- id: i + 1, title: `Card ${i + 1}`, status: 'todo', owner: 'Sam',
405
- }))
406
- const { target, destroy } = mountOn({
407
- data: many, columns, board: { groupBy: 'status', virtualized: true, cardHeight: 60 },
408
- })
409
- try {
410
- const rendered = target.querySelectorAll('.sv-board-card')
411
- expect(rendered.length).toBeGreaterThan(0)
412
- expect(rendered.length).toBeLessThan(30) // a small window, not all 100
413
- const body = target.querySelector('.sv-board-lane-body.is-virtual')!
414
- const spacer = body.querySelector('div[aria-hidden="true"][style*="height"]')
415
- expect(spacer).not.toBeNull()
416
- } finally { destroy() }
417
- })
418
-
419
- it('is off by default (all cards rendered)', () => {
420
- const many = Array.from({ length: 40 }, (_, i) => ({
421
- id: i + 1, title: `Card ${i + 1}`, status: 'todo', owner: 'Sam',
422
- }))
423
- const { target, destroy } = mountOn({ data: many, columns, board: { groupBy: 'status' } })
424
- try {
425
- expect(target.querySelectorAll('.sv-board-card')).toHaveLength(40)
426
- } finally { destroy() }
427
- })
428
- })
429
-
430
- describe('SvGridBoard laneSummary', () => {
431
- it('renders a per-lane summary in the header', () => {
432
- const { target, destroy } = mountOn({
433
- data, columns, board: { groupBy: 'status', laneSummary: (rows: any[]) => `${rows.length} items` },
434
- })
435
- try {
436
- const summaries = [...target.querySelectorAll('.sv-board-lane-summary')].map((n) => n.textContent)
437
- expect(summaries).toEqual(['2 items', '1 items'])
438
- } finally { destroy() }
439
- })
440
- })
441
-
442
- describe('SvGridBoard layout persistence', () => {
443
- const KEY = 'test-board-layout'
444
- const rowId = (r: any) => String(r.id)
445
- beforeEach(() => { try { localStorage.removeItem(KEY) } catch { /* ignore */ } })
446
-
447
- it('persists a move to localStorage and restores it on a fresh mount', () => {
448
- const a = mountOn({ data, columns, getRowId: rowId, board: { groupBy: 'status', persistKey: KEY } })
449
- const lanes = a.target.querySelectorAll('.sv-board-lane')
450
- fire(lanes[0]!.querySelector('.sv-board-card')!, 'dragstart')
451
- fire(lanes[1]!.querySelector('.sv-board-lane-body')!, 'dragover')
452
- fire(lanes[1]!.querySelector('.sv-board-lane-body')!, 'drop')
453
- const saved = JSON.parse(localStorage.getItem(KEY)!)
454
- expect(saved.laneOf['1']).toBe('done')
455
- a.destroy()
456
-
457
- // Remount from the same key: the moved card should reappear in done.
458
- const b = mountOn({ data, columns, getRowId: rowId, board: { groupBy: 'status', persistKey: KEY } })
459
- const bDone = b.target.querySelectorAll('.sv-board-lane')[1]!
460
- const titles = [...bDone.querySelectorAll('.sv-board-card-title')].map((n) => n.textContent)
461
- expect(titles).toContain('Design spec')
462
- b.destroy()
463
- })
464
-
465
- it('fires onLayoutChange with the serialized layout on change', () => {
466
- const onLayoutChange = vi.fn()
467
- const { target, destroy } = mountOn({ data, columns, getRowId: rowId, board: { groupBy: 'status', onLayoutChange } })
468
- const lanes = target.querySelectorAll('.sv-board-lane')
469
- fire(lanes[0]!.querySelector('.sv-board-card')!, 'dragstart')
470
- fire(lanes[1]!.querySelector('.sv-board-lane-body')!, 'dragover')
471
- fire(lanes[1]!.querySelector('.sv-board-lane-body')!, 'drop')
472
- expect(onLayoutChange).toHaveBeenCalled()
473
- const last = onLayoutChange.mock.calls.at(-1)![0]
474
- expect(last.laneOf['1']).toBe('done')
475
- destroy()
476
- })
477
- })
478
-
479
- describe('SvGridBoard sub-tasks', () => {
480
- const rowId = (r: any) => String(r.id)
481
- const subData = [
482
- { id: 1, title: 'Parent A', status: 'todo', items: [{ id: 'x', title: 'one', done: true }, { id: 'y', title: 'two', done: false }] },
483
- { id: 2, title: 'Parent B', status: 'done', items: [] },
484
- ]
485
- const subCols = [{ field: 'title', header: 'Title' }, { field: 'status', header: 'Status' }]
486
-
487
- it('shows a progress count from the subtasks field', () => {
488
- const { target, destroy } = mountOn({ data: subData, columns: subCols, getRowId: rowId, board: { groupBy: 'status', subtasks: 'items' } })
489
- try {
490
- expect(target.querySelector('.sv-board-subs-count')?.textContent).toBe('1/2')
491
- } finally { destroy() }
492
- })
493
-
494
- it('expands to a checklist and toggling fires onSubtaskToggle + updates progress', () => {
495
- const onSubtaskToggle = vi.fn()
496
- const { target, destroy } = mountOn({ data: subData, columns: subCols, getRowId: rowId, board: { groupBy: 'status', subtasks: 'items', onSubtaskToggle } })
497
- try {
498
- target.querySelector<HTMLButtonElement>('.sv-board-subs-head')!.click()
499
- flushSync()
500
- const boxes = target.querySelectorAll<HTMLInputElement>('.sv-board-subs-list input')
501
- expect(boxes).toHaveLength(2)
502
- boxes[1]!.click() // check "two"
503
- flushSync()
504
- expect(onSubtaskToggle).toHaveBeenCalledWith(expect.objectContaining({ id: 1 }), 'y', true)
505
- expect(target.querySelector('.sv-board-subs-count')?.textContent).toBe('2/2')
506
- } finally { destroy() }
507
- })
508
-
509
- it('adds a subtask via the inline input (onSubtaskAdd + progress grows)', () => {
510
- const onSubtaskAdd = vi.fn()
511
- const { target, destroy } = mountOn({ data: subData, columns: subCols, getRowId: rowId, board: { groupBy: 'status', subtasks: 'items', onSubtaskAdd } })
512
- try {
513
- target.querySelector<HTMLButtonElement>('.sv-board-subs-head')!.click()
514
- flushSync()
515
- const input = target.querySelector<HTMLInputElement>('.sv-board-subs-add')!
516
- input.value = 'three'
517
- input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }))
518
- flushSync()
519
- expect(onSubtaskAdd).toHaveBeenCalledWith(expect.objectContaining({ id: 1 }), 'three')
520
- expect(target.querySelector('.sv-board-subs-count')?.textContent).toBe('1/3')
521
- } finally { destroy() }
522
- })
523
- })
524
-
525
- describe('SvGridBoard card badges', () => {
526
- const badgeData = [{ id: 1, title: 'A', status: 'todo', labels: ['bug', 'urgent'], due: '2020-01-01', people: ['Sam Rivera', 'Lee Park'] }]
527
- const badgeCols = [{ field: 'title', header: 'Title' }, { field: 'status', header: 'Status' }]
528
-
529
- it('renders label, due (overdue), and assignee badges', () => {
530
- const { target, destroy } = mountOn({ data: badgeData, columns: badgeCols, board: { groupBy: 'status', labelsField: 'labels', dueField: 'due', assigneesField: 'people' } })
531
- try {
532
- expect(target.querySelectorAll('.sv-board-badge.is-label')).toHaveLength(2)
533
- const due = target.querySelector('.sv-board-badge.is-due')!
534
- expect(due.classList.contains('is-overdue')).toBe(true)
535
- expect(target.querySelectorAll('.sv-board-avatar')).toHaveLength(2)
536
- } finally { destroy() }
537
- })
538
- })
539
-
540
- describe('SvGridBoard quick-add composer', () => {
541
- it('opens an input and Enter calls onCardAdd(lane, title)', () => {
542
- const onCardAdd = vi.fn()
543
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', composer: true, onCardAdd } })
544
- try {
545
- const btn = target.querySelector<HTMLButtonElement>('.sv-board-composer-btn')!
546
- expect(btn).not.toBeNull()
547
- btn.click()
548
- flushSync()
549
- const input = target.querySelector<HTMLInputElement>('.sv-board-composer-input')!
550
- input.value = 'New card'
551
- input.dispatchEvent(new Event('input', { bubbles: true }))
552
- flushSync()
553
- input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }))
554
- flushSync()
555
- expect(onCardAdd).toHaveBeenCalledWith('todo', 'New card')
556
- } finally { destroy() }
557
- })
558
- })
559
-
560
- describe('SvGridBoard lane reorder', () => {
561
- it('drag a lane header to reorder lanes + fire onLaneReorder', () => {
562
- const onLaneReorder = vi.fn()
563
- const board = {
564
- groupBy: 'status',
565
- lanes: [{ id: 'todo', title: 'To do' }, { id: 'done', title: 'Done' }],
566
- reorderableLanes: true,
567
- onLaneReorder,
568
- }
569
- const { target, destroy } = mountOn({ data, columns, board })
570
- try {
571
- const heads = target.querySelectorAll('.sv-board-lane-head')
572
- fire(heads[1]!, 'dragstart') // grab "Done"
573
- fire(heads[0]!, 'dragover') // over "To do"
574
- fire(heads[0]!, 'drop')
575
- const titles = [...target.querySelectorAll('.sv-board-lane-title')].map((n) => n.textContent)
576
- expect(titles).toEqual(['Done', 'To do'])
577
- expect(onLaneReorder).toHaveBeenCalledWith(['done', 'todo'])
578
- } finally { destroy() }
579
- })
580
- })
581
-
582
- describe('SvGridBoard card context menu', () => {
583
- it('right-click opens a menu; an item runs its action (board-native moveTo)', () => {
584
- const onCardMove = vi.fn()
585
- const board = {
586
- groupBy: 'status',
587
- lanes: [{ id: 'todo', title: 'To do' }, { id: 'done', title: 'Done' }],
588
- onCardMove,
589
- cardMenu: (_row: any, ctx: any) => [
590
- { label: 'Move to Done', onSelect: () => ctx.moveTo('done') },
591
- { separator: true },
592
- { label: 'Edit', onSelect: () => ctx.edit() },
593
- ],
594
- }
595
- const { target, destroy } = mountOn({ data, columns, getRowId: (r: any) => String(r.id), board })
596
- try {
597
- const card = target.querySelector('.sv-board-card')! // "Design spec" (todo)
598
- card.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true, cancelable: true, clientX: 20, clientY: 20 }))
599
- flushSync()
600
- const menu = document.body.querySelector('.sv-board-ctx')
601
- expect(menu).not.toBeNull()
602
- const items = [...document.body.querySelectorAll('.sv-board-ctx [role="menuitem"]')]
603
- const move = items.find((i) => i.textContent?.includes('Move to Done'))! as HTMLElement
604
- move.click()
605
- flushSync()
606
- expect(onCardMove).toHaveBeenCalled()
607
- expect(onCardMove.mock.calls.at(-1)![0].toLane).toBe('done')
608
- expect(document.body.querySelector('.sv-board-ctx')).toBeNull() // closed
609
- } finally { destroy() }
610
- })
611
- })
612
-
613
- describe('SvGridBoard collapsible swimlanes + meta badges', () => {
614
- it('collapsibleSwimlanes: a toggle hides the band lanes', () => {
615
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', swimlaneBy: 'owner', collapsibleSwimlanes: true } })
616
- try {
617
- const band = target.querySelector('.sv-board-swim')!
618
- expect(band.querySelector('.sv-board-lanes')).not.toBeNull()
619
- band.querySelector<HTMLButtonElement>('.sv-board-swim-toggle')!.click()
620
- flushSync()
621
- expect(band.querySelector('.sv-board-lanes')).toBeNull()
622
- } finally { destroy() }
623
- })
624
-
625
- it('renders comment + attachment count badges and a cover strip', () => {
626
- const richData = [{ id: 1, title: 'A', status: 'todo', comments: ['a', 'b', 'c'], files: 2, cover: '#ff0000' }]
627
- const richCols = [{ field: 'title', header: 'Title' }, { field: 'status', header: 'Status' }]
628
- const { target, destroy } = mountOn({ data: richData, columns: richCols, board: { groupBy: 'status', commentsField: 'comments', attachmentsField: 'files', coverField: 'cover' } })
629
- try {
630
- const metas = [...target.querySelectorAll('.sv-board-badge.is-meta')].map((n) => n.textContent?.trim())
631
- expect(metas).toEqual(['3', '2'])
632
- const cover = target.querySelector<HTMLElement>('.sv-board-card-cover')!
633
- expect(cover).not.toBeNull()
634
- expect(cover.style.background).toContain('rgb(255, 0, 0)')
635
- } finally { destroy() }
636
- })
637
- })
638
-
639
- describe('SvGridBoard power features', () => {
640
- const rowId = (r: any) => String(r.id)
641
- const pData = [
642
- { id: 1, title: 'A', status: 'todo', tag: 'bug', assignee: 'Sam', blocked: true, created: '2020-01-01' },
643
- { id: 2, title: 'B', status: 'todo', tag: 'feat', assignee: 'Lee', blocked: false, created: '2026-07-20' },
644
- { id: 3, title: 'C', status: 'done', tag: 'bug', assignee: 'Sam', blocked: false, created: '2026-07-01' },
645
- ]
646
- const pCols = [{ field: 'title', header: 'Title' }, { field: 'status', header: 'Status' }]
647
-
648
- it('flagField renders a blocked ribbon', () => {
649
- const { target, destroy } = mountOn({ data: pData, columns: pCols, board: { groupBy: 'status', flagField: 'blocked' } })
650
- try {
651
- const first = target.querySelector('.sv-board-card')!
652
- expect(first.classList.contains('is-flagged')).toBe(true)
653
- expect(first.querySelector('.sv-board-card-flag')).not.toBeNull()
654
- } finally { destroy() }
655
- })
656
-
657
- it('ageField renders an age badge', () => {
658
- const { target, destroy } = mountOn({ data: pData, columns: pCols, board: { groupBy: 'status', ageField: 'created' } })
659
- try {
660
- const age = target.querySelector('.sv-board-badge.is-meta[title="Age"]')
661
- expect(age?.textContent?.trim()).toBeTruthy()
662
- } finally { destroy() }
663
- })
664
-
665
- it('facets: a chip filters the visible cards', () => {
666
- const { target, destroy } = mountOn({ data: pData, columns: pCols, board: { groupBy: 'status', facets: ['tag'] } })
667
- try {
668
- const chips = [...target.querySelectorAll<HTMLButtonElement>('.sv-board-facet')]
669
- expect(chips).toHaveLength(2) // bug, feat
670
- const bug = chips.find((c) => c.textContent?.startsWith('bug'))!
671
- bug.click()
672
- flushSync()
673
- expect(target.querySelectorAll('.sv-board-card')).toHaveLength(2) // the two "bug" cards
674
- } finally { destroy() }
675
- })
676
-
677
- it('multi-select: ctrl-click selects, and dragging the selection moves all', () => {
678
- const onCardMove = vi.fn()
679
- const { target, destroy } = mountOn({ data: pData, columns: pCols, getRowId: rowId, board: { groupBy: 'status', selectable: true, onCardMove } })
680
- try {
681
- const todo = target.querySelectorAll('.sv-board-lane')[0]!
682
- const cards = todo.querySelectorAll('.sv-board-card')
683
- cards[0]!.dispatchEvent(new MouseEvent('click', { bubbles: true }))
684
- cards[1]!.dispatchEvent(new MouseEvent('click', { bubbles: true, ctrlKey: true }))
685
- flushSync()
686
- expect(cards[0]!.classList.contains('is-selected')).toBe(true)
687
- expect(cards[1]!.classList.contains('is-selected')).toBe(true)
688
- // drag one selected card to the done lane -> both move
689
- const doneBody = target.querySelectorAll('.sv-board-lane')[1]!.querySelector('.sv-board-lane-body')!
690
- fire(cards[0]!, 'dragstart')
691
- fire(doneBody, 'dragover')
692
- fire(doneBody, 'drop')
693
- expect(onCardMove).toHaveBeenCalledTimes(2)
694
- expect(onCardMove.mock.calls.every((c) => c[0].toLane === 'done')).toBe(true)
695
- } finally { destroy() }
696
- })
697
-
698
- it('laneMenu: right-click a lane header opens a menu', () => {
699
- const { target, destroy } = mountOn({ data: pData, columns: pCols, board: { groupBy: 'status', laneMenu: () => [{ label: 'Clear' }] } })
700
- try {
701
- const head = target.querySelector('.sv-board-lane-head')!
702
- head.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true, cancelable: true, clientX: 5, clientY: 5 }))
703
- flushSync()
704
- expect(document.body.querySelector('.sv-board-ctx')).not.toBeNull()
705
- } finally { destroy() }
706
- })
707
-
708
- it('childrenField: shows a count and expands to child cards', () => {
709
- const epicData = [{ id: 1, title: 'Epic', status: 'todo', children: [{ id: 11, title: 'Story A', status: 'todo' }, { id: 12, title: 'Story B', status: 'done' }] }]
710
- const { target, destroy } = mountOn({ data: epicData, columns: pCols, board: { groupBy: 'status', childrenField: 'children' } })
711
- try {
712
- const head = target.querySelector('.sv-board-kids-head')!
713
- expect(head.textContent).toContain('2')
714
- head.dispatchEvent(new MouseEvent('click', { bubbles: true }))
715
- flushSync()
716
- expect(target.querySelectorAll('.sv-board-kid')).toHaveLength(2)
717
- } finally { destroy() }
718
- })
719
- })
720
-
721
- describe('SvGridBoard lane rename + swimlane summary', () => {
722
- it('double-click a lane title to rename -> onLaneRename', () => {
723
- const onLaneRename = vi.fn()
724
- const board = { groupBy: 'status', lanes: [{ id: 'todo', title: 'To do' }, { id: 'done', title: 'Done' }], onLaneRename }
725
- const { target, destroy } = mountOn({ data, columns, board })
726
- try {
727
- target.querySelector('.sv-board-lane-title')!.dispatchEvent(new MouseEvent('dblclick', { bubbles: true }))
728
- flushSync()
729
- const input = target.querySelector<HTMLInputElement>('.sv-board-lane-rename')!
730
- input.value = 'Backlog'
731
- input.dispatchEvent(new Event('input', { bubbles: true }))
732
- flushSync()
733
- input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }))
734
- flushSync()
735
- expect(onLaneRename).toHaveBeenCalledWith('todo', 'Backlog')
736
- } finally { destroy() }
737
- })
738
-
739
- it('swimlaneSummary renders in each band header', () => {
740
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', swimlaneBy: 'owner', swimlaneSummary: (rows: any[]) => `${rows.length} items` } })
741
- try {
742
- const summaries = [...target.querySelectorAll('.sv-board-swim-summary')].map((n) => n.textContent)
743
- expect(summaries).toEqual(['2 items', '1 items']) // Sam: 2, Lee: 1
744
- } finally { destroy() }
745
- })
746
- })
747
-
748
- describe('SvGridBoard badges with a custom card snippet', () => {
749
- it('renders built-in comment/attachment badges below a custom card', () => {
750
- const cardSnippet = createRawSnippet((row: any) => ({
751
- render: () => `<div class="mycard">${row().title}</div>`,
752
- }))
753
- const richData = [{ id: 1, title: 'A', status: 'todo', comments: ['x', 'y'], files: 3 }]
754
- const richCols = [{ field: 'title', header: 'T' }, { field: 'status', header: 'S' }]
755
- const { target, destroy } = mountOn({ data: richData, columns: richCols, board: { groupBy: 'status', card: cardSnippet as any, commentsField: 'comments', attachmentsField: 'files' } })
756
- try {
757
- expect(target.querySelector('.mycard')).not.toBeNull() // custom card rendered
758
- const metas = [...target.querySelectorAll('.sv-board-badge.is-meta')].map((n) => n.textContent?.trim())
759
- expect(metas).toEqual(['2', '3']) // comments + attachments badges appended
760
- } finally { destroy() }
761
- })
762
- })
763
-
764
- describe('SvGridBoard built-in detail drawer', () => {
765
- const rowId = (r: any) => String(r.id)
766
-
767
- it('board.drawer opens an SvForm drawer with all fields; Save commits + closes', () => {
768
- const onCardCommit = vi.fn()
769
- const { target, destroy } = mountOn({ data, columns, getRowId: rowId, board: { groupBy: 'status', drawer: true, onCardCommit } })
770
- try {
771
- target.querySelector('.sv-board-card')!.dispatchEvent(new MouseEvent('dblclick', { bubbles: true }))
772
- flushSync()
773
- const drawer = document.body.querySelector('.sv-drawer')
774
- expect(drawer).not.toBeNull()
775
- const form = document.body.querySelector('.sv-form')!
776
- expect(form.querySelectorAll('input').length).toBeGreaterThanOrEqual(3) // title, owner, status
777
- const save = [...form.querySelectorAll('button')].find((b) => b.textContent?.trim() === 'Save')!
778
- save.click()
779
- flushSync()
780
- expect(onCardCommit).toHaveBeenCalled()
781
- expect(onCardCommit.mock.calls.at(-1)![0].values.title).toBe('Design spec')
782
- expect(document.body.querySelector('.sv-drawer')).toBeNull() // closed
783
- } finally { destroy() }
784
- })
785
-
786
- it('board.drawer.fields limits the drawer to a subset', () => {
787
- const { target, destroy } = mountOn({ data, columns, board: { groupBy: 'status', drawer: { fields: ['title'] } } })
788
- try {
789
- target.querySelector('.sv-board-card')!.dispatchEvent(new MouseEvent('dblclick', { bubbles: true }))
790
- flushSync()
791
- expect(document.body.querySelectorAll('.sv-form input')).toHaveLength(1) // only title
792
- } finally { destroy() }
793
- })
794
- })
795
-
796
- describe('SvGridBoard blocked badge + comments thread', () => {
797
- const rowId = (r: any) => String(r.id)
798
-
799
- it('flagField shows a "Blocked" badge, using a string value as the reason', () => {
800
- const d = [{ id: 1, title: 'A', status: 'todo', blocked: 'Waiting on API' }]
801
- const c = [{ field: 'title', header: 'T' }, { field: 'status', header: 'S' }]
802
- const { target, destroy } = mountOn({ data: d, columns: c, board: { groupBy: 'status', flagField: 'blocked' } })
803
- try {
804
- const badge = target.querySelector('.sv-board-badge.is-blocked')!
805
- expect(badge.textContent?.trim()).toBe('Blocked')
806
- expect(badge.getAttribute('title')).toBe('Waiting on API')
807
- } finally { destroy() }
808
- })
809
-
810
- it('comment badge expands a thread; add + delete fire the callbacks', () => {
811
- const onCommentAdd = vi.fn()
812
- const onCommentDelete = vi.fn()
813
- const d = [{ id: 1, title: 'A', status: 'todo', comments: [{ id: 'c1', text: 'Hi', author: 'Sam' }] }]
814
- const c = [{ field: 'title', header: 'T' }, { field: 'status', header: 'S' }]
815
- const { target, destroy } = mountOn({ data: d, columns: c, getRowId: rowId, board: { groupBy: 'status', commentsField: 'comments', onCommentAdd, onCommentDelete } })
816
- try {
817
- target.querySelector<HTMLButtonElement>('.sv-board-badge.is-btn')!.click()
818
- flushSync()
819
- expect(target.querySelector('.sv-board-comments')).not.toBeNull()
820
- expect(target.querySelectorAll('.sv-board-comment')).toHaveLength(1)
821
- // delete
822
- target.querySelector<HTMLButtonElement>('.sv-board-comment-del')!.click()
823
- flushSync()
824
- expect(onCommentDelete).toHaveBeenCalledWith(expect.objectContaining({ id: 1 }), 'c1')
825
- // write
826
- const input = target.querySelector<HTMLInputElement>('.sv-board-comment-add')!
827
- input.value = 'New comment'
828
- input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }))
829
- flushSync()
830
- expect(onCommentAdd).toHaveBeenCalledWith(expect.objectContaining({ id: 1 }), 'New comment')
831
- } finally { destroy() }
832
- })
833
- })
834
-
835
- describe('SvGridBoard blocked cards are locked from moving', () => {
836
- const rowId = (r: any) => String(r.id)
837
- const d = [
838
- { id: 1, title: 'A', status: 'todo', blocked: true },
839
- { id: 2, title: 'B', status: 'todo', blocked: false },
840
- ]
841
- const c = [{ field: 'title', header: 'T' }, { field: 'status', header: 'S' }]
842
- const lanes = [{ id: 'todo', title: 'To do' }, { id: 'done', title: 'Done' }]
843
-
844
- it('a blocked card is not draggable and a drag is rejected', () => {
845
- const onCardMove = vi.fn()
846
- const { target, destroy } = mountOn({ data: d, columns: c, getRowId: rowId, board: { groupBy: 'status', flagField: 'blocked', lanes, onCardMove } })
847
- try {
848
- const blocked = target.querySelector('.sv-board-card')! // "A" (blocked)
849
- expect(blocked.getAttribute('draggable')).toBe('false')
850
- expect(blocked.classList.contains('is-locked')).toBe(true)
851
- const doneBody = target.querySelectorAll('.sv-board-lane')[1]!.querySelector('.sv-board-lane-body')!
852
- fire(blocked, 'dragstart')
853
- fire(doneBody, 'dragover')
854
- fire(doneBody, 'drop')
855
- expect(onCardMove).not.toHaveBeenCalled()
856
- } finally { destroy() }
857
- })
858
-
859
- it('Space does not grab a blocked card', () => {
860
- const { target, destroy } = mountOn({ data: d, columns: c, getRowId: rowId, board: { groupBy: 'status', flagField: 'blocked', lanes } })
861
- try {
862
- const blocked = target.querySelector('.sv-board-card')!
863
- blocked.dispatchEvent(new KeyboardEvent('keydown', { key: ' ', bubbles: true, cancelable: true }))
864
- flushSync()
865
- expect(blocked.getAttribute('aria-grabbed')).toBe('false')
866
- } finally { destroy() }
867
- })
868
-
869
- it('flagBlocksMoves:false keeps a flagged card draggable', () => {
870
- const { target, destroy } = mountOn({ data: d, columns: c, getRowId: rowId, board: { groupBy: 'status', flagField: 'blocked', flagBlocksMoves: false, lanes } })
871
- try {
872
- const blocked = target.querySelector('.sv-board-card')!
873
- expect(blocked.getAttribute('draggable')).toBe('true')
874
- expect(blocked.classList.contains('is-locked')).toBe(false)
875
- } finally { destroy() }
876
- })
877
- })
878
-
879
- describe('SvGridBoard drawer: comments + no outside-close', () => {
880
- const rowId = (r: any) => String(r.id)
881
- const c = [{ field: 'title', header: 'T' }, { field: 'status', header: 'S' }]
882
-
883
- it('the detail drawer includes the comments thread; adding works there', () => {
884
- const onCommentAdd = vi.fn()
885
- const d = [{ id: 1, title: 'A', status: 'todo', comments: [{ id: 'c1', text: 'Hi', author: 'Sam' }] }]
886
- const { target, destroy } = mountOn({ data: d, columns: c, getRowId: rowId, board: { groupBy: 'status', drawer: true, commentsField: 'comments', onCommentAdd } })
887
- try {
888
- target.querySelector('.sv-board-card')!.dispatchEvent(new MouseEvent('dblclick', { bubbles: true }))
889
- flushSync()
890
- const box = document.body.querySelector('.sv-board-drawer-comments')!
891
- expect(box).not.toBeNull()
892
- expect(box.querySelectorAll('.sv-board-comment')).toHaveLength(1)
893
- const input = box.querySelector<HTMLInputElement>('.sv-board-comment-add')!
894
- input.value = 'From drawer'
895
- input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }))
896
- flushSync()
897
- expect(onCommentAdd).toHaveBeenCalledWith(expect.objectContaining({ id: 1 }), 'From drawer')
898
- } finally { destroy() }
899
- })
900
-
901
- it('the drawer stays open on an outside pointerdown (so opening a select does not close it)', () => {
902
- const d = [{ id: 1, title: 'A', status: 'todo' }]
903
- const { target, destroy } = mountOn({ data: d, columns: c, getRowId: rowId, board: { groupBy: 'status', drawer: true } })
904
- try {
905
- target.querySelector('.sv-board-card')!.dispatchEvent(new MouseEvent('dblclick', { bubbles: true }))
906
- flushSync()
907
- expect(document.body.querySelector('.sv-drawer')).not.toBeNull()
908
- document.body.dispatchEvent(new MouseEvent('pointerdown', { bubbles: true }))
909
- flushSync()
910
- expect(document.body.querySelector('.sv-drawer')).not.toBeNull() // still open
911
- } finally { destroy() }
912
- })
913
- })
914
-
915
- describe('popover editors nest in the dismissable stack', () => {
916
- it('a dropdown opened inside a dialog does not dismiss the dialog when you click an option', () => {
917
- const dialogEl = document.createElement('div')
918
- document.body.appendChild(dialogEl)
919
- const onDialogDismiss = vi.fn()
920
- const dialog = createDismissableLayer({ element: () => dialogEl, onDismiss: onDialogDismiss })
921
- dialog.activate()
922
- const app = mount(SvDropDownList as any, {
923
- target: dialogEl,
924
- props: { options: [{ value: 'a', label: 'A' }, { value: 'b', label: 'B' }], value: 'a' } as any,
925
- })
926
- flushSync()
927
- try {
928
- dialogEl.querySelector('button')!.dispatchEvent(new MouseEvent('click', { bubbles: true }))
929
- flushSync()
930
- const panel = document.body.querySelector('.sv-ddl__panel')
931
- expect(panel).not.toBeNull() // dropdown open (portalled)
932
- panel!.dispatchEvent(new MouseEvent('pointerdown', { bubbles: true }))
933
- flushSync()
934
- expect(onDialogDismiss).not.toHaveBeenCalled() // dialog survives the option click
935
- } finally {
936
- dialog.release()
937
- unmount(app)
938
- dialogEl.remove()
939
- }
940
- })
941
- })