@nadicodeai/ui 12.1.102 → 12.1.104

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 (562) 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.js +2 -2
  5. package/dist/components/action-menu.d.ts +20 -19
  6. package/dist/components/action-menu.d.ts.map +1 -1
  7. package/dist/components/action-menu.js +22 -15
  8. package/dist/components/action-status.d.ts +14 -10
  9. package/dist/components/action-status.d.ts.map +1 -1
  10. package/dist/components/action-status.js +14 -10
  11. package/dist/components/activity-calendar.d.ts +3 -1
  12. package/dist/components/activity-calendar.d.ts.map +1 -1
  13. package/dist/components/activity-calendar.js +16 -2
  14. package/dist/components/activity-feed.d.ts +2 -2
  15. package/dist/components/activity-feed.d.ts.map +1 -1
  16. package/dist/components/activity-feed.js +14 -5
  17. package/dist/components/agent-card.d.ts +11 -5
  18. package/dist/components/agent-card.d.ts.map +1 -1
  19. package/dist/components/agent-card.js +13 -7
  20. package/dist/components/agent-list-row.js +1 -1
  21. package/dist/components/agent-orb-appearance.d.ts +7 -1
  22. package/dist/components/agent-orb-appearance.d.ts.map +1 -1
  23. package/dist/components/agent-orb-appearance.js +26 -0
  24. package/dist/components/agent-profile.d.ts +8 -7
  25. package/dist/components/agent-profile.d.ts.map +1 -1
  26. package/dist/components/agent-profile.js +6 -6
  27. package/dist/components/alert-dialog.d.ts +25 -16
  28. package/dist/components/alert-dialog.d.ts.map +1 -1
  29. package/dist/components/alert-dialog.js +30 -18
  30. package/dist/components/alert.d.ts +1 -1
  31. package/dist/components/avatar.d.ts +83 -17
  32. package/dist/components/avatar.d.ts.map +1 -1
  33. package/dist/components/avatar.js +89 -23
  34. package/dist/components/badge.d.ts +59 -8
  35. package/dist/components/badge.d.ts.map +1 -1
  36. package/dist/components/badge.js +57 -14
  37. package/dist/components/breadcrumb.d.ts +18 -7
  38. package/dist/components/breadcrumb.d.ts.map +1 -1
  39. package/dist/components/breadcrumb.js +37 -13
  40. package/dist/components/button-group.d.ts +12 -15
  41. package/dist/components/button-group.d.ts.map +1 -1
  42. package/dist/components/button-group.js +13 -17
  43. package/dist/components/button.d.ts +126 -23
  44. package/dist/components/button.d.ts.map +1 -1
  45. package/dist/components/button.js +164 -39
  46. package/dist/components/calendar.d.ts +26 -15
  47. package/dist/components/calendar.d.ts.map +1 -1
  48. package/dist/components/calendar.js +60 -46
  49. package/dist/components/card-row.d.ts +13 -5
  50. package/dist/components/card-row.d.ts.map +1 -1
  51. package/dist/components/card-row.js +24 -10
  52. package/dist/components/card.d.ts +6 -12
  53. package/dist/components/card.d.ts.map +1 -1
  54. package/dist/components/card.js +11 -16
  55. package/dist/components/carousel.d.ts +3 -3
  56. package/dist/components/carousel.d.ts.map +1 -1
  57. package/dist/components/carousel.js +7 -7
  58. package/dist/components/catalog-drawer.d.ts +7 -7
  59. package/dist/components/catalog-drawer.d.ts.map +1 -1
  60. package/dist/components/catalog-drawer.js +6 -6
  61. package/dist/components/chart-area-stacked.d.ts +1 -1
  62. package/dist/components/chart-area-stacked.d.ts.map +1 -1
  63. package/dist/components/chart-area-stacked.js +4 -4
  64. package/dist/components/chart-axis.d.ts +14 -1
  65. package/dist/components/chart-axis.d.ts.map +1 -1
  66. package/dist/components/chart-axis.js +11 -1
  67. package/dist/components/chart-bar-horizontal.d.ts +2 -2
  68. package/dist/components/chart-bar-horizontal.d.ts.map +1 -1
  69. package/dist/components/chart-bar-horizontal.js +14 -5
  70. package/dist/components/chart-bar-multiple.d.ts +1 -1
  71. package/dist/components/chart-bar-multiple.d.ts.map +1 -1
  72. package/dist/components/chart-bar-multiple.js +3 -3
  73. package/dist/components/chart-bar-stacked.d.ts +1 -1
  74. package/dist/components/chart-bar-stacked.d.ts.map +1 -1
  75. package/dist/components/chart-bar-stacked.js +3 -3
  76. package/dist/components/chart-card.d.ts +17 -6
  77. package/dist/components/chart-card.d.ts.map +1 -1
  78. package/dist/components/chart-card.js +11 -4
  79. package/dist/components/chart-date-range-control.d.ts +18 -9
  80. package/dist/components/chart-date-range-control.d.ts.map +1 -1
  81. package/dist/components/chart-date-range-control.js +43 -47
  82. package/dist/components/chart-sparkline.d.ts +4 -3
  83. package/dist/components/chart-sparkline.d.ts.map +1 -1
  84. package/dist/components/chart-sparkline.js +6 -5
  85. package/dist/components/check-counts.d.ts +44 -0
  86. package/dist/components/check-counts.d.ts.map +1 -0
  87. package/dist/components/check-counts.js +51 -0
  88. package/dist/components/checkbox.d.ts +39 -11
  89. package/dist/components/checkbox.d.ts.map +1 -1
  90. package/dist/components/checkbox.js +38 -11
  91. package/dist/components/choicebox.d.ts +96 -0
  92. package/dist/components/choicebox.d.ts.map +1 -0
  93. package/dist/components/choicebox.js +113 -0
  94. package/dist/components/clearable-input.d.ts +57 -0
  95. package/dist/components/clearable-input.d.ts.map +1 -0
  96. package/dist/components/clearable-input.js +58 -0
  97. package/dist/components/code-block.d.ts +77 -17
  98. package/dist/components/code-block.d.ts.map +1 -1
  99. package/dist/components/code-block.js +85 -15
  100. package/dist/components/collapsible.d.ts +27 -10
  101. package/dist/components/collapsible.d.ts.map +1 -1
  102. package/dist/components/collapsible.js +24 -9
  103. package/dist/components/collection-filters.d.ts +3 -1
  104. package/dist/components/collection-filters.d.ts.map +1 -1
  105. package/dist/components/collection-filters.js +7 -9
  106. package/dist/components/collection-page.d.ts +31 -10
  107. package/dist/components/collection-page.d.ts.map +1 -1
  108. package/dist/components/collection-page.js +14 -13
  109. package/dist/components/collection-search.d.ts +32 -10
  110. package/dist/components/collection-search.d.ts.map +1 -1
  111. package/dist/components/collection-search.js +24 -13
  112. package/dist/components/collection-sort.d.ts.map +1 -1
  113. package/dist/components/collection-sort.js +2 -2
  114. package/dist/components/collection-toolbar.d.ts +5 -2
  115. package/dist/components/collection-toolbar.d.ts.map +1 -1
  116. package/dist/components/collection-toolbar.js +7 -4
  117. package/dist/components/combobox.d.ts +97 -22
  118. package/dist/components/combobox.d.ts.map +1 -1
  119. package/dist/components/combobox.js +80 -28
  120. package/dist/components/command.d.ts +34 -21
  121. package/dist/components/command.d.ts.map +1 -1
  122. package/dist/components/command.js +33 -25
  123. package/dist/components/confirm-dialog.d.ts +23 -6
  124. package/dist/components/confirm-dialog.d.ts.map +1 -1
  125. package/dist/components/confirm-dialog.js +32 -13
  126. package/dist/components/context-menu.d.ts +14 -10
  127. package/dist/components/context-menu.d.ts.map +1 -1
  128. package/dist/components/context-menu.js +17 -12
  129. package/dist/components/copy-button.d.ts +5 -2
  130. package/dist/components/copy-button.d.ts.map +1 -1
  131. package/dist/components/copy-button.js +16 -8
  132. package/dist/components/data-table.d.ts +120 -54
  133. package/dist/components/data-table.d.ts.map +1 -1
  134. package/dist/components/data-table.js +163 -92
  135. package/dist/components/desktop-shell.d.ts +4 -2
  136. package/dist/components/desktop-shell.d.ts.map +1 -1
  137. package/dist/components/desktop-shell.js +3 -3
  138. package/dist/components/dialog.d.ts +63 -24
  139. package/dist/components/dialog.d.ts.map +1 -1
  140. package/dist/components/dialog.js +52 -31
  141. package/dist/components/disclosure-row.d.ts +1 -2
  142. package/dist/components/disclosure-row.d.ts.map +1 -1
  143. package/dist/components/disclosure-row.js +1 -2
  144. package/dist/components/disclosure.d.ts +1 -1
  145. package/dist/components/disclosure.js +1 -1
  146. package/dist/components/drawer.d.ts +33 -12
  147. package/dist/components/drawer.d.ts.map +1 -1
  148. package/dist/components/drawer.js +47 -35
  149. package/dist/components/dropdown-menu.d.ts +59 -14
  150. package/dist/components/dropdown-menu.d.ts.map +1 -1
  151. package/dist/components/dropdown-menu.js +58 -26
  152. package/dist/components/empty-state.d.ts +35 -12
  153. package/dist/components/empty-state.d.ts.map +1 -1
  154. package/dist/components/empty-state.js +35 -17
  155. package/dist/components/entry-scene.d.ts +4 -4
  156. package/dist/components/entry-scene.d.ts.map +1 -1
  157. package/dist/components/entry-scene.js +2 -2
  158. package/dist/components/field.d.ts +44 -14
  159. package/dist/components/field.d.ts.map +1 -1
  160. package/dist/components/field.js +49 -20
  161. package/dist/components/file-diff.d.ts.map +1 -1
  162. package/dist/components/file-diff.js +3 -4
  163. package/dist/components/form-dialog.d.ts +7 -7
  164. package/dist/components/form-dialog.d.ts.map +1 -1
  165. package/dist/components/form-dialog.js +13 -11
  166. package/dist/components/form-drawer.d.ts +10 -7
  167. package/dist/components/form-drawer.d.ts.map +1 -1
  168. package/dist/components/form-drawer.js +11 -10
  169. package/dist/components/gauge.d.ts +64 -0
  170. package/dist/components/gauge.d.ts.map +1 -0
  171. package/dist/components/gauge.js +73 -0
  172. package/dist/components/hover-card.d.ts +72 -14
  173. package/dist/components/hover-card.d.ts.map +1 -1
  174. package/dist/components/hover-card.js +51 -17
  175. package/dist/components/identity-mark.d.ts +8 -1
  176. package/dist/components/identity-mark.d.ts.map +1 -1
  177. package/dist/components/identity-mark.js +31 -5
  178. package/dist/components/input-group.d.ts +44 -21
  179. package/dist/components/input-group.d.ts.map +1 -1
  180. package/dist/components/input-group.js +74 -27
  181. package/dist/components/input.d.ts +64 -12
  182. package/dist/components/input.d.ts.map +1 -1
  183. package/dist/components/input.js +51 -15
  184. package/dist/components/item.d.ts +37 -15
  185. package/dist/components/item.d.ts.map +1 -1
  186. package/dist/components/item.js +41 -22
  187. package/dist/components/kbd.d.ts +49 -13
  188. package/dist/components/kbd.d.ts.map +1 -1
  189. package/dist/components/kbd.js +115 -16
  190. package/dist/components/kpi-card.d.ts +12 -4
  191. package/dist/components/kpi-card.d.ts.map +1 -1
  192. package/dist/components/kpi-card.js +13 -4
  193. package/dist/components/label.d.ts +17 -10
  194. package/dist/components/label.d.ts.map +1 -1
  195. package/dist/components/label.js +18 -11
  196. package/dist/components/library-shelf.d.ts +6 -6
  197. package/dist/components/library-shelf.d.ts.map +1 -1
  198. package/dist/components/library-shelf.js +5 -5
  199. package/dist/components/load-more-button.d.ts +35 -0
  200. package/dist/components/load-more-button.d.ts.map +1 -0
  201. package/dist/components/load-more-button.js +26 -0
  202. package/dist/components/message-notice.d.ts +8 -13
  203. package/dist/components/message-notice.d.ts.map +1 -1
  204. package/dist/components/message-notice.js +25 -22
  205. package/dist/components/middle-truncate.d.ts +33 -0
  206. package/dist/components/middle-truncate.d.ts.map +1 -0
  207. package/dist/components/middle-truncate.js +72 -0
  208. package/dist/components/multi-select.d.ts +94 -0
  209. package/dist/components/multi-select.d.ts.map +1 -0
  210. package/dist/components/multi-select.js +132 -0
  211. package/dist/components/native-select.d.ts +37 -13
  212. package/dist/components/native-select.d.ts.map +1 -1
  213. package/dist/components/native-select.js +27 -11
  214. package/dist/components/notice-banner.d.ts +17 -10
  215. package/dist/components/notice-banner.d.ts.map +1 -1
  216. package/dist/components/notice-banner.js +12 -11
  217. package/dist/components/numbered-steps.d.ts +10 -4
  218. package/dist/components/numbered-steps.d.ts.map +1 -1
  219. package/dist/components/numbered-steps.js +9 -7
  220. package/dist/components/object-page.d.ts +40 -14
  221. package/dist/components/object-page.d.ts.map +1 -1
  222. package/dist/components/object-page.js +12 -10
  223. package/dist/components/object-workspace.d.ts +29 -10
  224. package/dist/components/object-workspace.d.ts.map +1 -1
  225. package/dist/components/object-workspace.js +18 -8
  226. package/dist/components/overview-page.d.ts +2 -2
  227. package/dist/components/overview-page.d.ts.map +1 -1
  228. package/dist/components/overview-page.js +8 -7
  229. package/dist/components/page-actions.d.ts +28 -8
  230. package/dist/components/page-actions.d.ts.map +1 -1
  231. package/dist/components/page-actions.js +22 -25
  232. package/dist/components/page-header.d.ts +11 -4
  233. package/dist/components/page-header.d.ts.map +1 -1
  234. package/dist/components/page-header.js +10 -5
  235. package/dist/components/pending-label.d.ts +6 -5
  236. package/dist/components/pending-label.d.ts.map +1 -1
  237. package/dist/components/pending-label.js +14 -6
  238. package/dist/components/picture-label.d.ts +2 -2
  239. package/dist/components/picture-label.d.ts.map +1 -1
  240. package/dist/components/picture-label.js +3 -3
  241. package/dist/components/portal-sidebar-frame.d.ts +9 -21
  242. package/dist/components/portal-sidebar-frame.d.ts.map +1 -1
  243. package/dist/components/portal-sidebar-frame.js +13 -27
  244. package/dist/components/progress-checklist.d.ts +46 -0
  245. package/dist/components/progress-checklist.d.ts.map +1 -0
  246. package/dist/components/progress-checklist.js +46 -0
  247. package/dist/components/progress.d.ts +48 -8
  248. package/dist/components/progress.d.ts.map +1 -1
  249. package/dist/components/progress.js +92 -16
  250. package/dist/components/prose.d.ts +19 -0
  251. package/dist/components/prose.d.ts.map +1 -0
  252. package/dist/components/prose.js +29 -0
  253. package/dist/components/radio-group.d.ts +51 -12
  254. package/dist/components/radio-group.d.ts.map +1 -1
  255. package/dist/components/radio-group.js +42 -12
  256. package/dist/components/reading-column.js +1 -1
  257. package/dist/components/record-identity.d.ts +6 -5
  258. package/dist/components/record-identity.d.ts.map +1 -1
  259. package/dist/components/record-identity.js +12 -3
  260. package/dist/components/record-list.d.ts +117 -27
  261. package/dist/components/record-list.d.ts.map +1 -1
  262. package/dist/components/record-list.js +185 -55
  263. package/dist/components/record-time.d.ts +20 -7
  264. package/dist/components/record-time.d.ts.map +1 -1
  265. package/dist/components/record-time.js +38 -19
  266. package/dist/components/resizable.d.ts +7 -5
  267. package/dist/components/resizable.d.ts.map +1 -1
  268. package/dist/components/resizable.js +6 -6
  269. package/dist/components/scope-switcher.d.ts +2 -0
  270. package/dist/components/scope-switcher.d.ts.map +1 -1
  271. package/dist/components/scope-switcher.js +2 -2
  272. package/dist/components/scroll-area.d.ts +47 -11
  273. package/dist/components/scroll-area.d.ts.map +1 -1
  274. package/dist/components/scroll-area.js +72 -14
  275. package/dist/components/segmented-control.d.ts +82 -0
  276. package/dist/components/segmented-control.d.ts.map +1 -0
  277. package/dist/components/segmented-control.js +90 -0
  278. package/dist/components/select.d.ts +55 -15
  279. package/dist/components/select.d.ts.map +1 -1
  280. package/dist/components/select.js +62 -19
  281. package/dist/components/separator.d.ts +12 -5
  282. package/dist/components/separator.d.ts.map +1 -1
  283. package/dist/components/separator.js +11 -6
  284. package/dist/components/settings-facts.d.ts +34 -14
  285. package/dist/components/settings-facts.d.ts.map +1 -1
  286. package/dist/components/settings-facts.js +21 -12
  287. package/dist/components/settings-page.d.ts +4 -4
  288. package/dist/components/settings-page.js +5 -5
  289. package/dist/components/settings-section.d.ts +160 -34
  290. package/dist/components/settings-section.d.ts.map +1 -1
  291. package/dist/components/settings-section.js +92 -39
  292. package/dist/components/sheet.d.ts +47 -16
  293. package/dist/components/sheet.d.ts.map +1 -1
  294. package/dist/components/sheet.js +40 -19
  295. package/dist/components/sidebar-sections.d.ts +16 -12
  296. package/dist/components/sidebar-sections.d.ts.map +1 -1
  297. package/dist/components/sidebar-sections.js +30 -15
  298. package/dist/components/sidebar.d.ts +117 -21
  299. package/dist/components/sidebar.d.ts.map +1 -1
  300. package/dist/components/sidebar.js +180 -55
  301. package/dist/components/skeleton.d.ts +54 -8
  302. package/dist/components/skeleton.d.ts.map +1 -1
  303. package/dist/components/skeleton.js +44 -9
  304. package/dist/components/slider.d.ts +53 -11
  305. package/dist/components/slider.d.ts.map +1 -1
  306. package/dist/components/slider.js +71 -17
  307. package/dist/components/snippet.d.ts +57 -0
  308. package/dist/components/snippet.d.ts.map +1 -0
  309. package/dist/components/snippet.js +60 -0
  310. package/dist/components/sonner.d.ts +13 -14
  311. package/dist/components/sonner.d.ts.map +1 -1
  312. package/dist/components/sonner.js +25 -22
  313. package/dist/components/status-badge.d.ts +37 -11
  314. package/dist/components/status-badge.d.ts.map +1 -1
  315. package/dist/components/status-badge.js +63 -15
  316. package/dist/components/status-dot.d.ts +42 -11
  317. package/dist/components/status-dot.d.ts.map +1 -1
  318. package/dist/components/status-dot.js +40 -11
  319. package/dist/components/switch.d.ts +43 -12
  320. package/dist/components/switch.d.ts.map +1 -1
  321. package/dist/components/switch.js +42 -12
  322. package/dist/components/table-card.d.ts +21 -12
  323. package/dist/components/table-card.d.ts.map +1 -1
  324. package/dist/components/table-card.js +17 -9
  325. package/dist/components/table-layouts.d.ts +40 -8
  326. package/dist/components/table-layouts.d.ts.map +1 -1
  327. package/dist/components/table-layouts.js +52 -8
  328. package/dist/components/table-value.d.ts +4 -3
  329. package/dist/components/table-value.d.ts.map +1 -1
  330. package/dist/components/table-value.js +6 -5
  331. package/dist/components/table.d.ts +62 -25
  332. package/dist/components/table.d.ts.map +1 -1
  333. package/dist/components/table.js +62 -26
  334. package/dist/components/tabs.d.ts +86 -17
  335. package/dist/components/tabs.d.ts.map +1 -1
  336. package/dist/components/tabs.js +93 -22
  337. package/dist/components/text-link.d.ts +4 -1
  338. package/dist/components/text-link.d.ts.map +1 -1
  339. package/dist/components/text-link.js +4 -1
  340. package/dist/components/text-with-copy-button.d.ts +30 -0
  341. package/dist/components/text-with-copy-button.d.ts.map +1 -0
  342. package/dist/components/text-with-copy-button.js +32 -0
  343. package/dist/components/textarea.d.ts +40 -10
  344. package/dist/components/textarea.d.ts.map +1 -1
  345. package/dist/components/textarea.js +50 -11
  346. package/dist/components/theme-mode-switcher.d.ts +18 -1
  347. package/dist/components/theme-mode-switcher.d.ts.map +1 -1
  348. package/dist/components/theme-mode-switcher.js +20 -2
  349. package/dist/components/toggle-group.d.ts +28 -8
  350. package/dist/components/toggle-group.d.ts.map +1 -1
  351. package/dist/components/toggle-group.js +12 -6
  352. package/dist/components/toggle.d.ts +6 -3
  353. package/dist/components/toggle.d.ts.map +1 -1
  354. package/dist/components/toggle.js +10 -7
  355. package/dist/components/tooltip.d.ts +43 -12
  356. package/dist/components/tooltip.d.ts.map +1 -1
  357. package/dist/components/tooltip.js +45 -16
  358. package/dist/components/trend-badge.js +1 -1
  359. package/dist/components/update-card.js +1 -1
  360. package/dist/eslint/index.js +82 -0
  361. package/dist/eslint/rules/badge-is-static-label.js +93 -0
  362. package/dist/eslint/rules/button-icon-slot.js +102 -0
  363. package/dist/eslint/rules/button-link-for-navigation.js +146 -0
  364. package/dist/eslint/rules/button-no-aria-label-with-text.js +75 -0
  365. package/dist/eslint/rules/button-type-roles-only-in-buttons.js +83 -0
  366. package/dist/eslint/rules/choice-control-has-a-name.js +98 -0
  367. package/dist/eslint/rules/choice-group-in-fieldset.js +86 -0
  368. package/dist/eslint/rules/command-shortcut-single-owner.js +118 -0
  369. package/dist/eslint/rules/confirm-dialog-words.js +63 -0
  370. package/dist/eslint/rules/data-table-one-unsized-column.js +96 -0
  371. package/dist/eslint/rules/destructive-action-placement.js +69 -0
  372. package/dist/eslint/rules/disabled-choice-says-why.js +71 -0
  373. package/dist/eslint/rules/ellipsis-opens-a-dialog.js +110 -0
  374. package/dist/eslint/rules/input-group-owners.js +155 -0
  375. package/dist/eslint/rules/kbd-children-no-modifier-text.js +128 -0
  376. package/dist/eslint/rules/literal-text.js +41 -0
  377. package/dist/eslint/rules/middle-truncate-placement.js +69 -0
  378. package/dist/eslint/rules/no-bare-button-label.js +55 -0
  379. package/dist/eslint/rules/no-control-in-read-only-surface.js +106 -0
  380. package/dist/eslint/rules/no-hand-built-busy.js +104 -0
  381. package/dist/eslint/rules/no-hand-built-theme-picker.js +144 -0
  382. package/dist/eslint/rules/no-hand-built-tile.js +41 -0
  383. package/dist/eslint/rules/no-hand-formatted-date.js +87 -0
  384. package/dist/eslint/rules/no-hand-stacked-avatars.js +67 -0
  385. package/dist/eslint/rules/no-nested-collapse.js +60 -0
  386. package/dist/eslint/rules/no-search-in-form.js +47 -0
  387. package/dist/eslint/rules/no-shadcn-appearance-override.js +2 -16
  388. package/dist/eslint/rules/no-shell-prompt-in-snippet.js +74 -0
  389. package/dist/eslint/rules/no-stock-error-words.js +56 -0
  390. package/dist/eslint/rules/no-tooltip-around-labelled-field.js +72 -0
  391. package/dist/eslint/rules/no-weight-class-on-strong-in-type-role.js +57 -0
  392. package/dist/eslint/rules/one-submenu-level.js +43 -0
  393. package/dist/eslint/rules/one-toast-per-flow.js +91 -0
  394. package/dist/eslint/rules/option-count.js +167 -0
  395. package/dist/eslint/rules/page-command-link-not-render.js +43 -0
  396. package/dist/eslint/rules/progress-needs-name.js +57 -0
  397. package/dist/eslint/rules/settings-limit-in-footer.js +94 -0
  398. package/dist/eslint/rules/skeleton-in-region.js +80 -0
  399. package/dist/eslint/rules/sortable-heading-uses-sort.js +79 -0
  400. package/dist/eslint/rules/table-cell-inset-owner.js +107 -0
  401. package/dist/eslint/rules/tabs-selection-is-controlled.js +47 -0
  402. package/dist/eslint/rules/tooltip-only-arrow.js +38 -0
  403. package/dist/eslint/rules/tooltip-trigger-accessible-name.js +114 -0
  404. package/dist/eslint/strict-design-system.js +21 -7
  405. package/dist/index.d.ts +13 -13
  406. package/dist/index.d.ts.map +1 -1
  407. package/dist/index.js +12 -13
  408. package/dist/internal/assistant-ui/attachment.d.ts.map +1 -1
  409. package/dist/internal/assistant-ui/attachment.js +2 -2
  410. package/dist/internal/assistant-ui/reasoning.d.ts +1 -1
  411. package/dist/internal/assistant-ui/reasoning.d.ts.map +1 -1
  412. package/dist/internal/assistant-ui/tool-fallback.js +1 -1
  413. package/dist/internal/assistant-ui/tool-group.d.ts +1 -1
  414. package/dist/internal/assistant-ui/tool-group.d.ts.map +1 -1
  415. package/dist/internal/assistant-ui/tooltip-icon-button.d.ts +2 -3
  416. package/dist/internal/assistant-ui/tooltip-icon-button.d.ts.map +1 -1
  417. package/dist/internal/assistant-ui/tooltip-icon-button.js +1 -1
  418. package/dist/internal/catalog-list.js +2 -2
  419. package/dist/internal/collection-note.d.ts +23 -0
  420. package/dist/internal/collection-note.d.ts.map +1 -0
  421. package/dist/internal/collection-note.js +17 -0
  422. package/dist/internal/collection-rail.d.ts +57 -0
  423. package/dist/internal/collection-rail.d.ts.map +1 -0
  424. package/dist/internal/collection-rail.js +33 -0
  425. package/dist/internal/company-logo.d.ts +18 -0
  426. package/dist/internal/company-logo.d.ts.map +1 -0
  427. package/dist/internal/company-logo.js +14 -0
  428. package/dist/internal/control-name.d.ts +12 -0
  429. package/dist/internal/control-name.d.ts.map +1 -0
  430. package/dist/internal/control-name.js +1 -0
  431. package/dist/internal/diff-line.d.ts +9 -0
  432. package/dist/internal/diff-line.d.ts.map +1 -0
  433. package/dist/internal/diff-line.js +8 -0
  434. package/dist/internal/empty.d.ts +8 -4
  435. package/dist/internal/empty.d.ts.map +1 -1
  436. package/dist/internal/empty.js +14 -8
  437. package/dist/internal/field-frame.d.ts +33 -0
  438. package/dist/internal/field-frame.d.ts.map +1 -0
  439. package/dist/internal/field-frame.js +20 -0
  440. package/dist/internal/final-focus.d.ts +8 -0
  441. package/dist/internal/final-focus.d.ts.map +1 -0
  442. package/dist/internal/final-focus.js +10 -0
  443. package/dist/internal/footer-strip.d.ts.map +1 -1
  444. package/dist/internal/footer-strip.js +3 -1
  445. package/dist/internal/form-submit.d.ts +9 -5
  446. package/dist/internal/form-submit.d.ts.map +1 -1
  447. package/dist/internal/form-submit.js +31 -2
  448. package/dist/internal/input-box.d.ts +26 -0
  449. package/dist/internal/input-box.d.ts.map +1 -0
  450. package/dist/internal/input-box.js +59 -0
  451. package/dist/internal/menu-surface.d.ts +10 -3
  452. package/dist/internal/menu-surface.d.ts.map +1 -1
  453. package/dist/internal/menu-surface.js +10 -3
  454. package/dist/internal/notice.d.ts +25 -0
  455. package/dist/internal/notice.d.ts.map +1 -0
  456. package/dist/internal/notice.js +33 -0
  457. package/dist/internal/overlay-stem.d.ts +5 -0
  458. package/dist/internal/overlay-stem.d.ts.map +1 -0
  459. package/dist/internal/overlay-stem.js +7 -0
  460. package/dist/internal/phone-sheet.d.ts +4 -0
  461. package/dist/internal/phone-sheet.d.ts.map +1 -0
  462. package/dist/internal/phone-sheet.js +2 -0
  463. package/dist/internal/present-content.d.ts +3 -0
  464. package/dist/internal/present-content.d.ts.map +1 -0
  465. package/dist/internal/present-content.js +1 -0
  466. package/dist/internal/record-menu-items.d.ts +4 -3
  467. package/dist/internal/record-menu-items.d.ts.map +1 -1
  468. package/dist/internal/record-menu-items.js +21 -6
  469. package/dist/internal/settings-save.d.ts +9 -2
  470. package/dist/internal/settings-save.d.ts.map +1 -1
  471. package/dist/internal/settings-save.js +19 -6
  472. package/dist/internal/table-compact-line.d.ts +38 -0
  473. package/dist/internal/table-compact-line.d.ts.map +1 -0
  474. package/dist/internal/table-compact-line.js +35 -0
  475. package/dist/internal/title-when-cut.d.ts +8 -0
  476. package/dist/internal/title-when-cut.d.ts.map +1 -0
  477. package/dist/internal/title-when-cut.js +22 -0
  478. package/dist/internal/unsaved-guard.d.ts +18 -0
  479. package/dist/internal/unsaved-guard.d.ts.map +1 -0
  480. package/dist/internal/unsaved-guard.js +31 -0
  481. package/dist/lib/merge-tokens.generated.js +2 -2
  482. package/dist/showcase/foundations.d.ts.map +1 -1
  483. package/dist/showcase/foundations.js +10 -2
  484. package/dist/showcase/specimens/actions.d.ts +2 -0
  485. package/dist/showcase/specimens/actions.d.ts.map +1 -1
  486. package/dist/showcase/specimens/actions.js +30 -5
  487. package/dist/showcase/specimens/charts.d.ts.map +1 -1
  488. package/dist/showcase/specimens/charts.js +22 -13
  489. package/dist/showcase/specimens/choices.d.ts +14 -3
  490. package/dist/showcase/specimens/choices.d.ts.map +1 -1
  491. package/dist/showcase/specimens/choices.js +93 -13
  492. package/dist/showcase/specimens/compositions.d.ts.map +1 -1
  493. package/dist/showcase/specimens/compositions.js +136 -23
  494. package/dist/showcase/specimens/data.d.ts +12 -7
  495. package/dist/showcase/specimens/data.d.ts.map +1 -1
  496. package/dist/showcase/specimens/data.js +139 -35
  497. package/dist/showcase/specimens/feedback.d.ts +2 -0
  498. package/dist/showcase/specimens/feedback.d.ts.map +1 -1
  499. package/dist/showcase/specimens/feedback.js +39 -15
  500. package/dist/showcase/specimens/index.d.ts +20 -12
  501. package/dist/showcase/specimens/index.d.ts.map +1 -1
  502. package/dist/showcase/specimens/inputs.d.ts +4 -2
  503. package/dist/showcase/specimens/inputs.d.ts.map +1 -1
  504. package/dist/showcase/specimens/inputs.js +62 -19
  505. package/dist/showcase/specimens/menus.d.ts +0 -1
  506. package/dist/showcase/specimens/menus.d.ts.map +1 -1
  507. package/dist/showcase/specimens/menus.js +47 -17
  508. package/dist/showcase/specimens/navigation.d.ts +6 -4
  509. package/dist/showcase/specimens/navigation.d.ts.map +1 -1
  510. package/dist/showcase/specimens/navigation.js +61 -32
  511. package/dist/showcase/specimens/other.d.ts +1 -3
  512. package/dist/showcase/specimens/other.d.ts.map +1 -1
  513. package/dist/showcase/specimens/other.js +17 -13
  514. package/dist/showcase/specimens/status.d.ts +4 -1
  515. package/dist/showcase/specimens/status.d.ts.map +1 -1
  516. package/dist/showcase/specimens/status.js +64 -11
  517. package/dist/showcase/usage.generated.d.ts +1 -1
  518. package/dist/showcase/usage.generated.d.ts.map +1 -1
  519. package/dist/showcase/usage.generated.js +632 -544
  520. package/dist/standalone/index.js +1 -1
  521. package/dist/styles/components.css +13 -13
  522. package/dist/styles/globals.css +25 -0
  523. package/package.json +2 -3
  524. package/dist/components/approval-row.d.ts +0 -34
  525. package/dist/components/approval-row.d.ts.map +0 -1
  526. package/dist/components/approval-row.js +0 -27
  527. package/dist/components/channel-view.d.ts +0 -112
  528. package/dist/components/channel-view.d.ts.map +0 -1
  529. package/dist/components/channel-view.js +0 -84
  530. package/dist/components/dashboard-shell.d.ts +0 -51
  531. package/dist/components/dashboard-shell.d.ts.map +0 -1
  532. package/dist/components/dashboard-shell.js +0 -89
  533. package/dist/components/direction.d.ts +0 -2
  534. package/dist/components/direction.d.ts.map +0 -1
  535. package/dist/components/direction.js +0 -1
  536. package/dist/components/expandable-block.d.ts +0 -20
  537. package/dist/components/expandable-block.d.ts.map +0 -1
  538. package/dist/components/expandable-block.js +0 -32
  539. package/dist/components/form.d.ts +0 -42
  540. package/dist/components/form.d.ts.map +0 -1
  541. package/dist/components/form.js +0 -91
  542. package/dist/components/label-system.d.ts +0 -17
  543. package/dist/components/label-system.d.ts.map +0 -1
  544. package/dist/components/label-system.js +0 -21
  545. package/dist/components/memory-item.d.ts +0 -21
  546. package/dist/components/memory-item.d.ts.map +0 -1
  547. package/dist/components/memory-item.js +0 -18
  548. package/dist/components/menubar.d.ts +0 -43
  549. package/dist/components/menubar.d.ts.map +0 -1
  550. package/dist/components/menubar.js +0 -69
  551. package/dist/components/navigation-menu.d.ts +0 -26
  552. package/dist/components/navigation-menu.d.ts.map +0 -1
  553. package/dist/components/navigation-menu.js +0 -45
  554. package/dist/components/pagination.d.ts +0 -33
  555. package/dist/components/pagination.d.ts.map +0 -1
  556. package/dist/components/pagination.js +0 -41
  557. package/dist/components/plugin-slot-boundary.d.ts +0 -42
  558. package/dist/components/plugin-slot-boundary.d.ts.map +0 -1
  559. package/dist/components/plugin-slot-boundary.js +0 -41
  560. package/dist/components/status-row.d.ts +0 -32
  561. package/dist/components/status-row.d.ts.map +0 -1
  562. package/dist/components/status-row.js +0 -35
