@nadicodeai/ui 12.1.165 → 12.1.166

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 (363) hide show
  1. package/AGENTS.md +8 -9
  2. package/README.md +2 -17
  3. package/dist/components/accordion.d.ts.map +1 -1
  4. package/dist/components/accordion.js +2 -1
  5. package/dist/components/account-menu.d.ts.map +1 -1
  6. package/dist/components/account-menu.js +5 -3
  7. package/dist/components/activity-calendar.d.ts.map +1 -1
  8. package/dist/components/activity-calendar.js +3 -2
  9. package/dist/components/agent-card.js +1 -1
  10. package/dist/components/agent-orb.d.ts.map +1 -1
  11. package/dist/components/agent-orb.js +1 -0
  12. package/dist/components/agent-profile.d.ts.map +1 -1
  13. package/dist/components/agent-profile.js +7 -4
  14. package/dist/components/alert-dialog.d.ts +1 -1
  15. package/dist/components/alert-dialog.d.ts.map +1 -1
  16. package/dist/components/alert-dialog.js +3 -3
  17. package/dist/components/app-mark.js +1 -1
  18. package/dist/components/avatar.js +8 -8
  19. package/dist/components/badge.d.ts +11 -16
  20. package/dist/components/badge.d.ts.map +1 -1
  21. package/dist/components/badge.js +7 -43
  22. package/dist/components/breadcrumb.d.ts.map +1 -1
  23. package/dist/components/breadcrumb.js +3 -2
  24. package/dist/components/button.d.ts +5 -21
  25. package/dist/components/button.d.ts.map +1 -1
  26. package/dist/components/button.js +6 -76
  27. package/dist/components/calendar.d.ts +1 -1
  28. package/dist/components/calendar.d.ts.map +1 -1
  29. package/dist/components/calendar.js +3 -3
  30. package/dist/components/card-row.js +1 -1
  31. package/dist/components/card.d.ts +4 -1
  32. package/dist/components/card.d.ts.map +1 -1
  33. package/dist/components/card.js +3 -2
  34. package/dist/components/catalog-drawer.d.ts.map +1 -1
  35. package/dist/components/catalog-drawer.js +3 -2
  36. package/dist/components/chart-axis.d.ts.map +1 -1
  37. package/dist/components/chart-axis.js +0 -2
  38. package/dist/components/chart-bar-horizontal.d.ts.map +1 -1
  39. package/dist/components/chart-bar-horizontal.js +16 -14
  40. package/dist/components/chart-card.d.ts.map +1 -1
  41. package/dist/components/chart-card.js +0 -1
  42. package/dist/components/chart.d.ts.map +1 -1
  43. package/dist/components/chart.js +18 -32
  44. package/dist/components/checkbox.d.ts +3 -2
  45. package/dist/components/checkbox.d.ts.map +1 -1
  46. package/dist/components/checkbox.js +4 -3
  47. package/dist/components/choicebox.d.ts +5 -5
  48. package/dist/components/choicebox.d.ts.map +1 -1
  49. package/dist/components/choicebox.js +6 -5
  50. package/dist/components/clearable-input.d.ts.map +1 -1
  51. package/dist/components/clearable-input.js +2 -2
  52. package/dist/components/code-block.d.ts.map +1 -1
  53. package/dist/components/code-block.js +4 -2
  54. package/dist/components/collapsible.js +1 -1
  55. package/dist/components/collection-filters.d.ts.map +1 -1
  56. package/dist/components/collection-filters.js +1 -0
  57. package/dist/components/collection-page.js +1 -1
  58. package/dist/components/collection-sort.d.ts.map +1 -1
  59. package/dist/components/collection-sort.js +1 -4
  60. package/dist/components/collection-toolbar.js +1 -1
  61. package/dist/components/combobox.js +4 -4
  62. package/dist/components/command.d.ts.map +1 -1
  63. package/dist/components/command.js +1 -1
  64. package/dist/components/confirm-dialog.js +2 -2
  65. package/dist/components/context-menu.d.ts +1 -1
  66. package/dist/components/context-menu.d.ts.map +1 -1
  67. package/dist/components/copy-button.js +1 -1
  68. package/dist/components/data-table.d.ts +11 -3
  69. package/dist/components/data-table.d.ts.map +1 -1
  70. package/dist/components/data-table.js +12 -4
  71. package/dist/components/dialog.d.ts +1 -1
  72. package/dist/components/dialog.d.ts.map +1 -1
  73. package/dist/components/dialog.js +2 -2
  74. package/dist/components/drawer.d.ts +4 -4
  75. package/dist/components/drawer.d.ts.map +1 -1
  76. package/dist/components/drawer.js +14 -15
  77. package/dist/components/dropdown-menu.d.ts +1 -1
  78. package/dist/components/dropdown-menu.d.ts.map +1 -1
  79. package/dist/components/dropdown-menu.js +9 -5
  80. package/dist/components/empty-art.js +1 -1
  81. package/dist/components/empty-state.js +2 -2
  82. package/dist/components/entry-scene.d.ts.map +1 -1
  83. package/dist/components/entry-scene.js +2 -3
  84. package/dist/components/field.js +3 -3
  85. package/dist/components/file-diff.d.ts.map +1 -1
  86. package/dist/components/file-diff.js +5 -2
  87. package/dist/components/footer.d.ts +1 -1
  88. package/dist/components/footer.d.ts.map +1 -1
  89. package/dist/components/footer.js +3 -3
  90. package/dist/components/form-dialog.d.ts.map +1 -1
  91. package/dist/components/form-dialog.js +2 -1
  92. package/dist/components/form-drawer.d.ts +7 -9
  93. package/dist/components/form-drawer.d.ts.map +1 -1
  94. package/dist/components/form-drawer.js +5 -5
  95. package/dist/components/form.d.ts +26 -0
  96. package/dist/components/form.d.ts.map +1 -0
  97. package/dist/components/form.js +29 -0
  98. package/dist/components/gauge.js +2 -2
  99. package/dist/components/heatmap/calendar-heatmap.d.ts.map +1 -1
  100. package/dist/components/heatmap/calendar-heatmap.js +15 -13
  101. package/dist/components/hive-scene.d.ts.map +1 -1
  102. package/dist/components/hive-scene.js +3 -1
  103. package/dist/components/hover-card.d.ts +1 -1
  104. package/dist/components/hover-card.d.ts.map +1 -1
  105. package/dist/components/hover-card.js +1 -1
  106. package/dist/components/input-group.d.ts +5 -6
  107. package/dist/components/input-group.d.ts.map +1 -1
  108. package/dist/components/input-group.js +8 -11
  109. package/dist/components/input-otp.d.ts.map +1 -1
  110. package/dist/components/input-otp.js +2 -2
  111. package/dist/components/item.d.ts +1 -1
  112. package/dist/components/item.js +2 -2
  113. package/dist/components/kbd.d.ts +6 -9
  114. package/dist/components/kbd.d.ts.map +1 -1
  115. package/dist/components/kbd.js +7 -3
  116. package/dist/components/message-notice.js +1 -1
  117. package/dist/components/middle-truncate.d.ts.map +1 -1
  118. package/dist/components/middle-truncate.js +1 -0
  119. package/dist/components/model-identity.d.ts +4 -4
  120. package/dist/components/model-identity.d.ts.map +1 -1
  121. package/dist/components/model-identity.js +2 -2
  122. package/dist/components/model-mark.d.ts.map +1 -1
  123. package/dist/components/model-mark.js +4 -2
  124. package/dist/components/multi-select.js +2 -2
  125. package/dist/components/native-select.d.ts.map +1 -1
  126. package/dist/components/native-select.js +2 -6
  127. package/dist/components/notice-banner.js +1 -1
  128. package/dist/components/object-page.js +2 -2
  129. package/dist/components/object-workspace.d.ts.map +1 -1
  130. package/dist/components/object-workspace.js +1 -3
  131. package/dist/components/overview-page.d.ts +1 -1
  132. package/dist/components/overview-page.d.ts.map +1 -1
  133. package/dist/components/overview-page.js +2 -1
  134. package/dist/components/page-actions.d.ts.map +1 -1
  135. package/dist/components/page-actions.js +9 -4
  136. package/dist/components/pairing-code.js +1 -1
  137. package/dist/components/pending-label.d.ts.map +1 -1
  138. package/dist/components/pending-label.js +0 -1
  139. package/dist/components/popover.d.ts +1 -1
  140. package/dist/components/popover.d.ts.map +1 -1
  141. package/dist/components/portal-sidebar-frame.d.ts.map +1 -1
  142. package/dist/components/portal-sidebar-frame.js +1 -1
  143. package/dist/components/product-message.d.ts.map +1 -1
  144. package/dist/components/product-message.js +1 -0
  145. package/dist/components/progress-checklist.d.ts.map +1 -1
  146. package/dist/components/progress-checklist.js +2 -2
  147. package/dist/components/progress.d.ts.map +1 -1
  148. package/dist/components/progress.js +5 -4
  149. package/dist/components/radio-group.js +2 -2
  150. package/dist/components/reading-column.js +1 -1
  151. package/dist/components/record-identity.d.ts.map +1 -1
  152. package/dist/components/record-identity.js +2 -5
  153. package/dist/components/record-list.d.ts.map +1 -1
  154. package/dist/components/record-list.js +4 -3
  155. package/dist/components/record-sheet.js +1 -1
  156. package/dist/components/record-time.d.ts.map +1 -1
  157. package/dist/components/record-time.js +2 -1
  158. package/dist/components/resizable.d.ts.map +1 -1
  159. package/dist/components/resizable.js +1 -1
  160. package/dist/components/row-edit-form.d.ts +2 -1
  161. package/dist/components/row-edit-form.d.ts.map +1 -1
  162. package/dist/components/row-edit-form.js +2 -1
  163. package/dist/components/run-timeline.js +1 -1
  164. package/dist/components/scope-switcher.js +1 -1
  165. package/dist/components/segmented-control.js +1 -1
  166. package/dist/components/select.js +1 -1
  167. package/dist/components/settings-facts.js +1 -1
  168. package/dist/components/settings-section.js +1 -1
  169. package/dist/components/sheet.d.ts +1 -1
  170. package/dist/components/sheet.d.ts.map +1 -1
  171. package/dist/components/sheet.js +1 -1
  172. package/dist/components/sidebar.d.ts +2 -2
  173. package/dist/components/sidebar.d.ts.map +1 -1
  174. package/dist/components/sidebar.js +16 -18
  175. package/dist/components/site-menu.d.ts +28 -0
  176. package/dist/components/site-menu.d.ts.map +1 -0
  177. package/dist/components/site-menu.js +23 -0
  178. package/dist/components/slider.d.ts.map +1 -1
  179. package/dist/components/slider.js +2 -1
  180. package/dist/components/snippet.d.ts +2 -0
  181. package/dist/components/snippet.d.ts.map +1 -1
  182. package/dist/components/snippet.js +13 -6
  183. package/dist/components/sonner.d.ts.map +1 -1
  184. package/dist/components/sonner.js +3 -4
  185. package/dist/components/status-badge.d.ts +1 -1
  186. package/dist/components/status-badge.d.ts.map +1 -1
  187. package/dist/components/switch.js +1 -1
  188. package/dist/components/table-card.js +1 -1
  189. package/dist/components/table.js +4 -4
  190. package/dist/components/tabs-nav.d.ts +52 -0
  191. package/dist/components/tabs-nav.d.ts.map +1 -0
  192. package/dist/components/tabs-nav.js +95 -0
  193. package/dist/components/tabs.d.ts +2 -56
  194. package/dist/components/tabs.d.ts.map +1 -1
  195. package/dist/components/tabs.js +2 -91
  196. package/dist/components/text-link.d.ts +1 -2
  197. package/dist/components/text-link.d.ts.map +1 -1
  198. package/dist/components/text-link.js +1 -2
  199. package/dist/components/textarea.d.ts +5 -2
  200. package/dist/components/textarea.d.ts.map +1 -1
  201. package/dist/components/textarea.js +12 -4
  202. package/dist/components/toast.d.ts +2 -0
  203. package/dist/components/toast.d.ts.map +1 -1
  204. package/dist/components/toast.js +4 -0
  205. package/dist/components/toggle-group.d.ts +3 -1
  206. package/dist/components/toggle-group.d.ts.map +1 -1
  207. package/dist/components/toggle-group.js +3 -6
  208. package/dist/components/toggle.js +1 -1
  209. package/dist/components/tooltip.d.ts +12 -12
  210. package/dist/components/tooltip.d.ts.map +1 -1
  211. package/dist/components/tooltip.js +9 -9
  212. package/dist/components/trend-badge.js +2 -2
  213. package/dist/components/update-card.js +1 -1
  214. package/dist/components/usage-meter.d.ts +1 -1
  215. package/dist/components/usage-meter.d.ts.map +1 -1
  216. package/dist/components/usage-meter.js +9 -7
  217. package/dist/components/waiting-line.js +1 -1
  218. package/dist/index.d.ts +3 -7
  219. package/dist/index.d.ts.map +1 -1
  220. package/dist/index.js +3 -7
  221. package/dist/internal/agent-orb-motion.d.ts +4 -1
  222. package/dist/internal/agent-orb-motion.d.ts.map +1 -1
  223. package/dist/internal/agent-orb-motion.js +9 -7
  224. package/dist/internal/agent-orb.d.ts +4 -1
  225. package/dist/internal/agent-orb.d.ts.map +1 -1
  226. package/dist/internal/agent-orb.js +7 -1
  227. package/dist/internal/assistant-ui/attachment.d.ts.map +1 -1
  228. package/dist/internal/assistant-ui/attachment.js +15 -15
  229. package/dist/internal/assistant-ui/follow-up-suggestions.js +1 -1
  230. package/dist/internal/assistant-ui/markdown-text.js +26 -25
  231. package/dist/internal/assistant-ui/reasoning.d.ts.map +1 -1
  232. package/dist/internal/assistant-ui/reasoning.js +13 -16
  233. package/dist/internal/assistant-ui/thread.d.ts.map +1 -1
  234. package/dist/internal/assistant-ui/thread.js +22 -16
  235. package/dist/internal/assistant-ui/tool-fallback.d.ts.map +1 -1
  236. package/dist/internal/assistant-ui/tool-fallback.js +29 -21
  237. package/dist/internal/assistant-ui/tool-group.d.ts.map +1 -1
  238. package/dist/internal/assistant-ui/tool-group.js +6 -7
  239. package/dist/internal/assistant-ui/tooltip-icon-button.js +1 -1
  240. package/dist/internal/badge-frame.d.ts +15 -0
  241. package/dist/internal/badge-frame.d.ts.map +1 -0
  242. package/dist/internal/badge-frame.js +44 -0
  243. package/dist/internal/button-classes.d.ts +20 -0
  244. package/dist/internal/button-classes.d.ts.map +1 -0
  245. package/dist/internal/button-classes.js +74 -0
  246. package/dist/internal/catalog-list.d.ts.map +1 -1
  247. package/dist/internal/catalog-list.js +8 -4
  248. package/dist/internal/collection-rail.js +3 -3
  249. package/dist/internal/form-drawer-frame.d.ts +10 -0
  250. package/dist/internal/form-drawer-frame.d.ts.map +1 -0
  251. package/dist/internal/form-drawer-frame.js +9 -0
  252. package/dist/internal/form-submit.d.ts +2 -1
  253. package/dist/internal/form-submit.d.ts.map +1 -1
  254. package/dist/internal/settings-save.d.ts.map +1 -1
  255. package/dist/internal/settings-save.js +4 -2
  256. package/dist/internal/status-mark.d.ts.map +1 -1
  257. package/dist/internal/status-mark.js +4 -1
  258. package/dist/internal/tab-row.d.ts +10 -0
  259. package/dist/internal/tab-row.d.ts.map +1 -0
  260. package/dist/internal/tab-row.js +2 -0
  261. package/dist/internal/table-compact-line.d.ts +1 -1
  262. package/dist/internal/table-compact-line.d.ts.map +1 -1
  263. package/dist/internal/table-compact-line.js +1 -1
  264. package/dist/internal/tooltip-content-frame.d.ts +14 -0
  265. package/dist/internal/tooltip-content-frame.d.ts.map +1 -0
  266. package/dist/internal/tooltip-content-frame.js +11 -0
  267. package/dist/lib/css-variables.d.ts +8 -0
  268. package/dist/lib/css-variables.d.ts.map +1 -0
  269. package/dist/lib/css-variables.js +4 -0
  270. package/dist/lib/merge-tokens.generated.js +1 -1
  271. package/dist/lib/use-copy-to-clipboard.d.ts.map +1 -1
  272. package/dist/lib/use-copy-to-clipboard.js +1 -2
  273. package/dist/showcase/samples.js +1 -1
  274. package/dist/showcase/specimens/choices.d.ts.map +1 -1
  275. package/dist/showcase/specimens/choices.js +3 -2
  276. package/dist/showcase/specimens/compositions.d.ts.map +1 -1
  277. package/dist/showcase/specimens/compositions.js +7 -5
  278. package/dist/showcase/specimens/data.d.ts.map +1 -1
  279. package/dist/showcase/specimens/data.js +1 -1
  280. package/dist/showcase/specimens/feedback.d.ts.map +1 -1
  281. package/dist/showcase/specimens/feedback.js +1 -2
  282. package/dist/showcase/specimens/index.d.ts +2 -0
  283. package/dist/showcase/specimens/index.d.ts.map +1 -1
  284. package/dist/showcase/specimens/inputs.d.ts +1 -0
  285. package/dist/showcase/specimens/inputs.d.ts.map +1 -1
  286. package/dist/showcase/specimens/inputs.js +5 -2
  287. package/dist/showcase/specimens/menus.d.ts +1 -0
  288. package/dist/showcase/specimens/menus.d.ts.map +1 -1
  289. package/dist/showcase/specimens/menus.js +7 -2
  290. package/dist/showcase/specimens/navigation.d.ts.map +1 -1
  291. package/dist/showcase/specimens/navigation.js +6 -5
  292. package/dist/showcase/specimens/status.d.ts.map +1 -1
  293. package/dist/showcase/specimens/status.js +4 -4
  294. package/dist/showcase/usage.generated.d.ts +1 -1
  295. package/dist/showcase/usage.generated.d.ts.map +1 -1
  296. package/dist/showcase/usage.generated.js +38 -16
  297. package/dist/standalone/index.js +1 -1
  298. package/dist/standalone/orb-page.js +10 -8
  299. package/dist/styles/components.css +1 -1
  300. package/package.json +32 -33
  301. package/dist/eslint/index.js +0 -224
  302. package/dist/eslint/rules/badge-is-static-label.js +0 -93
  303. package/dist/eslint/rules/button-icon-slot.js +0 -102
  304. package/dist/eslint/rules/button-link-for-navigation.js +0 -146
  305. package/dist/eslint/rules/button-no-aria-label-with-text.js +0 -75
  306. package/dist/eslint/rules/button-type-roles-only-in-buttons.js +0 -83
  307. package/dist/eslint/rules/choice-control-has-a-name.js +0 -98
  308. package/dist/eslint/rules/choice-group-in-fieldset.js +0 -86
  309. package/dist/eslint/rules/command-shortcut-single-owner.js +0 -118
  310. package/dist/eslint/rules/confirm-dialog-words.js +0 -63
  311. package/dist/eslint/rules/data-table-one-unsized-column.js +0 -96
  312. package/dist/eslint/rules/destructive-action-placement.js +0 -69
  313. package/dist/eslint/rules/disabled-choice-says-why.js +0 -71
  314. package/dist/eslint/rules/disabled-control-appearance.js +0 -75
  315. package/dist/eslint/rules/ellipsis-opens-a-dialog.js +0 -110
  316. package/dist/eslint/rules/empty-state-owner.js +0 -145
  317. package/dist/eslint/rules/input-group-owners.js +0 -155
  318. package/dist/eslint/rules/jsx-class-utility.js +0 -200
  319. package/dist/eslint/rules/kbd-children-no-modifier-text.js +0 -128
  320. package/dist/eslint/rules/literal-text.js +0 -41
  321. package/dist/eslint/rules/menu-owner.js +0 -75
  322. package/dist/eslint/rules/middle-truncate-placement.js +0 -69
  323. package/dist/eslint/rules/no-app-feature-component.js +0 -100
  324. package/dist/eslint/rules/no-bare-button-label.js +0 -55
  325. package/dist/eslint/rules/no-choice-control-wrapper.js +0 -97
  326. package/dist/eslint/rules/no-comment.js +0 -77
  327. package/dist/eslint/rules/no-control-in-read-only-surface.js +0 -106
  328. package/dist/eslint/rules/no-decorative-icon.js +0 -164
  329. package/dist/eslint/rules/no-deprecated-zod-api.js +0 -215
  330. package/dist/eslint/rules/no-global-patch.js +0 -115
  331. package/dist/eslint/rules/no-hand-built-busy.js +0 -104
  332. package/dist/eslint/rules/no-hand-built-theme-picker.js +0 -144
  333. package/dist/eslint/rules/no-hand-built-tile.js +0 -41
  334. package/dist/eslint/rules/no-hand-formatted-date.js +0 -87
  335. package/dist/eslint/rules/no-hand-stacked-avatars.js +0 -67
  336. package/dist/eslint/rules/no-nested-collapse.js +0 -60
  337. package/dist/eslint/rules/no-package-component-redefinition.js +0 -175
  338. package/dist/eslint/rules/no-search-in-form.js +0 -47
  339. package/dist/eslint/rules/no-shadcn-appearance-override.js +0 -305
  340. package/dist/eslint/rules/no-shell-prompt-in-snippet.js +0 -74
  341. package/dist/eslint/rules/no-stock-error-words.js +0 -56
  342. package/dist/eslint/rules/no-subject-derived-expectation.js +0 -183
  343. package/dist/eslint/rules/no-tooltip-around-labelled-field.js +0 -72
  344. package/dist/eslint/rules/no-weight-class-on-strong-in-type-role.js +0 -57
  345. package/dist/eslint/rules/no-write-in-subscription.js +0 -140
  346. package/dist/eslint/rules/one-submenu-level.js +0 -43
  347. package/dist/eslint/rules/one-toast-per-flow.js +0 -91
  348. package/dist/eslint/rules/option-count.js +0 -167
  349. package/dist/eslint/rules/page-command-link-not-render.js +0 -43
  350. package/dist/eslint/rules/page-composition.js +0 -232
  351. package/dist/eslint/rules/progress-needs-name.js +0 -57
  352. package/dist/eslint/rules/rendered-import.js +0 -121
  353. package/dist/eslint/rules/server-action-discipline.js +0 -233
  354. package/dist/eslint/rules/settings-limit-in-footer.js +0 -94
  355. package/dist/eslint/rules/skeleton-in-region.js +0 -80
  356. package/dist/eslint/rules/sortable-heading-uses-sort.js +0 -79
  357. package/dist/eslint/rules/table-cell-inset-owner.js +0 -107
  358. package/dist/eslint/rules/tabs-selection-is-controlled.js +0 -47
  359. package/dist/eslint/rules/test-files-from-one-definition.js +0 -67
  360. package/dist/eslint/rules/tooltip-only-arrow.js +0 -38
  361. package/dist/eslint/rules/tooltip-trigger-accessible-name.js +0 -114
  362. package/dist/eslint/rules/workspace-declares-imports.js +0 -163
  363. package/dist/eslint/strict-design-system.js +0 -250
