@svgrid/enterprise 2.5.2 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (620) 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/dist/SvExpressionEditor.svelte.d.ts +12 -0
  8. package/dist/SvFileInput.svelte.d.ts +20 -0
  9. package/dist/SvGridAlerts.svelte.d.ts +77 -0
  10. package/dist/SvGridBoard.svelte.d.ts +30 -0
  11. package/dist/SvGridEditPanel.svelte.d.ts +73 -0
  12. package/dist/SvGridMasterDetail.svelte.d.ts +49 -0
  13. package/dist/SvGridScheduler.svelte.d.ts +30 -0
  14. package/dist/SvImportDialog.svelte.d.ts +88 -0
  15. package/dist/SvLookupInput.svelte.d.ts +21 -0
  16. package/dist/SvPivotDesigner.svelte.d.ts +176 -0
  17. package/dist/SvRecordDetail.svelte.d.ts +58 -0
  18. package/dist/SvSchedule.svelte.d.ts +29 -0
  19. package/dist/SvSchemaChart.svelte.d.ts +61 -0
  20. package/dist/SvSchemaDashboard.svelte.d.ts +46 -0
  21. package/dist/alerts/alert-engine-attach.d.ts +79 -0
  22. package/dist/alerts/alert-engine-attach.js +106 -0
  23. package/dist/alerts/alert-engine.d.ts +42 -0
  24. package/dist/alerts/alert-engine.js +196 -0
  25. package/dist/alerts/alert-formats.d.ts +26 -0
  26. package/dist/alerts/alert-formats.js +58 -0
  27. package/dist/alerts/alert-observer.d.ts +54 -0
  28. package/dist/alerts/alert-observer.js +156 -0
  29. package/dist/alerts/alert-scheduler.d.ts +30 -0
  30. package/dist/alerts/alert-scheduler.js +54 -0
  31. package/dist/alerts/alert-storage.d.ts +31 -0
  32. package/dist/alerts/alert-storage.js +92 -0
  33. package/dist/alerts/alert-store.svelte.d.ts +24 -0
  34. package/dist/alerts/alert-store.svelte.js +69 -0
  35. package/dist/alerts/alert-types.d.ts +86 -0
  36. package/dist/alerts/alert-types.js +1 -0
  37. package/dist/alerts.d.ts +2 -0
  38. package/{src/alerts.ts → dist/alerts.js} +9 -9
  39. package/dist/board.d.ts +7 -0
  40. package/{src/board.ts → dist/board.js} +13 -14
  41. package/dist/cdn/svgrid-enterprise.svelte-external.js +2987 -2981
  42. package/dist/designer/assets/{index-CM5xvaOy.js → index-BF0UH638.js} +3 -3
  43. package/dist/designer/assets/{src-D-ET9Mmo.js → src-BPJruwB9.js} +184 -184
  44. package/dist/designer/index.html +2 -2
  45. package/dist/edit-panel.d.ts +105 -0
  46. package/dist/edit-panel.js +350 -0
  47. package/dist/export-conditional.d.ts +31 -0
  48. package/dist/export-conditional.js +65 -0
  49. package/dist/export-ooxml.d.ts +93 -0
  50. package/dist/export-ooxml.js +385 -0
  51. package/dist/export-pdf.d.ts +107 -0
  52. package/dist/export-pdf.js +144 -0
  53. package/dist/export-print.d.ts +55 -0
  54. package/dist/export-print.js +91 -0
  55. package/{src/export-serialize.ts → dist/export-serialize.d.ts} +11 -24
  56. package/dist/export-serialize.js +11 -0
  57. package/dist/export-xls.d.ts +26 -0
  58. package/dist/export-xls.js +157 -0
  59. package/dist/export.d.ts +323 -0
  60. package/dist/export.js +1021 -0
  61. package/dist/expressions/evaluate.d.ts +17 -0
  62. package/dist/expressions/evaluate.js +214 -0
  63. package/dist/expressions/expression-columns.d.ts +61 -0
  64. package/dist/expressions/expression-columns.js +72 -0
  65. package/dist/expressions/expression-types.d.ts +125 -0
  66. package/dist/expressions/expression-types.js +1 -0
  67. package/dist/expressions/parse.d.ts +25 -0
  68. package/dist/expressions/parse.js +537 -0
  69. package/dist/import.d.ts +232 -0
  70. package/dist/import.js +846 -0
  71. package/dist/index.d.ts +66 -0
  72. package/dist/index.js +91 -0
  73. package/dist/install.d.ts +70 -0
  74. package/dist/install.js +61 -0
  75. package/dist/license-core.d.ts +37 -0
  76. package/dist/license-core.js +81 -0
  77. package/dist/license.d.ts +30 -0
  78. package/dist/license.js +139 -0
  79. package/dist/master-detail.d.ts +23 -0
  80. package/dist/master-detail.js +35 -0
  81. package/dist/node/studio.js +1 -1
  82. package/dist/pivot-chart.d.ts +28 -0
  83. package/dist/pivot-chart.js +71 -0
  84. package/dist/pivot-designer.d.ts +69 -0
  85. package/dist/pivot-designer.js +38 -0
  86. package/dist/pivot-enable.d.ts +6 -0
  87. package/{src/pivot-enable.ts → dist/pivot-enable.js} +13 -18
  88. package/dist/pivot.d.ts +111 -0
  89. package/dist/pivot.js +353 -0
  90. package/dist/print.d.ts +33 -0
  91. package/dist/print.js +61 -0
  92. package/dist/revoked.d.ts +1 -0
  93. package/{src/revoked.ts → dist/revoked.js} +5 -6
  94. package/dist/scheduler-assignments.d.ts +64 -0
  95. package/dist/scheduler-assignments.js +92 -0
  96. package/dist/scheduler-axis.d.ts +81 -0
  97. package/dist/scheduler-axis.js +180 -0
  98. package/{src/scheduler-booking.ts → dist/scheduler-booking.d.ts} +10 -43
  99. package/dist/scheduler-booking.js +50 -0
  100. package/dist/scheduler-config.d.ts +177 -0
  101. package/dist/scheduler-config.js +1 -0
  102. package/dist/scheduler-dependencies.d.ts +89 -0
  103. package/dist/scheduler-dependencies.js +179 -0
  104. package/dist/scheduler-freebusy.d.ts +19 -0
  105. package/{src/scheduler-freebusy.ts → dist/scheduler-freebusy.js} +9 -19
  106. package/{src/scheduler-heatmap.ts → dist/scheduler-heatmap.d.ts} +12 -35
  107. package/dist/scheduler-heatmap.js +41 -0
  108. package/dist/scheduler-resource-tree.d.ts +48 -0
  109. package/dist/scheduler-resource-tree.js +78 -0
  110. package/dist/scheduler-slots.d.ts +37 -0
  111. package/dist/scheduler-slots.js +80 -0
  112. package/dist/scheduler-summary.d.ts +41 -0
  113. package/dist/scheduler-summary.js +54 -0
  114. package/dist/scheduler.d.ts +7 -0
  115. package/{src/scheduler.ts → dist/scheduler.js} +13 -14
  116. package/dist/scheduling.d.ts +132 -0
  117. package/dist/scheduling.js +228 -0
  118. package/dist/schema-designer.d.ts +42 -0
  119. package/dist/schema-designer.js +117 -0
  120. package/dist/schema.d.ts +369 -0
  121. package/dist/schema.js +216 -0
  122. package/dist/smart-shim.d.ts +62 -0
  123. package/dist/smart-shim.js +34 -0
  124. package/dist/sources/aggregate.d.ts +43 -0
  125. package/dist/sources/aggregate.js +60 -0
  126. package/dist/sources/auth-supabase.d.ts +69 -0
  127. package/dist/sources/auth-supabase.js +39 -0
  128. package/dist/sources/dashboard.d.ts +65 -0
  129. package/dist/sources/dashboard.js +95 -0
  130. package/dist/sources/field-inference.d.ts +23 -0
  131. package/dist/sources/field-inference.js +52 -0
  132. package/dist/sources/filters.d.ts +35 -0
  133. package/dist/sources/filters.js +52 -0
  134. package/dist/sources/index.d.ts +18 -0
  135. package/dist/sources/index.js +18 -0
  136. package/dist/sources/introspect-supabase.d.ts +30 -0
  137. package/dist/sources/introspect-supabase.js +134 -0
  138. package/dist/sources/realtime-supabase.d.ts +37 -0
  139. package/dist/sources/realtime-supabase.js +52 -0
  140. package/dist/sources/relation-lookup.d.ts +50 -0
  141. package/dist/sources/relation-lookup.js +77 -0
  142. package/dist/sources/rest-adapters.d.ts +48 -0
  143. package/dist/sources/rest-adapters.js +85 -0
  144. package/dist/sources/rest.d.ts +38 -0
  145. package/dist/sources/rest.js +86 -0
  146. package/dist/sources/schema-from-columns.d.ts +37 -0
  147. package/dist/sources/schema-from-columns.js +48 -0
  148. package/dist/sources/supabase.d.ts +33 -0
  149. package/dist/sources/supabase.js +74 -0
  150. package/dist/sources/with-entity-rules.d.ts +25 -0
  151. package/dist/sources/with-entity-rules.js +47 -0
  152. package/dist/sources/with-relation-labels.d.ts +26 -0
  153. package/dist/sources/with-relation-labels.js +38 -0
  154. package/dist/staged-editing.d.ts +85 -0
  155. package/dist/staged-editing.js +0 -0
  156. package/dist/studio/bug-report.d.ts +61 -0
  157. package/dist/studio/bug-report.js +126 -0
  158. package/dist/studio/cli.d.ts +56 -0
  159. package/dist/studio/cli.js +70 -0
  160. package/dist/studio/copilot-core.d.ts +22 -0
  161. package/{src/studio/copilot-core.ts → dist/studio/copilot-core.js} +34 -38
  162. package/dist/studio/csv.d.ts +36 -0
  163. package/dist/studio/csv.js +173 -0
  164. package/dist/studio/db-connect-string.d.ts +45 -0
  165. package/dist/studio/db-connect-string.js +113 -0
  166. package/dist/studio/deploy-cli.d.ts +35 -0
  167. package/dist/studio/deploy-cli.js +81 -0
  168. package/dist/studio/emit-project.d.ts +77 -0
  169. package/dist/studio/emit-project.js +5389 -0
  170. package/dist/studio/emit-schema.d.ts +110 -0
  171. package/dist/studio/emit-schema.js +1128 -0
  172. package/dist/studio/index.d.ts +35 -0
  173. package/dist/studio/index.js +38 -0
  174. package/dist/studio/init-flow.d.ts +58 -0
  175. package/dist/studio/init-flow.js +451 -0
  176. package/dist/studio/introspect-db.d.ts +47 -0
  177. package/dist/studio/introspect-db.js +255 -0
  178. package/dist/studio/introspect-openapi.d.ts +19 -0
  179. package/dist/studio/introspect-openapi.js +244 -0
  180. package/dist/studio/introspect-prisma.d.ts +25 -0
  181. package/dist/studio/introspect-prisma.js +164 -0
  182. package/dist/studio/introspect.d.ts +35 -0
  183. package/dist/studio/introspect.js +306 -0
  184. package/dist/studio/project.d.ts +1327 -0
  185. package/dist/studio/project.js +1798 -0
  186. package/dist/studio/sample-data.d.ts +19 -0
  187. package/dist/studio/sample-data.js +207 -0
  188. package/dist/studio/samples/ats.d.ts +2 -0
  189. package/dist/studio/samples/ats.js +194 -0
  190. package/dist/studio/samples/clinic.d.ts +2 -0
  191. package/dist/studio/samples/clinic.js +171 -0
  192. package/dist/studio/samples/crm.d.ts +2 -0
  193. package/dist/studio/samples/crm.js +280 -0
  194. package/dist/studio/samples/datasets.d.ts +38 -0
  195. package/dist/studio/samples/datasets.js +296 -0
  196. package/dist/studio/samples/ecommerce.d.ts +2 -0
  197. package/dist/studio/samples/ecommerce.js +178 -0
  198. package/dist/studio/samples/events.d.ts +2 -0
  199. package/dist/studio/samples/events.js +192 -0
  200. package/dist/studio/samples/fleet.d.ts +2 -0
  201. package/dist/studio/samples/fleet.js +203 -0
  202. package/dist/studio/samples/gym.d.ts +2 -0
  203. package/dist/studio/samples/gym.js +205 -0
  204. package/dist/studio/samples/hr.d.ts +2 -0
  205. package/dist/studio/samples/hr.js +186 -0
  206. package/dist/studio/samples/index.d.ts +13 -0
  207. package/dist/studio/samples/index.js +44 -0
  208. package/dist/studio/samples/insurance.d.ts +2 -0
  209. package/dist/studio/samples/insurance.js +220 -0
  210. package/dist/studio/samples/inventory.d.ts +2 -0
  211. package/dist/studio/samples/inventory.js +204 -0
  212. package/dist/studio/samples/invoicing.d.ts +2 -0
  213. package/dist/studio/samples/invoicing.js +154 -0
  214. package/dist/studio/samples/library.d.ts +2 -0
  215. package/dist/studio/samples/library.js +171 -0
  216. package/dist/studio/samples/live-data.d.ts +5 -0
  217. package/dist/studio/samples/live-data.js +261 -0
  218. package/dist/studio/samples/projects.d.ts +2 -0
  219. package/dist/studio/samples/projects.js +203 -0
  220. package/dist/studio/samples/realestate.d.ts +2 -0
  221. package/dist/studio/samples/realestate.js +187 -0
  222. package/dist/studio/samples/restaurant.d.ts +2 -0
  223. package/dist/studio/samples/restaurant.js +180 -0
  224. package/dist/studio/samples/school.d.ts +2 -0
  225. package/dist/studio/samples/school.js +188 -0
  226. package/dist/studio/samples/shared.d.ts +142 -0
  227. package/dist/studio/samples/shared.js +164 -0
  228. package/dist/studio/samples/starter.d.ts +4 -0
  229. package/dist/studio/samples/starter.js +237 -0
  230. package/dist/studio/samples/subscriptions.d.ts +2 -0
  231. package/dist/studio/samples/subscriptions.js +175 -0
  232. package/dist/studio/samples/support.d.ts +2 -0
  233. package/dist/studio/samples/support.js +209 -0
  234. package/dist/studio/scaffold-app.d.ts +22 -0
  235. package/{src/studio/scaffold-app.ts → dist/studio/scaffold-app.js} +45 -63
  236. package/dist/studio/scaffold.d.ts +63 -0
  237. package/dist/studio/scaffold.js +346 -0
  238. package/dist/studio/screen-suites.d.ts +193 -0
  239. package/dist/studio/screen-suites.js +297 -0
  240. package/dist/studio/themes.d.ts +34 -0
  241. package/dist/studio/themes.js +41 -0
  242. package/dist/studio/ui-components.d.ts +89 -0
  243. package/dist/studio/ui-components.generated.d.ts +29 -0
  244. package/dist/studio/ui-components.generated.js +7139 -0
  245. package/dist/studio/ui-components.js +673 -0
  246. package/dist/studio/user-error.d.ts +23 -0
  247. package/{src/studio/user-error.ts → dist/studio/user-error.js} +10 -13
  248. package/dist/studio/verify.d.ts +34 -0
  249. package/dist/studio/verify.js +47 -0
  250. package/dist/sveltekit/in-memory.d.ts +14 -0
  251. package/dist/sveltekit/in-memory.js +113 -0
  252. package/dist/sveltekit/index.d.ts +6 -0
  253. package/dist/sveltekit/index.js +5 -0
  254. package/dist/sveltekit/query-plan.d.ts +44 -0
  255. package/dist/sveltekit/query-plan.js +76 -0
  256. package/dist/sveltekit/sql-source.d.ts +47 -0
  257. package/dist/sveltekit/sql-source.js +106 -0
  258. package/dist/sveltekit/sql.d.ts +48 -0
  259. package/dist/sveltekit/sql.js +73 -0
  260. package/dist/sveltekit/transport.d.ts +209 -0
  261. package/dist/sveltekit/transport.js +219 -0
  262. package/{src/sveltekit/types.ts → dist/sveltekit/types.d.ts} +8 -11
  263. package/dist/sveltekit/types.js +1 -0
  264. package/dist/upgrade-prompt.d.ts +16 -0
  265. package/dist/upgrade-prompt.js +141 -0
  266. package/dist/version.d.ts +13 -0
  267. package/{src/version.ts → dist/version.js} +1 -1
  268. package/dist/watermark.d.ts +2 -0
  269. package/dist/watermark.js +146 -0
  270. package/package.json +26 -24
  271. package/src/SvBoard.dom.test.ts +0 -67
  272. package/src/SvGridAlerts.dom.test.ts +0 -113
  273. package/src/SvGridEditPanel.dom.test.ts +0 -320
  274. package/src/SvRecordDetail.dom.test.ts +0 -137
  275. package/src/SvSchedule.dom.test.ts +0 -57
  276. package/src/ai-export-pdf.dom.test.ts +0 -77
  277. package/src/ai-export-xlsx.dom.test.ts +0 -90
  278. package/src/ai-export.dom.test.ts +0 -114
  279. package/src/alerts/alert-engine-attach.ts +0 -165
  280. package/src/alerts/alert-engine.test.ts +0 -135
  281. package/src/alerts/alert-engine.ts +0 -260
  282. package/src/alerts/alert-formats.test.ts +0 -87
  283. package/src/alerts/alert-formats.ts +0 -77
  284. package/src/alerts/alert-observer.test.ts +0 -189
  285. package/src/alerts/alert-observer.ts +0 -208
  286. package/src/alerts/alert-scheduler.ts +0 -96
  287. package/src/alerts/alert-storage.test.ts +0 -54
  288. package/src/alerts/alert-storage.ts +0 -116
  289. package/src/alerts/alert-store.svelte.ts +0 -80
  290. package/src/alerts/alert-types.ts +0 -94
  291. package/src/board.dom.test.ts +0 -941
  292. package/src/edit-panel.test.ts +0 -322
  293. package/src/edit-panel.ts +0 -379
  294. package/src/export-conditional.test.ts +0 -60
  295. package/src/export-conditional.ts +0 -94
  296. package/src/export-ooxml.test.ts +0 -152
  297. package/src/export-ooxml.ts +0 -489
  298. package/src/export-pdf.test.ts +0 -138
  299. package/src/export-pdf.ts +0 -245
  300. package/src/export-print.test.ts +0 -66
  301. package/src/export-print.ts +0 -132
  302. package/src/export-serialize.test.ts +0 -56
  303. package/src/export-xls.ts +0 -199
  304. package/src/export-xlsx-roundtrip.test.ts +0 -120
  305. package/src/export-xlsx.test.ts +0 -150
  306. package/src/export.test.ts +0 -349
  307. package/src/export.ts +0 -1464
  308. package/src/expressions/evaluate.test.ts +0 -111
  309. package/src/expressions/evaluate.ts +0 -237
  310. package/src/expressions/expression-columns.ts +0 -133
  311. package/src/expressions/expression-types.ts +0 -84
  312. package/src/expressions/parse.test.ts +0 -106
  313. package/src/expressions/parse.ts +0 -610
  314. package/src/import-automap.test.ts +0 -131
  315. package/src/import-hardening.test.ts +0 -158
  316. package/src/import.test.ts +0 -415
  317. package/src/import.ts +0 -1044
  318. package/src/index.ts +0 -569
  319. package/src/install.ts +0 -154
  320. package/src/license-core.test.ts +0 -23
  321. package/src/license-core.ts +0 -107
  322. package/src/license-expiry.test.ts +0 -127
  323. package/src/license.ts +0 -137
  324. package/src/master-detail.test.ts +0 -61
  325. package/src/master-detail.ts +0 -42
  326. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/_metadata.json +0 -178
  327. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/attachments-ZrPsKxob.js +0 -3875
  328. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/attachments-ZrPsKxob.js.map +0 -1
  329. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/constants-ACqvWGE2.js +0 -21
  330. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/constants-ACqvWGE2.js.map +0 -1
  331. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/dev-D3w5jt92.js +0 -1938
  332. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/dev-D3w5jt92.js.map +0 -1
  333. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/events-CC2V3H0y.js +0 -205
  334. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/events-CC2V3H0y.js.map +0 -1
  335. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/flags-BXP37tAa.js +0 -18
  336. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/flags-BXP37tAa.js.map +0 -1
  337. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/hydration-DwubnU5b.js +0 -264
  338. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/hydration-DwubnU5b.js.map +0 -1
  339. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/legacy-client-hD7f6PUz.js +0 -697
  340. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/legacy-client-hD7f6PUz.js.map +0 -1
  341. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte.js +0 -134
  342. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte.js.map +0 -1
  343. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_animate.js +0 -55
  344. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_animate.js.map +0 -1
  345. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_attachments.js +0 -2
  346. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_compiler.js +0 -46843
  347. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_compiler.js.map +0 -1
  348. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_easing.js +0 -237
  349. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_easing.js.map +0 -1
  350. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_events.js +0 -2
  351. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal.js +0 -4
  352. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal.js.map +0 -1
  353. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_client.js +0 -7
  354. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_disclose-version.js +0 -4
  355. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_disclose-version.js.map +0 -1
  356. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_async.js +0 -5
  357. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_async.js.map +0 -1
  358. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_legacy.js +0 -5
  359. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_legacy.js.map +0 -1
  360. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_tracing.js +0 -5
  361. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_tracing.js.map +0 -1
  362. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_server.js +0 -6
  363. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_legacy.js +0 -83
  364. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_legacy.js.map +0 -1
  365. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_motion.js +0 -559
  366. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_motion.js.map +0 -1
  367. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity.js +0 -24
  368. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity.js.map +0 -1
  369. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity_window.js +0 -122
  370. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity_window.js.map +0 -1
  371. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_server.js +0 -2
  372. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_store.js +0 -89
  373. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_store.js.map +0 -1
  374. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_transition.js +0 -241
  375. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_transition.js.map +0 -1
  376. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-DBx1SCN6.js +0 -4938
  377. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-DBx1SCN6.js.map +0 -1
  378. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-gjfpSTFS.js +0 -495
  379. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-gjfpSTFS.js.map +0 -1
  380. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/validate-DKoOKg8S.js +0 -190
  381. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/validate-DKoOKg8S.js.map +0 -1
  382. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/version-C0MiR7eR.js +0 -8
  383. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/version-C0MiR7eR.js.map +0 -1
  384. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/warnings-B6Y7P0Q-.js +0 -138
  385. package/src/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/warnings-B6Y7P0Q-.js.map +0 -1
  386. package/src/pivot-chart.test.ts +0 -86
  387. package/src/pivot-chart.ts +0 -112
  388. package/src/pivot-designer.ts +0 -101
  389. package/src/pivot.test.ts +0 -335
  390. package/src/pivot.ts +0 -578
  391. package/src/print.ts +0 -107
  392. package/src/scheduler-assignments.test.ts +0 -97
  393. package/src/scheduler-assignments.ts +0 -134
  394. package/src/scheduler-axis.test.ts +0 -108
  395. package/src/scheduler-axis.ts +0 -238
  396. package/src/scheduler-booking.test.ts +0 -57
  397. package/src/scheduler-config.ts +0 -179
  398. package/src/scheduler-dependencies.test.ts +0 -155
  399. package/src/scheduler-dependencies.ts +0 -223
  400. package/src/scheduler-freebusy.test.ts +0 -41
  401. package/src/scheduler-heatmap.test.ts +0 -39
  402. package/src/scheduler-resource-tree.test.ts +0 -84
  403. package/src/scheduler-resource-tree.ts +0 -107
  404. package/src/scheduler-slots.test.ts +0 -53
  405. package/src/scheduler-slots.ts +0 -94
  406. package/src/scheduler-summary.test.ts +0 -47
  407. package/src/scheduler-summary.ts +0 -81
  408. package/src/scheduling.test.ts +0 -194
  409. package/src/scheduling.ts +0 -293
  410. package/src/schema-designer.test.ts +0 -121
  411. package/src/schema-designer.ts +0 -142
  412. package/src/schema.test.ts +0 -268
  413. package/src/schema.ts +0 -562
  414. package/src/smart-shim.ts +0 -107
  415. package/src/sources/aggregate.test.ts +0 -79
  416. package/src/sources/aggregate.ts +0 -102
  417. package/src/sources/auth-supabase.test.ts +0 -80
  418. package/src/sources/auth-supabase.ts +0 -87
  419. package/src/sources/dashboard.kpi.test.ts +0 -50
  420. package/src/sources/dashboard.test.ts +0 -61
  421. package/src/sources/dashboard.ts +0 -136
  422. package/src/sources/field-inference.test.ts +0 -60
  423. package/src/sources/field-inference.ts +0 -63
  424. package/src/sources/filters.test.ts +0 -58
  425. package/src/sources/filters.ts +0 -70
  426. package/src/sources/index.ts +0 -67
  427. package/src/sources/introspect-supabase.test.ts +0 -112
  428. package/src/sources/introspect-supabase.ts +0 -139
  429. package/src/sources/realtime-supabase.test.ts +0 -93
  430. package/src/sources/realtime-supabase.ts +0 -99
  431. package/src/sources/relation-lookup.test.ts +0 -99
  432. package/src/sources/relation-lookup.ts +0 -128
  433. package/src/sources/rest-adapters.test.ts +0 -95
  434. package/src/sources/rest-adapters.ts +0 -120
  435. package/src/sources/rest.test.ts +0 -104
  436. package/src/sources/rest.ts +0 -129
  437. package/src/sources/schema-from-columns.test.ts +0 -106
  438. package/src/sources/schema-from-columns.ts +0 -88
  439. package/src/sources/supabase.test.ts +0 -110
  440. package/src/sources/supabase.ts +0 -99
  441. package/src/sources/with-entity-rules.test.ts +0 -104
  442. package/src/sources/with-entity-rules.ts +0 -78
  443. package/src/sources/with-relation-labels.test.ts +0 -75
  444. package/src/sources/with-relation-labels.ts +0 -73
  445. package/src/staged-editing.ts +0 -0
  446. package/src/studio/bug-report.test.ts +0 -101
  447. package/src/studio/bug-report.ts +0 -165
  448. package/src/studio/cli.test.ts +0 -187
  449. package/src/studio/cli.ts +0 -117
  450. package/src/studio/copilot-core.test.ts +0 -45
  451. package/src/studio/csv.test.ts +0 -90
  452. package/src/studio/csv.ts +0 -165
  453. package/src/studio/db-connect-string.test.ts +0 -94
  454. package/src/studio/db-connect-string.ts +0 -128
  455. package/src/studio/deploy-cli.test.ts +0 -56
  456. package/src/studio/deploy-cli.ts +0 -100
  457. package/src/studio/emit-project.test.ts +0 -3324
  458. package/src/studio/emit-project.ts +0 -5377
  459. package/src/studio/emit-schema.test.ts +0 -111
  460. package/src/studio/emit-schema.ts +0 -1181
  461. package/src/studio/index.ts +0 -380
  462. package/src/studio/init-flow.test.ts +0 -514
  463. package/src/studio/init-flow.ts +0 -556
  464. package/src/studio/introspect-db.test.ts +0 -186
  465. package/src/studio/introspect-db.ts +0 -312
  466. package/src/studio/introspect-openapi.test.ts +0 -84
  467. package/src/studio/introspect-openapi.ts +0 -252
  468. package/src/studio/introspect-prisma.test.ts +0 -99
  469. package/src/studio/introspect-prisma.ts +0 -175
  470. package/src/studio/introspect.test.ts +0 -172
  471. package/src/studio/introspect.ts +0 -310
  472. package/src/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/_svelte_metadata.json +0 -1
  473. package/src/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/package.json +0 -3
  474. package/src/studio/pipeline.test.ts +0 -42
  475. package/src/studio/project-robust.test.ts +0 -157
  476. package/src/studio/project.test.ts +0 -929
  477. package/src/studio/project.ts +0 -2394
  478. package/src/studio/sample-data.test.ts +0 -58
  479. package/src/studio/sample-data.ts +0 -203
  480. package/src/studio/samples/ats.ts +0 -202
  481. package/src/studio/samples/clinic.ts +0 -179
  482. package/src/studio/samples/crm.ts +0 -291
  483. package/src/studio/samples/datasets.test.ts +0 -84
  484. package/src/studio/samples/datasets.ts +0 -340
  485. package/src/studio/samples/ecommerce.ts +0 -187
  486. package/src/studio/samples/events.ts +0 -201
  487. package/src/studio/samples/fleet.ts +0 -213
  488. package/src/studio/samples/gym.ts +0 -215
  489. package/src/studio/samples/hr.ts +0 -195
  490. package/src/studio/samples/index.ts +0 -55
  491. package/src/studio/samples/insurance.ts +0 -229
  492. package/src/studio/samples/inventory.ts +0 -213
  493. package/src/studio/samples/invoicing.ts +0 -162
  494. package/src/studio/samples/library.ts +0 -180
  495. package/src/studio/samples/live-data.test.ts +0 -99
  496. package/src/studio/samples/live-data.ts +0 -306
  497. package/src/studio/samples/projects.ts +0 -212
  498. package/src/studio/samples/realestate.ts +0 -196
  499. package/src/studio/samples/restaurant.ts +0 -189
  500. package/src/studio/samples/samples.test.ts +0 -304
  501. package/src/studio/samples/school.ts +0 -197
  502. package/src/studio/samples/seed-floor.test.ts +0 -25
  503. package/src/studio/samples/shared.ts +0 -237
  504. package/src/studio/samples/starter.ts +0 -251
  505. package/src/studio/samples/subscriptions.ts +0 -183
  506. package/src/studio/samples/support.ts +0 -216
  507. package/src/studio/scaffold-app.test.ts +0 -91
  508. package/src/studio/scaffold.test.ts +0 -192
  509. package/src/studio/scaffold.ts +0 -390
  510. package/src/studio/screen-suites.test.ts +0 -269
  511. package/src/studio/screen-suites.ts +0 -448
  512. package/src/studio/themes.ts +0 -62
  513. package/src/studio/ui-components-surface.test.ts +0 -185
  514. package/src/studio/ui-components.generated.ts +0 -7154
  515. package/src/studio/ui-components.ts +0 -742
  516. package/src/studio/verify.test.ts +0 -47
  517. package/src/studio/verify.ts +0 -79
  518. package/src/sveltekit/in-memory.test.ts +0 -104
  519. package/src/sveltekit/in-memory.ts +0 -129
  520. package/src/sveltekit/index.ts +0 -24
  521. package/src/sveltekit/query-plan.test.ts +0 -109
  522. package/src/sveltekit/query-plan.ts +0 -125
  523. package/src/sveltekit/sql-source.test.ts +0 -198
  524. package/src/sveltekit/sql-source.ts +0 -171
  525. package/src/sveltekit/sql.test.ts +0 -80
  526. package/src/sveltekit/sql.ts +0 -131
  527. package/src/sveltekit/transport-scope.test.ts +0 -125
  528. package/src/sveltekit/transport.test.ts +0 -201
  529. package/src/sveltekit/transport.ts +0 -373
  530. package/src/upgrade-prompt.test.ts +0 -71
  531. package/src/upgrade-prompt.ts +0 -162
  532. package/src/version.test.ts +0 -17
  533. package/src/watermark.test.ts +0 -97
  534. package/src/watermark.ts +0 -156
  535. /package/{src → dist}/SvAlertRuleEditor.svelte +0 -0
  536. /package/{src → dist}/SvAlertsManager.svelte +0 -0
  537. /package/{src → dist}/SvAlertsPanel.svelte +0 -0
  538. /package/{src → dist}/SvAuthGate.svelte +0 -0
  539. /package/{src → dist}/SvBoard.svelte +0 -0
  540. /package/{src → dist}/SvExportMenu.svelte +0 -0
  541. /package/{src → dist}/SvExpressionEditor.svelte +0 -0
  542. /package/{src → dist}/SvFileInput.svelte +0 -0
  543. /package/{src → dist}/SvGridAlerts.svelte +0 -0
  544. /package/{src → dist}/SvGridBoard.svelte +0 -0
  545. /package/{src → dist}/SvGridEditPanel.svelte +0 -0
  546. /package/{src → dist}/SvGridMasterDetail.svelte +0 -0
  547. /package/{src → dist}/SvGridScheduler.svelte +0 -0
  548. /package/{src → dist}/SvImportDialog.svelte +0 -0
  549. /package/{src → dist}/SvLookupInput.svelte +0 -0
  550. /package/{src → dist}/SvPivotDesigner.svelte +0 -0
  551. /package/{src → dist}/SvRecordDetail.svelte +0 -0
  552. /package/{src → dist}/SvSchedule.svelte +0 -0
  553. /package/{src → dist}/SvSchemaChart.svelte +0 -0
  554. /package/{src → dist}/SvSchemaDashboard.svelte +0 -0
  555. /package/{src → dist}/pdfmake-shims.d.ts +0 -0
  556. /package/{src → dist}/smart.export.d.ts +0 -0
  557. /package/{src → dist}/smart.export.js +0 -0
  558. /package/{src → dist}/studio/HANDLERS-DESIGN.md +0 -0
  559. /package/{src → dist/studio}/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/_svelte_metadata.json +0 -0
  560. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/_metadata.json +0 -0
  561. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/attachments-BOv1rBKp.js +0 -0
  562. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/attachments-BOv1rBKp.js.map +0 -0
  563. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/constants-B9vgIdCd.js +0 -0
  564. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/constants-B9vgIdCd.js.map +0 -0
  565. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/dev-T1qbW_qD.js +0 -0
  566. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/dev-T1qbW_qD.js.map +0 -0
  567. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/events-Bo11SfVK.js +0 -0
  568. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/events-Bo11SfVK.js.map +0 -0
  569. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/flags-X7D4vfrZ.js +0 -0
  570. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/flags-X7D4vfrZ.js.map +0 -0
  571. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/hydration-oyUje5i1.js +0 -0
  572. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/hydration-oyUje5i1.js.map +0 -0
  573. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/legacy-client-DeSQgSFm.js +0 -0
  574. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/legacy-client-DeSQgSFm.js.map +0 -0
  575. /package/{src → dist/studio}/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/package.json +0 -0
  576. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte.js +0 -0
  577. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte.js.map +0 -0
  578. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_animate.js +0 -0
  579. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_animate.js.map +0 -0
  580. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_attachments.js +0 -0
  581. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_compiler.js +0 -0
  582. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_compiler.js.map +0 -0
  583. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_easing.js +0 -0
  584. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_easing.js.map +0 -0
  585. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_events.js +0 -0
  586. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal.js +0 -0
  587. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal.js.map +0 -0
  588. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_client.js +0 -0
  589. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_disclose-version.js +0 -0
  590. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_disclose-version.js.map +0 -0
  591. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_async.js +0 -0
  592. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_async.js.map +0 -0
  593. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_legacy.js +0 -0
  594. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_legacy.js.map +0 -0
  595. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_tracing.js +0 -0
  596. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_tracing.js.map +0 -0
  597. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_server.js +0 -0
  598. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_legacy.js +0 -0
  599. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_legacy.js.map +0 -0
  600. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_motion.js +0 -0
  601. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_motion.js.map +0 -0
  602. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity.js +0 -0
  603. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity.js.map +0 -0
  604. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity_window.js +0 -0
  605. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity_window.js.map +0 -0
  606. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_server.js +0 -0
  607. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_store.js +0 -0
  608. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_store.js.map +0 -0
  609. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_transition.js +0 -0
  610. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_transition.js.map +0 -0
  611. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-BbWyXNk1.js +0 -0
  612. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-BbWyXNk1.js.map +0 -0
  613. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-DI_fC7vt.js +0 -0
  614. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-DI_fC7vt.js.map +0 -0
  615. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/validate-Dyr3lQv9.js +0 -0
  616. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/validate-Dyr3lQv9.js.map +0 -0
  617. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/version-_9FHH-LF.js +0 -0
  618. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/version-_9FHH-LF.js.map +0 -0
  619. /package/{src → dist}/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/warnings-CUbSPnyP.js +0 -0
  620. /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
- })