snice 2.5.4 → 3.1.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 (323) hide show
  1. package/README.md +501 -882
  2. package/bin/templates/base/src/components/counter-button.ts +13 -26
  3. package/bin/templates/base/src/controllers/counter-controller.ts +3 -3
  4. package/dist/components/accordion/snice-accordion-item.d.ts +4 -5
  5. package/dist/components/accordion/snice-accordion-item.js +37 -39
  6. package/dist/components/accordion/snice-accordion-item.js.map +1 -1
  7. package/dist/components/accordion/snice-accordion.d.ts +5 -11
  8. package/dist/components/accordion/snice-accordion.js +51 -52
  9. package/dist/components/accordion/snice-accordion.js.map +1 -1
  10. package/dist/components/alert/snice-alert.d.ts +2 -6
  11. package/dist/components/alert/snice-alert.js +41 -56
  12. package/dist/components/alert/snice-alert.js.map +1 -1
  13. package/dist/components/avatar/snice-avatar.d.ts +2 -6
  14. package/dist/components/avatar/snice-avatar.js +64 -71
  15. package/dist/components/avatar/snice-avatar.js.map +1 -1
  16. package/dist/components/badge/snice-badge.d.ts +2 -3
  17. package/dist/components/badge/snice-badge.js +22 -23
  18. package/dist/components/badge/snice-badge.js.map +1 -1
  19. package/dist/components/breadcrumbs/snice-breadcrumbs.d.ts +5 -12
  20. package/dist/components/breadcrumbs/snice-breadcrumbs.js +88 -89
  21. package/dist/components/breadcrumbs/snice-breadcrumbs.js.map +1 -1
  22. package/dist/components/button/snice-button.d.ts +3 -7
  23. package/dist/components/button/snice-button.js +37 -58
  24. package/dist/components/button/snice-button.js.map +1 -1
  25. package/dist/components/card/snice-card.d.ts +5 -8
  26. package/dist/components/card/snice-card.js +71 -56
  27. package/dist/components/card/snice-card.js.map +1 -1
  28. package/dist/components/checkbox/snice-checkbox.d.ts +4 -13
  29. package/dist/components/checkbox/snice-checkbox.js +66 -137
  30. package/dist/components/checkbox/snice-checkbox.js.map +1 -1
  31. package/dist/components/chip/snice-chip.d.ts +5 -11
  32. package/dist/components/chip/snice-chip.js +44 -47
  33. package/dist/components/chip/snice-chip.js.map +1 -1
  34. package/dist/components/date-picker/snice-date-picker.d.ts +11 -11
  35. package/dist/components/date-picker/snice-date-picker.js +134 -133
  36. package/dist/components/date-picker/snice-date-picker.js.map +1 -1
  37. package/dist/components/divider/snice-divider.d.ts +2 -4
  38. package/dist/components/divider/snice-divider.js +14 -22
  39. package/dist/components/divider/snice-divider.js.map +1 -1
  40. package/dist/components/drawer/snice-drawer.d.ts +4 -4
  41. package/dist/components/drawer/snice-drawer.js +25 -19
  42. package/dist/components/drawer/snice-drawer.js.map +1 -1
  43. package/dist/components/input/snice-input.d.ts +8 -6
  44. package/dist/components/input/snice-input.js +122 -105
  45. package/dist/components/input/snice-input.js.map +1 -1
  46. package/dist/components/layout/snice-layout-blog.d.ts +4 -4
  47. package/dist/components/layout/snice-layout-blog.js +21 -19
  48. package/dist/components/layout/snice-layout-blog.js.map +1 -1
  49. package/dist/components/layout/snice-layout-card.d.ts +2 -2
  50. package/dist/components/layout/snice-layout-card.js +16 -9
  51. package/dist/components/layout/snice-layout-card.js.map +1 -1
  52. package/dist/components/layout/snice-layout-centered.d.ts +2 -2
  53. package/dist/components/layout/snice-layout-centered.js +14 -7
  54. package/dist/components/layout/snice-layout-centered.js.map +1 -1
  55. package/dist/components/layout/snice-layout-dashboard.d.ts +5 -5
  56. package/dist/components/layout/snice-layout-dashboard.js +38 -30
  57. package/dist/components/layout/snice-layout-dashboard.js.map +1 -1
  58. package/dist/components/layout/snice-layout-fullscreen.d.ts +2 -2
  59. package/dist/components/layout/snice-layout-fullscreen.js +17 -10
  60. package/dist/components/layout/snice-layout-fullscreen.js.map +1 -1
  61. package/dist/components/layout/snice-layout-landing.d.ts +4 -4
  62. package/dist/components/layout/snice-layout-landing.js +21 -19
  63. package/dist/components/layout/snice-layout-landing.js.map +1 -1
  64. package/dist/components/layout/snice-layout-minimal.d.ts +2 -2
  65. package/dist/components/layout/snice-layout-minimal.js +17 -6
  66. package/dist/components/layout/snice-layout-minimal.js.map +1 -1
  67. package/dist/components/layout/snice-layout-sidebar.d.ts +5 -4
  68. package/dist/components/layout/snice-layout-sidebar.js +42 -20
  69. package/dist/components/layout/snice-layout-sidebar.js.map +1 -1
  70. package/dist/components/layout/snice-layout-split.d.ts +2 -2
  71. package/dist/components/layout/snice-layout-split.js +14 -7
  72. package/dist/components/layout/snice-layout-split.js.map +1 -1
  73. package/dist/components/layout/snice-layout.d.ts +4 -4
  74. package/dist/components/layout/snice-layout.js +16 -10
  75. package/dist/components/layout/snice-layout.js.map +1 -1
  76. package/dist/components/login/snice-login.d.ts +6 -11
  77. package/dist/components/login/snice-login.js +97 -71
  78. package/dist/components/login/snice-login.js.map +1 -1
  79. package/dist/components/modal/snice-modal.d.ts +5 -9
  80. package/dist/components/modal/snice-modal.js +47 -78
  81. package/dist/components/modal/snice-modal.js.map +1 -1
  82. package/dist/components/nav/snice-nav.d.ts +13 -7
  83. package/dist/components/nav/snice-nav.js +191 -100
  84. package/dist/components/nav/snice-nav.js.map +1 -1
  85. package/dist/components/nav/snice-nav.types.d.ts +3 -3
  86. package/dist/components/pagination/snice-pagination.d.ts +6 -7
  87. package/dist/components/pagination/snice-pagination.js +94 -81
  88. package/dist/components/pagination/snice-pagination.js.map +1 -1
  89. package/dist/components/progress/snice-progress.d.ts +2 -7
  90. package/dist/components/progress/snice-progress.js +41 -98
  91. package/dist/components/progress/snice-progress.js.map +1 -1
  92. package/dist/components/radio/snice-radio.d.ts +4 -4
  93. package/dist/components/radio/snice-radio.js +52 -44
  94. package/dist/components/radio/snice-radio.js.map +1 -1
  95. package/dist/components/select/snice-option.d.ts +2 -1
  96. package/dist/components/select/snice-option.js +12 -5
  97. package/dist/components/select/snice-option.js.map +1 -1
  98. package/dist/components/select/snice-select.d.ts +9 -21
  99. package/dist/components/select/snice-select.js +98 -170
  100. package/dist/components/select/snice-select.js.map +1 -1
  101. package/dist/components/skeleton/snice-skeleton.d.ts +2 -6
  102. package/dist/components/skeleton/snice-skeleton.js +18 -49
  103. package/dist/components/skeleton/snice-skeleton.js.map +1 -1
  104. package/dist/components/snice-cell-BLFVdxPp.js +4 -0
  105. package/dist/components/snice-cell-BLFVdxPp.js.map +1 -0
  106. package/dist/components/switch/snice-switch.d.ts +2 -2
  107. package/dist/components/switch/snice-switch.js +38 -26
  108. package/dist/components/switch/snice-switch.js.map +1 -1
  109. package/dist/components/table/snice-cell-actions.d.ts +24 -0
  110. package/dist/components/table/snice-cell-actions.js +149 -0
  111. package/dist/components/table/snice-cell-actions.js.map +1 -0
  112. package/dist/components/table/snice-cell-boolean.d.ts +2 -2
  113. package/dist/components/table/snice-cell-boolean.js +13 -7
  114. package/dist/components/table/snice-cell-boolean.js.map +1 -1
  115. package/dist/components/table/snice-cell-color.d.ts +18 -0
  116. package/dist/components/table/snice-cell-color.js +149 -0
  117. package/dist/components/table/snice-cell-color.js.map +1 -0
  118. package/dist/components/table/snice-cell-currency.d.ts +24 -0
  119. package/dist/components/table/snice-cell-currency.js +235 -0
  120. package/dist/components/table/snice-cell-currency.js.map +1 -0
  121. package/dist/components/table/snice-cell-date.d.ts +2 -2
  122. package/dist/components/table/snice-cell-date.js +14 -8
  123. package/dist/components/table/snice-cell-date.js.map +1 -1
  124. package/dist/components/table/snice-cell-duration.d.ts +2 -2
  125. package/dist/components/table/snice-cell-duration.js +12 -6
  126. package/dist/components/table/snice-cell-duration.js.map +1 -1
  127. package/dist/components/table/snice-cell-email.d.ts +15 -0
  128. package/dist/components/table/snice-cell-email.js +125 -0
  129. package/dist/components/table/snice-cell-email.js.map +1 -0
  130. package/dist/components/table/snice-cell-filesize.d.ts +2 -2
  131. package/dist/components/table/snice-cell-filesize.js +12 -6
  132. package/dist/components/table/snice-cell-filesize.js.map +1 -1
  133. package/dist/components/table/snice-cell-image.d.ts +20 -0
  134. package/dist/components/table/snice-cell-image.js +162 -0
  135. package/dist/components/table/snice-cell-image.js.map +1 -0
  136. package/dist/components/table/snice-cell-json.d.ts +20 -0
  137. package/dist/components/table/snice-cell-json.js +186 -0
  138. package/dist/components/table/snice-cell-json.js.map +1 -0
  139. package/dist/components/table/snice-cell-link.d.ts +17 -0
  140. package/dist/components/table/snice-cell-link.js +142 -0
  141. package/dist/components/table/snice-cell-link.js.map +1 -0
  142. package/dist/components/table/snice-cell-location.d.ts +19 -0
  143. package/dist/components/table/snice-cell-location.js +185 -0
  144. package/dist/components/table/snice-cell-location.js.map +1 -0
  145. package/dist/components/table/snice-cell-number.d.ts +2 -2
  146. package/dist/components/table/snice-cell-number.js +12 -6
  147. package/dist/components/table/snice-cell-number.js.map +1 -1
  148. package/dist/components/table/snice-cell-percentage.d.ts +22 -0
  149. package/dist/components/table/snice-cell-percentage.js +208 -0
  150. package/dist/components/table/snice-cell-percentage.js.map +1 -0
  151. package/dist/components/table/snice-cell-phone.d.ts +18 -0
  152. package/dist/components/table/snice-cell-phone.js +153 -0
  153. package/dist/components/table/snice-cell-phone.js.map +1 -0
  154. package/dist/components/table/snice-cell-progress.d.ts +2 -2
  155. package/dist/components/table/snice-cell-progress.js +12 -6
  156. package/dist/components/table/snice-cell-progress.js.map +1 -1
  157. package/dist/components/table/snice-cell-rating.d.ts +2 -2
  158. package/dist/components/table/snice-cell-rating.js +12 -6
  159. package/dist/components/table/snice-cell-rating.js.map +1 -1
  160. package/dist/components/table/snice-cell-sparkline.d.ts +2 -2
  161. package/dist/components/table/snice-cell-sparkline.js +13 -7
  162. package/dist/components/table/snice-cell-sparkline.js.map +1 -1
  163. package/dist/components/table/snice-cell-status.d.ts +17 -0
  164. package/dist/components/table/snice-cell-status.js +144 -0
  165. package/dist/components/table/snice-cell-status.js.map +1 -0
  166. package/dist/components/table/snice-cell-tag.d.ts +16 -0
  167. package/dist/components/table/snice-cell-tag.js +131 -0
  168. package/dist/components/table/snice-cell-tag.js.map +1 -0
  169. package/dist/components/table/snice-cell-text.d.ts +2 -2
  170. package/dist/components/table/snice-cell-text.js +14 -8
  171. package/dist/components/table/snice-cell-text.js.map +1 -1
  172. package/dist/components/table/snice-cell.d.ts +2 -2
  173. package/dist/components/table/snice-cell.js +12 -6
  174. package/dist/components/table/snice-cell.js.map +1 -1
  175. package/dist/components/table/snice-column.d.ts +1 -1
  176. package/dist/components/table/snice-column.js +6 -3
  177. package/dist/components/table/snice-column.js.map +1 -1
  178. package/dist/components/table/snice-header.d.ts +5 -5
  179. package/dist/components/table/snice-header.js +60 -50
  180. package/dist/components/table/snice-header.js.map +1 -1
  181. package/dist/components/table/snice-progress.d.ts +2 -2
  182. package/dist/components/table/snice-progress.js +18 -11
  183. package/dist/components/table/snice-progress.js.map +1 -1
  184. package/dist/components/table/snice-rating.d.ts +2 -2
  185. package/dist/components/table/snice-rating.js +15 -8
  186. package/dist/components/table/snice-rating.js.map +1 -1
  187. package/dist/components/table/snice-row.d.ts +17 -6
  188. package/dist/components/table/snice-row.js +95 -44
  189. package/dist/components/table/snice-row.js.map +1 -1
  190. package/dist/components/table/snice-table.d.ts +18 -10
  191. package/dist/components/table/snice-table.js +355 -173
  192. package/dist/components/table/snice-table.js.map +1 -1
  193. package/dist/components/table/snice-table.types.d.ts +101 -2
  194. package/dist/components/tabs/snice-tab-panel.d.ts +2 -2
  195. package/dist/components/tabs/snice-tab-panel.js +12 -6
  196. package/dist/components/tabs/snice-tab-panel.js.map +1 -1
  197. package/dist/components/tabs/snice-tab.d.ts +6 -5
  198. package/dist/components/tabs/snice-tab.js +36 -19
  199. package/dist/components/tabs/snice-tab.js.map +1 -1
  200. package/dist/components/tabs/snice-tabs.d.ts +5 -5
  201. package/dist/components/tabs/snice-tabs.js +38 -28
  202. package/dist/components/tabs/snice-tabs.js.map +1 -1
  203. package/dist/components/toast/snice-toast-container.d.ts +7 -7
  204. package/dist/components/toast/snice-toast-container.js +19 -12
  205. package/dist/components/toast/snice-toast-container.js.map +1 -1
  206. package/dist/components/toast/snice-toast.d.ts +3 -15
  207. package/dist/components/toast/snice-toast.js +49 -108
  208. package/dist/components/toast/snice-toast.js.map +1 -1
  209. package/dist/components/tooltip/snice-tooltip.d.ts +2 -2
  210. package/dist/components/tooltip/snice-tooltip.js +14 -7
  211. package/dist/components/tooltip/snice-tooltip.js.map +1 -1
  212. package/dist/context.d.ts +44 -0
  213. package/dist/element-ready.d.ts +40 -0
  214. package/dist/{types/element.d.ts → element.d.ts} +2 -8
  215. package/dist/{types/events.d.ts → events.d.ts} +0 -4
  216. package/dist/index.cjs +2589 -605
  217. package/dist/index.cjs.map +1 -1
  218. package/dist/index.d.ts +21 -0
  219. package/dist/index.esm.js +2568 -604
  220. package/dist/index.esm.js.map +1 -1
  221. package/dist/index.iife.js +2589 -605
  222. package/dist/index.iife.js.map +1 -1
  223. package/dist/method-decorators.d.ts +121 -0
  224. package/dist/on.d.ts +59 -0
  225. package/dist/parts.d.ts +159 -0
  226. package/dist/render-debug.d.ts +27 -0
  227. package/dist/render-tracker.d.ts +14 -0
  228. package/dist/render.d.ts +96 -0
  229. package/dist/symbols.cjs +163 -0
  230. package/dist/symbols.cjs.map +1 -1
  231. package/dist/{types/symbols.d.ts → symbols.d.ts} +22 -0
  232. package/dist/symbols.esm.js +27 -3
  233. package/dist/symbols.esm.js.map +1 -1
  234. package/dist/template.d.ts +100 -0
  235. package/dist/transitions.cjs +219 -0
  236. package/dist/transitions.esm.js +2 -2
  237. package/dist/types/context.d.ts +48 -0
  238. package/dist/types/element-options.d.ts +26 -0
  239. package/dist/types/index.d.ts +25 -9
  240. package/dist/types/nav-context.d.ts +19 -0
  241. package/dist/types/{types/on-options.d.ts → on-options.d.ts} +2 -0
  242. package/dist/types/{types/placard.d.ts → placard.d.ts} +0 -1
  243. package/docs/ai/README.md +17 -0
  244. package/docs/ai/api.md +175 -0
  245. package/docs/ai/architecture.md +160 -0
  246. package/docs/ai/components/accordion.md +174 -0
  247. package/docs/ai/components/alert.md +77 -0
  248. package/docs/ai/components/avatar.md +61 -0
  249. package/docs/ai/components/badge.md +69 -0
  250. package/docs/ai/components/breadcrumbs.md +74 -0
  251. package/docs/ai/components/button.md +75 -0
  252. package/docs/ai/components/card.md +61 -0
  253. package/docs/ai/components/checkbox.md +74 -0
  254. package/docs/ai/components/chip.md +73 -0
  255. package/docs/ai/components/date-picker.md +75 -0
  256. package/docs/ai/components/divider.md +66 -0
  257. package/docs/ai/components/drawer.md +80 -0
  258. package/docs/ai/components/input.md +111 -0
  259. package/docs/ai/components/login.md +109 -0
  260. package/docs/ai/components/modal.md +67 -0
  261. package/docs/ai/components/nav.md +76 -0
  262. package/docs/ai/components/pagination.md +55 -0
  263. package/docs/ai/components/progress.md +72 -0
  264. package/docs/ai/components/radio.md +79 -0
  265. package/docs/ai/components/select.md +92 -0
  266. package/docs/ai/components/skeleton.md +57 -0
  267. package/docs/ai/components/switch.md +53 -0
  268. package/docs/ai/components/table.md +227 -0
  269. package/docs/ai/components/tabs.md +83 -0
  270. package/docs/ai/components/toast.md +140 -0
  271. package/docs/ai/components/tooltip.md +146 -0
  272. package/docs/ai/patterns.md +244 -0
  273. package/docs/components/accordion.md +558 -0
  274. package/docs/components/drawer.md +602 -0
  275. package/docs/components/modal.md +558 -0
  276. package/docs/components/nav.md +239 -0
  277. package/docs/components/pagination.md +289 -0
  278. package/docs/components/select.md +599 -0
  279. package/docs/components/switch.md +354 -0
  280. package/docs/components/tabs.md +546 -0
  281. package/docs/components/toast.md +506 -0
  282. package/docs/components/tooltip.md +523 -0
  283. package/docs/controllers.md +744 -0
  284. package/docs/elements.md +855 -0
  285. package/docs/events.md +807 -0
  286. package/docs/migration-v2-to-v3.md +569 -0
  287. package/docs/observe.md +588 -0
  288. package/docs/placards.md +401 -0
  289. package/docs/request-response.md +852 -0
  290. package/docs/routing.md +1186 -0
  291. package/package.json +10 -11
  292. package/dist/components/snice-cell-C9N6yGxQ.js +0 -4
  293. package/dist/components/snice-cell-C9N6yGxQ.js.map +0 -1
  294. package/dist/types/types/index.d.ts +0 -23
  295. /package/dist/{types/controller.d.ts → controller.d.ts} +0 -0
  296. /package/dist/{types/global.d.ts → global.d.ts} +0 -0
  297. /package/dist/{types/observe.d.ts → observe.d.ts} +0 -0
  298. /package/dist/{types/request-response.d.ts → request-response.d.ts} +0 -0
  299. /package/dist/{types/router.d.ts → router.d.ts} +0 -0
  300. /package/dist/{types/testing.d.ts → testing.d.ts} +0 -0
  301. /package/dist/{types/transitions.d.ts → transitions.d.ts} +0 -0
  302. /package/dist/types/{types/adopted-options.d.ts → adopted-options.d.ts} +0 -0
  303. /package/dist/types/{types/app-context.d.ts → app-context.d.ts} +0 -0
  304. /package/dist/types/{types/dispatch-options.d.ts → dispatch-options.d.ts} +0 -0
  305. /package/dist/types/{types/guard.d.ts → guard.d.ts} +0 -0
  306. /package/dist/types/{types/i-controller.d.ts → i-controller.d.ts} +0 -0
  307. /package/dist/types/{types/moved-options.d.ts → moved-options.d.ts} +0 -0
  308. /package/dist/types/{types/observe-options.d.ts → observe-options.d.ts} +0 -0
  309. /package/dist/types/{types/page-options.d.ts → page-options.d.ts} +0 -0
  310. /package/dist/types/{types/part-options.d.ts → part-options.d.ts} +0 -0
  311. /package/dist/types/{types/property-converter.d.ts → property-converter.d.ts} +0 -0
  312. /package/dist/types/{types/property-options.d.ts → property-options.d.ts} +0 -0
  313. /package/dist/types/{types/query-options.d.ts → query-options.d.ts} +0 -0
  314. /package/dist/types/{types/request-options.d.ts → request-options.d.ts} +0 -0
  315. /package/dist/types/{types/respond-options.d.ts → respond-options.d.ts} +0 -0
  316. /package/dist/types/{types/route-params.d.ts → route-params.d.ts} +0 -0
  317. /package/dist/types/{types/router-instance.d.ts → router-instance.d.ts} +0 -0
  318. /package/dist/types/{types/router-options.d.ts → router-options.d.ts} +0 -0
  319. /package/dist/types/{types/simple-array.d.ts → simple-array.d.ts} +0 -0
  320. /package/dist/types/{types/snice-element.d.ts → snice-element.d.ts} +0 -0
  321. /package/dist/types/{types/snice-global.d.ts → snice-global.d.ts} +0 -0
  322. /package/dist/types/{types/transition.d.ts → transition.d.ts} +0 -0
  323. /package/dist/{types/utils.d.ts → utils.d.ts} +0 -0
