@astryxdesign/core 0.1.6-canary.1b61ba6 → 0.1.6-canary.1d64659

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 (418) hide show
  1. package/README.md +0 -2
  2. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  3. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  4. package/dist/AlertDialog/AlertDialog.js +1 -4
  5. package/dist/AppShell/AppShell.d.ts.map +1 -1
  6. package/dist/AppShell/AppShell.js +1 -3
  7. package/dist/AvatarGroup/AvatarGroup.d.ts +1 -1
  8. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  9. package/dist/AvatarGroup/AvatarGroup.js +1 -4
  10. package/dist/Banner/Banner.d.ts.map +1 -1
  11. package/dist/Banner/Banner.js +6 -8
  12. package/dist/Breadcrumbs/Breadcrumbs.d.ts +1 -1
  13. package/dist/Breadcrumbs/Breadcrumbs.d.ts.map +1 -1
  14. package/dist/Breadcrumbs/Breadcrumbs.js +1 -4
  15. package/dist/Button/Button.d.ts.map +1 -1
  16. package/dist/Button/Button.js +4 -34
  17. package/dist/ButtonGroup/ButtonGroup.d.ts +5 -20
  18. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  19. package/dist/ButtonGroup/ButtonGroup.js +11 -27
  20. package/dist/Calendar/Calendar.d.ts.map +1 -1
  21. package/dist/Calendar/Calendar.js +5 -8
  22. package/dist/Carousel/Carousel.d.ts +1 -1
  23. package/dist/Carousel/Carousel.d.ts.map +1 -1
  24. package/dist/Carousel/Carousel.js +5 -8
  25. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  26. package/dist/Chat/ChatComposer.js +1 -4
  27. package/dist/Chat/ChatComposerDrawer.d.ts +1 -1
  28. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  29. package/dist/Chat/ChatComposerDrawer.js +2 -9
  30. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  31. package/dist/Chat/ChatComposerInput.js +2 -6
  32. package/dist/Chat/ChatLayout.d.ts +11 -1
  33. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  34. package/dist/Chat/ChatLayout.js +4 -6
  35. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  36. package/dist/Chat/ChatLayoutScrollButton.js +2 -4
  37. package/dist/Chat/ChatMessage.d.ts +1 -1
  38. package/dist/Chat/ChatMessage.d.ts.map +1 -1
  39. package/dist/Chat/ChatMessage.js +2 -8
  40. package/dist/Chat/ChatMessageBubble.d.ts +1 -1
  41. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  42. package/dist/Chat/ChatMessageBubble.js +1 -3
  43. package/dist/Chat/ChatMessageList.d.ts +1 -1
  44. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  45. package/dist/Chat/ChatMessageList.js +1 -3
  46. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  47. package/dist/Chat/ChatMessageMetadata.js +8 -13
  48. package/dist/Chat/ChatPastedTextToken.d.ts.map +1 -1
  49. package/dist/Chat/ChatPastedTextToken.js +1 -3
  50. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  51. package/dist/Chat/ChatSendButton.js +1 -3
  52. package/dist/Chat/index.d.ts +1 -1
  53. package/dist/Chat/index.d.ts.map +1 -1
  54. package/dist/Chat/useChatStreamScroll.d.ts +1 -12
  55. package/dist/Chat/useChatStreamScroll.d.ts.map +1 -1
  56. package/dist/Chat/useChatStreamScroll.js +6 -43
  57. package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
  58. package/dist/Chat/useSpeechRecognition.js +2 -4
  59. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  60. package/dist/Chat/useTriggerMenu.js +2 -4
  61. package/dist/CheckboxList/CheckboxList.d.ts +1 -1
  62. package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
  63. package/dist/CheckboxList/CheckboxList.js +1 -3
  64. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  65. package/dist/CheckboxList/CheckboxListItem.js +1 -3
  66. package/dist/Citation/Citation.d.ts.map +1 -1
  67. package/dist/Citation/Citation.js +2 -10
  68. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  69. package/dist/CodeBlock/CodeBlock.js +2 -4
  70. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  71. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  72. package/dist/CommandPalette/CommandPalette.js +3 -8
  73. package/dist/CommandPalette/CommandPaletteInput.d.ts +1 -1
  74. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  75. package/dist/CommandPalette/CommandPaletteInput.js +1 -4
  76. package/dist/CommandPalette/CommandPaletteList.d.ts +1 -1
  77. package/dist/CommandPalette/CommandPaletteList.d.ts.map +1 -1
  78. package/dist/CommandPalette/CommandPaletteList.js +1 -4
  79. package/dist/ContextMenu/ContextMenu.d.ts +1 -1
  80. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  81. package/dist/ContextMenu/ContextMenu.js +1 -4
  82. package/dist/DateInput/DateInput.d.ts +1 -1
  83. package/dist/DateInput/DateInput.d.ts.map +1 -1
  84. package/dist/DateInput/DateInput.js +5 -10
  85. package/dist/DateRangeInput/DateRangeInput.d.ts +1 -1
  86. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  87. package/dist/DateRangeInput/DateRangeInput.js +6 -11
  88. package/dist/DateTimeInput/DateTimeInput.d.ts +1 -1
  89. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  90. package/dist/DateTimeInput/DateTimeInput.js +7 -15
  91. package/dist/Dialog/Dialog.d.ts.map +1 -1
  92. package/dist/Dialog/Dialog.js +12 -15
  93. package/dist/Dialog/DialogHeader.d.ts +1 -1
  94. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  95. package/dist/Dialog/DialogHeader.js +3 -7
  96. package/dist/DropdownMenu/DropdownMenu.d.ts +1 -1
  97. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  98. package/dist/DropdownMenu/DropdownMenu.js +5 -11
  99. package/dist/FileInput/FileInput.d.ts.map +1 -1
  100. package/dist/FileInput/FileInput.js +1 -11
  101. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  102. package/dist/Lightbox/Lightbox.js +4 -6
  103. package/dist/Link/Link.d.ts +1 -1
  104. package/dist/Link/Link.d.ts.map +1 -1
  105. package/dist/Link/Link.js +1 -4
  106. package/dist/Markdown/Markdown.d.ts.map +1 -1
  107. package/dist/Markdown/Markdown.js +8 -10
  108. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  109. package/dist/MobileNav/MobileNav.js +2 -4
  110. package/dist/MobileNav/MobileNavToggle.d.ts +1 -1
  111. package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
  112. package/dist/MobileNav/MobileNavToggle.js +1 -4
  113. package/dist/MoreMenu/MoreMenu.d.ts +1 -1
  114. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  115. package/dist/MoreMenu/MoreMenu.js +1 -4
  116. package/dist/MultiSelector/MultiSelector.d.ts +1 -1
  117. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  118. package/dist/MultiSelector/MultiSelector.js +6 -13
  119. package/dist/NavItem/index.d.ts +9 -0
  120. package/dist/NavItem/index.d.ts.map +1 -0
  121. package/dist/NavItem/index.js +10 -0
  122. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  123. package/dist/NumberInput/NumberInput.js +1 -5
  124. package/dist/Outline/Outline.d.ts +1 -1
  125. package/dist/Outline/Outline.d.ts.map +1 -1
  126. package/dist/Outline/Outline.js +1 -4
  127. package/dist/Pagination/Pagination.d.ts +1 -1
  128. package/dist/Pagination/Pagination.d.ts.map +1 -1
  129. package/dist/Pagination/Pagination.js +11 -38
  130. package/dist/Popover/usePopover.d.ts.map +1 -1
  131. package/dist/Popover/usePopover.js +1 -4
  132. package/dist/PowerSearch/PowerSearch.d.ts +1 -1
  133. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  134. package/dist/PowerSearch/PowerSearch.js +12 -22
  135. package/dist/PowerSearch/PowerSearchEditPopover.d.ts +1 -1
  136. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  137. package/dist/PowerSearch/PowerSearchEditPopover.js +20 -26
  138. package/dist/PowerSearch/PowerSearchToken.d.ts.map +1 -1
  139. package/dist/PowerSearch/PowerSearchToken.js +3 -7
  140. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  141. package/dist/PowerSearch/PowerSearchValueEditor.js +21 -34
  142. package/dist/PowerSearch/formatFilterValue.d.ts +1 -2
  143. package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
  144. package/dist/PowerSearch/formatFilterValue.js +9 -19
  145. package/dist/PowerSearch/index.d.ts +1 -2
  146. package/dist/PowerSearch/index.d.ts.map +1 -1
  147. package/dist/PowerSearch/index.js +0 -1
  148. package/dist/PowerSearch/types.d.ts +2 -28
  149. package/dist/PowerSearch/types.d.ts.map +1 -1
  150. package/dist/PowerSearch/usePowerSearchConfig.d.ts.map +1 -1
  151. package/dist/PowerSearch/usePowerSearchConfig.js +27 -27
  152. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  153. package/dist/PowerSearch/usePowerSearchSource.js +8 -15
  154. package/dist/Resizable/ResizeHandle.d.ts +1 -1
  155. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  156. package/dist/Resizable/ResizeHandle.js +1 -4
  157. package/dist/Selector/Selector.d.ts.map +1 -1
  158. package/dist/Selector/Selector.js +5 -11
  159. package/dist/SideNav/SideNav.d.ts.map +1 -1
  160. package/dist/SideNav/SideNav.js +2 -4
  161. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  162. package/dist/SideNav/SideNavCollapseButton.js +1 -3
  163. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  164. package/dist/SideNav/SideNavHeading.js +3 -5
  165. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  166. package/dist/SideNav/SideNavItem.js +1 -7
  167. package/dist/TabList/TabList.d.ts +1 -1
  168. package/dist/TabList/TabList.d.ts.map +1 -1
  169. package/dist/TabList/TabList.js +1 -4
  170. package/dist/Table/BaseTable.d.ts.map +1 -1
  171. package/dist/Table/BaseTable.js +16 -29
  172. package/dist/Table/Table.d.ts.map +1 -1
  173. package/dist/Table/Table.js +3 -5
  174. package/dist/Table/plugins/columnResize/useTableColumnResize.js +1 -1
  175. package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
  176. package/dist/Table/plugins/filtering/useTableFiltering.js +19 -56
  177. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  178. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +4 -11
  179. package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
  180. package/dist/Table/plugins/pagination/useTablePagination.js +3 -6
  181. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  182. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +6 -8
  183. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  184. package/dist/Table/plugins/selection/useTableSelection.js +2 -5
  185. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  186. package/dist/Table/plugins/sortable/useTableSortable.js +4 -6
  187. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +2 -2
  188. package/dist/Table/types.d.ts +10 -17
  189. package/dist/Table/types.d.ts.map +1 -1
  190. package/dist/TextInput/TextInput.d.ts.map +1 -1
  191. package/dist/TextInput/TextInput.js +1 -5
  192. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  193. package/dist/Thumbnail/Thumbnail.js +2 -8
  194. package/dist/TimeInput/TimeInput.d.ts +1 -1
  195. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  196. package/dist/TimeInput/TimeInput.js +2 -7
  197. package/dist/Toast/Toast.d.ts.map +1 -1
  198. package/dist/Toast/Toast.js +1 -3
  199. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  200. package/dist/Toast/ToastViewport.js +1 -3
  201. package/dist/Token/Token.d.ts.map +1 -1
  202. package/dist/Token/Token.js +2 -8
  203. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  204. package/dist/Tokenizer/Tokenizer.js +1 -3
  205. package/dist/TopNav/TopNav.d.ts +1 -1
  206. package/dist/TopNav/TopNav.d.ts.map +1 -1
  207. package/dist/TopNav/TopNav.js +1 -4
  208. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  209. package/dist/TopNav/TopNavHeading.js +3 -5
  210. package/dist/TreeList/TreeList.d.ts.map +1 -1
  211. package/dist/TreeList/TreeList.js +1 -5
  212. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  213. package/dist/TreeList/TreeListItem.js +1 -7
  214. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  215. package/dist/Typeahead/BaseTypeahead.js +4 -8
  216. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  217. package/dist/Typeahead/Typeahead.js +1 -3
  218. package/dist/VisuallyHidden/VisuallyHidden.d.ts +0 -1
  219. package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -1
  220. package/dist/VisuallyHidden/VisuallyHidden.js +0 -1
  221. package/dist/astryx.css +1 -3
  222. package/dist/astryx.umd.js +60 -62
  223. package/dist/astryx.umd.js.map +4 -4
  224. package/dist/index.d.ts +0 -1
  225. package/dist/index.d.ts.map +1 -1
  226. package/dist/index.js +0 -3
  227. package/package.json +2 -23
  228. package/src/AlertDialog/AlertDialog.tsx +1 -4
  229. package/src/AppShell/AppShell.doc.mjs +2 -8
  230. package/src/AppShell/AppShell.tsx +1 -3
  231. package/src/AvatarGroup/AvatarGroup.tsx +1 -4
  232. package/src/Banner/Banner.tsx +5 -10
  233. package/src/Breadcrumbs/Breadcrumbs.tsx +1 -4
  234. package/src/Button/Button.tsx +4 -34
  235. package/src/ButtonGroup/ButtonGroup.test.tsx +2 -386
  236. package/src/ButtonGroup/ButtonGroup.tsx +11 -27
  237. package/src/Calendar/Calendar.tsx +5 -8
  238. package/src/Card/Card.doc.mjs +3 -3
  239. package/src/Carousel/Carousel.tsx +7 -10
  240. package/src/Chat/ChatComposer.tsx +1 -5
  241. package/src/Chat/ChatComposerDrawer.tsx +2 -9
  242. package/src/Chat/ChatComposerInput.tsx +4 -10
  243. package/src/Chat/ChatLayout.test.tsx +2 -127
  244. package/src/Chat/ChatLayout.tsx +12 -5
  245. package/src/Chat/ChatLayoutScrollButton.tsx +2 -4
  246. package/src/Chat/ChatMessage.tsx +1 -5
  247. package/src/Chat/ChatMessageBubble.tsx +0 -2
  248. package/src/Chat/ChatMessageList.doc.mjs +1 -1
  249. package/src/Chat/ChatMessageList.tsx +0 -2
  250. package/src/Chat/ChatMessageMetadata.tsx +9 -15
  251. package/src/Chat/ChatPastedTextToken.tsx +1 -3
  252. package/src/Chat/ChatSendButton.tsx +1 -3
  253. package/src/Chat/ChatToolCalls.doc.mjs +1 -1
  254. package/src/Chat/index.ts +0 -1
  255. package/src/Chat/useChatStreamScroll.ts +11 -67
  256. package/src/Chat/useSpeechRecognition.ts +2 -11
  257. package/src/Chat/useTriggerMenu.tsx +2 -4
  258. package/src/CheckboxList/CheckboxList.doc.mjs +1 -1
  259. package/src/CheckboxList/CheckboxList.tsx +0 -2
  260. package/src/CheckboxList/CheckboxListItem.tsx +1 -7
  261. package/src/Citation/Citation.tsx +2 -4
  262. package/src/ClickableCard/ClickableCard.doc.mjs +1 -1
  263. package/src/CodeBlock/CodeBlock.tsx +2 -4
  264. package/src/CommandPalette/CommandPalette.tsx +3 -10
  265. package/src/CommandPalette/CommandPaletteInput.test.tsx +1 -1
  266. package/src/CommandPalette/CommandPaletteInput.tsx +1 -5
  267. package/src/CommandPalette/CommandPaletteList.tsx +1 -4
  268. package/src/ContextMenu/ContextMenu.tsx +1 -4
  269. package/src/DateInput/DateInput.doc.mjs +2 -2
  270. package/src/DateInput/DateInput.tsx +5 -13
  271. package/src/DateRangeInput/DateRangeInput.doc.mjs +1 -1
  272. package/src/DateRangeInput/DateRangeInput.tsx +6 -14
  273. package/src/DateTimeInput/DateTimeInput.doc.mjs +2 -2
  274. package/src/DateTimeInput/DateTimeInput.tsx +7 -17
  275. package/src/Dialog/Dialog.tsx +15 -11
  276. package/src/Dialog/DialogHeader.tsx +3 -7
  277. package/src/DropdownMenu/DropdownMenu.tsx +8 -12
  278. package/src/Field/Field.doc.mjs +2 -2
  279. package/src/FileInput/FileInput.test.tsx +1 -40
  280. package/src/FileInput/FileInput.tsx +1 -12
  281. package/src/Grid/Grid.doc.mjs +5 -5
  282. package/src/InputGroup/InputGroup.doc.mjs +1 -1
  283. package/src/Lightbox/Lightbox.doc.mjs +2 -7
  284. package/src/Lightbox/Lightbox.tsx +4 -6
  285. package/src/Link/Link.tsx +1 -4
  286. package/src/Markdown/Markdown.tsx +4 -12
  287. package/src/MobileNav/MobileNav.tsx +2 -4
  288. package/src/MobileNav/MobileNavToggle.tsx +3 -5
  289. package/src/MoreMenu/MoreMenu.tsx +1 -4
  290. package/src/MultiSelector/MultiSelector.tsx +5 -14
  291. package/src/NavItem/index.ts +11 -0
  292. package/src/NumberInput/NumberInput.tsx +1 -3
  293. package/src/Outline/Outline.tsx +1 -4
  294. package/src/OverflowList/OverflowList.doc.mjs +2 -2
  295. package/src/Pagination/Pagination.tsx +12 -35
  296. package/src/Popover/usePopover.tsx +1 -6
  297. package/src/PowerSearch/PowerSearch.doc.mjs +4 -4
  298. package/src/PowerSearch/PowerSearch.tsx +10 -22
  299. package/src/PowerSearch/PowerSearchEditPopover.tsx +20 -27
  300. package/src/PowerSearch/PowerSearchToken.tsx +6 -17
  301. package/src/PowerSearch/PowerSearchValueEditor.tsx +21 -34
  302. package/src/PowerSearch/formatFilterValue.ts +8 -21
  303. package/src/PowerSearch/index.ts +0 -5
  304. package/src/PowerSearch/types.ts +9 -33
  305. package/src/PowerSearch/usePowerSearchConfig.ts +27 -59
  306. package/src/PowerSearch/usePowerSearchSource.ts +8 -17
  307. package/src/RadioList/RadioList.doc.mjs +1 -1
  308. package/src/Resizable/ResizeHandle.tsx +1 -4
  309. package/src/Section/Section.doc.mjs +4 -4
  310. package/src/SelectableCard/SelectableCard.doc.mjs +1 -1
  311. package/src/Selector/Selector.tsx +6 -11
  312. package/src/SideNav/SideNav.tsx +2 -4
  313. package/src/SideNav/SideNavCollapseButton.tsx +1 -3
  314. package/src/SideNav/SideNavHeading.tsx +3 -5
  315. package/src/SideNav/SideNavItem.tsx +1 -3
  316. package/src/Slider/Slider.doc.mjs +2 -2
  317. package/src/Stack/Stack.doc.mjs +10 -10
  318. package/src/Switch/Switch.doc.mjs +2 -2
  319. package/src/TabList/TabList.tsx +1 -4
  320. package/src/Table/BaseTable.tsx +19 -36
  321. package/src/Table/Table.test.tsx +1 -132
  322. package/src/Table/Table.tsx +4 -6
  323. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +1 -1
  324. package/src/Table/plugins/filtering/useTableFiltering.tsx +30 -31
  325. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +4 -6
  326. package/src/Table/plugins/pagination/useTablePagination.tsx +1 -4
  327. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +8 -9
  328. package/src/Table/plugins/selection/useTableSelection.tsx +7 -6
  329. package/src/Table/plugins/sortable/useTableSortable.tsx +5 -8
  330. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +4 -4
  331. package/src/Table/types.ts +12 -18
  332. package/src/Table/useTableFiltering.doc.mjs +2 -2
  333. package/src/Table/useTableSortable.doc.mjs +11 -11
  334. package/src/Text/Text.doc.mjs +2 -2
  335. package/src/TextInput/TextInput.tsx +1 -3
  336. package/src/Thumbnail/Thumbnail.tsx +2 -4
  337. package/src/TimeInput/TimeInput.doc.mjs +2 -2
  338. package/src/TimeInput/TimeInput.tsx +2 -6
  339. package/src/Timestamp/Timestamp.doc.mjs +4 -4
  340. package/src/Toast/Toast.tsx +1 -3
  341. package/src/Toast/ToastViewport.tsx +1 -3
  342. package/src/Token/Token.tsx +2 -4
  343. package/src/Tokenizer/Tokenizer.doc.mjs +2 -2
  344. package/src/Tokenizer/Tokenizer.tsx +4 -4
  345. package/src/Toolbar/Toolbar.doc.mjs +1 -1
  346. package/src/TopNav/TopNav.tsx +1 -4
  347. package/src/TopNav/TopNavHeading.tsx +3 -5
  348. package/src/TreeList/TreeList.tsx +1 -5
  349. package/src/TreeList/TreeListItem.tsx +1 -6
  350. package/src/Typeahead/BaseTypeahead.tsx +4 -11
  351. package/src/Typeahead/Typeahead.doc.mjs +1 -1
  352. package/src/Typeahead/Typeahead.tsx +1 -3
  353. package/src/VisuallyHidden/VisuallyHidden.tsx +0 -1
  354. package/src/index.ts +0 -3
  355. package/dist/PowerSearch/resolveOperatorLabel.d.ts +0 -23
  356. package/dist/PowerSearch/resolveOperatorLabel.d.ts.map +0 -1
  357. package/dist/PowerSearch/resolveOperatorLabel.js +0 -28
  358. package/dist/authoring/doc.d.ts +0 -145
  359. package/dist/authoring/doc.d.ts.map +0 -1
  360. package/dist/authoring/doc.js +0 -100
  361. package/dist/authoring/index.d.ts +0 -29
  362. package/dist/authoring/index.d.ts.map +0 -1
  363. package/dist/authoring/index.js +0 -28
  364. package/dist/authoring/integration.d.ts +0 -35
  365. package/dist/authoring/integration.d.ts.map +0 -1
  366. package/dist/authoring/integration.js +0 -30
  367. package/dist/authoring/template.d.ts +0 -66
  368. package/dist/authoring/template.d.ts.map +0 -1
  369. package/dist/authoring/template.js +0 -55
  370. package/dist/config.d.ts +0 -80
  371. package/dist/config.d.ts.map +0 -1
  372. package/dist/config.js +0 -40
  373. package/dist/i18n/InternationalizationContext.d.ts +0 -12
  374. package/dist/i18n/InternationalizationContext.d.ts.map +0 -1
  375. package/dist/i18n/InternationalizationContext.js +0 -29
  376. package/dist/i18n/InternationalizationProvider.d.ts +0 -62
  377. package/dist/i18n/InternationalizationProvider.d.ts.map +0 -1
  378. package/dist/i18n/InternationalizationProvider.js +0 -44
  379. package/dist/i18n/index.d.ts +0 -24
  380. package/dist/i18n/index.d.ts.map +0 -1
  381. package/dist/i18n/index.js +0 -21
  382. package/dist/i18n/resolve.d.ts +0 -22
  383. package/dist/i18n/resolve.d.ts.map +0 -1
  384. package/dist/i18n/resolve.js +0 -141
  385. package/dist/i18n/translator.d.ts +0 -25
  386. package/dist/i18n/translator.d.ts.map +0 -1
  387. package/dist/i18n/translator.js +0 -1
  388. package/dist/i18n/types.d.ts +0 -47
  389. package/dist/i18n/types.d.ts.map +0 -1
  390. package/dist/i18n/types.js +0 -1
  391. package/dist/i18n/useTranslator.d.ts +0 -15
  392. package/dist/i18n/useTranslator.d.ts.map +0 -1
  393. package/dist/i18n/useTranslator.js +0 -39
  394. package/locales/en.json +0 -746
  395. package/locales/pseudo.json +0 -560
  396. package/src/Chat/useChatStreamScroll.test.tsx +0 -168
  397. package/src/PowerSearch/formatFilterValue.test.ts +0 -282
  398. package/src/PowerSearch/resolveOperatorLabel.ts +0 -34
  399. package/src/authoring/doc.ts +0 -166
  400. package/src/authoring/index.test.ts +0 -52
  401. package/src/authoring/index.ts +0 -50
  402. package/src/authoring/integration.ts +0 -42
  403. package/src/authoring/template.ts +0 -74
  404. package/src/config.test.ts +0 -16
  405. package/src/config.ts +0 -92
  406. package/src/docPropLiterals.test.ts +0 -938
  407. package/src/i18n/InternationalizationContext.ts +0 -39
  408. package/src/i18n/InternationalizationProvider.doc.mjs +0 -72
  409. package/src/i18n/InternationalizationProvider.tsx +0 -83
  410. package/src/i18n/__tests__/e2e-pagination.test.tsx +0 -172
  411. package/src/i18n/__tests__/e2e-powersearch.test.tsx +0 -130
  412. package/src/i18n/__tests__/resolve.test.ts +0 -284
  413. package/src/i18n/index.ts +0 -32
  414. package/src/i18n/resolve.ts +0 -165
  415. package/src/i18n/translator.ts +0 -31
  416. package/src/i18n/types.ts +0 -53
  417. package/src/i18n/useTranslator.doc.mjs +0 -46
  418. package/src/i18n/useTranslator.ts +0 -50
