@nadicodeai/ui 12.1.101 → 12.1.103

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 (567) hide show
  1. package/dist/components/accordion.d.ts +38 -12
  2. package/dist/components/accordion.d.ts.map +1 -1
  3. package/dist/components/accordion.js +36 -15
  4. package/dist/components/account-menu.d.ts +18 -18
  5. package/dist/components/account-menu.d.ts.map +1 -1
  6. package/dist/components/account-menu.js +17 -13
  7. package/dist/components/action-menu.d.ts +20 -19
  8. package/dist/components/action-menu.d.ts.map +1 -1
  9. package/dist/components/action-menu.js +22 -15
  10. package/dist/components/action-status.d.ts +14 -10
  11. package/dist/components/action-status.d.ts.map +1 -1
  12. package/dist/components/action-status.js +14 -10
  13. package/dist/components/activity-calendar.d.ts +3 -1
  14. package/dist/components/activity-calendar.d.ts.map +1 -1
  15. package/dist/components/activity-calendar.js +16 -2
  16. package/dist/components/activity-feed.d.ts +2 -2
  17. package/dist/components/activity-feed.d.ts.map +1 -1
  18. package/dist/components/activity-feed.js +14 -5
  19. package/dist/components/agent-card.d.ts +11 -5
  20. package/dist/components/agent-card.d.ts.map +1 -1
  21. package/dist/components/agent-card.js +13 -7
  22. package/dist/components/agent-list-row.js +1 -1
  23. package/dist/components/agent-orb-appearance.d.ts +7 -1
  24. package/dist/components/agent-orb-appearance.d.ts.map +1 -1
  25. package/dist/components/agent-orb-appearance.js +26 -0
  26. package/dist/components/agent-profile.d.ts +8 -7
  27. package/dist/components/agent-profile.d.ts.map +1 -1
  28. package/dist/components/agent-profile.js +6 -6
  29. package/dist/components/alert-dialog.d.ts +25 -16
  30. package/dist/components/alert-dialog.d.ts.map +1 -1
  31. package/dist/components/alert-dialog.js +30 -18
  32. package/dist/components/alert.d.ts +1 -1
  33. package/dist/components/avatar.d.ts +83 -17
  34. package/dist/components/avatar.d.ts.map +1 -1
  35. package/dist/components/avatar.js +89 -23
  36. package/dist/components/badge.d.ts +59 -8
  37. package/dist/components/badge.d.ts.map +1 -1
  38. package/dist/components/badge.js +57 -14
  39. package/dist/components/breadcrumb.d.ts +18 -7
  40. package/dist/components/breadcrumb.d.ts.map +1 -1
  41. package/dist/components/breadcrumb.js +37 -13
  42. package/dist/components/button-group.d.ts +12 -15
  43. package/dist/components/button-group.d.ts.map +1 -1
  44. package/dist/components/button-group.js +13 -17
  45. package/dist/components/button.d.ts +126 -23
  46. package/dist/components/button.d.ts.map +1 -1
  47. package/dist/components/button.js +164 -39
  48. package/dist/components/calendar.d.ts +26 -15
  49. package/dist/components/calendar.d.ts.map +1 -1
  50. package/dist/components/calendar.js +60 -46
  51. package/dist/components/card-row.d.ts +13 -5
  52. package/dist/components/card-row.d.ts.map +1 -1
  53. package/dist/components/card-row.js +24 -10
  54. package/dist/components/card.d.ts +6 -12
  55. package/dist/components/card.d.ts.map +1 -1
  56. package/dist/components/card.js +11 -16
  57. package/dist/components/carousel.d.ts +3 -3
  58. package/dist/components/carousel.d.ts.map +1 -1
  59. package/dist/components/carousel.js +7 -7
  60. package/dist/components/catalog-drawer.d.ts +7 -7
  61. package/dist/components/catalog-drawer.d.ts.map +1 -1
  62. package/dist/components/catalog-drawer.js +6 -6
  63. package/dist/components/chart-area-stacked.d.ts +1 -1
  64. package/dist/components/chart-area-stacked.d.ts.map +1 -1
  65. package/dist/components/chart-area-stacked.js +4 -4
  66. package/dist/components/chart-axis.d.ts +14 -1
  67. package/dist/components/chart-axis.d.ts.map +1 -1
  68. package/dist/components/chart-axis.js +11 -1
  69. package/dist/components/chart-bar-horizontal.d.ts +2 -2
  70. package/dist/components/chart-bar-horizontal.d.ts.map +1 -1
  71. package/dist/components/chart-bar-horizontal.js +14 -5
  72. package/dist/components/chart-bar-multiple.d.ts +1 -1
  73. package/dist/components/chart-bar-multiple.d.ts.map +1 -1
  74. package/dist/components/chart-bar-multiple.js +3 -3
  75. package/dist/components/chart-bar-stacked.d.ts +1 -1
  76. package/dist/components/chart-bar-stacked.d.ts.map +1 -1
  77. package/dist/components/chart-bar-stacked.js +3 -3
  78. package/dist/components/chart-card.d.ts +17 -6
  79. package/dist/components/chart-card.d.ts.map +1 -1
  80. package/dist/components/chart-card.js +11 -4
  81. package/dist/components/chart-date-range-control.d.ts +18 -9
  82. package/dist/components/chart-date-range-control.d.ts.map +1 -1
  83. package/dist/components/chart-date-range-control.js +43 -47
  84. package/dist/components/chart-sparkline.d.ts +4 -3
  85. package/dist/components/chart-sparkline.d.ts.map +1 -1
  86. package/dist/components/chart-sparkline.js +6 -5
  87. package/dist/components/check-counts.d.ts +44 -0
  88. package/dist/components/check-counts.d.ts.map +1 -0
  89. package/dist/components/check-counts.js +51 -0
  90. package/dist/components/checkbox.d.ts +39 -11
  91. package/dist/components/checkbox.d.ts.map +1 -1
  92. package/dist/components/checkbox.js +38 -11
  93. package/dist/components/choicebox.d.ts +96 -0
  94. package/dist/components/choicebox.d.ts.map +1 -0
  95. package/dist/components/choicebox.js +113 -0
  96. package/dist/components/clearable-input.d.ts +57 -0
  97. package/dist/components/clearable-input.d.ts.map +1 -0
  98. package/dist/components/clearable-input.js +58 -0
  99. package/dist/components/code-block.d.ts +77 -17
  100. package/dist/components/code-block.d.ts.map +1 -1
  101. package/dist/components/code-block.js +85 -15
  102. package/dist/components/collapsible.d.ts +27 -10
  103. package/dist/components/collapsible.d.ts.map +1 -1
  104. package/dist/components/collapsible.js +24 -9
  105. package/dist/components/collection-filters.d.ts +3 -1
  106. package/dist/components/collection-filters.d.ts.map +1 -1
  107. package/dist/components/collection-filters.js +7 -9
  108. package/dist/components/collection-page.d.ts +31 -10
  109. package/dist/components/collection-page.d.ts.map +1 -1
  110. package/dist/components/collection-page.js +14 -13
  111. package/dist/components/collection-search.d.ts +32 -10
  112. package/dist/components/collection-search.d.ts.map +1 -1
  113. package/dist/components/collection-search.js +24 -13
  114. package/dist/components/collection-sort.d.ts.map +1 -1
  115. package/dist/components/collection-sort.js +2 -2
  116. package/dist/components/collection-toolbar.d.ts +5 -2
  117. package/dist/components/collection-toolbar.d.ts.map +1 -1
  118. package/dist/components/collection-toolbar.js +7 -4
  119. package/dist/components/combobox.d.ts +97 -22
  120. package/dist/components/combobox.d.ts.map +1 -1
  121. package/dist/components/combobox.js +80 -28
  122. package/dist/components/command.d.ts +34 -21
  123. package/dist/components/command.d.ts.map +1 -1
  124. package/dist/components/command.js +33 -25
  125. package/dist/components/confirm-dialog.d.ts +23 -6
  126. package/dist/components/confirm-dialog.d.ts.map +1 -1
  127. package/dist/components/confirm-dialog.js +32 -13
  128. package/dist/components/context-menu.d.ts +14 -10
  129. package/dist/components/context-menu.d.ts.map +1 -1
  130. package/dist/components/context-menu.js +17 -12
  131. package/dist/components/copy-button.d.ts +5 -2
  132. package/dist/components/copy-button.d.ts.map +1 -1
  133. package/dist/components/copy-button.js +16 -8
  134. package/dist/components/data-table.d.ts +120 -54
  135. package/dist/components/data-table.d.ts.map +1 -1
  136. package/dist/components/data-table.js +163 -92
  137. package/dist/components/desktop-shell.d.ts +4 -2
  138. package/dist/components/desktop-shell.d.ts.map +1 -1
  139. package/dist/components/desktop-shell.js +3 -3
  140. package/dist/components/dialog.d.ts +63 -24
  141. package/dist/components/dialog.d.ts.map +1 -1
  142. package/dist/components/dialog.js +52 -31
  143. package/dist/components/disclosure-row.d.ts +1 -2
  144. package/dist/components/disclosure-row.d.ts.map +1 -1
  145. package/dist/components/disclosure-row.js +1 -2
  146. package/dist/components/disclosure.d.ts +1 -1
  147. package/dist/components/disclosure.js +1 -1
  148. package/dist/components/drawer.d.ts +33 -12
  149. package/dist/components/drawer.d.ts.map +1 -1
  150. package/dist/components/drawer.js +47 -35
  151. package/dist/components/dropdown-menu.d.ts +59 -14
  152. package/dist/components/dropdown-menu.d.ts.map +1 -1
  153. package/dist/components/dropdown-menu.js +58 -26
  154. package/dist/components/empty-state.d.ts +35 -12
  155. package/dist/components/empty-state.d.ts.map +1 -1
  156. package/dist/components/empty-state.js +35 -17
  157. package/dist/components/entry-scene.d.ts +4 -4
  158. package/dist/components/entry-scene.d.ts.map +1 -1
  159. package/dist/components/entry-scene.js +2 -2
  160. package/dist/components/field.d.ts +44 -14
  161. package/dist/components/field.d.ts.map +1 -1
  162. package/dist/components/field.js +49 -20
  163. package/dist/components/file-diff.d.ts.map +1 -1
  164. package/dist/components/file-diff.js +3 -4
  165. package/dist/components/form-dialog.d.ts +7 -7
  166. package/dist/components/form-dialog.d.ts.map +1 -1
  167. package/dist/components/form-dialog.js +13 -11
  168. package/dist/components/form-drawer.d.ts +10 -7
  169. package/dist/components/form-drawer.d.ts.map +1 -1
  170. package/dist/components/form-drawer.js +11 -10
  171. package/dist/components/gauge.d.ts +64 -0
  172. package/dist/components/gauge.d.ts.map +1 -0
  173. package/dist/components/gauge.js +73 -0
  174. package/dist/components/hover-card.d.ts +72 -14
  175. package/dist/components/hover-card.d.ts.map +1 -1
  176. package/dist/components/hover-card.js +51 -17
  177. package/dist/components/identity-mark.d.ts +8 -1
  178. package/dist/components/identity-mark.d.ts.map +1 -1
  179. package/dist/components/identity-mark.js +31 -5
  180. package/dist/components/input-group.d.ts +44 -21
  181. package/dist/components/input-group.d.ts.map +1 -1
  182. package/dist/components/input-group.js +74 -27
  183. package/dist/components/input.d.ts +64 -12
  184. package/dist/components/input.d.ts.map +1 -1
  185. package/dist/components/input.js +51 -15
  186. package/dist/components/item.d.ts +37 -15
  187. package/dist/components/item.d.ts.map +1 -1
  188. package/dist/components/item.js +41 -22
  189. package/dist/components/kbd.d.ts +49 -13
  190. package/dist/components/kbd.d.ts.map +1 -1
  191. package/dist/components/kbd.js +115 -16
  192. package/dist/components/kpi-card.d.ts +12 -4
  193. package/dist/components/kpi-card.d.ts.map +1 -1
  194. package/dist/components/kpi-card.js +13 -4
  195. package/dist/components/label.d.ts +17 -10
  196. package/dist/components/label.d.ts.map +1 -1
  197. package/dist/components/label.js +18 -11
  198. package/dist/components/library-shelf.d.ts +6 -6
  199. package/dist/components/library-shelf.d.ts.map +1 -1
  200. package/dist/components/library-shelf.js +5 -5
  201. package/dist/components/load-more-button.d.ts +35 -0
  202. package/dist/components/load-more-button.d.ts.map +1 -0
  203. package/dist/components/load-more-button.js +26 -0
  204. package/dist/components/menu-choice-row.d.ts +6 -8
  205. package/dist/components/menu-choice-row.d.ts.map +1 -1
  206. package/dist/components/menu-choice-row.js +8 -8
  207. package/dist/components/message-notice.d.ts +8 -13
  208. package/dist/components/message-notice.d.ts.map +1 -1
  209. package/dist/components/message-notice.js +25 -22
  210. package/dist/components/middle-truncate.d.ts +33 -0
  211. package/dist/components/middle-truncate.d.ts.map +1 -0
  212. package/dist/components/middle-truncate.js +72 -0
  213. package/dist/components/multi-select.d.ts +94 -0
  214. package/dist/components/multi-select.d.ts.map +1 -0
  215. package/dist/components/multi-select.js +132 -0
  216. package/dist/components/native-select.d.ts +37 -13
  217. package/dist/components/native-select.d.ts.map +1 -1
  218. package/dist/components/native-select.js +27 -11
  219. package/dist/components/notice-banner.d.ts +17 -10
  220. package/dist/components/notice-banner.d.ts.map +1 -1
  221. package/dist/components/notice-banner.js +12 -11
  222. package/dist/components/numbered-steps.d.ts +10 -4
  223. package/dist/components/numbered-steps.d.ts.map +1 -1
  224. package/dist/components/numbered-steps.js +9 -7
  225. package/dist/components/object-page.d.ts +40 -14
  226. package/dist/components/object-page.d.ts.map +1 -1
  227. package/dist/components/object-page.js +12 -10
  228. package/dist/components/object-workspace.d.ts +29 -10
  229. package/dist/components/object-workspace.d.ts.map +1 -1
  230. package/dist/components/object-workspace.js +18 -8
  231. package/dist/components/overview-page.d.ts +2 -2
  232. package/dist/components/overview-page.d.ts.map +1 -1
  233. package/dist/components/overview-page.js +8 -7
  234. package/dist/components/page-actions.d.ts +28 -8
  235. package/dist/components/page-actions.d.ts.map +1 -1
  236. package/dist/components/page-actions.js +22 -25
  237. package/dist/components/page-header.d.ts +11 -4
  238. package/dist/components/page-header.d.ts.map +1 -1
  239. package/dist/components/page-header.js +10 -5
  240. package/dist/components/pending-label.d.ts +6 -5
  241. package/dist/components/pending-label.d.ts.map +1 -1
  242. package/dist/components/pending-label.js +14 -6
  243. package/dist/components/picture-label.d.ts +2 -2
  244. package/dist/components/picture-label.d.ts.map +1 -1
  245. package/dist/components/picture-label.js +3 -3
  246. package/dist/components/portal-sidebar-frame.d.ts +9 -21
  247. package/dist/components/portal-sidebar-frame.d.ts.map +1 -1
  248. package/dist/components/portal-sidebar-frame.js +13 -27
  249. package/dist/components/progress-checklist.d.ts +46 -0
  250. package/dist/components/progress-checklist.d.ts.map +1 -0
  251. package/dist/components/progress-checklist.js +46 -0
  252. package/dist/components/progress.d.ts +48 -8
  253. package/dist/components/progress.d.ts.map +1 -1
  254. package/dist/components/progress.js +92 -16
  255. package/dist/components/prose.d.ts +19 -0
  256. package/dist/components/prose.d.ts.map +1 -0
  257. package/dist/components/prose.js +29 -0
  258. package/dist/components/radio-group.d.ts +51 -12
  259. package/dist/components/radio-group.d.ts.map +1 -1
  260. package/dist/components/radio-group.js +42 -12
  261. package/dist/components/reading-column.js +1 -1
  262. package/dist/components/record-identity.d.ts +6 -5
  263. package/dist/components/record-identity.d.ts.map +1 -1
  264. package/dist/components/record-identity.js +12 -3
  265. package/dist/components/record-list.d.ts +117 -27
  266. package/dist/components/record-list.d.ts.map +1 -1
  267. package/dist/components/record-list.js +185 -55
  268. package/dist/components/record-time.d.ts +20 -7
  269. package/dist/components/record-time.d.ts.map +1 -1
  270. package/dist/components/record-time.js +38 -19
  271. package/dist/components/resizable.d.ts +7 -5
  272. package/dist/components/resizable.d.ts.map +1 -1
  273. package/dist/components/resizable.js +6 -6
  274. package/dist/components/scope-switcher.d.ts +2 -0
  275. package/dist/components/scope-switcher.d.ts.map +1 -1
  276. package/dist/components/scope-switcher.js +2 -2
  277. package/dist/components/scroll-area.d.ts +47 -11
  278. package/dist/components/scroll-area.d.ts.map +1 -1
  279. package/dist/components/scroll-area.js +72 -14
  280. package/dist/components/segmented-control.d.ts +82 -0
  281. package/dist/components/segmented-control.d.ts.map +1 -0
  282. package/dist/components/segmented-control.js +90 -0
  283. package/dist/components/select.d.ts +55 -15
  284. package/dist/components/select.d.ts.map +1 -1
  285. package/dist/components/select.js +62 -19
  286. package/dist/components/separator.d.ts +12 -5
  287. package/dist/components/separator.d.ts.map +1 -1
  288. package/dist/components/separator.js +11 -6
  289. package/dist/components/settings-facts.d.ts +34 -14
  290. package/dist/components/settings-facts.d.ts.map +1 -1
  291. package/dist/components/settings-facts.js +21 -12
  292. package/dist/components/settings-page.d.ts +4 -4
  293. package/dist/components/settings-page.js +5 -5
  294. package/dist/components/settings-section.d.ts +160 -34
  295. package/dist/components/settings-section.d.ts.map +1 -1
  296. package/dist/components/settings-section.js +92 -39
  297. package/dist/components/sheet.d.ts +47 -16
  298. package/dist/components/sheet.d.ts.map +1 -1
  299. package/dist/components/sheet.js +40 -19
  300. package/dist/components/sidebar-sections.d.ts +16 -12
  301. package/dist/components/sidebar-sections.d.ts.map +1 -1
  302. package/dist/components/sidebar-sections.js +30 -15
  303. package/dist/components/sidebar.d.ts +117 -21
  304. package/dist/components/sidebar.d.ts.map +1 -1
  305. package/dist/components/sidebar.js +180 -55
  306. package/dist/components/skeleton.d.ts +54 -8
  307. package/dist/components/skeleton.d.ts.map +1 -1
  308. package/dist/components/skeleton.js +44 -9
  309. package/dist/components/slider.d.ts +53 -11
  310. package/dist/components/slider.d.ts.map +1 -1
  311. package/dist/components/slider.js +71 -17
  312. package/dist/components/snippet.d.ts +57 -0
  313. package/dist/components/snippet.d.ts.map +1 -0
  314. package/dist/components/snippet.js +60 -0
  315. package/dist/components/sonner.d.ts +13 -14
  316. package/dist/components/sonner.d.ts.map +1 -1
  317. package/dist/components/sonner.js +25 -22
  318. package/dist/components/status-badge.d.ts +37 -11
  319. package/dist/components/status-badge.d.ts.map +1 -1
  320. package/dist/components/status-badge.js +63 -15
  321. package/dist/components/status-dot.d.ts +42 -11
  322. package/dist/components/status-dot.d.ts.map +1 -1
  323. package/dist/components/status-dot.js +40 -11
  324. package/dist/components/switch.d.ts +43 -12
  325. package/dist/components/switch.d.ts.map +1 -1
  326. package/dist/components/switch.js +42 -12
  327. package/dist/components/table-card.d.ts +21 -12
  328. package/dist/components/table-card.d.ts.map +1 -1
  329. package/dist/components/table-card.js +17 -9
  330. package/dist/components/table-layouts.d.ts +40 -8
  331. package/dist/components/table-layouts.d.ts.map +1 -1
  332. package/dist/components/table-layouts.js +52 -8
  333. package/dist/components/table-value.d.ts +4 -3
  334. package/dist/components/table-value.d.ts.map +1 -1
  335. package/dist/components/table-value.js +6 -5
  336. package/dist/components/table.d.ts +62 -25
  337. package/dist/components/table.d.ts.map +1 -1
  338. package/dist/components/table.js +62 -26
  339. package/dist/components/tabs.d.ts +86 -17
  340. package/dist/components/tabs.d.ts.map +1 -1
  341. package/dist/components/tabs.js +93 -22
  342. package/dist/components/text-link.d.ts +4 -1
  343. package/dist/components/text-link.d.ts.map +1 -1
  344. package/dist/components/text-link.js +4 -1
  345. package/dist/components/text-with-copy-button.d.ts +30 -0
  346. package/dist/components/text-with-copy-button.d.ts.map +1 -0
  347. package/dist/components/text-with-copy-button.js +32 -0
  348. package/dist/components/textarea.d.ts +40 -10
  349. package/dist/components/textarea.d.ts.map +1 -1
  350. package/dist/components/textarea.js +50 -11
  351. package/dist/components/theme-mode-switcher.d.ts +20 -3
  352. package/dist/components/theme-mode-switcher.d.ts.map +1 -1
  353. package/dist/components/theme-mode-switcher.js +23 -6
  354. package/dist/components/toggle-group.d.ts +28 -8
  355. package/dist/components/toggle-group.d.ts.map +1 -1
  356. package/dist/components/toggle-group.js +12 -6
  357. package/dist/components/toggle.d.ts +6 -3
  358. package/dist/components/toggle.d.ts.map +1 -1
  359. package/dist/components/toggle.js +10 -7
  360. package/dist/components/tooltip.d.ts +43 -12
  361. package/dist/components/tooltip.d.ts.map +1 -1
  362. package/dist/components/tooltip.js +45 -16
  363. package/dist/components/trend-badge.js +1 -1
  364. package/dist/components/update-card.js +1 -1
  365. package/dist/eslint/index.js +82 -0
  366. package/dist/eslint/rules/badge-is-static-label.js +93 -0
  367. package/dist/eslint/rules/button-icon-slot.js +102 -0
  368. package/dist/eslint/rules/button-link-for-navigation.js +146 -0
  369. package/dist/eslint/rules/button-no-aria-label-with-text.js +75 -0
  370. package/dist/eslint/rules/button-type-roles-only-in-buttons.js +83 -0
  371. package/dist/eslint/rules/choice-control-has-a-name.js +98 -0
  372. package/dist/eslint/rules/choice-group-in-fieldset.js +86 -0
  373. package/dist/eslint/rules/command-shortcut-single-owner.js +118 -0
  374. package/dist/eslint/rules/confirm-dialog-words.js +63 -0
  375. package/dist/eslint/rules/data-table-one-unsized-column.js +96 -0
  376. package/dist/eslint/rules/destructive-action-placement.js +69 -0
  377. package/dist/eslint/rules/disabled-choice-says-why.js +71 -0
  378. package/dist/eslint/rules/ellipsis-opens-a-dialog.js +110 -0
  379. package/dist/eslint/rules/input-group-owners.js +155 -0
  380. package/dist/eslint/rules/kbd-children-no-modifier-text.js +128 -0
  381. package/dist/eslint/rules/literal-text.js +41 -0
  382. package/dist/eslint/rules/middle-truncate-placement.js +69 -0
  383. package/dist/eslint/rules/no-bare-button-label.js +55 -0
  384. package/dist/eslint/rules/no-control-in-read-only-surface.js +106 -0
  385. package/dist/eslint/rules/no-hand-built-busy.js +104 -0
  386. package/dist/eslint/rules/no-hand-built-theme-picker.js +144 -0
  387. package/dist/eslint/rules/no-hand-built-tile.js +41 -0
  388. package/dist/eslint/rules/no-hand-formatted-date.js +87 -0
  389. package/dist/eslint/rules/no-hand-stacked-avatars.js +67 -0
  390. package/dist/eslint/rules/no-nested-collapse.js +60 -0
  391. package/dist/eslint/rules/no-search-in-form.js +47 -0
  392. package/dist/eslint/rules/no-shadcn-appearance-override.js +2 -16
  393. package/dist/eslint/rules/no-shell-prompt-in-snippet.js +74 -0
  394. package/dist/eslint/rules/no-stock-error-words.js +56 -0
  395. package/dist/eslint/rules/no-tooltip-around-labelled-field.js +72 -0
  396. package/dist/eslint/rules/no-weight-class-on-strong-in-type-role.js +57 -0
  397. package/dist/eslint/rules/one-submenu-level.js +43 -0
  398. package/dist/eslint/rules/one-toast-per-flow.js +91 -0
  399. package/dist/eslint/rules/option-count.js +167 -0
  400. package/dist/eslint/rules/page-command-link-not-render.js +43 -0
  401. package/dist/eslint/rules/progress-needs-name.js +57 -0
  402. package/dist/eslint/rules/settings-limit-in-footer.js +94 -0
  403. package/dist/eslint/rules/skeleton-in-region.js +80 -0
  404. package/dist/eslint/rules/sortable-heading-uses-sort.js +79 -0
  405. package/dist/eslint/rules/table-cell-inset-owner.js +107 -0
  406. package/dist/eslint/rules/tabs-selection-is-controlled.js +47 -0
  407. package/dist/eslint/rules/tooltip-only-arrow.js +38 -0
  408. package/dist/eslint/rules/tooltip-trigger-accessible-name.js +114 -0
  409. package/dist/eslint/strict-design-system.js +21 -7
  410. package/dist/index.d.ts +13 -13
  411. package/dist/index.d.ts.map +1 -1
  412. package/dist/index.js +12 -13
  413. package/dist/internal/assistant-ui/attachment.d.ts.map +1 -1
  414. package/dist/internal/assistant-ui/attachment.js +2 -2
  415. package/dist/internal/assistant-ui/reasoning.d.ts +1 -1
  416. package/dist/internal/assistant-ui/reasoning.d.ts.map +1 -1
  417. package/dist/internal/assistant-ui/tool-fallback.js +1 -1
  418. package/dist/internal/assistant-ui/tool-group.d.ts +1 -1
  419. package/dist/internal/assistant-ui/tool-group.d.ts.map +1 -1
  420. package/dist/internal/assistant-ui/tooltip-icon-button.d.ts +2 -3
  421. package/dist/internal/assistant-ui/tooltip-icon-button.d.ts.map +1 -1
  422. package/dist/internal/assistant-ui/tooltip-icon-button.js +1 -1
  423. package/dist/internal/catalog-list.js +2 -2
  424. package/dist/internal/collection-note.d.ts +23 -0
  425. package/dist/internal/collection-note.d.ts.map +1 -0
  426. package/dist/internal/collection-note.js +17 -0
  427. package/dist/internal/collection-rail.d.ts +57 -0
  428. package/dist/internal/collection-rail.d.ts.map +1 -0
  429. package/dist/internal/collection-rail.js +33 -0
  430. package/dist/internal/company-logo.d.ts +18 -0
  431. package/dist/internal/company-logo.d.ts.map +1 -0
  432. package/dist/internal/company-logo.js +14 -0
  433. package/dist/internal/control-name.d.ts +12 -0
  434. package/dist/internal/control-name.d.ts.map +1 -0
  435. package/dist/internal/control-name.js +1 -0
  436. package/dist/internal/diff-line.d.ts +9 -0
  437. package/dist/internal/diff-line.d.ts.map +1 -0
  438. package/dist/internal/diff-line.js +8 -0
  439. package/dist/internal/empty.d.ts +8 -4
  440. package/dist/internal/empty.d.ts.map +1 -1
  441. package/dist/internal/empty.js +14 -8
  442. package/dist/internal/field-frame.d.ts +33 -0
  443. package/dist/internal/field-frame.d.ts.map +1 -0
  444. package/dist/internal/field-frame.js +20 -0
  445. package/dist/internal/final-focus.d.ts +8 -0
  446. package/dist/internal/final-focus.d.ts.map +1 -0
  447. package/dist/internal/final-focus.js +10 -0
  448. package/dist/internal/footer-strip.d.ts.map +1 -1
  449. package/dist/internal/footer-strip.js +3 -1
  450. package/dist/internal/form-submit.d.ts +9 -5
  451. package/dist/internal/form-submit.d.ts.map +1 -1
  452. package/dist/internal/form-submit.js +31 -2
  453. package/dist/internal/input-box.d.ts +26 -0
  454. package/dist/internal/input-box.d.ts.map +1 -0
  455. package/dist/internal/input-box.js +59 -0
  456. package/dist/internal/menu-surface.d.ts +10 -3
  457. package/dist/internal/menu-surface.d.ts.map +1 -1
  458. package/dist/internal/menu-surface.js +10 -3
  459. package/dist/internal/notice.d.ts +25 -0
  460. package/dist/internal/notice.d.ts.map +1 -0
  461. package/dist/internal/notice.js +33 -0
  462. package/dist/internal/overlay-stem.d.ts +5 -0
  463. package/dist/internal/overlay-stem.d.ts.map +1 -0
  464. package/dist/internal/overlay-stem.js +7 -0
  465. package/dist/internal/phone-sheet.d.ts +4 -0
  466. package/dist/internal/phone-sheet.d.ts.map +1 -0
  467. package/dist/internal/phone-sheet.js +2 -0
  468. package/dist/internal/present-content.d.ts +3 -0
  469. package/dist/internal/present-content.d.ts.map +1 -0
  470. package/dist/internal/present-content.js +1 -0
  471. package/dist/internal/record-menu-items.d.ts +4 -3
  472. package/dist/internal/record-menu-items.d.ts.map +1 -1
  473. package/dist/internal/record-menu-items.js +21 -6
  474. package/dist/internal/settings-save.d.ts +9 -2
  475. package/dist/internal/settings-save.d.ts.map +1 -1
  476. package/dist/internal/settings-save.js +9 -6
  477. package/dist/internal/table-compact-line.d.ts +38 -0
  478. package/dist/internal/table-compact-line.d.ts.map +1 -0
  479. package/dist/internal/table-compact-line.js +35 -0
  480. package/dist/internal/title-when-cut.d.ts +8 -0
  481. package/dist/internal/title-when-cut.d.ts.map +1 -0
  482. package/dist/internal/title-when-cut.js +22 -0
  483. package/dist/internal/unsaved-guard.d.ts +18 -0
  484. package/dist/internal/unsaved-guard.d.ts.map +1 -0
  485. package/dist/internal/unsaved-guard.js +31 -0
  486. package/dist/lib/merge-tokens.generated.js +2 -2
  487. package/dist/showcase/foundations.d.ts.map +1 -1
  488. package/dist/showcase/foundations.js +10 -2
  489. package/dist/showcase/specimens/actions.d.ts +2 -0
  490. package/dist/showcase/specimens/actions.d.ts.map +1 -1
  491. package/dist/showcase/specimens/actions.js +30 -5
  492. package/dist/showcase/specimens/charts.d.ts.map +1 -1
  493. package/dist/showcase/specimens/charts.js +22 -13
  494. package/dist/showcase/specimens/choices.d.ts +14 -3
  495. package/dist/showcase/specimens/choices.d.ts.map +1 -1
  496. package/dist/showcase/specimens/choices.js +93 -13
  497. package/dist/showcase/specimens/compositions.d.ts.map +1 -1
  498. package/dist/showcase/specimens/compositions.js +136 -23
  499. package/dist/showcase/specimens/data.d.ts +12 -7
  500. package/dist/showcase/specimens/data.d.ts.map +1 -1
  501. package/dist/showcase/specimens/data.js +139 -35
  502. package/dist/showcase/specimens/feedback.d.ts +2 -0
  503. package/dist/showcase/specimens/feedback.d.ts.map +1 -1
  504. package/dist/showcase/specimens/feedback.js +39 -15
  505. package/dist/showcase/specimens/index.d.ts +20 -12
  506. package/dist/showcase/specimens/index.d.ts.map +1 -1
  507. package/dist/showcase/specimens/inputs.d.ts +4 -2
  508. package/dist/showcase/specimens/inputs.d.ts.map +1 -1
  509. package/dist/showcase/specimens/inputs.js +62 -19
  510. package/dist/showcase/specimens/menus.d.ts +0 -1
  511. package/dist/showcase/specimens/menus.d.ts.map +1 -1
  512. package/dist/showcase/specimens/menus.js +47 -18
  513. package/dist/showcase/specimens/navigation.d.ts +6 -4
  514. package/dist/showcase/specimens/navigation.d.ts.map +1 -1
  515. package/dist/showcase/specimens/navigation.js +61 -32
  516. package/dist/showcase/specimens/other.d.ts +1 -3
  517. package/dist/showcase/specimens/other.d.ts.map +1 -1
  518. package/dist/showcase/specimens/other.js +17 -13
  519. package/dist/showcase/specimens/status.d.ts +4 -1
  520. package/dist/showcase/specimens/status.d.ts.map +1 -1
  521. package/dist/showcase/specimens/status.js +64 -11
  522. package/dist/showcase/usage.generated.d.ts +1 -1
  523. package/dist/showcase/usage.generated.d.ts.map +1 -1
  524. package/dist/showcase/usage.generated.js +637 -549
  525. package/dist/standalone/index.js +1 -1
  526. package/dist/styles/components.css +13 -13
  527. package/dist/styles/globals.css +25 -0
  528. package/package.json +2 -3
  529. package/dist/components/approval-row.d.ts +0 -34
  530. package/dist/components/approval-row.d.ts.map +0 -1
  531. package/dist/components/approval-row.js +0 -27
  532. package/dist/components/channel-view.d.ts +0 -112
  533. package/dist/components/channel-view.d.ts.map +0 -1
  534. package/dist/components/channel-view.js +0 -84
  535. package/dist/components/dashboard-shell.d.ts +0 -51
  536. package/dist/components/dashboard-shell.d.ts.map +0 -1
  537. package/dist/components/dashboard-shell.js +0 -89
  538. package/dist/components/direction.d.ts +0 -2
  539. package/dist/components/direction.d.ts.map +0 -1
  540. package/dist/components/direction.js +0 -1
  541. package/dist/components/expandable-block.d.ts +0 -20
  542. package/dist/components/expandable-block.d.ts.map +0 -1
  543. package/dist/components/expandable-block.js +0 -32
  544. package/dist/components/form.d.ts +0 -42
  545. package/dist/components/form.d.ts.map +0 -1
  546. package/dist/components/form.js +0 -91
  547. package/dist/components/label-system.d.ts +0 -17
  548. package/dist/components/label-system.d.ts.map +0 -1
  549. package/dist/components/label-system.js +0 -21
  550. package/dist/components/memory-item.d.ts +0 -21
  551. package/dist/components/memory-item.d.ts.map +0 -1
  552. package/dist/components/memory-item.js +0 -18
  553. package/dist/components/menubar.d.ts +0 -43
  554. package/dist/components/menubar.d.ts.map +0 -1
  555. package/dist/components/menubar.js +0 -69
  556. package/dist/components/navigation-menu.d.ts +0 -26
  557. package/dist/components/navigation-menu.d.ts.map +0 -1
  558. package/dist/components/navigation-menu.js +0 -45
  559. package/dist/components/pagination.d.ts +0 -33
  560. package/dist/components/pagination.d.ts.map +0 -1
  561. package/dist/components/pagination.js +0 -41
  562. package/dist/components/plugin-slot-boundary.d.ts +0 -42
  563. package/dist/components/plugin-slot-boundary.d.ts.map +0 -1
  564. package/dist/components/plugin-slot-boundary.js +0 -41
  565. package/dist/components/status-row.d.ts +0 -32
  566. package/dist/components/status-row.d.ts.map +0 -1
  567. package/dist/components/status-row.js +0 -35