@@ -1,75 +0,0 @@
1
- /*
2
- * Standard tool checked first: `no-restricted-imports` holds the menu modules
3
- * and the ellipsis icons (`repo/menu-owner-imports` in the root config's
4
- * product-composition blocks), but not a destructive `Button` rendered once per
5
- * row: that is an import binding joined to where its element renders, which no
6
- * import rule sees and a selector cannot follow through a renamed import.
7
- */
8
- import { PACKAGE_BARREL, partOf, renderedImports, staticAttribute } from "./rendered-import.js";
9
-
10
- const BUTTON = new Map([
11
- [
12
- "Button",
13
- ["@nadicodeai/ui/components/button", PACKAGE_BARREL].map((from) => ({ from, part: "Button" })),
14
- ],
15
- ]);
16
-
17
- const FUNCTIONS = new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"]);
18
- const ROW_CALLBACKS = new Set(["map", "flatMap"]);
19
- const ROW_RENDERERS = new Set(["cell", "command"]);
20
- const ROW_COMPONENT = /Row$/;
21
-
22
- const nameOf = (key) => (key?.type === "Identifier" ? key.name : key?.value);
23
-
24
- function drawsOneRecord(fn) {
25
- const { parent } = fn;
26
- if (
27
- parent.type === "CallExpression" &&
28
- parent.arguments[0] === fn &&
29
- parent.callee.type === "MemberExpression" &&
30
- !parent.callee.computed &&
31
- ROW_CALLBACKS.has(parent.callee.property.name)
32
- ) {
33
- return true;
34
- }
35
- if (parent.type === "Property" && parent.value === fn) {
36
- return ROW_RENDERERS.has(nameOf(parent.key));
37
- }
38
- if (parent.type === "JSXExpressionContainer" && parent.parent.type === "JSXAttribute") {
39
- return ROW_RENDERERS.has(parent.parent.name.name);
40
- }
41
- if (fn.type === "FunctionDeclaration") return ROW_COMPONENT.test(fn.id?.name ?? "");
42
- return parent.type === "VariableDeclarator" && ROW_COMPONENT.test(nameOf(parent.id) ?? "");
43
- }
44
-
45
- function insideARow(node) {
46
- for (let current = node.parent; current; current = current.parent) {
47
- if (FUNCTIONS.has(current.type) && drawsOneRecord(current)) return true;
48
- }
49
- return false;
50
- }
51
-
52
- export const menuOwner = {
53
- meta: {
54
- type: "problem",
55
- docs: {
56
- description:
57
- "A record's destructive command is the last item of its ActionMenu, never a destructive button in its row.",
58
- },
59
- schema: [],
60
- messages: {
61
- "row-destructive-button":
62
- "A destructive command is the last item of the row's ActionMenu, after a divider.",
63
- },
64
- },
65
- create(context) {
66
- const importOf = renderedImports(context);
67
- return {
68
- JSXOpeningElement(node) {
69
- if (partOf(importOf(node.name), BUTTON, context.filename) !== "Button") return;
70
- if (staticAttribute(node, "variant") !== "destructive") return;
71
- if (insideARow(node)) context.report({ node, messageId: "row-destructive-button" });
72
- },
73
- };
74
- },
75
- };
@@ -1,69 +0,0 @@
1
- /*
2
- * Standard tool checked first: a `no-restricted-syntax` descendant selector can
3
- * match `MiddleTruncate` under an element by name, but not that the name is the
4
- * design system's import, that the class sits in a `cn(...)` call or a
5
- * same-file table, nor that the nearest control carries an `aria-label`
6
- * without a second selector per spelling.
7
- */
8
- import { openingElementClassUtilities } from "./jsx-class-utility.js";
9
- import { renderedImports } from "./rendered-import.js";
10
-
11
- const FROM_DESIGN_SYSTEM = /^(@nadicodeai\/ui(\/|$)|@\/|\.)/;
12
- const CONTROLS = new Set(["Button", "ButtonLink", "TextLink"]);
13
- const HOST_CONTROLS = new Set(["a", "button"]);
14
- const NAMING_ATTRIBUTES = new Set(["aria-label", "aria-labelledby"]);
15
- const TRUNCATING = /^(truncate|text-ellipsis|overflow-ellipsis|line-clamp-(?!none$).+)$/;
16
-
17
- const withoutVariants = (utility) => utility.split(":").pop().replace(/^!/, "");
18
-
19
- const namesItself = (openingElement) =>
20
- openingElement.attributes.some(
21
- (attribute) => attribute.type === "JSXAttribute" && NAMING_ATTRIBUTES.has(attribute.name.name),
22
- );
23
-
24
- export const middleTruncatePlacement = {
25
- meta: {
26
- type: "problem",
27
- docs: {
28
- description: "MiddleTruncate cuts its own ellipsis and a control around it carries the name.",
29
- },
30
- schema: [],
31
- messages: {
32
- "cuts-its-own-ellipsis":
33
- "MiddleTruncate cuts its own ellipsis: take it out of the element that also truncates. Inside a control, give the control an aria-label that names its target, since the cut value is not a name.",
34
- },
35
- },
36
- create(context) {
37
- const importOf = renderedImports(context);
38
- const designSystemExport = (elementName) => {
39
- const imported = importOf(elementName);
40
- return imported && FROM_DESIGN_SYSTEM.test(imported.source) ? imported.name : null;
41
- };
42
- const isControl = ({ name }) =>
43
- CONTROLS.has(designSystemExport(name)) ||
44
- (name.type === "JSXIdentifier" && HOST_CONTROLS.has(name.name) && !importOf(name));
45
- const truncates = (openingElement) =>
46
- openingElementClassUtilities(openingElement, context).some((utility) =>
47
- TRUNCATING.test(withoutVariants(utility)),
48
- );
49
-
50
- return {
51
- JSXElement(node) {
52
- if (designSystemExport(node.openingElement.name) !== "MiddleTruncate") return;
53
- let nearestControl = null;
54
- for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
55
- if (ancestor.type !== "JSXElement") continue;
56
- const { openingElement } = ancestor;
57
- if (truncates(openingElement)) {
58
- context.report({ node: node.openingElement, messageId: "cuts-its-own-ellipsis" });
59
- return;
60
- }
61
- if (!nearestControl && isControl(openingElement)) nearestControl = openingElement;
62
- }
63
- if (nearestControl && !namesItself(nearestControl)) {
64
- context.report({ node: node.openingElement, messageId: "cuts-its-own-ellipsis" });
65
- }
66
- },
67
- };
68
- },
69
- };
@@ -1,100 +0,0 @@
1
- /*
2
- * `@nadicodeai/ui` ships standard components. An operator login, a portal
3
- * activation screen, a customer-credential panel — those are use cases, and a
4
- * use case in the package is a screen two consumers can never both want. The
5
- * boundary is named in the app's vocabulary, so the rule reads names: the
6
- * module's own file name and everything it exports.
7
- *
8
- * Standard tool checked first: core `no-restricted-syntax` matches
9
- * an exported identifier against a regex through esquery, but it is given one
10
- * node at a time and never the file that node is in — and a module called
11
- * `activation.tsx` exporting `Banner` is the case the file name is there to
12
- * catch. `context.filename` is why this is a rule rather than a selector list.
13
- *
14
- * The vocabulary itself is configuration, not code: the banned words live in the
15
- * workspace's eslint config where the package boundary is drawn, and this file
16
- * holds only the matching. Replaces the @nadicodeai/ui no-app-feature-components
17
- * scanner (#822), which built a TypeScript AST over the package's components to
18
- * ask the same question.
19
- */
20
-
21
- /** `OperatorLoginCard` and `operator-login.tsx` both normalise to `operator-login`. */
22
- function normalizeName(value) {
23
- return value
24
- .replace(/\.[jt]sx?$/, "")
25
- .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
26
- .replace(/[\s_]+/g, "-")
27
- .toLowerCase();
28
- }
29
-
30
- /** The declared names one `export` statement introduces. */
31
- function exportedNames(node) {
32
- if (!node.declaration) {
33
- return node.specifiers.map((specifier) => specifier.exported.name ?? specifier.exported.value);
34
- }
35
- const declaration = node.declaration;
36
- if (declaration.type === "VariableDeclaration") {
37
- return declaration.declarations
38
- .filter((declarator) => declarator.id.type === "Identifier")
39
- .map((declarator) => declarator.id.name);
40
- }
41
- return declaration.id ? [declaration.id.name] : [];
42
- }
43
-
44
- export const noAppFeatureComponent = {
45
- meta: {
46
- type: "problem",
47
- docs: {
48
- description: "Disallow app-owned feature and use-case names in a shared component package",
49
- },
50
- schema: [
51
- {
52
- type: "object",
53
- properties: {
54
- names: {
55
- type: "array",
56
- items: {
57
- type: "object",
58
- properties: { feature: { type: "string" }, pattern: { type: "string" } },
59
- required: ["feature", "pattern"],
60
- additionalProperties: false,
61
- },
62
- },
63
- },
64
- additionalProperties: false,
65
- },
66
- ],
67
- messages: {
68
- appFeature:
69
- "{{what}} names the {{feature}} use case. This package ships standard components; compose an app feature inside the consuming app.",
70
- },
71
- },
72
- create(context) {
73
- const names = (context.options?.[0]?.names ?? []).map(({ feature, pattern }) => ({
74
- feature,
75
- pattern: new RegExp(pattern),
76
- }));
77
- if (names.length === 0) return {};
78
-
79
- const feature = (candidate) =>
80
- names.find(({ pattern }) => pattern.test(normalizeName(candidate)))?.feature;
81
-
82
- const report = (node, candidate, what) => {
83
- const matched = feature(candidate);
84
- if (matched)
85
- context.report({ node, messageId: "appFeature", data: { what, feature: matched } });
86
- };
87
-
88
- return {
89
- Program(node) {
90
- const file = context.filename.replaceAll("\\", "/").split("/").at(-1) ?? "";
91
- report(node, file, `The module name "${file}"`);
92
- },
93
- ExportNamedDeclaration(node) {
94
- for (const name of exportedNames(node)) {
95
- report(node, name, `The export "${name}"`);
96
- }
97
- },
98
- };
99
- },
100
- };
@@ -1,55 +0,0 @@
1
- /*
2
- * Standard tool checked first: `no-restricted-syntax` can match a `Button`
3
- * whose text is "OK", but not whether that `Button` is the package's (an
4
- * import binding, so a renamed or local one is judged correctly), nor read the
5
- * same word off a form's `submit={{ label }}`.
6
- */
7
- import { keyName, childText, literalText } from "./literal-text.js";
8
- import { renderedImports } from "./rendered-import.js";
9
-
10
- const BUTTONS = new Set(["Button", "ButtonLink"]);
11
- const BARE = /^(?:submit|ok|okay|confirm)[.!…]*$/i;
12
- const FROM_DESIGN_SYSTEM = /^(@nadicodeai\/ui(\/|$)|@\/|\.)/;
13
-
14
- export const noBareButtonLabel = {
15
- meta: {
16
- type: "problem",
17
- docs: {
18
- description:
19
- "A button says its result as a verb and a noun, never a bare Submit, OK or Confirm.",
20
- },
21
- schema: [],
22
- messages: {
23
- "bare-label":
24
- 'A button says its result: "Create customer", "Save changes", "Remove mailbox". "{{label}}" says nothing about what happens.',
25
- },
26
- },
27
- create(context) {
28
- const importOf = renderedImports(context);
29
-
30
- function report(node, label) {
31
- context.report({ node, messageId: "bare-label", data: { label } });
32
- }
33
-
34
- return {
35
- JSXElement(node) {
36
- const imported = importOf(node.openingElement.name);
37
- if (!imported || !BUTTONS.has(imported.name) || !FROM_DESIGN_SYSTEM.test(imported.source)) {
38
- return;
39
- }
40
- const label = childText(node);
41
- if (label !== null && BARE.test(label)) report(node.openingElement, label);
42
- },
43
- JSXAttribute(node) {
44
- if (node.name.name !== "submit" || node.value?.type !== "JSXExpressionContainer") return;
45
- const { expression } = node.value;
46
- if (expression.type !== "ObjectExpression") return;
47
- for (const property of expression.properties) {
48
- if (keyName(property) !== "label") continue;
49
- const label = literalText(property.value);
50
- if (label !== null && BARE.test(label.trim())) report(property.value, label.trim());
51
- }
52
- },
53
- };
54
- },
55
- };
@@ -1,97 +0,0 @@
1
- const CHOICE_CONTROLS = new Set(["Select", "ToggleGroup", "RadioGroup", "Tabs"]);
2
-
3
- const FUNCTIONS = new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"]);
4
-
5
- function enclosingFunction(node) {
6
- let current = node.parent;
7
- while (current && !FUNCTIONS.has(current.type)) current = current.parent;
8
- return current;
9
- }
10
-
11
- /** A component's own props: a destructured or typed parameter. */
12
- const isComponent = (fn) =>
13
- fn.params.some((param) => param.type === "ObjectPattern" || param.typeAnnotation);
14
-
15
- /** Whether `owner` handed the element its value: the element's own component, or a callback inside it. */
16
- function handedTo(element, owner) {
17
- for (let fn = enclosingFunction(element); fn; fn = enclosingFunction(fn)) {
18
- if (fn === owner) return true;
19
- if (isComponent(fn)) return false;
20
- }
21
- return false;
22
- }
23
-
24
- /** The identifiers in a handler that invoke what they name: the handler itself, a callee, or a method's receiver. */
25
- function invoked(handler) {
26
- const found = [];
27
- const visit = (node) => {
28
- // oxlint-disable-next-line anti-slop/no-runtime-typeof -- walks the generic AST, where only an object whose type is a string is a node.
29
- if (!node || typeof node.type !== "string") return;
30
- if (node.type === "Identifier") {
31
- const parent = node.parent;
32
- const isCallee = parent?.type === "CallExpression" && parent.callee === node;
33
- const isReceiver =
34
- parent?.type === "MemberExpression" &&
35
- parent.object === node &&
36
- parent.parent?.type === "CallExpression" &&
37
- parent.parent.callee === parent;
38
- if (node === handler || isCallee || isReceiver) found.push(node);
39
- }
40
- for (const [key, value] of Object.entries(node)) {
41
- if (key === "parent") continue;
42
- for (const child of Array.isArray(value) ? value : [value]) {
43
- // oxlint-disable-next-line anti-slop/no-runtime-typeof -- walks the generic AST, where only an object whose type is a string is a node.
44
- if (child && typeof child.type === "string") visit(child);
45
- }
46
- }
47
- };
48
- visit(handler);
49
- return found;
50
- }
51
-
52
- /**
53
- * A kit choice control whose onValueChange forwards to a callback the enclosing
54
- * component was handed. `ToolbarToggle` flattened Base UI's array into a string
55
- * there, and "Split by" stopped working while every check stayed green.
56
- */
57
- export const noChoiceControlWrapper = {
58
- meta: {
59
- type: "problem",
60
- docs: {
61
- description:
62
- "Render a kit choice control where its value is used, never behind a wrapper that forwards it.",
63
- },
64
- schema: [],
65
- messages: {
66
- wrapper:
67
- "Render the kit's {{control}} where the value is used, with its own API: this one forwards onValueChange to \"{{name}}\", which the component was handed, and a wrapper is where the value's shape gets lost.",
68
- },
69
- },
70
- create(context) {
71
- return {
72
- "JSXAttribute[name.name='onValueChange'] > JSXExpressionContainer"(container) {
73
- const opening = container.parent.parent;
74
- const control = opening.name.type === "JSXIdentifier" ? opening.name.name : null;
75
- if (!CHOICE_CONTROLS.has(control)) return;
76
- const handler = container.expression;
77
- for (const identifier of invoked(handler)) {
78
- const scope = context.sourceCode.getScope(identifier);
79
- let variable = null;
80
- for (let current = scope; current && !variable; current = current.upper) {
81
- variable = current.set.get(identifier.name) ?? null;
82
- }
83
- const definition = variable?.defs[0];
84
- if (definition?.type !== "Parameter") continue;
85
- if (definition.node === handler) continue;
86
- if (!handedTo(opening, definition.node)) continue;
87
- context.report({
88
- node: container,
89
- messageId: "wrapper",
90
- data: { control, name: identifier.name },
91
- });
92
- return;
93
- }
94
- },
95
- };
96
- },
97
- };
@@ -1,77 +0,0 @@
1
- /*
2
- * Code says what it does in its names and its structure, and a test says what
3
- * it proves in its name and its assertions; a comment restates one of them and
4
- * nothing keeps it true when the code changes. A directive to a tool is not
5
- * prose for the reader: ESLint's, Oxlint's, TypeScript's, Biome's, Prettier's,
6
- * coverage's and Vitest's stay, and so does the marker the seam guard requires.
7
- */
8
-
9
- const DIRECTIVE =
10
- /^[*/]?\s*(?:@ts-|eslint-|eslint\s+[\w@/-]+\s*:|oxlint-|biome-ignore|<reference\b|istanbul\b|c8\s|prettier-ignore|@vitest-environment|@jsx)/;
11
-
12
- const SEAM_MARKER = /^\s*NADIA\((?:added|changed|removed)\):/;
13
-
14
- function moduleHeader(comments, firstTokenStart) {
15
- const [first, ...rest] = comments;
16
- if (first === undefined || first.range[1] > firstTokenStart) return [];
17
- if (first.type === "Block") return [first];
18
- const run = [first];
19
- for (const next of rest) {
20
- if (
21
- next.type !== "Line" ||
22
- next.range[1] > firstTokenStart ||
23
- next.loc.start.line !== run.at(-1).loc.end.line + 1
24
- ) {
25
- break;
26
- }
27
- run.push(next);
28
- }
29
- return run;
30
- }
31
-
32
- export const noComment = {
33
- meta: {
34
- type: "problem",
35
- docs: {
36
- description:
37
- "Disallow comments in code, but for directives to a tool, the marker the seam guard requires and, when allowed, the one comment that opens a module",
38
- },
39
- schema: [
40
- {
41
- type: "object",
42
- properties: { allowModuleHeader: { type: "boolean" } },
43
- additionalProperties: false,
44
- },
45
- ],
46
- defaultOptions: [{ allowModuleHeader: false }],
47
- messages: {
48
- comment:
49
- "Code says what it does in its names and its structure, never in a comment. Rename or restructure, or remove the comment.",
50
- },
51
- },
52
-
53
- create(context) {
54
- const [{ allowModuleHeader }] = context.options;
55
- const { sourceCode } = context;
56
- return {
57
- Program() {
58
- const prose = sourceCode
59
- .getAllComments()
60
- .filter(
61
- (comment) =>
62
- comment.type !== "Shebang" &&
63
- !DIRECTIVE.test(comment.value) &&
64
- !SEAM_MARKER.test(comment.value),
65
- );
66
- const header = allowModuleHeader
67
- ? moduleHeader(prose, sourceCode.ast.tokens[0]?.range[0] ?? Infinity)
68
- : [];
69
- for (const comment of prose) {
70
- if (!header.includes(comment)) {
71
- context.report({ loc: comment.loc, messageId: "comment" });
72
- }
73
- }
74
- },
75
- };
76
- },
77
- };
@@ -1,106 +0,0 @@
1
- /*
2
- * Standard tool checked first: a `no-restricted-syntax` selector can match a
3
- * `Button` below `TooltipContent`, but not follow a renamed import to the part,
4
- * count the links across a HoverCardContent's children and its summary's
5
- * `action`.
6
- */
7
- import { renderedImports, walk } from "./rendered-import.js";
8
-
9
- const OVERLAYS = new Set(["Tooltip", "HoverCard"]);
10
- const CONTROLS = new Set(["Button", "ButtonLink", "TextLink", "Link", "a"]);
11
- const NATIVE_CONTROLS = new Set(["input", "select", "textarea"]);
12
- const HOVER_CARD_SUMMARY = "HoverCardSummary";
13
-
14
- const hasAttribute = (openingElement, attributeName) =>
15
- openingElement.attributes.some(
16
- (attribute) => attribute.type === "JSXAttribute" && attribute.name.name === attributeName,
17
- );
18
-
19
- export const noControlInReadOnlySurface = {
20
- meta: {
21
- type: "problem",
22
- docs: {
23
- description:
24
- "Tooltip text and a Choicebox tile are for reading; a HoverCard holds at most one link.",
25
- },
26
- schema: [],
27
- messages: {
28
- "read-only-surface":
29
- "Tooltip text and a Choicebox tile are for reading: move the control outside. A HoverCard holds at most one link, through HoverCardSummary's `action`, and never a second Tooltip or HoverCard; for more, open a Popover, a menu or the record's page.",
30
- },
31
- },
32
- create(context) {
33
- const importOf = renderedImports(context);
34
- const { visitorKeys } = context.sourceCode;
35
-
36
- const nameOf = (element) => {
37
- const { name } = element.openingElement;
38
- if (name.type !== "JSXIdentifier" && name.type !== "JSXMemberExpression") return null;
39
- if (name.type === "JSXIdentifier" && /^[a-z]/.test(name.name)) return name.name;
40
- const imported = importOf(name);
41
- if (!imported) return null;
42
- return imported.name === "default" ? name.name : imported.name;
43
- };
44
-
45
- const isInteractive = (element, name) =>
46
- CONTROLS.has(name) ||
47
- NATIVE_CONTROLS.has(name) ||
48
- hasAttribute(element.openingElement, "onClick") ||
49
- hasAttribute(element.openingElement, "tabIndex");
50
-
51
- function visitChildren(container, visit) {
52
- for (const child of container.children) {
53
- if (visit(child) === false) continue;
54
- walk(child, visitorKeys, visit);
55
- }
56
- }
57
-
58
- function checkTooltipContent(container) {
59
- visitChildren(container, (child) => {
60
- if (child.type !== "JSXElement") return true;
61
- const name = nameOf(child);
62
- if (!OVERLAYS.has(name) && !isInteractive(child, name)) return true;
63
- context.report({ node: child.openingElement, messageId: "read-only-surface" });
64
- return false;
65
- });
66
- }
67
-
68
- function checkChoiceboxItem(container) {
69
- visitChildren(container, (child) => {
70
- if (child.type !== "JSXElement" || !isInteractive(child, nameOf(child))) return true;
71
- context.report({ node: child.openingElement, messageId: "read-only-surface" });
72
- return false;
73
- });
74
- }
75
-
76
- function checkHoverCardContent(container) {
77
- let links = 0;
78
- visitChildren(container, (child) => {
79
- if (child.type !== "JSXElement") return true;
80
- const name = nameOf(child);
81
- const { openingElement } = child;
82
- if (OVERLAYS.has(name)) {
83
- context.report({ node: openingElement, messageId: "read-only-surface" });
84
- return false;
85
- }
86
- const isLink =
87
- CONTROLS.has(name) ||
88
- hasAttribute(openingElement, "onClick") ||
89
- (name === HOVER_CARD_SUMMARY && hasAttribute(openingElement, "action"));
90
- if (!isLink) return true;
91
- links += 1;
92
- if (links > 1) context.report({ node: openingElement, messageId: "read-only-surface" });
93
- return true;
94
- });
95
- }
96
-
97
- return {
98
- JSXElement(node) {
99
- const name = nameOf(node);
100
- if (name === "TooltipContent") checkTooltipContent(node);
101
- else if (name === "ChoiceboxGroupItem") checkChoiceboxItem(node);
102
- else if (name === "HoverCardContent") checkHoverCardContent(node);
103
- },
104
- };
105
- },
106
- };