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,10 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ interface ImportMetaEnv {
4
+ readonly VITE_API_URL?: string;
5
+ readonly VITE_WS_URL?: string;
6
+ }
7
+
8
+ interface ImportMeta {
9
+ readonly env: ImportMetaEnv;
10
+ }
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <meta name="description" content="{{projectName}} - Built with Snice + React" />
7
+ <meta name="theme-color" content="#2563eb" />
8
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
9
+ <title>{{projectName}}</title>
10
+ </head>
11
+ <body>
12
+ <div id="root"></div>
13
+ <script type="module" src="/src/main.tsx"></script>
14
+ </body>
15
+ </html>
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc && vite build",
9
+ "type-check": "tsc --noEmit",
10
+ "preview": "vite preview",
11
+ "test": "vitest run",
12
+ "test:watch": "vitest",
13
+ "test:coverage": "vitest run --coverage"
14
+ },
15
+ "dependencies": {
16
+ "react": "^19.0.0",
17
+ "react-dom": "^19.0.0",
18
+ "snice": "^4.0.0"
19
+ },
20
+ "devDependencies": {
21
+ "@types/react": "^19.0.0",
22
+ "@types/react-dom": "^19.0.0",
23
+ "@vitejs/plugin-react": "^4.3.0",
24
+ "@vitest/coverage-v8": "^1.0.4",
25
+ "@vitest/ui": "^1.0.4",
26
+ "happy-dom": "^12.10.3",
27
+ "typescript": "^5.3.3",
28
+ "vite": "^5.0.10",
29
+ "vitest": "^1.0.4"
30
+ }
31
+ }
@@ -0,0 +1,112 @@
1
+ import { useState, useCallback } from 'react';
2
+ import { SniceRouter, Route } from 'snice/react';
3
+ import { isAuthenticated as checkAuth } from './services/auth';
4
+ import { getUser } from './services/storage';
5
+ import { login, logout } from './services/auth';
6
+ import { NotificationsDaemon } from './daemons/notifications';
7
+ import { isAuthenticated } from './guards/auth';
8
+ import { AppLayout } from './components/AppLayout';
9
+ import { LoginPage } from './pages/LoginPage';
10
+ import { DashboardPage } from './pages/DashboardPage';
11
+ import { DataPage } from './pages/DataPage';
12
+ import { ProfilePage } from './pages/ProfilePage';
13
+ import { NotificationsPage } from './pages/NotificationsPage';
14
+ import { SettingsPage } from './pages/SettingsPage';
15
+ import type { User } from './types/auth';
16
+
17
+ // In production, use actual WebSocket URL from env
18
+ const wsUrl = import.meta.env.VITE_WS_URL || 'ws://localhost:8080';
19
+ const notifications = new NotificationsDaemon(wsUrl);
20
+ notifications.start();
21
+
22
+ export function App() {
23
+ const [authState, setAuthState] = useState(() => ({
24
+ user: getUser<User>(),
25
+ isAuthenticated: checkAuth()
26
+ }));
27
+
28
+ const refreshAuth = useCallback(() => {
29
+ setAuthState({
30
+ user: getUser<User>(),
31
+ isAuthenticated: checkAuth()
32
+ });
33
+ }, []);
34
+
35
+ const context = {
36
+ principal: authState,
37
+ notifications,
38
+ refreshAuth,
39
+ login: async (email: string, password: string) => {
40
+ const result = await login({ email, password });
41
+ refreshAuth();
42
+ return result;
43
+ },
44
+ logout: async () => {
45
+ await logout();
46
+ refreshAuth();
47
+ }
48
+ };
49
+
50
+ return (
51
+ <SniceRouter
52
+ mode="hash"
53
+ context={context}
54
+ layout={AppLayout}
55
+ fallback={<NotFound />}
56
+ >
57
+ <Route path="/login" page={LoginPage} layout={false} />
58
+ <Route
59
+ path="/"
60
+ page={DashboardPage}
61
+ guard={isAuthenticated}
62
+ guardRedirect="/login"
63
+ placard={{ name: 'dashboard', title: 'Dashboard', icon: '\ud83d\udcca', show: true, order: 1 }}
64
+ />
65
+ <Route
66
+ path="/dashboard"
67
+ page={DashboardPage}
68
+ guard={isAuthenticated}
69
+ guardRedirect="/login"
70
+ placard={{ name: 'dashboard', title: 'Dashboard', icon: '\ud83d\udcca', show: false }}
71
+ />
72
+ <Route
73
+ path="/profile"
74
+ page={ProfilePage}
75
+ guard={isAuthenticated}
76
+ guardRedirect="/login"
77
+ placard={{ name: 'profile', title: 'Profile', icon: '\ud83d\udc64', show: true, order: 2 }}
78
+ />
79
+ <Route
80
+ path="/notifications"
81
+ page={NotificationsPage}
82
+ guard={isAuthenticated}
83
+ guardRedirect="/login"
84
+ placard={{ name: 'notifications', title: 'Notifications', icon: '\ud83d\udd14', show: true, order: 3 }}
85
+ />
86
+ <Route
87
+ path="/settings"
88
+ page={SettingsPage}
89
+ guard={isAuthenticated}
90
+ guardRedirect="/login"
91
+ placard={{ name: 'settings', title: 'Settings', icon: '\u2699\ufe0f', show: true, order: 4 }}
92
+ />
93
+ <Route
94
+ path="/data"
95
+ page={DataPage}
96
+ guard={isAuthenticated}
97
+ guardRedirect="/login"
98
+ placard={{ name: 'data', title: 'Data', icon: '\ud83d\udcca', show: true, order: 5 }}
99
+ />
100
+ </SniceRouter>
101
+ );
102
+ }
103
+
104
+ function NotFound() {
105
+ return (
106
+ <div style={{ textAlign: 'center', padding: '4rem' }}>
107
+ <h1>404</h1>
108
+ <p>Page not found</p>
109
+ <a href="#/">Go home</a>
110
+ </div>
111
+ );
112
+ }
@@ -0,0 +1,85 @@
1
+ import { useState, useEffect, useCallback } from 'react';
2
+ import { useSniceContext } from 'snice/react';
3
+ import { Avatar, Divider } from 'snice/react';
4
+ import { NotificationBadge } from './NotificationBadge';
5
+ import type { NotificationsDaemon } from '../daemons/notifications';
6
+
7
+ export function AppHeader() {
8
+ const ctx = useSniceContext();
9
+ const app = ctx.application;
10
+ const principal = app.principal;
11
+ const authenticated = principal?.isAuthenticated || false;
12
+ const user = principal?.user;
13
+ const [menuOpen, setMenuOpen] = useState(false);
14
+ const [notificationCount, setNotificationCount] = useState(0);
15
+
16
+ useEffect(() => {
17
+ const daemon = app.notifications as NotificationsDaemon | undefined;
18
+ if (!daemon) return;
19
+
20
+ const unsubscribe = daemon.subscribe(() => {
21
+ setNotificationCount(prev => prev + 1);
22
+ });
23
+
24
+ return unsubscribe;
25
+ }, [app.notifications]);
26
+
27
+ const handleKeyDown = useCallback((e: KeyboardEvent) => {
28
+ if (e.key === 'Escape') {
29
+ setMenuOpen(false);
30
+ }
31
+ }, []);
32
+
33
+ useEffect(() => {
34
+ document.addEventListener('keydown', handleKeyDown);
35
+ return () => document.removeEventListener('keydown', handleKeyDown);
36
+ }, [handleKeyDown]);
37
+
38
+ const handleLogout = async () => {
39
+ setMenuOpen(false);
40
+ await app.logout();
41
+ };
42
+
43
+ return (
44
+ <header className="app-header">
45
+ <div className="brand">
46
+ <a href="#/">{'{{projectName}}'}</a>
47
+ </div>
48
+
49
+ {authenticated ? (
50
+ <>
51
+ <nav className="nav-links">
52
+ <a href="#/dashboard">Dashboard</a>
53
+ <a href="#/data">Data</a>
54
+ <a href="#/notifications">
55
+ <NotificationBadge count={notificationCount} />
56
+ Notifications
57
+ </a>
58
+ </nav>
59
+
60
+ <div className="user-section">
61
+ <button className="user-btn" onClick={() => setMenuOpen(!menuOpen)}>
62
+ <Avatar
63
+ src={user?.avatar || ''}
64
+ name={user?.name || ''}
65
+ size="small"
66
+ />
67
+ <span className="user-name">{user?.name}</span>
68
+ </button>
69
+
70
+ {menuOpen && (
71
+ <div className="user-menu">
72
+ <a href="#/profile" onClick={() => setMenuOpen(false)}>Profile</a>
73
+ <a href="#/settings" onClick={() => setMenuOpen(false)}>Settings</a>
74
+ <Divider />
75
+ <button onClick={handleLogout}>Sign Out</button>
76
+ </div>
77
+ )}
78
+ </div>
79
+ </>
80
+ ) : (
81
+ <a href="#/login" className="login-link">Sign In</a>
82
+ )}
83
+ </header>
84
+ );
85
+ }
@@ -0,0 +1,11 @@
1
+ import { type ReactNode } from 'react';
2
+ import { AppHeader } from './AppHeader';
3
+
4
+ export function AppLayout({ children }: { children: ReactNode }) {
5
+ return (
6
+ <div className="app">
7
+ <AppHeader />
8
+ <main>{children}</main>
9
+ </div>
10
+ );
11
+ }
@@ -0,0 +1,13 @@
1
+ interface NotificationBadgeProps {
2
+ count: number;
3
+ }
4
+
5
+ export function NotificationBadge({ count }: NotificationBadgeProps) {
6
+ if (count <= 0) return null;
7
+
8
+ return (
9
+ <span className="notification-badge">
10
+ {count > 99 ? '99+' : count}
11
+ </span>
12
+ );
13
+ }
@@ -0,0 +1,63 @@
1
+ import { useState, useRef, useCallback, useEffect } from 'react';
2
+
3
+ interface SearchBarProps {
4
+ placeholder?: string;
5
+ onSearch: (query: string) => void;
6
+ debounceMs?: number;
7
+ }
8
+
9
+ export function SearchBar({ placeholder = 'Search...', onSearch, debounceMs = 300 }: SearchBarProps) {
10
+ const [value, setValue] = useState('');
11
+ const timerRef = useRef<number | null>(null);
12
+
13
+ const debouncedSearch = useCallback((query: string) => {
14
+ if (timerRef.current !== null) {
15
+ clearTimeout(timerRef.current);
16
+ }
17
+ timerRef.current = window.setTimeout(() => {
18
+ onSearch(query);
19
+ }, debounceMs);
20
+ }, [onSearch, debounceMs]);
21
+
22
+ useEffect(() => {
23
+ return () => {
24
+ if (timerRef.current !== null) {
25
+ clearTimeout(timerRef.current);
26
+ }
27
+ };
28
+ }, []);
29
+
30
+ const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
31
+ const newValue = e.target.value;
32
+ setValue(newValue);
33
+ debouncedSearch(newValue);
34
+ };
35
+
36
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
37
+ if (e.key === 'Escape') {
38
+ setValue('');
39
+ onSearch('');
40
+ }
41
+ };
42
+
43
+ const clearSearch = () => {
44
+ setValue('');
45
+ onSearch('');
46
+ };
47
+
48
+ return (
49
+ <div className="search-bar">
50
+ <span className="search-icon">&#128269;</span>
51
+ <input
52
+ type="text"
53
+ value={value}
54
+ onChange={handleInput}
55
+ onKeyDown={handleKeyDown}
56
+ placeholder={placeholder}
57
+ />
58
+ {value.length > 0 && (
59
+ <button className="clear-btn" onClick={clearSearch}>&#10005;</button>
60
+ )}
61
+ </div>
62
+ );
63
+ }
@@ -0,0 +1,136 @@
1
+ import type { Notification } from '../types/notifications';
2
+
3
+ type NotificationHandler = (notification: Notification) => void;
4
+
5
+ export class NotificationsDaemon {
6
+ private ws: WebSocket | null = null;
7
+ private handlers: Set<NotificationHandler> = new Set();
8
+ private reconnectInterval: number = 5000;
9
+ private reconnectTimer: number | null = null;
10
+ private mockInterval: number | null = null;
11
+ private url: string;
12
+ private isStarted: boolean = false;
13
+
14
+ constructor(url: string) {
15
+ this.url = url;
16
+ }
17
+
18
+ start(): void {
19
+ if (this.isStarted) return;
20
+ this.isStarted = true;
21
+
22
+ // For demo purposes, use mock notifications instead of real WebSocket
23
+ // In production, uncomment the connect() line and remove startMockNotifications()
24
+ // this.connect();
25
+ this.startMockNotifications();
26
+ }
27
+
28
+ stop(): void {
29
+ if (!this.isStarted) return;
30
+ this.isStarted = false;
31
+
32
+ this.stopMockNotifications();
33
+
34
+ if (this.reconnectTimer !== null) {
35
+ clearTimeout(this.reconnectTimer);
36
+ this.reconnectTimer = null;
37
+ }
38
+
39
+ if (this.ws) {
40
+ this.ws.close();
41
+ this.ws = null;
42
+ }
43
+ }
44
+
45
+ dispose(): void {
46
+ this.stop();
47
+ this.handlers.clear();
48
+ }
49
+
50
+ subscribe(handler: NotificationHandler): () => void {
51
+ this.handlers.add(handler);
52
+ return () => this.handlers.delete(handler);
53
+ }
54
+
55
+ private connect(): void {
56
+ try {
57
+ this.ws = new WebSocket(this.url);
58
+
59
+ this.ws.onopen = () => {
60
+ console.log('WebSocket connected');
61
+ };
62
+
63
+ this.ws.onmessage = (event) => {
64
+ try {
65
+ const notification: Notification = JSON.parse(event.data);
66
+ this.notify(notification);
67
+ } catch (err) {
68
+ console.error('Failed to parse notification:', err);
69
+ }
70
+ };
71
+
72
+ this.ws.onerror = (error) => {
73
+ console.error('WebSocket error:', error);
74
+ };
75
+
76
+ this.ws.onclose = () => {
77
+ console.log('WebSocket disconnected');
78
+ if (this.isStarted) {
79
+ this.scheduleReconnect();
80
+ }
81
+ };
82
+ } catch (err) {
83
+ console.error('Failed to create WebSocket:', err);
84
+ if (this.isStarted) {
85
+ this.scheduleReconnect();
86
+ }
87
+ }
88
+ }
89
+
90
+ private scheduleReconnect(): void {
91
+ if (this.reconnectTimer !== null) return;
92
+
93
+ this.reconnectTimer = window.setTimeout(() => {
94
+ this.reconnectTimer = null;
95
+ this.connect();
96
+ }, this.reconnectInterval);
97
+ }
98
+
99
+ private notify(notification: Notification): void {
100
+ this.handlers.forEach(handler => {
101
+ try {
102
+ handler(notification);
103
+ } catch (err) {
104
+ console.error('Notification handler error:', err);
105
+ }
106
+ });
107
+ }
108
+
109
+ // Mock notifications for demo
110
+ private startMockNotifications(): void {
111
+ const messages = [
112
+ { title: 'Welcome!', message: 'Thanks for checking out the PWA template', type: 'info' as const },
113
+ { title: 'New Feature', message: 'Check out the notifications page', type: 'success' as const },
114
+ { title: 'System Update', message: 'A new version is available', type: 'info' as const },
115
+ { title: 'Reminder', message: 'Don\'t forget to star the repo!', type: 'warning' as const }
116
+ ];
117
+
118
+ let index = 0;
119
+ this.mockInterval = window.setInterval(() => {
120
+ const notification: Notification = {
121
+ id: `mock-${Date.now()}`,
122
+ ...messages[index % messages.length],
123
+ timestamp: new Date().toISOString()
124
+ };
125
+ this.notify(notification);
126
+ index++;
127
+ }, 10000); // Send notification every 10 seconds
128
+ }
129
+
130
+ private stopMockNotifications(): void {
131
+ if (this.mockInterval !== null) {
132
+ clearInterval(this.mockInterval);
133
+ this.mockInterval = null;
134
+ }
135
+ }
136
+ }
@@ -0,0 +1,15 @@
1
+ import { ContextAwareFetcher } from 'snice';
2
+ import { authMiddleware } from './middleware/auth';
3
+ import { errorMiddleware } from './middleware/error';
4
+ import { createRetryMiddleware } from './middleware/retry';
5
+
6
+ const fetcher = new ContextAwareFetcher();
7
+
8
+ // Add request middleware (runs before fetch)
9
+ fetcher.use('request', authMiddleware);
10
+ fetcher.use('request', createRetryMiddleware());
11
+
12
+ // Add response middleware (runs after fetch)
13
+ fetcher.use('response', errorMiddleware);
14
+
15
+ export { fetcher };
@@ -0,0 +1,6 @@
1
+ import type { Principal } from '../types/auth';
2
+
3
+ export const isAuthenticated = (ctx: any, _params: any) => {
4
+ const principal = ctx.principal as Principal | undefined;
5
+ return principal?.isAuthenticated === true;
6
+ };
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom/client';
3
+ import { App } from './App';
4
+ import 'snice/components/theme/theme.css';
5
+ import './styles/global.css';
6
+
7
+ // Import snice web component registrations
8
+ import 'snice/components/layout/snice-layout';
9
+ import 'snice/components/button/snice-button';
10
+ import 'snice/components/card/snice-card';
11
+ import 'snice/components/input/snice-input';
12
+ import 'snice/components/alert/snice-alert';
13
+ import 'snice/components/avatar/snice-avatar';
14
+ import 'snice/components/empty-state/snice-empty-state';
15
+ import 'snice/components/spinner/snice-spinner';
16
+ import 'snice/components/badge/snice-badge';
17
+ import 'snice/components/switch/snice-switch';
18
+ import 'snice/components/divider/snice-divider';
19
+ import 'snice/components/tabs/snice-tabs';
20
+ import 'snice/components/tabs/snice-tab';
21
+ import 'snice/components/login/snice-login';
22
+
23
+ ReactDOM.createRoot(document.getElementById('root')!).render(
24
+ <React.StrictMode>
25
+ <App />
26
+ </React.StrictMode>
27
+ );
@@ -0,0 +1,16 @@
1
+ import type { Context } from 'snice';
2
+ import { getToken } from '../services/storage';
3
+
4
+ export async function authMiddleware(
5
+ this: Context,
6
+ request: Request,
7
+ next: () => Promise<Response>
8
+ ): Promise<Response> {
9
+ const token = getToken();
10
+
11
+ if (token) {
12
+ request.headers.set('Authorization', `Bearer ${token}`);
13
+ }
14
+
15
+ return next();
16
+ }
@@ -0,0 +1,29 @@
1
+ import type { Context } from 'snice';
2
+ import { clearToken } from '../services/storage';
3
+
4
+ export async function errorMiddleware(
5
+ this: Context,
6
+ response: Response,
7
+ next: () => Promise<Response>
8
+ ): Promise<Response> {
9
+ // Handle 401 unauthorized - token expired or invalid
10
+ if (response.status === 401) {
11
+ clearToken();
12
+
13
+ // Getters in context will reflect logged-out state since token is cleared
14
+ window.location.href = '#/login';
15
+ throw new Error('Unauthorized - redirecting to login');
16
+ }
17
+
18
+ // Handle other errors
19
+ if (!response.ok) {
20
+ const contentType = response.headers.get('content-type');
21
+ if (contentType && contentType.includes('application/json')) {
22
+ const error = await response.json();
23
+ throw new Error(error.message || `Request failed with status ${response.status}`);
24
+ }
25
+ throw new Error(`Request failed with status ${response.status}`);
26
+ }
27
+
28
+ return next();
29
+ }
@@ -0,0 +1,31 @@
1
+ import type { Context } from 'snice';
2
+
3
+ export function createRetryMiddleware(retries = 3, delay = 1000) {
4
+ return async function retryMiddleware(
5
+ this: Context,
6
+ _request: Request,
7
+ next: () => Promise<Response>
8
+ ): Promise<Response> {
9
+ let lastError: Error;
10
+
11
+ for (let i = 0; i < retries; i++) {
12
+ try {
13
+ return await next();
14
+ } catch (err) {
15
+ lastError = err as Error;
16
+
17
+ // Don't retry on certain errors
18
+ if (err instanceof Error && err.message.includes('Unauthorized')) {
19
+ throw err;
20
+ }
21
+
22
+ // Wait before retrying (exponential backoff)
23
+ if (i < retries - 1) {
24
+ await new Promise(resolve => setTimeout(resolve, delay * (i + 1)));
25
+ }
26
+ }
27
+ }
28
+
29
+ throw lastError!;
30
+ };
31
+ }