@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,163 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { builtinModules } from "node:module";
3
- import { dirname, join, relative, sep } from "node:path";
4
-
5
- const DEPENDENCY_FIELDS = [
6
- "dependencies",
7
- "devDependencies",
8
- "peerDependencies",
9
- "optionalDependencies",
10
- ];
11
-
12
- const BUILTINS = new Set(builtinModules);
13
-
14
- export const DECLARED_DEPENDENCIES_SETTING = "nadicodeai/declared-dependencies";
15
-
16
- const manifests = new Map();
17
- const scopes = new Map();
18
-
19
- function readManifest(directory) {
20
- const path = join(directory, "package.json");
21
- return existsSync(path) ? JSON.parse(readFileSync(path, "utf8")) : undefined;
22
- }
23
-
24
- function manifestIn(directory) {
25
- if (!manifests.has(directory)) manifests.set(directory, readManifest(directory));
26
- return manifests.get(directory);
27
- }
28
-
29
- function declaredBy(manifest) {
30
- return new Set(DEPENDENCY_FIELDS.flatMap((field) => Object.keys(manifest[field] ?? {})));
31
- }
32
-
33
- function sortedNames(manifest) {
34
- return [...declaredBy(manifest)].sort();
35
- }
36
-
37
- export function declaredDependencies(rootDirectory) {
38
- const root = readManifest(rootDirectory);
39
- const workspaces = {};
40
- for (const path of [...workspacePaths(root)].sort()) {
41
- const manifest = readManifest(join(rootDirectory, path));
42
- if (manifest !== undefined) {
43
- workspaces[path] = { name: manifest.name, declared: sortedNames(manifest) };
44
- }
45
- }
46
- return { root: sortedNames(root), workspaces };
47
- }
48
-
49
- function workspacePaths(manifest) {
50
- const list = Array.isArray(manifest.workspaces)
51
- ? manifest.workspaces
52
- : (manifest.workspaces?.packages ?? []);
53
- return new Set(list.map((path) => path.replace(/\/$/, "")));
54
- }
55
-
56
- function computeScope(directory) {
57
- const candidates = [];
58
- for (let current = directory; ; current = dirname(current)) {
59
- const manifest = manifestIn(current);
60
- if (manifest?.workspaces !== undefined) {
61
- const listed = workspacePaths(manifest);
62
- const workspace = candidates.find((candidate) =>
63
- listed.has(relative(current, candidate).split(sep).join("/")),
64
- );
65
- if (workspace === undefined) return undefined;
66
- const own = manifestIn(workspace);
67
- const path = relative(current, workspace).split(sep).join("/");
68
- return {
69
- workspacePath: path,
70
- workspaceName: own.name ?? path,
71
- ownName: own.name,
72
- rootDeclared: declaredBy(manifest),
73
- workspaceDeclared: declaredBy(own),
74
- };
75
- }
76
- if (manifest !== undefined) candidates.push(current);
77
- if (dirname(current) === current) return undefined;
78
- }
79
- }
80
-
81
- function scopeOf(directory) {
82
- if (!scopes.has(directory)) scopes.set(directory, computeScope(directory));
83
- return scopes.get(directory);
84
- }
85
-
86
- function declaredNamesOf(scope, given) {
87
- const entry = given?.workspaces?.[scope.workspacePath];
88
- if (entry === undefined || !Array.isArray(given.root)) return scope;
89
- return {
90
- ownName: entry.name,
91
- workspaceName: entry.name ?? scope.workspacePath,
92
- rootDeclared: new Set(given.root),
93
- workspaceDeclared: new Set(entry.declared),
94
- };
95
- }
96
-
97
- function packageNameOf(specifier) {
98
- if (specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("node:")) {
99
- return undefined;
100
- }
101
- const [first, second = ""] = specifier.split("/");
102
- const name = first.startsWith("@") ? `${first}/${second}` : first;
103
- return BUILTINS.has(name) ? undefined : name;
104
- }
105
-
106
- function specifierOf(node) {
107
- // 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.
108
- return node?.type === "Literal" && typeof node.value === "string" ? node.value : undefined;
109
- }
110
-
111
- export const workspaceDeclaresImports = {
112
- meta: {
113
- type: "problem",
114
- docs: {
115
- description:
116
- "Require a workspace to declare each package it imports that the root package.json declares",
117
- },
118
- schema: [],
119
- messages: {
120
- undeclared:
121
- '"{{name}}" is declared by the root package.json but not by {{workspace}}. Declare it in the workspace that imports it, so a root bump is attributed to that workspace.',
122
- },
123
- },
124
- create(context) {
125
- const found = scopeOf(dirname(context.filename));
126
- if (found === undefined) return {};
127
- const scope = declaredNamesOf(found, context.settings[DECLARED_DEPENDENCIES_SETTING]);
128
-
129
- function check(source) {
130
- const specifier = specifierOf(source);
131
- if (specifier === undefined) return;
132
- const name = packageNameOf(specifier);
133
- if (
134
- name === undefined ||
135
- name === scope.ownName ||
136
- !scope.rootDeclared.has(name) ||
137
- scope.workspaceDeclared.has(name)
138
- ) {
139
- return;
140
- }
141
- context.report({
142
- node: source,
143
- messageId: "undeclared",
144
- data: { name, workspace: scope.workspaceName },
145
- });
146
- }
147
-
148
- return {
149
- ImportDeclaration: (node) => check(node.source),
150
- ExportNamedDeclaration: (node) => check(node.source),
151
- ExportAllDeclaration: (node) => check(node.source),
152
- ImportExpression: (node) => check(node.source),
153
- TSExternalModuleReference: (node) => check(node.expression),
154
- TSImportType: (node) =>
155
- check(node.argument?.type === "TSLiteralType" ? node.argument.literal : node.argument),
156
- CallExpression: (node) => {
157
- if (node.callee.type === "Identifier" && node.callee.name === "require") {
158
- check(node.arguments[0]);
159
- }
160
- },
161
- };
162
- },
163
- };
@@ -1,250 +0,0 @@
1
- import { createRequire } from "node:module";
2
-
3
- /*
4
- * The strict design-system checks, as selector lists for core
5
- * `no-restricted-syntax`. The plugin registers that core rule once per check,
6
- * under the check's own name, so each check keeps its `nadicodeai/<name>` id
7
- * and no two checks share one option list (flat config replaces a rule's
8
- * options rather than merging them).
9
- *
10
- * A class check reads the string literals inside a `className` attribute and a
11
- * `cva()` call, one class token at a time, variants included.
12
- */
13
-
14
- const theme = createRequire(import.meta.url)("@nadicodeai/design-system/tailwind").theme.extend;
15
- const escape = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
16
-
17
- /** Any variant chain: `md:`, `group-data-x/tabs:`, `has-[[data-slot=a]:focus]:`. */
18
- const VARIANTS = String.raw`(?:(?:[^\s:\[\]]|\[(?:[^\s\[\]]|\[[^\s\]]*\])*\])+:)*`;
19
- export const token = (body, variants = VARIANTS) =>
20
- String.raw`/(^|\s)${variants}!?(?:${body})!?(\s|$)/`;
21
- export const literal = (pattern) =>
22
- `:matches(Literal[value=${pattern}], TemplateElement[value.raw=${pattern}])`;
23
- const CLASS_SITES =
24
- ":matches(JSXAttribute[name.name='className'], Program:has(ImportDeclaration[source.value='class-variance-authority'] > ImportSpecifier[local.name='cva']) CallExpression[callee.name='cva'])";
25
- // A cva variant map's keys name variants, not classes.
26
- const classToken = (body, variants) =>
27
- `${CLASS_SITES} ${literal(token(body, variants))}:not(Property > .key)`;
28
- const ownClass = (body) =>
29
- `:has(> JSXOpeningElement:has(JSXAttribute[name.name='className'] ${literal(token(body))}))`;
30
-
31
- /** A component import from the package or the app may not be renamed: a check recognises it by its JSX name. */
32
- export const keepName = (names, checks = "design-system lint checks") =>
33
- names.map((name) => ({
34
- selector: `ImportDeclaration[source.value=/^(@nadicodeai\\/ui|@\\/components|\\.)/] > ImportSpecifier[imported.name='${name}'][local.name!='${name}']`,
35
- message: `Import ${name} under its own name: the ${checks} recognise it by that name.`,
36
- }));
37
-
38
- const OVERLAY_CONTENT = ["AlertDialogContent", "DialogContent", "DrawerContent", "SheetContent"];
39
- const OVERLAY_ROOTS = [
40
- "Dialog",
41
- "AlertDialog",
42
- "Drawer",
43
- "Sheet",
44
- "Popover",
45
- "DropdownMenu",
46
- "ContextMenu",
47
- "Tooltip",
48
- "HoverCard",
49
- "Combobox",
50
- "ActionMenu",
51
- ];
52
-
53
- const card = "JSXElement[openingElement.name.name=/^(Card|\\w*Card)$/]";
54
- const cardChild = `:matches(${card}, JSXExpressionContainer:has(> ${card}), JSXExpressionContainer:has(> :matches(ConditionalExpression, LogicalExpression):has(> ${card})))`;
55
- const mappedCards = `JSXExpressionContainer:has(> CallExpression[callee.property.name=/^(map|from)$/]:has(${card}))`;
56
-
57
- const bareControl =
58
- "JSXOpeningElement[name.name=/^(Button|button)$/]:not(:has(> JSXAttribute[name.name=/^aria-label(ledby)?$/])):not(:has(> JSXSpreadAttribute)):not(JSXAttribute[name.name='render'] JSXOpeningElement)";
59
- const onlyElements =
60
- ":not(:matches(JSXElement, JSXFragment, Literal[value=null], Literal[value=false], Identifier[name='undefined'], ConditionalExpression, LogicalExpression))";
61
- const rendersText = `:matches(JSXText[value=/\\S/], :matches(JSXElement, JSXFragment) > JSXExpressionContainer:not([expression.type=/^(JSXElement|JSXFragment|JSXEmptyExpression|ConditionalExpression|LogicalExpression)$/]), ConditionalExpression > ${onlyElements}:matches(.consequent, .alternate), LogicalExpression > ${onlyElements}.right)`;
62
- const elementChild =
63
- ":matches(JSXElement, JSXFragment, JSXExpressionContainer[expression.type=/^(JSXElement|JSXFragment|ConditionalExpression|LogicalExpression)$/])";
64
-
65
- const overlayRoot = `JSXOpeningElement[name.name=/Dialog|Drawer|Sheet|Popover|Menu|Tooltip|HoverCard|Combobox/]:not([name.name=/(Content|Trigger|Title|Description|Header|Footer|Body|Item|Group|Label|Separator|Close|Portal|Overlay|Backdrop)$/])`;
66
- const isTrue = ":matches([value=null], [value.expression.value=true])";
67
-
68
- const selectItem = "JSXElement[openingElement.name.name='SelectItem']";
69
- const nativeOption =
70
- "JSXElement[openingElement.name.name=/^(NativeSelectOption|option)$/]:has(> JSXOpeningElement:has(> JSXAttribute[name.name='value']:matches([value.value=/./], [value.expression.value=/./])))";
71
- const noExpressionChild =
72
- ":not(:has(> JSXExpressionContainer[expression.type!='JSXEmptyExpression']))";
73
- const fewItems = (parent, item) =>
74
- `${parent}:has(> ${item} ~ ${item}):not(:has(> ${item} ~ ${item} ~ ${item} ~ ${item}))${noExpressionChild}`;
75
- const fewOptions = (root, group, item) =>
76
- `JSXElement[openingElement.name.name='${root}']${noExpressionChild}:matches(${fewItems("JSXElement", item)}, :has(> ${fewItems(`JSXElement[openingElement.name.name=/^${group}$/]`, item)})) > JSXOpeningElement`;
77
- const fewFixedOptionsMessage =
78
- "Two or three fixed options are a SegmentedControl when they switch views of one surface, or a RadioGroup when they are a setting; a Select hides them until it opens.";
79
-
80
- const drawerSlot = "/^Drawer(Header|Body|Footer)$/";
81
- const drawerEdge = literal(token(String.raw`border(-[tby])?(-\d+)?`));
82
-
83
- const SPACING =
84
- "(?:p|px|py|pt|pr|pb|pl|ps|pe|m|mx|my|mt|mr|mb|ml|ms|me|gap|gap-x|gap-y|space-x|space-y|inset|inset-x|inset-y|top|right|bottom|left|start|end)";
85
- // The ladder rungs and the control geometry (seam, focus outline and offset, inline padding, touch target).
86
- const ON_GRID = String.raw`(?:0|1|2|4|8|10|12|16|24|32|40|44|48|64|96|128)(?:\.0+)?`;
87
-
88
- const typographyTokens = Object.keys(theme.fontSize).map(escape).join("|");
89
- const colorTokens = Object.keys(theme.colors).map(escape).join("|");
90
- const radiusValues = [...new Set(Object.values(theme.borderRadius))].map(escape).join("|");
91
- const radiusNames = Object.keys(theme.borderRadius).map(escape).join("|");
92
- const invalidTokenMessage =
93
- "This class is not generated by the installed nadicode design system. Use a utility from @nadicodeai/design-system/tailwind.";
94
-
95
- export const strictDesignSystemSelectors = {
96
- "card-row-owner": [
97
- {
98
- selector: `JSXElement:not([openingElement.name.name='CardRow']):matches(${ownClass(String.raw`grid-cols-(?!1(\s|$))\S+`)}, ${ownClass("flex-row")}, ${ownClass("flex")}:not(${ownClass("flex-col")})):matches(:has(> ${cardChild} ~ ${cardChild}), :has(> ${mappedCards})) > JSXOpeningElement`,
99
- message:
100
- "These cards are laid side by side without the owner of that row. An alignment class or a wrapper around a card is then enough for the shortest card to stop at its content and the row to end on a ragged edge. Use CardRow from @nadicodeai/ui, which stretches its cells and makes every card fill the one it lands in (rule/card-row-equal-height).",
101
- },
102
- ],
103
- "drawer-owns-its-edges": [
104
- ...keepName(["DrawerHeader", "DrawerBody", "DrawerFooter"]),
105
- {
106
- selector: `JSXOpeningElement[name.name=${drawerSlot}] > JSXAttribute[name.name='className'] ${drawerEdge}`,
107
- message:
108
- "This border gives a drawer slot a second edge. The drawer draws the hairline between its header, its body and its footer; drop the border class (rule/drawer-owns-its-edges).",
109
- },
110
- {
111
- selector: `JSXElement:has(> JSXElement[openingElement.name.name=${drawerSlot}]) > JSXOpeningElement > JSXAttribute[name.name='className'] ${drawerEdge}`,
112
- message:
113
- "This border draws an edge around a drawer slot. The drawer draws the hairline between its header, its body and its footer; render the slot without this wrapper (rule/drawer-owns-its-edges).",
114
- },
115
- ],
116
- "icon-control-accessible-name": [
117
- ...keepName(["Button"]),
118
- {
119
- selector: `JSXElement:not(:has(${rendersText})):matches(:has(> ${bareControl}:has(> JSXAttribute[name.name='size'][value.value=/^icon(-xs|-sm|-lg)?$/])), :has(> ${elementChild})) > ${bareControl}`,
120
- message:
121
- 'A screen reader announces "button" and nothing more for this control: its content is an icon, and an icon carries no name. Add aria-label with the action it performs, point aria-labelledby at the text that names it, or put that text in a child with the sr-only class.',
122
- },
123
- ],
124
- "no-invalid-token-utility": [
125
- {
126
- selector: classToken(`nc-type-(?!(?:${typographyTokens})(\\s|$))\\S*`),
127
- message: invalidTokenMessage,
128
- },
129
- {
130
- selector: classToken(
131
- `(?:bg|text|border|outline|ring|fill|stroke|decoration|accent|caret|divide|from|via|to|shadow)-nc-(?!(?:${colorTokens})(\\/\\S*)?(\\s|$))\\S+`,
132
- ),
133
- message: invalidTokenMessage,
134
- },
135
- ],
136
- "no-native-visible-control": [
137
- {
138
- selector:
139
- "JSXOpeningElement[name.name=/^(button|details|input|select|textarea)$/]:not([name.name='input']:has(> JSXAttribute[name.name='type']:matches([value.value='hidden'], [value.expression.value='hidden'], [value.expression.quasis.0.value.cooked='hidden']))):not(JSXOpeningElement > JSXAttribute[name.name='render'] > JSXExpressionContainer > JSXElement > JSXOpeningElement):not(Property[key.name='render'] > JSXElement > JSXOpeningElement)",
140
- message:
141
- "Use the @nadicodeai/ui primitive instead of a native visible control; a <details> takes Disclosure, which draws the one disclosure.",
142
- },
143
- ],
144
- "no-nested-overlay": [
145
- ...keepName(OVERLAY_CONTENT),
146
- {
147
- selector: `JSXElement[openingElement.name.name=/^(${OVERLAY_CONTENT.join("|")})$/] JSXElement[openingElement.name.name=/^(${OVERLAY_CONTENT.join("|")})$/] > JSXOpeningElement`,
148
- message:
149
- "This overlay is rendered inside another overlay. Two overlays on one tree keep both focus traps armed, so the keyboard cannot reach the outer surface and Escape closes the wrong layer, while the scrims stack. Render the second overlay as a sibling driven by state, or replace it with an inline disclosure inside the first.",
150
- },
151
- ],
152
- "no-off-grid-spacing": [
153
- {
154
- selector: classToken(String.raw`-?${SPACING}-\[-?(?!${ON_GRID}px\])\d+(?:\.\d+)?px\]`),
155
- message:
156
- "This pixel step sits off the design-system spacing ladder, so the rhythm reads as almost aligned and the value cannot follow the tokens. Use a rung: 0, nadicode-xxs (4px), nadicode-xs (8), nadicode-sm (12), nadicode-md (16), nadicode-lg (24), nadicode-xl (32), nadicode-2xl (40), nadicode-3xl (48), nadicode-4xl (64), nadicode-5xl (96), nadicode-6xl (128).",
157
- },
158
- ],
159
- "no-raw-shadow": [
160
- {
161
- selector: classToken(
162
- String.raw`shadow(?:-(?:2xs|xs|sm|md|lg|xl|2xl|inner|initial|\[\S*\]))?`,
163
- ),
164
- message:
165
- "A stock shadow paints a light-mode drop shadow with no ring, so the surface loses its edge against the dark workspace and cannot follow the tokens. Choose the physical level instead: nc-elevation-resting, nc-elevation-raised, nc-elevation-floating, or nc-elevation-modal.",
166
- },
167
- ],
168
- "no-repainted-focus": [
169
- {
170
- selector: classToken(
171
- String.raw`-?ring(?:-\S*)?`,
172
- String.raw`(?=\S*focus)${VARIANTS.slice(0, -1)}+`,
173
- ),
174
- message:
175
- "Focus never paints a box-shadow: the base layer draws the offset outline. Drop this ring utility.",
176
- },
177
- {
178
- selector: classToken(
179
- String.raw`\[outline\S*|outline(?!-(?:none|hidden|ring|sidebar-ring)(?:\s|$))(?!-offset-)(?:-\S*)?`,
180
- String.raw`(?=\S*focus)${VARIANTS.slice(0, -1)}+`,
181
- ),
182
- message:
183
- "This utility repaints focus with its own width or hue. The base layer owns the focus outline; a proxy target takes nc-focus-outline plus a ring-role color.",
184
- },
185
- ],
186
- "no-token-category-bypass": [
187
- {
188
- selector: classToken(
189
- String.raw`rounded(?:-(?:t|r|b|l|s|e|ss|se|ee|es|tl|tr|br|bl))?-\[\s*(?:${radiusValues}|var\(--(?:nc-rounded|radius)-(?:${radiusNames})\))\s*\]`,
190
- ),
191
- message:
192
- "This class spells a design-system radius by its value. Use the generated rounded-<token> utility the value belongs to.",
193
- },
194
- ],
195
- "overlay-body-owns-scroll": [
196
- ...keepName(["DialogContent", "DrawerContent"]),
197
- {
198
- selector: `JSXElement[openingElement.name.name=/^(DialogContent|DrawerContent)$/] JSXOpeningElement:not([name.name=/^(DialogContent|DrawerContent)$/]) > JSXAttribute[name.name='className'] ${literal(token("overflow-y-auto|overflow-y-scroll|overflow-auto"))}`,
199
- message:
200
- "This makes the element a second scroll container inside an overlay. The body slot owns an overlay's scroll, its shrinking and the inset that keeps focus outlines visible. Put the content in DialogBody or DrawerBody from @nadicodeai/ui and drop the overflow classes (rule/overlay-body-owns-scroll).",
201
- },
202
- ],
203
- "overlay-mounts-closed": [
204
- ...keepName(OVERLAY_ROOTS),
205
- {
206
- selector: `${overlayRoot} > JSXAttribute[name.name='open']${isTrue}`,
207
- message:
208
- "This overlay is given `open` fixed to true, so it only exists while open and neither its fade in nor its fade out runs. Keep it mounted and drive `open` from state.",
209
- },
210
- {
211
- selector: `${overlayRoot} > JSXAttribute[name.name='defaultOpen']${isTrue}`,
212
- message:
213
- "This overlay mounts open through `defaultOpen`, so its entry never runs. Mount it closed and open it from state.",
214
- },
215
- {
216
- selector: `${overlayRoot} > JSXAttribute[name.name='key'][value.type='JSXExpressionContainer']:not([value.expression.type='Literal']):not([value.expression.type='TemplateLiteral'][value.expression.expressions.length=0]):not(CallExpression[callee.property.name=/^(map|flatMap)$/] > :function JSXAttribute)`,
217
- message:
218
- "This overlay takes a `key` that remounts it, so an opening that changes the key mounts it already open and its fade in never runs. Keep one mounted overlay and reset its content another way, such as a key on the content inside it.",
219
- },
220
- ],
221
- "waiting-line-stays-mounted": [
222
- ...keepName(["WaitingLine"]),
223
- ...[
224
- "LogicalExpression > JSXElement[openingElement.name.name='WaitingLine']",
225
- "ConditionalExpression:not([alternate.type='JSXElement']) > JSXElement.consequent[openingElement.name.name='WaitingLine']",
226
- "ConditionalExpression:not([consequent.type='JSXElement']) > JSXElement.alternate[openingElement.name.name='WaitingLine']",
227
- ].map((selector) => ({
228
- selector,
229
- message:
230
- "This waiting line mounts with the wait, so its 2 px and its gap arrive with it and the layout moves. Keep it mounted with the control it waits for and pass `waiting`, or place it on its container's edge, out of the flow (rule/waiting-line-stays-mounted).",
231
- })),
232
- ],
233
- "prefer-radio-for-few-static-options": [
234
- ...keepName([
235
- "SelectContent",
236
- "SelectItem",
237
- "NativeSelect",
238
- "NativeSelectOption",
239
- "NativeSelectOptGroup",
240
- ]),
241
- {
242
- selector: fewOptions("SelectContent", "SelectGroup", selectItem),
243
- message: fewFixedOptionsMessage,
244
- },
245
- {
246
- selector: fewOptions("NativeSelect", "(NativeSelectOptGroup|optgroup)", nativeOption),
247
- message: fewFixedOptionsMessage,
248
- },
249
- ],
250
- };