@nadicodeai/ui 12.1.165 → 12.1.167

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 (367) 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 +14 -7
  69. package/dist/components/data-table.d.ts.map +1 -1
  70. package/dist/components/data-table.js +24 -15
  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 +5 -4
  154. package/dist/components/record-list.d.ts.map +1 -1
  155. package/dist/components/record-list.js +31 -17
  156. package/dist/components/record-sheet.js +1 -1
  157. package/dist/components/record-time.d.ts.map +1 -1
  158. package/dist/components/record-time.js +2 -1
  159. package/dist/components/resizable.d.ts.map +1 -1
  160. package/dist/components/resizable.js +1 -1
  161. package/dist/components/row-edit-form.d.ts +2 -1
  162. package/dist/components/row-edit-form.d.ts.map +1 -1
  163. package/dist/components/row-edit-form.js +2 -1
  164. package/dist/components/run-timeline.js +1 -1
  165. package/dist/components/scope-switcher.js +1 -1
  166. package/dist/components/segmented-control.js +1 -1
  167. package/dist/components/select.js +1 -1
  168. package/dist/components/settings-facts.js +1 -1
  169. package/dist/components/settings-section.js +1 -1
  170. package/dist/components/sheet.d.ts +1 -1
  171. package/dist/components/sheet.d.ts.map +1 -1
  172. package/dist/components/sheet.js +1 -1
  173. package/dist/components/sidebar.d.ts +2 -2
  174. package/dist/components/sidebar.d.ts.map +1 -1
  175. package/dist/components/sidebar.js +16 -18
  176. package/dist/components/site-menu.d.ts +28 -0
  177. package/dist/components/site-menu.d.ts.map +1 -0
  178. package/dist/components/site-menu.js +23 -0
  179. package/dist/components/slider.d.ts.map +1 -1
  180. package/dist/components/slider.js +2 -1
  181. package/dist/components/snippet.d.ts +2 -0
  182. package/dist/components/snippet.d.ts.map +1 -1
  183. package/dist/components/snippet.js +13 -6
  184. package/dist/components/sonner.d.ts.map +1 -1
  185. package/dist/components/sonner.js +3 -4
  186. package/dist/components/status-badge.d.ts +1 -1
  187. package/dist/components/status-badge.d.ts.map +1 -1
  188. package/dist/components/switch.js +1 -1
  189. package/dist/components/table-card.js +1 -1
  190. package/dist/components/table-layouts.d.ts +24 -9
  191. package/dist/components/table-layouts.d.ts.map +1 -1
  192. package/dist/components/table-layouts.js +27 -10
  193. package/dist/components/table.js +4 -4
  194. package/dist/components/tabs-nav.d.ts +52 -0
  195. package/dist/components/tabs-nav.d.ts.map +1 -0
  196. package/dist/components/tabs-nav.js +95 -0
  197. package/dist/components/tabs.d.ts +2 -56
  198. package/dist/components/tabs.d.ts.map +1 -1
  199. package/dist/components/tabs.js +2 -91
  200. package/dist/components/text-link.d.ts +1 -2
  201. package/dist/components/text-link.d.ts.map +1 -1
  202. package/dist/components/text-link.js +1 -2
  203. package/dist/components/textarea.d.ts +5 -2
  204. package/dist/components/textarea.d.ts.map +1 -1
  205. package/dist/components/textarea.js +12 -4
  206. package/dist/components/toast.d.ts +2 -0
  207. package/dist/components/toast.d.ts.map +1 -1
  208. package/dist/components/toast.js +4 -0
  209. package/dist/components/toggle-group.d.ts +3 -1
  210. package/dist/components/toggle-group.d.ts.map +1 -1
  211. package/dist/components/toggle-group.js +3 -6
  212. package/dist/components/toggle.js +1 -1
  213. package/dist/components/tooltip.d.ts +12 -12
  214. package/dist/components/tooltip.d.ts.map +1 -1
  215. package/dist/components/tooltip.js +9 -9
  216. package/dist/components/trend-badge.js +2 -2
  217. package/dist/components/update-card.js +1 -1
  218. package/dist/components/usage-meter.d.ts +1 -1
  219. package/dist/components/usage-meter.d.ts.map +1 -1
  220. package/dist/components/usage-meter.js +9 -7
  221. package/dist/components/waiting-line.js +1 -1
  222. package/dist/index.d.ts +3 -7
  223. package/dist/index.d.ts.map +1 -1
  224. package/dist/index.js +3 -7
  225. package/dist/internal/agent-orb-motion.d.ts +4 -1
  226. package/dist/internal/agent-orb-motion.d.ts.map +1 -1
  227. package/dist/internal/agent-orb-motion.js +9 -7
  228. package/dist/internal/agent-orb.d.ts +4 -1
  229. package/dist/internal/agent-orb.d.ts.map +1 -1
  230. package/dist/internal/agent-orb.js +7 -1
  231. package/dist/internal/assistant-ui/attachment.d.ts.map +1 -1
  232. package/dist/internal/assistant-ui/attachment.js +15 -15
  233. package/dist/internal/assistant-ui/follow-up-suggestions.js +1 -1
  234. package/dist/internal/assistant-ui/markdown-text.js +26 -25
  235. package/dist/internal/assistant-ui/reasoning.d.ts.map +1 -1
  236. package/dist/internal/assistant-ui/reasoning.js +13 -16
  237. package/dist/internal/assistant-ui/thread.d.ts.map +1 -1
  238. package/dist/internal/assistant-ui/thread.js +22 -16
  239. package/dist/internal/assistant-ui/tool-fallback.d.ts.map +1 -1
  240. package/dist/internal/assistant-ui/tool-fallback.js +29 -21
  241. package/dist/internal/assistant-ui/tool-group.d.ts.map +1 -1
  242. package/dist/internal/assistant-ui/tool-group.js +6 -7
  243. package/dist/internal/assistant-ui/tooltip-icon-button.js +1 -1
  244. package/dist/internal/badge-frame.d.ts +15 -0
  245. package/dist/internal/badge-frame.d.ts.map +1 -0
  246. package/dist/internal/badge-frame.js +44 -0
  247. package/dist/internal/button-classes.d.ts +20 -0
  248. package/dist/internal/button-classes.d.ts.map +1 -0
  249. package/dist/internal/button-classes.js +74 -0
  250. package/dist/internal/catalog-list.d.ts.map +1 -1
  251. package/dist/internal/catalog-list.js +8 -4
  252. package/dist/internal/collection-rail.js +3 -3
  253. package/dist/internal/form-drawer-frame.d.ts +10 -0
  254. package/dist/internal/form-drawer-frame.d.ts.map +1 -0
  255. package/dist/internal/form-drawer-frame.js +9 -0
  256. package/dist/internal/form-submit.d.ts +2 -1
  257. package/dist/internal/form-submit.d.ts.map +1 -1
  258. package/dist/internal/settings-save.d.ts.map +1 -1
  259. package/dist/internal/settings-save.js +4 -2
  260. package/dist/internal/status-mark.d.ts.map +1 -1
  261. package/dist/internal/status-mark.js +4 -1
  262. package/dist/internal/tab-row.d.ts +10 -0
  263. package/dist/internal/tab-row.d.ts.map +1 -0
  264. package/dist/internal/tab-row.js +2 -0
  265. package/dist/internal/table-compact-line.d.ts +1 -1
  266. package/dist/internal/table-compact-line.d.ts.map +1 -1
  267. package/dist/internal/table-compact-line.js +1 -1
  268. package/dist/internal/tooltip-content-frame.d.ts +14 -0
  269. package/dist/internal/tooltip-content-frame.d.ts.map +1 -0
  270. package/dist/internal/tooltip-content-frame.js +11 -0
  271. package/dist/lib/css-variables.d.ts +8 -0
  272. package/dist/lib/css-variables.d.ts.map +1 -0
  273. package/dist/lib/css-variables.js +4 -0
  274. package/dist/lib/merge-tokens.generated.js +1 -1
  275. package/dist/lib/use-copy-to-clipboard.d.ts.map +1 -1
  276. package/dist/lib/use-copy-to-clipboard.js +1 -2
  277. package/dist/showcase/samples.js +1 -1
  278. package/dist/showcase/specimens/choices.d.ts.map +1 -1
  279. package/dist/showcase/specimens/choices.js +3 -2
  280. package/dist/showcase/specimens/compositions.d.ts.map +1 -1
  281. package/dist/showcase/specimens/compositions.js +7 -5
  282. package/dist/showcase/specimens/data.d.ts.map +1 -1
  283. package/dist/showcase/specimens/data.js +1 -1
  284. package/dist/showcase/specimens/feedback.d.ts.map +1 -1
  285. package/dist/showcase/specimens/feedback.js +1 -2
  286. package/dist/showcase/specimens/index.d.ts +2 -0
  287. package/dist/showcase/specimens/index.d.ts.map +1 -1
  288. package/dist/showcase/specimens/inputs.d.ts +1 -0
  289. package/dist/showcase/specimens/inputs.d.ts.map +1 -1
  290. package/dist/showcase/specimens/inputs.js +5 -2
  291. package/dist/showcase/specimens/menus.d.ts +1 -0
  292. package/dist/showcase/specimens/menus.d.ts.map +1 -1
  293. package/dist/showcase/specimens/menus.js +7 -2
  294. package/dist/showcase/specimens/navigation.d.ts.map +1 -1
  295. package/dist/showcase/specimens/navigation.js +6 -5
  296. package/dist/showcase/specimens/status.d.ts.map +1 -1
  297. package/dist/showcase/specimens/status.js +4 -4
  298. package/dist/showcase/usage.generated.d.ts +1 -1
  299. package/dist/showcase/usage.generated.d.ts.map +1 -1
  300. package/dist/showcase/usage.generated.js +40 -18
  301. package/dist/standalone/index.js +2 -2
  302. package/dist/standalone/orb-page.js +10 -8
  303. package/dist/styles/components.css +14 -1
  304. package/package.json +32 -33
  305. package/dist/eslint/index.js +0 -224
  306. package/dist/eslint/rules/badge-is-static-label.js +0 -93
  307. package/dist/eslint/rules/button-icon-slot.js +0 -102
  308. package/dist/eslint/rules/button-link-for-navigation.js +0 -146
  309. package/dist/eslint/rules/button-no-aria-label-with-text.js +0 -75
  310. package/dist/eslint/rules/button-type-roles-only-in-buttons.js +0 -83
  311. package/dist/eslint/rules/choice-control-has-a-name.js +0 -98
  312. package/dist/eslint/rules/choice-group-in-fieldset.js +0 -86
  313. package/dist/eslint/rules/command-shortcut-single-owner.js +0 -118
  314. package/dist/eslint/rules/confirm-dialog-words.js +0 -63
  315. package/dist/eslint/rules/data-table-one-unsized-column.js +0 -96
  316. package/dist/eslint/rules/destructive-action-placement.js +0 -69
  317. package/dist/eslint/rules/disabled-choice-says-why.js +0 -71
  318. package/dist/eslint/rules/disabled-control-appearance.js +0 -75
  319. package/dist/eslint/rules/ellipsis-opens-a-dialog.js +0 -110
  320. package/dist/eslint/rules/empty-state-owner.js +0 -145
  321. package/dist/eslint/rules/input-group-owners.js +0 -155
  322. package/dist/eslint/rules/jsx-class-utility.js +0 -200
  323. package/dist/eslint/rules/kbd-children-no-modifier-text.js +0 -128
  324. package/dist/eslint/rules/literal-text.js +0 -41
  325. package/dist/eslint/rules/menu-owner.js +0 -75
  326. package/dist/eslint/rules/middle-truncate-placement.js +0 -69
  327. package/dist/eslint/rules/no-app-feature-component.js +0 -100
  328. package/dist/eslint/rules/no-bare-button-label.js +0 -55
  329. package/dist/eslint/rules/no-choice-control-wrapper.js +0 -97
  330. package/dist/eslint/rules/no-comment.js +0 -77
  331. package/dist/eslint/rules/no-control-in-read-only-surface.js +0 -106
  332. package/dist/eslint/rules/no-decorative-icon.js +0 -164
  333. package/dist/eslint/rules/no-deprecated-zod-api.js +0 -215
  334. package/dist/eslint/rules/no-global-patch.js +0 -115
  335. package/dist/eslint/rules/no-hand-built-busy.js +0 -104
  336. package/dist/eslint/rules/no-hand-built-theme-picker.js +0 -144
  337. package/dist/eslint/rules/no-hand-built-tile.js +0 -41
  338. package/dist/eslint/rules/no-hand-formatted-date.js +0 -87
  339. package/dist/eslint/rules/no-hand-stacked-avatars.js +0 -67
  340. package/dist/eslint/rules/no-nested-collapse.js +0 -60
  341. package/dist/eslint/rules/no-package-component-redefinition.js +0 -175
  342. package/dist/eslint/rules/no-search-in-form.js +0 -47
  343. package/dist/eslint/rules/no-shadcn-appearance-override.js +0 -305
  344. package/dist/eslint/rules/no-shell-prompt-in-snippet.js +0 -74
  345. package/dist/eslint/rules/no-stock-error-words.js +0 -56
  346. package/dist/eslint/rules/no-subject-derived-expectation.js +0 -183
  347. package/dist/eslint/rules/no-tooltip-around-labelled-field.js +0 -72
  348. package/dist/eslint/rules/no-weight-class-on-strong-in-type-role.js +0 -57
  349. package/dist/eslint/rules/no-write-in-subscription.js +0 -140
  350. package/dist/eslint/rules/one-submenu-level.js +0 -43
  351. package/dist/eslint/rules/one-toast-per-flow.js +0 -91
  352. package/dist/eslint/rules/option-count.js +0 -167
  353. package/dist/eslint/rules/page-command-link-not-render.js +0 -43
  354. package/dist/eslint/rules/page-composition.js +0 -232
  355. package/dist/eslint/rules/progress-needs-name.js +0 -57
  356. package/dist/eslint/rules/rendered-import.js +0 -121
  357. package/dist/eslint/rules/server-action-discipline.js +0 -233
  358. package/dist/eslint/rules/settings-limit-in-footer.js +0 -94
  359. package/dist/eslint/rules/skeleton-in-region.js +0 -80
  360. package/dist/eslint/rules/sortable-heading-uses-sort.js +0 -79
  361. package/dist/eslint/rules/table-cell-inset-owner.js +0 -107
  362. package/dist/eslint/rules/tabs-selection-is-controlled.js +0 -47
  363. package/dist/eslint/rules/test-files-from-one-definition.js +0 -67
  364. package/dist/eslint/rules/tooltip-only-arrow.js +0 -38
  365. package/dist/eslint/rules/tooltip-trigger-accessible-name.js +0 -114
  366. package/dist/eslint/rules/workspace-declares-imports.js +0 -163
  367. package/dist/eslint/strict-design-system.js +0 -250
