snice 4.29.0 → 4.30.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 (516) hide show
  1. package/README.md +3 -10
  2. package/adapters/react/SniceProvider.d.ts +71 -0
  3. package/adapters/react/SniceProvider.js +49 -0
  4. package/adapters/react/SniceProvider.js.map +1 -0
  5. package/adapters/react/SniceRouter.d.ts +44 -0
  6. package/adapters/react/SniceRouter.js +190 -0
  7. package/adapters/react/SniceRouter.js.map +1 -0
  8. package/adapters/react/components.d.ts +2 -0
  9. package/adapters/react/components.d.ts.map +1 -1
  10. package/adapters/react/components.js +1 -0
  11. package/adapters/react/components.js.map +1 -1
  12. package/adapters/react/components.ts +2 -0
  13. package/adapters/react/grid.d.ts +36 -0
  14. package/adapters/react/grid.d.ts.map +1 -0
  15. package/adapters/react/grid.js +24 -0
  16. package/adapters/react/grid.js.map +1 -0
  17. package/adapters/react/grid.tsx +44 -0
  18. package/adapters/react/index.d.ts +5 -0
  19. package/adapters/react/index.d.ts.map +1 -1
  20. package/adapters/react/index.js +3 -2
  21. package/adapters/react/index.js.map +1 -1
  22. package/adapters/react/index.ts +6 -3
  23. package/adapters/react/matchRoute.d.ts +16 -0
  24. package/adapters/react/matchRoute.js +32 -0
  25. package/adapters/react/matchRoute.js.map +1 -0
  26. package/adapters/react/types.d.ts +1 -15
  27. package/adapters/react/types.d.ts.map +1 -1
  28. package/adapters/react/types.ts +1 -15
  29. package/adapters/react/useRequestHandler.js +1 -1
  30. package/adapters/react/useRequestHandler.js.map +1 -1
  31. package/bin/snice.js +8 -13
  32. package/bin/templates/{pwa → default}/index.html +1 -1
  33. package/bin/templates/{pwa → default}/src/components/app-header.ts +36 -18
  34. package/bin/templates/{pwa → default}/src/components/notification-badge.ts +2 -21
  35. package/bin/templates/{pwa → default}/src/components/search-bar.ts +12 -12
  36. package/bin/templates/default/src/context.ts +17 -0
  37. package/bin/templates/{pwa → default}/src/controllers/notification-controller.ts +10 -15
  38. package/bin/templates/{pwa → default}/src/daemons/notifications.ts +0 -12
  39. package/bin/templates/{pwa → default}/src/main.ts +1 -7
  40. package/bin/templates/{pwa → default}/src/middleware/error.ts +1 -8
  41. package/bin/templates/{pwa → default}/src/pages/dashboard.ts +17 -18
  42. package/bin/templates/{pwa → default}/src/pages/data.ts +24 -24
  43. package/bin/templates/{pwa → default}/src/pages/login.ts +3 -6
  44. package/bin/templates/{pwa → default}/src/pages/notifications.ts +21 -19
  45. package/bin/templates/{pwa → default}/src/pages/profile.ts +10 -12
  46. package/bin/templates/{pwa → default}/src/pages/settings.ts +22 -22
  47. package/bin/templates/default/src/router.ts +13 -0
  48. package/bin/templates/default/src/styles/global.css +16 -0
  49. package/bin/templates/{pwa → default}/tsconfig.json +2 -1
  50. package/bin/templates/react/README.md +124 -0
  51. package/bin/templates/react/global.d.ts +10 -0
  52. package/bin/templates/react/index.html +15 -0
  53. package/bin/templates/react/package.json +31 -0
  54. package/bin/templates/react/src/App.tsx +112 -0
  55. package/bin/templates/react/src/components/AppHeader.tsx +85 -0
  56. package/bin/templates/react/src/components/AppLayout.tsx +11 -0
  57. package/bin/templates/react/src/components/NotificationBadge.tsx +13 -0
  58. package/bin/templates/react/src/components/SearchBar.tsx +63 -0
  59. package/bin/templates/react/src/daemons/notifications.ts +136 -0
  60. package/bin/templates/react/src/fetcher.ts +15 -0
  61. package/bin/templates/react/src/guards/auth.ts +6 -0
  62. package/bin/templates/react/src/main.tsx +27 -0
  63. package/bin/templates/react/src/middleware/auth.ts +16 -0
  64. package/bin/templates/react/src/middleware/error.ts +29 -0
  65. package/bin/templates/react/src/middleware/retry.ts +31 -0
  66. package/bin/templates/react/src/pages/DashboardPage.tsx +111 -0
  67. package/bin/templates/react/src/pages/DataPage.tsx +119 -0
  68. package/bin/templates/react/src/pages/LoginPage.tsx +46 -0
  69. package/bin/templates/react/src/pages/NotificationsPage.tsx +119 -0
  70. package/bin/templates/react/src/pages/ProfilePage.tsx +92 -0
  71. package/bin/templates/react/src/pages/SettingsPage.tsx +165 -0
  72. package/bin/templates/react/src/services/auth.ts +48 -0
  73. package/bin/templates/react/src/services/jwt.ts +35 -0
  74. package/bin/templates/react/src/services/storage.ts +24 -0
  75. package/bin/templates/react/src/styles/global.css +382 -0
  76. package/bin/templates/react/src/types/auth.ts +21 -0
  77. package/bin/templates/react/src/types/notifications.ts +9 -0
  78. package/bin/templates/react/tests/helpers/test-utils.ts +79 -0
  79. package/bin/templates/react/tests/middleware/auth.test.ts +67 -0
  80. package/bin/templates/react/tests/middleware/error.test.ts +105 -0
  81. package/bin/templates/react/tests/middleware/retry.test.ts +103 -0
  82. package/bin/templates/react/tests/services/auth.test.ts +89 -0
  83. package/bin/templates/react/tests/services/jwt.test.ts +76 -0
  84. package/bin/templates/react/tests/services/storage.test.ts +69 -0
  85. package/bin/templates/{base → react}/tsconfig.json +4 -6
  86. package/bin/templates/react/vite.config.ts +18 -0
  87. package/bin/templates/react/vitest.config.ts +18 -0
  88. package/dist/cdn/accordion/snice-accordion.js +1 -1
  89. package/dist/cdn/accordion/snice-accordion.min.js +1 -1
  90. package/dist/cdn/action-bar/snice-action-bar.js +1 -1
  91. package/dist/cdn/action-bar/snice-action-bar.min.js +1 -1
  92. package/dist/cdn/activity-feed/snice-activity-feed.js +1 -1
  93. package/dist/cdn/activity-feed/snice-activity-feed.min.js +1 -1
  94. package/dist/cdn/alert/snice-alert.js +1 -1
  95. package/dist/cdn/alert/snice-alert.min.js +1 -1
  96. package/dist/cdn/app-tiles/snice-app-tiles.js +1 -1
  97. package/dist/cdn/app-tiles/snice-app-tiles.min.js +1 -1
  98. package/dist/cdn/approval-flow/snice-approval-flow.js +1 -1
  99. package/dist/cdn/approval-flow/snice-approval-flow.min.js +1 -1
  100. package/dist/cdn/audio-recorder/snice-audio-recorder.js +1 -1
  101. package/dist/cdn/audio-recorder/snice-audio-recorder.min.js +1 -1
  102. package/dist/cdn/availability/snice-availability.js +1 -1
  103. package/dist/cdn/availability/snice-availability.min.js +1 -1
  104. package/dist/cdn/avatar/snice-avatar.js +1 -1
  105. package/dist/cdn/avatar/snice-avatar.min.js +1 -1
  106. package/dist/cdn/avatar-group/snice-avatar-group.js +1 -1
  107. package/dist/cdn/avatar-group/snice-avatar-group.min.js +1 -1
  108. package/dist/cdn/badge/snice-badge.js +1 -1
  109. package/dist/cdn/badge/snice-badge.min.js +1 -1
  110. package/dist/cdn/banner/snice-banner.js +1 -1
  111. package/dist/cdn/banner/snice-banner.min.js +1 -1
  112. package/dist/cdn/binpack/snice-binpack.js +1 -1
  113. package/dist/cdn/binpack/snice-binpack.min.js +1 -1
  114. package/dist/cdn/book/snice-book.js +1 -1
  115. package/dist/cdn/book/snice-book.min.js +1 -1
  116. package/dist/cdn/booking/snice-booking.js +1 -1
  117. package/dist/cdn/booking/snice-booking.min.js +1 -1
  118. package/dist/cdn/breadcrumbs/snice-breadcrumbs.js +1 -1
  119. package/dist/cdn/breadcrumbs/snice-breadcrumbs.min.js +1 -1
  120. package/dist/cdn/button/snice-button.js +1 -1
  121. package/dist/cdn/button/snice-button.min.js +1 -1
  122. package/dist/cdn/calendar/snice-calendar.js +1 -1
  123. package/dist/cdn/calendar/snice-calendar.min.js +1 -1
  124. package/dist/cdn/camera/snice-camera.js +1 -1
  125. package/dist/cdn/camera/snice-camera.min.js +1 -1
  126. package/dist/cdn/camera-annotate/snice-camera-annotate.js +1 -1
  127. package/dist/cdn/camera-annotate/snice-camera-annotate.min.js +1 -1
  128. package/dist/cdn/candlestick/snice-candlestick.js +1 -1
  129. package/dist/cdn/candlestick/snice-candlestick.min.js +1 -1
  130. package/dist/cdn/card/snice-card.js +1 -1
  131. package/dist/cdn/card/snice-card.min.js +1 -1
  132. package/dist/cdn/carousel/snice-carousel.js +1 -1
  133. package/dist/cdn/carousel/snice-carousel.min.js +1 -1
  134. package/dist/cdn/cart/snice-cart.js +1 -1
  135. package/dist/cdn/cart/snice-cart.min.js +1 -1
  136. package/dist/cdn/chart/snice-chart.js +1 -1
  137. package/dist/cdn/chart/snice-chart.min.js +1 -1
  138. package/dist/cdn/chat/snice-chat.js +1 -1
  139. package/dist/cdn/chat/snice-chat.min.js +1 -1
  140. package/dist/cdn/checkbox/snice-checkbox.js +1 -1
  141. package/dist/cdn/checkbox/snice-checkbox.min.js +1 -1
  142. package/dist/cdn/chip/README.md +2 -2
  143. package/dist/cdn/chip/snice-chip.js +2 -2
  144. package/dist/cdn/chip/snice-chip.js.map +1 -1
  145. package/dist/cdn/chip/snice-chip.min.js +3 -3
  146. package/dist/cdn/chip/snice-chip.min.js.map +1 -1
  147. package/dist/cdn/code-block/snice-code-block.js +1 -1
  148. package/dist/cdn/code-block/snice-code-block.min.js +1 -1
  149. package/dist/cdn/color-display/snice-color-display.js +1 -1
  150. package/dist/cdn/color-display/snice-color-display.min.js +1 -1
  151. package/dist/cdn/color-picker/snice-color-picker.js +1 -1
  152. package/dist/cdn/color-picker/snice-color-picker.min.js +1 -1
  153. package/dist/cdn/command-palette/snice-command-palette.js +1 -1
  154. package/dist/cdn/command-palette/snice-command-palette.min.js +1 -1
  155. package/dist/cdn/comments/snice-comments.js +1 -1
  156. package/dist/cdn/comments/snice-comments.min.js +1 -1
  157. package/dist/cdn/countdown/snice-countdown.js +1 -1
  158. package/dist/cdn/countdown/snice-countdown.min.js +1 -1
  159. package/dist/cdn/cropper/snice-cropper.js +1 -1
  160. package/dist/cdn/cropper/snice-cropper.min.js +1 -1
  161. package/dist/cdn/data-card/snice-data-card.js +1 -1
  162. package/dist/cdn/data-card/snice-data-card.min.js +1 -1
  163. package/dist/cdn/date-picker/README.md +1 -1
  164. package/dist/cdn/date-picker/snice-date-picker.js +2 -2
  165. package/dist/cdn/date-picker/snice-date-picker.js.map +1 -1
  166. package/dist/cdn/date-picker/snice-date-picker.min.js +2 -2
  167. package/dist/cdn/date-picker/snice-date-picker.min.js.map +1 -1
  168. package/dist/cdn/date-range-picker/README.md +1 -1
  169. package/dist/cdn/date-range-picker/snice-date-range-picker.js +2 -2
  170. package/dist/cdn/date-range-picker/snice-date-range-picker.js.map +1 -1
  171. package/dist/cdn/date-range-picker/snice-date-range-picker.min.js +11 -11
  172. package/dist/cdn/date-range-picker/snice-date-range-picker.min.js.map +1 -1
  173. package/dist/cdn/date-time-picker/README.md +1 -1
  174. package/dist/cdn/date-time-picker/snice-date-time-picker.js +2 -2
  175. package/dist/cdn/date-time-picker/snice-date-time-picker.js.map +1 -1
  176. package/dist/cdn/date-time-picker/snice-date-time-picker.min.js +2 -2
  177. package/dist/cdn/date-time-picker/snice-date-time-picker.min.js.map +1 -1
  178. package/dist/cdn/diff/snice-diff.js +1 -1
  179. package/dist/cdn/diff/snice-diff.min.js +1 -1
  180. package/dist/cdn/divider/snice-divider.js +1 -1
  181. package/dist/cdn/divider/snice-divider.min.js +1 -1
  182. package/dist/cdn/doc/snice-doc.js +1 -1
  183. package/dist/cdn/doc/snice-doc.min.js +1 -1
  184. package/dist/cdn/draw/README.md +2 -2
  185. package/dist/cdn/draw/snice-draw.js +26 -4
  186. package/dist/cdn/draw/snice-draw.js.map +1 -1
  187. package/dist/cdn/draw/snice-draw.min.js +3 -3
  188. package/dist/cdn/draw/snice-draw.min.js.map +1 -1
  189. package/dist/cdn/drawer/snice-drawer.js +1 -1
  190. package/dist/cdn/drawer/snice-drawer.min.js +1 -1
  191. package/dist/cdn/empty-state/snice-empty-state.js +1 -1
  192. package/dist/cdn/empty-state/snice-empty-state.min.js +1 -1
  193. package/dist/cdn/estimate/snice-estimate.js +1 -1
  194. package/dist/cdn/estimate/snice-estimate.min.js +1 -1
  195. package/dist/cdn/file-gallery/snice-file-gallery.js +1 -1
  196. package/dist/cdn/file-gallery/snice-file-gallery.min.js +1 -1
  197. package/dist/cdn/file-upload/snice-file-upload.js +1 -1
  198. package/dist/cdn/file-upload/snice-file-upload.min.js +1 -1
  199. package/dist/cdn/flip-card/snice-flip-card.js +1 -1
  200. package/dist/cdn/flip-card/snice-flip-card.min.js +1 -1
  201. package/dist/cdn/flow/snice-flow.js +1 -1
  202. package/dist/cdn/flow/snice-flow.min.js +1 -1
  203. package/dist/cdn/form-layout/snice-form-layout.js +1 -1
  204. package/dist/cdn/form-layout/snice-form-layout.min.js +1 -1
  205. package/dist/cdn/funnel/snice-funnel.js +1 -1
  206. package/dist/cdn/funnel/snice-funnel.min.js +1 -1
  207. package/dist/cdn/gantt/snice-gantt.js +1 -1
  208. package/dist/cdn/gantt/snice-gantt.min.js +1 -1
  209. package/dist/cdn/gauge/snice-gauge.js +1 -1
  210. package/dist/cdn/gauge/snice-gauge.min.js +1 -1
  211. package/dist/cdn/grid/README.md +27 -0
  212. package/dist/cdn/grid/snice-grid.js +862 -0
  213. package/dist/cdn/grid/snice-grid.js.map +1 -0
  214. package/dist/cdn/grid/snice-grid.min.js +13 -0
  215. package/dist/cdn/grid/snice-grid.min.js.map +1 -0
  216. package/dist/cdn/heatmap/snice-heatmap.js +1 -1
  217. package/dist/cdn/heatmap/snice-heatmap.min.js +1 -1
  218. package/dist/cdn/image/snice-image.js +1 -1
  219. package/dist/cdn/image/snice-image.min.js +1 -1
  220. package/dist/cdn/input/snice-input.js +1 -1
  221. package/dist/cdn/input/snice-input.min.js +1 -1
  222. package/dist/cdn/invoice/snice-invoice.js +1 -1
  223. package/dist/cdn/invoice/snice-invoice.min.js +1 -1
  224. package/dist/cdn/kanban/snice-kanban.js +1 -1
  225. package/dist/cdn/kanban/snice-kanban.min.js +1 -1
  226. package/dist/cdn/key-value/snice-key-value.js +1 -1
  227. package/dist/cdn/key-value/snice-key-value.min.js +1 -1
  228. package/dist/cdn/kpi/snice-kpi.js +1 -1
  229. package/dist/cdn/kpi/snice-kpi.min.js +1 -1
  230. package/dist/cdn/layout/snice-layout.js +1 -1
  231. package/dist/cdn/layout/snice-layout.min.js +1 -1
  232. package/dist/cdn/leaderboard/snice-leaderboard.js +1 -1
  233. package/dist/cdn/leaderboard/snice-leaderboard.min.js +1 -1
  234. package/dist/cdn/link/snice-link.js +1 -1
  235. package/dist/cdn/link/snice-link.min.js +1 -1
  236. package/dist/cdn/link-preview/snice-link-preview.js +1 -1
  237. package/dist/cdn/link-preview/snice-link-preview.min.js +1 -1
  238. package/dist/cdn/list/snice-list.js +1 -1
  239. package/dist/cdn/list/snice-list.min.js +1 -1
  240. package/dist/cdn/location/snice-location.js +1 -1
  241. package/dist/cdn/location/snice-location.min.js +1 -1
  242. package/dist/cdn/login/snice-login.js +1 -1
  243. package/dist/cdn/login/snice-login.min.js +1 -1
  244. package/dist/cdn/map/snice-map.js +1 -1
  245. package/dist/cdn/map/snice-map.min.js +1 -1
  246. package/dist/cdn/markdown/snice-markdown.js +1 -1
  247. package/dist/cdn/markdown/snice-markdown.min.js +1 -1
  248. package/dist/cdn/masonry/snice-masonry.js +1 -1
  249. package/dist/cdn/masonry/snice-masonry.min.js +1 -1
  250. package/dist/cdn/menu/snice-menu.js +1 -1
  251. package/dist/cdn/menu/snice-menu.min.js +1 -1
  252. package/dist/cdn/message-strip/README.md +2 -2
  253. package/dist/cdn/message-strip/snice-message-strip.js +2 -2
  254. package/dist/cdn/message-strip/snice-message-strip.js.map +1 -1
  255. package/dist/cdn/message-strip/snice-message-strip.min.js +6 -6
  256. package/dist/cdn/message-strip/snice-message-strip.min.js.map +1 -1
  257. package/dist/cdn/metric-table/snice-metric-table.js +1 -1
  258. package/dist/cdn/metric-table/snice-metric-table.min.js +1 -1
  259. package/dist/cdn/modal/snice-modal.js +1 -1
  260. package/dist/cdn/modal/snice-modal.min.js +1 -1
  261. package/dist/cdn/music-player/snice-music-player.js +1 -1
  262. package/dist/cdn/music-player/snice-music-player.min.js +1 -1
  263. package/dist/cdn/nav/snice-nav.js +1 -1
  264. package/dist/cdn/nav/snice-nav.min.js +1 -1
  265. package/dist/cdn/network-graph/snice-network-graph.js +1 -1
  266. package/dist/cdn/network-graph/snice-network-graph.min.js +1 -1
  267. package/dist/cdn/notification-center/snice-notification-center.js +1 -1
  268. package/dist/cdn/notification-center/snice-notification-center.min.js +1 -1
  269. package/dist/cdn/order-tracker/snice-order-tracker.js +1 -1
  270. package/dist/cdn/order-tracker/snice-order-tracker.min.js +1 -1
  271. package/dist/cdn/org-chart/snice-org-chart.js +1 -1
  272. package/dist/cdn/org-chart/snice-org-chart.min.js +1 -1
  273. package/dist/cdn/pagination/snice-pagination.js +1 -1
  274. package/dist/cdn/pagination/snice-pagination.min.js +1 -1
  275. package/dist/cdn/paint/README.md +2 -2
  276. package/dist/cdn/paint/snice-paint.js +26 -3
  277. package/dist/cdn/paint/snice-paint.js.map +1 -1
  278. package/dist/cdn/paint/snice-paint.min.js +3 -3
  279. package/dist/cdn/paint/snice-paint.min.js.map +1 -1
  280. package/dist/cdn/pdf-viewer/snice-pdf-viewer.js +1 -1
  281. package/dist/cdn/pdf-viewer/snice-pdf-viewer.min.js +1 -1
  282. package/dist/cdn/permission-matrix/snice-permission-matrix.js +1 -1
  283. package/dist/cdn/permission-matrix/snice-permission-matrix.min.js +1 -1
  284. package/dist/cdn/podcast-player/snice-podcast-player.js +1 -1
  285. package/dist/cdn/podcast-player/snice-podcast-player.min.js +1 -1
  286. package/dist/cdn/pricing-table/snice-pricing-table.js +1 -1
  287. package/dist/cdn/pricing-table/snice-pricing-table.min.js +1 -1
  288. package/dist/cdn/product-card/README.md +1 -1
  289. package/dist/cdn/product-card/snice-product-card.js +1 -1
  290. package/dist/cdn/product-card/snice-product-card.min.js +1 -1
  291. package/dist/cdn/progress/snice-progress.js +1 -1
  292. package/dist/cdn/progress/snice-progress.min.js +1 -1
  293. package/dist/cdn/progress-ring/snice-progress-ring.js +1 -1
  294. package/dist/cdn/progress-ring/snice-progress-ring.min.js +1 -1
  295. package/dist/cdn/qr-code/snice-qr-code.js +1 -1
  296. package/dist/cdn/qr-code/snice-qr-code.min.js +1 -1
  297. package/dist/cdn/qr-reader/snice-qr-reader.js +1 -1
  298. package/dist/cdn/qr-reader/snice-qr-reader.min.js +1 -1
  299. package/dist/cdn/radio/snice-radio.js +1 -1
  300. package/dist/cdn/radio/snice-radio.min.js +1 -1
  301. package/dist/cdn/range-slider/snice-range-slider.js +1 -1
  302. package/dist/cdn/range-slider/snice-range-slider.min.js +1 -1
  303. package/dist/cdn/rating/snice-rating.js +1 -1
  304. package/dist/cdn/rating/snice-rating.min.js +1 -1
  305. package/dist/cdn/receipt/snice-receipt.js +1 -1
  306. package/dist/cdn/receipt/snice-receipt.min.js +1 -1
  307. package/dist/cdn/recipe/snice-recipe.js +1 -1
  308. package/dist/cdn/recipe/snice-recipe.min.js +1 -1
  309. package/dist/cdn/runtime/README.md +2 -2
  310. package/dist/cdn/runtime/snice-runtime.esm.js +40 -15
  311. package/dist/cdn/runtime/snice-runtime.esm.js.map +1 -1
  312. package/dist/cdn/runtime/snice-runtime.esm.min.js +7 -7
  313. package/dist/cdn/runtime/snice-runtime.esm.min.js.map +1 -1
  314. package/dist/cdn/runtime/snice-runtime.js +40 -15
  315. package/dist/cdn/runtime/snice-runtime.js.map +1 -1
  316. package/dist/cdn/runtime/snice-runtime.min.js +6 -6
  317. package/dist/cdn/runtime/snice-runtime.min.js.map +1 -1
  318. package/dist/cdn/sankey/snice-sankey.js +1 -1
  319. package/dist/cdn/sankey/snice-sankey.min.js +1 -1
  320. package/dist/cdn/segmented-control/snice-segmented-control.js +1 -1
  321. package/dist/cdn/segmented-control/snice-segmented-control.min.js +1 -1
  322. package/dist/cdn/select/snice-select.js +1 -1
  323. package/dist/cdn/select/snice-select.min.js +1 -1
  324. package/dist/cdn/skeleton/snice-skeleton.js +1 -1
  325. package/dist/cdn/skeleton/snice-skeleton.min.js +1 -1
  326. package/dist/cdn/slider/snice-slider.js +1 -1
  327. package/dist/cdn/slider/snice-slider.min.js +1 -1
  328. package/dist/cdn/sortable/snice-sortable.js +1 -1
  329. package/dist/cdn/sortable/snice-sortable.min.js +1 -1
  330. package/dist/cdn/sparkline/snice-sparkline.js +1 -1
  331. package/dist/cdn/sparkline/snice-sparkline.min.js +1 -1
  332. package/dist/cdn/spinner/snice-spinner.js +1 -1
  333. package/dist/cdn/spinner/snice-spinner.min.js +1 -1
  334. package/dist/cdn/split-button/snice-split-button.js +1 -1
  335. package/dist/cdn/split-button/snice-split-button.min.js +1 -1
  336. package/dist/cdn/split-pane/snice-split-pane.js +1 -1
  337. package/dist/cdn/split-pane/snice-split-pane.min.js +1 -1
  338. package/dist/cdn/spotlight/snice-spotlight.js +1 -1
  339. package/dist/cdn/spotlight/snice-spotlight.min.js +1 -1
  340. package/dist/cdn/spreadsheet/snice-spreadsheet.js +1 -1
  341. package/dist/cdn/spreadsheet/snice-spreadsheet.min.js +1 -1
  342. package/dist/cdn/stat-group/snice-stat-group.js +1 -1
  343. package/dist/cdn/stat-group/snice-stat-group.min.js +1 -1
  344. package/dist/cdn/step-input/snice-step-input.js +1 -1
  345. package/dist/cdn/step-input/snice-step-input.min.js +1 -1
  346. package/dist/cdn/stepper/snice-stepper.js +1 -1
  347. package/dist/cdn/stepper/snice-stepper.min.js +1 -1
  348. package/dist/cdn/switch/snice-switch.js +1 -1
  349. package/dist/cdn/switch/snice-switch.min.js +1 -1
  350. package/dist/cdn/table/snice-table.js +1 -1
  351. package/dist/cdn/table/snice-table.min.js +1 -1
  352. package/dist/cdn/tabs/snice-tabs.js +1 -1
  353. package/dist/cdn/tabs/snice-tabs.min.js +1 -1
  354. package/dist/cdn/tag/README.md +1 -1
  355. package/dist/cdn/tag/snice-tag.js +2 -2
  356. package/dist/cdn/tag/snice-tag.js.map +1 -1
  357. package/dist/cdn/tag/snice-tag.min.js +3 -3
  358. package/dist/cdn/tag/snice-tag.min.js.map +1 -1
  359. package/dist/cdn/tag-input/README.md +2 -2
  360. package/dist/cdn/tag-input/snice-tag-input.js +2 -2
  361. package/dist/cdn/tag-input/snice-tag-input.js.map +1 -1
  362. package/dist/cdn/tag-input/snice-tag-input.min.js +2 -2
  363. package/dist/cdn/tag-input/snice-tag-input.min.js.map +1 -1
  364. package/dist/cdn/terminal/snice-terminal.js +1 -1
  365. package/dist/cdn/terminal/snice-terminal.min.js +1 -1
  366. package/dist/cdn/testimonial/snice-testimonial.js +1 -1
  367. package/dist/cdn/testimonial/snice-testimonial.min.js +1 -1
  368. package/dist/cdn/textarea/snice-textarea.js +1 -1
  369. package/dist/cdn/textarea/snice-textarea.min.js +1 -1
  370. package/dist/cdn/time-picker/README.md +1 -1
  371. package/dist/cdn/time-picker/snice-time-picker.js +2 -2
  372. package/dist/cdn/time-picker/snice-time-picker.js.map +1 -1
  373. package/dist/cdn/time-picker/snice-time-picker.min.js +2 -2
  374. package/dist/cdn/time-picker/snice-time-picker.min.js.map +1 -1
  375. package/dist/cdn/time-range-picker/snice-time-range-picker.js +1 -1
  376. package/dist/cdn/time-range-picker/snice-time-range-picker.min.js +1 -1
  377. package/dist/cdn/timeline/snice-timeline.js +1 -1
  378. package/dist/cdn/timeline/snice-timeline.min.js +1 -1
  379. package/dist/cdn/timer/snice-timer.js +1 -1
  380. package/dist/cdn/timer/snice-timer.min.js +1 -1
  381. package/dist/cdn/toast/README.md +1 -1
  382. package/dist/cdn/toast/snice-toast.js +7 -3
  383. package/dist/cdn/toast/snice-toast.js.map +1 -1
  384. package/dist/cdn/toast/snice-toast.min.js +6 -6
  385. package/dist/cdn/toast/snice-toast.min.js.map +1 -1
  386. package/dist/cdn/tooltip/snice-tooltip.js +1 -1
  387. package/dist/cdn/tooltip/snice-tooltip.min.js +1 -1
  388. package/dist/cdn/tree/snice-tree.js +1 -1
  389. package/dist/cdn/tree/snice-tree.min.js +1 -1
  390. package/dist/cdn/treemap/snice-treemap.js +1 -1
  391. package/dist/cdn/treemap/snice-treemap.min.js +1 -1
  392. package/dist/cdn/user-card/snice-user-card.js +1 -1
  393. package/dist/cdn/user-card/snice-user-card.min.js +1 -1
  394. package/dist/cdn/video-player/snice-video-player.js +1 -1
  395. package/dist/cdn/video-player/snice-video-player.min.js +1 -1
  396. package/dist/cdn/virtual-scroller/snice-virtual-scroller.js +1 -1
  397. package/dist/cdn/virtual-scroller/snice-virtual-scroller.min.js +1 -1
  398. package/dist/cdn/waterfall/README.md +1 -1
  399. package/dist/cdn/waterfall/snice-waterfall.js +1 -1
  400. package/dist/cdn/waterfall/snice-waterfall.min.js +1 -1
  401. package/dist/cdn/weather/snice-weather.js +1 -1
  402. package/dist/cdn/weather/snice-weather.min.js +1 -1
  403. package/dist/cdn/work-order/snice-work-order.js +1 -1
  404. package/dist/cdn/work-order/snice-work-order.min.js +1 -1
  405. package/dist/components/chip/snice-chip.js +1 -1
  406. package/dist/components/chip/snice-chip.js.map +1 -1
  407. package/dist/components/date-picker/snice-date-picker.js +1 -1
  408. package/dist/components/date-picker/snice-date-picker.js.map +1 -1
  409. package/dist/components/date-range-picker/snice-date-range-picker.js +1 -1
  410. package/dist/components/date-range-picker/snice-date-range-picker.js.map +1 -1
  411. package/dist/components/date-time-picker/snice-date-time-picker.js +1 -1
  412. package/dist/components/date-time-picker/snice-date-time-picker.js.map +1 -1
  413. package/dist/components/draw/snice-draw.d.ts +2 -0
  414. package/dist/components/draw/snice-draw.js +25 -3
  415. package/dist/components/draw/snice-draw.js.map +1 -1
  416. package/dist/components/grid/snice-grid.d.ts +73 -0
  417. package/dist/components/grid/snice-grid.js +795 -0
  418. package/dist/components/grid/snice-grid.js.map +1 -0
  419. package/dist/components/grid/snice-grid.types.d.ts +41 -0
  420. package/dist/components/message-strip/snice-message-strip.js +1 -1
  421. package/dist/components/message-strip/snice-message-strip.js.map +1 -1
  422. package/dist/components/paint/snice-paint.d.ts +2 -0
  423. package/dist/components/paint/snice-paint.js +25 -2
  424. package/dist/components/paint/snice-paint.js.map +1 -1
  425. package/dist/components/tag/snice-tag.js +1 -1
  426. package/dist/components/tag/snice-tag.js.map +1 -1
  427. package/dist/components/tag-input/snice-tag-input.js +1 -1
  428. package/dist/components/tag-input/snice-tag-input.js.map +1 -1
  429. package/dist/components/theme/theme.css +15 -0
  430. package/dist/components/time-picker/snice-time-picker.js +1 -1
  431. package/dist/components/time-picker/snice-time-picker.js.map +1 -1
  432. package/dist/components/toast/snice-toast-container.js +4 -0
  433. package/dist/components/toast/snice-toast-container.js.map +1 -1
  434. package/dist/components/toast/snice-toast.js +2 -2
  435. package/dist/index.cjs +37 -12
  436. package/dist/index.cjs.map +1 -1
  437. package/dist/index.esm.js +37 -12
  438. package/dist/index.esm.js.map +1 -1
  439. package/dist/index.iife.js +37 -12
  440. package/dist/index.iife.js.map +1 -1
  441. package/dist/react/SniceProvider.d.ts +71 -0
  442. package/dist/react/SniceProvider.js +49 -0
  443. package/dist/react/SniceProvider.js.map +1 -0
  444. package/dist/react/SniceRouter.d.ts +44 -0
  445. package/dist/react/SniceRouter.js +190 -0
  446. package/dist/react/SniceRouter.js.map +1 -0
  447. package/dist/react/index.d.ts +3 -0
  448. package/dist/react/index.js +14 -0
  449. package/dist/react/index.js.map +1 -0
  450. package/dist/react/matchRoute.d.ts +16 -0
  451. package/dist/react/matchRoute.js +32 -0
  452. package/dist/react/matchRoute.js.map +1 -0
  453. package/dist/react/useRequestHandler.js +1 -1
  454. package/dist/react/useRequestHandler.js.map +1 -1
  455. package/dist/symbols.cjs +1 -1
  456. package/dist/symbols.esm.js +1 -1
  457. package/dist/transitions.cjs +1 -1
  458. package/dist/transitions.esm.js +1 -1
  459. package/dist/types/guard.d.ts +4 -11
  460. package/docs/ai/README.md +7 -7
  461. package/docs/ai/components/grid.md +116 -0
  462. package/docs/ai/patterns.md +24 -0
  463. package/docs/ai/react-integration.md +97 -0
  464. package/docs/components/grid.md +249 -0
  465. package/docs/plans/2026-03-10-grid-component-design.md +138 -0
  466. package/docs/plans/2026-03-10-grid-component-plan.md +716 -0
  467. package/docs/plans/2026-03-10-react-integration-plan.md +1178 -0
  468. package/docs/react-integration.md +508 -0
  469. package/docs/request-response.md +7 -21
  470. package/package.json +1 -1
  471. package/bin/templates/base/README.md +0 -33
  472. package/bin/templates/base/global.d.ts +0 -14
  473. package/bin/templates/base/index.html +0 -13
  474. package/bin/templates/base/package.json +0 -21
  475. package/bin/templates/base/src/components/counter-button.ts +0 -88
  476. package/bin/templates/base/src/components/counter-button.types.ts +0 -7
  477. package/bin/templates/base/src/components/feature-card.ts +0 -59
  478. package/bin/templates/base/src/components/feature-card.types.ts +0 -5
  479. package/bin/templates/base/src/controllers/counter-controller.ts +0 -24
  480. package/bin/templates/base/src/main.ts +0 -24
  481. package/bin/templates/base/src/pages/about-page.ts +0 -68
  482. package/bin/templates/base/src/pages/home-page.ts +0 -105
  483. package/bin/templates/base/src/pages/not-found-page.ts +0 -55
  484. package/bin/templates/base/src/router.ts +0 -9
  485. package/bin/templates/base/src/styles/global.css +0 -27
  486. package/bin/templates/base/src/types/api-response.ts +0 -5
  487. package/bin/templates/base/src/types/status.ts +0 -1
  488. package/bin/templates/base/src/types/theme.ts +0 -1
  489. package/bin/templates/base/src/types/user.ts +0 -5
  490. package/bin/templates/base/vite.config.ts +0 -38
  491. package/bin/templates/pwa/public/vite.svg +0 -1
  492. package/bin/templates/pwa/src/router.ts +0 -20
  493. package/bin/templates/pwa/src/styles/global.css +0 -64
  494. /package/bin/templates/{pwa → default}/README.md +0 -0
  495. /package/bin/templates/{pwa → default}/global.d.ts +0 -0
  496. /package/bin/templates/{pwa → default}/package.json +0 -0
  497. /package/bin/templates/{pwa → default}/public/icons/.gitkeep +0 -0
  498. /package/bin/templates/{base → default}/public/vite.svg +0 -0
  499. /package/bin/templates/{pwa → default}/src/fetcher.ts +0 -0
  500. /package/bin/templates/{pwa → default}/src/guards/auth.ts +0 -0
  501. /package/bin/templates/{pwa → default}/src/middleware/auth.ts +0 -0
  502. /package/bin/templates/{pwa → default}/src/middleware/retry.ts +0 -0
  503. /package/bin/templates/{pwa → default}/src/services/auth.ts +0 -0
  504. /package/bin/templates/{pwa → default}/src/services/jwt.ts +0 -0
  505. /package/bin/templates/{pwa → default}/src/services/storage.ts +0 -0
  506. /package/bin/templates/{pwa → default}/src/types/auth.ts +0 -0
  507. /package/bin/templates/{pwa → default}/src/types/notifications.ts +0 -0
  508. /package/bin/templates/{pwa → default}/tests/helpers/test-utils.ts +0 -0
  509. /package/bin/templates/{pwa → default}/tests/middleware/auth.test.ts +0 -0
  510. /package/bin/templates/{pwa → default}/tests/middleware/error.test.ts +0 -0
  511. /package/bin/templates/{pwa → default}/tests/middleware/retry.test.ts +0 -0
  512. /package/bin/templates/{pwa → default}/tests/services/auth.test.ts +0 -0
  513. /package/bin/templates/{pwa → default}/tests/services/jwt.test.ts +0 -0
  514. /package/bin/templates/{pwa → default}/tests/services/storage.test.ts +0 -0
  515. /package/bin/templates/{pwa → default}/vite.config.ts +0 -0
  516. /package/bin/templates/{pwa → default}/vitest.config.ts +0 -0