@@ -0,0 +1,569 @@
1
+ # Migration Guide: Snice v2.x → v3.0.0
2
+
3
+ ## Breaking Changes Summary
4
+
5
+ Snice v3.0.0 introduces a complete rewrite of the rendering system with **differential rendering** and **tagged templates**, inspired by lit-html but with a custom implementation. This is a **major breaking change** with no backward compatibility.
6
+
7
+ ### Removed APIs
8
+ - ❌ `html()` method
9
+ - ❌ `css()` method
10
+ - ❌ `@part` decorator
11
+
12
+ ### Event Handling with @on
13
+ - ✅ `@on` decorator available
14
+ - Works in both elements AND controllers
15
+ - Supports event delegation with selectors
16
+ - Supports keyboard modifiers (`@on('keydown:Enter')`)
17
+ - Supports debounce and throttle options
18
+
19
+ ### New APIs
20
+ - ✅ `html``template literals
21
+ - ✅ `css``template literals
22
+ - ✅ `@render()` decorator
23
+ - ✅ `@styles()` decorator
24
+ - ✅ Template event syntax (`@click`, `@input`, `@keydown:Enter`)
25
+ - Now supports keyboard modifiers with both `.` and `:` notation
26
+ - ✅ Template property binding (`.value`)
27
+ - ✅ Template boolean attributes (`?disabled`)
28
+ - ✅ Auto-rendering on property changes
29
+ - ✅ Differential rendering (only updates changed parts)
30
+
31
+ ---
32
+
33
+ ## Migration Steps
34
+
35
+ ### Step 1: Update Rendering Methods
36
+
37
+ **Before (v2.x):**
38
+ ```typescript
39
+ @element('my-counter')
40
+ class Counter extends HTMLElement {
41
+ @property({ type: Number })
42
+ count = 0;
43
+
44
+ html() {
45
+ return `
46
+ <div class="counter">
47
+ <span>${this.count}</span>
48
+ <button>Increment</button>
49
+ </div>
50
+ `;
51
+ }
52
+
53
+ css() {
54
+ return `
55
+ .counter {
56
+ padding: 1rem;
57
+ background: #f0f0f0;
58
+ }
59
+ `;
60
+ }
61
+ }
62
+ ```
63
+
64
+ **After (v3.0.0):**
65
+ ```typescript
66
+ import { element, property, render, styles, html, css } from 'snice';
67
+
68
+ @element('my-counter')
69
+ class Counter extends HTMLElement {
70
+ @property({ type: Number })
71
+ count = 0;
72
+
73
+ @render()
74
+ renderContent() {
75
+ return html`
76
+ <div class="counter">
77
+ <span>${this.count}</span>
78
+ <button>Increment</button>
79
+ </div>
80
+ `;
81
+ }
82
+
83
+ @styles()
84
+ componentStyles() {
85
+ return css`
86
+ .counter {
87
+ padding: 1rem;
88
+ background: #f0f0f0;
89
+ }
90
+ `;
91
+ }
92
+ }
93
+ ```
94
+
95
+ **Key Changes:**
96
+ - Import `html` and `css` tagged template functions
97
+ - Import `@render` and `@styles` decorators
98
+ - Replace `html()` with `@render()` method returning `html\`...\``
99
+ - Replace `css()` with `@styles()` method returning `css\`...\``
100
+
101
+ ---
102
+
103
+ ### Step 2: Event Handlers - Two Options!
104
+
105
+ **v3.0.0 gives you TWO ways to handle events:**
106
+
107
+ #### Option A: Template Event Syntax (Recommended for simple cases)
108
+
109
+ **Before (v2.x):**
110
+ ```typescript
111
+ @element('my-button')
112
+ class MyButton extends HTMLElement {
113
+ html() {
114
+ return `<button>Click me</button>`;
115
+ }
116
+
117
+ @on('click', 'button')
118
+ handleClick(event: Event) {
119
+ console.log('Clicked!', event);
120
+ }
121
+ }
122
+ ```
123
+
124
+ **After (v3.0.0):**
125
+ ```typescript
126
+ import { element, render, html } from 'snice';
127
+
128
+ @element('my-button')
129
+ class MyButton extends HTMLElement {
130
+ @render()
131
+ renderContent() {
132
+ return html`
133
+ <button @click=${this.handleClick}>Click me</button>
134
+ <input @keydown:Enter=${this.handleEnter} />
135
+ `;
136
+ }
137
+
138
+ handleClick(event: Event) {
139
+ console.log('Clicked!', event);
140
+ }
141
+
142
+ handleEnter(event: KeyboardEvent) {
143
+ console.log('Enter pressed!');
144
+ }
145
+ }
146
+ ```
147
+
148
+ #### Option B: `@on` Decorator
149
+
150
+ **The `@on` decorator works in both elements and controllers!**
151
+
152
+ ```typescript
153
+ import { element, render, html, on } from 'snice';
154
+
155
+ @element('my-button')
156
+ class MyButton extends HTMLElement {
157
+ @render()
158
+ renderContent() {
159
+ return html`
160
+ <button>Click me</button>
161
+ <input type="text" placeholder="Press Enter..." />
162
+ `;
163
+ }
164
+
165
+ // Event delegation with selectors
166
+ @on('click', 'button')
167
+ handleClick(event: Event) {
168
+ console.log('Button clicked!', event);
169
+ }
170
+
171
+ // Keyboard modifiers
172
+ @on('keydown:Enter', 'input')
173
+ handleEnter(event: KeyboardEvent) {
174
+ console.log('Enter pressed in input!');
175
+ }
176
+
177
+ // Debounce support
178
+ @on('input', 'input', { debounce: 300 })
179
+ handleInput(event: Event) {
180
+ console.log('Input value:', (event.target as HTMLInputElement).value);
181
+ }
182
+ }
183
+ ```
184
+
185
+ **Key Features:**
186
+ - ✅ Event delegation with CSS selectors
187
+ - ✅ Keyboard modifiers (`keydown:Enter`, `keydown:ctrl+s`)
188
+ - ✅ Debounce and throttle options
189
+ - ✅ preventDefault and stopPropagation options
190
+ - ✅ Works in both elements AND controllers
191
+
192
+ ---
193
+
194
+ ### Step 3: Automatic Re-rendering
195
+
196
+ **Before (v2.x):**
197
+ ```typescript
198
+ @element('user-profile')
199
+ class UserProfile extends HTMLElement {
200
+ @property()
201
+ name = '';
202
+
203
+ html() {
204
+ return `<h1>${this.name}</h1>`;
205
+ }
206
+
207
+ @on('click', 'button')
208
+ updateName() {
209
+ this.name = 'New Name';
210
+ // Manual re-render required!
211
+ this.shadowRoot!.innerHTML = this.html();
212
+ }
213
+ }
214
+ ```
215
+
216
+ **After (v3.0.0):**
217
+ ```typescript
218
+ import { element, property, render, html } from 'snice';
219
+
220
+ @element('user-profile')
221
+ class UserProfile extends HTMLElement {
222
+ @property()
223
+ name = '';
224
+
225
+ @render()
226
+ renderContent() {
227
+ return html`
228
+ <h1>${this.name}</h1>
229
+ <button @click=${this.updateName}>Update</button>
230
+ `;
231
+ }
232
+
233
+ updateName() {
234
+ this.name = 'New Name';
235
+ // Auto re-renders! No manual render needed!
236
+ }
237
+ }
238
+ ```
239
+
240
+ **Key Changes:**
241
+ - **Automatic re-rendering** when properties change
242
+ - **Differential rendering** - only updates changed parts
243
+ - **No manual `innerHTML` manipulation** needed
244
+
245
+ ---
246
+
247
+ ### Step 4: Replace @part with Differential Rendering
248
+
249
+ **Before (v2.x):**
250
+ ```typescript
251
+ @element('todo-list')
252
+ class TodoList extends HTMLElement {
253
+ todos = ['Task 1', 'Task 2'];
254
+
255
+ html() {
256
+ return `
257
+ <div>
258
+ <ul part="todos"></ul>
259
+ <button>Add</button>
260
+ </div>
261
+ `;
262
+ }
263
+
264
+ @part('todos')
265
+ renderTodos() {
266
+ return this.todos.map(t => `<li>${t}</li>`).join('');
267
+ }
268
+
269
+ @on('click', 'button')
270
+ addTodo() {
271
+ this.todos.push('New Task');
272
+ this.renderTodos(); // Manual partial update
273
+ }
274
+ }
275
+ ```
276
+
277
+ **After (v3.0.0):**
278
+ ```typescript
279
+ import { element, render, html } from 'snice';
280
+
281
+ @element('todo-list')
282
+ class TodoList extends HTMLElement {
283
+ todos = ['Task 1', 'Task 2'];
284
+
285
+ @render()
286
+ renderContent() {
287
+ return html`
288
+ <div>
289
+ <ul>
290
+ ${this.todos.map(t => html`<li>${t}</li>`)}
291
+ </ul>
292
+ <button @click=${this.addTodo}>Add</button>
293
+ </div>
294
+ `;
295
+ }
296
+
297
+ addTodo() {
298
+ this.todos = [...this.todos, 'New Task'];
299
+ // Differential rendering automatically updates only the new <li>!
300
+ }
301
+ }
302
+ ```
303
+
304
+ **Key Changes:**
305
+ - **Remove `@part` entirely**
306
+ - Use **nested templates** with `.map()`
307
+ - **Differential rendering handles partial updates automatically**
308
+ - Must **reassign arrays** to trigger render: `this.todos = [...]`
309
+
310
+ ---
311
+
312
+ ### Step 5: Property and Boolean Attribute Binding
313
+
314
+ **New in v3.0.0:**
315
+
316
+ ```typescript
317
+ import { element, property, render, html } from 'snice';
318
+
319
+ @element('custom-input')
320
+ class CustomInput extends HTMLElement {
321
+ @property()
322
+ value = '';
323
+
324
+ @property({ type: Boolean })
325
+ disabled = false;
326
+
327
+ @render()
328
+ renderContent() {
329
+ return html`
330
+ <input
331
+ .value=${this.value}
332
+ ?disabled=${this.disabled}
333
+ @input=${this.handleInput}
334
+ />
335
+ `;
336
+ }
337
+
338
+ handleInput(e: Event) {
339
+ this.value = (e.target as HTMLInputElement).value;
340
+ }
341
+ }
342
+ ```
343
+
344
+ **Template Syntax:**
345
+ - `.value=${x}` - Sets **property**, not attribute (for form inputs)
346
+ - `?disabled=${bool}` - **Boolean attribute** (added if true, removed if false)
347
+ - `class=${x}` - Sets **attribute** (regular binding)
348
+
349
+ ---
350
+
351
+ ## Render Options
352
+
353
+ ### Debouncing
354
+
355
+ Debounce renders for performance (useful for search inputs):
356
+
357
+ ```typescript
358
+ @render({ debounce: 300 })
359
+ renderContent() {
360
+ return html`<input .value=${this.searchTerm} @input=${this.onSearch} />`;
361
+ }
362
+
363
+ onSearch(e: Event) {
364
+ this.searchTerm = (e.target as HTMLInputElement).value;
365
+ // Renders only after 300ms of no changes
366
+ }
367
+ ```
368
+
369
+ ### Throttling
370
+
371
+ Limit render frequency:
372
+
373
+ ```typescript
374
+ @render({ throttle: 100 })
375
+ renderContent() {
376
+ return html`<div>Scroll: ${this.scrollY}</div>`;
377
+ }
378
+ ```
379
+
380
+ ### One-time Rendering
381
+
382
+ Disable auto-rendering (manual control):
383
+
384
+ ```typescript
385
+ @render({ once: true })
386
+ renderContent() {
387
+ return html`<div>Static content</div>`;
388
+ }
389
+
390
+ updateManually() {
391
+ this.someData = 'new value';
392
+ this.renderContent(); // Explicit call to re-render
393
+ }
394
+ ```
395
+
396
+ ### Synchronous Rendering
397
+
398
+ Skip microtask batching (immediate updates):
399
+
400
+ ```typescript
401
+ @render({ sync: true })
402
+ renderContent() {
403
+ return html`<div>${this.count}</div>`;
404
+ }
405
+ ```
406
+
407
+ ---
408
+
409
+ ## Common Patterns
410
+
411
+ ### Conditional Rendering
412
+
413
+ ```typescript
414
+ @render()
415
+ renderContent() {
416
+ return html`
417
+ <div>
418
+ ${this.isLoggedIn
419
+ ? html`<span>Welcome, ${this.user.name}!</span>`
420
+ : html`<a href="/login">Login</a>`
421
+ }
422
+ </div>
423
+ `;
424
+ }
425
+ ```
426
+
427
+ ### Lists with Keys
428
+
429
+ For optimal performance, use unique keys when rendering lists:
430
+
431
+ ```typescript
432
+ @render()
433
+ renderContent() {
434
+ return html`
435
+ <ul>
436
+ ${this.items.map(item => html`
437
+ <li key=${item.id}>
438
+ ${item.name}
439
+ <button @click=${() => this.remove(item.id)}>Remove</button>
440
+ </li>
441
+ `)}
442
+ </ul>
443
+ `;
444
+ }
445
+ ```
446
+
447
+ ### Nested Components
448
+
449
+ ```typescript
450
+ @render()
451
+ renderContent() {
452
+ return html`
453
+ <div>
454
+ <user-card userId=${this.userId}></user-card>
455
+ <comment-list postId=${this.postId}></comment-list>
456
+ </div>
457
+ `;
458
+ }
459
+ ```
460
+
461
+ ---
462
+
463
+ ## TypeScript Support
464
+
465
+ Update your imports:
466
+
467
+ ```typescript
468
+ import {
469
+ element,
470
+ property,
471
+ render,
472
+ styles,
473
+ html,
474
+ css,
475
+ type TemplateResult,
476
+ type CSSResult,
477
+ type RenderOptions
478
+ } from 'snice';
479
+ ```
480
+
481
+ Type your render methods:
482
+
483
+ ```typescript
484
+ @render()
485
+ renderContent(): TemplateResult {
486
+ return html`<div>Content</div>`;
487
+ }
488
+
489
+ @styles()
490
+ componentStyles(): CSSResult {
491
+ return css`:host { display: block; }`;
492
+ }
493
+ ```
494
+
495
+ ---
496
+
497
+ ## Testing
498
+
499
+ Update your tests to work with the new rendering system:
500
+
501
+ **Before (v2.x):**
502
+ ```typescript
503
+ const el = document.createElement('my-element') as MyElement;
504
+ document.body.appendChild(el);
505
+ expect(el.shadowRoot!.innerHTML).toContain('expected content');
506
+ ```
507
+
508
+ **After (v3.0.0):**
509
+ ```typescript
510
+ const el = document.createElement('my-element') as MyElement;
511
+ document.body.appendChild(el);
512
+
513
+ // Wait for initial render
514
+ await el.ready;
515
+
516
+ // Check rendered content
517
+ expect(el.shadowRoot!.textContent).toContain('expected content');
518
+
519
+ // Trigger property change
520
+ el.someProperty = 'new value';
521
+
522
+ // Wait for next microtask (auto-render)
523
+ await new Promise(resolve => queueMicrotask(resolve));
524
+
525
+ // Verify differential update
526
+ expect(el.shadowRoot!.textContent).toContain('new value');
527
+ ```
528
+
529
+ ---
530
+
531
+ ## Performance Benefits
532
+
533
+ ### v2.x (Manual)
534
+ - ❌ Full `innerHTML` replacement on every update
535
+ - ❌ All event listeners destroyed and recreated
536
+ - ❌ Manual `@part` updates required
537
+ - ❌ No batching of updates
538
+
539
+ ### v3.0.0 (Differential)
540
+ - ✅ **Only changed parts updated**
541
+ - ✅ Event listeners preserved and reused
542
+ - ✅ **Automatic batching** (microtask queue)
543
+ - ✅ **Debounce/throttle** built-in
544
+ - ✅ **10-100x faster** for large components
545
+
546
+ ---
547
+
548
+ ## Need Help?
549
+
550
+ - Check the updated [README.md](./README.md) for full examples
551
+ - See [docs/](./docs/) for detailed API documentation
552
+ - Open an issue on GitLab for migration questions
553
+
554
+ ---
555
+
556
+ ## Quick Reference
557
+
558
+ | v2.x | v3.0.0 |
559
+ |------|--------|
560
+ | `html()` method | `@render()` with `html\`\`` |
561
+ | `css()` method | `@styles()` with `css\`\`` |
562
+ | `@on('click', 'button')` | **Still works!** OR use `@click=${handler}` in template |
563
+ | `@on('keydown:Enter')` | **Still works!** OR use `@keydown:Enter=${handler}` in template |
564
+ | `@on('input', { debounce: 300 })` | **Still works!** (enhanced with throttle too) |
565
+ | `@part('name')` | Use `@render()` (differential rendering) |
566
+ | Manual `innerHTML` update | Automatic on property change |
567
+ | `this.shadowRoot!.innerHTML = ...` | Just update property: `this.count++` |
568
+
569
+ **Automatic differential rendering with powerful event handling!** 🚀