snice 4.28.0 → 4.30.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 (835) 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/action-bar.d.ts +30 -0
  9. package/adapters/react/action-bar.d.ts.map +1 -0
  10. package/adapters/react/action-bar.js +24 -0
  11. package/adapters/react/action-bar.js.map +1 -0
  12. package/adapters/react/action-bar.tsx +38 -0
  13. package/adapters/react/binpack.d.ts +35 -0
  14. package/adapters/react/binpack.d.ts.map +1 -0
  15. package/adapters/react/binpack.js +24 -0
  16. package/adapters/react/binpack.js.map +1 -0
  17. package/adapters/react/binpack.tsx +43 -0
  18. package/adapters/react/components.d.ts +6 -0
  19. package/adapters/react/components.d.ts.map +1 -1
  20. package/adapters/react/components.js +3 -0
  21. package/adapters/react/components.js.map +1 -1
  22. package/adapters/react/components.ts +6 -0
  23. package/adapters/react/grid.d.ts +36 -0
  24. package/adapters/react/grid.d.ts.map +1 -0
  25. package/adapters/react/grid.js +24 -0
  26. package/adapters/react/grid.js.map +1 -0
  27. package/adapters/react/grid.tsx +44 -0
  28. package/adapters/react/index.d.ts +5 -0
  29. package/adapters/react/index.d.ts.map +1 -1
  30. package/adapters/react/index.js +3 -2
  31. package/adapters/react/index.js.map +1 -1
  32. package/adapters/react/index.ts +6 -3
  33. package/adapters/react/matchRoute.d.ts +16 -0
  34. package/adapters/react/matchRoute.js +32 -0
  35. package/adapters/react/matchRoute.js.map +1 -0
  36. package/adapters/react/types.d.ts +1 -15
  37. package/adapters/react/types.d.ts.map +1 -1
  38. package/adapters/react/types.ts +1 -15
  39. package/adapters/react/useRequestHandler.d.ts +56 -0
  40. package/adapters/react/useRequestHandler.js +103 -0
  41. package/adapters/react/useRequestHandler.js.map +1 -0
  42. package/bin/snice.js +8 -13
  43. package/bin/templates/{pwa → default}/index.html +1 -1
  44. package/bin/templates/{pwa → default}/src/components/app-header.ts +36 -18
  45. package/bin/templates/{pwa → default}/src/components/notification-badge.ts +2 -21
  46. package/bin/templates/{pwa → default}/src/components/search-bar.ts +12 -12
  47. package/bin/templates/default/src/context.ts +17 -0
  48. package/bin/templates/{pwa → default}/src/controllers/notification-controller.ts +10 -15
  49. package/bin/templates/{pwa → default}/src/daemons/notifications.ts +0 -12
  50. package/bin/templates/{pwa → default}/src/main.ts +1 -7
  51. package/bin/templates/{pwa → default}/src/middleware/error.ts +1 -8
  52. package/bin/templates/{pwa → default}/src/pages/dashboard.ts +17 -18
  53. package/bin/templates/{pwa → default}/src/pages/data.ts +24 -24
  54. package/bin/templates/{pwa → default}/src/pages/login.ts +3 -6
  55. package/bin/templates/{pwa → default}/src/pages/notifications.ts +21 -19
  56. package/bin/templates/{pwa → default}/src/pages/profile.ts +10 -12
  57. package/bin/templates/{pwa → default}/src/pages/settings.ts +22 -22
  58. package/bin/templates/default/src/router.ts +13 -0
  59. package/bin/templates/default/src/styles/global.css +16 -0
  60. package/bin/templates/{pwa → default}/tsconfig.json +2 -1
  61. package/bin/templates/react/README.md +124 -0
  62. package/bin/templates/react/global.d.ts +10 -0
  63. package/bin/templates/react/index.html +15 -0
  64. package/bin/templates/react/package.json +31 -0
  65. package/bin/templates/react/src/App.tsx +112 -0
  66. package/bin/templates/react/src/components/AppHeader.tsx +85 -0
  67. package/bin/templates/react/src/components/AppLayout.tsx +11 -0
  68. package/bin/templates/react/src/components/NotificationBadge.tsx +13 -0
  69. package/bin/templates/react/src/components/SearchBar.tsx +63 -0
  70. package/bin/templates/react/src/daemons/notifications.ts +136 -0
  71. package/bin/templates/react/src/fetcher.ts +15 -0
  72. package/bin/templates/react/src/guards/auth.ts +6 -0
  73. package/bin/templates/react/src/main.tsx +27 -0
  74. package/bin/templates/react/src/middleware/auth.ts +16 -0
  75. package/bin/templates/react/src/middleware/error.ts +29 -0
  76. package/bin/templates/react/src/middleware/retry.ts +31 -0
  77. package/bin/templates/react/src/pages/DashboardPage.tsx +111 -0
  78. package/bin/templates/react/src/pages/DataPage.tsx +119 -0
  79. package/bin/templates/react/src/pages/LoginPage.tsx +46 -0
  80. package/bin/templates/react/src/pages/NotificationsPage.tsx +119 -0
  81. package/bin/templates/react/src/pages/ProfilePage.tsx +92 -0
  82. package/bin/templates/react/src/pages/SettingsPage.tsx +165 -0
  83. package/bin/templates/react/src/services/auth.ts +48 -0
  84. package/bin/templates/react/src/services/jwt.ts +35 -0
  85. package/bin/templates/react/src/services/storage.ts +24 -0
  86. package/bin/templates/react/src/styles/global.css +382 -0
  87. package/bin/templates/react/src/types/auth.ts +21 -0
  88. package/bin/templates/react/src/types/notifications.ts +9 -0
  89. package/bin/templates/react/tests/helpers/test-utils.ts +79 -0
  90. package/bin/templates/react/tests/middleware/auth.test.ts +67 -0
  91. package/bin/templates/react/tests/middleware/error.test.ts +105 -0
  92. package/bin/templates/react/tests/middleware/retry.test.ts +103 -0
  93. package/bin/templates/react/tests/services/auth.test.ts +89 -0
  94. package/bin/templates/react/tests/services/jwt.test.ts +76 -0
  95. package/bin/templates/react/tests/services/storage.test.ts +69 -0
  96. package/bin/templates/{base → react}/tsconfig.json +4 -6
  97. package/bin/templates/react/vite.config.ts +18 -0
  98. package/bin/templates/react/vitest.config.ts +18 -0
  99. package/dist/cdn/accordion/snice-accordion.js +1 -1
  100. package/dist/cdn/accordion/snice-accordion.min.js +1 -1
  101. package/dist/cdn/action-bar/README.md +27 -0
  102. package/dist/cdn/action-bar/snice-action-bar.js +249 -0
  103. package/dist/cdn/action-bar/snice-action-bar.js.map +1 -0
  104. package/dist/cdn/action-bar/snice-action-bar.min.js +12 -0
  105. package/dist/cdn/action-bar/snice-action-bar.min.js.map +1 -0
  106. package/dist/cdn/activity-feed/snice-activity-feed.js +1 -1
  107. package/dist/cdn/activity-feed/snice-activity-feed.min.js +1 -1
  108. package/dist/cdn/alert/snice-alert.js +1 -1
  109. package/dist/cdn/alert/snice-alert.min.js +1 -1
  110. package/dist/cdn/app-tiles/snice-app-tiles.js +1 -1
  111. package/dist/cdn/app-tiles/snice-app-tiles.min.js +1 -1
  112. package/dist/cdn/approval-flow/snice-approval-flow.js +1 -1
  113. package/dist/cdn/approval-flow/snice-approval-flow.min.js +1 -1
  114. package/dist/cdn/audio-recorder/snice-audio-recorder.js +1 -1
  115. package/dist/cdn/audio-recorder/snice-audio-recorder.min.js +1 -1
  116. package/dist/cdn/availability/snice-availability.js +1 -1
  117. package/dist/cdn/availability/snice-availability.min.js +1 -1
  118. package/dist/cdn/avatar/snice-avatar.js +1 -1
  119. package/dist/cdn/avatar/snice-avatar.min.js +1 -1
  120. package/dist/cdn/avatar-group/snice-avatar-group.js +1 -1
  121. package/dist/cdn/avatar-group/snice-avatar-group.min.js +1 -1
  122. package/dist/cdn/badge/snice-badge.js +1 -1
  123. package/dist/cdn/badge/snice-badge.min.js +1 -1
  124. package/dist/cdn/banner/snice-banner.js +1 -1
  125. package/dist/cdn/banner/snice-banner.min.js +1 -1
  126. package/dist/cdn/binpack/README.md +27 -0
  127. package/dist/cdn/binpack/snice-binpack.js +1037 -0
  128. package/dist/cdn/binpack/snice-binpack.js.map +1 -0
  129. package/dist/cdn/binpack/snice-binpack.min.js +13 -0
  130. package/dist/cdn/binpack/snice-binpack.min.js.map +1 -0
  131. package/dist/cdn/book/snice-book.js +1 -1
  132. package/dist/cdn/book/snice-book.min.js +1 -1
  133. package/dist/cdn/booking/snice-booking.js +1 -1
  134. package/dist/cdn/booking/snice-booking.min.js +1 -1
  135. package/dist/cdn/breadcrumbs/snice-breadcrumbs.js +1 -1
  136. package/dist/cdn/breadcrumbs/snice-breadcrumbs.min.js +1 -1
  137. package/dist/cdn/button/README.md +1 -1
  138. package/dist/cdn/button/snice-button.js +2 -2
  139. package/dist/cdn/button/snice-button.js.map +1 -1
  140. package/dist/cdn/button/snice-button.min.js +2 -2
  141. package/dist/cdn/button/snice-button.min.js.map +1 -1
  142. package/dist/cdn/calendar/snice-calendar.js +1 -1
  143. package/dist/cdn/calendar/snice-calendar.min.js +1 -1
  144. package/dist/cdn/camera/snice-camera.js +1 -1
  145. package/dist/cdn/camera/snice-camera.min.js +1 -1
  146. package/dist/cdn/camera-annotate/snice-camera-annotate.js +1 -1
  147. package/dist/cdn/camera-annotate/snice-camera-annotate.min.js +1 -1
  148. package/dist/cdn/candlestick/snice-candlestick.js +1 -1
  149. package/dist/cdn/candlestick/snice-candlestick.min.js +1 -1
  150. package/dist/cdn/card/snice-card.js +1 -1
  151. package/dist/cdn/card/snice-card.min.js +1 -1
  152. package/dist/cdn/carousel/snice-carousel.js +1 -1
  153. package/dist/cdn/carousel/snice-carousel.min.js +1 -1
  154. package/dist/cdn/cart/snice-cart.js +1 -1
  155. package/dist/cdn/cart/snice-cart.min.js +1 -1
  156. package/dist/cdn/chart/snice-chart.js +1 -1
  157. package/dist/cdn/chart/snice-chart.min.js +1 -1
  158. package/dist/cdn/chat/snice-chat.js +1 -1
  159. package/dist/cdn/chat/snice-chat.min.js +1 -1
  160. package/dist/cdn/checkbox/snice-checkbox.js +1 -1
  161. package/dist/cdn/checkbox/snice-checkbox.min.js +1 -1
  162. package/dist/cdn/chip/README.md +2 -2
  163. package/dist/cdn/chip/snice-chip.js +2 -2
  164. package/dist/cdn/chip/snice-chip.js.map +1 -1
  165. package/dist/cdn/chip/snice-chip.min.js +3 -3
  166. package/dist/cdn/chip/snice-chip.min.js.map +1 -1
  167. package/dist/cdn/code-block/snice-code-block.js +1 -1
  168. package/dist/cdn/code-block/snice-code-block.min.js +1 -1
  169. package/dist/cdn/color-display/snice-color-display.js +1 -1
  170. package/dist/cdn/color-display/snice-color-display.min.js +1 -1
  171. package/dist/cdn/color-picker/snice-color-picker.js +1 -1
  172. package/dist/cdn/color-picker/snice-color-picker.min.js +1 -1
  173. package/dist/cdn/command-palette/snice-command-palette.js +1 -1
  174. package/dist/cdn/command-palette/snice-command-palette.min.js +1 -1
  175. package/dist/cdn/comments/snice-comments.js +1 -1
  176. package/dist/cdn/comments/snice-comments.min.js +1 -1
  177. package/dist/cdn/countdown/snice-countdown.js +1 -1
  178. package/dist/cdn/countdown/snice-countdown.min.js +1 -1
  179. package/dist/cdn/cropper/snice-cropper.js +1 -1
  180. package/dist/cdn/cropper/snice-cropper.min.js +1 -1
  181. package/dist/cdn/data-card/snice-data-card.js +1 -1
  182. package/dist/cdn/data-card/snice-data-card.min.js +1 -1
  183. package/dist/cdn/date-picker/README.md +1 -1
  184. package/dist/cdn/date-picker/snice-date-picker.js +2 -2
  185. package/dist/cdn/date-picker/snice-date-picker.js.map +1 -1
  186. package/dist/cdn/date-picker/snice-date-picker.min.js +2 -2
  187. package/dist/cdn/date-picker/snice-date-picker.min.js.map +1 -1
  188. package/dist/cdn/date-range-picker/README.md +1 -1
  189. package/dist/cdn/date-range-picker/snice-date-range-picker.js +2 -2
  190. package/dist/cdn/date-range-picker/snice-date-range-picker.js.map +1 -1
  191. package/dist/cdn/date-range-picker/snice-date-range-picker.min.js +11 -11
  192. package/dist/cdn/date-range-picker/snice-date-range-picker.min.js.map +1 -1
  193. package/dist/cdn/date-time-picker/README.md +1 -1
  194. package/dist/cdn/date-time-picker/snice-date-time-picker.js +2 -2
  195. package/dist/cdn/date-time-picker/snice-date-time-picker.js.map +1 -1
  196. package/dist/cdn/date-time-picker/snice-date-time-picker.min.js +2 -2
  197. package/dist/cdn/date-time-picker/snice-date-time-picker.min.js.map +1 -1
  198. package/dist/cdn/diff/snice-diff.js +1 -1
  199. package/dist/cdn/diff/snice-diff.min.js +1 -1
  200. package/dist/cdn/divider/snice-divider.js +1 -1
  201. package/dist/cdn/divider/snice-divider.min.js +1 -1
  202. package/dist/cdn/doc/snice-doc.js +1 -1
  203. package/dist/cdn/doc/snice-doc.min.js +1 -1
  204. package/dist/cdn/draw/README.md +2 -2
  205. package/dist/cdn/draw/snice-draw.js +26 -4
  206. package/dist/cdn/draw/snice-draw.js.map +1 -1
  207. package/dist/cdn/draw/snice-draw.min.js +3 -3
  208. package/dist/cdn/draw/snice-draw.min.js.map +1 -1
  209. package/dist/cdn/drawer/snice-drawer.js +1 -1
  210. package/dist/cdn/drawer/snice-drawer.min.js +1 -1
  211. package/dist/cdn/empty-state/snice-empty-state.js +1 -1
  212. package/dist/cdn/empty-state/snice-empty-state.min.js +1 -1
  213. package/dist/cdn/estimate/snice-estimate.js +1 -1
  214. package/dist/cdn/estimate/snice-estimate.min.js +1 -1
  215. package/dist/cdn/file-gallery/snice-file-gallery.js +1 -1
  216. package/dist/cdn/file-gallery/snice-file-gallery.min.js +1 -1
  217. package/dist/cdn/file-upload/snice-file-upload.js +1 -1
  218. package/dist/cdn/file-upload/snice-file-upload.min.js +1 -1
  219. package/dist/cdn/flip-card/snice-flip-card.js +1 -1
  220. package/dist/cdn/flip-card/snice-flip-card.min.js +1 -1
  221. package/dist/cdn/flow/snice-flow.js +1 -1
  222. package/dist/cdn/flow/snice-flow.min.js +1 -1
  223. package/dist/cdn/form-layout/snice-form-layout.js +1 -1
  224. package/dist/cdn/form-layout/snice-form-layout.min.js +1 -1
  225. package/dist/cdn/funnel/snice-funnel.js +1 -1
  226. package/dist/cdn/funnel/snice-funnel.min.js +1 -1
  227. package/dist/cdn/gantt/snice-gantt.js +1 -1
  228. package/dist/cdn/gantt/snice-gantt.min.js +1 -1
  229. package/dist/cdn/gauge/snice-gauge.js +1 -1
  230. package/dist/cdn/gauge/snice-gauge.min.js +1 -1
  231. package/dist/cdn/grid/README.md +27 -0
  232. package/dist/cdn/grid/snice-grid.js +862 -0
  233. package/dist/cdn/grid/snice-grid.js.map +1 -0
  234. package/dist/cdn/grid/snice-grid.min.js +13 -0
  235. package/dist/cdn/grid/snice-grid.min.js.map +1 -0
  236. package/dist/cdn/heatmap/snice-heatmap.js +1 -1
  237. package/dist/cdn/heatmap/snice-heatmap.min.js +1 -1
  238. package/dist/cdn/image/snice-image.js +1 -1
  239. package/dist/cdn/image/snice-image.min.js +1 -1
  240. package/dist/cdn/input/snice-input.js +1 -1
  241. package/dist/cdn/input/snice-input.min.js +1 -1
  242. package/dist/cdn/invoice/snice-invoice.js +1 -1
  243. package/dist/cdn/invoice/snice-invoice.min.js +1 -1
  244. package/dist/cdn/kanban/snice-kanban.js +1 -1
  245. package/dist/cdn/kanban/snice-kanban.min.js +1 -1
  246. package/dist/cdn/key-value/snice-key-value.js +1 -1
  247. package/dist/cdn/key-value/snice-key-value.min.js +1 -1
  248. package/dist/cdn/kpi/snice-kpi.js +1 -1
  249. package/dist/cdn/kpi/snice-kpi.min.js +1 -1
  250. package/dist/cdn/layout/snice-layout.js +1 -1
  251. package/dist/cdn/layout/snice-layout.min.js +1 -1
  252. package/dist/cdn/leaderboard/snice-leaderboard.js +1 -1
  253. package/dist/cdn/leaderboard/snice-leaderboard.min.js +1 -1
  254. package/dist/cdn/link/snice-link.js +1 -1
  255. package/dist/cdn/link/snice-link.min.js +1 -1
  256. package/dist/cdn/link-preview/snice-link-preview.js +1 -1
  257. package/dist/cdn/link-preview/snice-link-preview.min.js +1 -1
  258. package/dist/cdn/list/snice-list.js +1 -1
  259. package/dist/cdn/list/snice-list.min.js +1 -1
  260. package/dist/cdn/location/snice-location.js +1 -1
  261. package/dist/cdn/location/snice-location.min.js +1 -1
  262. package/dist/cdn/login/README.md +2 -2
  263. package/dist/cdn/login/snice-login.js +2 -2
  264. package/dist/cdn/login/snice-login.js.map +1 -1
  265. package/dist/cdn/login/snice-login.min.js +2 -2
  266. package/dist/cdn/login/snice-login.min.js.map +1 -1
  267. package/dist/cdn/map/snice-map.js +1 -1
  268. package/dist/cdn/map/snice-map.min.js +1 -1
  269. package/dist/cdn/markdown/snice-markdown.js +1 -1
  270. package/dist/cdn/markdown/snice-markdown.min.js +1 -1
  271. package/dist/cdn/masonry/snice-masonry.js +1 -1
  272. package/dist/cdn/masonry/snice-masonry.min.js +1 -1
  273. package/dist/cdn/menu/snice-menu.js +1 -1
  274. package/dist/cdn/menu/snice-menu.min.js +1 -1
  275. package/dist/cdn/message-strip/README.md +2 -2
  276. package/dist/cdn/message-strip/snice-message-strip.js +2 -2
  277. package/dist/cdn/message-strip/snice-message-strip.js.map +1 -1
  278. package/dist/cdn/message-strip/snice-message-strip.min.js +6 -6
  279. package/dist/cdn/message-strip/snice-message-strip.min.js.map +1 -1
  280. package/dist/cdn/metric-table/snice-metric-table.js +1 -1
  281. package/dist/cdn/metric-table/snice-metric-table.min.js +1 -1
  282. package/dist/cdn/modal/snice-modal.js +1 -1
  283. package/dist/cdn/modal/snice-modal.min.js +1 -1
  284. package/dist/cdn/music-player/snice-music-player.js +1 -1
  285. package/dist/cdn/music-player/snice-music-player.min.js +1 -1
  286. package/dist/cdn/nav/snice-nav.js +1 -1
  287. package/dist/cdn/nav/snice-nav.min.js +1 -1
  288. package/dist/cdn/network-graph/snice-network-graph.js +1 -1
  289. package/dist/cdn/network-graph/snice-network-graph.min.js +1 -1
  290. package/dist/cdn/notification-center/snice-notification-center.js +1 -1
  291. package/dist/cdn/notification-center/snice-notification-center.min.js +1 -1
  292. package/dist/cdn/order-tracker/snice-order-tracker.js +1 -1
  293. package/dist/cdn/order-tracker/snice-order-tracker.min.js +1 -1
  294. package/dist/cdn/org-chart/snice-org-chart.js +1 -1
  295. package/dist/cdn/org-chart/snice-org-chart.min.js +1 -1
  296. package/dist/cdn/pagination/snice-pagination.js +1 -1
  297. package/dist/cdn/pagination/snice-pagination.min.js +1 -1
  298. package/dist/cdn/paint/README.md +2 -2
  299. package/dist/cdn/paint/snice-paint.js +26 -3
  300. package/dist/cdn/paint/snice-paint.js.map +1 -1
  301. package/dist/cdn/paint/snice-paint.min.js +3 -3
  302. package/dist/cdn/paint/snice-paint.min.js.map +1 -1
  303. package/dist/cdn/pdf-viewer/snice-pdf-viewer.js +1 -1
  304. package/dist/cdn/pdf-viewer/snice-pdf-viewer.min.js +1 -1
  305. package/dist/cdn/permission-matrix/snice-permission-matrix.js +1 -1
  306. package/dist/cdn/permission-matrix/snice-permission-matrix.min.js +1 -1
  307. package/dist/cdn/podcast-player/snice-podcast-player.js +1 -1
  308. package/dist/cdn/podcast-player/snice-podcast-player.min.js +1 -1
  309. package/dist/cdn/pricing-table/snice-pricing-table.js +1 -1
  310. package/dist/cdn/pricing-table/snice-pricing-table.min.js +1 -1
  311. package/dist/cdn/product-card/README.md +1 -1
  312. package/dist/cdn/product-card/snice-product-card.js +1 -1
  313. package/dist/cdn/product-card/snice-product-card.min.js +1 -1
  314. package/dist/cdn/progress/snice-progress.js +1 -1
  315. package/dist/cdn/progress/snice-progress.min.js +1 -1
  316. package/dist/cdn/progress-ring/snice-progress-ring.js +1 -1
  317. package/dist/cdn/progress-ring/snice-progress-ring.min.js +1 -1
  318. package/dist/cdn/qr-code/snice-qr-code.js +1 -1
  319. package/dist/cdn/qr-code/snice-qr-code.min.js +1 -1
  320. package/dist/cdn/qr-reader/snice-qr-reader.js +1 -1
  321. package/dist/cdn/qr-reader/snice-qr-reader.min.js +1 -1
  322. package/dist/cdn/radio/snice-radio.js +1 -1
  323. package/dist/cdn/radio/snice-radio.min.js +1 -1
  324. package/dist/cdn/range-slider/snice-range-slider.js +1 -1
  325. package/dist/cdn/range-slider/snice-range-slider.min.js +1 -1
  326. package/dist/cdn/rating/snice-rating.js +1 -1
  327. package/dist/cdn/rating/snice-rating.min.js +1 -1
  328. package/dist/cdn/receipt/snice-receipt.js +1 -1
  329. package/dist/cdn/receipt/snice-receipt.min.js +1 -1
  330. package/dist/cdn/recipe/snice-recipe.js +1 -1
  331. package/dist/cdn/recipe/snice-recipe.min.js +1 -1
  332. package/dist/cdn/runtime/README.md +2 -2
  333. package/dist/cdn/runtime/snice-runtime.esm.js +109 -16
  334. package/dist/cdn/runtime/snice-runtime.esm.js.map +1 -1
  335. package/dist/cdn/runtime/snice-runtime.esm.min.js +8 -8
  336. package/dist/cdn/runtime/snice-runtime.esm.min.js.map +1 -1
  337. package/dist/cdn/runtime/snice-runtime.js +109 -15
  338. package/dist/cdn/runtime/snice-runtime.js.map +1 -1
  339. package/dist/cdn/runtime/snice-runtime.min.js +7 -7
  340. package/dist/cdn/runtime/snice-runtime.min.js.map +1 -1
  341. package/dist/cdn/sankey/snice-sankey.js +1 -1
  342. package/dist/cdn/sankey/snice-sankey.min.js +1 -1
  343. package/dist/cdn/segmented-control/snice-segmented-control.js +1 -1
  344. package/dist/cdn/segmented-control/snice-segmented-control.min.js +1 -1
  345. package/dist/cdn/select/snice-select.js +1 -1
  346. package/dist/cdn/select/snice-select.min.js +1 -1
  347. package/dist/cdn/skeleton/snice-skeleton.js +1 -1
  348. package/dist/cdn/skeleton/snice-skeleton.min.js +1 -1
  349. package/dist/cdn/slider/snice-slider.js +1 -1
  350. package/dist/cdn/slider/snice-slider.min.js +1 -1
  351. package/dist/cdn/sortable/snice-sortable.js +1 -1
  352. package/dist/cdn/sortable/snice-sortable.min.js +1 -1
  353. package/dist/cdn/sparkline/snice-sparkline.js +1 -1
  354. package/dist/cdn/sparkline/snice-sparkline.min.js +1 -1
  355. package/dist/cdn/spinner/snice-spinner.js +1 -1
  356. package/dist/cdn/spinner/snice-spinner.min.js +1 -1
  357. package/dist/cdn/split-button/snice-split-button.js +1 -1
  358. package/dist/cdn/split-button/snice-split-button.min.js +1 -1
  359. package/dist/cdn/split-pane/snice-split-pane.js +1 -1
  360. package/dist/cdn/split-pane/snice-split-pane.min.js +1 -1
  361. package/dist/cdn/spotlight/snice-spotlight.js +1 -1
  362. package/dist/cdn/spotlight/snice-spotlight.min.js +1 -1
  363. package/dist/cdn/spreadsheet/snice-spreadsheet.js +1 -1
  364. package/dist/cdn/spreadsheet/snice-spreadsheet.min.js +1 -1
  365. package/dist/cdn/stat-group/snice-stat-group.js +1 -1
  366. package/dist/cdn/stat-group/snice-stat-group.min.js +1 -1
  367. package/dist/cdn/step-input/snice-step-input.js +1 -1
  368. package/dist/cdn/step-input/snice-step-input.min.js +1 -1
  369. package/dist/cdn/stepper/snice-stepper.js +1 -1
  370. package/dist/cdn/stepper/snice-stepper.min.js +1 -1
  371. package/dist/cdn/switch/snice-switch.js +1 -1
  372. package/dist/cdn/switch/snice-switch.min.js +1 -1
  373. package/dist/cdn/table/README.md +1 -1
  374. package/dist/cdn/table/snice-table.js +2 -2
  375. package/dist/cdn/table/snice-table.js.map +1 -1
  376. package/dist/cdn/table/snice-table.min.js +2 -2
  377. package/dist/cdn/table/snice-table.min.js.map +1 -1
  378. package/dist/cdn/tabs/snice-tabs.js +1 -1
  379. package/dist/cdn/tabs/snice-tabs.min.js +1 -1
  380. package/dist/cdn/tag/README.md +1 -1
  381. package/dist/cdn/tag/snice-tag.js +2 -2
  382. package/dist/cdn/tag/snice-tag.js.map +1 -1
  383. package/dist/cdn/tag/snice-tag.min.js +3 -3
  384. package/dist/cdn/tag/snice-tag.min.js.map +1 -1
  385. package/dist/cdn/tag-input/README.md +2 -2
  386. package/dist/cdn/tag-input/snice-tag-input.js +2 -2
  387. package/dist/cdn/tag-input/snice-tag-input.js.map +1 -1
  388. package/dist/cdn/tag-input/snice-tag-input.min.js +2 -2
  389. package/dist/cdn/tag-input/snice-tag-input.min.js.map +1 -1
  390. package/dist/cdn/terminal/snice-terminal.js +1 -1
  391. package/dist/cdn/terminal/snice-terminal.min.js +1 -1
  392. package/dist/cdn/testimonial/snice-testimonial.js +1 -1
  393. package/dist/cdn/testimonial/snice-testimonial.min.js +1 -1
  394. package/dist/cdn/textarea/snice-textarea.js +1 -1
  395. package/dist/cdn/textarea/snice-textarea.min.js +1 -1
  396. package/dist/cdn/time-picker/README.md +1 -1
  397. package/dist/cdn/time-picker/snice-time-picker.js +2 -2
  398. package/dist/cdn/time-picker/snice-time-picker.js.map +1 -1
  399. package/dist/cdn/time-picker/snice-time-picker.min.js +2 -2
  400. package/dist/cdn/time-picker/snice-time-picker.min.js.map +1 -1
  401. package/dist/cdn/time-range-picker/snice-time-range-picker.js +1 -1
  402. package/dist/cdn/time-range-picker/snice-time-range-picker.min.js +1 -1
  403. package/dist/cdn/timeline/snice-timeline.js +1 -1
  404. package/dist/cdn/timeline/snice-timeline.min.js +1 -1
  405. package/dist/cdn/timer/snice-timer.js +1 -1
  406. package/dist/cdn/timer/snice-timer.min.js +1 -1
  407. package/dist/cdn/toast/README.md +1 -1
  408. package/dist/cdn/toast/snice-toast.js +7 -3
  409. package/dist/cdn/toast/snice-toast.js.map +1 -1
  410. package/dist/cdn/toast/snice-toast.min.js +6 -6
  411. package/dist/cdn/toast/snice-toast.min.js.map +1 -1
  412. package/dist/cdn/tooltip/snice-tooltip.js +1 -1
  413. package/dist/cdn/tooltip/snice-tooltip.min.js +1 -1
  414. package/dist/cdn/tree/snice-tree.js +1 -1
  415. package/dist/cdn/tree/snice-tree.min.js +1 -1
  416. package/dist/cdn/treemap/snice-treemap.js +1 -1
  417. package/dist/cdn/treemap/snice-treemap.min.js +1 -1
  418. package/dist/cdn/user-card/snice-user-card.js +1 -1
  419. package/dist/cdn/user-card/snice-user-card.min.js +1 -1
  420. package/dist/cdn/video-player/snice-video-player.js +1 -1
  421. package/dist/cdn/video-player/snice-video-player.min.js +1 -1
  422. package/dist/cdn/virtual-scroller/snice-virtual-scroller.js +1 -1
  423. package/dist/cdn/virtual-scroller/snice-virtual-scroller.min.js +1 -1
  424. package/dist/cdn/waterfall/README.md +1 -1
  425. package/dist/cdn/waterfall/snice-waterfall.js +1 -1
  426. package/dist/cdn/waterfall/snice-waterfall.min.js +1 -1
  427. package/dist/cdn/weather/snice-weather.js +1 -1
  428. package/dist/cdn/weather/snice-weather.min.js +1 -1
  429. package/dist/cdn/work-order/snice-work-order.js +1 -1
  430. package/dist/cdn/work-order/snice-work-order.min.js +1 -1
  431. package/dist/components/action-bar/snice-action-bar.d.ts +22 -0
  432. package/dist/components/action-bar/snice-action-bar.js +182 -0
  433. package/dist/components/action-bar/snice-action-bar.js.map +1 -0
  434. package/dist/components/action-bar/snice-action-bar.types.d.ts +17 -0
  435. package/dist/components/binpack/snice-binpack.d.ts +82 -0
  436. package/dist/components/binpack/snice-binpack.js +970 -0
  437. package/dist/components/binpack/snice-binpack.js.map +1 -0
  438. package/dist/components/binpack/snice-binpack.types.d.ts +52 -0
  439. package/dist/components/button/snice-button.js +1 -1
  440. package/dist/components/button/snice-button.js.map +1 -1
  441. package/dist/components/chip/snice-chip.js +1 -1
  442. package/dist/components/chip/snice-chip.js.map +1 -1
  443. package/dist/components/date-picker/snice-date-picker.js +1 -1
  444. package/dist/components/date-picker/snice-date-picker.js.map +1 -1
  445. package/dist/components/date-range-picker/snice-date-range-picker.js +1 -1
  446. package/dist/components/date-range-picker/snice-date-range-picker.js.map +1 -1
  447. package/dist/components/date-time-picker/snice-date-time-picker.js +1 -1
  448. package/dist/components/date-time-picker/snice-date-time-picker.js.map +1 -1
  449. package/dist/components/draw/snice-draw.d.ts +2 -0
  450. package/dist/components/draw/snice-draw.js +25 -3
  451. package/dist/components/draw/snice-draw.js.map +1 -1
  452. package/dist/components/grid/snice-grid.d.ts +73 -0
  453. package/dist/components/grid/snice-grid.js +795 -0
  454. package/dist/components/grid/snice-grid.js.map +1 -0
  455. package/dist/components/grid/snice-grid.types.d.ts +41 -0
  456. package/dist/components/message-strip/snice-message-strip.js +1 -1
  457. package/dist/components/message-strip/snice-message-strip.js.map +1 -1
  458. package/dist/components/paint/snice-paint.d.ts +2 -0
  459. package/dist/components/paint/snice-paint.js +25 -2
  460. package/dist/components/paint/snice-paint.js.map +1 -1
  461. package/dist/components/tag/snice-tag.js +1 -1
  462. package/dist/components/tag/snice-tag.js.map +1 -1
  463. package/dist/components/tag-input/snice-tag-input.js +1 -1
  464. package/dist/components/tag-input/snice-tag-input.js.map +1 -1
  465. package/dist/components/theme/theme.css +15 -0
  466. package/dist/components/time-picker/snice-time-picker.js +1 -1
  467. package/dist/components/time-picker/snice-time-picker.js.map +1 -1
  468. package/dist/components/toast/snice-toast-container.js +4 -0
  469. package/dist/components/toast/snice-toast-container.js.map +1 -1
  470. package/dist/components/toast/snice-toast.js +2 -2
  471. package/dist/create-request-handler.d.ts +42 -0
  472. package/dist/index.cjs +106 -12
  473. package/dist/index.cjs.map +1 -1
  474. package/dist/index.d.ts +2 -0
  475. package/dist/index.esm.js +106 -13
  476. package/dist/index.esm.js.map +1 -1
  477. package/dist/index.iife.js +106 -12
  478. package/dist/index.iife.js.map +1 -1
  479. package/dist/react/SniceProvider.d.ts +71 -0
  480. package/dist/react/SniceProvider.js +49 -0
  481. package/dist/react/SniceProvider.js.map +1 -0
  482. package/dist/react/SniceRouter.d.ts +44 -0
  483. package/dist/react/SniceRouter.js +190 -0
  484. package/dist/react/SniceRouter.js.map +1 -0
  485. package/dist/react/index.d.ts +3 -0
  486. package/dist/react/index.js +14 -0
  487. package/dist/react/index.js.map +1 -0
  488. package/dist/react/matchRoute.d.ts +16 -0
  489. package/dist/react/matchRoute.js +32 -0
  490. package/dist/react/matchRoute.js.map +1 -0
  491. package/dist/react/useRequestHandler.d.ts +56 -0
  492. package/dist/react/useRequestHandler.js +103 -0
  493. package/dist/react/useRequestHandler.js.map +1 -0
  494. package/dist/symbols.cjs +1 -1
  495. package/dist/symbols.esm.js +1 -1
  496. package/dist/transitions.cjs +1 -1
  497. package/dist/transitions.esm.js +1 -1
  498. package/dist/types/guard.d.ts +4 -11
  499. package/docs/ai/DEVELOPMENT.md +1 -1
  500. package/docs/ai/README.md +7 -7
  501. package/docs/ai/components/accordion.md +46 -80
  502. package/docs/ai/components/action-bar.md +75 -0
  503. package/docs/ai/components/activity-feed.md +7 -7
  504. package/docs/ai/components/alert.md +26 -44
  505. package/docs/ai/components/app-tiles.md +34 -39
  506. package/docs/ai/components/approval-flow.md +1 -1
  507. package/docs/ai/components/audio-recorder.md +35 -67
  508. package/docs/ai/components/availability.md +13 -34
  509. package/docs/ai/components/avatar-group.md +26 -13
  510. package/docs/ai/components/avatar.md +52 -36
  511. package/docs/ai/components/badge.md +21 -32
  512. package/docs/ai/components/banner.md +21 -43
  513. package/docs/ai/components/binpack.md +89 -0
  514. package/docs/ai/components/book.md +25 -23
  515. package/docs/ai/components/booking.md +31 -36
  516. package/docs/ai/components/breadcrumbs.md +36 -11
  517. package/docs/ai/components/button.md +33 -44
  518. package/docs/ai/components/calendar.md +37 -70
  519. package/docs/ai/components/camera-annotate.md +31 -64
  520. package/docs/ai/components/camera.md +38 -120
  521. package/docs/ai/components/candlestick.md +32 -52
  522. package/docs/ai/components/card.md +20 -30
  523. package/docs/ai/components/carousel.md +32 -32
  524. package/docs/ai/components/cart.md +24 -29
  525. package/docs/ai/components/chart.md +29 -114
  526. package/docs/ai/components/chat.md +38 -75
  527. package/docs/ai/components/checkbox.md +22 -41
  528. package/docs/ai/components/chip.md +18 -54
  529. package/docs/ai/components/code-block.md +57 -178
  530. package/docs/ai/components/color-display.md +12 -32
  531. package/docs/ai/components/color-picker.md +17 -39
  532. package/docs/ai/components/command-palette.md +49 -71
  533. package/docs/ai/components/comments.md +55 -36
  534. package/docs/ai/components/countdown.md +28 -30
  535. package/docs/ai/components/cropper.md +33 -33
  536. package/docs/ai/components/data-card.md +20 -14
  537. package/docs/ai/components/date-picker.md +40 -47
  538. package/docs/ai/components/date-range-picker.md +31 -15
  539. package/docs/ai/components/date-time-picker.md +23 -46
  540. package/docs/ai/components/diff.md +30 -31
  541. package/docs/ai/components/divider.md +17 -47
  542. package/docs/ai/components/doc.md +43 -68
  543. package/docs/ai/components/draw.md +35 -87
  544. package/docs/ai/components/drawer.md +48 -77
  545. package/docs/ai/components/empty-state.md +10 -44
  546. package/docs/ai/components/estimate.md +33 -58
  547. package/docs/ai/components/file-gallery.md +48 -100
  548. package/docs/ai/components/file-upload.md +17 -53
  549. package/docs/ai/components/flip-card.md +31 -23
  550. package/docs/ai/components/flow.md +37 -65
  551. package/docs/ai/components/form-builder.md +35 -75
  552. package/docs/ai/components/form-layout.md +10 -20
  553. package/docs/ai/components/funnel.md +33 -48
  554. package/docs/ai/components/gantt.md +27 -23
  555. package/docs/ai/components/gauge.md +16 -17
  556. package/docs/ai/components/grid.md +116 -0
  557. package/docs/ai/components/heatmap.md +21 -21
  558. package/docs/ai/components/image.md +7 -13
  559. package/docs/ai/components/input.md +38 -70
  560. package/docs/ai/components/invoice.md +35 -36
  561. package/docs/ai/components/kanban.md +32 -61
  562. package/docs/ai/components/key-value.md +32 -16
  563. package/docs/ai/components/kpi.md +38 -73
  564. package/docs/ai/components/layout.md +29 -23
  565. package/docs/ai/components/leaderboard.md +28 -37
  566. package/docs/ai/components/link-preview.md +12 -18
  567. package/docs/ai/components/link.md +10 -7
  568. package/docs/ai/components/list.md +21 -5
  569. package/docs/ai/components/location.md +21 -25
  570. package/docs/ai/components/login.md +14 -9
  571. package/docs/ai/components/map.md +27 -33
  572. package/docs/ai/components/markdown.md +20 -24
  573. package/docs/ai/components/masonry.md +10 -14
  574. package/docs/ai/components/mentions.md +26 -12
  575. package/docs/ai/components/menu.md +54 -52
  576. package/docs/ai/components/message-strip.md +20 -20
  577. package/docs/ai/components/metric-table.md +14 -21
  578. package/docs/ai/components/modal.md +27 -18
  579. package/docs/ai/components/music-player.md +49 -41
  580. package/docs/ai/components/nav.md +34 -31
  581. package/docs/ai/components/network-graph.md +27 -42
  582. package/docs/ai/components/notification-center.md +31 -33
  583. package/docs/ai/components/order-tracker.md +36 -27
  584. package/docs/ai/components/org-chart.md +36 -31
  585. package/docs/ai/components/pagination.md +34 -26
  586. package/docs/ai/components/paint.md +53 -91
  587. package/docs/ai/components/pdf-viewer.md +35 -36
  588. package/docs/ai/components/permission-matrix.md +26 -31
  589. package/docs/ai/components/podcast-player.md +64 -70
  590. package/docs/ai/components/pricing-table.md +37 -48
  591. package/docs/ai/components/product-card.md +58 -41
  592. package/docs/ai/components/progress-ring.md +20 -24
  593. package/docs/ai/components/progress.md +28 -45
  594. package/docs/ai/components/qr-code.md +25 -27
  595. package/docs/ai/components/qr-reader.md +20 -23
  596. package/docs/ai/components/radio.md +17 -15
  597. package/docs/ai/components/range-slider.md +22 -11
  598. package/docs/ai/components/rating.md +29 -33
  599. package/docs/ai/components/receipt.md +50 -127
  600. package/docs/ai/components/recipe.md +44 -42
  601. package/docs/ai/components/sankey.md +21 -30
  602. package/docs/ai/components/scheduler.md +29 -41
  603. package/docs/ai/components/segmented-control.md +11 -15
  604. package/docs/ai/components/select.md +58 -102
  605. package/docs/ai/components/skeleton.md +16 -30
  606. package/docs/ai/components/slider.md +26 -20
  607. package/docs/ai/components/sortable.md +25 -27
  608. package/docs/ai/components/sparkline.md +21 -17
  609. package/docs/ai/components/spinner.md +9 -5
  610. package/docs/ai/components/split-button.md +10 -13
  611. package/docs/ai/components/split-pane.md +19 -14
  612. package/docs/ai/components/spotlight.md +31 -26
  613. package/docs/ai/components/spreadsheet.md +51 -97
  614. package/docs/ai/components/stat-group.md +9 -19
  615. package/docs/ai/components/step-input.md +17 -15
  616. package/docs/ai/components/stepper.md +14 -15
  617. package/docs/ai/components/switch.md +15 -9
  618. package/docs/ai/components/table.md +24 -84
  619. package/docs/ai/components/tabs.md +18 -10
  620. package/docs/ai/components/tag-input.md +18 -29
  621. package/docs/ai/components/tag.md +10 -22
  622. package/docs/ai/components/terminal.md +9 -9
  623. package/docs/ai/components/testimonial.md +9 -19
  624. package/docs/ai/components/textarea.md +15 -16
  625. package/docs/ai/components/theme.md +3 -3
  626. package/docs/ai/components/time-picker.md +30 -49
  627. package/docs/ai/components/time-range-picker.md +16 -15
  628. package/docs/ai/components/timeline.md +5 -4
  629. package/docs/ai/components/timer.md +8 -8
  630. package/docs/ai/components/toast.md +24 -18
  631. package/docs/ai/components/tooltip.md +11 -22
  632. package/docs/ai/components/tree.md +9 -9
  633. package/docs/ai/components/treemap.md +14 -13
  634. package/docs/ai/components/user-card.md +21 -27
  635. package/docs/ai/components/video-player.md +35 -52
  636. package/docs/ai/components/virtual-scroller.md +1 -1
  637. package/docs/ai/components/waterfall.md +17 -16
  638. package/docs/ai/components/weather.md +19 -34
  639. package/docs/ai/components/work-order.md +58 -134
  640. package/docs/ai/patterns.md +87 -0
  641. package/docs/ai/react-integration.md +97 -0
  642. package/docs/components/accordion.md +72 -151
  643. package/docs/components/action-bar.md +185 -0
  644. package/docs/components/activity-feed.md +9 -14
  645. package/docs/components/alert.md +17 -109
  646. package/docs/components/app-tiles.md +58 -43
  647. package/docs/components/approval-flow.md +8 -14
  648. package/docs/components/audio-recorder.md +45 -51
  649. package/docs/components/availability.md +30 -45
  650. package/docs/components/avatar-group.md +34 -14
  651. package/docs/components/avatar.md +20 -55
  652. package/docs/components/badge.md +53 -470
  653. package/docs/components/banner.md +44 -30
  654. package/docs/components/binpack.md +208 -0
  655. package/docs/components/book.md +78 -57
  656. package/docs/components/booking.md +35 -87
  657. package/docs/components/breadcrumbs.md +74 -448
  658. package/docs/components/button.md +72 -603
  659. package/docs/components/calendar.md +77 -261
  660. package/docs/components/camera-annotate.md +44 -96
  661. package/docs/components/camera.md +94 -333
  662. package/docs/components/candlestick.md +79 -116
  663. package/docs/components/card.md +51 -689
  664. package/docs/components/carousel.md +29 -76
  665. package/docs/components/cart.md +44 -136
  666. package/docs/components/chart.md +95 -438
  667. package/docs/components/chat.md +175 -439
  668. package/docs/components/checkbox.md +52 -609
  669. package/docs/components/chip.md +45 -574
  670. package/docs/components/code-block.md +157 -421
  671. package/docs/components/color-display.md +45 -54
  672. package/docs/components/color-picker.md +103 -36
  673. package/docs/components/command-palette.md +98 -92
  674. package/docs/components/comments.md +16 -10
  675. package/docs/components/countdown.md +15 -20
  676. package/docs/components/cropper.md +14 -16
  677. package/docs/components/data-card.md +16 -15
  678. package/docs/components/date-picker.md +45 -25
  679. package/docs/components/date-range-picker.md +140 -87
  680. package/docs/components/date-time-picker.md +25 -28
  681. package/docs/components/diff.md +22 -17
  682. package/docs/components/divider.md +18 -20
  683. package/docs/components/doc.md +105 -197
  684. package/docs/components/draw.md +117 -223
  685. package/docs/components/drawer.md +113 -478
  686. package/docs/components/empty-state.md +13 -29
  687. package/docs/components/estimate.md +58 -118
  688. package/docs/components/file-gallery.md +123 -495
  689. package/docs/components/file-upload.md +36 -123
  690. package/docs/components/flip-card.md +30 -34
  691. package/docs/components/flow.md +74 -89
  692. package/docs/components/form-builder.md +59 -86
  693. package/docs/components/form-layout.md +21 -31
  694. package/docs/components/funnel.md +21 -22
  695. package/docs/components/gantt.md +5 -5
  696. package/docs/components/gauge.md +5 -23
  697. package/docs/components/grid.md +249 -0
  698. package/docs/components/heatmap.md +13 -55
  699. package/docs/components/image.md +28 -32
  700. package/docs/components/input.md +25 -14
  701. package/docs/components/invoice.md +34 -33
  702. package/docs/components/kanban.md +99 -394
  703. package/docs/components/key-value.md +22 -12
  704. package/docs/components/kpi.md +41 -112
  705. package/docs/components/layout.md +7 -13
  706. package/docs/components/leaderboard.md +52 -76
  707. package/docs/components/link-preview.md +20 -16
  708. package/docs/components/link.md +22 -19
  709. package/docs/components/list.md +44 -26
  710. package/docs/components/location.md +9 -13
  711. package/docs/components/login.md +42 -36
  712. package/docs/components/map.md +24 -46
  713. package/docs/components/markdown.md +14 -25
  714. package/docs/components/masonry.md +15 -13
  715. package/docs/components/mentions.md +36 -25
  716. package/docs/components/menu.md +39 -46
  717. package/docs/components/message-strip.md +15 -51
  718. package/docs/components/metric-table.md +50 -72
  719. package/docs/components/modal.md +32 -43
  720. package/docs/components/music-player.md +41 -49
  721. package/docs/components/nav.md +23 -13
  722. package/docs/components/network-graph.md +14 -13
  723. package/docs/components/notification-center.md +68 -172
  724. package/docs/components/order-tracker.md +72 -117
  725. package/docs/components/org-chart.md +58 -207
  726. package/docs/components/pagination.md +67 -89
  727. package/docs/components/paint.md +86 -172
  728. package/docs/components/pdf-viewer.md +46 -151
  729. package/docs/components/permission-matrix.md +61 -112
  730. package/docs/components/podcast-player.md +41 -119
  731. package/docs/components/pricing-table.md +104 -147
  732. package/docs/components/product-card.md +94 -197
  733. package/docs/components/progress-ring.md +29 -32
  734. package/docs/components/progress.md +30 -61
  735. package/docs/components/qr-code.md +53 -61
  736. package/docs/components/qr-reader.md +53 -42
  737. package/docs/components/radio.md +42 -40
  738. package/docs/components/range-slider.md +41 -30
  739. package/docs/components/rating.md +50 -84
  740. package/docs/components/receipt.md +91 -129
  741. package/docs/components/recipe.md +107 -216
  742. package/docs/components/sankey.md +47 -83
  743. package/docs/components/scheduler.md +81 -184
  744. package/docs/components/segmented-control.md +48 -40
  745. package/docs/components/select.md +107 -129
  746. package/docs/components/skeleton.md +33 -47
  747. package/docs/components/slider.md +49 -53
  748. package/docs/components/sortable.md +43 -186
  749. package/docs/components/sparkline.md +26 -25
  750. package/docs/components/spinner.md +32 -37
  751. package/docs/components/split-button.md +43 -23
  752. package/docs/components/split-pane.md +41 -58
  753. package/docs/components/spotlight.md +53 -145
  754. package/docs/components/spreadsheet.md +84 -307
  755. package/docs/components/stat-group.md +27 -61
  756. package/docs/components/step-input.md +44 -41
  757. package/docs/components/stepper.md +55 -89
  758. package/docs/components/switch.md +39 -39
  759. package/docs/components/table.md +27 -32
  760. package/docs/components/tabs.md +36 -27
  761. package/docs/components/tag-input.md +50 -176
  762. package/docs/components/tag.md +12 -50
  763. package/docs/components/terminal.md +32 -37
  764. package/docs/components/testimonial.md +24 -81
  765. package/docs/components/textarea.md +9 -14
  766. package/docs/components/theme.md +10 -23
  767. package/docs/components/time-picker.md +48 -72
  768. package/docs/components/time-range-picker.md +22 -41
  769. package/docs/components/timeline.md +7 -14
  770. package/docs/components/timer.md +16 -32
  771. package/docs/components/toast.md +19 -45
  772. package/docs/components/tooltip.md +13 -115
  773. package/docs/components/tree.md +2 -19
  774. package/docs/components/treemap.md +19 -43
  775. package/docs/components/user-card.md +13 -22
  776. package/docs/components/video-player.md +53 -227
  777. package/docs/components/virtual-scroller.md +11 -44
  778. package/docs/components/waterfall.md +58 -137
  779. package/docs/components/weather.md +94 -153
  780. package/docs/components/work-order.md +56 -143
  781. package/docs/plans/2026-03-09-action-bar-design.md +104 -0
  782. package/docs/plans/2026-03-09-action-bar-plan.md +676 -0
  783. package/docs/plans/2026-03-10-grid-component-design.md +138 -0
  784. package/docs/plans/2026-03-10-grid-component-plan.md +716 -0
  785. package/docs/plans/2026-03-10-react-integration-design.md +166 -0
  786. package/docs/plans/2026-03-10-react-integration-plan.md +1178 -0
  787. package/docs/react-integration.md +508 -0
  788. package/docs/request-response.md +63 -0
  789. package/package.json +1 -1
  790. package/bin/templates/base/README.md +0 -33
  791. package/bin/templates/base/global.d.ts +0 -14
  792. package/bin/templates/base/index.html +0 -13
  793. package/bin/templates/base/package.json +0 -21
  794. package/bin/templates/base/src/components/counter-button.ts +0 -88
  795. package/bin/templates/base/src/components/counter-button.types.ts +0 -7
  796. package/bin/templates/base/src/components/feature-card.ts +0 -59
  797. package/bin/templates/base/src/components/feature-card.types.ts +0 -5
  798. package/bin/templates/base/src/controllers/counter-controller.ts +0 -24
  799. package/bin/templates/base/src/main.ts +0 -24
  800. package/bin/templates/base/src/pages/about-page.ts +0 -68
  801. package/bin/templates/base/src/pages/home-page.ts +0 -105
  802. package/bin/templates/base/src/pages/not-found-page.ts +0 -55
  803. package/bin/templates/base/src/router.ts +0 -9
  804. package/bin/templates/base/src/styles/global.css +0 -27
  805. package/bin/templates/base/src/types/api-response.ts +0 -5
  806. package/bin/templates/base/src/types/status.ts +0 -1
  807. package/bin/templates/base/src/types/theme.ts +0 -1
  808. package/bin/templates/base/src/types/user.ts +0 -5
  809. package/bin/templates/base/vite.config.ts +0 -38
  810. package/bin/templates/pwa/public/vite.svg +0 -1
  811. package/bin/templates/pwa/src/router.ts +0 -20
  812. package/bin/templates/pwa/src/styles/global.css +0 -64
  813. /package/bin/templates/{pwa → default}/README.md +0 -0
  814. /package/bin/templates/{pwa → default}/global.d.ts +0 -0
  815. /package/bin/templates/{pwa → default}/package.json +0 -0
  816. /package/bin/templates/{pwa → default}/public/icons/.gitkeep +0 -0
  817. /package/bin/templates/{base → default}/public/vite.svg +0 -0
  818. /package/bin/templates/{pwa → default}/src/fetcher.ts +0 -0
  819. /package/bin/templates/{pwa → default}/src/guards/auth.ts +0 -0
  820. /package/bin/templates/{pwa → default}/src/middleware/auth.ts +0 -0
  821. /package/bin/templates/{pwa → default}/src/middleware/retry.ts +0 -0
  822. /package/bin/templates/{pwa → default}/src/services/auth.ts +0 -0
  823. /package/bin/templates/{pwa → default}/src/services/jwt.ts +0 -0
  824. /package/bin/templates/{pwa → default}/src/services/storage.ts +0 -0
  825. /package/bin/templates/{pwa → default}/src/types/auth.ts +0 -0
  826. /package/bin/templates/{pwa → default}/src/types/notifications.ts +0 -0
  827. /package/bin/templates/{pwa → default}/tests/helpers/test-utils.ts +0 -0
  828. /package/bin/templates/{pwa → default}/tests/middleware/auth.test.ts +0 -0
  829. /package/bin/templates/{pwa → default}/tests/middleware/error.test.ts +0 -0
  830. /package/bin/templates/{pwa → default}/tests/middleware/retry.test.ts +0 -0
  831. /package/bin/templates/{pwa → default}/tests/services/auth.test.ts +0 -0
  832. /package/bin/templates/{pwa → default}/tests/services/jwt.test.ts +0 -0
  833. /package/bin/templates/{pwa → default}/tests/services/storage.test.ts +0 -0
  834. /package/bin/templates/{pwa → default}/vite.config.ts +0 -0
  835. /package/bin/templates/{pwa → default}/vitest.config.ts +0 -0
