solid-tom-ui 1.0.8 → 1.0.11

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 (502) hide show
  1. package/dist/README.md +246 -0
  2. package/dist/components/avatar/index.d.ts +3 -0
  3. package/{components → dist/components}/avatar/index.d.ts.map +1 -1
  4. package/dist/components/button/index.d.ts +3 -0
  5. package/{components → dist/components}/button/index.d.ts.map +1 -1
  6. package/dist/components/collapse/index.d.ts +3 -0
  7. package/{components → dist/components}/collapse/index.d.ts.map +1 -1
  8. package/dist/components/float-button/index.d.ts +3 -0
  9. package/{components → dist/components}/float-button/index.d.ts.map +1 -1
  10. package/dist/components/input/index.d.ts +3 -0
  11. package/dist/components/input/index.d.ts.map +1 -0
  12. package/dist/components/menu/index.d.ts +4 -0
  13. package/{components → dist/components}/menu/index.d.ts.map +1 -1
  14. package/{components → dist/components}/menu/menu.types.d.ts +9 -10
  15. package/{components → dist/components}/menu/menu.types.d.ts.map +1 -1
  16. package/dist/components/rating/index.d.ts +3 -0
  17. package/{components → dist/components}/rating/index.d.ts.map +1 -1
  18. package/dist/components/slider/index.d.ts +3 -0
  19. package/{components → dist/components}/slider/index.d.ts.map +1 -1
  20. package/{components → dist/components}/tour/tour.d.ts.map +1 -1
  21. package/{components → dist/components}/tour/tour.js +1 -1
  22. package/{components → dist/components}/tour/tour.js.map +1 -1
  23. package/{components → dist/components}/z-index/z-index.types.js.map +1 -1
  24. package/dist/package.json +45 -0
  25. package/dist/skill/avatar.skill.md.txt +255 -0
  26. package/dist/skill/badge.skill.md.txt +223 -0
  27. package/dist/skill/blank.skill.md.txt +0 -0
  28. package/dist/skill/breadcrumb.skill.md.txt +177 -0
  29. package/dist/skill/button.skill.md.txt +198 -0
  30. package/dist/skill/carousel.skill.md.txt +406 -0
  31. package/dist/skill/chat-bubble.skill.md.txt +342 -0
  32. package/dist/skill/checkbox.skill.md.txt +326 -0
  33. package/dist/skill/code-preview.skill.md.txt +240 -0
  34. package/dist/skill/collapse.skill.md.txt +329 -0
  35. package/dist/skill/context-menu.skill.md.txt +233 -0
  36. package/dist/skill/diff.skill.md.txt +244 -0
  37. package/dist/skill/divider.skill.md.txt +151 -0
  38. package/dist/skill/doc.skill.md.txt +191 -0
  39. package/dist/skill/drawer.skill.md.txt +157 -0
  40. package/dist/skill/dropdown.skill.md.txt +198 -0
  41. package/dist/skill/float-button.skill.md.txt +315 -0
  42. package/dist/skill/hover-3d-image.skill.md.txt +120 -0
  43. package/dist/skill/iframe.skill.md.txt +114 -0
  44. package/dist/skill/image-preview.skill.md.txt +162 -0
  45. package/dist/skill/indicator.skill.md.txt +60 -0
  46. package/dist/skill/input.skill.md.txt +489 -0
  47. package/dist/skill/loading.skill.md.txt +127 -0
  48. package/dist/skill/mansory.skill.md.txt +0 -0
  49. package/dist/skill/menu.skill.md.txt +476 -0
  50. package/dist/skill/modal.skill.md.txt +359 -0
  51. package/dist/skill/pagination.skill.md.txt +405 -0
  52. package/dist/skill/progress-bar.skill.md.txt +207 -0
  53. package/dist/skill/qr-code.skill.md.txt +136 -0
  54. package/dist/skill/rating.skill.md.txt +167 -0
  55. package/dist/skill/select-zone.skill.md.txt +93 -0
  56. package/dist/skill/select.skill.md.txt +663 -0
  57. package/dist/skill/skeleton.skill.md.txt +192 -0
  58. package/dist/skill/slider.skill.md.txt +404 -0
  59. package/dist/skill/splitter.skill.md.txt +411 -0
  60. package/dist/skill/steps.skill.md.txt +264 -0
  61. package/dist/skill/swap.skill.md.txt +139 -0
  62. package/dist/skill/switch.skill.md.txt +191 -0
  63. package/dist/skill/tab.skill.md.txt +484 -0
  64. package/dist/skill/table.example.header.md.txt +667 -0
  65. package/dist/skill/table.skill.md.txt +1407 -0
  66. package/dist/skill/text-rotate.skill.md.txt +186 -0
  67. package/dist/skill/timeline.skill.md.txt +247 -0
  68. package/dist/skill/toast.skill.md.txt +531 -0
  69. package/dist/skill/tooltip.skill.md.txt +222 -0
  70. package/dist/skill/tour.skill.md.txt +156 -0
  71. package/dist/skill/upload.skill.md.txt +358 -0
  72. package/dist/skill/z-index.skill.md.txt +0 -0
  73. package/{solid-ui.css → dist/solid-ui.css} +2 -2
  74. package/package.json +97 -9
  75. package/components/avatar/index.d.ts +0 -2
  76. package/components/button/index.d.ts +0 -2
  77. package/components/collapse/index.d.ts +0 -2
  78. package/components/float-button/index.d.ts +0 -2
  79. package/components/input/index.d.ts +0 -2
  80. package/components/input/index.d.ts.map +0 -1
  81. package/components/menu/index.d.ts +0 -4
  82. package/components/rating/index.d.ts +0 -2
  83. package/components/slider/index.d.ts +0 -2
  84. package/macos.code-workspace +0 -8
  85. /package/{components → dist/components}/avatar/avatar.d.ts +0 -0
  86. /package/{components → dist/components}/avatar/avatar.d.ts.map +0 -0
  87. /package/{components → dist/components}/avatar/avatar.js +0 -0
  88. /package/{components → dist/components}/avatar/avatar.js.map +0 -0
  89. /package/{components → dist/components}/avatar/avatar.types.d.ts +0 -0
  90. /package/{components → dist/components}/avatar/avatar.types.d.ts.map +0 -0
  91. /package/{components → dist/components}/badge/badge.d.ts +0 -0
  92. /package/{components → dist/components}/badge/badge.d.ts.map +0 -0
  93. /package/{components → dist/components}/badge/badge.js +0 -0
  94. /package/{components → dist/components}/badge/badge.js.map +0 -0
  95. /package/{components → dist/components}/badge/badge.types.d.ts +0 -0
  96. /package/{components → dist/components}/badge/badge.types.d.ts.map +0 -0
  97. /package/{components → dist/components}/badge/index.d.ts +0 -0
  98. /package/{components → dist/components}/badge/index.d.ts.map +0 -0
  99. /package/{components → dist/components}/blank/blank.d.ts +0 -0
  100. /package/{components → dist/components}/blank/blank.d.ts.map +0 -0
  101. /package/{components → dist/components}/blank/index.d.ts +0 -0
  102. /package/{components → dist/components}/blank/index.d.ts.map +0 -0
  103. /package/{components → dist/components}/breadcrumb/breadcrumb.d.ts +0 -0
  104. /package/{components → dist/components}/breadcrumb/breadcrumb.d.ts.map +0 -0
  105. /package/{components → dist/components}/breadcrumb/breadcrumb.js +0 -0
  106. /package/{components → dist/components}/breadcrumb/breadcrumb.js.map +0 -0
  107. /package/{components → dist/components}/breadcrumb/index.d.ts +0 -0
  108. /package/{components → dist/components}/breadcrumb/index.d.ts.map +0 -0
  109. /package/{components → dist/components}/button/button.d.ts +0 -0
  110. /package/{components → dist/components}/button/button.d.ts.map +0 -0
  111. /package/{components → dist/components}/button/button.js +0 -0
  112. /package/{components → dist/components}/button/button.js.map +0 -0
  113. /package/{components → dist/components}/button/button.types.d.ts +0 -0
  114. /package/{components → dist/components}/button/button.types.d.ts.map +0 -0
  115. /package/{components → dist/components}/carousel/carousel.d.ts +0 -0
  116. /package/{components → dist/components}/carousel/carousel.d.ts.map +0 -0
  117. /package/{components → dist/components}/carousel/carousel.js +0 -0
  118. /package/{components → dist/components}/carousel/carousel.js.map +0 -0
  119. /package/{components → dist/components}/carousel/carousel.types.d.ts +0 -0
  120. /package/{components → dist/components}/carousel/carousel.types.d.ts.map +0 -0
  121. /package/{components → dist/components}/carousel/index.d.ts +0 -0
  122. /package/{components → dist/components}/carousel/index.d.ts.map +0 -0
  123. /package/{components → dist/components}/chat-bubble/chatBubble.d.ts +0 -0
  124. /package/{components → dist/components}/chat-bubble/chatBubble.d.ts.map +0 -0
  125. /package/{components → dist/components}/chat-bubble/chatBubble.js +0 -0
  126. /package/{components → dist/components}/chat-bubble/chatBubble.js.map +0 -0
  127. /package/{components → dist/components}/chat-bubble/chatBubble.type.d.ts +0 -0
  128. /package/{components → dist/components}/chat-bubble/chatBubble.type.d.ts.map +0 -0
  129. /package/{components → dist/components}/chat-bubble/index.d.ts +0 -0
  130. /package/{components → dist/components}/chat-bubble/index.d.ts.map +0 -0
  131. /package/{components → dist/components}/checkbox/checkbox.d.ts +0 -0
  132. /package/{components → dist/components}/checkbox/checkbox.d.ts.map +0 -0
  133. /package/{components → dist/components}/checkbox/checkbox.js +0 -0
  134. /package/{components → dist/components}/checkbox/checkbox.js.map +0 -0
  135. /package/{components → dist/components}/checkbox/index.d.ts +0 -0
  136. /package/{components → dist/components}/checkbox/index.d.ts.map +0 -0
  137. /package/{components → dist/components}/collapse/collapse.d.ts +0 -0
  138. /package/{components → dist/components}/collapse/collapse.d.ts.map +0 -0
  139. /package/{components → dist/components}/collapse/collapse.js +0 -0
  140. /package/{components → dist/components}/collapse/collapse.js.map +0 -0
  141. /package/{components → dist/components}/collapse/collapse.types.d.ts +0 -0
  142. /package/{components → dist/components}/collapse/collapse.types.d.ts.map +0 -0
  143. /package/{components → dist/components}/context-menu/context-menu.d.ts +0 -0
  144. /package/{components → dist/components}/context-menu/context-menu.d.ts.map +0 -0
  145. /package/{components → dist/components}/context-menu/context-menu.js +0 -0
  146. /package/{components → dist/components}/context-menu/context-menu.js.map +0 -0
  147. /package/{components → dist/components}/context-menu/context-menu.store.d.ts +0 -0
  148. /package/{components → dist/components}/context-menu/context-menu.store.d.ts.map +0 -0
  149. /package/{components → dist/components}/context-menu/context-menu.store.js +0 -0
  150. /package/{components → dist/components}/context-menu/context-menu.store.js.map +0 -0
  151. /package/{components → dist/components}/context-menu/context-menu.types.d.ts +0 -0
  152. /package/{components → dist/components}/context-menu/context-menu.types.d.ts.map +0 -0
  153. /package/{components → dist/components}/context-menu/index.d.ts +0 -0
  154. /package/{components → dist/components}/context-menu/index.d.ts.map +0 -0
  155. /package/{components → dist/components}/diff/diff.d.ts +0 -0
  156. /package/{components → dist/components}/diff/diff.d.ts.map +0 -0
  157. /package/{components → dist/components}/diff/diff.js +0 -0
  158. /package/{components → dist/components}/diff/diff.js.map +0 -0
  159. /package/{components → dist/components}/diff/index.d.ts +0 -0
  160. /package/{components → dist/components}/diff/index.d.ts.map +0 -0
  161. /package/{components → dist/components}/divider/divider.d.ts +0 -0
  162. /package/{components → dist/components}/divider/divider.d.ts.map +0 -0
  163. /package/{components → dist/components}/divider/divider.js +0 -0
  164. /package/{components → dist/components}/divider/divider.js.map +0 -0
  165. /package/{components → dist/components}/divider/divider.types.d.ts +0 -0
  166. /package/{components → dist/components}/divider/divider.types.d.ts.map +0 -0
  167. /package/{components → dist/components}/divider/index.d.ts +0 -0
  168. /package/{components → dist/components}/divider/index.d.ts.map +0 -0
  169. /package/{components → dist/components}/drawer/drawer.d.ts +0 -0
  170. /package/{components → dist/components}/drawer/drawer.d.ts.map +0 -0
  171. /package/{components → dist/components}/drawer/drawer.js +0 -0
  172. /package/{components → dist/components}/drawer/drawer.js.map +0 -0
  173. /package/{components → dist/components}/drawer/drawer.types.d.ts +0 -0
  174. /package/{components → dist/components}/drawer/drawer.types.d.ts.map +0 -0
  175. /package/{components → dist/components}/drawer/index.d.ts +0 -0
  176. /package/{components → dist/components}/drawer/index.d.ts.map +0 -0
  177. /package/{components → dist/components}/dropdown/dropdown.d.ts +0 -0
  178. /package/{components → dist/components}/dropdown/dropdown.d.ts.map +0 -0
  179. /package/{components → dist/components}/dropdown/dropdown.js +0 -0
  180. /package/{components → dist/components}/dropdown/dropdown.js.map +0 -0
  181. /package/{components → dist/components}/dropdown/dropdown.store.d.ts +0 -0
  182. /package/{components → dist/components}/dropdown/dropdown.store.d.ts.map +0 -0
  183. /package/{components → dist/components}/dropdown/dropdown.store.js +0 -0
  184. /package/{components → dist/components}/dropdown/dropdown.store.js.map +0 -0
  185. /package/{components → dist/components}/dropdown/dropdown.types.d.ts +0 -0
  186. /package/{components → dist/components}/dropdown/dropdown.types.d.ts.map +0 -0
  187. /package/{components → dist/components}/dropdown/index.d.ts +0 -0
  188. /package/{components → dist/components}/dropdown/index.d.ts.map +0 -0
  189. /package/{components → dist/components}/float-button/float-button.d.ts +0 -0
  190. /package/{components → dist/components}/float-button/float-button.d.ts.map +0 -0
  191. /package/{components → dist/components}/float-button/float-button.js +0 -0
  192. /package/{components → dist/components}/float-button/float-button.js.map +0 -0
  193. /package/{components → dist/components}/float-button/float-button.types.d.ts +0 -0
  194. /package/{components → dist/components}/float-button/float-button.types.d.ts.map +0 -0
  195. /package/{components → dist/components}/hover-3d-image/hover-3d-example.d.ts +0 -0
  196. /package/{components → dist/components}/hover-3d-image/hover-3d-example.d.ts.map +0 -0
  197. /package/{components → dist/components}/hover-3d-image/hover-3d-image.d.ts +0 -0
  198. /package/{components → dist/components}/hover-3d-image/hover-3d-image.d.ts.map +0 -0
  199. /package/{components → dist/components}/hover-3d-image/hover-3d-image.js +0 -0
  200. /package/{components → dist/components}/hover-3d-image/hover-3d-image.js.map +0 -0
  201. /package/{components → dist/components}/hover-3d-image/index.d.ts +0 -0
  202. /package/{components → dist/components}/hover-3d-image/index.d.ts.map +0 -0
  203. /package/{components → dist/components}/image-preview/image-preview.d.ts +0 -0
  204. /package/{components → dist/components}/image-preview/image-preview.d.ts.map +0 -0
  205. /package/{components → dist/components}/image-preview/image-preview.js +0 -0
  206. /package/{components → dist/components}/image-preview/image-preview.js.map +0 -0
  207. /package/{components → dist/components}/image-preview/index.d.ts +0 -0
  208. /package/{components → dist/components}/image-preview/index.d.ts.map +0 -0
  209. /package/{components → dist/components}/indicator/index.d.ts +0 -0
  210. /package/{components → dist/components}/indicator/index.d.ts.map +0 -0
  211. /package/{components → dist/components}/indicator/indicator.d.ts +0 -0
  212. /package/{components → dist/components}/indicator/indicator.d.ts.map +0 -0
  213. /package/{components → dist/components}/indicator/indicator.js +0 -0
  214. /package/{components → dist/components}/indicator/indicator.js.map +0 -0
  215. /package/{components → dist/components}/indicator/indicator.types.d.ts +0 -0
  216. /package/{components → dist/components}/indicator/indicator.types.d.ts.map +0 -0
  217. /package/{components → dist/components}/input/input.d.ts +0 -0
  218. /package/{components → dist/components}/input/input.d.ts.map +0 -0
  219. /package/{components → dist/components}/input/input.js +0 -0
  220. /package/{components → dist/components}/input/input.js.map +0 -0
  221. /package/{components → dist/components}/input/input.types.d.ts +0 -0
  222. /package/{components → dist/components}/input/input.types.d.ts.map +0 -0
  223. /package/{components → dist/components}/input/input.utils.d.ts +0 -0
  224. /package/{components → dist/components}/input/input.utils.d.ts.map +0 -0
  225. /package/{components → dist/components}/input/input.utils.js +0 -0
  226. /package/{components → dist/components}/input/input.utils.js.map +0 -0
  227. /package/{components → dist/components}/input/variants/input-color.d.ts +0 -0
  228. /package/{components → dist/components}/input/variants/input-color.d.ts.map +0 -0
  229. /package/{components → dist/components}/input/variants/input-color.js +0 -0
  230. /package/{components → dist/components}/input/variants/input-color.js.map +0 -0
  231. /package/{components → dist/components}/input/variants/input-date.d.ts +0 -0
  232. /package/{components → dist/components}/input/variants/input-date.d.ts.map +0 -0
  233. /package/{components → dist/components}/input/variants/input-date.js +0 -0
  234. /package/{components → dist/components}/input/variants/input-date.js.map +0 -0
  235. /package/{components → dist/components}/input/variants/input-number.d.ts +0 -0
  236. /package/{components → dist/components}/input/variants/input-number.d.ts.map +0 -0
  237. /package/{components → dist/components}/input/variants/input-number.js +0 -0
  238. /package/{components → dist/components}/input/variants/input-number.js.map +0 -0
  239. /package/{components → dist/components}/input/variants/input-otp.d.ts +0 -0
  240. /package/{components → dist/components}/input/variants/input-otp.d.ts.map +0 -0
  241. /package/{components → dist/components}/input/variants/input-otp.js +0 -0
  242. /package/{components → dist/components}/input/variants/input-otp.js.map +0 -0
  243. /package/{components → dist/components}/input/variants/input-password.d.ts +0 -0
  244. /package/{components → dist/components}/input/variants/input-password.d.ts.map +0 -0
  245. /package/{components → dist/components}/input/variants/input-password.js +0 -0
  246. /package/{components → dist/components}/input/variants/input-password.js.map +0 -0
  247. /package/{components → dist/components}/input/variants/input-radio.d.ts +0 -0
  248. /package/{components → dist/components}/input/variants/input-radio.d.ts.map +0 -0
  249. /package/{components → dist/components}/input/variants/input-radio.js +0 -0
  250. /package/{components → dist/components}/input/variants/input-radio.js.map +0 -0
  251. /package/{components → dist/components}/input/variants/input-range.d.ts +0 -0
  252. /package/{components → dist/components}/input/variants/input-range.d.ts.map +0 -0
  253. /package/{components → dist/components}/input/variants/input-range.js +0 -0
  254. /package/{components → dist/components}/input/variants/input-range.js.map +0 -0
  255. /package/{components → dist/components}/input/variants/input-text.d.ts +0 -0
  256. /package/{components → dist/components}/input/variants/input-text.d.ts.map +0 -0
  257. /package/{components → dist/components}/input/variants/input-text.js +0 -0
  258. /package/{components → dist/components}/input/variants/input-text.js.map +0 -0
  259. /package/{components → dist/components}/input/variants/input-textarea.d.ts +0 -0
  260. /package/{components → dist/components}/input/variants/input-textarea.d.ts.map +0 -0
  261. /package/{components → dist/components}/input/variants/input-textarea.js +0 -0
  262. /package/{components → dist/components}/input/variants/input-textarea.js.map +0 -0
  263. /package/{components → dist/components}/loading/index.d.ts +0 -0
  264. /package/{components → dist/components}/loading/index.d.ts.map +0 -0
  265. /package/{components → dist/components}/loading/loading.d.ts +0 -0
  266. /package/{components → dist/components}/loading/loading.d.ts.map +0 -0
  267. /package/{components → dist/components}/loading/loading.js +0 -0
  268. /package/{components → dist/components}/loading/loading.js.map +0 -0
  269. /package/{components → dist/components}/mansory/index.d.ts +0 -0
  270. /package/{components → dist/components}/mansory/index.d.ts.map +0 -0
  271. /package/{components → dist/components}/mansory/mansory.d.ts +0 -0
  272. /package/{components → dist/components}/mansory/mansory.d.ts.map +0 -0
  273. /package/{components → dist/components}/mansory/mansory.js +0 -0
  274. /package/{components → dist/components}/mansory/mansory.js.map +0 -0
  275. /package/{components → dist/components}/mansory/mansory.types.d.ts +0 -0
  276. /package/{components → dist/components}/mansory/mansory.types.d.ts.map +0 -0
  277. /package/{components → dist/components}/menu/menu.d.ts +0 -0
  278. /package/{components → dist/components}/menu/menu.d.ts.map +0 -0
  279. /package/{components → dist/components}/menu/menu.data-example.d.ts +0 -0
  280. /package/{components → dist/components}/menu/menu.data-example.d.ts.map +0 -0
  281. /package/{components → dist/components}/menu/menu.js +0 -0
  282. /package/{components → dist/components}/menu/menu.js.map +0 -0
  283. /package/{components → dist/components}/modal/index.d.ts +0 -0
  284. /package/{components → dist/components}/modal/index.d.ts.map +0 -0
  285. /package/{components → dist/components}/modal/modal.d.ts +0 -0
  286. /package/{components → dist/components}/modal/modal.d.ts.map +0 -0
  287. /package/{components → dist/components}/modal/modal.js +0 -0
  288. /package/{components → dist/components}/modal/modal.js.map +0 -0
  289. /package/{components → dist/components}/modal/modalContext.d.ts +0 -0
  290. /package/{components → dist/components}/modal/modalContext.d.ts.map +0 -0
  291. /package/{components → dist/components}/modal/modalContext.js +0 -0
  292. /package/{components → dist/components}/modal/modalContext.js.map +0 -0
  293. /package/{components → dist/components}/pagination/index.d.ts +0 -0
  294. /package/{components → dist/components}/pagination/index.d.ts.map +0 -0
  295. /package/{components → dist/components}/pagination/pagination.d.ts +0 -0
  296. /package/{components → dist/components}/pagination/pagination.d.ts.map +0 -0
  297. /package/{components → dist/components}/pagination/pagination.js +0 -0
  298. /package/{components → dist/components}/pagination/pagination.js.map +0 -0
  299. /package/{components → dist/components}/pagination/pagination.types.d.ts +0 -0
  300. /package/{components → dist/components}/pagination/pagination.types.d.ts.map +0 -0
  301. /package/{components → dist/components}/progress-bar/index.d.ts +0 -0
  302. /package/{components → dist/components}/progress-bar/index.d.ts.map +0 -0
  303. /package/{components → dist/components}/progress-bar/progress-bar.d.ts +0 -0
  304. /package/{components → dist/components}/progress-bar/progress-bar.d.ts.map +0 -0
  305. /package/{components → dist/components}/progress-bar/progress-bar.js +0 -0
  306. /package/{components → dist/components}/progress-bar/progress-bar.js.map +0 -0
  307. /package/{components → dist/components}/progress-bar/progress-bar.types.d.ts +0 -0
  308. /package/{components → dist/components}/progress-bar/progress-bar.types.d.ts.map +0 -0
  309. /package/{components → dist/components}/qr-code/index.d.ts +0 -0
  310. /package/{components → dist/components}/qr-code/index.d.ts.map +0 -0
  311. /package/{components → dist/components}/qr-code/qr-code.d.ts +0 -0
  312. /package/{components → dist/components}/qr-code/qr-code.d.ts.map +0 -0
  313. /package/{components → dist/components}/qr-code/qr-code.js +0 -0
  314. /package/{components → dist/components}/qr-code/qr-code.js.map +0 -0
  315. /package/{components → dist/components}/qr-code/qr-code.types.d.ts +0 -0
  316. /package/{components → dist/components}/qr-code/qr-code.types.d.ts.map +0 -0
  317. /package/{components → dist/components}/rating/rating.d.ts +0 -0
  318. /package/{components → dist/components}/rating/rating.d.ts.map +0 -0
  319. /package/{components → dist/components}/rating/rating.js +0 -0
  320. /package/{components → dist/components}/rating/rating.js.map +0 -0
  321. /package/{components → dist/components}/rating/rating.types.d.ts +0 -0
  322. /package/{components → dist/components}/rating/rating.types.d.ts.map +0 -0
  323. /package/{components → dist/components}/select/index.d.ts +0 -0
  324. /package/{components → dist/components}/select/index.d.ts.map +0 -0
  325. /package/{components → dist/components}/select/select.d.ts +0 -0
  326. /package/{components → dist/components}/select/select.d.ts.map +0 -0
  327. /package/{components → dist/components}/select/select.js +0 -0
  328. /package/{components → dist/components}/select/select.js.map +0 -0
  329. /package/{components → dist/components}/select/select.types.d.ts +0 -0
  330. /package/{components → dist/components}/select/select.types.d.ts.map +0 -0
  331. /package/{components → dist/components}/select-zone/index.d.ts +0 -0
  332. /package/{components → dist/components}/select-zone/index.d.ts.map +0 -0
  333. /package/{components → dist/components}/select-zone/select-zone.d.ts +0 -0
  334. /package/{components → dist/components}/select-zone/select-zone.d.ts.map +0 -0
  335. /package/{components → dist/components}/select-zone/select-zone.js +0 -0
  336. /package/{components → dist/components}/select-zone/select-zone.js.map +0 -0
  337. /package/{components → dist/components}/select-zone/select-zone.types.d.ts +0 -0
  338. /package/{components → dist/components}/select-zone/select-zone.types.d.ts.map +0 -0
  339. /package/{components → dist/components}/skeleton/index.d.ts +0 -0
  340. /package/{components → dist/components}/skeleton/index.d.ts.map +0 -0
  341. /package/{components → dist/components}/skeleton/skeleton.d.ts +0 -0
  342. /package/{components → dist/components}/skeleton/skeleton.d.ts.map +0 -0
  343. /package/{components → dist/components}/skeleton/skeleton.js +0 -0
  344. /package/{components → dist/components}/skeleton/skeleton.js.map +0 -0
  345. /package/{components → dist/components}/slider/slider.d.ts +0 -0
  346. /package/{components → dist/components}/slider/slider.d.ts.map +0 -0
  347. /package/{components → dist/components}/slider/slider.js +0 -0
  348. /package/{components → dist/components}/slider/slider.js.map +0 -0
  349. /package/{components → dist/components}/slider/slider.types.d.ts +0 -0
  350. /package/{components → dist/components}/slider/slider.types.d.ts.map +0 -0
  351. /package/{components → dist/components}/splitter/index.d.ts +0 -0
  352. /package/{components → dist/components}/splitter/index.d.ts.map +0 -0
  353. /package/{components → dist/components}/splitter/splitter.d.ts +0 -0
  354. /package/{components → dist/components}/splitter/splitter.d.ts.map +0 -0
  355. /package/{components → dist/components}/splitter/splitter.js +0 -0
  356. /package/{components → dist/components}/splitter/splitter.js.map +0 -0
  357. /package/{components → dist/components}/splitter/splitter.types.d.ts +0 -0
  358. /package/{components → dist/components}/splitter/splitter.types.d.ts.map +0 -0
  359. /package/{components → dist/components}/steps/index.d.ts +0 -0
  360. /package/{components → dist/components}/steps/index.d.ts.map +0 -0
  361. /package/{components → dist/components}/steps/steps.d.ts +0 -0
  362. /package/{components → dist/components}/steps/steps.d.ts.map +0 -0
  363. /package/{components → dist/components}/steps/steps.js +0 -0
  364. /package/{components → dist/components}/steps/steps.js.map +0 -0
  365. /package/{components → dist/components}/swap/index.d.ts +0 -0
  366. /package/{components → dist/components}/swap/index.d.ts.map +0 -0
  367. /package/{components → dist/components}/swap/swap.d.ts +0 -0
  368. /package/{components → dist/components}/swap/swap.d.ts.map +0 -0
  369. /package/{components → dist/components}/swap/swap.js +0 -0
  370. /package/{components → dist/components}/swap/swap.js.map +0 -0
  371. /package/{components → dist/components}/switch/index.d.ts +0 -0
  372. /package/{components → dist/components}/switch/index.d.ts.map +0 -0
  373. /package/{components → dist/components}/switch/switch.d.ts +0 -0
  374. /package/{components → dist/components}/switch/switch.d.ts.map +0 -0
  375. /package/{components → dist/components}/switch/switch.js +0 -0
  376. /package/{components → dist/components}/switch/switch.js.map +0 -0
  377. /package/{components → dist/components}/switch/switch.types.d.ts +0 -0
  378. /package/{components → dist/components}/switch/switch.types.d.ts.map +0 -0
  379. /package/{components → dist/components}/tab/index.d.ts +0 -0
  380. /package/{components → dist/components}/tab/index.d.ts.map +0 -0
  381. /package/{components → dist/components}/tab/tab.d.ts +0 -0
  382. /package/{components → dist/components}/tab/tab.d.ts.map +0 -0
  383. /package/{components → dist/components}/tab/tab.js +0 -0
  384. /package/{components → dist/components}/tab/tab.js.map +0 -0
  385. /package/{components → dist/components}/tab/tab.types.d.ts +0 -0
  386. /package/{components → dist/components}/tab/tab.types.d.ts.map +0 -0
  387. /package/{components → dist/components}/table/index.d.ts +0 -0
  388. /package/{components → dist/components}/table/index.d.ts.map +0 -0
  389. /package/{components → dist/components}/table/index.js +0 -0
  390. /package/{components → dist/components}/table/table.d.ts +0 -0
  391. /package/{components → dist/components}/table/table.d.ts.map +0 -0
  392. /package/{components → dist/components}/table/table.js +0 -0
  393. /package/{components → dist/components}/table/table.js.map +0 -0
  394. /package/{components → dist/components}/table/table.types.d.ts +0 -0
  395. /package/{components → dist/components}/table/table.types.d.ts.map +0 -0
  396. /package/{components → dist/components}/text-rotate/index.d.ts +0 -0
  397. /package/{components → dist/components}/text-rotate/index.d.ts.map +0 -0
  398. /package/{components → dist/components}/text-rotate/text-rotate.d.ts +0 -0
  399. /package/{components → dist/components}/text-rotate/text-rotate.d.ts.map +0 -0
  400. /package/{components → dist/components}/text-rotate/text-rotate.js +0 -0
  401. /package/{components → dist/components}/text-rotate/text-rotate.js.map +0 -0
  402. /package/{components → dist/components}/timeline/index.d.ts +0 -0
  403. /package/{components → dist/components}/timeline/index.d.ts.map +0 -0
  404. /package/{components → dist/components}/timeline/timeline.d.ts +0 -0
  405. /package/{components → dist/components}/timeline/timeline.d.ts.map +0 -0
  406. /package/{components → dist/components}/timeline/timeline.js +0 -0
  407. /package/{components → dist/components}/timeline/timeline.js.map +0 -0
  408. /package/{components → dist/components}/timeline/timeline.types.d.ts +0 -0
  409. /package/{components → dist/components}/timeline/timeline.types.d.ts.map +0 -0
  410. /package/{components → dist/components}/toast/icons/ErrorIcon.d.ts +0 -0
  411. /package/{components → dist/components}/toast/icons/ErrorIcon.d.ts.map +0 -0
  412. /package/{components → dist/components}/toast/icons/ErrorIcon.js +0 -0
  413. /package/{components → dist/components}/toast/icons/ErrorIcon.js.map +0 -0
  414. /package/{components → dist/components}/toast/icons/IconCircle.d.ts +0 -0
  415. /package/{components → dist/components}/toast/icons/IconCircle.d.ts.map +0 -0
  416. /package/{components → dist/components}/toast/icons/IconCircle.js +0 -0
  417. /package/{components → dist/components}/toast/icons/IconCircle.js.map +0 -0
  418. /package/{components → dist/components}/toast/icons/InfoIcon.d.ts +0 -0
  419. /package/{components → dist/components}/toast/icons/InfoIcon.d.ts.map +0 -0
  420. /package/{components → dist/components}/toast/icons/InfoIcon.js +0 -0
  421. /package/{components → dist/components}/toast/icons/InfoIcon.js.map +0 -0
  422. /package/{components → dist/components}/toast/icons/LoaderIcon.d.ts +0 -0
  423. /package/{components → dist/components}/toast/icons/LoaderIcon.d.ts.map +0 -0
  424. /package/{components → dist/components}/toast/icons/LoaderIcon.js +0 -0
  425. /package/{components → dist/components}/toast/icons/LoaderIcon.js.map +0 -0
  426. /package/{components → dist/components}/toast/icons/SuccessIcon.d.ts +0 -0
  427. /package/{components → dist/components}/toast/icons/SuccessIcon.d.ts.map +0 -0
  428. /package/{components → dist/components}/toast/icons/SuccessIcon.js +0 -0
  429. /package/{components → dist/components}/toast/icons/SuccessIcon.js.map +0 -0
  430. /package/{components → dist/components}/toast/icons/WarningIcon.d.ts +0 -0
  431. /package/{components → dist/components}/toast/icons/WarningIcon.d.ts.map +0 -0
  432. /package/{components → dist/components}/toast/icons/WarningIcon.js +0 -0
  433. /package/{components → dist/components}/toast/icons/WarningIcon.js.map +0 -0
  434. /package/{components → dist/components}/toast/icons/index.d.ts +0 -0
  435. /package/{components → dist/components}/toast/icons/index.d.ts.map +0 -0
  436. /package/{components → dist/components}/toast/index.d.ts +0 -0
  437. /package/{components → dist/components}/toast/index.d.ts.map +0 -0
  438. /package/{components → dist/components}/toast/toast.d.ts +0 -0
  439. /package/{components → dist/components}/toast/toast.d.ts.map +0 -0
  440. /package/{components → dist/components}/toast/toast.js +0 -0
  441. /package/{components → dist/components}/toast/toast.js.map +0 -0
  442. /package/{components → dist/components}/toast/toast.store.d.ts +0 -0
  443. /package/{components → dist/components}/toast/toast.store.d.ts.map +0 -0
  444. /package/{components → dist/components}/toast/toast.store.js +0 -0
  445. /package/{components → dist/components}/toast/toast.store.js.map +0 -0
  446. /package/{components → dist/components}/toast/toast.type.d.ts +0 -0
  447. /package/{components → dist/components}/toast/toast.type.d.ts.map +0 -0
  448. /package/{components → dist/components}/tooltip/index.d.ts +0 -0
  449. /package/{components → dist/components}/tooltip/index.d.ts.map +0 -0
  450. /package/{components → dist/components}/tooltip/tooltip.d.ts +0 -0
  451. /package/{components → dist/components}/tooltip/tooltip.d.ts.map +0 -0
  452. /package/{components → dist/components}/tooltip/tooltip.js +0 -0
  453. /package/{components → dist/components}/tooltip/tooltip.js.map +0 -0
  454. /package/{components → dist/components}/tooltip/tooltip.types.d.ts +0 -0
  455. /package/{components → dist/components}/tooltip/tooltip.types.d.ts.map +0 -0
  456. /package/{components → dist/components}/tour/index.d.ts +0 -0
  457. /package/{components → dist/components}/tour/index.d.ts.map +0 -0
  458. /package/{components → dist/components}/tour/tour.d.ts +0 -0
  459. /package/{components → dist/components}/tour/tour.types.d.ts +0 -0
  460. /package/{components → dist/components}/tour/tour.types.d.ts.map +0 -0
  461. /package/{components → dist/components}/upload/index.d.ts +0 -0
  462. /package/{components → dist/components}/upload/index.d.ts.map +0 -0
  463. /package/{components → dist/components}/upload/upload.d.ts +0 -0
  464. /package/{components → dist/components}/upload/upload.d.ts.map +0 -0
  465. /package/{components → dist/components}/upload/upload.js +0 -0
  466. /package/{components → dist/components}/upload/upload.js.map +0 -0
  467. /package/{components → dist/components}/upload/upload.types.d.ts +0 -0
  468. /package/{components → dist/components}/upload/upload.types.d.ts.map +0 -0
  469. /package/{components → dist/components}/z-index/index.d.ts +0 -0
  470. /package/{components → dist/components}/z-index/index.d.ts.map +0 -0
  471. /package/{components → dist/components}/z-index/z-index.context.d.ts +0 -0
  472. /package/{components → dist/components}/z-index/z-index.context.d.ts.map +0 -0
  473. /package/{components → dist/components}/z-index/z-index.context.js +0 -0
  474. /package/{components → dist/components}/z-index/z-index.context.js.map +0 -0
  475. /package/{components → dist/components}/z-index/z-index.d.ts +0 -0
  476. /package/{components → dist/components}/z-index/z-index.d.ts.map +0 -0
  477. /package/{components → dist/components}/z-index/z-index.js +0 -0
  478. /package/{components → dist/components}/z-index/z-index.js.map +0 -0
  479. /package/{components → dist/components}/z-index/z-index.store.d.ts +0 -0
  480. /package/{components → dist/components}/z-index/z-index.store.d.ts.map +0 -0
  481. /package/{components → dist/components}/z-index/z-index.store.js +0 -0
  482. /package/{components → dist/components}/z-index/z-index.store.js.map +0 -0
  483. /package/{components → dist/components}/z-index/z-index.types.d.ts +0 -0
  484. /package/{components → dist/components}/z-index/z-index.types.d.ts.map +0 -0
  485. /package/{components → dist/components}/z-index/z-index.types.js +0 -0
  486. /package/{lib.d.ts → dist/lib.d.ts} +0 -0
  487. /package/{lib.d.ts.map → dist/lib.d.ts.map} +0 -0
  488. /package/{lib.js → dist/lib.js} +0 -0
  489. /package/{type.d.ts → dist/type.d.ts} +0 -0
  490. /package/{type.d.ts.map → dist/type.d.ts.map} +0 -0
  491. /package/{utils → dist/utils}/cn.d.ts +0 -0
  492. /package/{utils → dist/utils}/cn.d.ts.map +0 -0
  493. /package/{utils → dist/utils}/cn.js +0 -0
  494. /package/{utils → dist/utils}/cn.js.map +0 -0
  495. /package/{utils → dist/utils}/element-tracker.js +0 -0
  496. /package/{utils → dist/utils}/element-tracker.js.map +0 -0
  497. /package/{utils → dist/utils}/helper.d.ts +0 -0
  498. /package/{utils → dist/utils}/helper.d.ts.map +0 -0
  499. /package/{utils → dist/utils}/helper.js +0 -0
  500. /package/{utils → dist/utils}/helper.js.map +0 -0
  501. /package/{utils → dist/utils}/hoc.js +0 -0
  502. /package/{utils → dist/utils}/hoc.js.map +0 -0