@@ -1,72 +0,0 @@
1
- /*
2
- * Standard tool checked first: a `no-restricted-syntax` selector can match a
3
- * `Field` descendant of a `Tooltip` by element name, but not that both are
4
- * imports from the design system, nor reach a field named in the `render`
5
- * element of a trigger, so it would also refuse a product's own `Input`.
6
- */
7
- import { renderedImports, walk } from "./rendered-import.js";
8
-
9
- const WRAPPERS = new Set(["Tooltip", "TooltipTrigger", "HoverCard", "HoverCardTrigger"]);
10
- const POPUPS = new Set(["TooltipContent", "HoverCardContent"]);
11
- const FIELDS = new Set([
12
- "Input",
13
- "Textarea",
14
- "ClearableInput",
15
- "CollectionSearch",
16
- "Select",
17
- "SelectTrigger",
18
- "NativeSelect",
19
- "Combobox",
20
- "ComboboxInput",
21
- "Checkbox",
22
- "Switch",
23
- "Label",
24
- "FieldLabel",
25
- "SettingsField",
26
- ]);
27
-
28
- const FROM_DESIGN_SYSTEM = /^(@nadicodeai\/ui(\/|$)|@\/|\.)/;
29
-
30
- export const noTooltipAroundLabelledField = {
31
- meta: {
32
- type: "problem",
33
- docs: {
34
- description:
35
- "A Tooltip or HoverCard never wraps a field: put the help on an icon button beside it.",
36
- },
37
- schema: [],
38
- messages: {
39
- "field-tooltip":
40
- "Do not put a Tooltip or HoverCard on a field: its text becomes a second, hidden label. Put the help on an icon button beside the field.",
41
- },
42
- },
43
- create(context) {
44
- const importOf = renderedImports(context);
45
- const exportOf = (elementName) => {
46
- const imported = importOf(elementName);
47
- return imported && FROM_DESIGN_SYSTEM.test(imported.source) ? imported.name : null;
48
- };
49
-
50
- function wrapsAField(element) {
51
- let found = false;
52
- walk(element, context.sourceCode.visitorKeys, (child) => {
53
- if (child.type !== "JSXElement") return true;
54
- const name = exportOf(child.openingElement.name);
55
- if (POPUPS.has(name)) return false;
56
- if (!FIELDS.has(name)) return true;
57
- found = true;
58
- return "stop";
59
- });
60
- return found;
61
- }
62
-
63
- return {
64
- JSXElement(node) {
65
- if (!WRAPPERS.has(exportOf(node.openingElement.name))) return;
66
- if (wrapsAField(node)) {
67
- context.report({ node: node.openingElement, messageId: "field-tooltip" });
68
- }
69
- },
70
- };
71
- },
72
- };
@@ -1,57 +0,0 @@
1
- /*
2
- * Standard tool checked first: a `no-restricted-syntax` selector can match a
3
- * `strong` whose own className holds a weight class, but cannot ask whether some
4
- * element above it carries a type role, so it would refuse every weighted
5
- * `<strong>` or none. This rule reads both classNames, ancestors included, in
6
- * one file.
7
- */
8
- import { openingElementClassUtilities } from "./jsx-class-utility.js";
9
-
10
- const STRONG_TAGS = new Set(["strong", "b"]);
11
- const WEIGHT_CLASS = /^font-(medium|semibold|bold)$/;
12
- const TYPE_ROLE_CLASS = /^(nc-type-|text-(display-|heading-|body-|label|caption))/;
13
-
14
- const baseUtility = (utility) => utility.slice(utility.lastIndexOf(":") + 1).replace(/^!/, "");
15
-
16
- const hasUtility = (element, context, pattern) =>
17
- openingElementClassUtilities(element, context).some((utility) =>
18
- pattern.test(baseUtility(utility)),
19
- );
20
-
21
- function hasTypeRoleAncestor(element, context) {
22
- for (let ancestor = element.parent?.parent; ancestor; ancestor = ancestor.parent) {
23
- if (
24
- ancestor.type === "JSXElement" &&
25
- hasUtility(ancestor.openingElement, context, TYPE_ROLE_CLASS)
26
- ) {
27
- return true;
28
- }
29
- }
30
- return false;
31
- }
32
-
33
- export const noWeightClassOnStrongInTypeRole = {
34
- meta: {
35
- type: "problem",
36
- docs: {
37
- description:
38
- "A type role sets the weight of a nested <strong>; the element carries no weight class.",
39
- },
40
- schema: [],
41
- messages: {
42
- "weight-on-strong":
43
- "The type role sets the weight of a nested <strong>: 550 in copy, 500 in labels and headings. Remove the font-weight class from the <strong>.",
44
- },
45
- },
46
- create(context) {
47
- return {
48
- JSXOpeningElement(node) {
49
- if (node.name.type !== "JSXIdentifier" || !STRONG_TAGS.has(node.name.name)) return;
50
- if (!hasUtility(node, context, WEIGHT_CLASS)) return;
51
- if (hasTypeRoleAncestor(node, context)) {
52
- context.report({ node, messageId: "weight-on-strong" });
53
- }
54
- },
55
- };
56
- },
57
- };
@@ -1,140 +0,0 @@
1
- /*
2
- * A callback a store subscription or a watcher runs must not write: code that
3
- * listens to another system's state and writes that state, or state coupled to
4
- * it, back is a loop the other system can restart on every change. Nadia's
5
- * desktop once held Hermes's pane layout this way, and Hermes's own reaction to
6
- * each correction fed the next one until the window ran out of memory. The
7
- * product declares its intent once and the owning system applies it.
8
- *
9
- * Standard tool checked first: core `no-restricted-syntax` can match a write
10
- * nested in an inline callback, but the loop was written as `atom.listen(hold)`,
11
- * a named function declared elsewhere in the file, and a selector cannot follow
12
- * that reference. This rule resolves a passed identifier through scope analysis
13
- * to the function it names in the same file.
14
- *
15
- * What counts as a subscription and as a write is configuration: the workspace
16
- * names its subscription methods (an event listener's `addEventListener`
17
- * included) and its writers where the rule is turned on, and this file holds
18
- * only the matching. A writer is matched against the called name and against
19
- * its dotted path, so `location.replace` can be a writer while a string's
20
- * `replace` is not; an assignment inside the callback, such as
21
- * `location.hash = …`, is matched by the path it assigns.
22
- */
23
-
24
- const FUNCTIONS = new Set(["ArrowFunctionExpression", "FunctionExpression", "FunctionDeclaration"]);
25
-
26
- function pathOf(node) {
27
- if (node.type === "Identifier") return node.name;
28
- if (node.type === "ThisExpression") return "this";
29
- if (node.type === "ChainExpression") return pathOf(node.expression);
30
- if (node.type === "MemberExpression" && !node.computed && node.property.type === "Identifier") {
31
- const object = pathOf(node.object);
32
- return object === null ? null : `${object}.${node.property.name}`;
33
- }
34
- return null;
35
- }
36
-
37
- function calleeName(callee) {
38
- if (callee.type === "Identifier") return callee.name;
39
- if (
40
- callee.type === "MemberExpression" &&
41
- !callee.computed &&
42
- callee.property.type === "Identifier"
43
- ) {
44
- return callee.property.name;
45
- }
46
- if (callee.type === "ChainExpression") return calleeName(callee.expression);
47
- return null;
48
- }
49
-
50
- function variableOf(scope, name) {
51
- for (let current = scope; current; current = current.upper) {
52
- const found = current.set.get(name);
53
- if (found) return found;
54
- }
55
- return null;
56
- }
57
-
58
- function functionOf(context, node) {
59
- if (FUNCTIONS.has(node.type)) return node;
60
- if (node.type !== "Identifier") return null;
61
- const variable = variableOf(context.sourceCode.getScope(node), node.name);
62
- for (const definition of variable?.defs ?? []) {
63
- if (definition.type === "FunctionName") return definition.node;
64
- const init = definition.type === "Variable" ? definition.node.init : null;
65
- if (init && FUNCTIONS.has(init.type)) return init;
66
- }
67
- return null;
68
- }
69
-
70
- function* writesIn(node, keys) {
71
- if (node.type === "CallExpression") {
72
- yield { node, names: [calleeName(node.callee), pathOf(node.callee)] };
73
- }
74
- if (node.type === "AssignmentExpression") {
75
- yield { node, names: [pathOf(node.left)] };
76
- }
77
- for (const key of keys[node.type] ?? []) {
78
- const child = node[key];
79
- for (const each of Array.isArray(child) ? child : [child]) {
80
- // 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.
81
- if (each && typeof each.type === "string") yield* writesIn(each, keys);
82
- }
83
- }
84
- }
85
-
86
- export const noWriteInSubscription = {
87
- meta: {
88
- type: "problem",
89
- docs: {
90
- description: "Disallow writes inside a callback passed to a store subscription or a watcher",
91
- },
92
- schema: [
93
- {
94
- type: "object",
95
- properties: {
96
- subscriptions: { type: "string" },
97
- writers: { type: "string" },
98
- reason: { type: "string" },
99
- },
100
- required: ["subscriptions", "writers"],
101
- additionalProperties: false,
102
- },
103
- ],
104
- messages: {
105
- writeBack:
106
- "`{{writer}}` writes from inside the callback `{{subscription}}` runs on every change of the state it watches. Declare the intent once and let the owner of that state apply it.{{reason}}",
107
- },
108
- },
109
- create(context) {
110
- const options = context.options?.[0];
111
- if (!options) return {};
112
- const subscriptions = new RegExp(options.subscriptions);
113
- const writers = new RegExp(options.writers);
114
- const reason = options.reason ? ` ${options.reason}` : "";
115
- const keys = context.sourceCode.visitorKeys;
116
- const reported = new Set();
117
-
118
- return {
119
- CallExpression(node) {
120
- const subscription = calleeName(node.callee);
121
- if (!subscription || !subscriptions.test(subscription)) return;
122
- for (const argument of node.arguments) {
123
- const callback = functionOf(context, argument);
124
- if (!callback) continue;
125
- for (const write of writesIn(callback.body, keys)) {
126
- const writer = write.names.find((name) => name !== null && writers.test(name));
127
- if (writer && !reported.has(write.node)) {
128
- reported.add(write.node);
129
- context.report({
130
- node: write.node,
131
- messageId: "writeBack",
132
- data: { reason, subscription, writer },
133
- });
134
- }
135
- }
136
- }
137
- },
138
- };
139
- },
140
- };
@@ -1,43 +0,0 @@
1
- /*
2
- * Standard tool checked first: a `no-restricted-syntax` descendant selector
3
- * matches by element name, so it cannot tell the package's
4
- * `DropdownMenuSub` from a local component of the same name or follow a
5
- * renamed import.
6
- */
7
- import { renderedImports } from "./rendered-import.js";
8
-
9
- const SUBMENUS = new Set(["DropdownMenuSub", "ContextMenuSub", "MenubarSub"]);
10
- const FROM_DESIGN_SYSTEM = /^(@nadicodeai\/ui(\/|$)|@\/|\.)/;
11
-
12
- export const oneSubmenuLevel = {
13
- meta: {
14
- type: "problem",
15
- docs: { description: "A menu has one level of submenu, never a submenu inside a submenu." },
16
- schema: [],
17
- messages: {
18
- "nested-submenu":
19
- "A menu opens one submenu deep. A third level hides commands behind a pointer path that is easy to lose: flatten the inner submenu into a group of the first, or move it to its own menu.",
20
- },
21
- },
22
- create(context) {
23
- const importOf = renderedImports(context);
24
- const isSubmenu = (element) => {
25
- const imported = importOf(element.openingElement.name);
26
- return (
27
- imported !== null && SUBMENUS.has(imported.name) && FROM_DESIGN_SYSTEM.test(imported.source)
28
- );
29
- };
30
-
31
- return {
32
- JSXElement(node) {
33
- if (!isSubmenu(node)) return;
34
- for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
35
- if (ancestor.type === "JSXElement" && isSubmenu(ancestor)) {
36
- context.report({ node: node.openingElement, messageId: "nested-submenu" });
37
- return;
38
- }
39
- }
40
- },
41
- };
42
- },
43
- };
@@ -1,91 +0,0 @@
1
- /*
2
- * Standard tool checked first: `no-restricted-syntax` selectors match one node
3
- * and its ancestors, but whether two calls can both run is a question about
4
- * how their paths split (if/else, ?:, try/catch, switch cases, an early
5
- * return), which no selector can ask.
6
- */
7
- const TOAST_CALLS = new Set(["notify", "notifyError", "showMessageToast"]);
8
- const EXITS = new Set(["ReturnStatement", "ThrowStatement"]);
9
- const STATEMENT_LISTS = new Set(["BlockStatement", "SwitchCase", "Program", "StaticBlock"]);
10
-
11
- const calleeName = (callee) => {
12
- if (callee.type === "Identifier") return callee.name;
13
- if (callee.type === "MemberExpression" && !callee.computed) return callee.property.name;
14
- return null;
15
- };
16
-
17
- const isToastCall = (node) => TOAST_CALLS.has(calleeName(node.callee));
18
-
19
- const chainOf = (node) => {
20
- const chain = [];
21
- for (let current = node; current; current = current.parent) chain.push(current);
22
- return chain;
23
- };
24
-
25
- const branchesOf = (split) => {
26
- if (split.type === "IfStatement") return [split.consequent, split.alternate];
27
- if (split.type === "ConditionalExpression") return [split.consequent, split.alternate];
28
- if (split.type === "TryStatement") return [split.block, split.handler];
29
- if (split.type === "SwitchStatement") return split.cases;
30
- return [];
31
- };
32
-
33
- const onDifferentBranches = (split, first, second) => {
34
- const branches = branchesOf(split);
35
- return branches.includes(first) && branches.includes(second) && first !== second;
36
- };
37
-
38
- const leavesBefore = (below, split) =>
39
- below.some((node) => {
40
- if (EXITS.has(node.type)) return true;
41
- const list = node.parent;
42
- if (!STATEMENT_LISTS.has(list.type) || list === split) return false;
43
- const siblings = list.type === "SwitchCase" ? list.consequent : list.body;
44
- return siblings.slice(siblings.indexOf(node) + 1).some((next) => EXITS.has(next.type));
45
- });
46
-
47
- function runsAfter(earlier, later) {
48
- const laterChain = chainOf(later);
49
- const earlierChain = chainOf(earlier);
50
- const meeting = earlierChain.findIndex((node) => laterChain.includes(node));
51
- const split = earlierChain[meeting];
52
- const earlierBelow = earlierChain.slice(0, meeting);
53
- const laterSide = laterChain[laterChain.indexOf(split) - 1];
54
- if (onDifferentBranches(split, earlierBelow.at(-1), laterSide)) return false;
55
- return !leavesBefore(earlierBelow, split);
56
- }
57
-
58
- export const oneToastPerFlow = {
59
- meta: {
60
- type: "problem",
61
- docs: {
62
- description:
63
- "A flow raises one toast when it ends, never one per step: a success and a failure on separate paths are fine.",
64
- },
65
- schema: [],
66
- messages: {
67
- "toast-per-step": "Raise one toast when the flow ends, not one per step.",
68
- },
69
- },
70
- create(context) {
71
- const scopes = [[]];
72
-
73
- function closeScope() {
74
- const calls = scopes.pop();
75
- calls.forEach((call, index) => {
76
- if (calls.slice(0, index).some((earlier) => runsAfter(earlier, call))) {
77
- context.report({ node: call, messageId: "toast-per-step" });
78
- }
79
- });
80
- }
81
-
82
- return {
83
- ":function": () => scopes.push([]),
84
- ":function:exit": closeScope,
85
- "Program:exit": closeScope,
86
- CallExpression(node) {
87
- if (isToastCall(node)) scopes.at(-1).push(node);
88
- },
89
- };
90
- },
91
- };
@@ -1,167 +0,0 @@
1
- /*
2
- * Standard tool checked first: a `no-restricted-syntax` selector can count the
3
- * children of one element, but not follow a renamed import to the part, count
4
- * the items below wrappers, or tell a literal list from one that a `map`,
5
- * a spread or a condition makes.
6
- */
7
- import { findBelow, renderedImports, walk } from "./rendered-import.js";
8
-
9
- const GROUPS = new Map([
10
- ["RadioGroup", { item: "RadioGroupItem", min: 2, max: 6 }],
11
- ["ChoiceboxGroup", { item: "ChoiceboxGroupItem", max: 6 }],
12
- ["MultiSelect", { item: "MultiSelectRow", min: 2 }],
13
- ["MultiSelectContent", { item: "MultiSelectRow", min: 2 }],
14
- ]);
15
- const COMMAND_PROPS = new Map([
16
- ["ActionMenu", "commands"],
17
- ["ActionContextMenu", "commands"],
18
- ["PageActions", "menu"],
19
- ["PageActionsRow", "menu"],
20
- ]);
21
- const MENU_TYPES = new Set(["RecordMenu", "PageMenu"]);
22
- const MAX_COMMANDS = 10;
23
- const LIST_CALLBACKS = new Set(["map", "flatMap"]);
24
-
25
- const isChildPosition = (node) =>
26
- node.parent.type === "JSXElement" || node.parent.type === "JSXFragment";
27
-
28
- const withoutTypeAssertion = (node) =>
29
- node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression" ? node.expression : node;
30
-
31
- const keyName = (property) =>
32
- property.key.type === "Identifier" ? property.key.name : property.key.value;
33
-
34
- function literalCommands(menu) {
35
- const object = withoutTypeAssertion(menu);
36
- if (object.type !== "ObjectExpression") return null;
37
- const property = object.properties.find(
38
- (candidate) =>
39
- candidate.type === "Property" && !candidate.computed && keyName(candidate) === "commands",
40
- );
41
- return property ? literalArray(property.value) : null;
42
- }
43
-
44
- function literalArray(value) {
45
- const array = withoutTypeAssertion(value);
46
- if (array.type !== "ArrayExpression") return null;
47
- return array.elements.every((element) => element && element.type !== "SpreadElement")
48
- ? array
49
- : null;
50
- }
51
-
52
- export const optionCount = {
53
- meta: {
54
- type: "problem",
55
- docs: {
56
- description:
57
- "A RadioGroup holds 2 to 6 options, a Choicebox at most 6 tiles, a MultiSelect at least 2 rows, a menu about 10 commands.",
58
- },
59
- schema: [],
60
- messages: {
61
- "option-count":
62
- "Keep the choice readable: a RadioGroup holds 2 to 6 options (7 or more is a Select or Combobox), a Choicebox at most 6 tiles, a MultiSelect at least 2 rows (one is a Checkbox or Switch), a menu about 10 commands (group the rest by job into a second menu or a page).",
63
- },
64
- },
65
- create(context) {
66
- const importOf = renderedImports(context);
67
- const { visitorKeys } = context.sourceCode;
68
-
69
- const importedName = (element) => importOf(element.openingElement.name)?.name ?? null;
70
-
71
- const hidesItems = (container) =>
72
- findBelow(
73
- container,
74
- visitorKeys,
75
- (node) =>
76
- node.type === "JSXElement" ||
77
- node.type === "JSXFragment" ||
78
- (node.type === "CallExpression" &&
79
- node.callee.type === "MemberExpression" &&
80
- LIST_CALLBACKS.has(node.callee.property.name)),
81
- ) !== null;
82
-
83
- function countLiteralItems(group, itemName) {
84
- let count = 0;
85
- let literal = true;
86
- const tally = (node) => {
87
- if (node.type === "JSXElement" && importedName(node) === itemName) count += 1;
88
- if (
89
- (node.type === "JSXExpressionContainer" || node.type === "JSXSpreadChild") &&
90
- isChildPosition(node) &&
91
- hidesItems(node)
92
- ) {
93
- literal = false;
94
- return "stop";
95
- }
96
- return true;
97
- };
98
- for (const child of group.children) {
99
- if (child.type === "JSXText" && child.value.trim() === "") continue;
100
- if (child.type !== "JSXElement") return null;
101
- tally(child);
102
- if (walk(child, visitorKeys, tally) === "stop" || !literal) return null;
103
- }
104
- return count;
105
- }
106
-
107
- const ownsContent = (element) =>
108
- findBelow(
109
- element,
110
- visitorKeys,
111
- (node) => node.type === "JSXElement" && importedName(node) === "MultiSelectContent",
112
- ) !== null;
113
-
114
- function checkGroup(element, name) {
115
- const { item, min = 0, max = Infinity } = GROUPS.get(name);
116
- if (name === "MultiSelect" && ownsContent(element)) return;
117
- const count = countLiteralItems(element, item);
118
- if (!count) return;
119
- if (count < min || count > max) {
120
- context.report({ node: element.openingElement, messageId: "option-count" });
121
- }
122
- }
123
-
124
- function checkCommands(array) {
125
- if (array && array.elements.length > MAX_COMMANDS) {
126
- context.report({ node: array, messageId: "option-count" });
127
- }
128
- }
129
-
130
- function checkMenuAttribute(openingElement, name) {
131
- const prop = COMMAND_PROPS.get(name);
132
- const attribute = openingElement.attributes.find(
133
- (candidate) => candidate.type === "JSXAttribute" && candidate.name.name === prop,
134
- );
135
- if (attribute?.value?.type !== "JSXExpressionContainer") return;
136
- const { expression } = attribute.value;
137
- checkCommands(prop === "commands" ? literalArray(expression) : literalCommands(expression));
138
- }
139
-
140
- const isMenuType = (annotation) =>
141
- annotation?.type === "TSTypeReference" &&
142
- annotation.typeName.type === "Identifier" &&
143
- MENU_TYPES.has(annotation.typeName.name);
144
-
145
- return {
146
- JSXElement(node) {
147
- const name = importedName(node);
148
- if (GROUPS.has(name)) checkGroup(node, name);
149
- },
150
- JSXOpeningElement(node) {
151
- const name = importOf(node.name)?.name;
152
- if (COMMAND_PROPS.has(name)) checkMenuAttribute(node, name);
153
- },
154
- VariableDeclarator(node) {
155
- if (
156
- node.init?.type === "ObjectExpression" &&
157
- isMenuType(node.id.typeAnnotation?.typeAnnotation)
158
- ) {
159
- checkCommands(literalCommands(node.init));
160
- }
161
- },
162
- "TSAsExpression, TSSatisfiesExpression"(node) {
163
- if (isMenuType(node.typeAnnotation)) checkCommands(literalCommands(node.expression));
164
- },
165
- };
166
- },
167
- };
@@ -1,43 +0,0 @@
1
- /*
2
- * Standard tool checked first: a `no-restricted-syntax` selector can match a
3
- * `render` property holding a `<Link>`, but not that the same object literal
4
- * also has a `label`, which is what tells a command (PageCommand, MenuCommand)
5
- * from any other object with a `render` field.
6
- */
7
- import { writtenName } from "./rendered-import.js";
8
-
9
- const ADDRESS_ELEMENTS = new Set(["a", "Link", "NextLink"]);
10
-
11
- const keyName = (property) => {
12
- if (property.type !== "Property" || property.computed) return null;
13
- return property.key.type === "Identifier" ? property.key.name : property.key.value;
14
- };
15
-
16
- const goesToAnAddress = (value) =>
17
- value.type === "JSXElement" && ADDRESS_ELEMENTS.has(writtenName(value.openingElement.name));
18
-
19
- export const pageCommandLinkNotRender = {
20
- meta: {
21
- type: "problem",
22
- docs: {
23
- description: "A command that goes to an address passes it as `link`, not as `render`.",
24
- },
25
- schema: [],
26
- messages: {
27
- "link-in-render":
28
- 'A command that goes to an address passes it as `link: <Link href="..." />`; `render` is only for an element that is itself a command, such as a component that renders a Button.',
29
- },
30
- },
31
- create(context) {
32
- return {
33
- ObjectExpression(node) {
34
- if (!node.properties.some((property) => keyName(property) === "label")) return;
35
- for (const property of node.properties) {
36
- if (keyName(property) === "render" && goesToAnAddress(property.value)) {
37
- context.report({ node: property.value, messageId: "link-in-render" });
38
- }
39
- }
40
- },
41
- };
42
- },
43
- };