@sondor-technology/sondor-components 1.0.9 → 1.0.10

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 (431) hide show
  1. package/dist/components/accordion/accordion.constants.d.ts +5 -0
  2. package/dist/components/accordion/accordion.constants.d.ts.map +1 -0
  3. package/dist/components/accordion/accordion.constants.js +3 -0
  4. package/dist/components/accordion/accordion.constants.js.map +1 -0
  5. package/dist/components/accordion/accordion.d.ts +29 -0
  6. package/dist/components/accordion/accordion.d.ts.map +1 -0
  7. package/dist/components/accordion/accordion.js +226 -0
  8. package/dist/components/accordion/accordion.js.map +1 -0
  9. package/dist/components/alert/alert.constants.d.ts +2 -0
  10. package/dist/components/alert/alert.constants.d.ts.map +1 -1
  11. package/dist/components/alert/alert.d.ts +50 -2
  12. package/dist/components/alert/alert.d.ts.map +1 -1
  13. package/dist/components/alert/alert.js +285 -16
  14. package/dist/components/alert/alert.js.map +1 -1
  15. package/dist/components/avatar/avatar.d.ts +20 -0
  16. package/dist/components/avatar/avatar.d.ts.map +1 -0
  17. package/dist/components/avatar/avatar.js +100 -0
  18. package/dist/components/avatar/avatar.js.map +1 -0
  19. package/dist/components/back-to-top/back-to-top.d.ts +29 -0
  20. package/dist/components/back-to-top/back-to-top.d.ts.map +1 -0
  21. package/dist/components/back-to-top/back-to-top.js +149 -0
  22. package/dist/components/back-to-top/back-to-top.js.map +1 -0
  23. package/dist/components/bar-chart/bar-chart.d.ts +42 -0
  24. package/dist/components/bar-chart/bar-chart.d.ts.map +1 -0
  25. package/dist/components/bar-chart/bar-chart.js +298 -0
  26. package/dist/components/bar-chart/bar-chart.js.map +1 -0
  27. package/dist/components/breadcrumb/breadcrumb.js +2 -2
  28. package/dist/components/button/button.d.ts +1 -0
  29. package/dist/components/button/button.d.ts.map +1 -1
  30. package/dist/components/button/button.js +8 -8
  31. package/dist/components/button/button.js.map +1 -1
  32. package/dist/components/button-group/button-group.js +4 -4
  33. package/dist/components/calendar/calendar.d.ts.map +1 -1
  34. package/dist/components/calendar/calendar.js +11 -9
  35. package/dist/components/calendar/calendar.js.map +1 -1
  36. package/dist/components/chart/chart-base.d.ts +59 -0
  37. package/dist/components/chart/chart-base.d.ts.map +1 -0
  38. package/dist/components/chart/chart-base.js +261 -0
  39. package/dist/components/chart/chart-base.js.map +1 -0
  40. package/dist/components/chart/chart.utils.d.ts +27 -0
  41. package/dist/components/chart/chart.utils.d.ts.map +1 -0
  42. package/dist/components/chart/chart.utils.js +117 -0
  43. package/dist/components/chart/chart.utils.js.map +1 -0
  44. package/dist/components/code-block/code-block.d.ts +5 -0
  45. package/dist/components/code-block/code-block.d.ts.map +1 -1
  46. package/dist/components/code-block/code-block.js +34 -24
  47. package/dist/components/code-block/code-block.js.map +1 -1
  48. package/dist/components/consent/consent.d.ts +63 -0
  49. package/dist/components/consent/consent.d.ts.map +1 -0
  50. package/dist/components/consent/consent.js +327 -0
  51. package/dist/components/consent/consent.js.map +1 -0
  52. package/dist/components/consent/consent.utils.d.ts +36 -0
  53. package/dist/components/consent/consent.utils.d.ts.map +1 -0
  54. package/dist/components/consent/consent.utils.js +82 -0
  55. package/dist/components/consent/consent.utils.js.map +1 -0
  56. package/dist/components/contact/contact.d.ts +22 -0
  57. package/dist/components/contact/contact.d.ts.map +1 -0
  58. package/dist/components/contact/contact.js +83 -0
  59. package/dist/components/contact/contact.js.map +1 -0
  60. package/dist/components/container/container.d.ts +20 -0
  61. package/dist/components/container/container.d.ts.map +1 -0
  62. package/dist/components/container/container.js +68 -0
  63. package/dist/components/container/container.js.map +1 -0
  64. package/dist/components/content-card/content-card.js +4 -4
  65. package/dist/components/context-menu/context-menu.d.ts +89 -0
  66. package/dist/components/context-menu/context-menu.d.ts.map +1 -0
  67. package/dist/components/context-menu/context-menu.js +414 -0
  68. package/dist/components/context-menu/context-menu.js.map +1 -0
  69. package/dist/components/cron-builder/cron-builder.d.ts.map +1 -1
  70. package/dist/components/cron-builder/cron-builder.js +13 -11
  71. package/dist/components/cron-builder/cron-builder.js.map +1 -1
  72. package/dist/components/cta/cta.d.ts +20 -0
  73. package/dist/components/cta/cta.d.ts.map +1 -0
  74. package/dist/components/cta/cta.js +64 -0
  75. package/dist/components/cta/cta.js.map +1 -0
  76. package/dist/components/drawer/drawer.js +6 -6
  77. package/dist/components/faq/faq-item.d.ts +22 -0
  78. package/dist/components/faq/faq-item.d.ts.map +1 -0
  79. package/dist/components/faq/faq-item.js +117 -0
  80. package/dist/components/faq/faq-item.js.map +1 -0
  81. package/dist/components/faq/faq.d.ts +18 -0
  82. package/dist/components/faq/faq.d.ts.map +1 -0
  83. package/dist/components/faq/faq.js +38 -0
  84. package/dist/components/faq/faq.js.map +1 -0
  85. package/dist/components/feature-grid/feature-grid.d.ts +22 -0
  86. package/dist/components/feature-grid/feature-grid.d.ts.map +1 -0
  87. package/dist/components/feature-grid/feature-grid.js +55 -0
  88. package/dist/components/feature-grid/feature-grid.js.map +1 -0
  89. package/dist/components/feature-grid/feature.d.ts +18 -0
  90. package/dist/components/feature-grid/feature.d.ts.map +1 -0
  91. package/dist/components/feature-grid/feature.js +91 -0
  92. package/dist/components/feature-grid/feature.js.map +1 -0
  93. package/dist/components/field/field.js +2 -2
  94. package/dist/components/footer/footer.js +4 -4
  95. package/dist/components/form/form-reset.d.ts +7 -0
  96. package/dist/components/form/form-reset.d.ts.map +1 -0
  97. package/dist/components/form/form-reset.js +47 -0
  98. package/dist/components/form/form-reset.js.map +1 -0
  99. package/dist/components/form/form.d.ts +5 -0
  100. package/dist/components/form/form.d.ts.map +1 -1
  101. package/dist/components/form/form.js +17 -3
  102. package/dist/components/form/form.js.map +1 -1
  103. package/dist/components/grid/grid.d.ts +5 -0
  104. package/dist/components/grid/grid.d.ts.map +1 -1
  105. package/dist/components/grid/grid.js +86 -4
  106. package/dist/components/grid/grid.js.map +1 -1
  107. package/dist/components/heat-map/heat-map.d.ts +39 -0
  108. package/dist/components/heat-map/heat-map.d.ts.map +1 -0
  109. package/dist/components/heat-map/heat-map.js +306 -0
  110. package/dist/components/heat-map/heat-map.js.map +1 -0
  111. package/dist/components/hero/hero.d.ts +26 -0
  112. package/dist/components/hero/hero.d.ts.map +1 -0
  113. package/dist/components/hero/hero.js +132 -0
  114. package/dist/components/hero/hero.js.map +1 -0
  115. package/dist/components/icon/icon-paths.d.ts +84 -0
  116. package/dist/components/icon/icon-paths.d.ts.map +1 -1
  117. package/dist/components/icon/icon-paths.js +89 -0
  118. package/dist/components/icon/icon-paths.js.map +1 -1
  119. package/dist/components/icon/icon.d.ts +2 -0
  120. package/dist/components/icon/icon.d.ts.map +1 -1
  121. package/dist/components/icon/icon.js +10 -1
  122. package/dist/components/icon/icon.js.map +1 -1
  123. package/dist/components/image/image.d.ts +31 -0
  124. package/dist/components/image/image.d.ts.map +1 -0
  125. package/dist/components/image/image.js +179 -0
  126. package/dist/components/image/image.js.map +1 -0
  127. package/dist/components/input/input.js +4 -4
  128. package/dist/components/lazy/lazy.d.ts +34 -0
  129. package/dist/components/lazy/lazy.d.ts.map +1 -0
  130. package/dist/components/lazy/lazy.js +104 -0
  131. package/dist/components/lazy/lazy.js.map +1 -0
  132. package/dist/components/line-chart/line-chart.d.ts +37 -0
  133. package/dist/components/line-chart/line-chart.d.ts.map +1 -0
  134. package/dist/components/line-chart/line-chart.js +271 -0
  135. package/dist/components/line-chart/line-chart.js.map +1 -0
  136. package/dist/components/list/list-item.d.ts +45 -0
  137. package/dist/components/list/list-item.d.ts.map +1 -0
  138. package/dist/components/list/list-item.js +263 -0
  139. package/dist/components/list/list-item.js.map +1 -0
  140. package/dist/components/list/list.d.ts +50 -0
  141. package/dist/components/list/list.d.ts.map +1 -0
  142. package/dist/components/list/list.js +161 -0
  143. package/dist/components/list/list.js.map +1 -0
  144. package/dist/components/logo-cloud/logo-cloud.d.ts +19 -0
  145. package/dist/components/logo-cloud/logo-cloud.d.ts.map +1 -0
  146. package/dist/components/logo-cloud/logo-cloud.js +66 -0
  147. package/dist/components/logo-cloud/logo-cloud.js.map +1 -0
  148. package/dist/components/modal/modal.d.ts +12 -0
  149. package/dist/components/modal/modal.d.ts.map +1 -1
  150. package/dist/components/modal/modal.js +40 -11
  151. package/dist/components/modal/modal.js.map +1 -1
  152. package/dist/components/page-layout/page-layout.js +8 -8
  153. package/dist/components/pagination/pagination.d.ts +15 -0
  154. package/dist/components/pagination/pagination.d.ts.map +1 -0
  155. package/dist/components/pagination/pagination.js +126 -0
  156. package/dist/components/pagination/pagination.js.map +1 -0
  157. package/dist/components/pagination/pagination.utils.d.ts +3 -0
  158. package/dist/components/pagination/pagination.utils.d.ts.map +1 -0
  159. package/dist/components/pagination/pagination.utils.js +19 -0
  160. package/dist/components/pagination/pagination.utils.js.map +1 -0
  161. package/dist/components/pie-chart/pie-chart.d.ts +33 -0
  162. package/dist/components/pie-chart/pie-chart.d.ts.map +1 -0
  163. package/dist/components/pie-chart/pie-chart.js +233 -0
  164. package/dist/components/pie-chart/pie-chart.js.map +1 -0
  165. package/dist/components/pin-input/pin-input.js +4 -4
  166. package/dist/components/popover/popover.d.ts.map +1 -1
  167. package/dist/components/popover/popover.js +1 -3
  168. package/dist/components/popover/popover.js.map +1 -1
  169. package/dist/components/post-list/post-card.d.ts +16 -0
  170. package/dist/components/post-list/post-card.d.ts.map +1 -0
  171. package/dist/components/post-list/post-card.js +22 -0
  172. package/dist/components/post-list/post-card.js.map +1 -0
  173. package/dist/components/post-list/post-list.d.ts +17 -0
  174. package/dist/components/post-list/post-list.d.ts.map +1 -0
  175. package/dist/components/post-list/post-list.js +23 -0
  176. package/dist/components/post-list/post-list.js.map +1 -0
  177. package/dist/components/pricing/pricing-tier.d.ts +23 -0
  178. package/dist/components/pricing/pricing-tier.d.ts.map +1 -0
  179. package/dist/components/pricing/pricing-tier.js +144 -0
  180. package/dist/components/pricing/pricing-tier.js.map +1 -0
  181. package/dist/components/pricing/pricing.d.ts +18 -0
  182. package/dist/components/pricing/pricing.d.ts.map +1 -0
  183. package/dist/components/pricing/pricing.js +38 -0
  184. package/dist/components/pricing/pricing.js.map +1 -0
  185. package/dist/components/progress/progress.d.ts +17 -0
  186. package/dist/components/progress/progress.d.ts.map +1 -0
  187. package/dist/components/progress/progress.js +109 -0
  188. package/dist/components/progress/progress.js.map +1 -0
  189. package/dist/components/project-grid/project-card.d.ts +17 -0
  190. package/dist/components/project-grid/project-card.d.ts.map +1 -0
  191. package/dist/components/project-grid/project-card.js +23 -0
  192. package/dist/components/project-grid/project-card.js.map +1 -0
  193. package/dist/components/project-grid/project-grid.d.ts +17 -0
  194. package/dist/components/project-grid/project-grid.d.ts.map +1 -0
  195. package/dist/components/project-grid/project-grid.js +23 -0
  196. package/dist/components/project-grid/project-grid.js.map +1 -0
  197. package/dist/components/radio/radio.js +1 -1
  198. package/dist/components/reveal/reveal.constants.d.ts +10 -0
  199. package/dist/components/reveal/reveal.constants.d.ts.map +1 -0
  200. package/dist/components/reveal/reveal.constants.js +11 -0
  201. package/dist/components/reveal/reveal.constants.js.map +1 -0
  202. package/dist/components/reveal/reveal.d.ts +64 -0
  203. package/dist/components/reveal/reveal.d.ts.map +1 -0
  204. package/dist/components/reveal/reveal.js +352 -0
  205. package/dist/components/reveal/reveal.js.map +1 -0
  206. package/dist/components/scroll-progress/scroll-progress.d.ts +32 -0
  207. package/dist/components/scroll-progress/scroll-progress.d.ts.map +1 -0
  208. package/dist/components/scroll-progress/scroll-progress.js +120 -0
  209. package/dist/components/scroll-progress/scroll-progress.js.map +1 -0
  210. package/dist/components/section/card-row.d.ts +30 -0
  211. package/dist/components/section/card-row.d.ts.map +1 -0
  212. package/dist/components/section/card-row.js +174 -0
  213. package/dist/components/section/card-row.js.map +1 -0
  214. package/dist/components/section/card.d.ts +27 -0
  215. package/dist/components/section/card.d.ts.map +1 -0
  216. package/dist/components/section/card.js +205 -0
  217. package/dist/components/section/card.js.map +1 -0
  218. package/dist/components/section/row-item.d.ts +22 -0
  219. package/dist/components/section/row-item.d.ts.map +1 -0
  220. package/dist/components/section/row-item.js +53 -0
  221. package/dist/components/section/row-item.js.map +1 -0
  222. package/dist/components/section/section.d.ts +70 -0
  223. package/dist/components/section/section.d.ts.map +1 -0
  224. package/dist/components/section/section.js +240 -0
  225. package/dist/components/section/section.js.map +1 -0
  226. package/dist/components/select/select.js +3 -3
  227. package/dist/components/series-nav/series-nav.d.ts +29 -0
  228. package/dist/components/series-nav/series-nav.d.ts.map +1 -0
  229. package/dist/components/series-nav/series-nav.js +178 -0
  230. package/dist/components/series-nav/series-nav.js.map +1 -0
  231. package/dist/components/site-header/site-header.d.ts +51 -0
  232. package/dist/components/site-header/site-header.d.ts.map +1 -0
  233. package/dist/components/site-header/site-header.js +296 -0
  234. package/dist/components/site-header/site-header.js.map +1 -0
  235. package/dist/components/skeleton/skeleton.js +7 -7
  236. package/dist/components/sparkline/sparkline.d.ts +19 -0
  237. package/dist/components/sparkline/sparkline.d.ts.map +1 -0
  238. package/dist/components/sparkline/sparkline.js +99 -0
  239. package/dist/components/sparkline/sparkline.js.map +1 -0
  240. package/dist/components/spinner/spinner.d.ts +13 -0
  241. package/dist/components/spinner/spinner.d.ts.map +1 -0
  242. package/dist/components/spinner/spinner.js +65 -0
  243. package/dist/components/spinner/spinner.js.map +1 -0
  244. package/dist/components/split/split.d.ts +23 -0
  245. package/dist/components/split/split.d.ts.map +1 -0
  246. package/dist/components/split/split.js +104 -0
  247. package/dist/components/split/split.js.map +1 -0
  248. package/dist/components/stack/stack.d.ts +21 -0
  249. package/dist/components/stack/stack.d.ts.map +1 -0
  250. package/dist/components/stack/stack.js +102 -0
  251. package/dist/components/stack/stack.js.map +1 -0
  252. package/dist/components/stat-card/stat-card.d.ts +35 -0
  253. package/dist/components/stat-card/stat-card.d.ts.map +1 -0
  254. package/dist/components/stat-card/stat-card.js +199 -0
  255. package/dist/components/stat-card/stat-card.js.map +1 -0
  256. package/dist/components/stats/stat.d.ts +16 -0
  257. package/dist/components/stats/stat.d.ts.map +1 -0
  258. package/dist/components/stats/stat.js +51 -0
  259. package/dist/components/stats/stat.js.map +1 -0
  260. package/dist/components/stats/stats.d.ts +19 -0
  261. package/dist/components/stats/stats.d.ts.map +1 -0
  262. package/dist/components/stats/stats.js +45 -0
  263. package/dist/components/stats/stats.js.map +1 -0
  264. package/dist/components/switch/switch.js +2 -2
  265. package/dist/components/table/data-table.d.ts +115 -27
  266. package/dist/components/table/data-table.d.ts.map +1 -1
  267. package/dist/components/table/data-table.js +1012 -411
  268. package/dist/components/table/data-table.js.map +1 -1
  269. package/dist/components/table/data-table.utils.d.ts +81 -0
  270. package/dist/components/table/data-table.utils.d.ts.map +1 -0
  271. package/dist/components/table/data-table.utils.js +208 -0
  272. package/dist/components/table/data-table.utils.js.map +1 -0
  273. package/dist/components/table/table.d.ts +28 -0
  274. package/dist/components/table/table.d.ts.map +1 -1
  275. package/dist/components/table/table.js +161 -33
  276. package/dist/components/table/table.js.map +1 -1
  277. package/dist/components/team/person.d.ts +19 -0
  278. package/dist/components/team/person.d.ts.map +1 -0
  279. package/dist/components/team/person.js +123 -0
  280. package/dist/components/team/person.js.map +1 -0
  281. package/dist/components/team/team.d.ts +18 -0
  282. package/dist/components/team/team.d.ts.map +1 -0
  283. package/dist/components/team/team.js +36 -0
  284. package/dist/components/team/team.js.map +1 -0
  285. package/dist/components/testimonials/testimonial.d.ts +18 -0
  286. package/dist/components/testimonials/testimonial.d.ts.map +1 -0
  287. package/dist/components/testimonials/testimonial.js +115 -0
  288. package/dist/components/testimonials/testimonial.js.map +1 -0
  289. package/dist/components/testimonials/testimonials.d.ts +18 -0
  290. package/dist/components/testimonials/testimonials.d.ts.map +1 -0
  291. package/dist/components/testimonials/testimonials.js +36 -0
  292. package/dist/components/testimonials/testimonials.js.map +1 -0
  293. package/dist/components/textarea/textarea.js +3 -3
  294. package/dist/components/theme-toggle/theme-toggle.js +1 -1
  295. package/dist/components/time-picker/time-picker.js +3 -3
  296. package/dist/components/timeline/timeline-item.d.ts +18 -0
  297. package/dist/components/timeline/timeline-item.d.ts.map +1 -0
  298. package/dist/components/timeline/timeline-item.js +102 -0
  299. package/dist/components/timeline/timeline-item.js.map +1 -0
  300. package/dist/components/timeline/timeline.d.ts +18 -0
  301. package/dist/components/timeline/timeline.d.ts.map +1 -0
  302. package/dist/components/timeline/timeline.js +30 -0
  303. package/dist/components/timeline/timeline.js.map +1 -0
  304. package/dist/components/toast/toast.d.ts +33 -0
  305. package/dist/components/toast/toast.d.ts.map +1 -0
  306. package/dist/components/toast/toast.js +147 -0
  307. package/dist/components/toast/toast.js.map +1 -0
  308. package/dist/components/toggle-group/toggle-button.d.ts +2 -0
  309. package/dist/components/toggle-group/toggle-button.d.ts.map +1 -1
  310. package/dist/components/toggle-group/toggle-button.js +12 -4
  311. package/dist/components/toggle-group/toggle-button.js.map +1 -1
  312. package/dist/components/toggle-group/toggle-group.js +4 -4
  313. package/dist/components/tooltip/tooltip.js +21 -21
  314. package/dist/components/vertical-nav/vertical-nav-group.js +3 -3
  315. package/dist/components/vertical-nav/vertical-nav-item.js +4 -4
  316. package/dist/components/video-embed/video-embed.d.ts +37 -0
  317. package/dist/components/video-embed/video-embed.d.ts.map +1 -0
  318. package/dist/components/video-embed/video-embed.js +183 -0
  319. package/dist/components/video-embed/video-embed.js.map +1 -0
  320. package/dist/index.d.ts +107 -0
  321. package/dist/index.d.ts.map +1 -0
  322. package/dist/index.js +104 -0
  323. package/dist/index.js.map +1 -0
  324. package/dist/styles/index.css +205 -2
  325. package/dist/styles/reset.d.ts.map +1 -1
  326. package/dist/styles/reset.js +5 -0
  327. package/dist/styles/reset.js.map +1 -1
  328. package/package.json +210 -7
  329. package/src/components/accordion/accordion.constants.ts +5 -0
  330. package/src/components/accordion/accordion.ts +209 -0
  331. package/src/components/alert/alert.constants.ts +3 -0
  332. package/src/components/alert/alert.ts +284 -17
  333. package/src/components/avatar/avatar.ts +84 -0
  334. package/src/components/back-to-top/back-to-top.ts +140 -0
  335. package/src/components/bar-chart/bar-chart.ts +295 -0
  336. package/src/components/breadcrumb/breadcrumb.ts +2 -2
  337. package/src/components/button/button.ts +9 -8
  338. package/src/components/button-group/button-group.ts +4 -4
  339. package/src/components/calendar/calendar.ts +12 -9
  340. package/src/components/chart/chart-base.ts +275 -0
  341. package/src/components/chart/chart.utils.ts +140 -0
  342. package/src/components/code-block/code-block.ts +35 -24
  343. package/src/components/consent/consent.ts +312 -0
  344. package/src/components/consent/consent.utils.ts +110 -0
  345. package/src/components/contact/contact.ts +83 -0
  346. package/src/components/container/container.ts +60 -0
  347. package/src/components/content-card/content-card.ts +4 -4
  348. package/src/components/context-menu/context-menu.ts +426 -0
  349. package/src/components/cron-builder/cron-builder.ts +21 -18
  350. package/src/components/cta/cta.ts +64 -0
  351. package/src/components/drawer/drawer.ts +6 -6
  352. package/src/components/faq/faq-item.ts +110 -0
  353. package/src/components/faq/faq.ts +40 -0
  354. package/src/components/feature-grid/feature-grid.ts +52 -0
  355. package/src/components/feature-grid/feature.ts +84 -0
  356. package/src/components/field/field.ts +2 -2
  357. package/src/components/footer/footer.ts +4 -4
  358. package/src/components/form/form-reset.ts +45 -0
  359. package/src/components/form/form.ts +17 -3
  360. package/src/components/grid/grid.ts +73 -4
  361. package/src/components/heat-map/heat-map.ts +292 -0
  362. package/src/components/hero/hero.ts +132 -0
  363. package/src/components/icon/icon-paths.ts +92 -1
  364. package/src/components/icon/icon.ts +8 -1
  365. package/src/components/image/image.ts +165 -0
  366. package/src/components/input/input.ts +4 -4
  367. package/src/components/lazy/lazy.ts +94 -0
  368. package/src/components/line-chart/line-chart.ts +271 -0
  369. package/src/components/list/list-item.ts +225 -0
  370. package/src/components/list/list.ts +157 -0
  371. package/src/components/logo-cloud/logo-cloud.ts +65 -0
  372. package/src/components/modal/modal.ts +37 -11
  373. package/src/components/page-layout/page-layout.ts +8 -8
  374. package/src/components/pagination/pagination.ts +120 -0
  375. package/src/components/pagination/pagination.utils.ts +14 -0
  376. package/src/components/pie-chart/pie-chart.ts +230 -0
  377. package/src/components/pin-input/pin-input.ts +4 -4
  378. package/src/components/popover/popover.ts +1 -3
  379. package/src/components/post-list/post-card.ts +18 -0
  380. package/src/components/post-list/post-list.ts +19 -0
  381. package/src/components/pricing/pricing-tier.ts +132 -0
  382. package/src/components/pricing/pricing.ts +39 -0
  383. package/src/components/progress/progress.ts +95 -0
  384. package/src/components/project-grid/project-card.ts +19 -0
  385. package/src/components/project-grid/project-grid.ts +19 -0
  386. package/src/components/radio/radio.ts +1 -1
  387. package/src/components/reveal/reveal.constants.ts +20 -0
  388. package/src/components/reveal/reveal.ts +344 -0
  389. package/src/components/scroll-progress/scroll-progress.ts +119 -0
  390. package/src/components/section/card-row.ts +152 -0
  391. package/src/components/section/card.ts +197 -0
  392. package/src/components/section/row-item.ts +38 -0
  393. package/src/components/section/section.ts +232 -0
  394. package/src/components/select/select.ts +3 -3
  395. package/src/components/series-nav/series-nav.ts +164 -0
  396. package/src/components/site-header/site-header.ts +276 -0
  397. package/src/components/skeleton/skeleton.ts +7 -7
  398. package/src/components/sparkline/sparkline.ts +83 -0
  399. package/src/components/spinner/spinner.ts +55 -0
  400. package/src/components/split/split.ts +106 -0
  401. package/src/components/stack/stack.ts +88 -0
  402. package/src/components/stat-card/stat-card.ts +179 -0
  403. package/src/components/stats/stat.ts +49 -0
  404. package/src/components/stats/stats.ts +47 -0
  405. package/src/components/switch/switch.ts +2 -2
  406. package/src/components/table/data-table.ts +1015 -425
  407. package/src/components/table/data-table.utils.ts +276 -0
  408. package/src/components/table/table.ts +168 -38
  409. package/src/components/team/person.ts +113 -0
  410. package/src/components/team/team.ts +37 -0
  411. package/src/components/testimonials/testimonial.ts +108 -0
  412. package/src/components/testimonials/testimonials.ts +37 -0
  413. package/src/components/textarea/textarea.ts +3 -3
  414. package/src/components/theme-toggle/theme-toggle.ts +1 -1
  415. package/src/components/time-picker/time-picker.ts +3 -3
  416. package/src/components/timeline/timeline-item.ts +100 -0
  417. package/src/components/timeline/timeline.ts +31 -0
  418. package/src/components/toast/toast.ts +153 -0
  419. package/src/components/toggle-group/toggle-button.ts +9 -4
  420. package/src/components/toggle-group/toggle-group.ts +4 -4
  421. package/src/components/tooltip/tooltip.ts +21 -21
  422. package/src/components/vertical-nav/vertical-nav-group.ts +3 -3
  423. package/src/components/vertical-nav/vertical-nav-item.ts +4 -4
  424. package/src/components/video-embed/video-embed.ts +162 -0
  425. package/src/index.ts +108 -0
  426. package/src/styles/globals.css +63 -0
  427. package/src/styles/index.css +3 -1
  428. package/src/styles/prose.css +154 -0
  429. package/src/styles/reset.ts +5 -0
  430. package/src/styles/theme.css +53 -1
  431. package/src/styles/typography.css +1 -0