@@ -0,0 +1,1407 @@
1
+ ## COMPONENT IDENTITY
2
+ - **Import**: `import { Table, createColumnHelper } from 'solid-tom-ui';`
3
+ - **Exports**: `Table` (named export), `createColumnHelper` (re-exported from TanStack), all table type exports (type exports)
4
+ - **Framework**: SolidJS
5
+ - **Underlying library**: `@tanstack/solid-table` v8 + `@tanstack/solid-virtual` (optional virtual scrolling)
6
+ - **Purpose**: Feature-rich data table — virtual scrolling, expandable rows, column pinning, zebra striping, sort/filter, pagination, and row selection
7
+
8
+ ---
9
+
10
+ ## STATIC FACTORY METHODS
11
+
12
+ `Table` has two static factory methods that generate `ColumnDef` objects:
13
+
14
+ ### `Table.Selection<TData>(options?)`
15
+
16
+ Generates a **row selection column** (checkbox or radio). Place it anywhere in the `columns` array — only the first one is rendered (duplicates silently ignored).
17
+
18
+ **`TableSelectionOptions<TData>`**:
19
+
20
+ | Option | Type | Default | Description |
21
+ |---|---|---|---|
22
+ | `type` | `'checkbox' \| 'radio'` | `'checkbox'` | Multi-select or single-select |
23
+ | `title` | `JSXElement` | — | Custom header content (overrides auto select-all checkbox) |
24
+ | `width` | `string \| number` | `48` | Column width (px) |
25
+ | `hideSelectAll` | `boolean` | `false` | Hide select-all checkbox in header (checkbox type only) |
26
+ | `renderCell` | `(checked, record, index) => JSXElement` | — | Custom cell renderer; clicking the result toggles the row |
27
+
28
+ **Behavior**:
29
+ - `type='checkbox'` → renders `<input type="checkbox">` per cell; header renders select-all checkbox (unless `hideSelectAll` or `title` set)
30
+ - `type='radio'` → renders `<input type="radio">` per cell; forces `enableMultiRowSelection=false` internally; header is empty
31
+ - Presence of `Table.Selection()` in columns **auto-enables** `enableRowSelection` (no need to pass the prop separately)
32
+ - Column id: `__selection__` (internal, do not rely on it for external logic)
33
+
34
+ ### `Table.Expanded<TData>(options)`
35
+
36
+ Generates a **row expand toggle column**. Place it anywhere in the `columns` array. Required option: `expandedRowRender`.
37
+
38
+ **`TableExpandedOptions<TData>`**:
39
+
40
+ | Option | Type | Default | Description |
41
+ |---|---|---|---|
42
+ | `expandedRowRender` | `(record, index, indent, expanded) => JSX.Element \| null` | **required** | Render the expanded row content |
43
+ | `rowExpandable` | `(record, index) => boolean` | — | When omitted, all rows are expandable |
44
+ | `expandIcon` | `(expanded: boolean) => JSX.Element` | — | Custom icon; receives current expanded state. When omitted, uses a rotating `chevron-right` |
45
+ | `width` | `number` | `48` | Column width (px) |
46
+
47
+ **Behavior**:
48
+ - Column id: `__expanded__` (internal)
49
+ - Clicking the expand cell (or the icon) toggles the row
50
+ - Expanded content renders in a separate `<tr>` spanning all columns, below the data row
51
+ - `rowExpandable` returning `false` hides the icon and prevents toggling for that row
52
+
53
+ ---
54
+
55
+ ## PROP REFERENCE
56
+
57
+ ### Core data props
58
+
59
+ | Prop | Type | Default | Description |
60
+ |---|---|---|---|
61
+ | `columns` | `ColumnDef<TData, any>[]` | **required** | Column definitions. Use `createColumnHelper` for type safety. |
62
+ | `data` | `TData[]` | **required** | Table rows data. |
63
+ | `options` | `Partial<Omit<TableOptions<TData>, 'data' \| 'columns' \| 'getCoreRowModel'>>` | — | Pass-through for any TanStack table option not exposed as a prop (e.g. custom row models, meta). |
64
+ | `onTableReady` | `(table: TableInstance<TData>) => void` | — | Receives the TanStack `table` instance after creation. Use to access full TanStack API. |
65
+ | `getRowId` | `(row, index, parent?) => string` | — | Custom row ID. Required when using selection/expand with non-index IDs (e.g. `row => String(row.id)`). |
66
+
67
+ ### Style props
68
+
69
+ | Prop | Type | Default | Description |
70
+ |---|---|---|---|
71
+ | `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Cell padding + font size variant |
72
+ | `zebra` | `boolean \| { rows?: boolean; cols?: boolean }` | `{ rows: true }` | Zebra striping. `true` → `{ rows: true, cols: false }` (rows only). `false` or omit → disabled. |
73
+ | `border` | `boolean \| { outer?: boolean; horizontal?: boolean; vertical?: boolean }` | — | Border control. `true` → all borders. `false` → no borders. Object for granular control. |
74
+ | `rounded` | `string` | `'rounded-sm'` | Tailwind rounded class applied to root. Also sets `overflow-hidden`. Pass `''` to disable. |
75
+ | `resizable` | `boolean` | `true` | Enable drag-to-resize columns via overlay handles (data columns only, not selection/expand columns). |
76
+ | `showHeader` | `boolean` | `true` | Show or hide the table header (`<thead>`). Set to `false` to render the table without any column header row. |
77
+ | `color` | `BaseColorProps` | `'info'` | Theme color token used for hover/highlight/sort icon colors via CSS custom properties. |
78
+ | `scroll` | `{ x?: string \| number \| true; y?: string \| number }` | — | Scroll config. See scroll section below. |
79
+ | `virtual` | `boolean \| TableVirtualOptions` | — | Enable virtual scrolling for large datasets. Requires `scroll.y`. See virtual section below. |
80
+
81
+ ### Slot / render props
82
+
83
+ | Prop | Type | Description |
84
+ |---|---|---|
85
+ | `headerPanel` | `() => JSXElement` | Renders above the table (toolbar, title, filters, etc.). Has its own panel div with optional border. |
86
+ | `footerPanel` | `() => JSXElement` | Renders below the table (pagination, summary, etc.). Has its own panel div. |
87
+ | `emptyContent` | `JSXElement` | Content shown when `data` is empty. Default: `"No data"`. |
88
+ | `class` | `TableClassNames` | Custom class names per semantic part. See `TableClassNames` below. |
89
+ | `onRowClick` | `(row: Row<TData>, e: MouseEvent) => void` | Fired on body row click. Does NOT fire when clicking selection or expand cells. |
90
+ | `onCell` | `(cell: Cell<TData, unknown>, rowIndex: number) => TableCellSpanResult` | Table-level callback to control `colSpan`/`rowSpan` for body cells. Per-column `meta.onCell` takes priority. Only applies in non-virtual mode. |
91
+
92
+ ### Row selection props
93
+
94
+ | Prop | Type | Description |
95
+ |---|---|---|
96
+ | `enableRowSelection` | `boolean \| ((row) => boolean)` | Enable selection. Auto-set to `true` when `Table.Selection()` column is present. |
97
+ | `rowSelection` | `RowSelectionState` | Controlled selection state. Shape: `{ [rowId: string]: boolean }` |
98
+ | `onRowSelectionChange` | `OnChangeFn<RowSelectionState>` | Called when selection changes (TanStack updater function). |
99
+
100
+ ### Sorting props
101
+
102
+ | Prop | Type | Default | Description |
103
+ |---|---|---|---|
104
+ | `enableSorting` | `boolean` | `false` | Enable column sorting. Must be `true` for any sort to work. |
105
+ | `sorting` | `SortingState` | — | Controlled sort state. Shape: `[{ id: string; desc: boolean }]` |
106
+ | `onSortingChange` | `OnChangeFn<SortingState>` | — | Called when sort changes. |
107
+
108
+ **Multi-sort behavior**: Every header click accumulates sort columns (equivalent to always holding Shift). Clicking a sorted column cycles through: unsorted → asc → desc → unsorted. Multiple columns can be sorted simultaneously. The priority badge (1, 2, 3...) is shown on each sorted column when more than one column is sorted.
109
+
110
+ ### Filtering props
111
+
112
+ | Prop | Type | Default | Description |
113
+ |---|---|---|---|
114
+ | `enableColumnFilters` | `boolean` | `false` | Enable column-level filtering. |
115
+ | `columnFilters` | `ColumnFiltersState` | — | Controlled column filter state. |
116
+ | `onColumnFiltersChange` | `OnChangeFn<ColumnFiltersState>` | — | Called when column filters change. |
117
+ | `globalFilter` | `string` | — | Global filter string. |
118
+ | `onGlobalFilterChange` | `OnChangeFn<string>` | — | Called when global filter changes. |
119
+
120
+ ### Visibility props
121
+
122
+ | Prop | Type | Description |
123
+ |---|---|---|
124
+ | `columnVisibility` | `VisibilityState` | Controlled column visibility. Shape: `{ [colId: string]: boolean }` |
125
+ | `onColumnVisibilityChange` | `OnChangeFn<VisibilityState>` | Called when visibility changes. |
126
+
127
+ ### Pagination props
128
+
129
+ | Prop | Type | Default | Description |
130
+ |---|---|---|---|
131
+ | `pagination` | `PaginationState` | — | Initial/controlled pagination state. Shape: `{ pageIndex: number; pageSize: number }`. Used to seed or override the table's internal page state. |
132
+ | `paginationProps` | `PaginationComponentProps` | — | When provided, enables client-side pagination and renders a `<Pagination>` component below the table. See details below. |
133
+
134
+ **`paginationProps`** is `Omit<PaginationProps, 'current' | 'pageSize' | 'defaultCurrent' | 'defaultPageSize'> & { total: number; position?: 'start' | 'end' }`:
135
+
136
+ | Option | Type | Description |
137
+ |---|---|---|
138
+ | `total` | `number` | **required** — Total number of data items (used to compute page count). |
139
+ | `position` | `'start' \| 'end'` | Position of the Pagination component relative to the table. `'start'` = above table, `'end'` = below table. Default: `'end'`. |
140
+ | `onChange` | `(page, size) => void` | Called after the table's internal page/size state has already been updated. Use for server-side pagination to fetch the new page. |
141
+ | `showSizeChanger` | `boolean` | Show page size selector. |
142
+ | `showQuickJumper` | `boolean` | Show "go to page" input. |
143
+ | `size` | `PaginationSize` | Size variant for the Pagination component. |
144
+ | `disabled` | `boolean` | Disable pagination controls. |
145
+ | `...` | `PaginationProps` | Any other `PaginationProps` except `current`, `pageSize`, `defaultCurrent`, `defaultPageSize` (wired automatically). |
146
+
147
+ **Notes**:
148
+ - `current` and `pageSize` in the `<Pagination>` component are wired automatically from table state — do not pass them
149
+ - For **client-side pagination**: pass all `data` rows; the table slices them automatically
150
+ - For **server-side pagination**: pass only the current page's rows as `data`, and use `paginationProps.onChange` to fetch the new page
151
+ - The `<Pagination>` component renders outside the table border (below `sui-table-root`)
152
+
153
+ ### Expanded rows props (state management)
154
+
155
+ | Prop | Type | Description |
156
+ |---|---|---|
157
+ | `defaultExpandAllRows` | `boolean` | Expand all rows on first mount (uncontrolled; applied once). |
158
+ | `defaultExpandedRowKeys` | `string[]` | Initial expanded row keys (uncontrolled). |
159
+ | `expandedRowKeys` | `string[]` | Controlled list of expanded row keys. |
160
+ | `onExpandedRowsChange` | `(expandedKeys: string[]) => void` | Called when the set of expanded keys changes. |
161
+ | `onExpand` | `(expanded: boolean, record: TData) => void` | Called when a single row's expand icon is clicked. |
162
+
163
+ ### Infinite scroll props (virtual mode only)
164
+
165
+ | Prop | Type | Description |
166
+ |---|---|---|
167
+ | `getVirtualData` | `() => Promise<TData[]>` | Called when the user scrolls near the end of the virtual list (auto mode) or clicks "Load more" (manual mode). Must return a Promise resolving with the next page of data. The resolved rows are automatically appended to the internal data. Only fires when `virtual` is set. |
168
+ | `loadingMore` | `'none' \| 'auto' \| 'manual'` | Controls behavior and loading indicator at the end of the virtual list. `'none'`: no indicator, no action (default). `'auto'`: shows a spinner; `getVirtualData` is called automatically when scrolling near the end. `'manual'`: shows a "Load more" button; `getVirtualData` is only called when the user clicks the button. Only applies in virtual mode. |
169
+
170
+ ---
171
+
172
+ ## `TableClassNames` — per-part class customization
173
+
174
+ ```ts
175
+ interface TableClassNames {
176
+ root?: string; // root <div> wrapping everything
177
+ headerPanel?: string; // headerPanel slot wrapper
178
+ table?: string; // <table> element
179
+ thead?: string; // <thead>
180
+ tbody?: string; // <tbody>
181
+ tfoot?: string; // footerPanel wrapper (reuses tfoot key)
182
+ tr?: string; // every <tr>
183
+ th?: string; // every <th>
184
+ td?: string; // every <td>
185
+ headerRow?: string; // <tr> in thead only
186
+ bodyRow?: string; // <tr> in tbody only
187
+ footerRow?: string; // (reserved, not used for tfoot tr)
188
+ empty?: string; // empty state <td>
189
+ }
190
+ ```
191
+
192
+ ---
193
+
194
+ ## SCROLL CONFIGURATION
195
+
196
+ `scroll.x` — horizontal scrolling:
197
+
198
+ | Value | Behavior |
199
+ |---|---|
200
+ | `number` | Wrapper `max-width` = `${n}px`; table scrolls inside |
201
+ | `string` (e.g. `'600px'`) | Wrapper `max-width` = value |
202
+ | `true` | Wrapper inherits parent width; table `min-width` = sum of all column sizes |
203
+ | `'max-content'` | Table `width` = `max-content`; wrapper scrolls |
204
+ | omitted | No horizontal scroll constraint |
205
+
206
+ `scroll.y` — vertical scrolling:
207
+
208
+ | Value | Behavior |
209
+ |---|---|
210
+ | `number` | Wrapper `max-height` = `${n}px`; `<thead>` becomes sticky (fixed header) |
211
+ | `string` | Wrapper `max-height` = value |
212
+ | omitted | No vertical scroll |
213
+
214
+ **Note**: When `scroll.y` is set OR any column has `meta.fixed`, `thead tr` becomes `position: sticky; top: 0`.
215
+
216
+ ---
217
+
218
+ ## VIRTUAL SCROLLING
219
+
220
+ Virtual scrolling renders only the rows visible in the viewport instead of all rows, keeping DOM size and rendering cost constant regardless of dataset size. Powered by `@tanstack/solid-virtual`.
221
+
222
+ ### Requirements
223
+
224
+ - `scroll.y` **must** be set to define the fixed-height viewport
225
+ - `virtual` prop must be set to `true` or a `TableVirtualOptions` object
226
+
227
+ ### `TableVirtualOptions`
228
+
229
+ | Option | Type | Default | Description |
230
+ |---|---|---|---|
231
+ | `itemSize` | `number` | `40` | Estimated row height in pixels. Match to your `size` variant. |
232
+ | `overscan` | `number` | `5` | Extra rows rendered beyond the visible area (above + below). |
233
+
234
+ **Approximate row heights by size variant**:
235
+
236
+ | Size | Estimated height |
237
+ |---|---|
238
+ | `xs` | `26px` |
239
+ | `sm` | `33px` |
240
+ | `md` | `40px` (default) |
241
+ | `lg` | `48px` |
242
+ | `xl` | `58px` |
243
+
244
+ ### How it works
245
+
246
+ - The scroll wrapper (`sui-table-wrapper`) becomes the virtualizer's scroll container
247
+ - Only visible rows (+ `overscan` buffer) are rendered in the DOM
248
+ - Top and bottom spacer `<tr>` elements fill the virtual space so the scrollbar reflects total height
249
+ - `measureElement` is called on each rendered row `<tr>` so the virtualizer can refine height estimates dynamically
250
+
251
+ ### Virtual sort loading indicator
252
+
253
+ When `enableSorting` is set and the user clicks a sortable column header in virtual mode, sorting is executed asynchronously:
254
+
255
+ 1. A full-height loading overlay (spinner + "Sorting" text) replaces the tbody rows immediately
256
+ 2. A microtask yields to let the loading state render
257
+ 3. The actual sort executes
258
+ 4. The loading overlay is shown for at least 500ms total, then removed
259
+ 5. The scroll position is reset to the top so the virtualizer renders the newly sorted rows
260
+
261
+ This prevents jank on large datasets where synchronous sorting would block the UI thread. Clicking a column header while sorting is in progress is a no-op.
262
+
263
+ ### Infinite scroll
264
+
265
+ Use `getVirtualData` + `loadingMore` together to implement lazy-loading / infinite scroll on top of virtual scrolling.
266
+
267
+ **`loadingMore` values**:
268
+ - `'none'` (default) — no indicator shown; `getVirtualData` is never called automatically
269
+ - `'auto'` — renders a spinner row below the last virtual row when fetching; `getVirtualData` is triggered automatically when scrolling near the end or when content doesn't fill the viewport
270
+ - `'manual'` — renders a "Load more" button row; `getVirtualData` is only called when the user clicks the button (NOT on scroll)
271
+
272
+ **How `getVirtualData` works:**
273
+ - `getVirtualData` returns a `Promise<TData[]>` — the component calls it and automatically appends the resolved rows to the internal data
274
+ - The component tracks a loading state internally (`isFetchingMore`) to prevent concurrent calls
275
+ - The `data` prop serves as the **initial data**; subsequent pages are appended internally
276
+ - When the `data` prop reference changes, the internal data resets to the new prop value
277
+
278
+ **Auto-fill behavior**: When content is too short to fill the viewport (no scrollbar appears), the component automatically calls `getVirtualData` in a promise chain until enough rows are loaded to create a scrollbar. This only runs in `'auto'` mode (not `'manual'`).
279
+
280
+ **How scroll detection works internally:**
281
+ - A scroll listener is attached to the `wrapperEl` (scroll container) on mount, only when `virtual` is set
282
+ - In `'auto'` mode: fires `getVirtualData` when `scrollTop + clientHeight ≥ scrollHeight − threshold`, where `threshold = itemSize × overscan` (default: `40 × 5 = 200px`)
283
+ - In `'manual'` mode: no scroll listener fires `getVirtualData`; only the button click does
284
+ - In `'none'` mode: no action on scroll
285
+
286
+ **Implementation pattern (`'auto'` mode):**
287
+ ```tsx
288
+ const initialData = fetchFirstPage(); // stable reference — do not recreate on each render
289
+ const [loadedCount, setLoadedCount] = createSignal(initialData.length);
290
+ const hasMore = () => loadedCount() < TOTAL;
291
+
292
+ const getVirtualData = () =>
293
+ fetchNextPage(loadedCount()).then(newRows => {
294
+ setLoadedCount(prev => prev + newRows.length);
295
+ return newRows; // component appends automatically
296
+ });
297
+
298
+ <Table
299
+ data={initialData}
300
+ getVirtualData={hasMore() ? getVirtualData : undefined}
301
+ loadingMore={hasMore() ? 'auto' : 'none'}
302
+ // ...
303
+ />
304
+ ```
305
+
306
+ **Implementation pattern (`'manual'` mode):**
307
+ ```tsx
308
+ <Table
309
+ data={initialData}
310
+ getVirtualData={hasMore() ? getVirtualData : undefined}
311
+ loadingMore={hasMore() ? 'manual' : 'none'}
312
+ // ...
313
+ />
314
+ ```
315
+
316
+ **Rules:**
317
+ - Keep the `data` prop as a **stable reference** (e.g. a constant or a signal that only changes on explicit reset). The component resets internal data whenever `data` changes reference.
318
+ - `getRowId` is required to give each row a stable unique ID across pages
319
+ - Set `loadingMore='none'` (or omit `getVirtualData`) when all data is exhausted to hide the indicator
320
+ - The component prevents concurrent calls internally — no extra guard needed in the caller
321
+
322
+ ### Limitations
323
+
324
+ - **Expanded rows are not supported** with virtual scrolling (variable heights break virtualizer accuracy)
325
+ - **`scroll.y` is required** — without a fixed viewport height, no scrolling occurs and virtual mode has no effect
326
+ - **`resizable={false}` is recommended** — column resizing and virtual mode can be used together but may cause minor visual glitches
327
+
328
+ ### Example
329
+
330
+ ```tsx
331
+ // Basic — 10,000 rows with defaults
332
+ <Table
333
+ columns={columns}
334
+ data={largeData}
335
+ scroll={{ y: 400 }}
336
+ virtual
337
+ border
338
+ size="md"
339
+ resizable={false}
340
+ getRowId={row => String(row.id)}
341
+ />
342
+
343
+ // Custom options (lg size rows)
344
+ <Table
345
+ columns={columns}
346
+ data={largeData}
347
+ scroll={{ y: 400 }}
348
+ virtual={{ itemSize: 48, overscan: 10 }}
349
+ size="lg"
350
+ resizable={false}
351
+ />
352
+ ```
353
+
354
+ ---
355
+
356
+ ## COLUMN META EXTENSIONS
357
+
358
+ `ColumnDef.meta` supports several custom fields beyond TanStack's defaults:
359
+
360
+ ### `meta.fixed` — sticky columns
361
+
362
+ ```ts
363
+ meta: { fixed: 'start' } // sticky left
364
+ meta: { fixed: 'end' } // sticky right
365
+ meta: { fixed: true } // alias for 'start'
366
+ ```
367
+
368
+ See [FIXED (STICKY) COLUMNS](#fixed-sticky-columns) below.
369
+
370
+ ### `meta.align` — cell alignment
371
+
372
+ Horizontal alignment applied to **both** the header and body cells. Default: `'start'`.
373
+
374
+ ```ts
375
+ meta: { align: 'start' | 'center' | 'end' }
376
+ ```
377
+
378
+ ```ts
379
+ col.accessor('score', {
380
+ header: 'Score',
381
+ meta: { align: 'end' }, // right-align header + cells
382
+ })
383
+ ```
384
+
385
+ ### `meta.tooltip` — cell tooltip
386
+
387
+ Wraps every body cell in a `Tooltip` component. Table automatically injects `usePortal=true` and `containerId` (the `<tbody>` element ID), so `position` defaults to `'top'` if not specified.
388
+
389
+ Type: `TableCellTooltipOptions` — same as `TooltipProps` but omits `children`, `usePortal`, `containerId`. The `content` field can be a **static string** or a **function** receiving the cell value.
390
+
391
+ ```ts
392
+ meta: {
393
+ tooltip?: TableCellTooltipOptions
394
+ }
395
+ ```
396
+
397
+ ```ts
398
+ col.accessor('email', {
399
+ header: 'Email',
400
+ meta: {
401
+ tooltip: {
402
+ content: (value) => `Send email to: ${value}`,
403
+ position: 'bottom',
404
+ },
405
+ },
406
+ })
407
+
408
+ // Static content:
409
+ col.accessor('notes', {
410
+ header: 'Notes',
411
+ meta: { tooltip: { content: 'Click to edit' } },
412
+ })
413
+ ```
414
+
415
+ ### `meta.onCell` — per-column cell spanning
416
+
417
+ Controls `colSpan` and `rowSpan` for body cells in this column. **Takes priority** over the table-level `onCell` prop.
418
+
419
+ Return `{ colSpan: 0 }` or `{ rowSpan: 0 }` to hide a cell that is covered by a spanning neighbour.
420
+
421
+ ```ts
422
+ meta: {
423
+ onCell?: (cell: Cell<TData, unknown>, rowIndex: number) => TableCellSpanResult
424
+ }
425
+ ```
426
+
427
+ ```ts
428
+ col.accessor('product', {
429
+ header: 'Product',
430
+ meta: {
431
+ onCell: (cell, rowIndex) => {
432
+ if (cell.getValue() === 'Widget B') return { colSpan: 3 };
433
+ return {};
434
+ },
435
+ },
436
+ })
437
+ ```
438
+
439
+ ### `meta.onHeaderCell` — per-column header spanning
440
+
441
+ Controls `colSpan` and `rowSpan` for the header cell (`<th>`) of this column. Overrides TanStack's auto-computed values.
442
+
443
+ ```ts
444
+ meta: {
445
+ onHeaderCell?: (header: Header<TData, unknown>) => TableCellSpanResult
446
+ }
447
+ ```
448
+
449
+ ```ts
450
+ col.accessor('name', {
451
+ header: 'Full Name',
452
+ meta: {
453
+ onHeaderCell: (header) => ({ colSpan: 2 }),
454
+ },
455
+ })
456
+ ```
457
+
458
+ ---
459
+
460
+ ## FIXED (STICKY) COLUMNS
461
+
462
+ Set `meta.fixed` on any `ColumnDef`:
463
+
464
+ ```ts
465
+ meta: { fixed: 'start' } // sticky left
466
+ meta: { fixed: 'end' } // sticky right
467
+ meta: { fixed: true } // alias for 'start'
468
+ ```
469
+
470
+ **Rules**:
471
+ - Offsets are computed automatically by measuring DOM widths via `ResizeObserver`
472
+ - The rightmost `'start'` column gets a drop-shadow on its right edge
473
+ - The leftmost `'end'` column gets a drop-shadow on its left edge
474
+ - Fixed columns require `scroll.x` to be set, otherwise they overlap content
475
+ - `resizable` should be `false` when using fixed columns (set `resizable={false}`)
476
+
477
+ ---
478
+
479
+ ## COLUMN RESIZING
480
+
481
+ - Enabled by default (`resizable={true}`)
482
+ - Overlay `<div>` handles are positioned at each column's right border
483
+ - Drag starts `mousemove` listener on `document`; drag end cleans up
484
+ - Minimum column width: `40px`
485
+ - Only data columns are resizable (`__selection__` and `__expanded__` are excluded)
486
+ - When any column has been resized, `table-fixed` CSS layout is activated and `<colgroup>` drives widths
487
+ - The last data column always takes remaining space (no explicit width applied)
488
+
489
+ ---
490
+
491
+ ## EVENT DELEGATION
492
+
493
+ The component uses a **single delegated `onClick`** on `<table>` instead of per-cell handlers:
494
+
495
+ 1. Click on `th[data-column-id]` → triggers sorting toggle for that column
496
+ 2. Click on `td.sui-table-selection-cell` → toggles row selection
497
+ 3. Click on `td.sui-table-expand-cell` → toggles row expansion
498
+ 4. Click on `tr[data-row-id]` (body) → fires `onRowClick` prop
499
+ 5. Priority: selection cell > expand cell > body row (each returns early)
500
+
501
+ ---
502
+
503
+ ## BEHAVIORAL RULES
504
+
505
+ ### Controlled vs Uncontrolled for sorting/selection/pagination
506
+ - All TanStack features follow the same pattern: pass `state.*` + `on*Change` for controlled, or omit both for uncontrolled (TanStack manages internally)
507
+ - The component passes controlled state via reactive getters to TanStack's `createSolidTable` (not snapshots), so signal changes propagate correctly
508
+
509
+ ### Multi-sort always enabled
510
+ - Every column header click is treated as a multi-sort event (`isMultiSortEvent: () => true` is hardcoded)
511
+ - Clicking a column adds it to the sort stack; clicking again cycles it (asc → desc → unsorted)
512
+ - There is no way to sort by a single column exclusively — use `options={{ isMultiSortEvent: () => false }}` to override if needed
513
+
514
+ ### Expandable rows — controlled vs uncontrolled
515
+ - **Uncontrolled**: omit `expandedRowKeys`. Use `defaultExpandedRowKeys` for initial state. `defaultExpandAllRows` expands all rows once on mount.
516
+ - **Controlled**: pass `expandedRowKeys` + `onExpandedRowsChange`. You must update the signal yourself.
517
+ - Row IDs used for expansion are TanStack row IDs (auto-indexed `"0"`, `"1"`, ... unless `getRowId` is provided)
518
+
519
+ ### Selection column auto-wiring
520
+ - If `Table.Selection()` is present in `columns`, `enableRowSelection` is automatically set to `true`
521
+ - For `type='radio'`, `enableMultiRowSelection` is automatically set to `false`
522
+ - Only the **first** `Table.Selection()` in the array is rendered; additional ones are silently dropped
523
+
524
+ ### Column `size` and `table-fixed` layout
525
+ - If any `ColumnDef` has an explicit `size` field, `table-fixed` layout + `<colgroup>` is activated
526
+ - Without explicit sizes, columns share width equally (browser default)
527
+ - Sized body cells render content inside `<div class="sui-table-sized-cell">` (truncates overflow with ellipsis)
528
+
529
+ ### Pagination with `paginationProps`
530
+ - Providing `paginationProps` automatically enables `getPaginationRowModel` (client-side pagination)
531
+ - The `<Pagination>` component renders outside `sui-table-root`, inside `sui-table-outer`
532
+ - `current` and `pageSize` are wired from internal table state; do not pass them in `paginationProps`
533
+ - `paginationProps.onChange(page, size)` is called **after** the table's internal state has already been updated
534
+
535
+ ---
536
+
537
+ ## USAGE PATTERNS
538
+
539
+ ### 1. Minimal table
540
+
541
+ ```tsx
542
+ import { Table, createColumnHelper } from 'solid-tom-ui';
543
+
544
+ type Person = { name: string; age: number };
545
+ const col = createColumnHelper<Person>();
546
+
547
+ const columns = [
548
+ col.accessor('name', { header: 'Name' }),
549
+ col.accessor('age', { header: 'Age' }),
550
+ ];
551
+
552
+ const data: Person[] = [{ name: 'Alice', age: 30 }];
553
+
554
+ <Table columns={columns} data={data} />
555
+ ```
556
+
557
+ ### 2. Sortable table (controlled)
558
+
559
+ ```tsx
560
+ const [sorting, setSorting] = createSignal<SortingState>([]);
561
+
562
+ <Table
563
+ columns={columns}
564
+ data={data}
565
+ enableSorting
566
+ sorting={sorting()}
567
+ onSortingChange={setSorting}
568
+ />
569
+ ```
570
+
571
+ Per column, disable sorting:
572
+ ```ts
573
+ col.accessor('id', { header: '#', enableSorting: false })
574
+ ```
575
+
576
+ Note: Every sort click is multi-sort by default. To disable multi-sort, use:
577
+ ```tsx
578
+ <Table options={{ isMultiSortEvent: () => false }} ... />
579
+ ```
580
+
581
+ ### 3. Row selection — checkbox (controlled)
582
+
583
+ ```tsx
584
+ const [rowSelection, setRowSelection] = createSignal<RowSelectionState>({});
585
+
586
+ const columns = [
587
+ Table.Selection({ type: 'checkbox' }),
588
+ col.accessor('name', { header: 'Name' }),
589
+ ];
590
+
591
+ <Table
592
+ columns={columns}
593
+ data={data}
594
+ rowSelection={rowSelection()}
595
+ onRowSelectionChange={setRowSelection}
596
+ getRowId={row => String(row.id)} // use stable IDs
597
+ />
598
+
599
+ // Read selected IDs:
600
+ const selectedIds = () => Object.keys(rowSelection()).filter(k => rowSelection()[k]);
601
+ ```
602
+
603
+ ### 4. Row selection — radio (single-select)
604
+
605
+ ```tsx
606
+ const columns = [
607
+ Table.Selection({ type: 'radio' }),
608
+ col.accessor('name', { header: 'Name' }),
609
+ ];
610
+
611
+ <Table
612
+ columns={columns}
613
+ data={data}
614
+ rowSelection={rowSelection()}
615
+ onRowSelectionChange={setRowSelection}
616
+ getRowId={row => String(row.id)}
617
+ />
618
+ ```
619
+
620
+ ### 5. Row selection — hide select-all
621
+
622
+ ```tsx
623
+ Table.Selection({ type: 'checkbox', hideSelectAll: true })
624
+ ```
625
+
626
+ ### 6. Row selection — custom cell renderer
627
+
628
+ ```tsx
629
+ Table.Selection<Person>({
630
+ type: 'checkbox',
631
+ title: 'Select',
632
+ width: 80,
633
+ renderCell: (checked, record) => (
634
+ <button class={checked ? 'btn-primary' : 'btn-ghost'}>
635
+ {checked ? 'Selected' : 'Select'}
636
+ </button>
637
+ ),
638
+ })
639
+ ```
640
+
641
+ ### 7. Expandable rows — basic (uncontrolled)
642
+
643
+ ```tsx
644
+ const columns = [
645
+ col.accessor('name', { header: 'Name' }),
646
+ Table.Expanded({
647
+ expandedRowRender: (record) => (
648
+ <div>Details: {record.email}</div>
649
+ ),
650
+ }),
651
+ col.accessor('job', { header: 'Job' }),
652
+ ];
653
+
654
+ <Table columns={columns} data={data} border />
655
+ ```
656
+
657
+ ### 8. Expandable rows — custom icon
658
+
659
+ ```tsx
660
+ Table.Expanded({
661
+ expandIcon: (expanded) => (
662
+ <DynamicIcon name={expanded ? 'square-minus' : 'square-plus'} size={16} />
663
+ ),
664
+ expandedRowRender: (record) => <div>{record.email}</div>,
665
+ })
666
+ ```
667
+
668
+ ### 9. Expandable rows — conditional (rowExpandable)
669
+
670
+ ```tsx
671
+ Table.Expanded<Person>({
672
+ rowExpandable: (record) => record.hasDetails === true,
673
+ expandedRowRender: (record) => <div>{record.details}</div>,
674
+ })
675
+ ```
676
+
677
+ ### 10. Expandable rows — controlled
678
+
679
+ ```tsx
680
+ const [expandedKeys, setExpandedKeys] = createSignal<string[]>([]);
681
+
682
+ <Table
683
+ columns={columns}
684
+ data={data}
685
+ expandedRowKeys={expandedKeys()}
686
+ onExpandedRowsChange={setExpandedKeys}
687
+ onExpand={(expanded, record) => console.log(expanded, record)}
688
+ />
689
+
690
+ // Expand all programmatically (row IDs are 0-indexed strings by default):
691
+ setExpandedKeys(data.map((_, i) => String(i)));
692
+ ```
693
+
694
+ ### 11. Expandable rows — expand all on mount
695
+
696
+ ```tsx
697
+ <Table columns={columns} data={data} defaultExpandAllRows />
698
+ ```
699
+
700
+ ### 12. Expandable rows — nested table
701
+
702
+ ```tsx
703
+ Table.Expanded<Person>({
704
+ rowExpandable: record => orders[record.id]?.length > 0,
705
+ expandedRowRender: record => (
706
+ <div class="ml-10">
707
+ <Table columns={orderColumns} data={orders[record.id]} size="xs" border resizable={false} />
708
+ </div>
709
+ ),
710
+ })
711
+ ```
712
+
713
+ ### 13. Scroll — vertical (fixed header)
714
+
715
+ ```tsx
716
+ <Table columns={columns} data={data} scroll={{ y: 400 }} border />
717
+ ```
718
+
719
+ ### 14. Scroll — horizontal
720
+
721
+ ```tsx
722
+ <Table columns={columns} data={data} scroll={{ x: 800 }} />
723
+ // or: auto min-width from column sizes
724
+ <Table columns={columns} data={data} scroll={{ x: true }} />
725
+ ```
726
+
727
+ ### 15. Fixed (sticky) columns
728
+
729
+ ```tsx
730
+ const columns = [
731
+ col.accessor('id', {
732
+ header: '#',
733
+ size: 60,
734
+ meta: { fixed: 'start' }, // sticky left
735
+ }),
736
+ col.accessor('name', { header: 'Name', size: 150 }),
737
+ col.accessor('action', {
738
+ header: 'Action',
739
+ size: 100,
740
+ meta: { fixed: 'end' }, // sticky right
741
+ }),
742
+ ];
743
+
744
+ <Table
745
+ columns={columns}
746
+ data={data}
747
+ scroll={{ x: true, y: 400 }}
748
+ resizable={false} // recommended: disable resizing with fixed columns
749
+ />
750
+ ```
751
+
752
+ ### 16. Borders
753
+
754
+ ```tsx
755
+ <Table columns={columns} data={data} border /> // all borders
756
+ <Table columns={columns} data={data} border={false} /> // no borders
757
+ <Table columns={columns} data={data} border={{ outer: true, horizontal: true }} />
758
+ <Table columns={columns} data={data} border={{ vertical: true }} />
759
+ ```
760
+
761
+ ### 17. Zebra striping
762
+
763
+ ```tsx
764
+ <Table columns={columns} data={data} zebra /> // rows only (default)
765
+ <Table columns={columns} data={data} zebra={{ rows: true }} /> // rows only
766
+ <Table columns={columns} data={data} zebra={{ cols: true }} /> // cols only
767
+ <Table columns={columns} data={data} zebra={{ rows: true, cols: true }} /> // both
768
+ <Table columns={columns} data={data} zebra={false} /> // disabled
769
+ ```
770
+
771
+ Note: `zebra={true}` is equivalent to `zebra={{ rows: true }}` — it only enables row striping, NOT column striping.
772
+
773
+ ### 18. Size variants
774
+
775
+ ```tsx
776
+ <Table columns={columns} data={data} size="xs" />
777
+ <Table columns={columns} data={data} size="sm" />
778
+ <Table columns={columns} data={data} size="md" /> // default
779
+ <Table columns={columns} data={data} size="lg" />
780
+ <Table columns={columns} data={data} size="xl" />
781
+ ```
782
+
783
+ ### 19. Header and footer panels
784
+
785
+ ```tsx
786
+ <Table
787
+ columns={columns}
788
+ data={data}
789
+ border
790
+ rounded="rounded-sm"
791
+ headerPanel={() => (
792
+ <div class="flex items-center justify-between">
793
+ <span class="font-semibold">Employee List</span>
794
+ <span class="text-sm opacity-60">{data.length} records</span>
795
+ </div>
796
+ )}
797
+ footerPanel={() => (
798
+ <div class="flex justify-end gap-2">
799
+ <button onClick={() => setPage(p => p - 1)}>Prev</button>
800
+ <button onClick={() => setPage(p => p + 1)}>Next</button>
801
+ </div>
802
+ )}
803
+ />
804
+ ```
805
+
806
+ ### 20. Empty state
807
+
808
+ ```tsx
809
+ <Table
810
+ columns={columns}
811
+ data={[]}
812
+ emptyContent={<span class="text-gray-400 italic">No records found</span>}
813
+ />
814
+ ```
815
+
816
+ ### 21. Row click handler
817
+
818
+ ```tsx
819
+ <Table
820
+ columns={columns}
821
+ data={data}
822
+ onRowClick={(row, e) => {
823
+ console.log('clicked row:', row.original);
824
+ }}
825
+ />
826
+ ```
827
+
828
+ ### 22. Access TanStack table instance
829
+
830
+ ```tsx
831
+ let tableInstance: TableInstance<Person>;
832
+
833
+ <Table
834
+ columns={columns}
835
+ data={data}
836
+ onTableReady={(table) => { tableInstance = table; }}
837
+ />
838
+
839
+ // Later: tableInstance.getSelectedRowModel(), etc.
840
+ ```
841
+
842
+ ### 23. Client-side pagination (with Pagination component)
843
+
844
+ ```tsx
845
+ // paginationProps wires the <Pagination> component automatically.
846
+ // Pass all data rows; the table slices them by page internally.
847
+ <Table
848
+ columns={columns}
849
+ data={allData} // all rows — table slices by page
850
+ border
851
+ paginationProps={{
852
+ total: allData.length, // required
853
+ showSizeChanger: true,
854
+ }}
855
+ />
856
+ ```
857
+
858
+ ### 24. Server-side pagination
859
+
860
+ ```tsx
861
+ const [pagination, setPagination] = createSignal<PaginationState>({ pageIndex: 0, pageSize: 10 });
862
+ const [serverData, setServerData] = createSignal<Person[]>([]);
863
+
864
+ // Fetch initial page
865
+ onMount(() => fetchPage(0, 10).then(setServerData));
866
+
867
+ <Table
868
+ columns={columns}
869
+ data={serverData()} // only current page's rows
870
+ pagination={pagination()} // seed/control internal page state
871
+ paginationProps={{
872
+ total: totalCount(), // required for correct page count
873
+ onChange: (page, size) => {
874
+ // Called AFTER table state is updated
875
+ setPagination({ pageIndex: page - 1, pageSize: size });
876
+ fetchPage(page - 1, size).then(setServerData);
877
+ },
878
+ }}
879
+ />
880
+ ```
881
+
882
+ ### 25. Column visibility
883
+
884
+ ```tsx
885
+ const [visibility, setVisibility] = createSignal<VisibilityState>({ email: false });
886
+
887
+ <Table
888
+ columns={columns}
889
+ data={data}
890
+ columnVisibility={visibility()}
891
+ onColumnVisibilityChange={setVisibility}
892
+ />
893
+ ```
894
+
895
+ ### 26. Pass-through TanStack options
896
+
897
+ ```tsx
898
+ <Table
899
+ columns={columns}
900
+ data={data}
901
+ options={{
902
+ autoResetPageIndex: false,
903
+ meta: { myCustomMeta: 'value' },
904
+ isMultiSortEvent: () => false, // disable multi-sort
905
+ }}
906
+ />
907
+ ```
908
+
909
+ ### 27. Virtual scrolling — basic (10,000+ rows)
910
+
911
+ ```tsx
912
+ <Table
913
+ columns={columns}
914
+ data={largeData} // 10,000+ rows
915
+ scroll={{ y: 400 }}
916
+ virtual // true → defaults: itemSize=40, overscan=5
917
+ border
918
+ size="md"
919
+ resizable={false}
920
+ getRowId={row => String(row.id)}
921
+ />
922
+ ```
923
+
924
+ ### 28. Virtual scrolling — custom options
925
+
926
+ ```tsx
927
+ // Tune itemSize to match actual row height (size="lg" ≈ 48px)
928
+ <Table
929
+ columns={columns}
930
+ data={largeData}
931
+ scroll={{ y: 420 }}
932
+ virtual={{ itemSize: 48, overscan: 10 }}
933
+ size="lg"
934
+ resizable={false}
935
+ />
936
+ ```
937
+
938
+ ### 29. Virtual scrolling — with row selection
939
+
940
+ ```tsx
941
+ const [rowSelection, setRowSelection] = createSignal<RowSelectionState>({});
942
+
943
+ const columns = [
944
+ Table.Selection({ type: 'checkbox' }),
945
+ col.accessor('name', { header: 'Name' }),
946
+ // ...
947
+ ];
948
+
949
+ <Table
950
+ columns={columns}
951
+ data={largeData}
952
+ scroll={{ y: 400 }}
953
+ virtual
954
+ rowSelection={rowSelection()}
955
+ onRowSelectionChange={setRowSelection}
956
+ getRowId={row => String(row.id)}
957
+ />
958
+ ```
959
+
960
+ ### 30. Virtual scrolling — with sorting
961
+
962
+ ```tsx
963
+ <Table
964
+ columns={columns}
965
+ data={largeData}
966
+ scroll={{ y: 400 }}
967
+ virtual
968
+ enableSorting
969
+ resizable={false}
970
+ getRowId={row => String(row.id)}
971
+ />
972
+ // Sorting in virtual mode shows a loading indicator while the sort executes,
973
+ // then scrolls to the top automatically.
974
+ ```
975
+
976
+ ### 31. Virtual scrolling — infinite scroll auto mode
977
+
978
+ ```tsx
979
+ const TOTAL = 200;
980
+
981
+ const initialRows = fetchPage(0); // stable reference — do NOT recreate on each render
982
+ const [loadedCount, setLoadedCount] = createSignal(initialRows.length);
983
+ const hasMore = () => loadedCount() < TOTAL;
984
+
985
+ const getVirtualData = () =>
986
+ fetchPage(loadedCount()).then(newRows => {
987
+ setLoadedCount(prev => prev + newRows.length);
988
+ return newRows; // component appends automatically
989
+ });
990
+
991
+ <Table
992
+ columns={columns}
993
+ data={initialRows} // stable initial data
994
+ scroll={{ y: 420 }}
995
+ virtual
996
+ border
997
+ size="sm"
998
+ resizable={false}
999
+ getRowId={row => String(row.id)} // required for stable row identity
1000
+ getVirtualData={hasMore() ? getVirtualData : undefined}
1001
+ loadingMore={hasMore() ? 'auto' : 'none'} // 'none' when all data is loaded
1002
+ />
1003
+ // 'auto' mode: getVirtualData is called automatically on scroll near end + auto-fill when viewport not full.
1004
+ // Component appends resolved rows internally — no manual setRows needed.
1005
+ // Concurrent calls are prevented internally — no extra guard needed.
1006
+ ```
1007
+
1008
+ ### 32. Virtual scrolling — infinite scroll manual mode (Load more button)
1009
+
1010
+ ```tsx
1011
+ <Table
1012
+ columns={columns}
1013
+ data={initialRows}
1014
+ scroll={{ y: 420 }}
1015
+ virtual
1016
+ getRowId={row => String(row.id)}
1017
+ getVirtualData={hasMore() ? getVirtualData : undefined}
1018
+ loadingMore={hasMore() ? 'manual' : 'none'} // 'none' hides the button when all loaded
1019
+ />
1020
+ // 'manual' mode: getVirtualData fires ONLY on "Load more" button click, NOT on scroll.
1021
+ ```
1022
+
1023
+ ### 33. Hide table header
1024
+
1025
+ ```tsx
1026
+ <Table columns={columns} data={data} showHeader={false} />
1027
+ ```
1028
+
1029
+ ### 34. Sorting — uncontrolled (simplest)
1030
+
1031
+ ```tsx
1032
+ // No state management needed — table handles sort state internally.
1033
+ // Click any column header to toggle: asc → desc → none.
1034
+ <Table columns={columns} data={data} enableSorting border />
1035
+ ```
1036
+
1037
+ ### 35. Sorting — pre-sorted on mount
1038
+
1039
+ ```tsx
1040
+ // Initialize the sorting signal with a value to sort the table on first render.
1041
+ const [sorting, setSorting] = createSignal<SortingState>([{ id: 'salary', desc: true }]);
1042
+
1043
+ <Table
1044
+ columns={columns}
1045
+ data={data}
1046
+ enableSorting
1047
+ sorting={sorting()}
1048
+ onSortingChange={setSorting}
1049
+ />
1050
+ ```
1051
+
1052
+ ### 36. Sorting — disable sort on specific columns
1053
+
1054
+ ```tsx
1055
+ const columns = [
1056
+ col.accessor('id', { header: '#', size: 60, enableSorting: false }), // not sortable
1057
+ col.accessor('name', { header: 'Name', size: 160 }), // sortable
1058
+ col.accessor('job', { header: 'Job', enableSorting: false }), // not sortable
1059
+ ];
1060
+
1061
+ <Table columns={columns} data={data} enableSorting />
1062
+ ```
1063
+
1064
+ ### 37. Sorting — programmatic multi-sort presets
1065
+
1066
+ ```tsx
1067
+ const [sorting, setSorting] = createSignal<SortingState>([]);
1068
+
1069
+ // Set multiple sort columns at once via external controls:
1070
+ const applyPreset = () =>
1071
+ setSorting([
1072
+ { id: 'department', desc: false },
1073
+ { id: 'salary', desc: true },
1074
+ ]);
1075
+
1076
+ <Table
1077
+ columns={columns}
1078
+ data={data}
1079
+ enableSorting
1080
+ sorting={sorting()}
1081
+ onSortingChange={setSorting}
1082
+ />
1083
+ // Priority badges (1, 2…) appear on each sorted column automatically.
1084
+ ```
1085
+
1086
+ ### 38. Sorting — custom sortingFn
1087
+
1088
+ ```tsx
1089
+ const columns: ColumnDef<Person, any>[] = [
1090
+ col.accessor('joinedAt', {
1091
+ header: 'Joined',
1092
+ // Compare as Date objects (ISO strings sort lexicographically but this shows the pattern)
1093
+ sortingFn: (rowA, rowB, columnId) => {
1094
+ const a = new Date(rowA.getValue<string>(columnId)).getTime();
1095
+ const b = new Date(rowB.getValue<string>(columnId)).getTime();
1096
+ return a < b ? -1 : a > b ? 1 : 0;
1097
+ },
1098
+ }),
1099
+ col.accessor('score', {
1100
+ header: 'Score',
1101
+ sortingFn: 'alphanumeric', // TanStack built-in: handles numbers + mixed strings
1102
+ }),
1103
+ ];
1104
+
1105
+ <Table columns={columns} data={data} enableSorting sorting={sorting()} onSortingChange={setSorting} />
1106
+ ```
1107
+
1108
+ ### 39. Sorting — server-side
1109
+
1110
+ ```tsx
1111
+ const [sorting, setSorting] = createSignal<SortingState>([]);
1112
+ const [serverData, setServerData] = createSignal<Person[]>(initialData);
1113
+
1114
+ const handleSortingChange = (updater: SortingState | ((prev: SortingState) => SortingState)) => {
1115
+ const next = typeof updater === 'function' ? updater(sorting()) : updater;
1116
+ setSorting(next);
1117
+ fetchSortedData(next).then(setServerData); // call your API with the new sort params
1118
+ };
1119
+
1120
+ <Table
1121
+ columns={columns}
1122
+ data={serverData()}
1123
+ enableSorting
1124
+ sorting={sorting()}
1125
+ onSortingChange={handleSortingChange}
1126
+ options={{ manualSorting: true }} // disables client-side row sorting
1127
+ />
1128
+ ```
1129
+
1130
+ ### 40. Column alignment
1131
+
1132
+ ```tsx
1133
+ const columns = [
1134
+ col.accessor('id', {
1135
+ header: '#',
1136
+ size: 60,
1137
+ meta: { align: 'end' }, // right-align header + cells
1138
+ }),
1139
+ col.accessor('name', {
1140
+ header: 'Name',
1141
+ size: 150,
1142
+ meta: { align: 'start' }, // default
1143
+ }),
1144
+ col.accessor('score', {
1145
+ header: 'Score',
1146
+ meta: { align: 'center' }, // center-align
1147
+ }),
1148
+ ];
1149
+ ```
1150
+
1151
+ ### 41. Cell tooltip
1152
+
1153
+ ```tsx
1154
+ const columns = [
1155
+ col.accessor('email', {
1156
+ header: 'Email',
1157
+ meta: {
1158
+ tooltip: {
1159
+ content: (value) => `Send to: ${value as string}`,
1160
+ position: 'top',
1161
+ },
1162
+ },
1163
+ }),
1164
+ col.accessor('notes', {
1165
+ header: 'Notes',
1166
+ meta: {
1167
+ tooltip: { content: 'Click cell to edit' },
1168
+ },
1169
+ }),
1170
+ ];
1171
+
1172
+ <Table columns={columns} data={data} />
1173
+ // Hovering any cell in the tooltip-enabled column shows the tooltip automatically.
1174
+ ```
1175
+
1176
+ ### 42. Cell spanning (colSpan / rowSpan)
1177
+
1178
+ ```tsx
1179
+ // Table-level: applies to all columns unless overridden by meta.onCell
1180
+ <Table
1181
+ columns={columns}
1182
+ data={data}
1183
+ onCell={(cell, rowIndex) => {
1184
+ if (cell.column.id === 'category' && rowIndex === 0) return { colSpan: 2 };
1185
+ return {};
1186
+ }}
1187
+ />
1188
+ ```
1189
+
1190
+ ```tsx
1191
+ // Column-level (higher priority than table-level onCell):
1192
+ const columns = [
1193
+ col.accessor('product', {
1194
+ header: 'Product',
1195
+ meta: {
1196
+ onCell: (cell, rowIndex) => {
1197
+ if (cell.getValue() === 'Total') return { colSpan: 3 };
1198
+ return {};
1199
+ },
1200
+ },
1201
+ }),
1202
+ col.accessor('qty', { header: 'Qty' }),
1203
+ col.accessor('price', { header: 'Price' }),
1204
+ ];
1205
+ // Return { colSpan: 0 } or { rowSpan: 0 } to hide cells covered by a spanning neighbour.
1206
+ ```
1207
+
1208
+ ### 43. Header spanning (via meta.onHeaderCell)
1209
+
1210
+ ```tsx
1211
+ const columns = [
1212
+ col.accessor('firstName', {
1213
+ header: 'First Name',
1214
+ meta: {
1215
+ onHeaderCell: () => ({ colSpan: 2 }), // spans 2 header columns
1216
+ },
1217
+ }),
1218
+ col.accessor('lastName', {
1219
+ header: 'Last Name',
1220
+ // this th will be covered — return colSpan: 0 on the header to hide it
1221
+ meta: {
1222
+ onHeaderCell: () => ({ colSpan: 0 }),
1223
+ },
1224
+ }),
1225
+ ];
1226
+ ```
1227
+
1228
+ ### 44. Pagination above the table
1229
+
1230
+ ```tsx
1231
+ <Table
1232
+ columns={columns}
1233
+ data={allData}
1234
+ paginationProps={{
1235
+ total: allData.length,
1236
+ position: 'start', // renders Pagination above the table
1237
+ }}
1238
+ />
1239
+ ```
1240
+
1241
+ ### 46. Sorting — imperative via onTableReady
1242
+
1243
+ ```tsx
1244
+ let tableInstance: TableInstance<Person> | undefined;
1245
+
1246
+ <Table
1247
+ columns={columns}
1248
+ data={data}
1249
+ enableSorting
1250
+ onTableReady={t => (tableInstance = t)}
1251
+ />
1252
+
1253
+ // Later — sort imperatively without external signal:
1254
+ tableInstance?.setSorting([{ id: 'name', desc: false }]);
1255
+ tableInstance?.setSorting([{ id: 'age', desc: false }, { id: 'score', desc: true }]);
1256
+ tableInstance?.setSorting([]); // clear all sorting
1257
+ ```
1258
+
1259
+ ---
1260
+
1261
+ ## CSS CLASSES (public API)
1262
+
1263
+ | Class | Applied to |
1264
+ |---|---|
1265
+ | `sui-table-outer` | Outermost wrapper `<div>` (contains root + pagination component) |
1266
+ | `sui-table-has-pagination` | `sui-table-outer` when `paginationProps` is set |
1267
+ | `sui-table-root` | Root wrapper `<div>` inside `sui-table-outer` |
1268
+ | `sui-table-border-outer` | Root when `border.outer=true` |
1269
+ | `sui-table-resizable` | Root when `resizable=true` |
1270
+ | `sui-table-resizing` | Root while a column is being dragged |
1271
+ | `sui-table-fixed-header` | Root when `scroll.y` set or any column has `fixed` |
1272
+ | `sui-table-wrapper` | Scroll container `<div>` |
1273
+ | `sui-table-scroll` | Scroll wrapper when scroll is active |
1274
+ | `sui-table` | `<table>` element |
1275
+ | `sui-table-xs/sm/md/lg/xl` | Applied to `<table>` via wrapper class |
1276
+ | `sui-table-zebra-rows` | `<table>` when `zebra.rows=true` |
1277
+ | `sui-table-zebra-cols` | `<table>` when `zebra.cols=true` |
1278
+ | `sui-table-border-horizontal` | `<table>` when `border.horizontal=true` |
1279
+ | `sui-table-border-vertical` | `<table>` when `border.vertical=true` |
1280
+ | `sui-table-th-sortable` | `<th>` when column `getCanSort()` is true |
1281
+ | `sui-table-header-cell` | Inner `<div>` in `<th>` |
1282
+ | `sui-table-header-cell-text` | `<span>` wrapping header text |
1283
+ | `sui-table-sized-header-cell` | Header cell inner div when column has explicit size |
1284
+ | `sui-table-sort-icon` | Sort icon `<span>` in `<th>` |
1285
+ | `sui-table-sort-priority` | Sort priority badge `<span>` (shown when 2+ columns sorted) |
1286
+ | `sui-table-row-selected` | `<tr>` when row is selected |
1287
+ | `sui-table-row-expanded` | `<tr>` when row is expanded |
1288
+ | `sui-table-row-odd` | `<tr>` at even index (0, 2, 4...) — note: class name is "odd" but index is even |
1289
+ | `sui-table-row-even` | `<tr>` at odd index (1, 3, 5...) |
1290
+ | `sui-table-sized-cell` | Inner `<div>` in body `<td>` when column has explicit size (overflow ellipsis) |
1291
+ | `sui-table-empty` | `<td>` for empty state |
1292
+ | `sui-table-panel` | Header/footer panel `<div>` |
1293
+ | `sui-table-panel-bordered` | Header panel when `border.outer=true` |
1294
+ | `sui-table-selection-cell` | `<th>` and `<td>` for selection column |
1295
+ | `sui-table-expand-cell` | `<th>` and `<td>` for expand column |
1296
+ | `sui-table-expand-icon` | Icon wrapper `<span>` in expand cell |
1297
+ | `sui-table-expand-icon-svg` | Default chevron `<svg>` |
1298
+ | `sui-table-expand-icon-expanded` | Added to SVG when row is expanded (rotates 90°) |
1299
+ | `sui-table-expanded-row` | `<tr>` containing expanded content |
1300
+ | `sui-table-expanded-content` | `<td>` inside expanded row |
1301
+ | `sui-table-cell-fixed` | `<th>` / `<td>` for sticky columns |
1302
+ | `sui-table-cell-fixed-start-last` | Last sticky-start column (renders right shadow) |
1303
+ | `sui-table-cell-fixed-end-first` | First sticky-end column (renders left shadow) |
1304
+ | `sui-table-resize-handle` | Resize handle overlay `<div>` |
1305
+ | `sui-table-resize-handle-active` | Handle currently being dragged |
1306
+ | `tbe-tt-cell` | Class applied to the Tooltip root wrapping a cell with `meta.tooltip` |
1307
+
1308
+ ---
1309
+
1310
+ ## CSS CUSTOM PROPERTIES
1311
+
1312
+ Resolved from `color` prop (via `getColor()` utility):
1313
+
1314
+ | Property | Usage |
1315
+ |---|---|
1316
+ | `--color` | Primary accent: sort icons, hover border, resize handle active |
1317
+ | `--hover-bg-color` | `color-mix(color 10%, base-100)` — cell hover background |
1318
+ | `--row-highlight-bg-color` | `color-mix(color 6%, base-100)` — zebra rows, expanded content |
1319
+ | `--row-highlight-border` | `color-mix(color 15%, base-100)` — hover inset border |
1320
+ | `--header-bg-color` | `color-mix(color 20%, base-100)` — thead background |
1321
+
1322
+ ---
1323
+
1324
+ ## INTERNAL COLUMN IDs
1325
+
1326
+ | ID | Created by | Notes |
1327
+ |---|---|---|
1328
+ | `__selection__` | `Table.Selection()` | Do not reference in `columnVisibility` or other state by this ID |
1329
+ | `__expanded__` | `Table.Expanded()` | Do not reference in `columnVisibility` or other state by this ID |
1330
+
1331
+ ---
1332
+
1333
+ ## CONSTRAINTS & EDGE CASES
1334
+
1335
+ - **`getRowId` is required** for selection and controlled expansion to work correctly when `data` has a non-index stable ID. Without it, row IDs are `"0"`, `"1"`, etc. (position-based, breaks on re-order/filter).
1336
+ - **Controlled expanded keys use TanStack row IDs** (not raw data IDs). If `getRowId` returns `String(row.id)`, expanded keys must also use that same format.
1337
+ - **`defaultExpandAllRows` applies once** — subsequent data changes won't re-expand. Use controlled mode for dynamic expand-all.
1338
+ - **`simple` mode does not exist** — unlike Pagination, Table has no simple mode.
1339
+ - **`enableSorting` must be `true` at the table level** even if individual columns have `enableSorting: true` on their `ColumnDef`.
1340
+ - **Multi-sort is always on** — every header click adds to the sort stack. Override with `options={{ isMultiSortEvent: () => false }}`.
1341
+ - **`resizable={false}` is recommended** when using `meta.fixed` columns, as resizing computes widths separately from fixed offset computation (they can diverge).
1342
+ - **Zebra row classes**: `sui-table-row-odd` is applied to rows at even indexes (0, 2, 4...) and `sui-table-row-even` to odd indexes — the naming matches visual appearance, not the index parity.
1343
+ - **`zebra={true}`** enables row striping only (`{ rows: true, cols: false }`), not column striping. Pass `{ rows: true, cols: true }` explicitly for both.
1344
+ - **Column `size` vs resize**: TanStack's `size` on `ColumnDef` only activates `table-fixed` layout if the component detects it at initialization (`colsWithExplicitSize` Set). Columns added after mount via reactive `columns` signal may not update this set — define columns outside the component or in a `createMemo` that runs before first render.
1345
+ - **`options.state` is merged** — `p.options?.state` is spread into the table's `state` object, so you can extend state (e.g. custom meta state) without losing the controlled props.
1346
+ - **`footerPanel` class key**: The `class.tfoot` key is used for the footer panel wrapper div (not a `<tfoot>` element — the actual `<tfoot>` element is not rendered).
1347
+ - **Empty state colspan**: `table.getAllColumns().length` is used (includes hidden columns) — always renders correctly.
1348
+ - **`paginationProps` vs `pagination`**: `paginationProps` enables pagination AND renders the `<Pagination>` component. `pagination` is just a state seed/override. Both can be used together for server-side pagination.
1349
+ - **`loadingMore='manual'` blocks auto-fill**: In `'manual'` mode, the auto-fill behavior (filling viewport when content is too short) is suppressed — the user must click the button.
1350
+ - **`TableExample` / `TableSortingExample` etc.** are demo components only — do not use in production (not exported from `solid-tom-ui`).
1351
+ - **`showHeader=false`** removes the entire `<thead>` from the DOM. Column resizing and fixed-column offset measurement rely on `<thead>` cells, so combining `showHeader={false}` with `resizable` or `meta.fixed` columns may produce incorrect behavior.
1352
+ - **`onCell` is ignored in virtual mode** — cell spanning (`colSpan`/`rowSpan`) only works in non-virtual table rendering. Use it only when `virtual` is not set.
1353
+ - **`meta.onCell` vs `onCell`**: Column-level `meta.onCell` takes priority over the table-level `onCell` prop for the same column.
1354
+ - **`meta.tooltip`**: `usePortal` and `containerId` are injected automatically by the Table — do not set them manually. The `position` prop defaults to `'top'` if omitted.
1355
+ - **`meta.align`**: Affects alignment of both the header cell inner div and the body cell text alignment (`text-align`). Setting `meta.align='end'` right-aligns numbers automatically.
1356
+ - **`paginationProps.position`**: `'start'` renders Pagination above the table inside `sui-table-outer`; `'end'` (default) renders it below.
1357
+
1358
+ ---
1359
+
1360
+ ## DO / DON'T
1361
+
1362
+ **DO**
1363
+ - Import `createColumnHelper` from `solid-tom-ui` (re-exported for convenience)
1364
+ - Always provide `getRowId` when using row selection or controlled expand with business IDs
1365
+ - Use `Table.Selection()` and `Table.Expanded()` as `ColumnDef` entries, not as components
1366
+ - Set `resizable={false}` when using fixed columns
1367
+ - Set `scroll={{ x: true, y: 400 }}` together when you need both fixed header and horizontal scroll with fixed columns
1368
+ - Use `onTableReady` to access the full TanStack table API for operations not covered by props
1369
+ - Use `options` prop to pass TanStack options not exposed directly (e.g. `autoResetPageIndex`, custom row models, `isMultiSortEvent`)
1370
+ - Always set `scroll.y` when using `virtual` — without a fixed viewport height, virtual mode has no effect
1371
+ - Tune `virtual.itemSize` to match your `size` variant row height for smoother scrolling (xs≈26, sm≈33, md≈40, lg≈48, xl≈58)
1372
+ - Set `resizable={false}` when using virtual scrolling
1373
+ - Use `getVirtualData` + `loadingMore` together for infinite scroll — `'auto'` for spinner, `'manual'` for button
1374
+ - The component handles concurrent call prevention internally — no extra guard needed in the `getVirtualData` callback
1375
+ - Always **append** new rows to existing data (`[...prev, ...newRows]`) — replacing the array causes a scroll jump
1376
+ - Provide `getRowId` when using infinite scroll so rows across pages have stable unique IDs
1377
+ - Use `paginationProps` to add a pagination UI below the table; it also enables client-side pagination automatically
1378
+ - Use `meta.align` to right-align numeric columns (`'end'`) or center-align status columns (`'center'`)
1379
+ - Use `meta.tooltip` for per-column cell tooltips — Table handles portal and container injection automatically
1380
+ - Use `meta.onCell` (column-level) for column-specific cell spanning; use table-level `onCell` for cross-column logic
1381
+ - Return `{ colSpan: 0 }` or `{ rowSpan: 0 }` from `onCell`/`meta.onCell` to hide cells covered by a spanning neighbour
1382
+
1383
+ **DON'T**
1384
+ - Don't place `Table.Selection()` or `Table.Expanded()` more than once in the same `columns` array (duplicates are silently dropped)
1385
+ - Don't use `enableSorting` on individual `ColumnDef` only — you must also set `enableSorting` prop on `<Table>`
1386
+ - Don't pass `current`, `pageSize`, `defaultCurrent`, or `defaultPageSize` inside `paginationProps` — they are wired automatically
1387
+ - Don't rely on `__selection__` or `__expanded__` column IDs in external logic
1388
+ - Don't use `defaultExpandAllRows` when you need reactive expand-all — use controlled `expandedRowKeys` instead
1389
+ - Don't pass `color` as a hex string — it must be a design system token (`'info'`, `'primary'`, `'success'`, etc.)
1390
+ - Don't combine `virtual` with row expansion (`Table.Expanded()`) — expanded rows have variable heights that break virtualizer accuracy
1391
+ - Don't use `virtual` without `scroll.y` — the prop has no effect without a bounded scroll viewport
1392
+ - Don't use `getVirtualData` or `loadingMore` outside virtual mode — both props are no-ops without `virtual`
1393
+ - Don't replace the entire `data` array on each page load (infinite scroll) — always append to preserve scroll position
1394
+ - Don't forget to hide `loadingMore` when all data is loaded — leaving it as `'auto'` causes repeated empty fetches; leaving it as `'manual'` keeps showing the button forever
1395
+ - Don't pass `loadingMore='auto'` while not actually fetching — it will suppress the auto-fill trigger
1396
+ - Don't use `onCell` in virtual mode — cell spanning is ignored in virtual rendering
1397
+ - Don't set `usePortal` or `containerId` in `meta.tooltip` — the Table component injects these automatically
1398
+ - Don't use `meta.onCell` and table-level `onCell` for the same column expecting them to merge — column-level wins entirely
1399
+ - Don't assume `zebra={true}` enables column striping — it only enables row striping
1400
+ - Don't combine `showHeader={false}` with `resizable` or fixed columns — header cells are needed for measurement and resize handle positioning
1401
+ ---
1402
+
1403
+ ## Component Conventions
1404
+
1405
+ > **CSS encoding**: internal CSS classes use short encoded names (e.g. `tl01`, `tl02`) per project convention.
1406
+
1407
+ > **Unique IDs**: if this component needs to generate HTML `id` attributes, always use `createUniqueId()` from `solid-js` — never `Math.random()` or `Date.now()`.