@@ -0,0 +1,102 @@
1
+ /*
2
+ * Standard tool checked first: the `repo/shadcn-composition` selector in the
3
+ * root config (`Button JSXOpeningElement[name.name=/Icon$/]` without
4
+ * `data-icon`) matches by element name under any `Button`, so it cannot tell a
5
+ * text Button from an icon-only one (the size decides where an icon goes), nor
6
+ * a `Button` imported from `@nadicodeai/ui` from a local one, nor an icon bound
7
+ * to an icon module from a component that only ends in `Icon`.
8
+ */
9
+ import {
10
+ PACKAGE_BARREL,
11
+ partOf,
12
+ renderedImports,
13
+ sourceMatches,
14
+ staticAttribute,
15
+ writtenName,
16
+ } from "./rendered-import.js";
17
+
18
+ const BUTTONS = new Map(
19
+ ["Button", "ButtonLink"].map((name) => [
20
+ name,
21
+ ["@nadicodeai/ui/components/button", PACKAGE_BARREL].map((from) => ({ from, part: name })),
22
+ ]),
23
+ );
24
+
25
+ const TEXT_SIZES = new Set(["default", "xs", "sm", "lg"]);
26
+
27
+ const isAttribute = (attribute, name) =>
28
+ attribute.type === "JSXAttribute" && attribute.name.name === name;
29
+
30
+ export const buttonIconSlot = {
31
+ meta: {
32
+ type: "problem",
33
+ docs: {
34
+ description:
35
+ "A text Button takes its icon as prefix or suffix; an icon-only Button takes the icon as its child with no data-icon.",
36
+ },
37
+ schema: [
38
+ {
39
+ type: "object",
40
+ properties: {
41
+ iconModules: { type: "array", items: { type: "string" }, uniqueItems: true },
42
+ },
43
+ additionalProperties: false,
44
+ },
45
+ ],
46
+ defaultOptions: [{ iconModules: ["lucide-react", "@nadicodeai/ui/components/house-icons"] }],
47
+ messages: {
48
+ "icon-slot":
49
+ 'Pass an icon in a text Button as prefix={<Icon />} or suffix={<Icon />}; an icon-only Button (size="icon") takes the icon as its child.',
50
+ },
51
+ },
52
+ create(context) {
53
+ const [{ iconModules }] = context.options;
54
+ const importOf = renderedImports(context);
55
+ const isButton = (openingElement) =>
56
+ partOf(importOf(openingElement.name), BUTTONS, context.filename) !== null;
57
+
58
+ const isIcon = (openingElement) => {
59
+ const imported = importOf(openingElement.name);
60
+ if (
61
+ imported &&
62
+ iconModules.some((module) => sourceMatches(imported.source, module, context.filename))
63
+ ) {
64
+ return true;
65
+ }
66
+ return /Icon$/.test(writtenName(openingElement.name) ?? "");
67
+ };
68
+
69
+ function enclosingButton(node) {
70
+ for (let current = node.parent.parent; current; current = current.parent) {
71
+ if (current.type === "JSXAttribute") return null;
72
+ if (current.type === "JSXElement" && isButton(current.openingElement)) {
73
+ return current.openingElement;
74
+ }
75
+ }
76
+ return null;
77
+ }
78
+
79
+ function takesTextSize(button) {
80
+ if (button.attributes.some((attribute) => attribute.type === "JSXSpreadAttribute")) {
81
+ return false;
82
+ }
83
+ if (!button.attributes.some((attribute) => isAttribute(attribute, "size"))) return true;
84
+ return TEXT_SIZES.has(staticAttribute(button, "size"));
85
+ }
86
+
87
+ return {
88
+ JSXOpeningElement(node) {
89
+ if (node.parent.type !== "JSXElement") return;
90
+ const carriesDataIcon = node.attributes.some((attribute) =>
91
+ isAttribute(attribute, "data-icon"),
92
+ );
93
+ if (!carriesDataIcon && !isIcon(node)) return;
94
+ const button = enclosingButton(node);
95
+ if (!button) return;
96
+ if (carriesDataIcon || takesTextSize(button)) {
97
+ context.report({ node, messageId: "icon-slot" });
98
+ }
99
+ },
100
+ };
101
+ },
102
+ };
@@ -0,0 +1,146 @@
1
+ /*
2
+ * Standard tool checked first: `no-restricted-imports` can hold `buttonVariants`
3
+ * back, but not tell the Buzz tree's own `buttonVariants` from the package's, and
4
+ * a `no-restricted-syntax` selector cannot follow a renamed `Button` import to
5
+ * the `onClick` and `render` it reads.
6
+ */
7
+ import { PACKAGE_BARREL, partOf, renderedImports, writtenName } from "./rendered-import.js";
8
+
9
+ const BUTTON_MODULES = ["@nadicodeai/ui/components/button", PACKAGE_BARREL];
10
+
11
+ const BUTTON = new Map([["Button", BUTTON_MODULES.map((from) => ({ from, part: "Button" }))]]);
12
+
13
+ const LINK_ELEMENTS = new Set(["a", "Link", "NextLink"]);
14
+ const ROUTER_METHODS = new Set(["push", "replace"]);
15
+ const FUNCTIONS = new Set(["FunctionExpression", "ArrowFunctionExpression"]);
16
+
17
+ function variantsBindings(context) {
18
+ const names = new Set();
19
+ const namespaces = new Set();
20
+ for (const statement of context.sourceCode.ast.body) {
21
+ if (statement.type !== "ImportDeclaration" || statement.importKind === "type") continue;
22
+ if (!BUTTON_MODULES.includes(statement.source.value)) continue;
23
+ for (const specifier of statement.specifiers) {
24
+ if (specifier.importKind === "type") continue;
25
+ if (specifier.type === "ImportNamespaceSpecifier") namespaces.add(specifier.local.name);
26
+ else if (
27
+ specifier.type === "ImportSpecifier" &&
28
+ (specifier.imported.name ?? specifier.imported.value) === "buttonVariants"
29
+ ) {
30
+ names.add(specifier.local.name);
31
+ }
32
+ }
33
+ }
34
+ return (callee) => {
35
+ if (callee.type === "Identifier") return names.has(callee.name);
36
+ return (
37
+ callee.type === "MemberExpression" &&
38
+ !callee.computed &&
39
+ callee.object.type === "Identifier" &&
40
+ namespaces.has(callee.object.name) &&
41
+ callee.property.name === "buttonVariants"
42
+ );
43
+ };
44
+ }
45
+
46
+ const unwrap = (node) => {
47
+ if (node.type === "AwaitExpression") return unwrap(node.argument);
48
+ if (node.type === "UnaryExpression" && node.operator === "void") return unwrap(node.argument);
49
+ if (node.type === "ChainExpression") return unwrap(node.expression);
50
+ return node;
51
+ };
52
+
53
+ const isLocationTarget = (node) => {
54
+ if (node.type !== "MemberExpression" || node.computed) return false;
55
+ const { object, property } = node;
56
+ if (object.type === "Identifier") {
57
+ if (object.name === "window") return property.name === "location";
58
+ return object.name === "location" && property.name === "href";
59
+ }
60
+ return (
61
+ isLocationTarget(object) && object.property.name === "location" && property.name === "href"
62
+ );
63
+ };
64
+
65
+ function goesToAnAddress(expression) {
66
+ const node = unwrap(expression);
67
+ if (node.type === "AssignmentExpression") return isLocationTarget(node.left);
68
+ if (node.type !== "CallExpression") return false;
69
+ const { callee } = node;
70
+ if (callee.type === "Identifier") return callee.name === "navigate";
71
+ return (
72
+ callee.type === "MemberExpression" &&
73
+ !callee.computed &&
74
+ callee.object.type === "Identifier" &&
75
+ callee.object.name === "router" &&
76
+ ROUTER_METHODS.has(callee.property.name)
77
+ );
78
+ }
79
+
80
+ function onlyGoesToAnAddress(fn) {
81
+ if (fn.body.type !== "BlockStatement") return goesToAnAddress(fn.body);
82
+ const { body } = fn.body;
83
+ return (
84
+ body.length > 0 &&
85
+ body.every(
86
+ (statement) =>
87
+ statement.type === "ExpressionStatement" && goesToAnAddress(statement.expression),
88
+ )
89
+ );
90
+ }
91
+
92
+ const attributeValue = (openingElement, attributeName) => {
93
+ const attribute = openingElement.attributes.find(
94
+ (candidate) => candidate.type === "JSXAttribute" && candidate.name.name === attributeName,
95
+ );
96
+ return attribute?.value?.type === "JSXExpressionContainer" ? attribute.value.expression : null;
97
+ };
98
+
99
+ const isLinkElement = (node) =>
100
+ node?.type === "JSXElement" && LINK_ELEMENTS.has(writtenName(node.openingElement.name) ?? "");
101
+
102
+ function enclosingAttribute(node) {
103
+ for (let current = node.parent; current; current = current.parent) {
104
+ if (current.type === "JSXAttribute") return current;
105
+ }
106
+ return null;
107
+ }
108
+
109
+ export const buttonLinkForNavigation = {
110
+ meta: {
111
+ type: "problem",
112
+ docs: {
113
+ description: "A control that goes to an address is a ButtonLink; a Button runs a command.",
114
+ },
115
+ schema: [],
116
+ messages: {
117
+ "navigating-button":
118
+ "A control that goes to an address is a ButtonLink; a Button runs a command.",
119
+ },
120
+ },
121
+ create(context) {
122
+ const importOf = renderedImports(context);
123
+ const isButtonVariants = variantsBindings(context);
124
+ return {
125
+ CallExpression(node) {
126
+ if (!isButtonVariants(node.callee)) return;
127
+ const attribute = enclosingAttribute(node);
128
+ if (attribute?.name.name !== "className") return;
129
+ if (isLinkElement(attribute.parent.parent)) {
130
+ context.report({ node, messageId: "navigating-button" });
131
+ }
132
+ },
133
+ JSXOpeningElement(node) {
134
+ if (partOf(importOf(node.name), BUTTON, context.filename) !== "Button") return;
135
+ const onClick = attributeValue(node, "onClick");
136
+ if (onClick && FUNCTIONS.has(onClick.type) && onlyGoesToAnAddress(onClick)) {
137
+ context.report({ node, messageId: "navigating-button" });
138
+ return;
139
+ }
140
+ if (isLinkElement(attributeValue(node, "render"))) {
141
+ context.report({ node, messageId: "navigating-button" });
142
+ }
143
+ },
144
+ };
145
+ },
146
+ };
@@ -0,0 +1,75 @@
1
+ /*
2
+ * Standard tool checked first: a `no-restricted-syntax` selector can match
3
+ * `JSXElement[openingElement.name.name='Button']:has(JSXAttribute[name.name='aria-label'])`,
4
+ * but not that the element is the package's Button rather than a local one with
5
+ * the same name, nor that a child is text rather than an icon, nor the `size`
6
+ * that makes a non-literal child an icon-only label. Those need the import
7
+ * binding and the children read together.
8
+ */
9
+ import { PACKAGE_BARREL, partOf, renderedImports, staticAttribute } from "./rendered-import.js";
10
+
11
+ const BUTTONS = new Map(
12
+ ["Button", "ButtonLink"].map((name) => [
13
+ name,
14
+ ["@nadicodeai/ui/components/button", PACKAGE_BARREL].map((from) => ({ from, part: name })),
15
+ ]),
16
+ );
17
+
18
+ const NAMING_ATTRIBUTES = new Set(["aria-label", "aria-labelledby"]);
19
+
20
+ const namesItself = (openingElement) =>
21
+ openingElement.attributes.some(
22
+ (attribute) => attribute.type === "JSXAttribute" && NAMING_ATTRIBUTES.has(attribute.name.name),
23
+ );
24
+
25
+ const isIconSize = (openingElement) =>
26
+ String(staticAttribute(openingElement, "size") ?? "").startsWith("icon");
27
+
28
+ function staticText(expression) {
29
+ if (expression.type === "Literal") {
30
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- ESTree types Literal.value as string | number | boolean | RegExp | bigint | null; only typeof picks the string.
31
+ return typeof expression.value === "string" ? expression.value : null;
32
+ }
33
+ if (expression.type === "TemplateLiteral" && expression.expressions.length === 0) {
34
+ return expression.quasis[0].value.cooked;
35
+ }
36
+ return null;
37
+ }
38
+
39
+ function childText(child) {
40
+ if (child.type === "JSXText") return child.value.trim() === "" ? "none" : "visible";
41
+ if (child.type !== "JSXExpressionContainer") return "none";
42
+ const { expression } = child;
43
+ if (expression.type === "JSXEmptyExpression") return "none";
44
+ const text = staticText(expression);
45
+ if (text !== null) return text.trim() === "" ? "none" : "visible";
46
+ return expression.type === "Literal" ? "none" : "computed";
47
+ }
48
+
49
+ export const buttonNoAriaLabelWithText = {
50
+ meta: {
51
+ type: "problem",
52
+ docs: {
53
+ description: "A Button with visible text is named by its text, never by an aria-label.",
54
+ },
55
+ schema: [],
56
+ messages: {
57
+ "named-by-its-text":
58
+ "A Button with visible text is named by its text; remove aria-label. When the text alone does not name the target, use `accessibleName` on a PageCommand.",
59
+ },
60
+ },
61
+ create(context) {
62
+ const importOf = renderedImports(context);
63
+ return {
64
+ JSXElement(node) {
65
+ const { openingElement } = node;
66
+ if (!partOf(importOf(openingElement.name), BUTTONS, context.filename)) return;
67
+ if (!namesItself(openingElement)) return;
68
+ const kinds = node.children.map(childText);
69
+ const showsText =
70
+ kinds.includes("visible") || (kinds.includes("computed") && !isIconSize(openingElement));
71
+ if (showsText) context.report({ node: openingElement, messageId: "named-by-its-text" });
72
+ },
73
+ };
74
+ },
75
+ };
@@ -0,0 +1,83 @@
1
+ /*
2
+ * Standard tool checked first: `no-restricted-syntax` can match a class token
3
+ * in a `className` literal (strict-design-system.js does), but not which file
4
+ * the token is in, so it cannot allow the files that render a button and refuse
5
+ * the rest, nor tell the small role's two files from the other four.
6
+ */
7
+
8
+ const BUTTON_ROLE = /(?:^|:)!?(text-button(?:-lg|-xs)?|nc-type-button(?:-[a-z0-9]+)*)!?$/;
9
+ const SMALL_ROLE = /-xs$/;
10
+ const CLASS_FUNCTIONS = new Set(["cva", "cn"]);
11
+
12
+ const inFiles = (filename, files) => {
13
+ const path = filename.replaceAll("\\", "/");
14
+ return files.some((file) => path === file || path.endsWith(`/${file}`));
15
+ };
16
+
17
+ const classSite = (node) => {
18
+ for (let current = node.parent; current; current = current.parent) {
19
+ if (current.type === "JSXAttribute") return current.name.name === "className";
20
+ if (
21
+ current.type === "CallExpression" &&
22
+ current.callee.type === "Identifier" &&
23
+ CLASS_FUNCTIONS.has(current.callee.name)
24
+ ) {
25
+ return true;
26
+ }
27
+ }
28
+ return false;
29
+ };
30
+
31
+ const isVariantKey = (node) => node.parent.type === "Property" && node.parent.key === node;
32
+
33
+ export const buttonTypeRolesOnlyInButtons = {
34
+ meta: {
35
+ type: "problem",
36
+ docs: {
37
+ description:
38
+ "The button type roles label a component that renders a button, in the files that render one.",
39
+ },
40
+ schema: [
41
+ {
42
+ type: "object",
43
+ properties: {
44
+ allow: { type: "array", items: { type: "string" }, uniqueItems: true },
45
+ allowSmall: { type: "array", items: { type: "string" }, uniqueItems: true },
46
+ },
47
+ additionalProperties: false,
48
+ },
49
+ ],
50
+ defaultOptions: [{ allow: [], allowSmall: [] }],
51
+ messages: {
52
+ "button-role":
53
+ "Button type roles label a component that renders a button. Use a body-* or label-* role for other text; text-button-xs is only for the small button inside a field.",
54
+ },
55
+ },
56
+ create(context) {
57
+ const [{ allow, allowSmall }] = context.options;
58
+ const inAllowed = inFiles(context.filename, allow);
59
+ const inSmallAllowed = inFiles(context.filename, allowSmall);
60
+
61
+ const refused = (value) =>
62
+ value
63
+ .split(/\s+/)
64
+ .map((utility) => BUTTON_ROLE.exec(utility)?.[1])
65
+ .filter(Boolean)
66
+ .some((role) => (SMALL_ROLE.test(role) ? !inSmallAllowed : !inAllowed));
67
+
68
+ function check(node, value) {
69
+ if (isVariantKey(node) || !classSite(node)) return;
70
+ if (refused(value)) context.report({ node, messageId: "button-role" });
71
+ }
72
+
73
+ return {
74
+ Literal(node) {
75
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- ESTree types Literal.value as string | number | boolean | RegExp | bigint | null; only typeof picks the string.
76
+ if (typeof node.value === "string") check(node, node.value);
77
+ },
78
+ TemplateElement(node) {
79
+ check(node, node.value.cooked ?? node.value.raw);
80
+ },
81
+ };
82
+ },
83
+ };
@@ -0,0 +1,98 @@
1
+ /*
2
+ * Standard tool checked first: `jsx-a11y/label-has-associated-control` checks a
3
+ * Label for a control, not a control for a name, and a `no-restricted-syntax`
4
+ * selector cannot tell that the package's Checkbox is meant rather than a local
5
+ * one, that a Label elsewhere in the file points at its id through `htmlFor`,
6
+ * or that a labelling ancestor wraps it. Those need the import bindings, the
7
+ * ancestors and the file's labels read together.
8
+ */
9
+ import { packageModules, partOf, renderedImports, staticAttribute } from "./rendered-import.js";
10
+
11
+ const partsIn = (module, names) =>
12
+ names.map((name) => [
13
+ name,
14
+ [...packageModules(module), `@/components/${module}`].map((from) => ({ from, part: name })),
15
+ ]);
16
+
17
+ const CONTROLS = new Map([
18
+ ...partsIn("checkbox", ["Checkbox"]),
19
+ ...partsIn("switch", ["Switch"]),
20
+ ...partsIn("radio-group", ["RadioGroupItem"]),
21
+ ]);
22
+
23
+ const LABELS = new Map([...partsIn("label", ["Label"]), ...partsIn("field", ["FieldLabel"])]);
24
+
25
+ const NAMING_ANCESTORS = new Map([...LABELS, ...partsIn("settings-section", ["SettingsField"])]);
26
+
27
+ const NAMING_ATTRIBUTES = new Set(["aria-label", "aria-labelledby"]);
28
+
29
+ const findAttribute = (openingElement, name) =>
30
+ openingElement.attributes.find(
31
+ (attribute) => attribute.type === "JSXAttribute" && attribute.name.name === name,
32
+ );
33
+
34
+ const hasSpread = (openingElement) =>
35
+ openingElement.attributes.some((attribute) => attribute.type === "JSXSpreadAttribute");
36
+
37
+ export const choiceControlHasAName = {
38
+ meta: {
39
+ type: "problem",
40
+ docs: {
41
+ description:
42
+ "A Checkbox, Switch or RadioGroupItem is named by an aria-label, an aria-labelledby, a Label with htmlFor, or a labelling ancestor.",
43
+ },
44
+ schema: [],
45
+ messages: {
46
+ unnamed:
47
+ "Name this control: give it an aria-label (a row's checkbox: Select <row name>), an aria-labelledby, or a Label with htmlFor.",
48
+ },
49
+ },
50
+ create(context) {
51
+ const importOf = renderedImports(context);
52
+ const isPart = (parts) => (openingElement) =>
53
+ Boolean(partOf(importOf(openingElement.name), parts, context.filename));
54
+ const isControl = isPart(CONTROLS);
55
+ const isLabel = isPart(LABELS);
56
+ const isNamingAncestor = isPart(NAMING_ANCESTORS);
57
+
58
+ const reference = (openingElement, attributeName) => {
59
+ const attribute = findAttribute(openingElement, attributeName);
60
+ if (!attribute) return null;
61
+ const stated = staticAttribute(openingElement, attributeName);
62
+ if (stated !== undefined) return String(stated);
63
+ return attribute.value ? context.sourceCode.getText(attribute.value) : null;
64
+ };
65
+
66
+ const controls = [];
67
+ const pointedAt = new Set();
68
+
69
+ const hasNamingAncestor = (element) => {
70
+ for (let current = element.parent; current; current = current.parent) {
71
+ if (current.type === "JSXElement" && isNamingAncestor(current.openingElement)) return true;
72
+ }
73
+ return false;
74
+ };
75
+
76
+ return {
77
+ JSXElement(node) {
78
+ const { openingElement } = node;
79
+ if (isLabel(openingElement)) {
80
+ const target = reference(openingElement, "htmlFor");
81
+ if (target !== null) pointedAt.add(target);
82
+ return;
83
+ }
84
+ if (!isControl(openingElement)) return;
85
+ if (hasSpread(openingElement)) return;
86
+ if (openingElement.attributes.some((a) => NAMING_ATTRIBUTES.has(a.name?.name))) return;
87
+ if (hasNamingAncestor(node)) return;
88
+ controls.push({ node: openingElement, id: reference(openingElement, "id") });
89
+ },
90
+ "Program:exit"() {
91
+ for (const { node, id } of controls) {
92
+ if (id !== null && pointedAt.has(id)) continue;
93
+ context.report({ node, messageId: "unnamed" });
94
+ }
95
+ },
96
+ };
97
+ },
98
+ };
@@ -0,0 +1,86 @@
1
+ /*
2
+ * Standard tool checked first: a `no-restricted-syntax` selector can match a
3
+ * `RadioGroup` without a `FieldSet` ancestor, but not that the `FieldSet`
4
+ * holds a `FieldLegend`, nor that two `Checkbox` elements share a parent once
5
+ * each sits in its own `Field`, so it would miss the checkbox group.
6
+ */
7
+ import { findBelow, renderedImports } from "./rendered-import.js";
8
+
9
+ const FROM_DESIGN_SYSTEM = /^(@nadicodeai\/ui(\/|$)|@\/|\.)/;
10
+ const ROW_WRAPPERS = new Set(["Field", "FieldContent", "FieldLabel", "Label"]);
11
+
12
+ const isRepeater = (node) =>
13
+ (node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression") &&
14
+ node.parent.type === "CallExpression" &&
15
+ node.parent.callee.type === "MemberExpression" &&
16
+ node.parent.callee.property.name === "map";
17
+
18
+ export const choiceGroupInFieldset = {
19
+ meta: {
20
+ type: "problem",
21
+ docs: {
22
+ description: "A group of radios or checkboxes sits in a FieldSet with a FieldLegend.",
23
+ },
24
+ schema: [],
25
+ messages: {
26
+ "choice-group":
27
+ "A group of radios or checkboxes sits in a FieldSet with a FieldLegend, so the group is announced by its legend.",
28
+ },
29
+ },
30
+ create(context) {
31
+ const importOf = renderedImports(context);
32
+ const exportOf = (element) => {
33
+ const imported = importOf(element.openingElement.name);
34
+ return imported && FROM_DESIGN_SYSTEM.test(imported.source) ? imported.name : null;
35
+ };
36
+ const checkboxGroups = new Map();
37
+
38
+ function hasLegendedFieldSet(node) {
39
+ for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
40
+ if (ancestor.type !== "JSXElement" || exportOf(ancestor) !== "FieldSet") continue;
41
+ const legend = findBelow(
42
+ ancestor,
43
+ context.sourceCode.visitorKeys,
44
+ (child) => child.type === "JSXElement" && exportOf(child) === "FieldLegend",
45
+ );
46
+ if (legend) return true;
47
+ }
48
+ return false;
49
+ }
50
+
51
+ function reportUnlessGrouped(element) {
52
+ if (!hasLegendedFieldSet(element)) {
53
+ context.report({ node: element.openingElement, messageId: "choice-group" });
54
+ }
55
+ }
56
+
57
+ function recordCheckbox(element) {
58
+ let repeated = false;
59
+ let parent = element.parent;
60
+ while (parent) {
61
+ if (isRepeater(parent)) repeated = true;
62
+ const isRow = parent.type === "JSXElement" && ROW_WRAPPERS.has(exportOf(parent));
63
+ const isGroup = (parent.type === "JSXElement" || parent.type === "JSXFragment") && !isRow;
64
+ if (isGroup) break;
65
+ parent = parent.parent;
66
+ }
67
+ if (!parent) return;
68
+ const group = checkboxGroups.get(parent) ?? { first: element, count: 0 };
69
+ group.count += repeated ? 2 : 1;
70
+ checkboxGroups.set(parent, group);
71
+ }
72
+
73
+ return {
74
+ JSXElement(node) {
75
+ const name = exportOf(node);
76
+ if (name === "RadioGroup") reportUnlessGrouped(node);
77
+ else if (name === "Checkbox") recordCheckbox(node);
78
+ },
79
+ "Program:exit"() {
80
+ for (const { first, count } of checkboxGroups.values()) {
81
+ if (count >= 2) reportUnlessGrouped(first);
82
+ }
83
+ },
84
+ };
85
+ },
86
+ };