@@ -1,938 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- /* eslint-disable @typescript-eslint/no-require-imports */
4
- /**
5
- * @file Guards doc prop types against opaque named unions (#1645).
6
- * @input Every {Name}.doc.mjs plus the TypeScript sources they describe.
7
- * @output Fails when a documented prop type hides its legal literal values.
8
- * @position Repo-wide doc-shape guard, sibling of docPropReferences.test.ts.
9
- *
10
- * A prop type of `SpacingStep` or `TableSortState<TSortKey>` names a type
11
- * without revealing what may be written into it. Readers without an IDE —
12
- * agents especially — then guess: `gap={16}` (pixels, not a scale step),
13
- * `direction: 'desc'` (the type says `'descending'`). Both fail to compile.
14
- * `PropDoc.type` in docs-types.ts already asks for inlined unions
15
- * (`"'primary' | 'secondary' | 'ghost'"`); this test holds docs to it.
16
- *
17
- * Two ways a doc prop can hide values, checked at different strictness:
18
- *
19
- * 1. DIRECT — the prop type *is* (or contains) a literal-union type name.
20
- * `gap: SpacingStep` must read `gap: 0 | 0.5 | 1 | …`. The name never
21
- * buys the reader anything the literals don't, so inlining is required;
22
- * prose is not an escape (see ENUMERATED_IN_PROSE for the one exception).
23
- *
24
- * 2. INDIRECT — the prop type names a composite whose own definition
25
- * carries a literal union: `status: InputStatus` hides
26
- * `'warning' | 'error' | 'success'`, `sort: TableSortState` hides
27
- * `direction: 'ascending' | 'descending'`. Here the values may be
28
- * surfaced in the type (spell the shape out — preferred when the object
29
- * is small) *or* in the description, because forcing a twelve-field
30
- * object into the type column would make the docs worse, not better.
31
- *
32
- * Both registries are derived from the TypeScript sources at test time, so a
33
- * new member on a union (or a renamed one) fails here until docs catch up.
34
- */
35
-
36
- import {describe, it, expect} from 'vitest';
37
- import {readdirSync, readFileSync} from 'node:fs';
38
- import {join, relative} from 'node:path';
39
-
40
- const SRC_DIR = __dirname;
41
-
42
- type DocExport = {
43
- name?: string;
44
- props?: PropEntry[];
45
- components?: {name?: string; props?: PropEntry[]}[];
46
- };
47
-
48
- type DocModule = {
49
- docs?: DocExport;
50
- docsZh?: DocExport;
51
- };
52
-
53
- type PropEntry = {name: string; type?: string; description?: string};
54
-
55
- /**
56
- * Unions too large to read inside a prop-type cell. Exempt from inlining,
57
- * but only while the prop's description enumerates every member — the
58
- * values still have to be discoverable from the docs alone.
59
- */
60
- const ENUMERATED_IN_PROSE = new Set(['IconName']);
61
-
62
- /**
63
- * Generic wrappers whose type argument is still a value the consumer writes,
64
- * so the walk descends through them. Every other generic (`ReactElement<P>`,
65
- * `Record<K, V>`, `Ref<T>`) wraps a type the consumer never spells out by
66
- * hand, and descending into it would demand, say, all 26 icon names in
67
- * Button's `endContent` docs.
68
- */
69
- const TRANSPARENT_WRAPPERS = new Set(['Array', 'ReadonlyArray']);
70
-
71
- /**
72
- * A union of nothing but string/number literals (plus null/undefined).
73
- *
74
- * Built so each separator has exactly ONE way to be parsed. The obvious
75
- * spelling — `(?:\s*\|?\s*LITERAL\s*(?:\|\s*)?)+` — lets a repetition's
76
- * trailing `(?:\|\s*)?` and the next one's leading `\|?` both claim the same
77
- * pipe, so every separator doubles the parse tree. On a union that *fails* to
78
- * match (a literal prefix ending in a named type, e.g. `'a' | 'b' | … |
79
- * ComponentType` — an ordinary TS pattern) the engine explores all 2^n of them:
80
- * measured at 1.2s for 10 members and 7.8s for 12. This form is linear, and
81
- * agrees with the old one on every type alias in the package.
82
- */
83
- const LITERAL = String.raw`(?:'[^']*'|-?\d+(?:\.\d+)?|null|undefined)`;
84
- const LITERAL_UNION = new RegExp(
85
- String.raw`^\s*\|?\s*${LITERAL}(?:\s*\|\s*${LITERAL})*\s*$`,
86
- );
87
-
88
- function findFiles(dir: string, suffixes: string[]): string[] {
89
- const out: string[] = [];
90
- for (const entry of readdirSync(dir, {withFileTypes: true})) {
91
- const full = join(dir, entry.name);
92
- if (entry.isDirectory()) {
93
- out.push(...findFiles(full, suffixes));
94
- } else if (suffixes.some(s => entry.name.endsWith(s))) {
95
- out.push(full);
96
- }
97
- }
98
- return out;
99
- }
100
-
101
- /** Strip comments so a doc block's prose never reads as type syntax. */
102
- function stripComments(src: string): string {
103
- return src.replace(/\/\*[\s\S]*?\*\//g, '').replace(/\/\/.*$/gm, '');
104
- }
105
-
106
- /**
107
- * Literal members of a union flagged `@deprecated` in source. Docs shouldn't
108
- * advertise a deprecated value as a legal option (the prose can still mention
109
- * it), so the guard doesn't require it to be inlined. Detected from the *raw*
110
- * declaration, because the registry parses members from comment-stripped
111
- * source where the `@deprecated` marker is already gone. A member is
112
- * deprecated when a `@deprecated` JSDoc or line comment immediately precedes
113
- * it in the union — e.g. a member `'c'` written just after a
114
- * `@deprecated`-tagged block comment is treated as deprecated and dropped,
115
- * while undecorated members like `'a'` and `'b'` are kept.
116
- */
117
- function deprecatedLiteralMembers(rawRhs: string): Set<string> {
118
- const out = new Set<string>();
119
- const marker =
120
- /(?:\/\*\*?[\s\S]*?@deprecated[\s\S]*?\*\/|\/\/[^\n]*@deprecated[^\n]*)\s*\|\s*('[^']*'|-?\d+(?:\.\d+)?|null|undefined)/g;
121
- for (const m of rawRhs.matchAll(marker)) {
122
- out.add(m[1]);
123
- }
124
- return out;
125
- }
126
-
127
- /**
128
- * Names a consumer would have to write values for, given a type expression.
129
- * Skips string literals, generic parameters, and the type arguments of any
130
- * wrapper that isn't transparent.
131
- */
132
- function authoredTypeNames(expr: string): string[] {
133
- const names: string[] = [];
134
- const text = expr.replace(/'[^']*'/g, "''");
135
- let i = 0;
136
- while (i < text.length) {
137
- const match = /[A-Za-z_$][A-Za-z0-9_$]*/.exec(text.slice(i));
138
- if (!match) {
139
- break;
140
- }
141
- const start = i + match.index;
142
- const name = match[0];
143
- let end = start + name.length;
144
- if (/^[A-Z]/.test(name)) {
145
- names.push(name);
146
- }
147
- // A '<' directly after the name opens that name's type arguments.
148
- const rest = text.slice(end);
149
- const open = /^\s*</.exec(rest);
150
- if (open) {
151
- let depth = 0;
152
- let j = end + open[0].length - 1;
153
- for (; j < text.length; j++) {
154
- if (text[j] === '<') {
155
- depth++;
156
- } else if (text[j] === '>') {
157
- depth--;
158
- if (depth === 0) {
159
- break;
160
- }
161
- }
162
- }
163
- const args = text.slice(end + open[0].length, j);
164
- if (TRANSPARENT_WRAPPERS.has(name)) {
165
- names.push(...authoredTypeNames(args));
166
- }
167
- end = j + 1;
168
- }
169
- i = end;
170
- }
171
- return names;
172
- }
173
-
174
- // --- Registries, read straight from the TypeScript sources -----------------
175
-
176
- /** Literal-union type name → its members, e.g. "'start' | 'center'". */
177
- const literalUnions = new Map<string, string>();
178
- /** Every other exported type/interface name → its definition body. */
179
- const namedBodies = new Map<string, string>();
180
-
181
- for (const file of findFiles(SRC_DIR, ['.ts', '.tsx'])) {
182
- if (file.includes('.test.')) {
183
- continue;
184
- }
185
- const raw = readFileSync(file, 'utf8');
186
- const src = stripComments(raw);
187
- // Raw type declarations, keyed by name, so we can inspect `@deprecated`
188
- // markers the comment-stripped `src` has already removed.
189
- const rawTypeRhs = new Map<string, string>();
190
- for (const m of raw.matchAll(
191
- /export type ([A-Z][A-Za-z0-9]*)(?:<[^>]*>)?\s*=\s*([^;]+);/g,
192
- )) {
193
- rawTypeRhs.set(m[1], m[2]);
194
- }
195
- for (const m of src.matchAll(
196
- /export type ([A-Z][A-Za-z0-9]*)(?:<[^>]*>)?\s*=\s*([^;]+);/g,
197
- )) {
198
- const [, name, rhsRaw] = m;
199
- const rhs = rhsRaw.replace(/\s+/g, ' ').trim();
200
- if (LITERAL_UNION.test(rhs)) {
201
- const deprecated = deprecatedLiteralMembers(rawTypeRhs.get(name) ?? '');
202
- literalUnions.set(
203
- name,
204
- rhs
205
- .replace(/^\|\s*/, '')
206
- .split('|')
207
- .map(s => s.trim())
208
- .filter(Boolean)
209
- .filter(member => !deprecated.has(member))
210
- .join(' | '),
211
- );
212
- } else {
213
- namedBodies.set(name, rhs);
214
- }
215
- }
216
- for (const m of src.matchAll(
217
- /export interface ([A-Z][A-Za-z0-9]*)(?:<[^>]*>)?\s*(?:extends [^{]+)?\{/g,
218
- )) {
219
- const open = src.indexOf('{', m.index);
220
- let depth = 0;
221
- let close = open;
222
- for (; close < src.length; close++) {
223
- if (src[close] === '{') {
224
- depth++;
225
- } else if (src[close] === '}') {
226
- depth--;
227
- if (depth === 0) {
228
- break;
229
- }
230
- }
231
- }
232
- namedBodies.set(m[1], src.slice(open, close + 1).replace(/\s+/g, ' '));
233
- }
234
- }
235
-
236
- /** Literal unions a consumer must know to author a value of `name`. */
237
- function requiredUnions(
238
- name: string,
239
- seen = new Set<string>(),
240
- ): Map<string, string> {
241
- const found = new Map<string, string>();
242
- if (seen.has(name)) {
243
- return found;
244
- }
245
- seen.add(name);
246
- const literals = literalUnions.get(name);
247
- if (literals) {
248
- found.set(name, literals);
249
- return found;
250
- }
251
- const body = namedBodies.get(name);
252
- if (!body) {
253
- return found;
254
- }
255
- for (const inner of authoredTypeNames(body)) {
256
- for (const [k, v] of requiredUnions(inner, seen)) {
257
- found.set(k, v);
258
- }
259
- }
260
- return found;
261
- }
262
-
263
- // --- Source prop declarations, per component directory ---------------------
264
-
265
- /**
266
- * "{dir}::{Component}Props" → prop name → the type expression source declares.
267
- *
268
- * Keyed by the exact prop bag, never by directory: Chat/ alone holds
269
- * ChatComposer, ChatMessage and ChatToolCalls, each with a differently-typed
270
- * `status`, and judging one component's docs against a sibling's declaration
271
- * is a false accusation. A component with no `{Name}Props` bag here (Heading
272
- * re-exports its props from elsewhere) is simply not checked by this pass —
273
- * a missed prop costs nothing, a wrong failure costs the guard its
274
- * credibility.
275
- */
276
- const sourcePropTypes = new Map<string, Map<string, string>>();
277
-
278
- /**
279
- * Bag name → its members, for bags whose name is unique across the package;
280
- * `null` marks a name declared in more than one place, which is never
281
- * resolved rather than resolved wrongly.
282
- *
283
- * A hook's config bag does not live in the directory its doc does:
284
- * `useTableSortable.doc.mjs` sits in `Table/`, but `UseTableSortableConfig`
285
- * is declared in `Table/plugins/sortable/`. Directory-keying alone therefore
286
- * cannot see it — which is why `sort`, the very prop #1645 was filed about,
287
- * had no source-side guard at all until this index existed.
288
- */
289
- const bagsByName = new Map<string, Map<string, string> | null>();
290
-
291
- /**
292
- * Bags a hook's config may be called. Astryx spells it `Use{Name}Config` or
293
- * `Use{Name}Options` (see UseTableSortableConfig, UsePopoverOptions); the
294
- * other two are cheap insurance and cost nothing when absent.
295
- */
296
- const HOOK_BAG_SUFFIXES = ['Config', 'Options', 'Props', 'Params'];
297
-
298
- for (const file of findFiles(SRC_DIR, ['.ts', '.tsx'])) {
299
- if (file.includes('.test.')) {
300
- continue;
301
- }
302
- const dir = file.slice(0, file.lastIndexOf('/'));
303
- const src = stripComments(readFileSync(file, 'utf8'));
304
- for (const m of src.matchAll(
305
- /export (?:interface|type) ([A-Z][A-Za-z0-9]*(?:Props|Config|Options|Params))(?:<[^>]*>)?\s*(?:extends [^{]+|=\s*)?\{/g,
306
- )) {
307
- const open = src.indexOf('{', m.index);
308
- let depth = 0;
309
- let close = open;
310
- for (; close < src.length; close++) {
311
- if (src[close] === '{') {
312
- depth++;
313
- } else if (src[close] === '}') {
314
- depth--;
315
- if (depth === 0) {
316
- break;
317
- }
318
- }
319
- }
320
- const body = src.slice(open + 1, close);
321
- const byProp = new Map<string, string>();
322
- // Top-level `name?: Type;` members only — nested object literals would
323
- // need a real parser, and a missed prop costs nothing here.
324
- let depthInBody = 0;
325
- for (const rawLine of body.split(/[;\n]/)) {
326
- // `=>` is an arrow, not a closing angle bracket: counting it as one
327
- // drives the depth negative and silently swallows every prop below a
328
- // callback member. (It did, until this line.)
329
- const line = rawLine.replace(/=>/g, '');
330
- const opens = (line.match(/[{(<]/g) || []).length;
331
- const closes = (line.match(/[})>]/g) || []).length;
332
- const member = /^\s*([a-z][A-Za-z0-9]*)\??\s*:\s*(.+?)\s*$/.exec(rawLine);
333
- if (depthInBody === 0 && member) {
334
- byProp.set(member[1], member[2]);
335
- }
336
- depthInBody = Math.max(0, depthInBody + opens - closes);
337
- }
338
- sourcePropTypes.set(`${dir}::${m[1]}`, byProp);
339
- // Second index, keyed by bag name alone, for the cross-directory hook
340
- // lookup below. A duplicate name poisons the entry: guessing between two
341
- // declarations is how a guard earns a false accusation.
342
- bagsByName.set(m[1], bagsByName.has(m[1]) ? null : byProp);
343
- }
344
- }
345
-
346
- /**
347
- * The type source declares for `Component.prop`, if it can be found.
348
- *
349
- * Two lookups, most-specific first:
350
- * 1. The component's own `{Name}Props` bag in its own directory. Exact, and
351
- * the only pass that runs for components — Chat/ holds three differently
352
- * typed `status` props, so a directory-wide search would misjudge them.
353
- * 2. For hooks only (`useThing`), the uniquely-named `UseThingConfig` /
354
- * `UseThingOptions` bag, wherever in the package it is declared.
355
- *
356
- * Anything else stays undefined and is judged on the doc alone: a missed prop
357
- * costs nothing, a wrong failure costs the guard its credibility. (Heading
358
- * re-exports its props and so has no bag here — deliberately unresolved.)
359
- */
360
- function declaredType(
361
- dir: string,
362
- component: string,
363
- prop: string,
364
- ): string | undefined {
365
- const own = sourcePropTypes.get(`${dir}::${component}Props`)?.get(prop);
366
- if (own !== undefined) {
367
- return own;
368
- }
369
- if (!/^use[A-Z]/.test(component)) {
370
- return undefined;
371
- }
372
- const pascal = component[0].toUpperCase() + component.slice(1);
373
- for (const suffix of HOOK_BAG_SUFFIXES) {
374
- const declared = bagsByName.get(`${pascal}${suffix}`)?.get(prop);
375
- if (declared !== undefined) {
376
- return declared;
377
- }
378
- }
379
- return undefined;
380
- }
381
-
382
- // --- Doc props -------------------------------------------------------------
383
-
384
- const docFiles = findFiles(SRC_DIR, ['.doc.mjs']);
385
-
386
- interface DocProp {
387
- file: string;
388
- dir: string;
389
- component: string;
390
- prop: string;
391
- type: string;
392
- description: string;
393
- }
394
-
395
- const docProps: DocProp[] = [];
396
- for (const file of docFiles) {
397
- const mod = require(file) as DocModule;
398
- // A type is language-neutral: the translated docs carry their own props[]
399
- // (the `--zh` CLI surface renders them), so they are held to the same bar.
400
- for (const key of ['docs', 'docsZh'] as const) {
401
- const docs = mod[key];
402
- if (!docs) {
403
- continue;
404
- }
405
- const entries = [
406
- {name: docs.name, props: docs.props},
407
- ...(docs.components || []),
408
- ];
409
- for (const {name, props} of entries) {
410
- if (!name || !Array.isArray(props)) {
411
- continue;
412
- }
413
- for (const prop of props) {
414
- if (typeof prop.type !== 'string') {
415
- continue;
416
- }
417
- docProps.push({
418
- file: `${relative(SRC_DIR, file)}${key === 'docsZh' ? ' (zh)' : ''}`,
419
- dir: file.slice(0, file.lastIndexOf('/')),
420
- component: name,
421
- prop: prop.name,
422
- type: prop.type,
423
- description: prop.description || '',
424
- });
425
- }
426
- }
427
- }
428
- }
429
-
430
- function escapeRe(s: string): string {
431
- return s.replace(/[.*+?^${}()|[\]\\-]/g, '\\$&');
432
- }
433
-
434
- /** The value members of a union — `null`/`undefined` carry nothing to spell. */
435
- function literalMembers(literals: string): string[] {
436
- return literals
437
- .split('|')
438
- .map(s => s.trim())
439
- .filter(s => s.startsWith("'") || /^-?\d/.test(s));
440
- }
441
-
442
- /**
443
- * Where a literal has to be written to count as surfaced.
444
- *
445
- * `code` — a type column. The literal must appear *as a literal*: quotes
446
- * intact for strings, digit-boundary-anchored for numbers.
447
- * `prose` — a free-text description. Quotes are optional (prose may say
448
- * `direction is ascending or descending`), but the boundary still holds.
449
- *
450
- * The boundary is the whole point. A bare `text.includes('sm')` is satisfied
451
- * by `'xsm'`, and `text.includes('1')` by `1.5` or `10` — so a doc could drop
452
- * a member and stay "green" purely because a longer sibling contains its
453
- * characters. Every union whose members share substrings (TextSize, TextType,
454
- * SpacingStep, IconName) is exposed to that, which is most of them.
455
- */
456
- type Surface = 'code' | 'prose';
457
-
458
- function isSurfaced(text: string, literal: string, surface: Surface): boolean {
459
- const isString = literal.startsWith("'");
460
- const inner = isString ? literal.slice(1, -1) : literal;
461
- if (isString) {
462
- // In code, the quotes are part of the literal: 'xsm' does not contain
463
- // the *literal* 'sm', only the characters. In prose they are optional.
464
- const body = escapeRe(inner);
465
- return surface === 'code'
466
- ? new RegExp(`['"\`]${body}['"\`]`).test(text)
467
- : new RegExp(`(?<![\\w-])${body}(?![\\w-])`).test(text);
468
- }
469
- // Numbers: reject a match that is really part of a longer number — `1` must
470
- // not be found inside `1.5`, `10` or `-1`. A trailing dot is allowed only
471
- // when it is sentence punctuation ("steps go 0, 0.5, 1."), not a decimal.
472
- return new RegExp(`(?<![\\w.-])${escapeRe(inner)}(?![\\w-])(?!\\.\\d)`).test(
473
- text,
474
- );
475
- }
476
-
477
- /** Members of `literals` not written out in `text`. */
478
- function missingFrom(
479
- text: string,
480
- literals: string,
481
- surface: Surface = 'code',
482
- ): string[] {
483
- return literalMembers(literals).filter(
484
- literal => !isSurfaced(text, literal, surface),
485
- );
486
- }
487
-
488
- interface Violation {
489
- where: string;
490
- detail: string;
491
- }
492
-
493
- /**
494
- * Reasons this one prop hides values a reader would have to guess at.
495
- *
496
- * `resolveFrom` is the type expression whose unions the reader must know;
497
- * `type`/`description` are what the docs actually say. They are the same
498
- * expression for the doc-side pass, and differ for the source-side pass,
499
- * where the component's own `.tsx` declaration is the authority and the docs
500
- * are the thing on trial. That second pass is what makes the guard
501
- * drift-proof: inlined literals go stale the moment the union in source
502
- * gains a member, and only the source knows that happened.
503
- *
504
- * Pure — the synthetic cases below exercise it directly, so the guard is
505
- * proven to bite without dirtying a real doc.
506
- */
507
- function hiddenValueReasons(
508
- type: string,
509
- description: string,
510
- resolveFrom: string = type,
511
- ): string[] {
512
- const reasons: string[] = [];
513
- for (const named of authoredTypeNames(resolveFrom)) {
514
- for (const [union, literals] of requiredUnions(named)) {
515
- if (ENUMERATED_IN_PROSE.has(union)) {
516
- const missing = missingFrom(description, literals, 'prose');
517
- if (missing.length > 0) {
518
- reasons.push(
519
- `${union} is exempt from inlining only while its description ` +
520
- `enumerates every value; these are missing from the ` +
521
- `description: ${missing.join(', ')}.`,
522
- );
523
- }
524
- } else if (named === union) {
525
- // DIRECT: the name is the union. Inlining is always affordable, so
526
- // the type column is the only surface that counts.
527
- if (missingFrom(type, literals, 'code').length > 0) {
528
- reasons.push(
529
- `names the union ${union} instead of inlining it. ` +
530
- `Write: "${literals}".`,
531
- );
532
- }
533
- } else if (
534
- // INDIRECT: the union hides inside a composite. Spell the shape out
535
- // in the type, or name the values in the description. Each surface is
536
- // read on its own terms — the type as code, the description as prose —
537
- // rather than concatenated, so a value half-spelled in one and
538
- // half-mentioned in the other cannot pass for a value that is written
539
- // down anywhere.
540
- literalMembers(literals).some(
541
- literal =>
542
- !isSurfaced(type, literal, 'code') &&
543
- !isSurfaced(description, literal, 'prose'),
544
- )
545
- ) {
546
- reasons.push(
547
- `${named} hides ${union} = ${literals}, and neither the type nor ` +
548
- `the description says so. Spell the shape out in the type ` +
549
- `(preferred for small objects) or name the legal values in the ` +
550
- `description, so a reader without an IDE can see what is legal.`,
551
- );
552
- }
553
- }
554
- }
555
- return reasons;
556
- }
557
-
558
- function findViolations(): Violation[] {
559
- const violations: Violation[] = [];
560
- for (const {file, dir, component, prop, type, description} of docProps) {
561
- const where = `${file} — ${component}.${prop}: "${type}"`;
562
- const seen = new Set<string>();
563
- const report = (detail: string) => {
564
- if (!seen.has(detail)) {
565
- seen.add(detail);
566
- violations.push({where, detail});
567
- }
568
- };
569
- // Pass 1: what the docs themselves name.
570
- for (const detail of hiddenValueReasons(type, description)) {
571
- report(detail);
572
- }
573
- // Pass 2: what the component actually declares in source.
574
- const declared = declaredType(dir, component, prop);
575
- if (declared) {
576
- for (const detail of hiddenValueReasons(type, description, declared)) {
577
- report(`source declares \`${prop}: ${declared}\` — ${detail}`);
578
- }
579
- }
580
- }
581
- return violations;
582
- }
583
-
584
- describe('doc prop types surface their literal values (#1645)', () => {
585
- it('sanity: finds doc props and literal-union types in source', () => {
586
- expect(docProps.length).toBeGreaterThan(0);
587
- expect(literalUnions.size).toBeGreaterThan(0);
588
- });
589
-
590
- it('sanity: the registries read the real source definitions', () => {
591
- expect(literalUnions.get('SpacingStep')).toBe(
592
- '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
593
- );
594
- expect(literalUnions.get('TableSortDirection')).toBe(
595
- "'ascending' | 'descending'",
596
- );
597
- // @deprecated members are dropped: SwitchLabelSpacing is
598
- // `'hug' | 'spread' | (@deprecated) 'default'`, and docs shouldn't have to
599
- // advertise the deprecated value as a legal option.
600
- expect(literalUnions.get('SwitchLabelSpacing')).toBe("'hug' | 'spread'");
601
- expect([...requiredUnions('InputStatus').keys()]).toContain(
602
- 'InputStatusType',
603
- );
604
- expect([...requiredUnions('TableSortState').keys()]).toContain(
605
- 'TableSortDirection',
606
- );
607
- });
608
-
609
- it('sanity: does not descend into opaque generic wrappers', () => {
610
- // Button's endContent is ReactElement<IconProps>; the consumer writes
611
- // <Icon icon="check" />, not an IconProps object, so IconName's 26
612
- // values are Icon's business, not Button's.
613
- expect(authoredTypeNames('ReactElement<IconProps>')).toEqual([
614
- 'ReactElement',
615
- ]);
616
- expect(authoredTypeNames('Record<string, MarkdownSource>')).toEqual([
617
- 'Record',
618
- ]);
619
- expect(
620
- authoredTypeNames('ReadonlyArray<TableSortEntry<TSortKey>>'),
621
- ).toEqual(['ReadonlyArray', 'TableSortEntry']);
622
- });
623
-
624
- it('LITERAL_UNION rejects a long near-miss union in linear time', () => {
625
- // Every `export type` in the package is fed to this regex, so it must stay
626
- // cheap on the ones that DON'T match. The dangerous shape is a long literal
627
- // prefix ending in something that isn't a literal — `'a' | 'b' | … |
628
- // ComponentType`, the autocomplete escape hatch — which the regex can only
629
- // reject after trying every way to parse it. An ambiguous pattern has 2^n
630
- // of those. This union is 24 members long: linear, it is instant; ambiguous,
631
- // it would outlive the CI job.
632
- const nearMiss =
633
- Array.from({length: 24}, (_, i) => `'v${i}'`).join(' | ') +
634
- ' | ComponentType';
635
- const start = performance.now();
636
- expect(LITERAL_UNION.test(nearMiss)).toBe(false);
637
- expect(performance.now() - start).toBeLessThan(100);
638
- });
639
-
640
- it('no documented prop type hides its legal values', () => {
641
- const violations = findViolations();
642
- expect(
643
- violations,
644
- violations.map(v => `${v.where}\n ${v.detail}`).join('\n'),
645
- ).toEqual([]);
646
- });
647
-
648
- describe('the guard bites (synthetic props, not real docs)', () => {
649
- it('flags a bare literal-union name and accepts the inlined form', () => {
650
- expect(hiddenValueReasons('SpacingStep', 'Gap between items.')).toEqual([
651
- expect.stringContaining('names the union SpacingStep'),
652
- ]);
653
- expect(
654
- hiddenValueReasons(
655
- '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
656
- 'Gap between items.',
657
- ),
658
- ).toEqual([]);
659
- });
660
-
661
- it('is not fooled by prose alone for a direct union', () => {
662
- // The #1645 failure mode: prose hints at the scale, the type column
663
- // still says nothing, and the CLI signature builder (which splits the
664
- // type on `|`) still has no values to print.
665
- expect(
666
- hiddenValueReasons('SpacingStep', 'Steps: 0, 0.5, 1, 1.5, 2, 3, 4.'),
667
- ).not.toEqual([]);
668
- });
669
-
670
- it('flags a partially inlined union — one forgotten member is enough', () => {
671
- // Judged against what source declares, so a doc that drops 'stretch'
672
- // (or an inlined SpacingStep that misses a step the scale later gains)
673
- // is caught even though the doc no longer names the type at all.
674
- expect(
675
- hiddenValueReasons(
676
- "'start' | 'center' | 'end'",
677
- 'Alignment.',
678
- 'GridAlignment',
679
- ),
680
- ).toEqual([expect.stringContaining('GridAlignment')]);
681
- expect(
682
- hiddenValueReasons(
683
- "'start' | 'center' | 'end' | 'stretch'",
684
- 'Alignment.',
685
- 'GridAlignment',
686
- ),
687
- ).toEqual([]);
688
- });
689
-
690
- it('the source-side pass indexes the real component prop bags', () => {
691
- const gridDir = docProps.find(p => p.component === 'Grid')!.dir;
692
- expect(declaredType(gridDir, 'Grid', 'gap')).toBe('SpacingStep');
693
- expect(declaredType(gridDir, 'Grid', 'align')).toBe('GridAlignment');
694
- });
695
-
696
- it('never judges a component against a sibling in the same directory', () => {
697
- // Chat/ declares three differently-typed `status` props. Reading
698
- // ChatComposer's docs against ChatMessageMetadata's declaration would
699
- // be a false accusation, so the index is keyed by prop bag, not folder.
700
- const chatDir = docProps.find(p => p.component === 'ChatComposer')!.dir;
701
- expect(declaredType(chatDir, 'ChatComposer', 'status')).toBe(
702
- 'ChatComposerStatus',
703
- );
704
- expect(declaredType(chatDir, 'ChatMessageMetadata', 'status')).toBe(
705
- 'ChatMessageStatus',
706
- );
707
- // Heading re-exports its props, so there is no HeadingProps bag here:
708
- // the pass must stay silent rather than borrow TextProps.
709
- const textDir = docProps.find(p => p.component === 'Text')!.dir;
710
- expect(declaredType(textDir, 'Heading', 'type')).toBeUndefined();
711
- });
712
-
713
- it('flags a composite that hides a union, and takes either surface', () => {
714
- expect(hiddenValueReasons('InputStatus', 'Validation status.')).toEqual([
715
- expect.stringContaining('InputStatus hides InputStatusType'),
716
- ]);
717
- // Spelled out in the type…
718
- expect(
719
- hiddenValueReasons(
720
- "{type: 'warning' | 'error' | 'success', message?: string}",
721
- 'Validation status.',
722
- ),
723
- ).toEqual([]);
724
- // …or named in the description.
725
- expect(
726
- hiddenValueReasons(
727
- 'InputStatus',
728
- "Validation status. type is 'warning', 'error', or 'success'.",
729
- ),
730
- ).toEqual([]);
731
- });
732
-
733
- it("catches the issue's headline: sort direction is not 'asc'/'desc'", () => {
734
- expect(
735
- hiddenValueReasons(
736
- 'TableSortState<TSortKey>',
737
- 'Ordered array of {sortKey, direction} entries.',
738
- ),
739
- ).toEqual([expect.stringContaining("'ascending' | 'descending'")]);
740
- // The word "descending" contains "ascending"'s literal only as a
741
- // substring of itself, so a doc naming just one is still flagged.
742
- expect(
743
- hiddenValueReasons(
744
- 'TableSortState<TSortKey>',
745
- "Entries sort 'ascending' by default.",
746
- ),
747
- ).toEqual([expect.stringContaining("'ascending' | 'descending'")]);
748
- });
749
-
750
- it('lets a value-free type through untouched', () => {
751
- expect(hiddenValueReasons('boolean', 'Disables the control.')).toEqual(
752
- [],
753
- );
754
- expect(hiddenValueReasons('ReactNode', 'Slot content.')).toEqual([]);
755
- expect(hiddenValueReasons('(value: string) => void', 'Called.')).toEqual(
756
- [],
757
- );
758
- });
759
-
760
- it('a longer sibling literal does not mask a shorter one', () => {
761
- // A substring match lies: 'sm' looks "present" inside 'xsm', and the
762
- // spacing step 1 looks "present" inside 1.5 and 10. Both unions below
763
- // are complete EXCEPT for the masked member — so the *only* thing that
764
- // can fail them is the guard noticing the masked one is really gone.
765
- // (Every other member is still listed. A test that drops extra members
766
- // too would pass on the substring match alone and prove nothing —
767
- // which is precisely why GridAlignment, whose members share no
768
- // substrings, cannot exercise this class at all.)
769
- expect(
770
- hiddenValueReasons(
771
- // TextSize without 'sm'. 'xsm' is still there, masking it.
772
- "'4xs' | '3xs' | '2xs' | 'xsm' | 'base' | 'lg' | 'xl' | '2xl' | " +
773
- "'3xl' | '4xl'",
774
- 'Size.',
775
- 'TextSize',
776
- ),
777
- ).toEqual([expect.stringContaining('TextSize')]);
778
- expect(
779
- hiddenValueReasons(
780
- // SpacingStep without the step 1. 1.5 and 10 still mask it.
781
- '0 | 0.5 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
782
- 'Gap.',
783
- 'SpacingStep',
784
- ),
785
- ).toEqual([expect.stringContaining('SpacingStep')]);
786
- // …and the complete unions still pass, so the boundary match is not
787
- // simply rejecting everything.
788
- expect(
789
- hiddenValueReasons(
790
- "'4xs' | '3xs' | '2xs' | 'xsm' | 'sm' | 'base' | 'lg' | 'xl' | " +
791
- "'2xl' | '3xl' | '4xl'",
792
- 'Size.',
793
- 'TextSize',
794
- ),
795
- ).toEqual([]);
796
- expect(
797
- hiddenValueReasons(
798
- '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
799
- 'Gap.',
800
- 'SpacingStep',
801
- ),
802
- ).toEqual([]);
803
- });
804
-
805
- it('holds the prose exemption to its bargain', () => {
806
- // IconName may stay named — but only while every value is in the prose.
807
- const enumerated = docProps.find(
808
- p => p.component === 'Icon' && p.prop === 'icon',
809
- );
810
- expect(enumerated?.type).toContain('IconName');
811
- expect(
812
- hiddenValueReasons(enumerated!.type, enumerated!.description),
813
- ).toEqual([]);
814
- // Drop the enumeration and the exemption stops covering it.
815
- expect(
816
- hiddenValueReasons('IconName | ComponentType<SVGProps>', 'An icon.'),
817
- ).toEqual([expect.stringContaining('exempt from inlining only while')]);
818
- });
819
- });
820
-
821
- /**
822
- * The synthetic cases above prove the predicate bites. These prove the
823
- * *shipped docs are actually wired to it* — each one takes a real doc
824
- * entry, stages the exact drift the PR exists to prevent, and asserts the
825
- * guard fails. A guard that green-lights the regression it was built to
826
- * catch is decoration; these are the tests that stop it becoming one.
827
- */
828
- describe('the guard bites the real docs when they drift', () => {
829
- const realProp = (component: string, prop: string): DocProp => {
830
- const found = docProps.find(
831
- p =>
832
- p.component === component &&
833
- p.prop === prop &&
834
- !p.file.includes('(zh)'),
835
- );
836
- if (!found) {
837
- throw new Error(`no doc prop ${component}.${prop}`);
838
- }
839
- return found;
840
- };
841
-
842
- /** What source says this doc prop is — the authority drift is judged against. */
843
- const authority = (p: DocProp): string => {
844
- const declared = declaredType(p.dir, p.component, p.prop);
845
- if (!declared) {
846
- throw new Error(
847
- `${p.component}.${p.prop} has no source declaration, so nothing ` +
848
- `holds its inlined literals to the union in source.`,
849
- );
850
- }
851
- return declared;
852
- };
853
-
854
- it("#1645's headline prop is guarded: useTableSortable.sort", () => {
855
- // The hook's config bag is UseTableSortableConfig, and it lives in
856
- // Table/plugins/sortable/ while the doc sits in Table/ — so this only
857
- // resolves because the source pass looks past `{Name}Props` *and* past
858
- // the doc's own directory.
859
- const sort = realProp('useTableSortable', 'sort');
860
- expect(authority(sort)).toBe('TableSortState<TSortKey>');
861
- // The shipped doc is honest today…
862
- expect(
863
- hiddenValueReasons(sort.type, sort.description, authority(sort)),
864
- ).toEqual([]);
865
- // …and the moment it stops naming 'descending', the guard fails. This
866
- // is the doc lying about the legal sort values all over again — the
867
- // literal bug #1645 was filed for.
868
- const stale = (s: string) => s.replace(/'?descending'?/g, '');
869
- expect(stale(sort.type)).not.toBe(sort.type);
870
- expect(
871
- hiddenValueReasons(
872
- stale(sort.type),
873
- stale(sort.description),
874
- authority(sort),
875
- ),
876
- ).toEqual([expect.stringContaining("'ascending' | 'descending'")]);
877
- });
878
-
879
- it('Timestamp.size cannot quietly lose a step masked by a sibling', () => {
880
- const size = realProp('Timestamp', 'size');
881
- expect(authority(size)).toBe('TextSize');
882
- expect(
883
- hiddenValueReasons(size.type, size.description, authority(size)),
884
- ).toEqual([]);
885
- // Delete 'sm'. A substring match calls it present — 'xsm' contains it.
886
- const stale = size.type.replace("'sm' | ", '');
887
- expect(stale).not.toBe(size.type);
888
- expect(stale).toContain("'xsm'");
889
- expect(
890
- hiddenValueReasons(stale, size.description, authority(size)),
891
- ).toEqual([expect.stringContaining('TextSize')]);
892
- });
893
-
894
- /**
895
- * The two props that must NOT be inlined. Everything else in this file
896
- * pushes toward spelling unions out; these two push back, because the
897
- * docsite playground reads `type` to choose a control. What each one is
898
- * really protecting differs, and the specifics live next to the playground
899
- * itself — see apps/docsite/src/__tests__/component-prop-controls.test.ts,
900
- * which exercises the actual gate. These only pin the doc's shape, so the
901
- * next person to "finish the job" trips here first.
902
- */
903
- it('AppShell.mobileNav stays a bare ReactNode (the editor hides on an exact string)', () => {
904
- const nav = realProp('AppShell', 'mobileNav');
905
- // PropertyEditor's UNSUPPORTED_PROP_TYPES is a Set of exact type strings.
906
- // Widening drops that match, and the prop would then be hidden only by
907
- // the second, incidental gate (its slotElements). Keep the exact string.
908
- expect(nav.type).toBe('ReactNode');
909
- // The values still have to be discoverable — they live in the prose.
910
- expect(nav.description).toContain('breakpoint');
911
- expect(nav.description).toContain("'md'");
912
- });
913
-
914
- it('Lightbox.media keeps naming its type (spelling it out yields a string control)', () => {
915
- const media = realProp('Lightbox', 'media');
916
- expect(media.type).toBe('LightboxMedia | LightboxMedia[]');
917
- // Same bargain as IconName: named is allowed only while the prose
918
- // carries the values a consumer must write.
919
- expect(media.description).toContain("'image'");
920
- expect(media.description).toContain("'video'");
921
- });
922
-
923
- it('Grid.gap cannot quietly lose the step 1, masked by 1.5 and 10', () => {
924
- const gap = realProp('Grid', 'gap');
925
- expect(authority(gap)).toBe('SpacingStep');
926
- expect(
927
- hiddenValueReasons(gap.type, gap.description, authority(gap)),
928
- ).toEqual([]);
929
- const stale = gap.type.replace('1 | 1.5', '1.5');
930
- expect(stale).not.toBe(gap.type);
931
- expect(stale).toContain('1.5');
932
- expect(stale).toContain('10');
933
- expect(
934
- hiddenValueReasons(stale, gap.description, authority(gap)),
935
- ).toEqual([expect.stringContaining('SpacingStep')]);
936
- });
937
- });
938
- });