@@ -0,0 +1,96 @@
1
+ /*
2
+ * Standard tool checked first: a `no-restricted-syntax` selector matches one
3
+ * node, but this reads a whole `columns` array (how many of its objects lack a
4
+ * `size`, whether one sets `meta.wraps`, whether a spread or a call makes the
5
+ * list unknowable) and follows a variable to its array, which no selector can.
6
+ */
7
+ import { renderedImports } from "./rendered-import.js";
8
+
9
+ const COMMANDS_COLUMN_ID = "actions";
10
+
11
+ const WRAPPERS = new Set(["TSAsExpression", "TSSatisfiesExpression", "TSNonNullExpression"]);
12
+
13
+ function unwrap(node) {
14
+ let current = node;
15
+ while (WRAPPERS.has(current.type)) current = current.expression;
16
+ return current;
17
+ }
18
+
19
+ const keyName = (property) => {
20
+ if (property.computed) return null;
21
+ return property.key.type === "Identifier" ? property.key.name : property.key.value;
22
+ };
23
+
24
+ const propertyOf = (column, name) =>
25
+ column.properties.find((property) => property.type === "Property" && keyName(property) === name);
26
+
27
+ function setsWraps(column) {
28
+ const meta = propertyOf(column, "meta")?.value;
29
+ if (meta?.type !== "ObjectExpression") return false;
30
+ const wraps = propertyOf(meta, "wraps")?.value;
31
+ return wraps !== undefined && !(wraps.type === "Literal" && wraps.value === false);
32
+ }
33
+
34
+ const isCommandsColumn = (column) => propertyOf(column, "id")?.value.value === COMMANDS_COLUMN_ID;
35
+
36
+ const isKnownColumn = (element) =>
37
+ element?.type === "ObjectExpression" &&
38
+ element.properties.every((property) => property.type === "Property");
39
+
40
+ function arrayOf(context, expression) {
41
+ const node = unwrap(expression);
42
+ if (node.type === "ArrayExpression") return node;
43
+ if (node.type !== "Identifier") return null;
44
+ for (let scope = context.sourceCode.getScope(node); scope; scope = scope.upper) {
45
+ const variable = scope.set.get(node.name);
46
+ if (!variable) continue;
47
+ const [definition] = variable.defs;
48
+ const initialisedOnce =
49
+ variable.defs.length === 1 && variable.references.filter((use) => use.isWrite()).length === 1;
50
+ if (!initialisedOnce || definition.node.type !== "VariableDeclarator") return null;
51
+ const init = definition.node.init ? unwrap(definition.node.init) : null;
52
+ return init?.type === "ArrayExpression" ? init : null;
53
+ }
54
+ return null;
55
+ }
56
+
57
+ function breaksTheRule(array) {
58
+ if (!array.elements.every(isKnownColumn)) return false;
59
+ if (array.elements.some(setsWraps)) return false;
60
+ const unsized = array.elements.filter((column) => !propertyOf(column, "size"));
61
+ if (unsized.length > 1) return true;
62
+ const content = array.elements.filter((column) => !isCommandsColumn(column));
63
+ return content.length > 0 && unsized.length === 0;
64
+ }
65
+
66
+ export const dataTableOneUnsizedColumn = {
67
+ meta: {
68
+ type: "problem",
69
+ docs: {
70
+ description:
71
+ "A DataTable's columns all have a size in pixels except the one that takes the spare width.",
72
+ },
73
+ schema: [],
74
+ messages: {
75
+ "one-unsized-column":
76
+ "Give every column a `size` in pixels except the one that takes the spare width. Columns without a size share what is left, so two of them make the widths depend on the data.",
77
+ },
78
+ },
79
+ create(context) {
80
+ const importOf = renderedImports(context);
81
+ return {
82
+ JSXOpeningElement(node) {
83
+ if (importOf(node.name)?.name !== "DataTable") return;
84
+ const attribute = node.attributes.find(
85
+ (candidate) => candidate.type === "JSXAttribute" && candidate.name.name === "columns",
86
+ );
87
+ const value = attribute?.value;
88
+ if (value?.type !== "JSXExpressionContainer") return;
89
+ const array = arrayOf(context, value.expression);
90
+ if (array && breaksTheRule(array)) {
91
+ context.report({ node: value.expression, messageId: "one-unsized-column" });
92
+ }
93
+ },
94
+ };
95
+ },
96
+ };
@@ -0,0 +1,69 @@
1
+ /*
2
+ * Standard tool checked first: a `no-restricted-syntax` descendant selector can
3
+ * match a `Button` below `SheetContent`, but not that the button is the design
4
+ * system's, nor follow a renamed import, nor read `variant="destructive"` off
5
+ * the opening element or ignore a match that only sits in a `render` prop.
6
+ */
7
+ import { renderedImports, staticAttribute } from "./rendered-import.js";
8
+
9
+ const BUTTONS = new Set(["Button", "ButtonLink"]);
10
+ const CONFIRMATIONS = new Set(["ConfirmDialog", "AlertDialog", "ConfirmActionDialog"]);
11
+ const CLOSED_SURFACES = new Set([
12
+ "SheetContent",
13
+ "DrawerContent",
14
+ "FormDrawer",
15
+ "CatalogDrawer",
16
+ "AccordionContent",
17
+ "CollapsibleContent",
18
+ "Disclosure",
19
+ "HoverCardContent",
20
+ ]);
21
+
22
+ const FROM_DESIGN_SYSTEM = /^(@nadicodeai\/ui(\/|$)|@\/|\.)/;
23
+
24
+ export const destructiveActionPlacement = {
25
+ meta: {
26
+ type: "problem",
27
+ docs: {
28
+ description:
29
+ "A destructive action is confirmed in a ConfirmDialog opened from the page or a row's menu, never inside a sheet, drawer, hover card or collapsed section.",
30
+ },
31
+ schema: [],
32
+ messages: {
33
+ "destructive-placement":
34
+ "A destructive action is confirmed in a ConfirmDialog opened from the page or the row's menu: only a modal dims the whole page. Do not place it in a sheet, a drawer, a hover card or a section that starts closed.",
35
+ },
36
+ },
37
+ create(context) {
38
+ const importOf = renderedImports(context);
39
+ const exportOf = (element) => {
40
+ const imported = importOf(element.openingElement.name);
41
+ return imported && FROM_DESIGN_SYSTEM.test(imported.source) ? imported.name : null;
42
+ };
43
+
44
+ const isDestructive = (element) => {
45
+ const name = exportOf(element);
46
+ if (CONFIRMATIONS.has(name)) return true;
47
+ return (
48
+ BUTTONS.has(name) && staticAttribute(element.openingElement, "variant") === "destructive"
49
+ );
50
+ };
51
+
52
+ function insideClosedSurface(element) {
53
+ let child = element;
54
+ for (let node = element.parent; node; child = node, node = node.parent) {
55
+ if (node.type !== "JSXElement" || !node.children.includes(child)) continue;
56
+ if (CLOSED_SURFACES.has(exportOf(node))) return true;
57
+ }
58
+ return false;
59
+ }
60
+
61
+ return {
62
+ JSXElement(node) {
63
+ if (isDestructive(node) && insideClosedSurface(node)) {
64
+ context.report({ node: node.openingElement, messageId: "destructive-placement" });
65
+ }
66
+ },
67
+ };
68
+ },
69
+ };
@@ -0,0 +1,71 @@
1
+ /*
2
+ * Standard tool checked first: a `no-restricted-syntax` selector can match a
3
+ * `disabled` attribute on a `Checkbox`, but not follow a renamed import to the
4
+ * component, nor read the other attributes of the same element (aria-describedby,
5
+ * a spread) or tell a wait (`disabled={pending}`) from a reason.
6
+ */
7
+ import { PACKAGE_BARREL, partOf, renderedImports } from "./rendered-import.js";
8
+
9
+ const MODULES = [
10
+ ["Checkbox", "checkbox"],
11
+ ["Switch", "switch"],
12
+ ["RadioGroupItem", "radio-group"],
13
+ ];
14
+
15
+ const CHOICE = new Map(
16
+ MODULES.map(([part, module]) => [
17
+ part,
18
+ [`@nadicodeai/ui/components/${module}`, PACKAGE_BARREL].map((from) => ({ from, part })),
19
+ ]),
20
+ );
21
+
22
+ const WAIT = /^(?:is)?(?:pending|saving|submitting|busy)$/i;
23
+
24
+ const unwrapChain = (node) => (node.type === "ChainExpression" ? node.expression : node);
25
+
26
+ function isWait(attribute) {
27
+ if (attribute.value?.type !== "JSXExpressionContainer") return false;
28
+ const read = unwrapChain(attribute.value.expression);
29
+ if (read.type === "Identifier") return WAIT.test(read.name);
30
+ if (read.type !== "MemberExpression" || read.computed) return false;
31
+ return WAIT.test(read.property.name);
32
+ }
33
+
34
+ function isEnabledLiteral(attribute) {
35
+ const expression = attribute.value?.expression;
36
+ return expression?.type === "Literal" && expression.value === false;
37
+ }
38
+
39
+ const attributeNamed = (openingElement, name) =>
40
+ openingElement.attributes.find(
41
+ (attribute) => attribute.type === "JSXAttribute" && attribute.name.name === name,
42
+ );
43
+
44
+ export const disabledChoiceSaysWhy = {
45
+ meta: {
46
+ type: "problem",
47
+ docs: {
48
+ description:
49
+ "A disabled Checkbox, Switch or RadioGroupItem points aria-describedby at the line that names the reason.",
50
+ },
51
+ schema: [],
52
+ messages: {
53
+ "disabled-without-reason":
54
+ "Say why this is disabled: point aria-describedby at the line that names the reason, or use ChoiceboxGroupItem's disabledReason.",
55
+ },
56
+ },
57
+ create(context) {
58
+ const importOf = renderedImports(context);
59
+
60
+ return {
61
+ JSXOpeningElement(node) {
62
+ if (!partOf(importOf(node.name), CHOICE, context.filename)) return;
63
+ const disabled = attributeNamed(node, "disabled");
64
+ if (!disabled || isEnabledLiteral(disabled) || isWait(disabled)) return;
65
+ if (attributeNamed(node, "aria-describedby")) return;
66
+ if (node.attributes.some((attribute) => attribute.type === "JSXSpreadAttribute")) return;
67
+ context.report({ node: disabled, messageId: "disabled-without-reason" });
68
+ },
69
+ };
70
+ },
71
+ };
@@ -0,0 +1,110 @@
1
+ /*
2
+ * Standard tool checked first: `no-restricted-syntax` can match a label that
3
+ * ends in an ellipsis, but not what its command does: whether the handler
4
+ * opens something (a call that opens or passes `true`), runs, or navigates.
5
+ */
6
+ import { childText, keyName, literalText } from "./literal-text.js";
7
+ import { renderedImports } from "./rendered-import.js";
8
+
9
+ const ENDS_IN_ELLIPSIS = /(?:…|\.\.\.)\s*$/;
10
+ const COMMAND_KEYS = new Set(["onClick", "onSelect", "link", "render", "icon"]);
11
+ const HANDLER_KEYS = new Set(["onClick", "onSelect"]);
12
+ const MENU_ROWS = new Set([
13
+ "DropdownMenuItem",
14
+ "DropdownMenuCommand",
15
+ "ContextMenuItem",
16
+ "MenubarItem",
17
+ ]);
18
+ const MENU_LINKS = new Set(["DropdownMenuLink", "ContextMenuLink"]);
19
+ const FROM_DESIGN_SYSTEM = /^(@nadicodeai\/ui(\/|$)|@\/|\.)/;
20
+ const OPENING_CALL = /^(?:open|show)(?:[A-Z]|$)/;
21
+ const FUNCTIONS = new Set(["ArrowFunctionExpression", "FunctionExpression"]);
22
+
23
+ const calleeName = (callee) => {
24
+ if (callee.type === "Identifier") return callee.name;
25
+ if (callee.type === "MemberExpression" && !callee.computed) return callee.property.name;
26
+ return null;
27
+ };
28
+
29
+ function opensSomething(node, visitorKeys) {
30
+ const calls = [];
31
+ const stack = [node.body];
32
+ while (stack.length > 0) {
33
+ const current = stack.pop();
34
+ if (current.type === "CallExpression") calls.push(current);
35
+ for (const key of visitorKeys[current.type] ?? []) {
36
+ const value = current[key];
37
+ for (const child of Array.isArray(value) ? value : [value]) {
38
+ if (child?.type) stack.push(child);
39
+ }
40
+ }
41
+ }
42
+ return calls.some(
43
+ (call) =>
44
+ OPENING_CALL.test(calleeName(call.callee) ?? "") ||
45
+ call.arguments.some((argument) => argument.type === "Literal" && argument.value === true),
46
+ );
47
+ }
48
+
49
+ export const ellipsisOpensADialog = {
50
+ meta: {
51
+ type: "problem",
52
+ docs: {
53
+ description: "A command's label ends in an ellipsis only when the command opens a dialog.",
54
+ },
55
+ schema: [],
56
+ messages: {
57
+ "ellipsis-without-dialog":
58
+ 'An ellipsis says "this asks for more before it acts". "{{label}}" navigates or runs at once, so drop the ellipsis; keep it only on a command that opens a dialog.',
59
+ },
60
+ },
61
+ create(context) {
62
+ const importOf = renderedImports(context);
63
+ const { visitorKeys } = context.sourceCode;
64
+
65
+ function reportsNoDialog(handler) {
66
+ return (
67
+ handler !== undefined &&
68
+ FUNCTIONS.has(handler.type) &&
69
+ !opensSomething(handler, visitorKeys)
70
+ );
71
+ }
72
+
73
+ return {
74
+ ObjectExpression(node) {
75
+ const keys = new Map(node.properties.map((property) => [keyName(property), property]));
76
+ const label = literalText(keys.get("label")?.value);
77
+ if (label === null || !ENDS_IN_ELLIPSIS.test(label)) return;
78
+ if (![...keys.keys()].some((key) => COMMAND_KEYS.has(key))) return;
79
+ if (keys.has("render")) return;
80
+ const handlerProperty = [...keys].find(([key]) => HANDLER_KEYS.has(key))?.[1];
81
+ const navigates = keys.has("link");
82
+ if (navigates || reportsNoDialog(handlerProperty?.value)) {
83
+ context.report({
84
+ node: keys.get("label").value,
85
+ messageId: "ellipsis-without-dialog",
86
+ data: { label },
87
+ });
88
+ }
89
+ },
90
+ JSXElement(node) {
91
+ const imported = importOf(node.openingElement.name);
92
+ if (!imported || !FROM_DESIGN_SYSTEM.test(imported.source)) return;
93
+ const row = MENU_ROWS.has(imported.name);
94
+ if (!row && !MENU_LINKS.has(imported.name)) return;
95
+ const label = childText(node);
96
+ if (label === null || !ENDS_IN_ELLIPSIS.test(label)) return;
97
+ const handler = node.openingElement.attributes.find(
98
+ (attribute) => attribute.type === "JSXAttribute" && HANDLER_KEYS.has(attribute.name.name),
99
+ )?.value?.expression;
100
+ if (!row || reportsNoDialog(handler)) {
101
+ context.report({
102
+ node: node.openingElement,
103
+ messageId: "ellipsis-without-dialog",
104
+ data: { label },
105
+ });
106
+ }
107
+ },
108
+ };
109
+ },
110
+ };
@@ -0,0 +1,155 @@
1
+ /*
2
+ * Standard tool checked first: a `no-restricted-syntax` selector can match an
3
+ * `InputGroupAddon` holding `<Search/>`, but not an element joined to its import
4
+ * (a renamed or namespaced one), nor the shape of a whole group: only addons of
5
+ * fixed text or one icon around one input, a group with another button, a
6
+ * block addon or a textarea allowed. That needs the group's children together.
7
+ */
8
+ import {
9
+ PACKAGE_BARREL,
10
+ findBelow,
11
+ partOf,
12
+ renderedImports,
13
+ staticAttribute,
14
+ walk,
15
+ } from "./rendered-import.js";
16
+
17
+ const GROUP_PARTS = [
18
+ "InputGroup",
19
+ "InputGroupAddon",
20
+ "InputGroupButton",
21
+ "InputGroupInput",
22
+ "InputGroupText",
23
+ "InputGroupTextarea",
24
+ ];
25
+
26
+ const GROUP_MODULES = [
27
+ "@nadicodeai/ui/components/input-group",
28
+ PACKAGE_BARREL,
29
+ "@/components/input-group",
30
+ ];
31
+
32
+ const PARTS = new Map(
33
+ GROUP_PARTS.map((part) => [part, GROUP_MODULES.map((from) => ({ from, part }))]),
34
+ );
35
+
36
+ const ICON_MODULES = new Set(["lucide-react", "@nadicodeai/ui/components/house-icons"]);
37
+ const SEARCH_ICONS = new Set(["Search", "SearchIcon"]);
38
+ const CLEAR_ICONS = new Set(["X", "XIcon"]);
39
+ const INLINE_ALIGNS = new Set(["inline-start", "inline-end"]);
40
+
41
+ const significant = (element) =>
42
+ element.children.filter(
43
+ (child) =>
44
+ !(child.type === "JSXText" && child.value.trim() === "") &&
45
+ !(child.type === "JSXExpressionContainer" && child.expression.type === "JSXEmptyExpression"),
46
+ );
47
+
48
+ const isFixedText = (child) =>
49
+ child.type === "JSXText" ||
50
+ (child.type === "JSXExpressionContainer" && child.expression.type === "Literal");
51
+
52
+ export const inputGroupOwners = {
53
+ meta: {
54
+ type: "problem",
55
+ docs: {
56
+ description:
57
+ "A search box, a box that clears and fixed text or an icon in a box are drawn by the component that owns them, not by hand from InputGroup parts.",
58
+ },
59
+ schema: [],
60
+ messages: {
61
+ "hand-built-field":
62
+ "Use the component that owns this field: CollectionSearch for a collection's search, ClearableInput for a box that clears, Input's prefix and suffix for fixed text or an icon in the box.",
63
+ },
64
+ },
65
+ create(context) {
66
+ const importOf = renderedImports(context);
67
+ const { visitorKeys } = context.sourceCode;
68
+
69
+ const partName = (element) =>
70
+ partOf(importOf(element.openingElement.name), PARTS, context.filename);
71
+
72
+ const iconName = (element) => {
73
+ const imported = importOf(element.openingElement.name);
74
+ return imported && ICON_MODULES.has(imported.source) ? imported.name : null;
75
+ };
76
+
77
+ const holdsIcon = (element, names) =>
78
+ findBelow(
79
+ element,
80
+ visitorKeys,
81
+ (node) => node.type === "JSXElement" && names.has(iconName(node)),
82
+ ) !== null;
83
+
84
+ function holdsTextOrOneIcon(element) {
85
+ const content = significant(element);
86
+ if (content.length === 0) return false;
87
+ if (content.length === 1 && content[0].type === "JSXElement") {
88
+ const [only] = content;
89
+ if (iconName(only)) return true;
90
+ return partName(only) === "InputGroupText" && holdsTextOrOneIcon(only);
91
+ }
92
+ return content.every(isFixedText);
93
+ }
94
+
95
+ function readGroup(group) {
96
+ const facts = {
97
+ inputs: 0,
98
+ hasTextarea: false,
99
+ hasBlockAddon: false,
100
+ hasSearchAddon: false,
101
+ hasClearButton: false,
102
+ hasOtherButton: false,
103
+ };
104
+ walk(group, visitorKeys, (node) => {
105
+ if (node.type !== "JSXElement") return true;
106
+ const part = partName(node);
107
+ if (part === "InputGroup") return false;
108
+ if (part === "InputGroupInput") facts.inputs += 1;
109
+ if (part === "InputGroupTextarea") facts.hasTextarea = true;
110
+ if (part === "InputGroupAddon") {
111
+ const { openingElement } = node;
112
+ const hasAlign = openingElement.attributes.some(
113
+ (attribute) => attribute.type === "JSXAttribute" && attribute.name.name === "align",
114
+ );
115
+ if (hasAlign && !INLINE_ALIGNS.has(staticAttribute(openingElement, "align"))) {
116
+ facts.hasBlockAddon = true;
117
+ }
118
+ if (holdsIcon(node, SEARCH_ICONS)) facts.hasSearchAddon = true;
119
+ }
120
+ if (part === "InputGroupButton") {
121
+ if (holdsIcon(node, CLEAR_ICONS)) facts.hasClearButton = true;
122
+ else facts.hasOtherButton = true;
123
+ }
124
+ return true;
125
+ });
126
+ return facts;
127
+ }
128
+
129
+ function isFixedAdornments(group) {
130
+ const children = significant(group);
131
+ if (!children.every((child) => child.type === "JSXElement")) return false;
132
+ const parts = children.map(partName);
133
+ const addons = children.filter((_, index) => parts[index] === "InputGroupAddon");
134
+ const inputs = parts.filter((part) => part === "InputGroupInput");
135
+ return (
136
+ inputs.length === 1 &&
137
+ addons.length > 0 &&
138
+ addons.length + inputs.length === children.length &&
139
+ addons.every(holdsTextOrOneIcon)
140
+ );
141
+ }
142
+
143
+ return {
144
+ JSXElement(node) {
145
+ if (partName(node) !== "InputGroup") return;
146
+ const facts = readGroup(node);
147
+ if (facts.hasTextarea || facts.hasBlockAddon || facts.hasOtherButton) return;
148
+ const isSearch = facts.inputs > 0 && facts.hasSearchAddon;
149
+ if (isSearch || facts.hasClearButton || isFixedAdornments(node)) {
150
+ context.report({ node: node.openingElement, messageId: "hand-built-field" });
151
+ }
152
+ },
153
+ };
154
+ },
155
+ };
@@ -0,0 +1,128 @@
1
+ /*
2
+ * A shortcut hint is `<Kbd meta>K</Kbd>`: the modifier is a flag, the child is
3
+ * one key from `KBD_KEYS`, and the component draws the person's platform. A
4
+ * hand-written ⌘ or "Ctrl" is right on one platform and wrong on the others.
5
+ *
6
+ * Standard tool checked first: `no-restricted-syntax` can match a `Kbd` child
7
+ * by text, but not whether this `Kbd` is the package's (an import binding, so a
8
+ * renamed or local `Kbd` is judged correctly), and it would need the key list
9
+ * spelled into a regex. The list is read from the package's own `KBD_KEYS`
10
+ * array at lint time, so a key added there changes this rule's answer with no
11
+ * edit here.
12
+ */
13
+ import { readFileSync } from "node:fs";
14
+ import { createRequire } from "node:module";
15
+ import { fileURLToPath } from "node:url";
16
+
17
+ import { packageModules, partOf, renderedImports } from "./rendered-import.js";
18
+
19
+ const KBD_MODULE = "@nadicodeai/ui/components/kbd";
20
+ const OWNER_FILE = "packages/ui/src/components/kbd.tsx";
21
+
22
+ const KBD = new Map([["Kbd", packageModules("kbd").map((from) => ({ from, part: "Kbd" }))]]);
23
+
24
+ /*
25
+ * TypeScript is loaded when this rule first runs, not when the plugin loads:
26
+ * the plugin ships inside `@nadicodeai/ui`, which does not depend on the
27
+ * compiler, and a consumer who never enables this rule never asks for it.
28
+ */
29
+ let ts;
30
+ function typescript() {
31
+ ts ??= createRequire(import.meta.url)("typescript");
32
+ return ts;
33
+ }
34
+
35
+ function arrayLiteralOf(ts, expression) {
36
+ let node = expression;
37
+ while (
38
+ node &&
39
+ (ts.isAsExpression(node) ||
40
+ ts.isSatisfiesExpression(node) ||
41
+ ts.isParenthesizedExpression(node))
42
+ ) {
43
+ node = node.expression;
44
+ }
45
+ return node && ts.isArrayLiteralExpression(node) ? node : null;
46
+ }
47
+
48
+ function readKeys() {
49
+ const ts = typescript();
50
+ const file = fileURLToPath(import.meta.resolve(KBD_MODULE));
51
+ const source = ts.createSourceFile(
52
+ file,
53
+ readFileSync(file, "utf8"),
54
+ ts.ScriptTarget.Latest,
55
+ false,
56
+ file.endsWith(".js") ? ts.ScriptKind.JS : ts.ScriptKind.TSX,
57
+ );
58
+ for (const statement of source.statements) {
59
+ if (!ts.isVariableStatement(statement)) continue;
60
+ for (const declaration of statement.declarationList.declarations) {
61
+ if (!ts.isIdentifier(declaration.name) || declaration.name.text !== "KBD_KEYS") continue;
62
+ const array = arrayLiteralOf(ts, declaration.initializer);
63
+ if (!array) break;
64
+ return new Set(array.elements.map((element) => element.text));
65
+ }
66
+ }
67
+ throw new Error(`${file} has no KBD_KEYS array literal to read the keys from.`);
68
+ }
69
+
70
+ let keys;
71
+
72
+ /** Read once per lint process; the built module does not move under it. */
73
+ function kbdKeys() {
74
+ keys ??= readKeys();
75
+ return keys;
76
+ }
77
+
78
+ function writtenText(child) {
79
+ if (child.type === "JSXText") return child.value.trim() === "" ? null : child.value.trim();
80
+ if (child.type !== "JSXExpressionContainer") return null;
81
+ const { expression } = child;
82
+ // 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.
83
+ if (expression.type === "Literal" && typeof expression.value === "string") {
84
+ return expression.value;
85
+ }
86
+ if (expression.type === "TemplateLiteral" && expression.expressions.length === 0) {
87
+ return expression.quasis[0].value.cooked;
88
+ }
89
+ return null;
90
+ }
91
+
92
+ export const kbdChildrenNoModifierText = {
93
+ meta: {
94
+ type: "problem",
95
+ docs: {
96
+ description:
97
+ "A Kbd child is one key from KBD_KEYS with the modifier as a flag, and a shortcut is never a lowercase kbd element.",
98
+ },
99
+ schema: [],
100
+ messages: {
101
+ "hand-written-key":
102
+ "Write the modifier as a flag, <Kbd meta>K</Kbd>, and the child as one key from KBD_KEYS. A hand-written glyph shows the wrong key on Windows and Linux.",
103
+ },
104
+ },
105
+ create(context) {
106
+ const importOf = renderedImports(context);
107
+ const ownsTheElement = context.filename.replaceAll("\\", "/").endsWith(`/${OWNER_FILE}`);
108
+
109
+ return {
110
+ JSXElement(node) {
111
+ const name = node.openingElement.name;
112
+ if (name.type === "JSXIdentifier" && name.name === "kbd") {
113
+ if (!ownsTheElement) {
114
+ context.report({ node: node.openingElement, messageId: "hand-written-key" });
115
+ }
116
+ return;
117
+ }
118
+ if (partOf(importOf(name), KBD, context.filename) !== "Kbd") return;
119
+ for (const child of node.children) {
120
+ const text = writtenText(child);
121
+ if (text !== null && !kbdKeys().has(text)) {
122
+ context.report({ node: child, messageId: "hand-written-key" });
123
+ }
124
+ }
125
+ },
126
+ };
127
+ },
128
+ };
@@ -0,0 +1,41 @@
1
+ import { staticAttribute } from "./rendered-import.js";
2
+
3
+ /** The string a Literal or a template without expressions states, else null. */
4
+ export function literalText(node) {
5
+ if (!node) return null;
6
+ if (node.type === "Literal") {
7
+ // 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.
8
+ return typeof node.value === "string" ? node.value : null;
9
+ }
10
+ if (node.type === "TemplateLiteral" && node.expressions.length === 0) {
11
+ return node.quasis[0].value.cooked;
12
+ }
13
+ return null;
14
+ }
15
+
16
+ /** The text a JSX element's children state when all of them are literal text, else null. */
17
+ export function childText(element) {
18
+ let text = "";
19
+ for (const child of element.children) {
20
+ if (child.type === "JSXText") text += child.value;
21
+ else if (child.type === "JSXExpressionContainer" && literalText(child.expression) !== null) {
22
+ text += literalText(child.expression);
23
+ } else return null;
24
+ }
25
+ const trimmed = text.replace(/\s+/g, " ").trim();
26
+ return trimmed === "" ? null : trimmed;
27
+ }
28
+
29
+ /** The key an object property names, else null. */
30
+ export function keyName(property) {
31
+ if (property.type !== "Property" || property.computed) return null;
32
+ if (property.key.type === "Identifier") return property.key.name;
33
+ return literalText(property.key);
34
+ }
35
+
36
+ /** An attribute's value when the source states it as a string, else null. */
37
+ export function stringAttribute(openingElement, name) {
38
+ const value = staticAttribute(openingElement, name);
39
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- staticAttribute returns true, a number or a string; only typeof picks the string.
40
+ return typeof value === "string" ? value : null;
41
+ }