@@ -0,0 +1,716 @@
1
+ # Grid Component Implementation Plan
2
+
3
+ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
+
5
+ **Goal:** Create `snice-grid`, a grid-coordinate-based layout component with animated transitions and drag-and-drop, mirroring binpack's API patterns.
6
+
7
+ **Architecture:** Items declare grid positions via `grid-col`/`grid-row` attributes (and optional `grid-colspan`/`grid-rowspan`). The component translates coordinates to pixel positions. Collision resolution uses push-right-then-down. Drag snaps to nearest grid cell on release. Container uses `overflow: hidden` when `columns`/`rows` are set.
8
+
9
+ **Tech Stack:** Snice framework (TC39 decorators, shadow DOM), TypeScript, CSS-in-shadow-DOM, Vitest
10
+
11
+ ---
12
+
13
+ ### Task 1: Types File
14
+
15
+ **Files:**
16
+ - Create: `components/grid/snice-grid.types.ts`
17
+
18
+ **Step 1: Write the types file**
19
+
20
+ ```typescript
21
+ export interface SniceGridElement extends HTMLElement {
22
+ gap: string;
23
+ columnWidth: number;
24
+ rowHeight: number;
25
+ columns: number;
26
+ rows: number;
27
+ originLeft: boolean;
28
+ originTop: boolean;
29
+ transitionDuration: string;
30
+ stagger: number;
31
+ resize: boolean;
32
+ draggable: boolean;
33
+ dragThrottle: number;
34
+
35
+ layout(): void;
36
+ fit(element: HTMLElement, col?: number, row?: number): void;
37
+ reloadItems(): void;
38
+ getItemElements(): HTMLElement[];
39
+ getLayout(): GridLayout;
40
+ setLayout(layout: GridLayout): void;
41
+ }
42
+
43
+ export interface GridLayoutEntry {
44
+ col: number;
45
+ row: number;
46
+ colspan?: number;
47
+ rowspan?: number;
48
+ order: number;
49
+ hidden?: boolean;
50
+ }
51
+
52
+ export type GridLayout = Record<string, GridLayoutEntry>;
53
+
54
+ export interface GridLayoutCompleteDetail {
55
+ items: HTMLElement[];
56
+ }
57
+
58
+ export interface GridDragItemPositionedDetail {
59
+ item: HTMLElement;
60
+ col: number;
61
+ row: number;
62
+ }
63
+
64
+ export interface GridEventMap {
65
+ 'grid-layout-complete': CustomEvent<GridLayoutCompleteDetail>;
66
+ 'grid-drag-item-positioned': CustomEvent<GridDragItemPositionedDetail>;
67
+ }
68
+ ```
69
+
70
+ **Step 2: Commit**
71
+
72
+ ```bash
73
+ git add components/grid/snice-grid.types.ts
74
+ git commit -m "feat(grid): add type definitions"
75
+ ```
76
+
77
+ ---
78
+
79
+ ### Task 2: CSS File
80
+
81
+ **Files:**
82
+ - Create: `components/grid/snice-grid.css`
83
+
84
+ **Step 1: Write the CSS**
85
+
86
+ Mirror binpack's CSS structure. Key differences: `--grid-gap` and `--grid-transition-duration` custom property names, `.grid` container class, `overflow: hidden` on `:host`.
87
+
88
+ ```css
89
+ :host {
90
+ display: block;
91
+ position: relative;
92
+ width: 100%;
93
+ font-family: var(--snice-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif);
94
+ contain: layout style;
95
+ --grid-gap: 1rem;
96
+ --grid-transition-duration: 0.4s;
97
+ overflow: hidden;
98
+ }
99
+
100
+ .grid {
101
+ position: relative;
102
+ width: 100%;
103
+ min-height: 1rem;
104
+ }
105
+
106
+ ::slotted(*) {
107
+ position: absolute;
108
+ top: 0;
109
+ left: 0;
110
+ box-sizing: border-box;
111
+ }
112
+
113
+ ::slotted([hidden]) {
114
+ display: none !important;
115
+ }
116
+
117
+ /* Gate transitions behind [ready] to prevent FOUC */
118
+ :host([ready]) ::slotted(*) {
119
+ transition: transform var(--grid-transition-duration) ease;
120
+ }
121
+
122
+ /* Dragging states */
123
+ ::slotted(.grid-dragging) {
124
+ z-index: 100;
125
+ opacity: 0.9;
126
+ transition: none !important;
127
+ cursor: grabbing !important;
128
+ user-select: none;
129
+ }
130
+
131
+ ::slotted(.grid-positioning) {
132
+ z-index: 99;
133
+ }
134
+
135
+ :host([draggable]) ::slotted(*) {
136
+ cursor: grab;
137
+ }
138
+
139
+ /* Drop placeholder */
140
+ .grid-drop-placeholder {
141
+ position: absolute;
142
+ top: 0;
143
+ left: 0;
144
+ outline: 3px dashed rgba(128, 128, 128, 0.5);
145
+ outline-offset: -6px;
146
+ border-radius: 4px;
147
+ transition: transform 0.2s ease;
148
+ pointer-events: none;
149
+ display: none;
150
+ }
151
+
152
+ .grid-drop-placeholder.visible {
153
+ display: block;
154
+ }
155
+ ```
156
+
157
+ **Step 2: Commit**
158
+
159
+ ```bash
160
+ git add components/grid/snice-grid.css
161
+ git commit -m "feat(grid): add component styles"
162
+ ```
163
+
164
+ ---
165
+
166
+ ### Task 3: Test File — Basic Functionality and Properties
167
+
168
+ **Files:**
169
+ - Create: `tests/components/grid.test.ts`
170
+
171
+ **Step 1: Write failing tests**
172
+
173
+ ```typescript
174
+ import { describe, it, expect, afterEach } from 'vitest';
175
+ import { createComponent, removeComponent, wait } from './test-utils';
176
+ import '../../components/grid/snice-grid';
177
+ import type { SniceGridElement } from '../../components/grid/snice-grid.types';
178
+
179
+ describe('snice-grid', () => {
180
+ let el: SniceGridElement;
181
+
182
+ afterEach(() => {
183
+ if (el) {
184
+ removeComponent(el as HTMLElement);
185
+ }
186
+ });
187
+
188
+ describe('basic functionality', () => {
189
+ it('should render grid element', async () => {
190
+ el = await createComponent<SniceGridElement>('snice-grid');
191
+ expect(el).toBeTruthy();
192
+ expect(el.tagName).toBe('SNICE-GRID');
193
+ });
194
+
195
+ it('should have default properties', async () => {
196
+ el = await createComponent<SniceGridElement>('snice-grid');
197
+ expect(el.gap).toBe('1rem');
198
+ expect(el.columnWidth).toBe(80);
199
+ expect(el.rowHeight).toBe(80);
200
+ expect(el.columns).toBe(0);
201
+ expect(el.rows).toBe(0);
202
+ expect(el.originLeft).toBe(true);
203
+ expect(el.originTop).toBe(true);
204
+ expect(el.transitionDuration).toBe('0.4s');
205
+ expect(el.stagger).toBe(0);
206
+ expect(el.resize).toBe(true);
207
+ });
208
+
209
+ it('should render slot element', async () => {
210
+ el = await createComponent<SniceGridElement>('snice-grid');
211
+ const slot = el.shadowRoot?.querySelector('slot');
212
+ expect(slot).toBeTruthy();
213
+ });
214
+
215
+ it('should render container with role=list', async () => {
216
+ el = await createComponent<SniceGridElement>('snice-grid');
217
+ const container = el.shadowRoot?.querySelector('.grid');
218
+ expect(container).toBeTruthy();
219
+ expect(container?.getAttribute('role')).toBe('list');
220
+ });
221
+
222
+ it('should have part=base on container', async () => {
223
+ el = await createComponent<SniceGridElement>('snice-grid');
224
+ const container = el.shadowRoot?.querySelector('[part="base"]');
225
+ expect(container).toBeTruthy();
226
+ });
227
+ });
228
+
229
+ describe('property reflection', () => {
230
+ it('should reflect gap attribute', async () => {
231
+ el = await createComponent<SniceGridElement>('snice-grid', {
232
+ gap: '2rem'
233
+ });
234
+ expect(el.getAttribute('gap')).toBe('2rem');
235
+ expect(el.gap).toBe('2rem');
236
+ });
237
+
238
+ it('should reflect column-width attribute', async () => {
239
+ el = await createComponent<SniceGridElement>('snice-grid', {
240
+ 'column-width': 100
241
+ });
242
+ expect(el.columnWidth).toBe(100);
243
+ });
244
+
245
+ it('should reflect row-height attribute', async () => {
246
+ el = await createComponent<SniceGridElement>('snice-grid', {
247
+ 'row-height': 60
248
+ });
249
+ expect(el.rowHeight).toBe(60);
250
+ });
251
+
252
+ it('should reflect columns attribute', async () => {
253
+ el = await createComponent<SniceGridElement>('snice-grid', {
254
+ columns: 5
255
+ });
256
+ expect(el.columns).toBe(5);
257
+ });
258
+
259
+ it('should reflect rows attribute', async () => {
260
+ el = await createComponent<SniceGridElement>('snice-grid', {
261
+ rows: 4
262
+ });
263
+ expect(el.rows).toBe(4);
264
+ });
265
+
266
+ it('should reflect origin-left attribute', async () => {
267
+ el = await createComponent<SniceGridElement>('snice-grid', {
268
+ 'origin-left': false
269
+ });
270
+ expect(el.originLeft).toBe(false);
271
+ });
272
+
273
+ it('should reflect origin-top attribute', async () => {
274
+ el = await createComponent<SniceGridElement>('snice-grid', {
275
+ 'origin-top': false
276
+ });
277
+ expect(el.originTop).toBe(false);
278
+ });
279
+
280
+ it('should reflect transition-duration attribute', async () => {
281
+ el = await createComponent<SniceGridElement>('snice-grid', {
282
+ 'transition-duration': '1s'
283
+ });
284
+ expect(el.transitionDuration).toBe('1s');
285
+ });
286
+
287
+ it('should reflect stagger attribute', async () => {
288
+ el = await createComponent<SniceGridElement>('snice-grid', {
289
+ stagger: 50
290
+ });
291
+ expect(el.stagger).toBe(50);
292
+ });
293
+
294
+ it('should reflect resize attribute', async () => {
295
+ el = await createComponent<SniceGridElement>('snice-grid', {
296
+ resize: false
297
+ });
298
+ expect(el.resize).toBe(false);
299
+ });
300
+ });
301
+
302
+ describe('API methods', () => {
303
+ it('should expose layout() method', async () => {
304
+ el = await createComponent<SniceGridElement>('snice-grid');
305
+ expect(typeof el.layout).toBe('function');
306
+ el.layout();
307
+ });
308
+
309
+ it('should expose fit() method', async () => {
310
+ el = await createComponent<SniceGridElement>('snice-grid');
311
+ expect(typeof el.fit).toBe('function');
312
+ });
313
+
314
+ it('should expose reloadItems() method', async () => {
315
+ el = await createComponent<SniceGridElement>('snice-grid');
316
+ expect(typeof el.reloadItems).toBe('function');
317
+ el.reloadItems();
318
+ });
319
+
320
+ it('should expose getItemElements() method', async () => {
321
+ el = await createComponent<SniceGridElement>('snice-grid');
322
+ expect(typeof el.getItemElements).toBe('function');
323
+ const items = el.getItemElements();
324
+ expect(Array.isArray(items)).toBe(true);
325
+ expect(items).toHaveLength(0);
326
+ });
327
+
328
+ it('should collect slotted items via getItemElements()', async () => {
329
+ el = await createComponent<SniceGridElement>('snice-grid');
330
+
331
+ const item1 = document.createElement('div');
332
+ item1.setAttribute('name', 'a');
333
+ item1.setAttribute('grid-col', '0');
334
+ item1.setAttribute('grid-row', '0');
335
+ const item2 = document.createElement('div');
336
+ item2.setAttribute('name', 'b');
337
+ item2.setAttribute('grid-col', '1');
338
+ item2.setAttribute('grid-row', '0');
339
+ el.appendChild(item1);
340
+ el.appendChild(item2);
341
+ await wait(50);
342
+
343
+ el.reloadItems();
344
+ await wait(50);
345
+
346
+ const items = el.getItemElements();
347
+ expect(items).toHaveLength(2);
348
+ expect(items).toContain(item1);
349
+ expect(items).toContain(item2);
350
+ });
351
+
352
+ it('should position item at grid coordinates via fit()', async () => {
353
+ el = await createComponent<SniceGridElement>('snice-grid', {
354
+ 'column-width': 80,
355
+ 'row-height': 80,
356
+ gap: '0px'
357
+ });
358
+
359
+ const item = document.createElement('div');
360
+ item.setAttribute('name', 'a');
361
+ item.setAttribute('grid-col', '0');
362
+ item.setAttribute('grid-row', '0');
363
+ el.appendChild(item);
364
+ await wait(50);
365
+ el.reloadItems();
366
+
367
+ el.fit(item, 2, 3);
368
+ // col=2, row=3 with columnWidth=80, rowHeight=80, gap=0
369
+ // x = 2 * (80 + 0) = 160, y = 3 * (80 + 0) = 240
370
+ expect(item.style.transform).toContain('160');
371
+ expect(item.style.transform).toContain('240');
372
+ });
373
+
374
+ it('should ignore fit() on unknown elements', async () => {
375
+ el = await createComponent<SniceGridElement>('snice-grid');
376
+ const outsider = document.createElement('div');
377
+ el.fit(outsider, 1, 1);
378
+ });
379
+ });
380
+
381
+ describe('grid positioning', () => {
382
+ it('should position items based on grid-col and grid-row attributes', async () => {
383
+ el = await createComponent<SniceGridElement>('snice-grid', {
384
+ 'column-width': 100,
385
+ 'row-height': 50,
386
+ gap: '10px'
387
+ });
388
+
389
+ const item = document.createElement('div');
390
+ item.setAttribute('name', 'a');
391
+ item.setAttribute('grid-col', '2');
392
+ item.setAttribute('grid-row', '1');
393
+ el.appendChild(item);
394
+ await wait(50);
395
+ el.reloadItems();
396
+ el.layout();
397
+
398
+ // x = 2 * (100 + 10) = 220, y = 1 * (50 + 10) = 60
399
+ expect(item.style.transform).toBe('translate(220px, 60px)');
400
+ });
401
+
402
+ it('should auto-size items to colspan x rowspan', async () => {
403
+ el = await createComponent<SniceGridElement>('snice-grid', {
404
+ 'column-width': 80,
405
+ 'row-height': 80,
406
+ gap: '8px'
407
+ });
408
+
409
+ const item = document.createElement('div');
410
+ item.setAttribute('name', 'a');
411
+ item.setAttribute('grid-col', '0');
412
+ item.setAttribute('grid-row', '0');
413
+ item.setAttribute('grid-colspan', '2');
414
+ item.setAttribute('grid-rowspan', '3');
415
+ el.appendChild(item);
416
+ await wait(50);
417
+ el.reloadItems();
418
+ el.layout();
419
+
420
+ // width = 2 * 80 + (2 - 1) * 8 = 168
421
+ // height = 3 * 80 + (3 - 1) * 8 = 256
422
+ expect(item.style.width).toBe('168px');
423
+ expect(item.style.height).toBe('256px');
424
+ });
425
+
426
+ it('should hide items with hidden attribute', async () => {
427
+ el = await createComponent<SniceGridElement>('snice-grid');
428
+
429
+ const item = document.createElement('div');
430
+ item.setAttribute('name', 'a');
431
+ item.setAttribute('grid-col', '0');
432
+ item.setAttribute('grid-row', '0');
433
+ item.setAttribute('hidden', '');
434
+ el.appendChild(item);
435
+ await wait(50);
436
+ el.reloadItems();
437
+ el.layout();
438
+
439
+ // Hidden items should not be positioned
440
+ expect(item.style.transform).toBe('');
441
+ });
442
+ });
443
+
444
+ describe('collision resolution', () => {
445
+ it('should push item right when position is occupied', async () => {
446
+ el = await createComponent<SniceGridElement>('snice-grid', {
447
+ 'column-width': 80,
448
+ 'row-height': 80,
449
+ gap: '0px'
450
+ });
451
+
452
+ // Two items at the same position — second should be pushed right
453
+ const item1 = document.createElement('div');
454
+ item1.setAttribute('name', 'a');
455
+ item1.setAttribute('grid-col', '0');
456
+ item1.setAttribute('grid-row', '0');
457
+ const item2 = document.createElement('div');
458
+ item2.setAttribute('name', 'b');
459
+ item2.setAttribute('grid-col', '0');
460
+ item2.setAttribute('grid-row', '0');
461
+ el.appendChild(item1);
462
+ el.appendChild(item2);
463
+ await wait(50);
464
+ el.reloadItems();
465
+ el.layout();
466
+
467
+ // item1 at (0,0), item2 pushed to (1,0) → x=80
468
+ expect(item1.style.transform).toBe('translate(0px, 0px)');
469
+ expect(item2.style.transform).toBe('translate(80px, 0px)');
470
+ });
471
+
472
+ it('should push to next row when row is full', async () => {
473
+ el = await createComponent<SniceGridElement>('snice-grid', {
474
+ 'column-width': 80,
475
+ 'row-height': 80,
476
+ gap: '0px',
477
+ columns: 2
478
+ });
479
+
480
+ // 3 items at (0,0) — third should wrap to next row
481
+ const items: HTMLElement[] = [];
482
+ for (let i = 0; i < 3; i++) {
483
+ const item = document.createElement('div');
484
+ item.setAttribute('name', String.fromCharCode(97 + i));
485
+ item.setAttribute('grid-col', '0');
486
+ item.setAttribute('grid-row', '0');
487
+ items.push(item);
488
+ el.appendChild(item);
489
+ }
490
+ await wait(50);
491
+ el.reloadItems();
492
+ el.layout();
493
+
494
+ expect(items[0].style.transform).toBe('translate(0px, 0px)');
495
+ expect(items[1].style.transform).toBe('translate(80px, 0px)');
496
+ expect(items[2].style.transform).toBe('translate(0px, 80px)');
497
+ });
498
+
499
+ it('should handle colspan collision', async () => {
500
+ el = await createComponent<SniceGridElement>('snice-grid', {
501
+ 'column-width': 80,
502
+ 'row-height': 80,
503
+ gap: '0px',
504
+ columns: 4
505
+ });
506
+
507
+ // item1 at (0,0) colspan=2, item2 at (1,0) — overlaps, should push right to col 2
508
+ const item1 = document.createElement('div');
509
+ item1.setAttribute('name', 'a');
510
+ item1.setAttribute('grid-col', '0');
511
+ item1.setAttribute('grid-row', '0');
512
+ item1.setAttribute('grid-colspan', '2');
513
+ const item2 = document.createElement('div');
514
+ item2.setAttribute('name', 'b');
515
+ item2.setAttribute('grid-col', '1');
516
+ item2.setAttribute('grid-row', '0');
517
+ el.appendChild(item1);
518
+ el.appendChild(item2);
519
+ await wait(50);
520
+ el.reloadItems();
521
+ el.layout();
522
+
523
+ expect(item1.style.transform).toBe('translate(0px, 0px)');
524
+ expect(item2.style.transform).toBe('translate(160px, 0px)');
525
+ });
526
+ });
527
+
528
+ describe('layout persistence', () => {
529
+ it('should return layout via getLayout()', async () => {
530
+ el = await createComponent<SniceGridElement>('snice-grid', {
531
+ 'column-width': 80,
532
+ 'row-height': 80,
533
+ gap: '0px'
534
+ });
535
+
536
+ const item = document.createElement('div');
537
+ item.setAttribute('name', 'myitem');
538
+ item.setAttribute('grid-col', '2');
539
+ item.setAttribute('grid-row', '3');
540
+ el.appendChild(item);
541
+ await wait(50);
542
+ el.reloadItems();
543
+ el.layout();
544
+
545
+ const layout = el.getLayout();
546
+ expect(layout['myitem']).toBeDefined();
547
+ expect(layout['myitem'].col).toBe(2);
548
+ expect(layout['myitem'].row).toBe(3);
549
+ expect(layout['myitem'].order).toBe(0);
550
+ });
551
+
552
+ it('should restore layout via setLayout()', async () => {
553
+ el = await createComponent<SniceGridElement>('snice-grid', {
554
+ 'column-width': 80,
555
+ 'row-height': 80,
556
+ gap: '0px'
557
+ });
558
+
559
+ const item = document.createElement('div');
560
+ item.setAttribute('name', 'myitem');
561
+ item.setAttribute('grid-col', '0');
562
+ item.setAttribute('grid-row', '0');
563
+ el.appendChild(item);
564
+ await wait(50);
565
+ el.reloadItems();
566
+
567
+ el.setLayout({
568
+ myitem: { col: 3, row: 2, order: 0 }
569
+ });
570
+
571
+ // x = 3 * 80 = 240, y = 2 * 80 = 160
572
+ expect(item.style.transform).toBe('translate(240px, 160px)');
573
+ });
574
+ });
575
+
576
+ describe('events', () => {
577
+ it('should fire grid-layout-complete on layout()', async () => {
578
+ el = await createComponent<SniceGridElement>('snice-grid');
579
+
580
+ let eventFired = false;
581
+ (el as HTMLElement).addEventListener('grid-layout-complete', () => {
582
+ eventFired = true;
583
+ });
584
+
585
+ el.layout();
586
+ expect(eventFired).toBe(true);
587
+ });
588
+ });
589
+
590
+ describe('ready attribute', () => {
591
+ it('should set ready attribute after initialization', async () => {
592
+ el = await createComponent<SniceGridElement>('snice-grid');
593
+ await wait(20);
594
+ expect(el.hasAttribute('ready')).toBe(true);
595
+ });
596
+ });
597
+ });
598
+ ```
599
+
600
+ **Step 2: Run tests to verify they fail**
601
+
602
+ Run: `npx vitest run tests/components/grid.test.ts`
603
+ Expected: FAIL — module `../../components/grid/snice-grid` not found
604
+
605
+ **Step 3: Commit**
606
+
607
+ ```bash
608
+ git add tests/components/grid.test.ts
609
+ git commit -m "test(grid): add failing tests for grid component"
610
+ ```
611
+
612
+ ---
613
+
614
+ ### Task 4: Grid Component — Core Layout Engine
615
+
616
+ **Files:**
617
+ - Create: `components/grid/snice-grid.ts`
618
+
619
+ This is the main implementation file. Structure mirrors binpack exactly:
620
+ 1. Imports and types
621
+ 2. `OccupancyGrid` helper class (replaces binpack's `Packer`)
622
+ 3. `SniceGrid` component class with decorators
623
+
624
+ **Step 1: Write the component**
625
+
626
+ The component has these sections:
627
+
628
+ **OccupancyGrid class** — A 2D boolean grid tracking occupied cells. Methods:
629
+ - `occupy(col, row, colspan, rowspan)` — marks cells as taken
630
+ - `isOccupied(col, row, colspan, rowspan)` — checks if any cell in the range is taken
631
+ - `findNextFree(col, row, colspan, rowspan, maxCols)` — scans right-then-down for open space
632
+ - `grow(col, row)` — expands grid dimensions as needed
633
+
634
+ **SniceGrid class** — Same decorator pattern as binpack:
635
+ - `@element('snice-grid')`, `@property()` for all properties
636
+ - `@query()` for `.grid`, `slot`, `.grid-drop-placeholder`
637
+ - `@ready()` / `@dispose()` lifecycle
638
+ - `@watch()` for property change → relayout
639
+ - `@dispatch()` for events
640
+ - `@render()` template, `@styles()` CSS
641
+ - `performLayout()` — reads item attributes, builds occupancy grid, resolves collisions, positions items
642
+ - Same drag implementation as binpack but snapping to grid cells on release
643
+
644
+ Key implementation details:
645
+ - `performLayout()`: iterate items in DOM order, read `grid-col`/`grid-row`/`grid-colspan`/`grid-rowspan` attributes, check occupancy grid, if collision → `findNextFree()`, set `transform` and `width`/`height`
646
+ - `fit(el, col, row)`: update element's `grid-col`/`grid-row` attributes, call `performLayout()`
647
+ - `getLayout()`: read current resolved positions from item attributes
648
+ - `setLayout()`: set attributes from map, reorder DOM, call `performLayout()`
649
+ - Container sizing: after layout, compute `maxCol`/`maxRow` from placed items, set container width/height. If `columns`/`rows` set, use those for fixed size
650
+ - Drag: on release, compute nearest cell from pixel position, call `fit()` which triggers collision resolution
651
+
652
+ **Step 2: Run tests**
653
+
654
+ Run: `npx vitest run tests/components/grid.test.ts`
655
+ Expected: ALL PASS
656
+
657
+ **Step 3: Commit**
658
+
659
+ ```bash
660
+ git add components/grid/snice-grid.ts
661
+ git commit -m "feat(grid): implement core grid layout component"
662
+ ```
663
+
664
+ ---
665
+
666
+ ### Task 5: Demo HTML
667
+
668
+ **Files:**
669
+ - Create: `components/grid/demo.html`
670
+
671
+ **Step 1: Write basic demo page**
672
+
673
+ Simple demo with a few items at various grid positions, some spanning multiple cells. Include controls to toggle draggable, change column/row counts. Follow the pattern from `components/binpack/demo.html`.
674
+
675
+ **Step 2: Manual verification**
676
+
677
+ Run: `npx vite --open components/grid/demo.html`
678
+ Verify: Items appear at correct grid positions, spanning works, collision pushes items right.
679
+
680
+ **Step 3: Commit**
681
+
682
+ ```bash
683
+ git add components/grid/demo.html
684
+ git commit -m "feat(grid): add demo page"
685
+ ```
686
+
687
+ ---
688
+
689
+ ### Task 6: Run Full Test Suite
690
+
691
+ **Step 1: Run all tests**
692
+
693
+ Run: `npx vitest run`
694
+ Expected: All tests pass, no regressions.
695
+
696
+ **Step 2: Final commit if any fixes needed**
697
+
698
+ ---
699
+
700
+ ### Task 7: CDN Build Setup
701
+
702
+ **Files:**
703
+ - Modify: Check if `snice.config.ts` or equivalent needs a grid entry for CDN build
704
+
705
+ **Step 1: Build the component for CDN**
706
+
707
+ ```bash
708
+ npm run build:core
709
+ npx snice build-component grid
710
+ ```
711
+
712
+ **Step 2: Verify CDN bundle exists**
713
+
714
+ Check `dist/cdn/grid/snice-grid.min.js` exists.
715
+
716
+ **Step 3: Commit if config changes were needed**