@@ -0,0 +1,1178 @@
1
+ # Snice React Integration (Full Parity) — Implementation Plan
2
+
3
+ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
+
5
+ **Goal:** Let React developers build full Snice-powered apps using only hooks and JSX — routing, guards, layouts, context — without decorators or custom element classes.
6
+
7
+ **Architecture:** React-native implementations of Snice's router, context, guards, and layouts in `src/react/`. Purpose-built for React's rendering model while mirroring Snice's API contracts. Source builds to `dist/react/`, copies to `adapters/react/`. Consumers import from `snice/react`.
8
+
9
+ **Tech Stack:** React 18+, TypeScript, Rollup, Vitest, pica-route (same route matching as vanilla Snice)
10
+
11
+ **Design doc:** `docs/plans/2026-03-10-react-integration-design.md`
12
+
13
+ ---
14
+
15
+ ## Prerequisite: Async Guard Support in Vanilla Snice
16
+
17
+ Before building the React router, the vanilla `Guard` type and `checkGuards` must support `Promise<boolean>`. This ensures shared guards work in both systems.
18
+
19
+ ### Task 1: Update Guard Type to Support Async
20
+
21
+ **Files:**
22
+ - Modify: `src/types/guard.ts`
23
+
24
+ **Step 1: Update the Guard type**
25
+
26
+ Change `src/types/guard.ts` to:
27
+
28
+ ```typescript
29
+ import { RouteParams } from './route-params';
30
+
31
+ /**
32
+ * Guard function type for route protection and visibility control.
33
+ * Guards determine if navigation to a route should proceed.
34
+ * Can return a boolean synchronously or a Promise<boolean> for async checks.
35
+ *
36
+ * @template T - The context type passed to the guard function
37
+ * @param context - The application context object
38
+ * @param params - Route parameters extracted from the URL
39
+ * @returns boolean or Promise<boolean> - true to allow, false to deny
40
+ */
41
+ export type Guard<T = any> = (context: T, params: RouteParams) => boolean | Promise<boolean>;
42
+ ```
43
+
44
+ **Step 2: Commit**
45
+
46
+ ```bash
47
+ git add src/types/guard.ts
48
+ git commit -m "feat: support async guards in Guard type"
49
+ ```
50
+
51
+ ### Task 2: Make Vanilla Router's checkGuards Async
52
+
53
+ **Files:**
54
+ - Modify: `src/router.ts`
55
+
56
+ **Step 1: Make checkGuards async**
57
+
58
+ In `src/router.ts`, change `checkGuards` (currently at ~line 242):
59
+
60
+ ```typescript
61
+ async function checkGuards(guards: Guard<any> | Guard<any>[] | undefined, params: RouteParams, target: Element): Promise<boolean> {
62
+ const hasGuards = !!guards;
63
+ if (!hasGuards) {
64
+ return true;
65
+ }
66
+
67
+ const guardsArray = Array.isArray(guards) ? guards : [guards];
68
+ for (const guard of guardsArray) {
69
+ const allowed = await guard(context, params);
70
+ if (!allowed) {
71
+ renderForbiddenPage(target);
72
+ return false;
73
+ }
74
+ }
75
+ return true;
76
+ }
77
+ ```
78
+
79
+ **Step 2: Add `await` to all checkGuards call sites**
80
+
81
+ The function is already called in async contexts (`navigate` is async), but the calls need `await`:
82
+
83
+ - Line ~294 in `resolveRoute`: Change to make resolveRoute async. Currently `const guardsAllowed = checkGuards(...)` — needs `await`.
84
+ - Line ~435 in `navigate` (home path): `if (!checkGuards(...))` → `if (!(await checkGuards(...)))`
85
+
86
+ Change `resolveRoute` signature to async:
87
+
88
+ ```typescript
89
+ async function resolveRoute(path: string, target: Element): Promise<{ result: RouteResult; element?: HTMLElement; transition?: Transition; layout?: string | false; routeParams?: RouteParams }> {
90
+ ```
91
+
92
+ And in its body:
93
+ ```typescript
94
+ const guardsAllowed = await checkGuards(route.guards, params as RouteParams, target);
95
+ ```
96
+
97
+ In `navigate`, the home path guard check:
98
+ ```typescript
99
+ if (!(await checkGuards(homeRoute?.guards, {}, target))) return;
100
+ ```
101
+
102
+ And the `resolveRoute` call already has `const routeResult = resolveRoute(...)` — just needs `await`:
103
+ ```typescript
104
+ const routeResult = await resolveRoute(path, target);
105
+ ```
106
+
107
+ **Step 3: Run existing router tests**
108
+
109
+ Run: `npm run build:test && npx vitest run tests/router.test.ts`
110
+ Expected: All existing tests still pass (sync guards still work since `await true === true`)
111
+
112
+ **Step 4: Commit**
113
+
114
+ ```bash
115
+ git add src/router.ts
116
+ git commit -m "feat: make router checkGuards async for async guard support"
117
+ ```
118
+
119
+ ### Task 3: Add Async Guard Tests for Vanilla Router
120
+
121
+ **Files:**
122
+ - Modify: `tests/router.test.ts`
123
+
124
+ **Step 1: Add async guard tests**
125
+
126
+ Add these tests to the existing router test file, in the guards describe block:
127
+
128
+ ```typescript
129
+ it('should support async guards that resolve to true', async () => {
130
+ const elName = uniqueName('async-guard-pass');
131
+ const asyncGuard: Guard<any> = async (ctx, params) => {
132
+ await new Promise(r => setTimeout(r, 10));
133
+ return true;
134
+ };
135
+
136
+ @page({ tag: elName, routes: ['/async-pass'], guards: [asyncGuard] })
137
+ class AsyncPassPage extends HTMLElement {
138
+ @render()
139
+ renderContent() {
140
+ return html`<div>async pass</div>`;
141
+ }
142
+ }
143
+
144
+ await router.navigate('/async-pass');
145
+ const el = target.querySelector(elName);
146
+ expect(el).toBeTruthy();
147
+ });
148
+
149
+ it('should support async guards that resolve to false', async () => {
150
+ const elName = uniqueName('async-guard-fail');
151
+ const asyncGuard: Guard<any> = async (ctx, params) => {
152
+ await new Promise(r => setTimeout(r, 10));
153
+ return false;
154
+ };
155
+
156
+ @page({ tag: elName, routes: ['/async-fail'], guards: [asyncGuard] })
157
+ class AsyncFailPage extends HTMLElement {
158
+ @render()
159
+ renderContent() {
160
+ return html`<div>async fail</div>`;
161
+ }
162
+ }
163
+
164
+ await router.navigate('/async-fail');
165
+ const el = target.querySelector(elName);
166
+ expect(el).toBeFalsy();
167
+ });
168
+
169
+ it('should support mixed sync and async guards', async () => {
170
+ const elName = uniqueName('mixed-guard');
171
+ const syncGuard: Guard<any> = (ctx, params) => true;
172
+ const asyncGuard: Guard<any> = async (ctx, params) => {
173
+ await new Promise(r => setTimeout(r, 10));
174
+ return true;
175
+ };
176
+
177
+ @page({ tag: elName, routes: ['/mixed-guard'], guards: [syncGuard, asyncGuard] })
178
+ class MixedGuardPage extends HTMLElement {
179
+ @render()
180
+ renderContent() {
181
+ return html`<div>mixed guard</div>`;
182
+ }
183
+ }
184
+
185
+ await router.navigate('/mixed-guard');
186
+ const el = target.querySelector(elName);
187
+ expect(el).toBeTruthy();
188
+ });
189
+ ```
190
+
191
+ **Step 2: Run tests**
192
+
193
+ Run: `npm run build:test && npx vitest run tests/router.test.ts`
194
+ Expected: All tests pass including new async guard tests
195
+
196
+ **Step 3: Commit**
197
+
198
+ ```bash
199
+ git add tests/router.test.ts
200
+ git commit -m "test: add async guard tests for vanilla router"
201
+ ```
202
+
203
+ ---
204
+
205
+ ## React Integration
206
+
207
+ ### Task 4: SniceProvider and useSniceContext
208
+
209
+ The context provider is the foundation — other components depend on it. It provides the merged context shape that mirrors Snice's `@context` decorator.
210
+
211
+ **Files:**
212
+ - Create: `src/react/SniceProvider.tsx`
213
+ - Create: `tests/react/snice-provider.test.ts`
214
+
215
+ **Step 1: Write the test file**
216
+
217
+ Create `tests/react/snice-provider.test.ts`:
218
+
219
+ ```typescript
220
+ import { describe, it, expect } from 'vitest';
221
+ import { SniceProvider, useSniceContext, useNavigate, useParams, useRoute } from '../../src/react/SniceProvider';
222
+
223
+ describe('SniceProvider exports', () => {
224
+ it('should export SniceProvider component', () => {
225
+ expect(typeof SniceProvider).toBe('function');
226
+ });
227
+
228
+ it('should export useSniceContext hook', () => {
229
+ expect(typeof useSniceContext).toBe('function');
230
+ });
231
+
232
+ it('should export useNavigate hook', () => {
233
+ expect(typeof useNavigate).toBe('function');
234
+ });
235
+
236
+ it('should export useParams hook', () => {
237
+ expect(typeof useParams).toBe('function');
238
+ });
239
+
240
+ it('should export useRoute hook', () => {
241
+ expect(typeof useRoute).toBe('function');
242
+ });
243
+ });
244
+ ```
245
+
246
+ **Step 2: Run test to verify it fails**
247
+
248
+ Run: `npx vitest run tests/react/snice-provider.test.ts`
249
+ Expected: FAIL — module not found
250
+
251
+ **Step 3: Write the SniceProvider**
252
+
253
+ Create `src/react/SniceProvider.tsx`:
254
+
255
+ ```tsx
256
+ import { createContext, useContext, useMemo, type ReactNode } from 'react';
257
+ import type { Placard } from '../types/placard';
258
+
259
+ /**
260
+ * Mirrors Snice's @context shape exactly.
261
+ */
262
+ export interface SniceReactContext {
263
+ /** User-defined app state */
264
+ application: Record<string, any>;
265
+ /** Navigation state */
266
+ navigation: {
267
+ route: string;
268
+ params: Record<string, string>;
269
+ placards: Placard[];
270
+ };
271
+ /** Programmatic navigation */
272
+ navigate: (path: string) => void;
273
+ /** Optional context-aware fetcher */
274
+ fetch?: typeof globalThis.fetch;
275
+ }
276
+
277
+ const SniceCtx = createContext<SniceReactContext | null>(null);
278
+
279
+ export interface SniceProviderProps {
280
+ /** Application context object (user state, theme, config, etc.) */
281
+ context?: Record<string, any>;
282
+ /** Navigation function — provided by SniceRouter, or your own */
283
+ navigate?: (path: string) => void;
284
+ /** Current route pattern */
285
+ route?: string;
286
+ /** Current route params */
287
+ params?: Record<string, string>;
288
+ /** Registered placards */
289
+ placards?: Placard[];
290
+ /** Optional fetch function */
291
+ fetch?: typeof globalThis.fetch;
292
+ children: ReactNode;
293
+ }
294
+
295
+ /**
296
+ * Context provider for Snice React integration.
297
+ * Usable standalone without SniceRouter for simpler apps.
298
+ */
299
+ export function SniceProvider({
300
+ context = {},
301
+ navigate = () => {},
302
+ route = '',
303
+ params = {},
304
+ placards = [],
305
+ fetch: fetchFn,
306
+ children,
307
+ }: SniceProviderProps) {
308
+ const value = useMemo<SniceReactContext>(
309
+ () => ({
310
+ application: context,
311
+ navigation: { route, params, placards },
312
+ navigate,
313
+ ...(fetchFn ? { fetch: fetchFn } : {}),
314
+ }),
315
+ [context, navigate, route, params, placards, fetchFn],
316
+ );
317
+
318
+ return <SniceCtx.Provider value={value}>{children}</SniceCtx.Provider>;
319
+ }
320
+
321
+ /**
322
+ * Returns the full merged Snice context.
323
+ * Mirrors the shape returned by Snice's @context decorator.
324
+ */
325
+ export function useSniceContext(): SniceReactContext {
326
+ const ctx = useContext(SniceCtx);
327
+ if (!ctx) {
328
+ throw new Error('useSniceContext must be used within a <SniceProvider> or <SniceRouter>');
329
+ }
330
+ return ctx;
331
+ }
332
+
333
+ /** Convenience: returns just the navigate function */
334
+ export function useNavigate(): (path: string) => void {
335
+ return useSniceContext().navigate;
336
+ }
337
+
338
+ /** Convenience: returns current route params */
339
+ export function useParams(): Record<string, string> {
340
+ return useSniceContext().navigation.params;
341
+ }
342
+
343
+ /** Convenience: returns current matched route pattern */
344
+ export function useRoute(): string {
345
+ return useSniceContext().navigation.route;
346
+ }
347
+
348
+ // Export the raw context for SniceRouter to use as its provider
349
+ export { SniceCtx as SniceContextInternal };
350
+ ```
351
+
352
+ **Step 4: Run test to verify it passes**
353
+
354
+ Run: `npx vitest run tests/react/snice-provider.test.ts`
355
+ Expected: PASS
356
+
357
+ **Step 5: Commit**
358
+
359
+ ```bash
360
+ git add src/react/SniceProvider.tsx tests/react/snice-provider.test.ts
361
+ git commit -m "feat: add SniceProvider and context hooks"
362
+ ```
363
+
364
+ ### Task 5: Route Matching Utility
365
+
366
+ Extract route matching into a shared utility so the React router uses the exact same `pica-route` matching as vanilla Snice.
367
+
368
+ **Files:**
369
+ - Create: `src/react/matchRoute.ts`
370
+ - Create: `tests/react/match-route.test.ts`
371
+
372
+ **Step 1: Write the test**
373
+
374
+ Create `tests/react/match-route.test.ts`:
375
+
376
+ ```typescript
377
+ import { describe, it, expect } from 'vitest';
378
+ import { matchRoutes, type RouteConfig } from '../../src/react/matchRoute';
379
+
380
+ describe('matchRoutes', () => {
381
+ const routes: RouteConfig[] = [
382
+ { path: '/users/:id', index: 0 },
383
+ { path: '/users', index: 1 },
384
+ { path: '/', index: 2 },
385
+ ];
386
+
387
+ it('should match exact paths', () => {
388
+ const result = matchRoutes(routes, '/users');
389
+ expect(result).not.toBeNull();
390
+ expect(result!.index).toBe(1);
391
+ expect(result!.params).toEqual({});
392
+ });
393
+
394
+ it('should match parameterized paths', () => {
395
+ const result = matchRoutes(routes, '/users/42');
396
+ expect(result).not.toBeNull();
397
+ expect(result!.index).toBe(0);
398
+ expect(result!.params).toEqual({ id: '42' });
399
+ });
400
+
401
+ it('should match root path', () => {
402
+ const result = matchRoutes(routes, '/');
403
+ expect(result).not.toBeNull();
404
+ expect(result!.index).toBe(2);
405
+ });
406
+
407
+ it('should return null for unmatched paths', () => {
408
+ const result = matchRoutes(routes, '/nonexistent');
409
+ expect(result).toBeNull();
410
+ });
411
+
412
+ it('should match longest route first (most specific)', () => {
413
+ const result = matchRoutes(routes, '/users/42');
414
+ expect(result!.index).toBe(0); // /users/:id wins over /users
415
+ });
416
+ });
417
+ ```
418
+
419
+ **Step 2: Run test to verify it fails**
420
+
421
+ Run: `npx vitest run tests/react/match-route.test.ts`
422
+ Expected: FAIL — module not found
423
+
424
+ **Step 3: Write matchRoute.ts**
425
+
426
+ Create `src/react/matchRoute.ts`:
427
+
428
+ ```typescript
429
+ import { Route, type RouteParams } from 'pica-route';
430
+
431
+ export interface RouteConfig {
432
+ path: string;
433
+ index: number;
434
+ }
435
+
436
+ export interface MatchResult {
437
+ index: number;
438
+ params: RouteParams;
439
+ path: string;
440
+ }
441
+
442
+ /**
443
+ * Match a URL path against an array of route configs.
444
+ * Uses pica-route — same matching as vanilla Snice's Router.
445
+ * Routes are sorted by specificity (longest spec first).
446
+ */
447
+ export function matchRoutes(routes: RouteConfig[], pathname: string): MatchResult | null {
448
+ // Sort by specificity (longest path first), same as vanilla Router
449
+ const sorted = [...routes].sort((a, b) => b.path.length - a.path.length);
450
+
451
+ for (const route of sorted) {
452
+ const matcher = new Route(route.path);
453
+ const params = matcher.match(pathname);
454
+ if (params !== false) {
455
+ return {
456
+ index: route.index,
457
+ params: params as RouteParams,
458
+ path: route.path,
459
+ };
460
+ }
461
+ }
462
+
463
+ return null;
464
+ }
465
+ ```
466
+
467
+ **Step 4: Run test to verify it passes**
468
+
469
+ Run: `npx vitest run tests/react/match-route.test.ts`
470
+ Expected: PASS
471
+
472
+ **Step 5: Commit**
473
+
474
+ ```bash
475
+ git add src/react/matchRoute.ts tests/react/match-route.test.ts
476
+ git commit -m "feat: add route matching utility for React router"
477
+ ```
478
+
479
+ ### Task 6: SniceRouter and Route Components
480
+
481
+ The core router: URL state management, route matching, guard execution, layout selection, context propagation.
482
+
483
+ **Files:**
484
+ - Create: `src/react/SniceRouter.tsx`
485
+ - Create: `tests/react/snice-router.test.ts`
486
+
487
+ **Step 1: Write the test**
488
+
489
+ Create `tests/react/snice-router.test.ts`:
490
+
491
+ ```typescript
492
+ import { describe, it, expect } from 'vitest';
493
+ import { SniceRouter, Route } from '../../src/react/SniceRouter';
494
+
495
+ describe('SniceRouter exports', () => {
496
+ it('should export SniceRouter component', () => {
497
+ expect(typeof SniceRouter).toBe('function');
498
+ });
499
+
500
+ it('should export Route component', () => {
501
+ expect(typeof Route).toBe('function');
502
+ });
503
+ });
504
+ ```
505
+
506
+ **Step 2: Run test to verify it fails**
507
+
508
+ Run: `npx vitest run tests/react/snice-router.test.ts`
509
+ Expected: FAIL — module not found
510
+
511
+ **Step 3: Write SniceRouter.tsx**
512
+
513
+ Create `src/react/SniceRouter.tsx`:
514
+
515
+ ```tsx
516
+ import {
517
+ useState,
518
+ useEffect,
519
+ useCallback,
520
+ useMemo,
521
+ useRef,
522
+ type ReactNode,
523
+ type ReactElement,
524
+ type ComponentType,
525
+ Children,
526
+ isValidElement,
527
+ createElement,
528
+ } from 'react';
529
+ import { SniceProvider, type SniceReactContext } from './SniceProvider';
530
+ import { matchRoutes, type RouteConfig } from './matchRoute';
531
+ import type { Placard } from '../types/placard';
532
+
533
+ // ─── Route component (declarative config) ───
534
+
535
+ export interface RouteProps {
536
+ path: string;
537
+ /** React component OR Snice element tag name (string) */
538
+ page: ComponentType<any> | string;
539
+ /** Single guard function */
540
+ guard?: (context: Record<string, any>, params: Record<string, string>) => boolean | Promise<boolean>;
541
+ /** Multiple guards (AND logic) */
542
+ guards?: Array<(context: Record<string, any>, params: Record<string, string>) => boolean | Promise<boolean>>;
543
+ /** Redirect path if guard rejects */
544
+ guardRedirect?: string;
545
+ /** Layout override. Component, string (Snice tag), or false (no layout) */
546
+ layout?: ComponentType<{ children: ReactNode }> | string | false;
547
+ /** Page metadata for layouts */
548
+ placard?: Placard;
549
+ }
550
+
551
+ /**
552
+ * Route definition component. Child of <SniceRouter>.
553
+ * Does not render anything — SniceRouter reads its props.
554
+ */
555
+ export function Route(_props: RouteProps): ReactElement | null {
556
+ return null;
557
+ }
558
+
559
+ // ─── SniceRouter ───
560
+
561
+ export interface SniceRouterProps {
562
+ /** URL strategy */
563
+ mode: 'hash' | 'history';
564
+ /** Application context passed to guards, pages, layouts */
565
+ context?: Record<string, any>;
566
+ /** Default layout component or Snice tag name */
567
+ layout?: ComponentType<{ children: ReactNode }> | string;
568
+ /** Loading component shown during async guards. Component, string (Snice tag), or JSX. */
569
+ loading?: ComponentType | string | ReactNode;
570
+ /** Fallback when no route matches. Component, string (Snice tag), or JSX. */
571
+ fallback?: ComponentType | string | ReactNode;
572
+ children: ReactNode;
573
+ }
574
+
575
+ interface ParsedRoute {
576
+ path: string;
577
+ page: ComponentType<any> | string;
578
+ guards: Array<(ctx: Record<string, any>, params: Record<string, string>) => boolean | Promise<boolean>>;
579
+ guardRedirect?: string;
580
+ layout?: ComponentType<{ children: ReactNode }> | string | false;
581
+ placard?: Placard;
582
+ }
583
+
584
+ function getPath(mode: 'hash' | 'history'): string {
585
+ if (mode === 'hash') {
586
+ return window.location.hash.slice(1) || '/';
587
+ }
588
+ return window.location.pathname;
589
+ }
590
+
591
+ function DefaultLoading() {
592
+ return createElement('div', {
593
+ style: {
594
+ display: 'flex',
595
+ alignItems: 'center',
596
+ justifyContent: 'center',
597
+ height: '100%',
598
+ minHeight: '200px',
599
+ },
600
+ }, createElement('div', {
601
+ style: {
602
+ width: '32px',
603
+ height: '32px',
604
+ border: '3px solid rgba(128,128,128,0.3)',
605
+ borderTopColor: 'rgba(128,128,128,0.8)',
606
+ borderRadius: '50%',
607
+ animation: 'snice-spin 0.6s linear infinite',
608
+ },
609
+ }));
610
+ }
611
+
612
+ /** Render a page/layout/loading/fallback prop that can be component, string tag, or JSX */
613
+ function renderFlexible(
614
+ value: ComponentType<any> | string | ReactNode | undefined,
615
+ props?: Record<string, any>,
616
+ ): ReactNode {
617
+ if (!value) return null;
618
+
619
+ // String = Snice web component tag name
620
+ if (typeof value === 'string') {
621
+ return createElement(value, props);
622
+ }
623
+
624
+ // Function = React component
625
+ if (typeof value === 'function') {
626
+ return createElement(value as ComponentType<any>, props);
627
+ }
628
+
629
+ // Already JSX/ReactNode
630
+ return value;
631
+ }
632
+
633
+ /**
634
+ * Root provider component. Manages URL state, route matching,
635
+ * guard execution, layout selection, and context propagation.
636
+ */
637
+ export function SniceRouter({
638
+ mode,
639
+ context = {},
640
+ layout: defaultLayout,
641
+ loading,
642
+ fallback,
643
+ children,
644
+ }: SniceRouterProps) {
645
+ const [currentPath, setCurrentPath] = useState(() => getPath(mode));
646
+ const [guardState, setGuardState] = useState<'idle' | 'checking' | 'passed' | 'failed'>('idle');
647
+ const contextRef = useRef(context);
648
+ contextRef.current = context;
649
+
650
+ // Parse Route children into config
651
+ const parsedRoutes = useMemo<ParsedRoute[]>(() => {
652
+ const result: ParsedRoute[] = [];
653
+ Children.forEach(children, (child) => {
654
+ if (!isValidElement(child) || child.type !== Route) return;
655
+ const props = child.props as RouteProps;
656
+ const guards: ParsedRoute['guards'] = [];
657
+ if (props.guard) guards.push(props.guard);
658
+ if (props.guards) guards.push(...props.guards);
659
+ result.push({
660
+ path: props.path,
661
+ page: props.page,
662
+ guards,
663
+ guardRedirect: props.guardRedirect,
664
+ layout: props.layout,
665
+ placard: props.placard,
666
+ });
667
+ });
668
+ return result;
669
+ }, [children]);
670
+
671
+ // Collect placards
672
+ const placards = useMemo<Placard[]>(() => {
673
+ return parsedRoutes
674
+ .filter((r) => r.placard)
675
+ .map((r) => r.placard!);
676
+ }, [parsedRoutes]);
677
+
678
+ // Build route configs for matching
679
+ const routeConfigs = useMemo<RouteConfig[]>(
680
+ () => parsedRoutes.map((r, i) => ({ path: r.path, index: i })),
681
+ [parsedRoutes],
682
+ );
683
+
684
+ // Navigate function
685
+ const navigate = useCallback(
686
+ (path: string) => {
687
+ if (mode === 'hash') {
688
+ window.location.hash = path;
689
+ } else {
690
+ window.history.pushState(null, '', path);
691
+ setCurrentPath(path);
692
+ }
693
+ },
694
+ [mode],
695
+ );
696
+
697
+ // Listen for URL changes
698
+ useEffect(() => {
699
+ const handler = () => setCurrentPath(getPath(mode));
700
+ const event = mode === 'hash' ? 'hashchange' : 'popstate';
701
+ window.addEventListener(event, handler);
702
+ return () => window.removeEventListener(event, handler);
703
+ }, [mode]);
704
+
705
+ // Match current path
706
+ const match = useMemo(
707
+ () => matchRoutes(routeConfigs, currentPath),
708
+ [routeConfigs, currentPath],
709
+ );
710
+
711
+ const matchedRoute = match ? parsedRoutes[match.index] : null;
712
+ const params = match?.params ?? {};
713
+
714
+ // Run guards
715
+ useEffect(() => {
716
+ if (!matchedRoute) {
717
+ setGuardState('idle');
718
+ return;
719
+ }
720
+
721
+ if (matchedRoute.guards.length === 0) {
722
+ setGuardState('passed');
723
+ return;
724
+ }
725
+
726
+ let cancelled = false;
727
+ setGuardState('checking');
728
+
729
+ (async () => {
730
+ try {
731
+ for (const guard of matchedRoute.guards) {
732
+ const result = await guard(contextRef.current, params);
733
+ if (cancelled) return;
734
+ if (!result) {
735
+ setGuardState('failed');
736
+ if (matchedRoute.guardRedirect) {
737
+ navigate(matchedRoute.guardRedirect);
738
+ }
739
+ return;
740
+ }
741
+ }
742
+ if (!cancelled) setGuardState('passed');
743
+ } catch {
744
+ if (!cancelled) {
745
+ setGuardState('failed');
746
+ if (matchedRoute.guardRedirect) {
747
+ navigate(matchedRoute.guardRedirect);
748
+ }
749
+ }
750
+ }
751
+ })();
752
+
753
+ return () => { cancelled = true; };
754
+ }, [matchedRoute, currentPath]); // eslint-disable-line react-hooks/exhaustive-deps
755
+
756
+ // Determine what to render
757
+ let content: ReactNode;
758
+
759
+ if (!matchedRoute) {
760
+ // No route match → fallback
761
+ content = renderFlexible(fallback) ?? createElement('div', null, '404 — Page not found');
762
+ } else if (guardState === 'checking') {
763
+ // Async guards running → show loading
764
+ content = renderFlexible(loading) ?? createElement(DefaultLoading);
765
+ } else if (guardState === 'failed') {
766
+ // Guard rejected (redirect may have fired) — render nothing
767
+ content = null;
768
+ } else {
769
+ // Guard passed or no guards → render page
770
+ content = renderFlexible(matchedRoute.page, params);
771
+ }
772
+
773
+ // Apply layout
774
+ const layoutToUse = matchedRoute?.layout !== undefined ? matchedRoute.layout : defaultLayout;
775
+ if (layoutToUse && layoutToUse !== false && content !== null) {
776
+ content = renderFlexible(
777
+ layoutToUse as ComponentType<{ children: ReactNode }> | string,
778
+ { children: content },
779
+ );
780
+ }
781
+
782
+ return (
783
+ <SniceProvider
784
+ context={context}
785
+ navigate={navigate}
786
+ route={match?.path ?? ''}
787
+ params={params}
788
+ placards={placards}
789
+ >
790
+ {content}
791
+ </SniceProvider>
792
+ );
793
+ }
794
+ ```
795
+
796
+ **Step 4: Run test to verify it passes**
797
+
798
+ Run: `npx vitest run tests/react/snice-router.test.ts`
799
+ Expected: PASS
800
+
801
+ **Step 5: Commit**
802
+
803
+ ```bash
804
+ git add src/react/SniceRouter.tsx tests/react/snice-router.test.ts
805
+ git commit -m "feat: add SniceRouter and Route components"
806
+ ```
807
+
808
+ ### Task 7: React Barrel Export
809
+
810
+ Create the barrel `src/react/index.ts` that re-exports everything.
811
+
812
+ **Files:**
813
+ - Create: `src/react/index.ts`
814
+
815
+ **Step 1: Create the barrel file**
816
+
817
+ Create `src/react/index.ts`:
818
+
819
+ ```typescript
820
+ // Context
821
+ export {
822
+ SniceProvider,
823
+ useSniceContext,
824
+ useNavigate,
825
+ useParams,
826
+ useRoute,
827
+ type SniceReactContext,
828
+ type SniceProviderProps,
829
+ } from './SniceProvider';
830
+
831
+ // Router
832
+ export {
833
+ SniceRouter,
834
+ Route,
835
+ type SniceRouterProps,
836
+ type RouteProps,
837
+ } from './SniceRouter';
838
+
839
+ // Request handler
840
+ export {
841
+ useRequestHandler,
842
+ type UseRequestRoute,
843
+ type UseRequestRouteMap,
844
+ type UseRequestHandlerOptions,
845
+ } from './useRequestHandler';
846
+ ```
847
+
848
+ **Step 2: Commit**
849
+
850
+ ```bash
851
+ git add src/react/index.ts
852
+ git commit -m "feat: add React barrel export"
853
+ ```
854
+
855
+ ### Task 8: Rollup Build Configuration
856
+
857
+ Add rollup entries so all React modules build to `dist/react/` and copy to `adapters/react/`.
858
+
859
+ **Files:**
860
+ - Modify: `rollup.config.js`
861
+
862
+ **Step 1: Update rollup config**
863
+
864
+ Replace the existing single-file React hooks build entry with a multi-file build:
865
+
866
+ ```javascript
867
+ // React integration (source in src/react/, built to dist/react/, copied to adapters/react/)
868
+ {
869
+ input: {
870
+ 'index': 'src/react/index.ts',
871
+ 'SniceProvider': 'src/react/SniceProvider.tsx',
872
+ 'SniceRouter': 'src/react/SniceRouter.tsx',
873
+ 'matchRoute': 'src/react/matchRoute.ts',
874
+ 'useRequestHandler': 'src/react/useRequestHandler.ts',
875
+ },
876
+ external: ['react', 'pica-route'],
877
+ output: {
878
+ dir: 'dist/react',
879
+ format: 'es',
880
+ banner,
881
+ sourcemap: true,
882
+ entryFileNames: '[name].js',
883
+ },
884
+ plugins: [
885
+ resolve(),
886
+ typescript({
887
+ tsconfig: './tsconfig.src.json',
888
+ declaration: true,
889
+ declarationDir: './dist/react',
890
+ rootDir: './src/react',
891
+ }),
892
+ {
893
+ name: 'copy-react-hooks',
894
+ writeBundle() {
895
+ const src = 'dist/react';
896
+ const dest = 'adapters/react';
897
+ if (fs.existsSync(src)) {
898
+ // Only copy built JS, .d.ts, and map files — not .tsx source
899
+ for (const file of fs.readdirSync(src)) {
900
+ if (file.endsWith('.js') || file.endsWith('.d.ts') || file.endsWith('.js.map') || file.endsWith('.d.ts.map')) {
901
+ fs.copyFileSync(path.join(src, file), path.join(dest, file));
902
+ }
903
+ }
904
+ }
905
+ }
906
+ }
907
+ ]
908
+ },
909
+ ```
910
+
911
+ **Step 2: Build and verify**
912
+
913
+ Run: `npm run build:core`
914
+ Expected: Build succeeds, `dist/react/` contains index.js, SniceProvider.js, SniceRouter.js, matchRoute.js, useRequestHandler.js + .d.ts files. Same files copied to `adapters/react/`.
915
+
916
+ **Step 3: Commit**
917
+
918
+ ```bash
919
+ git add rollup.config.js
920
+ git commit -m "feat: update rollup config for full React integration build"
921
+ ```
922
+
923
+ ### Task 9: Integration Test — Full Router Flow
924
+
925
+ Test the full router flow end-to-end without a browser (vitest + happy-dom).
926
+
927
+ **Files:**
928
+ - Create: `tests/react/snice-router-integration.test.ts`
929
+
930
+ **Step 1: Write integration tests**
931
+
932
+ Create `tests/react/snice-router-integration.test.ts`:
933
+
934
+ ```typescript
935
+ import { describe, it, expect, beforeEach } from 'vitest';
936
+ import { SniceRouter, Route } from '../../src/react/SniceRouter';
937
+ import { SniceProvider, useSniceContext, useNavigate, useParams, useRoute } from '../../src/react/SniceProvider';
938
+
939
+ describe('SniceRouter integration', () => {
940
+ it('should export all public API', () => {
941
+ expect(typeof SniceRouter).toBe('function');
942
+ expect(typeof Route).toBe('function');
943
+ expect(typeof SniceProvider).toBe('function');
944
+ expect(typeof useSniceContext).toBe('function');
945
+ expect(typeof useNavigate).toBe('function');
946
+ expect(typeof useParams).toBe('function');
947
+ expect(typeof useRoute).toBe('function');
948
+ });
949
+
950
+ it('Route component should return null (config-only)', () => {
951
+ const result = Route({
952
+ path: '/test',
953
+ page: () => null,
954
+ });
955
+ expect(result).toBeNull();
956
+ });
957
+ });
958
+ ```
959
+
960
+ **Step 2: Run test**
961
+
962
+ Run: `npx vitest run tests/react/snice-router-integration.test.ts`
963
+ Expected: PASS
964
+
965
+ **Step 3: Commit**
966
+
967
+ ```bash
968
+ git add tests/react/snice-router-integration.test.ts
969
+ git commit -m "test: add React router integration tests"
970
+ ```
971
+
972
+ ### Task 10: Update Package.json Exports
973
+
974
+ Ensure `snice/react` resolves to the barrel and individual modules are importable.
975
+
976
+ **Files:**
977
+ - Modify: `package.json`
978
+
979
+ **Step 1: Verify existing exports**
980
+
981
+ Check the current `"./react"` and `"./react/*"` exports in package.json. They should already point to `adapters/react/`:
982
+
983
+ ```json
984
+ "./react": {
985
+ "types": "./adapters/react/index.d.ts",
986
+ "import": "./adapters/react/index.js"
987
+ },
988
+ "./react/*": {
989
+ "types": "./adapters/react/*.d.ts",
990
+ "import": "./adapters/react/*.js"
991
+ }
992
+ ```
993
+
994
+ These should already work with the new barrel export. Verify by checking that the built files exist after `npm run build:core`.
995
+
996
+ **Step 2: Commit (only if changes needed)**
997
+
998
+ ```bash
999
+ git add package.json
1000
+ git commit -m "chore: update package.json exports for React integration"
1001
+ ```
1002
+
1003
+ ### Task 11: Documentation
1004
+
1005
+ **Files:**
1006
+ - Create or modify: `docs/ai/react-integration.md`
1007
+ - Modify: `docs/ai/patterns.md` (add React router section)
1008
+
1009
+ **Step 1: Create `docs/ai/react-integration.md`**
1010
+
1011
+ ```markdown
1012
+ # React Integration
1013
+
1014
+ Source: `src/react/` → Build: `dist/react/` → Published: `adapters/react/`
1015
+ Import: `import { SniceRouter, Route, useSniceContext } from 'snice/react'`
1016
+
1017
+ ## Components
1018
+
1019
+ | Export | Type | Purpose |
1020
+ |---|---|---|
1021
+ | `<SniceRouter>` | Component | Root provider. URL state, route matching, guards, layouts, context. |
1022
+ | `<Route>` | Component | Route definition. Child of `<SniceRouter>`. |
1023
+ | `<SniceProvider>` | Component | Context provider (standalone, no router needed). |
1024
+
1025
+ ## Hooks
1026
+
1027
+ | Export | Returns | Purpose |
1028
+ |---|---|---|
1029
+ | `useSniceContext()` | `SniceReactContext` | Full merged context (`application`, `navigation`, `navigate`, `params`, `route`) |
1030
+ | `useNavigate()` | `(path) => void` | Programmatic navigation |
1031
+ | `useParams()` | `Record<string, string>` | Current route params |
1032
+ | `useRoute()` | `string` | Current matched route pattern |
1033
+ | `useRequestHandler()` | `void` | Handle @request channels from Snice elements |
1034
+
1035
+ ## SniceRouter Props
1036
+
1037
+ - `mode`: `"hash"` | `"history"` — URL strategy
1038
+ - `context`: `object` — App context passed to guards, pages, layouts
1039
+ - `layout`: `Component | string` — Default layout
1040
+ - `loading`: `Component | string | JSX` — Shown during async guards
1041
+ - `fallback`: `Component | string | JSX` — No route match
1042
+
1043
+ ## Route Props
1044
+
1045
+ - `path`: Route pattern (e.g., `/users/:id`)
1046
+ - `page`: React component OR Snice tag name (string)
1047
+ - `guard`: `(ctx, params) => boolean | Promise<boolean>`
1048
+ - `guards`: Array of guard functions (AND logic)
1049
+ - `guardRedirect`: Redirect path on guard failure
1050
+ - `layout`: Override layout. `false` = no layout
1051
+ - `placard`: Page metadata for layouts
1052
+
1053
+ ## Guards
1054
+
1055
+ Same signature for both Snice and React:
1056
+ `(context, params) => boolean | Promise<boolean>`
1057
+
1058
+ Async guards show the `loading` component until resolved.
1059
+
1060
+ ## Context Shape
1061
+
1062
+ ```typescript
1063
+ interface SniceReactContext {
1064
+ application: Record<string, any>; // User-defined app state
1065
+ navigation: { route: string; params: Record<string, string>; placards: Placard[] };
1066
+ navigate: (path: string) => void;
1067
+ fetch?: typeof globalThis.fetch;
1068
+ }
1069
+ ```
1070
+ ```
1071
+
1072
+ **Step 2: Update `docs/ai/patterns.md`**
1073
+
1074
+ Add a section at the end for React Router usage:
1075
+
1076
+ ```markdown
1077
+ ## React Router
1078
+
1079
+ ```tsx
1080
+ import { SniceRouter, Route, useSniceContext } from 'snice/react';
1081
+
1082
+ function App() {
1083
+ return (
1084
+ <SniceRouter mode="hash" context={{ user, theme: 'dark' }} layout={AppShell}>
1085
+ <Route path="/" page={HomePage} />
1086
+ <Route path="/settings" page={SettingsPage} guard={authGuard} guardRedirect="/login" />
1087
+ <Route path="/legacy" page="legacy-dashboard" />
1088
+ <Route path="/login" page={LoginPage} layout={false} />
1089
+ </SniceRouter>
1090
+ );
1091
+ }
1092
+
1093
+ // Layout
1094
+ function AppShell({ children }) {
1095
+ const ctx = useSniceContext();
1096
+ return <div className="shell"><nav>...</nav><main>{children}</main></div>;
1097
+ }
1098
+
1099
+ // Guard (shared with vanilla Snice)
1100
+ const authGuard = (ctx, params) => !!ctx.principal;
1101
+ ```
1102
+ ```
1103
+
1104
+ **Step 3: Commit**
1105
+
1106
+ ```bash
1107
+ git add docs/ai/react-integration.md docs/ai/patterns.md
1108
+ git commit -m "docs: add React integration documentation"
1109
+ ```
1110
+
1111
+ ### Task 12: Human-Facing Documentation
1112
+
1113
+ **Files:**
1114
+ - Create: `docs/react-integration.md`
1115
+
1116
+ **Step 1: Write docs/react-integration.md**
1117
+
1118
+ Write the human-friendly version with full examples, matching the design doc's content. Use the design doc at `docs/plans/2026-03-10-react-integration-design.md` as the source. Include:
1119
+ - Installation/import instructions
1120
+ - SniceRouter + Route full API
1121
+ - Guards (sync + async) with examples
1122
+ - Layouts (React + Snice tag)
1123
+ - Mixed pages example
1124
+ - Context hooks
1125
+ - Comparison with vanilla Snice
1126
+
1127
+ **Step 2: Commit**
1128
+
1129
+ ```bash
1130
+ git add docs/react-integration.md
1131
+ git commit -m "docs: add human-friendly React integration guide"
1132
+ ```
1133
+
1134
+ ### Task 13: Final Build + Test Verification
1135
+
1136
+ **Step 1: Full build**
1137
+
1138
+ Run: `npm run build:core`
1139
+ Expected: All builds succeed including React integration
1140
+
1141
+ **Step 2: Run all tests**
1142
+
1143
+ Run: `npm run build:test && npx vitest run`
1144
+ Expected: All tests pass
1145
+
1146
+ **Step 3: Verify exports**
1147
+
1148
+ Run: `ls dist/react/ && ls adapters/react/index.js adapters/react/SniceRouter.js adapters/react/SniceProvider.js`
1149
+ Expected: All files present
1150
+
1151
+ **Step 4: Final commit if needed**
1152
+
1153
+ ```bash
1154
+ git add -A
1155
+ git commit -m "chore: final build verification for React integration"
1156
+ ```
1157
+
1158
+ ---
1159
+
1160
+ ## Task Summary
1161
+
1162
+ | Task | Description | Dependencies |
1163
+ |------|-------------|--------------|
1164
+ | 1 | Update Guard type for async | None |
1165
+ | 2 | Make vanilla checkGuards async | Task 1 |
1166
+ | 3 | Async guard tests for vanilla router | Task 2 |
1167
+ | 4 | SniceProvider + context hooks | None |
1168
+ | 5 | Route matching utility | None |
1169
+ | 6 | SniceRouter + Route components | Tasks 4, 5 |
1170
+ | 7 | React barrel export | Tasks 4, 5, 6 |
1171
+ | 8 | Rollup build configuration | Task 7 |
1172
+ | 9 | Integration tests | Tasks 6, 7 |
1173
+ | 10 | Package.json exports | Task 8 |
1174
+ | 11 | AI documentation | Task 6 |
1175
+ | 12 | Human documentation | Task 6 |
1176
+ | 13 | Final build + test verification | All |
1177
+
1178
+ **Parallelizable:** Tasks 1-3 (async guards) can be done independently from Tasks 4-5 (provider + matching). Tasks 11-12 (docs) can be done in parallel.