@@ -4,385 +4,743 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { LitElement, html, css } from "lit";
8
- import { customElement, property, state } from "lit/decorators.js";
7
+ import { LitElement, html, css, nothing } from "lit";
8
+ import { customElement, property, query, state } from "lit/decorators.js";
9
9
  import { classMap } from "lit/directives/class-map.js";
10
- import { resetStyles } from "../../styles/reset.js";
11
10
  import { ifDefined } from "lit/directives/if-defined.js";
11
+ import { resetStyles } from "../../styles/reset.js";
12
+ import "../icon/icon.js";
13
+ import "../skeleton/skeleton.js";
14
+ import "../pagination/pagination.js";
15
+ import "../context-menu/context-menu.js";
16
+ import { applyFilters, cellValue, defaultOperator, deriveOptions, describeFilter, isFilterComplete, nextSort, operatorsFor, paginate, searchRows, sortRows, } from "./data-table.utils.js";
17
+ const DEBOUNCE_MS = 350;
18
+ const SKELETON_ROWS = 5;
19
+ /**
20
+ * Data table with search, multi-column filtering, multi-column sorting, pagination, column
21
+ * visibility and ordering, and per-row action menus.
22
+ *
23
+ * Data handling: by default the table filters, sorts and pages `data` itself. Set `server-side`
24
+ * (or `total-rows`) to handle that on a server instead: the table then shows `data` as given
25
+ * and reports every change through `st-data-change`.
26
+ *
27
+ * Events (bubble, composed):
28
+ * - `st-data-change` `{ page, pageSize, search, sort, filters }` on any user change.
29
+ * - `st-row-click` the row object, when `clickable-rows` is set.
30
+ * - `st-row-action` `{ value, item, row }` when a row menu item is chosen.
31
+ */
12
32
  let StDataTable = class StDataTable extends LitElement {
13
33
  constructor() {
14
34
  super(...arguments);
15
35
  this.columns = [];
16
36
  this.data = [];
37
+ /** Total rows on the server. Implies server-side handling. */
17
38
  this.totalRows = 0;
39
+ this.serverSide = false;
18
40
  this.page = 1;
19
41
  this.pageSize = 10;
20
- this.multiSort = false;
42
+ this.pageSizeOptions = [10, 25, 50, 100];
43
+ /** Free-text search across searchable columns. */
44
+ this.search = "";
45
+ this.sort = [];
46
+ this.filters = [];
47
+ /** Sort by several columns with Shift+click (on by default). */
48
+ this.multiSort = true;
49
+ this.singleSort = false;
21
50
  this.loading = false;
51
+ this.clickableRows = false;
52
+ this.dense = false;
53
+ this.striped = false;
54
+ this.stickyHeader = false;
55
+ /**
56
+ * Reserves space for this many rows so the footer never moves between pages. Pages with fewer
57
+ * rows are padded with blank space; pages with more (a larger page size) scroll inside the
58
+ * table while the header and footer stay put. Cells stay on one line (long text is truncated).
59
+ */
60
+ this.fixedRows = 0;
61
+ this.caption = "";
62
+ this.emptyText = "No data available.";
63
+ this.searchPlaceholder = "Search…";
64
+ this.hideSearch = false;
65
+ this.hideColumnMenu = false;
66
+ this.fixedColumns = false;
67
+ /** Column used to name a row in assistive text, e.g. "Actions for Ada". Defaults to the first. */
68
+ this.rowLabelKey = "";
22
69
  this.internalColumns = [];
23
- this.sortState = [];
24
- this.searchQuery = "";
25
- this.showColumnMenu = false;
26
- this.draggedColumnKey = null;
27
- this.handleOutsideClick = (e) => {
28
- const path = e.composedPath();
29
- const toggleWrapper = this.shadowRoot?.querySelector(".columns-toggle-wrapper");
30
- // 🚀 THE FIX: Use composedPath() to pierce the Shadow DOM and check if
31
- // the click originated from inside the wrapper element.
32
- if (toggleWrapper && !path.includes(toggleWrapper)) {
33
- this.showColumnMenu = false;
34
- }
35
- };
36
- }
37
- willUpdate(changedProperties) {
38
- // 🚀 FIX: Properly sync dynamically updated columns while preserving user visibility states
39
- if (changedProperties.has("columns") && this.columns) {
40
- this.internalColumns = this.columns.map((newCol) => {
41
- const existing = this.internalColumns.find((ic) => ic.key === newCol.key);
42
- return { ...newCol, hidden: existing ? existing.hidden : newCol.hidden };
70
+ this.searchDraft = "";
71
+ this.filtersOpen = false;
72
+ this.announcement = "";
73
+ this.menuOpenFor = null;
74
+ this.view = { rows: [], total: 0, page: 1, totalPages: 1, from: 0, to: 0 };
75
+ this.menuMode = "row";
76
+ this.draggedKey = null;
77
+ this.announceNext = false;
78
+ }
79
+ // ---------------------------------------------------------------- lifecycle
80
+ willUpdate(changed) {
81
+ if (changed.has("columns") && this.columns) {
82
+ // Keep the user's visibility and order when the columns array is replaced.
83
+ const previous = this.internalColumns;
84
+ const merged = this.columns.map((col) => {
85
+ const existing = previous.find((c) => c.key === col.key);
86
+ return { ...col, hidden: existing ? existing.hidden : col.hidden };
43
87
  });
88
+ const order = previous.map((c) => c.key);
89
+ this.internalColumns = previous.length
90
+ ? [...merged].sort((a, b) => {
91
+ const ai = order.indexOf(a.key);
92
+ const bi = order.indexOf(b.key);
93
+ return (ai === -1 ? Infinity : ai) - (bi === -1 ? Infinity : bi);
94
+ })
95
+ : merged;
96
+ }
97
+ if (changed.has("search") && this.search !== this.searchDraft)
98
+ this.searchDraft = this.search;
99
+ this.view = this.computeView();
100
+ if (!this.isServer && this.page !== this.view.page)
101
+ this.page = this.view.page;
102
+ }
103
+ updated() {
104
+ this.applyFixedHeight();
105
+ if (this.announceNext) {
106
+ this.announceNext = false;
107
+ const n = this.view.total;
108
+ this.announcement = `${n} ${n === 1 ? "result" : "results"}`;
44
109
  }
45
110
  }
46
111
  connectedCallback() {
47
112
  super.connectedCallback();
48
- document.addEventListener("click", this.handleOutsideClick);
113
+ this.resizeObserver = new ResizeObserver(() => this.applyFixedHeight());
114
+ this.resizeObserver.observe(this);
115
+ }
116
+ /**
117
+ * Caps the scroll area at the header plus `fixedRows` real rows. Measuring (rather than
118
+ * calculating) keeps it exact whatever the font, density or borders.
119
+ */
120
+ applyFixedHeight() {
121
+ const wrapper = this.renderRoot.querySelector(".table-wrapper");
122
+ if (!wrapper)
123
+ return;
124
+ if (this.fixedRows <= 0) {
125
+ wrapper.style.maxHeight = "";
126
+ this.style.removeProperty("--st-data-table-fixed-rows");
127
+ return;
128
+ }
129
+ this.style.setProperty("--st-data-table-fixed-rows", String(this.fixedRows));
130
+ const head = wrapper.querySelector("thead")?.getBoundingClientRect().height ?? 0;
131
+ const rows = Array.from(wrapper.querySelectorAll("tbody tr:not(.spacer)"))
132
+ .filter((row) => !row.querySelector("td.empty"))
133
+ .slice(0, this.fixedRows);
134
+ if (!rows.length)
135
+ return;
136
+ const rowHeight = rows[0].getBoundingClientRect().height;
137
+ wrapper.style.maxHeight = `${Math.ceil(head + rowHeight * this.fixedRows + 1)}px`;
49
138
  }
50
139
  disconnectedCallback() {
51
- document.removeEventListener("click", this.handleOutsideClick);
140
+ this.resizeObserver?.disconnect();
141
+ window.clearTimeout(this.debounce);
52
142
  super.disconnectedCallback();
53
143
  }
54
- emitChange() {
144
+ // --------------------------------------------------------------- derivations
145
+ get isServer() {
146
+ return this.serverSide || this.totalRows > 0;
147
+ }
148
+ get canMultiSort() {
149
+ return this.multiSort && !this.singleSort;
150
+ }
151
+ get visibleColumns() {
152
+ return this.internalColumns.filter((c) => !c.hidden);
153
+ }
154
+ get filterColumns() {
155
+ return this.internalColumns.filter((c) => c.filter);
156
+ }
157
+ get activeFilters() {
158
+ return this.filters.filter((f) => isFilterComplete(f, this.internalColumns));
159
+ }
160
+ get hasQuery() {
161
+ return this.activeFilters.length > 0 || this.search.trim() !== "";
162
+ }
163
+ computeView() {
164
+ if (this.isServer) {
165
+ const total = this.totalRows > 0 ? this.totalRows : this.data.length;
166
+ const totalPages = Math.max(1, Math.ceil(total / Math.max(1, this.pageSize)));
167
+ const from = this.data.length ? (this.page - 1) * this.pageSize + 1 : 0;
168
+ return {
169
+ rows: this.data,
170
+ total,
171
+ page: this.page,
172
+ totalPages,
173
+ from,
174
+ to: this.data.length ? from + this.data.length - 1 : 0,
175
+ };
176
+ }
177
+ const columns = this.internalColumns;
178
+ let rows = searchRows(this.data, this.search, columns);
179
+ rows = applyFilters(rows, this.filters, columns);
180
+ rows = sortRows(rows, this.sort, columns);
181
+ return paginate(rows, this.page, this.pageSize);
182
+ }
183
+ optionsFor(column) {
184
+ return column.options ?? deriveOptions(this.data, column);
185
+ }
186
+ // ------------------------------------------------------------------- events
187
+ emitChange(announce = true) {
188
+ this.announceNext = announce;
55
189
  this.dispatchEvent(new CustomEvent("st-data-change", {
56
190
  detail: {
57
191
  page: this.page,
58
192
  pageSize: this.pageSize,
59
- search: this.searchQuery,
60
- sort: this.sortState,
193
+ search: this.search,
194
+ sort: this.sort,
195
+ filters: this.activeFilters,
61
196
  },
62
197
  bubbles: true,
63
198
  composed: true,
64
199
  }));
65
200
  }
66
- handleSearchInput(e) {
201
+ emitDebounced() {
202
+ window.clearTimeout(this.debounce);
203
+ this.debounce = window.setTimeout(() => this.emitChange(), DEBOUNCE_MS);
204
+ }
205
+ onSearchInput(e) {
67
206
  if (this.loading)
68
207
  return;
69
- const val = e.target.value;
70
- window.clearTimeout(this.searchTimeout);
71
- this.searchTimeout = window.setTimeout(() => {
72
- this.searchQuery = val;
208
+ this.searchDraft = e.target.value;
209
+ window.clearTimeout(this.debounce);
210
+ this.debounce = window.setTimeout(() => {
211
+ this.search = this.searchDraft;
73
212
  this.page = 1;
74
213
  this.emitChange();
75
- }, 350);
214
+ }, DEBOUNCE_MS);
215
+ }
216
+ clearSearch() {
217
+ this.searchDraft = "";
218
+ this.search = "";
219
+ this.page = 1;
220
+ this.emitChange();
76
221
  }
77
- handleSort(key, e) {
222
+ onSort(key, e) {
78
223
  if (this.loading)
79
224
  return;
80
- const isShift = e.shiftKey && this.multiSort;
81
- const existingIndex = this.sortState.findIndex((s) => s.key === key);
82
- let newDirection = "asc";
83
- if (existingIndex !== -1) {
84
- newDirection = this.sortState[existingIndex].direction === "asc" ? "desc" : null;
85
- }
86
- let newSortState = [...this.sortState];
87
- if (isShift) {
88
- if (newDirection) {
89
- if (existingIndex !== -1) {
90
- newSortState[existingIndex].direction = newDirection;
91
- }
92
- else {
93
- newSortState.push({ key, direction: newDirection });
94
- }
95
- }
96
- else {
97
- newSortState.splice(existingIndex, 1);
98
- }
99
- }
100
- else {
101
- if (newDirection) {
102
- newSortState = [{ key, direction: newDirection }];
103
- }
104
- else {
105
- newSortState = [];
106
- }
107
- }
108
- this.sortState = newSortState;
225
+ this.sort = nextSort(this.sort, key, e.shiftKey && this.canMultiSort);
109
226
  this.page = 1;
110
227
  this.emitChange();
111
228
  }
112
- get totalPages() {
113
- return Math.max(1, Math.ceil(this.totalRows / this.pageSize));
229
+ removeSort(key) {
230
+ this.sort = this.sort.filter((s) => s.key !== key);
231
+ this.page = 1;
232
+ this.emitChange();
114
233
  }
115
- prevPage() {
116
- if (!this.loading && this.page > 1) {
117
- this.page--;
118
- this.emitChange();
119
- }
234
+ goToPage(page) {
235
+ if (this.loading || page === this.page)
236
+ return;
237
+ this.page = page;
238
+ this.emitChange(false);
239
+ }
240
+ onPageSize(e) {
241
+ this.pageSize = Number(e.target.value);
242
+ this.page = 1;
243
+ this.emitChange(false);
244
+ }
245
+ clearAll() {
246
+ this.searchDraft = "";
247
+ this.search = "";
248
+ this.filters = [];
249
+ this.page = 1;
250
+ this.emitChange();
251
+ }
252
+ // ------------------------------------------------------------------ filters
253
+ addFilter() {
254
+ const column = this.filterColumns[0];
255
+ if (!column)
256
+ return;
257
+ this.filters = [...this.filters, { key: column.key, op: defaultOperator(column.filter), value: "" }];
258
+ this.filtersOpen = true;
120
259
  }
121
- nextPage() {
122
- if (!this.loading && this.page < this.totalPages) {
123
- this.page++;
260
+ updateFilter(index, patch, debounce = false) {
261
+ this.filters = this.filters.map((f, i) => (i === index ? { ...f, ...patch } : f));
262
+ this.page = 1;
263
+ if (debounce)
264
+ this.emitDebounced();
265
+ else
124
266
  this.emitChange();
125
- }
126
267
  }
127
- toggleColumnVisibility(key) {
128
- this.internalColumns = this.internalColumns.map((col) => col.key === key ? { ...col, hidden: !col.hidden } : col);
268
+ onFilterColumn(index, key) {
269
+ const column = this.internalColumns.find((c) => c.key === key);
270
+ if (!column?.filter)
271
+ return;
272
+ this.updateFilter(index, { key, op: defaultOperator(column.filter), value: "" });
273
+ }
274
+ onFilterOperator(index, op) {
275
+ const column = this.internalColumns.find((c) => c.key === this.filters[index].key);
276
+ const info = operatorsFor(column.filter).find((o) => o.op === op);
277
+ this.updateFilter(index, { op, value: info?.needsValue ? this.filters[index].value : "" });
278
+ }
279
+ removeFilter(index) {
280
+ this.filters = this.filters.filter((_, i) => i !== index);
281
+ this.page = 1;
282
+ this.emitChange();
283
+ }
284
+ // ------------------------------------------------------------------ columns
285
+ columnItems() {
286
+ const visible = this.visibleColumns.length;
287
+ return this.internalColumns.map((c) => ({
288
+ label: c.header,
289
+ value: c.key,
290
+ checked: !c.hidden,
291
+ keepOpen: true,
292
+ // Always keep at least one column on screen.
293
+ disabled: !c.hidden && visible === 1,
294
+ }));
295
+ }
296
+ openColumnMenu(e) {
297
+ this.menuMode = "columns";
298
+ this.menuOpenFor = null;
299
+ this.menu.label = "Columns";
300
+ this.menu.items = this.columnItems();
301
+ this.menu.showAt(e.currentTarget);
302
+ }
303
+ toggleColumn(key) {
304
+ this.internalColumns = this.internalColumns.map((c) => (c.key === key ? { ...c, hidden: !c.hidden } : c));
305
+ this.menu.items = this.columnItems();
306
+ }
307
+ moveColumn(from, to) {
308
+ if (from === to)
309
+ return;
310
+ const cols = [...this.internalColumns];
311
+ const fromIndex = cols.findIndex((c) => c.key === from);
312
+ const toIndex = cols.findIndex((c) => c.key === to);
313
+ if (fromIndex < 0 || toIndex < 0)
314
+ return;
315
+ const [moved] = cols.splice(fromIndex, 1);
316
+ cols.splice(toIndex, 0, moved);
317
+ this.internalColumns = cols;
318
+ }
319
+ onHeaderKeydown(e, key) {
320
+ if (this.fixedColumns || !e.altKey || (e.key !== "ArrowLeft" && e.key !== "ArrowRight"))
321
+ return;
322
+ e.preventDefault();
323
+ const visible = this.visibleColumns;
324
+ const index = visible.findIndex((c) => c.key === key);
325
+ const target = visible[index + (e.key === "ArrowLeft" ? -1 : 1)];
326
+ if (target) {
327
+ this.moveColumn(key, target.key);
328
+ this.updateComplete.then(() => this.renderRoot.querySelector(`[data-col="${key}"] .th-btn, [data-col="${key}"]`)?.focus());
329
+ }
129
330
  }
130
- handleDragStart(e, key) {
131
- this.draggedColumnKey = key;
331
+ onDragStart(e, key) {
332
+ this.draggedKey = key;
132
333
  if (e.dataTransfer) {
133
334
  e.dataTransfer.effectAllowed = "move";
134
335
  e.dataTransfer.setData("text/plain", key);
135
336
  }
136
337
  }
137
- handleDragOver(e) {
338
+ onDragOver(e) {
138
339
  e.preventDefault();
139
- if (e.dataTransfer)
140
- e.dataTransfer.dropEffect = "move";
141
- const target = e.target.closest("th");
142
- if (target)
143
- target.classList.add("drag-over");
144
- }
145
- handleDragLeave(e) {
146
- const target = e.target.closest("th");
147
- if (target)
148
- target.classList.remove("drag-over");
149
- }
150
- handleDrop(e, targetKey) {
340
+ e.currentTarget.classList.add("drag-over");
341
+ }
342
+ onDrop(e, key) {
151
343
  e.preventDefault();
152
- const targetEl = e.target.closest("th");
153
- if (targetEl)
154
- targetEl.classList.remove("drag-over");
155
- if (!this.draggedColumnKey || this.draggedColumnKey === targetKey)
344
+ e.currentTarget.classList.remove("drag-over");
345
+ if (this.draggedKey)
346
+ this.moveColumn(this.draggedKey, key);
347
+ this.draggedKey = null;
348
+ }
349
+ // --------------------------------------------------------------- row actions
350
+ itemsFor(row) {
351
+ if (!this.rowActions)
352
+ return [];
353
+ return typeof this.rowActions === "function" ? this.rowActions(row) : this.rowActions;
354
+ }
355
+ rowLabel(row) {
356
+ const column = this.internalColumns.find((c) => c.key === this.rowLabelKey) ?? this.internalColumns[0];
357
+ return column ? String(cellValue(row, column) ?? "") : "";
358
+ }
359
+ openRowMenu(row, target) {
360
+ const items = this.itemsFor(row);
361
+ if (!items.length)
156
362
  return;
157
- const newCols = [...this.internalColumns];
158
- const fromIndex = newCols.findIndex((c) => c.key === this.draggedColumnKey);
159
- const toIndex = newCols.findIndex((c) => c.key === targetKey);
160
- const [movedCol] = newCols.splice(fromIndex, 1);
161
- newCols.splice(toIndex, 0, movedCol);
162
- this.internalColumns = newCols;
163
- this.draggedColumnKey = null;
363
+ this.menuMode = "row";
364
+ this.menuOpenFor = row;
365
+ this.menu.label = `Actions for ${this.rowLabel(row)}`.trim();
366
+ this.menu.items = items;
367
+ if (target instanceof HTMLElement)
368
+ this.menu.showAt(target, row);
369
+ else
370
+ this.menu.show(target.x, target.y, row);
164
371
  }
165
- renderSortIcon(key) {
166
- const sortIndex = this.sortState.findIndex((s) => s.key === key);
167
- if (sortIndex === -1) {
168
- return html `<svg
169
- class="sort-icon"
170
- viewBox="0 0 24 24"
171
- fill="none"
172
- stroke="currentColor"
173
- stroke-width="2"
174
- stroke-linecap="round"
175
- stroke-linejoin="round"
176
- >
177
- <path d="m7 15 5 5 5-5" />
178
- <path d="m7 9 5-5 5 5" />
179
- </svg>`;
372
+ onRowContextMenu(e, row) {
373
+ if (!this.rowActions || this.loading || !this.itemsFor(row).length)
374
+ return;
375
+ e.preventDefault();
376
+ this.openRowMenu(row, { x: e.clientX, y: e.clientY });
377
+ }
378
+ onMenuSelect(e) {
379
+ e.stopPropagation();
380
+ if (this.menuMode === "columns") {
381
+ this.toggleColumn(e.detail.value);
382
+ return;
180
383
  }
181
- const sortConfig = this.sortState[sortIndex];
182
- const icon = sortConfig.direction === "asc"
183
- ? html `<svg
184
- class="sort-icon active"
185
- viewBox="0 0 24 24"
186
- fill="none"
187
- stroke="currentColor"
188
- stroke-width="2"
189
- stroke-linecap="round"
190
- stroke-linejoin="round"
191
- >
192
- <path d="m18 15-6-6-6 6" />
193
- </svg>`
194
- : html `<svg
195
- class="sort-icon active"
196
- viewBox="0 0 24 24"
197
- fill="none"
198
- stroke="currentColor"
199
- stroke-width="2"
200
- stroke-linecap="round"
201
- stroke-linejoin="round"
202
- >
203
- <path d="m6 9 6 6 6-6" />
204
- </svg>`;
205
- const priority = this.sortState.length > 1 && this.multiSort
206
- ? html `<span class="sort-priority">${sortIndex + 1}</span>`
207
- : "";
208
- return html `${icon}${priority}`;
384
+ this.dispatchEvent(new CustomEvent("st-row-action", {
385
+ detail: { value: e.detail.value, item: e.detail.item, row: e.detail.context },
386
+ bubbles: true,
387
+ composed: true,
388
+ }));
209
389
  }
210
- render() {
211
- const visibleColumns = this.internalColumns.filter((c) => !c.hidden);
212
- const skeletonRowsCount = Math.min(this.pageSize, 5);
390
+ onRowClick(row) {
391
+ if (!this.clickableRows || this.loading)
392
+ return;
393
+ this.dispatchEvent(new CustomEvent("st-row-click", { detail: row, bubbles: true, composed: true }));
394
+ }
395
+ onRowKeydown(e, row) {
396
+ if (e.target !== e.currentTarget || (e.key !== "Enter" && e.key !== " "))
397
+ return;
398
+ e.preventDefault();
399
+ this.onRowClick(row);
400
+ }
401
+ // ------------------------------------------------------------------- render
402
+ renderToolbar() {
403
+ const filterCount = this.activeFilters.length;
213
404
  return html `
214
405
  <div class="toolbar">
215
- <div class="search-wrapper">
216
- <svg
217
- class="search-icon"
218
- aria-hidden="true"
219
- viewBox="0 0 24 24"
220
- fill="none"
221
- stroke="currentColor"
222
- stroke-width="2"
223
- stroke-linecap="round"
224
- stroke-linejoin="round"
225
- >
226
- <circle cx="11" cy="11" r="8"></circle>
227
- <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
228
- </svg>
229
- <input
230
- type="text"
231
- class="search-input"
232
- placeholder="Search..."
233
- aria-label="Search data table"
234
- spellcheck="false"
235
- autocapitalize="none"
236
- ?disabled=${this.loading}
237
- @input=${this.handleSearchInput}
238
- />
239
- </div>
240
-
241
- <div class="columns-toggle-wrapper">
242
- <st-button
243
- variant="secondary"
244
- size="sm"
245
- aria-haspopup="menu"
246
- aria-expanded=${this.showColumnMenu}
247
- @click=${() => (this.showColumnMenu = !this.showColumnMenu)}
248
- >
249
- Columns
250
- </st-button>
251
-
252
- ${this.showColumnMenu
406
+ ${this.hideSearch
407
+ ? nothing
408
+ : html `
409
+ <div class="search" role="search">
410
+ <st-icon name="search" size="sm" aria-hidden="true"></st-icon>
411
+ <input
412
+ class="search-input"
413
+ type="search"
414
+ spellcheck="false"
415
+ autocapitalize="none"
416
+ autocomplete="off"
417
+ aria-label="Search table"
418
+ placeholder=${this.searchPlaceholder}
419
+ .value=${this.searchDraft}
420
+ ?disabled=${this.loading}
421
+ @input=${this.onSearchInput}
422
+ />
423
+ </div>
424
+ `}
425
+ ${this.filterColumns.length
253
426
  ? html `
254
- <div class="columns-menu" role="menu">
255
- ${this.internalColumns.map((col) => html `
256
- <label
257
- class="column-option"
258
- role="menuitemcheckbox"
259
- aria-checked=${!col.hidden}
260
- >
261
- <input
262
- type="checkbox"
263
- .checked=${!col.hidden}
264
- @change=${() => this.toggleColumnVisibility(col.key)}
265
- />
266
- ${col.header}
267
- </label>
268
- `)}
269
- </div>
270
- `
271
- : ""}
272
- </div>
427
+ <button
428
+ class="tool-btn filters-btn"
429
+ type="button"
430
+ aria-expanded=${this.filtersOpen ? "true" : "false"}
431
+ aria-controls="filter-panel"
432
+ @click=${() => {
433
+ this.filtersOpen = !this.filtersOpen;
434
+ if (this.filtersOpen && !this.filters.length)
435
+ this.addFilter();
436
+ }}
437
+ >
438
+ <st-icon name="filter" size="sm" aria-hidden="true"></st-icon>
439
+ Filters
440
+ ${filterCount
441
+ ? html `<span class="count" aria-label="${filterCount} active">${filterCount}</span>`
442
+ : nothing}
443
+ </button>
444
+ `
445
+ : nothing}
446
+ ${this.hideColumnMenu
447
+ ? nothing
448
+ : html `
449
+ <button
450
+ class="tool-btn columns-btn"
451
+ type="button"
452
+ aria-haspopup="menu"
453
+ @click=${this.openColumnMenu}
454
+ >
455
+ <st-icon name="table" size="sm" aria-hidden="true"></st-icon>
456
+ Columns
457
+ </button>
458
+ `}
273
459
  </div>
274
-
275
- <div class="table-wrapper">
276
- <table aria-busy=${this.loading}>
277
- <thead>
278
- <tr>
279
- ${visibleColumns.map((col) => {
280
- const sortItem = this.sortState.find((s) => s.key === col.key);
281
- const ariaSort = sortItem
282
- ? sortItem.direction === "asc"
283
- ? "ascending"
284
- : "descending"
285
- : "none";
460
+ `;
461
+ }
462
+ renderFilterPanel() {
463
+ if (!this.filtersOpen || !this.filterColumns.length)
464
+ return nothing;
465
+ return html `
466
+ <div class="filter-panel" id="filter-panel" role="group" aria-label="Filters">
467
+ ${this.filters.map((filter, index) => {
468
+ const column = this.internalColumns.find((c) => c.key === filter.key);
469
+ const type = column?.filter;
470
+ if (!column || !type)
471
+ return nothing;
472
+ const operator = operatorsFor(type).find((o) => o.op === filter.op);
286
473
  return html `
287
- <th
288
- scope="col"
289
- aria-sort=${ifDefined(col.sortable ? ariaSort : undefined)}
290
- draggable="true"
291
- @dragstart=${(e) => this.handleDragStart(e, col.key)}
292
- @dragover=${this.handleDragOver}
293
- @dragleave=${this.handleDragLeave}
294
- @drop=${(e) => this.handleDrop(e, col.key)}
295
- >
296
- <div class="th-content">
297
- <svg
298
- class="drag-handle"
299
- aria-hidden="true"
300
- width="12"
301
- height="12"
302
- viewBox="0 0 24 24"
303
- fill="none"
304
- stroke="currentColor"
305
- stroke-width="2"
306
- stroke-linecap="round"
307
- stroke-linejoin="round"
474
+ <div class="filter-row" role="group" aria-label="Filter ${index + 1}">
475
+ <select
476
+ aria-label="Filter ${index + 1} column"
477
+ @change=${(e) => this.onFilterColumn(index, e.target.value)}
478
+ >
479
+ ${this.filterColumns.map((c) => html `<option value=${c.key} .selected=${c.key === filter.key}>${c.header}</option>`)}
480
+ </select>
481
+ <select
482
+ aria-label="Filter ${index + 1} condition"
483
+ @change=${(e) => this.onFilterOperator(index, e.target.value)}
484
+ >
485
+ ${operatorsFor(type).map((o) => html `<option value=${o.op} .selected=${o.op === filter.op}>${o.label}</option>`)}
486
+ </select>
487
+ ${operator?.needsValue
488
+ ? type === "select"
489
+ ? html `
490
+ <select
491
+ class="filter-value"
492
+ aria-label="Filter ${index + 1} value"
493
+ @change=${(e) => this.updateFilter(index, { value: e.target.value })}
308
494
  >
309
- <circle cx="9" cy="12" r="1" />
310
- <circle cx="9" cy="5" r="1" />
311
- <circle cx="9" cy="19" r="1" />
312
- <circle cx="15" cy="12" r="1" />
313
- <circle cx="15" cy="5" r="1" />
314
- <circle cx="15" cy="19" r="1" />
315
- </svg>
316
-
317
- <div
318
- class=${classMap({ "sortable-header": !!col.sortable })}
319
- @click=${(e) => col.sortable && this.handleSort(col.key, e)}
320
- >
321
- ${col.header} ${col.sortable ? this.renderSortIcon(col.key) : ""}
322
- </div>
323
- </div>
324
- </th>
325
- `;
495
+ <option value="" .selected=${!filter.value}>Choose…</option>
496
+ ${this.optionsFor(column).map((o) => html `<option value=${o.value} .selected=${o.value === filter.value}>${o.label}</option>`)}
497
+ </select>
498
+ `
499
+ : html `
500
+ <input
501
+ class="filter-value"
502
+ type=${type === "number" ? "number" : "text"}
503
+ aria-label="Filter ${index + 1} value"
504
+ placeholder="Value"
505
+ .value=${filter.value ?? ""}
506
+ @input=${(e) => this.updateFilter(index, { value: e.target.value }, true)}
507
+ />
508
+ `
509
+ : nothing}
510
+ <button
511
+ class="row-menu-btn"
512
+ type="button"
513
+ aria-label="Remove filter ${index + 1}"
514
+ @click=${() => this.removeFilter(index)}
515
+ >
516
+ <st-icon name="x" size="sm" aria-hidden="true"></st-icon>
517
+ </button>
518
+ </div>
519
+ `;
326
520
  })}
327
- </tr>
328
- </thead>
329
-
330
- <tbody aria-live="polite">
331
- ${this.loading
332
- ? html `
333
- ${Array.from({ length: skeletonRowsCount }).map(() => html `
334
- <tr>
335
- ${visibleColumns.map(() => html `
336
- <td><st-skeleton variant="text" width="75%"></st-skeleton></td>
337
- `)}
338
- </tr>
339
- `)}
340
- `
341
- : this.data.length === 0
342
- ? html `
343
- <tr>
344
- <td
345
- colspan=${visibleColumns.length}
346
- style="text-align: center; padding: 2rem;"
347
- >
348
- No results found.
349
- </td>
350
- </tr>
351
- `
352
- : this.data.map((row) => html `
353
- <tr>
354
- ${visibleColumns.map((col) => html `<td>${row[col.key] ?? ""}</td>`)}
355
- </tr>
356
- `)}
357
- </tbody>
358
- </table>
359
- </div>
360
-
361
- <div class="pagination">
362
- <div class="pagination-info">
363
- Page ${this.page} of ${this.totalPages} (${this.totalRows} total items)
521
+ <div class="panel-actions">
522
+ <button class="link-btn add-filter" type="button" @click=${this.addFilter}>Add filter</button>
523
+ ${this.filters.length
524
+ ? html `<button class="link-btn" type="button" @click=${() => ((this.filters = []), this.emitChange())}>
525
+ Clear filters
526
+ </button>`
527
+ : nothing}
364
528
  </div>
365
- <div class="pagination-controls">
366
- <st-button
367
- variant="secondary"
368
- size="sm"
369
- ?disabled=${this.loading || this.page === 1}
370
- @click=${this.prevPage}
529
+ </div>
530
+ `;
531
+ }
532
+ renderChips() {
533
+ const filters = this.activeFilters;
534
+ const sorts = this.sort.filter((s) => this.internalColumns.some((c) => c.key === s.key));
535
+ if (!filters.length && !sorts.length && !this.search.trim())
536
+ return nothing;
537
+ return html `
538
+ <div class="chips" role="group" aria-label="Active filters and sorting">
539
+ ${this.search.trim()
540
+ ? html `<button class="chip" type="button" aria-label="Clear search: ${this.search}" @click=${this.clearSearch}>
541
+ Search: ${this.search} <st-icon name="x" size="sm" aria-hidden="true"></st-icon>
542
+ </button>`
543
+ : nothing}
544
+ ${filters.map((f) => {
545
+ const text = describeFilter(f, this.internalColumns);
546
+ return html `<button
547
+ class="chip filter-chip"
548
+ type="button"
549
+ aria-label="Remove filter: ${text}"
550
+ @click=${() => this.removeFilter(this.filters.indexOf(f))}
371
551
  >
372
- Prev
373
- </st-button>
374
- <st-button
375
- variant="secondary"
376
- size="sm"
377
- ?disabled=${this.loading || this.page === this.totalPages}
378
- @click=${this.nextPage}
552
+ ${text} <st-icon name="x" size="sm" aria-hidden="true"></st-icon>
553
+ </button>`;
554
+ })}
555
+ ${sorts.map((s, i) => {
556
+ const header = this.internalColumns.find((c) => c.key === s.key).header;
557
+ const dir = s.direction === "asc" ? "ascending" : "descending";
558
+ return html `<button
559
+ class="chip sort-chip"
560
+ type="button"
561
+ aria-label="Remove sort: ${header} ${dir}"
562
+ @click=${() => this.removeSort(s.key)}
379
563
  >
380
- Next
381
- </st-button>
382
- </div>
564
+ ${sorts.length > 1 ? `${i + 1}. ` : ""}${header} ${s.direction === "asc" ? "↑" : "↓"}
565
+ <st-icon name="x" size="sm" aria-hidden="true"></st-icon>
566
+ </button>`;
567
+ })}
568
+ ${filters.length + sorts.length + (this.search.trim() ? 1 : 0) > 1
569
+ ? html `<button class="link-btn clear-all" type="button" @click=${() => ((this.sort = []), this.clearAll())}>
570
+ Clear all
571
+ </button>`
572
+ : nothing}
573
+ </div>
574
+ `;
575
+ }
576
+ renderSortIcon(key) {
577
+ const index = this.sort.findIndex((s) => s.key === key);
578
+ if (index === -1) {
579
+ return html `<svg class="sort-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
580
+ <path d="m7 15 5 5 5-5" /><path d="m7 9 5-5 5 5" />
581
+ </svg>`;
582
+ }
583
+ const asc = this.sort[index].direction === "asc";
584
+ return html `
585
+ <svg class="sort-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
586
+ <path d=${asc ? "m18 15-6-6-6 6" : "m6 9 6 6 6-6"} />
587
+ </svg>
588
+ ${this.sort.length > 1 ? html `<span class="priority" aria-hidden="true">${index + 1}</span>` : nothing}
589
+ `;
590
+ }
591
+ sortLabel(key) {
592
+ const s = this.sort.find((x) => x.key === key);
593
+ return s ? (s.direction === "asc" ? "ascending" : "descending") : "none";
594
+ }
595
+ renderHeader() {
596
+ const hasActions = !!this.rowActions;
597
+ return html `
598
+ <thead>
599
+ <tr>
600
+ ${this.visibleColumns.map((col) => html `
601
+ <th
602
+ scope="col"
603
+ data-col=${col.key}
604
+ class=${classMap({ "align-center": col.align === "center", "align-end": col.align === "end" })}
605
+ style=${ifDefined(col.width ? `width:${col.width}` : undefined)}
606
+ aria-sort=${ifDefined(col.sortable ? this.sortLabel(col.key) : undefined)}
607
+ draggable=${this.fixedColumns ? "false" : "true"}
608
+ @dragstart=${(e) => this.onDragStart(e, col.key)}
609
+ @dragover=${this.onDragOver}
610
+ @dragleave=${(e) => e.currentTarget.classList.remove("drag-over")}
611
+ @drop=${(e) => this.onDrop(e, col.key)}
612
+ >
613
+ ${col.sortable
614
+ ? html `<button
615
+ class=${classMap({ "th-btn": true, sorted: this.sort.some((s) => s.key === col.key) })}
616
+ type="button"
617
+ title=${this.canMultiSort ? "Click to sort, Shift+click to add a column" : "Click to sort"}
618
+ @click=${(e) => this.onSort(col.key, e)}
619
+ @keydown=${(e) => this.onHeaderKeydown(e, col.key)}
620
+ >
621
+ ${col.header} ${this.renderSortIcon(col.key)}
622
+ </button>`
623
+ : col.header}
624
+ </th>
625
+ `)}
626
+ ${hasActions ? html `<th scope="col" class="actions-col"><span class="sr-only">Actions</span></th>` : nothing}
627
+ </tr>
628
+ </thead>
629
+ `;
630
+ }
631
+ renderBody() {
632
+ const colSpan = this.visibleColumns.length + (this.rowActions ? 1 : 0) || 1;
633
+ if (this.loading) {
634
+ return Array.from({ length: this.fixedRows > 0 ? this.fixedRows : Math.min(this.pageSize, SKELETON_ROWS) }, () => html `<tr>
635
+ ${Array.from({ length: colSpan }, () => html `<td><st-skeleton variant="text" width="70%"></st-skeleton></td>`)}
636
+ </tr>`);
637
+ }
638
+ if (!this.view.rows.length) {
639
+ return html `<tr>
640
+ <td class="empty" colspan=${colSpan}>
641
+ ${this.hasQuery ? "No results match your search or filters." : this.emptyText}
642
+ ${this.hasQuery
643
+ ? html ` <button class="link-btn" type="button" @click=${() => ((this.sort = []), this.clearAll())}>Clear all</button>`
644
+ : nothing}
645
+ </td>
646
+ </tr>`;
647
+ }
648
+ const spacers = this.renderSpacers(this.view.rows.length, colSpan);
649
+ return [this.renderRows(colSpan), spacers];
650
+ }
651
+ /** Blank rows that pad a short page up to `fixedRows` so the footer stays put. */
652
+ renderSpacers(count, colSpan) {
653
+ if (this.fixedRows <= count)
654
+ return nothing;
655
+ return Array.from({ length: this.fixedRows - count }, () => html `<tr class="spacer" aria-hidden="true"><td colspan=${colSpan}></td></tr>`);
656
+ }
657
+ renderRows(_colSpan) {
658
+ return this.view.rows.map((row) => {
659
+ const hasMenu = !!this.rowActions && this.itemsFor(row).length > 0;
660
+ return html `
661
+ <tr
662
+ class=${classMap({ clickable: this.clickableRows, "menu-open": this.menuOpenFor === row })}
663
+ tabindex=${ifDefined(this.clickableRows ? "0" : undefined)}
664
+ @click=${() => this.onRowClick(row)}
665
+ @keydown=${(e) => this.onRowKeydown(e, row)}
666
+ @contextmenu=${(e) => this.onRowContextMenu(e, row)}
667
+ >
668
+ ${this.visibleColumns.map((col) => html `
669
+ <td class=${classMap({ "align-center": col.align === "center", "align-end": col.align === "end" })}>
670
+ ${col.render ? col.render(row) : (cellValue(row, col) ?? "")}
671
+ </td>
672
+ `)}
673
+ ${this.rowActions
674
+ ? html `<td class="actions-col">
675
+ ${hasMenu
676
+ ? html `<button
677
+ class="row-menu-btn"
678
+ type="button"
679
+ aria-label="Actions for ${this.rowLabel(row)}"
680
+ aria-haspopup="menu"
681
+ aria-expanded=${this.menuOpenFor === row ? "true" : "false"}
682
+ @click=${(e) => {
683
+ e.stopPropagation();
684
+ this.openRowMenu(row, e.currentTarget);
685
+ }}
686
+ >
687
+ <st-icon name="ellipsis" size="sm" aria-hidden="true"></st-icon>
688
+ </button>`
689
+ : nothing}
690
+ </td>`
691
+ : nothing}
692
+ </tr>
693
+ `;
694
+ });
695
+ }
696
+ renderFooter() {
697
+ const { total, from, to, totalPages, page } = this.view;
698
+ const options = this.pageSizeOptions.includes(this.pageSize)
699
+ ? this.pageSizeOptions
700
+ : [...this.pageSizeOptions, this.pageSize].sort((a, b) => a - b);
701
+ return html `
702
+ <div class="footer">
703
+ <span class="info">${this.loading ? "Loading…" : total ? `Showing ${from}–${to} of ${total}` : "No results"}</span>
704
+ <label class="page-size">
705
+ Rows per page
706
+ <select class="page-size-select" ?disabled=${this.loading} @change=${this.onPageSize}>
707
+ ${options.map((n) => html `<option value=${n} .selected=${n === this.pageSize}>${n}</option>`)}
708
+ </select>
709
+ </label>
710
+ ${totalPages > 1
711
+ ? html `<st-pagination
712
+ page=${page}
713
+ total-pages=${totalPages}
714
+ @st-page-change=${(e) => {
715
+ e.stopPropagation();
716
+ this.goToPage(e.detail.page);
717
+ }}
718
+ ></st-pagination>`
719
+ : nothing}
383
720
  </div>
384
721
  `;
385
722
  }
723
+ render() {
724
+ return html `
725
+ ${this.renderToolbar()} ${this.renderFilterPanel()} ${this.renderChips()}
726
+ <div class=${classMap({ "table-wrapper": true, fixed: this.fixedRows > 0 })}>
727
+ <table aria-busy=${this.loading ? "true" : "false"}>
728
+ ${this.caption ? html `<caption>${this.caption}</caption>` : nothing}
729
+ ${this.renderHeader()}
730
+ <tbody>
731
+ ${this.renderBody()}
732
+ </tbody>
733
+ </table>
734
+ </div>
735
+ ${this.renderFooter()}
736
+ <div class="sr-only" aria-live="polite" aria-atomic="true">${this.announcement}</div>
737
+ <st-context-menu
738
+ trigger="manual"
739
+ @st-menu-select=${this.onMenuSelect}
740
+ @st-menu-close=${() => (this.menuOpenFor = null)}
741
+ ></st-context-menu>
742
+ `;
743
+ }
386
744
  };
387
745
  StDataTable.styles = [
388
746
  resetStyles,
@@ -391,188 +749,368 @@ StDataTable.styles = [
391
749
  display: block;
392
750
  width: 100%;
393
751
  font-family: var(--st-font-family, inherit);
752
+ color: var(--st-color-text);
753
+ }
754
+
755
+ .sr-only {
756
+ position: absolute;
757
+ width: 1px;
758
+ height: 1px;
759
+ overflow: hidden;
760
+ clip: rect(0 0 0 0);
761
+ white-space: nowrap;
394
762
  }
395
763
 
764
+ /* ---------- Toolbar ---------- */
396
765
  .toolbar {
397
766
  display: flex;
398
- justify-content: space-between;
767
+ flex-wrap: wrap;
399
768
  align-items: center;
400
- gap: var(--st-spacing-md);
769
+ gap: var(--st-spacing-sm);
401
770
  margin-bottom: var(--st-spacing-md);
402
- flex-wrap: wrap;
403
771
  }
404
772
 
405
- .search-wrapper {
406
- flex: 1;
407
- min-width: 250px;
773
+ .search {
408
774
  position: relative;
775
+ flex: 1;
776
+ min-width: 14rem;
777
+ }
778
+
779
+ .search st-icon {
780
+ position: absolute;
781
+ left: var(--st-spacing-sm);
782
+ top: 50%;
783
+ transform: translateY(-50%);
784
+ color: var(--st-color-text-muted);
785
+ pointer-events: none;
409
786
  }
410
787
 
411
788
  .search-input {
412
789
  width: 100%;
413
- padding: 0.5rem 0.75rem 0.5rem 2.25rem;
790
+ padding: var(--st-spacing-sm) var(--st-spacing-sm) var(--st-spacing-sm) 2.25rem;
414
791
  border: 1px solid var(--st-color-border);
415
792
  border-radius: var(--st-radius-md);
416
- background-color: var(--st-color-surface);
417
- color: var(--st-color-text);
793
+ background: var(--st-color-surface);
794
+ color: inherit;
795
+ font: inherit;
418
796
  font-size: var(--st-font-size-sm);
419
797
  }
420
798
 
421
- .search-input:disabled {
422
- opacity: 0.6;
423
- cursor: not-allowed;
799
+ .search-input:focus-visible,
800
+ select:focus-visible,
801
+ .filter-value:focus-visible {
802
+ outline: 2px solid var(--st-color-primary);
803
+ outline-offset: 1px;
424
804
  }
425
805
 
426
- .search-icon {
427
- position: absolute;
428
- left: 0.75rem;
429
- top: 50%;
430
- transform: translateY(-50%);
431
- width: 1rem;
432
- height: 1rem;
433
- color: var(--st-color-text-muted);
434
- }
435
-
436
- .columns-toggle-wrapper {
437
- position: relative;
806
+ .tool-btn,
807
+ .chip,
808
+ .link-btn,
809
+ .row-menu-btn,
810
+ .th-btn {
811
+ font: inherit;
812
+ color: inherit;
813
+ cursor: pointer;
438
814
  }
439
815
 
440
- .columns-menu {
441
- position: absolute;
442
- top: calc(100% + 0.5rem);
443
- right: 0;
444
- background: var(--st-color-surface);
816
+ .tool-btn {
817
+ display: inline-flex;
818
+ align-items: center;
819
+ gap: var(--st-spacing-xs);
820
+ padding: var(--st-spacing-sm) var(--st-spacing-md);
445
821
  border: 1px solid var(--st-color-border);
446
822
  border-radius: var(--st-radius-md);
447
- padding: var(--st-spacing-sm);
448
- min-width: 200px;
449
- box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);
450
- z-index: 10;
823
+ background: var(--st-color-surface);
824
+ font-size: var(--st-font-size-sm);
825
+ }
826
+
827
+ .tool-btn:hover:not(:disabled) {
828
+ background: var(--st-color-surface-hover);
829
+ }
830
+
831
+ .tool-btn[aria-expanded="true"] {
832
+ border-color: var(--st-color-primary);
833
+ color: var(--st-color-primary-text);
834
+ }
835
+
836
+ .tool-btn:focus-visible,
837
+ .chip:focus-visible,
838
+ .link-btn:focus-visible,
839
+ .row-menu-btn:focus-visible,
840
+ .th-btn:focus-visible {
841
+ outline: 2px solid var(--st-color-primary);
842
+ outline-offset: 2px;
843
+ }
844
+
845
+ .count {
846
+ min-width: 1.25rem;
847
+ padding: 0 var(--st-spacing-xs);
848
+ border-radius: 999px;
849
+ background: var(--st-color-primary);
850
+ color: var(--st-color-on-primary);
851
+ font-size: var(--st-font-size-xs);
852
+ text-align: center;
853
+ }
854
+
855
+ /* ---------- Filter panel and chips ---------- */
856
+ .filter-panel {
451
857
  display: flex;
452
858
  flex-direction: column;
453
- gap: 0.25rem;
859
+ gap: var(--st-spacing-sm);
860
+ margin-bottom: var(--st-spacing-md);
861
+ padding: var(--st-spacing-md);
862
+ border: 1px solid var(--st-color-border);
863
+ border-radius: var(--st-radius-md);
864
+ background: var(--st-color-surface);
454
865
  }
455
866
 
456
- .column-option {
867
+ .filter-row {
457
868
  display: flex;
869
+ flex-wrap: wrap;
458
870
  align-items: center;
459
- gap: 0.5rem;
871
+ gap: var(--st-spacing-sm);
872
+ }
873
+
874
+ select,
875
+ .filter-value {
876
+ padding: var(--st-spacing-xs) var(--st-spacing-sm);
877
+ border: 1px solid var(--st-color-border);
878
+ border-radius: var(--st-radius-sm);
879
+ background: var(--st-color-bg);
880
+ color: inherit;
881
+ font: inherit;
460
882
  font-size: var(--st-font-size-sm);
461
- cursor: pointer;
462
- padding: 0.25rem;
463
883
  }
464
884
 
885
+ .filter-value {
886
+ min-width: 10rem;
887
+ flex: 1;
888
+ }
889
+
890
+ .panel-actions {
891
+ display: flex;
892
+ gap: var(--st-spacing-md);
893
+ }
894
+
895
+ .link-btn {
896
+ padding: 0;
897
+ border: 0;
898
+ background: none;
899
+ color: var(--st-color-primary-text);
900
+ font-size: var(--st-font-size-sm);
901
+ text-decoration: underline;
902
+ }
903
+
904
+ .chips {
905
+ display: flex;
906
+ flex-wrap: wrap;
907
+ align-items: center;
908
+ gap: var(--st-spacing-xs);
909
+ margin-bottom: var(--st-spacing-md);
910
+ }
911
+
912
+ .chip {
913
+ display: inline-flex;
914
+ align-items: center;
915
+ gap: var(--st-spacing-xs);
916
+ padding: 2px var(--st-spacing-sm);
917
+ border: 1px solid transparent;
918
+ border-radius: 999px;
919
+ background: var(--st-color-primary-bg);
920
+ color: var(--st-color-primary-text);
921
+ font-size: var(--st-font-size-xs);
922
+ }
923
+
924
+ .chip:hover {
925
+ border-color: var(--st-color-primary);
926
+ }
927
+
928
+ /* ---------- Table ---------- */
465
929
  .table-wrapper {
466
- width: 100%;
467
- overflow-x: auto;
930
+ overflow: auto;
468
931
  border: 1px solid var(--st-color-border);
469
932
  border-radius: var(--st-radius-md);
933
+ max-height: var(--st-table-max-height, none);
470
934
  }
471
935
 
472
936
  table {
473
937
  width: 100%;
474
938
  border-collapse: collapse;
475
- text-align: left;
476
939
  font-size: var(--st-font-size-sm);
477
- background-color: var(--st-color-surface);
940
+ }
941
+
942
+ caption {
943
+ padding: var(--st-spacing-sm) var(--st-spacing-md);
944
+ text-align: left;
945
+ font-weight: var(--st-font-weight-medium);
478
946
  }
479
947
 
480
948
  th {
481
- font-weight: 600;
482
949
  padding: var(--st-spacing-sm) var(--st-spacing-md);
483
950
  border-bottom: 2px solid var(--st-color-border);
951
+ background: var(--st-color-surface);
484
952
  color: var(--st-color-text-muted);
953
+ font-weight: var(--st-font-weight-semibold);
954
+ text-align: left;
485
955
  white-space: nowrap;
486
- background-color: var(--st-color-surface-muted, #f8fafc);
487
- user-select: none;
488
956
  }
489
957
 
490
- th[draggable="true"] {
491
- cursor: grab;
958
+ :host([sticky-header]) th {
959
+ position: sticky;
960
+ top: 0;
961
+ z-index: 1;
962
+ }
963
+
964
+ /* ---------- Fixed row count ---------- */
965
+ .table-wrapper.fixed {
966
+ --_row-height: var(--st-data-table-row-height, 3.25rem);
967
+ }
968
+
969
+ :host([dense]) .table-wrapper.fixed {
970
+ --_row-height: var(--st-data-table-row-height, 2.5rem);
971
+ }
972
+
973
+ .fixed th,
974
+ .fixed td {
975
+ height: var(--_row-height);
976
+ padding-top: 0;
977
+ padding-bottom: 0;
978
+ overflow: hidden;
979
+ text-overflow: ellipsis;
980
+ white-space: nowrap;
981
+ max-width: var(--st-data-table-cell-max-width, 24rem);
982
+ }
983
+
984
+ .fixed th {
985
+ position: sticky;
986
+ top: 0;
987
+ z-index: 1;
988
+ }
989
+
990
+ .fixed td.empty {
991
+ height: calc(var(--st-data-table-fixed-rows, 1) * var(--_row-height));
492
992
  }
493
993
 
494
- th[draggable="true"]:active {
495
- cursor: grabbing;
994
+ .fixed tr.spacer td {
995
+ border-bottom: 0;
496
996
  }
497
997
 
498
998
  th.drag-over {
499
- border-left: 2px solid var(--st-color-primary);
999
+ box-shadow: inset 3px 0 0 var(--st-color-primary);
500
1000
  }
501
1001
 
502
- .th-content {
503
- display: flex;
504
- align-items: center;
505
- gap: 0.5rem;
1002
+ td {
1003
+ padding: var(--st-spacing-md);
1004
+ border-bottom: 1px solid var(--st-color-border);
506
1005
  }
507
1006
 
508
- .sortable-header {
509
- cursor: pointer;
510
- display: flex;
511
- align-items: center;
512
- gap: 0.25rem;
1007
+ :host([dense]) td {
1008
+ padding: var(--st-spacing-xs) var(--st-spacing-md);
513
1009
  }
514
1010
 
515
- .sortable-header:hover {
516
- color: var(--st-color-text);
1011
+ tbody tr:last-child td {
1012
+ border-bottom: 0;
517
1013
  }
518
1014
 
519
- .sort-icon {
520
- width: 1rem;
521
- height: 1rem;
522
- color: var(--st-color-text-muted);
1015
+ :host([striped]) tbody tr:nth-of-type(even) {
1016
+ background: var(--st-color-surface-muted);
523
1017
  }
524
1018
 
525
- .sort-icon.active {
526
- color: var(--st-color-primary);
1019
+ .align-center {
1020
+ text-align: center;
1021
+ }
1022
+ .align-end {
1023
+ text-align: end;
527
1024
  }
528
1025
 
529
- .sort-priority {
530
- font-size: 0.7rem;
531
- background: var(--st-color-border);
532
- color: var(--st-color-text);
533
- border-radius: 50%;
534
- width: 1.1rem;
535
- height: 1.1rem;
1026
+ tbody tr.clickable {
1027
+ cursor: pointer;
1028
+ }
1029
+
1030
+ tbody tr.clickable:hover,
1031
+ tbody tr.menu-open {
1032
+ background: var(--st-color-surface-hover);
1033
+ }
1034
+
1035
+ tbody tr.clickable:focus-visible {
1036
+ outline: 2px solid var(--st-color-primary);
1037
+ outline-offset: -2px;
1038
+ }
1039
+
1040
+ .th-btn {
536
1041
  display: inline-flex;
537
1042
  align-items: center;
538
- justify-content: center;
1043
+ gap: var(--st-spacing-xs);
1044
+ padding: 0;
1045
+ border: 0;
1046
+ background: none;
1047
+ font-weight: inherit;
539
1048
  }
540
1049
 
541
- td {
542
- padding: var(--st-spacing-sm) var(--st-spacing-md);
543
- border-bottom: 1px solid var(--st-color-border);
544
- color: var(--st-color-text);
1050
+ .th-btn.sorted {
1051
+ color: var(--st-color-primary-text);
545
1052
  }
546
1053
 
547
- tbody tr:last-child td {
548
- border-bottom: none;
1054
+ .sort-icon {
1055
+ width: 0.875rem;
1056
+ height: 0.875rem;
1057
+ opacity: 0.45;
549
1058
  }
550
1059
 
551
- tbody tr:hover {
552
- background-color: var(--st-color-surface-hover, #f1f5f9);
1060
+ .th-btn.sorted .sort-icon {
1061
+ opacity: 1;
553
1062
  }
554
1063
 
555
- .pagination {
556
- display: flex;
557
- justify-content: space-between;
558
- align-items: center;
559
- padding: var(--st-spacing-md) 0;
560
- font-size: var(--st-font-size-sm);
1064
+ .priority {
1065
+ min-width: 1rem;
1066
+ border-radius: 999px;
1067
+ background: var(--st-color-primary-bg);
1068
+ font-size: var(--st-font-size-xs);
1069
+ text-align: center;
1070
+ }
1071
+
1072
+ .actions-col {
1073
+ width: 1%;
1074
+ text-align: end;
1075
+ }
1076
+
1077
+ .row-menu-btn {
1078
+ display: inline-flex;
1079
+ padding: var(--st-spacing-xs);
1080
+ border: 0;
1081
+ border-radius: var(--st-radius-sm);
1082
+ background: none;
561
1083
  color: var(--st-color-text-muted);
562
1084
  }
563
1085
 
564
- .pagination-controls {
565
- display: flex;
566
- gap: var(--st-spacing-sm);
1086
+ .row-menu-btn:hover,
1087
+ .row-menu-btn[aria-expanded="true"] {
1088
+ background: var(--st-color-surface-hover);
1089
+ color: var(--st-color-text);
567
1090
  }
568
1091
 
569
- .drag-handle {
570
- opacity: 0.3;
571
- cursor: grab;
1092
+ .empty {
1093
+ padding: var(--st-spacing-xl);
1094
+ text-align: center;
1095
+ color: var(--st-color-text-muted);
572
1096
  }
573
1097
 
574
- .drag-handle:hover {
575
- opacity: 0.7;
1098
+ /* ---------- Footer ---------- */
1099
+ .footer {
1100
+ display: flex;
1101
+ flex-wrap: wrap;
1102
+ align-items: center;
1103
+ justify-content: space-between;
1104
+ gap: var(--st-spacing-md);
1105
+ margin-top: var(--st-spacing-md);
1106
+ color: var(--st-color-text-muted);
1107
+ font-size: var(--st-font-size-sm);
1108
+ }
1109
+
1110
+ .page-size {
1111
+ display: inline-flex;
1112
+ align-items: center;
1113
+ gap: var(--st-spacing-sm);
576
1114
  }
577
1115
  `,
578
1116
  ];
@@ -586,29 +1124,92 @@ __decorate([
586
1124
  property({ type: Number, attribute: "total-rows" })
587
1125
  ], StDataTable.prototype, "totalRows", void 0);
588
1126
  __decorate([
589
- property({ type: Number })
1127
+ property({ type: Boolean, attribute: "server-side" })
1128
+ ], StDataTable.prototype, "serverSide", void 0);
1129
+ __decorate([
1130
+ property({ type: Number, reflect: true })
590
1131
  ], StDataTable.prototype, "page", void 0);
591
1132
  __decorate([
592
1133
  property({ type: Number, attribute: "page-size" })
593
1134
  ], StDataTable.prototype, "pageSize", void 0);
1135
+ __decorate([
1136
+ property({ type: Array, attribute: false })
1137
+ ], StDataTable.prototype, "pageSizeOptions", void 0);
1138
+ __decorate([
1139
+ property({ type: String })
1140
+ ], StDataTable.prototype, "search", void 0);
1141
+ __decorate([
1142
+ property({ type: Array, attribute: false })
1143
+ ], StDataTable.prototype, "sort", void 0);
1144
+ __decorate([
1145
+ property({ type: Array, attribute: false })
1146
+ ], StDataTable.prototype, "filters", void 0);
594
1147
  __decorate([
595
1148
  property({ type: Boolean, attribute: "multi-sort" })
596
1149
  ], StDataTable.prototype, "multiSort", void 0);
1150
+ __decorate([
1151
+ property({ type: Boolean, attribute: "single-sort" })
1152
+ ], StDataTable.prototype, "singleSort", void 0);
597
1153
  __decorate([
598
1154
  property({ type: Boolean, reflect: true })
599
1155
  ], StDataTable.prototype, "loading", void 0);
1156
+ __decorate([
1157
+ property({ type: Boolean, attribute: "clickable-rows" })
1158
+ ], StDataTable.prototype, "clickableRows", void 0);
1159
+ __decorate([
1160
+ property({ type: Boolean, reflect: true })
1161
+ ], StDataTable.prototype, "dense", void 0);
1162
+ __decorate([
1163
+ property({ type: Boolean, reflect: true })
1164
+ ], StDataTable.prototype, "striped", void 0);
1165
+ __decorate([
1166
+ property({ type: Boolean, reflect: true, attribute: "sticky-header" })
1167
+ ], StDataTable.prototype, "stickyHeader", void 0);
1168
+ __decorate([
1169
+ property({ type: Number, attribute: "fixed-rows" })
1170
+ ], StDataTable.prototype, "fixedRows", void 0);
1171
+ __decorate([
1172
+ property({ type: String })
1173
+ ], StDataTable.prototype, "caption", void 0);
1174
+ __decorate([
1175
+ property({ type: String, attribute: "empty-text" })
1176
+ ], StDataTable.prototype, "emptyText", void 0);
1177
+ __decorate([
1178
+ property({ type: String, attribute: "search-placeholder" })
1179
+ ], StDataTable.prototype, "searchPlaceholder", void 0);
1180
+ __decorate([
1181
+ property({ type: Boolean, attribute: "hide-search" })
1182
+ ], StDataTable.prototype, "hideSearch", void 0);
1183
+ __decorate([
1184
+ property({ type: Boolean, attribute: "hide-column-menu" })
1185
+ ], StDataTable.prototype, "hideColumnMenu", void 0);
1186
+ __decorate([
1187
+ property({ type: Boolean, attribute: "fixed-columns" })
1188
+ ], StDataTable.prototype, "fixedColumns", void 0);
1189
+ __decorate([
1190
+ property({ attribute: false })
1191
+ ], StDataTable.prototype, "rowActions", void 0);
1192
+ __decorate([
1193
+ property({ type: String, attribute: "row-label-key" })
1194
+ ], StDataTable.prototype, "rowLabelKey", void 0);
600
1195
  __decorate([
601
1196
  state()
602
1197
  ], StDataTable.prototype, "internalColumns", void 0);
603
1198
  __decorate([
604
1199
  state()
605
- ], StDataTable.prototype, "sortState", void 0);
1200
+ ], StDataTable.prototype, "searchDraft", void 0);
1201
+ __decorate([
1202
+ state()
1203
+ ], StDataTable.prototype, "filtersOpen", void 0);
606
1204
  __decorate([
607
1205
  state()
608
- ], StDataTable.prototype, "searchQuery", void 0);
1206
+ ], StDataTable.prototype, "announcement", void 0);
609
1207
  __decorate([
610
1208
  state()
611
- ], StDataTable.prototype, "showColumnMenu", void 0);
1209
+ ], StDataTable.prototype, "menuOpenFor", void 0);
1210
+ __decorate([
1211
+ query("st-context-menu")
1212
+ ], StDataTable.prototype, "menu", void 0);
612
1213
  StDataTable = __decorate([
613
1214
  customElement("st-data-table")
614
1215
  ], StDataTable);