@astryxdesign/core 0.1.9 → 0.2.0-canary.136a00f

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 (560) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/dist/Avatar/Avatar.d.ts +42 -3
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +190 -59
  5. package/dist/Avatar/AvatarStatusDot.d.ts +6 -4
  6. package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
  7. package/dist/AvatarGroup/AvatarGroup.d.ts +7 -1
  8. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  9. package/dist/AvatarGroup/AvatarGroup.js +58 -6
  10. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
  11. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  12. package/dist/AvatarGroup/AvatarGroupOverflow.js +7 -2
  13. package/dist/Banner/Banner.js +2 -2
  14. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  15. package/dist/Breadcrumbs/BreadcrumbItem.js +11 -4
  16. package/dist/Breadcrumbs/index.d.ts +1 -0
  17. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  18. package/dist/Breadcrumbs/index.js +2 -1
  19. package/dist/Button/Button.d.ts +1 -1
  20. package/dist/Button/Button.d.ts.map +1 -1
  21. package/dist/Button/Button.js +6 -4
  22. package/dist/Calendar/Calendar.d.ts.map +1 -1
  23. package/dist/Calendar/Calendar.js +50 -9
  24. package/dist/Calendar/dayCellUtils.d.ts +4 -4
  25. package/dist/Calendar/dayCellUtils.js +2 -2
  26. package/dist/Calendar/styles.d.ts +30 -31
  27. package/dist/Calendar/styles.d.ts.map +1 -1
  28. package/dist/Calendar/styles.js +30 -31
  29. package/dist/Card/Card.js +1 -1
  30. package/dist/Carousel/Carousel.d.ts.map +1 -1
  31. package/dist/Carousel/Carousel.js +22 -12
  32. package/dist/Chat/ChatComposerInput.js +1 -1
  33. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  34. package/dist/Chat/ChatDictationButton.js +3 -1
  35. package/dist/Chat/ChatLayout.js +4 -4
  36. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  37. package/dist/Chat/ChatMessageBubble.js +8 -8
  38. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  39. package/dist/Chat/ChatToolCalls.js +10 -3
  40. package/dist/Chat/useTriggerMenu.js +2 -2
  41. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  42. package/dist/CheckboxInput/CheckboxInput.js +6 -6
  43. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  44. package/dist/CheckboxList/CheckboxListItem.js +19 -4
  45. package/dist/Citation/Citation.d.ts +22 -1
  46. package/dist/Citation/Citation.d.ts.map +1 -1
  47. package/dist/Citation/Citation.js +20 -6
  48. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  49. package/dist/CodeBlock/CodeBlock.js +16 -10
  50. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  51. package/dist/Collapsible/Collapsible.js +3 -1
  52. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  53. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  54. package/dist/CommandPalette/CommandPalette.js +42 -3
  55. package/dist/CommandPalette/CommandPaletteItem.js +1 -1
  56. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  57. package/dist/ContextMenu/ContextMenu.js +23 -5
  58. package/dist/ContextMenu/index.d.ts +1 -0
  59. package/dist/ContextMenu/index.d.ts.map +1 -1
  60. package/dist/ContextMenu/index.js +3 -1
  61. package/dist/DateInput/DateInput.d.ts +10 -2
  62. package/dist/DateInput/DateInput.d.ts.map +1 -1
  63. package/dist/DateInput/DateInput.js +33 -19
  64. package/dist/DateRangeInput/DateRangeInput.d.ts +10 -2
  65. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  66. package/dist/DateRangeInput/DateRangeInput.js +23 -20
  67. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  68. package/dist/DateTimeInput/DateTimeInput.js +23 -18
  69. package/dist/Divider/Divider.d.ts +2 -2
  70. package/dist/Divider/Divider.d.ts.map +1 -1
  71. package/dist/Divider/Divider.js +13 -0
  72. package/dist/DropdownMenu/DropdownMenu.d.ts +6 -0
  73. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  74. package/dist/DropdownMenu/DropdownMenu.js +22 -5
  75. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  76. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +4 -1
  77. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  78. package/dist/DropdownMenu/DropdownMenuItem.js +5 -2
  79. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +8 -11
  80. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
  81. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +3 -1
  82. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +1 -1
  83. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  84. package/dist/DropdownMenu/DropdownMenuRadioItem.js +5 -2
  85. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +104 -0
  86. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -0
  87. package/dist/DropdownMenu/DropdownMenuSubMenu.js +427 -0
  88. package/dist/DropdownMenu/index.d.ts +10 -0
  89. package/dist/DropdownMenu/index.d.ts.map +1 -1
  90. package/dist/DropdownMenu/index.js +13 -0
  91. package/dist/DropdownMenu/menuItemHover.d.ts +23 -0
  92. package/dist/DropdownMenu/menuItemHover.d.ts.map +1 -0
  93. package/dist/DropdownMenu/menuItemHover.js +33 -0
  94. package/dist/DropdownMenu/menuItemRoles.d.ts +8 -0
  95. package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -1
  96. package/dist/DropdownMenu/menuItemRoles.js +10 -1
  97. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  98. package/dist/DropdownMenu/renderDropdownItems.js +21 -6
  99. package/dist/Field/Field.d.ts +3 -1
  100. package/dist/Field/Field.d.ts.map +1 -1
  101. package/dist/Field/Field.js +4 -1
  102. package/dist/Field/FieldLabel.d.ts +2 -1
  103. package/dist/Field/FieldLabel.d.ts.map +1 -1
  104. package/dist/Field/FieldLabel.js +9 -5
  105. package/dist/Field/inputStyles.stylex.d.ts +1 -0
  106. package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
  107. package/dist/Field/inputStyles.stylex.js +1 -0
  108. package/dist/FieldStatus/FieldStatus.d.ts +10 -0
  109. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  110. package/dist/FieldStatus/FieldStatus.js +39 -3
  111. package/dist/FileInput/FileInput.d.ts +10 -2
  112. package/dist/FileInput/FileInput.d.ts.map +1 -1
  113. package/dist/FileInput/FileInput.js +93 -65
  114. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  115. package/dist/HoverCard/useHoverCard.js +10 -4
  116. package/dist/Icon/Icon.d.ts +15 -1
  117. package/dist/Icon/Icon.d.ts.map +1 -1
  118. package/dist/Icon/Icon.js +19 -3
  119. package/dist/Item/Item.d.ts +16 -3
  120. package/dist/Item/Item.d.ts.map +1 -1
  121. package/dist/Item/Item.js +31 -6
  122. package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
  123. package/dist/Layer/layerAnimations.stylex.js +10 -2
  124. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  125. package/dist/Lightbox/Lightbox.js +19 -13
  126. package/dist/List/List.d.ts.map +1 -1
  127. package/dist/List/List.js +6 -3
  128. package/dist/List/ListItem.d.ts +11 -1
  129. package/dist/List/ListItem.d.ts.map +1 -1
  130. package/dist/List/ListItem.js +2 -0
  131. package/dist/Markdown/Markdown.d.ts.map +1 -1
  132. package/dist/Markdown/Markdown.js +7 -0
  133. package/dist/MetadataList/MetadataList.d.ts +1 -1
  134. package/dist/MetadataList/MetadataList.d.ts.map +1 -1
  135. package/dist/MetadataList/MetadataList.js +4 -2
  136. package/dist/MultiSelector/MultiSelector.d.ts +9 -1
  137. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  138. package/dist/MultiSelector/MultiSelector.js +80 -42
  139. package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
  140. package/dist/NumberInput/NumberInput.d.ts +10 -2
  141. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  142. package/dist/NumberInput/NumberInput.js +22 -17
  143. package/dist/Outline/Outline.js +2 -2
  144. package/dist/Pagination/Pagination.d.ts.map +1 -1
  145. package/dist/Pagination/Pagination.js +11 -3
  146. package/dist/PowerSearch/PowerSearch.d.ts +9 -2
  147. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  148. package/dist/PowerSearch/PowerSearch.js +2 -0
  149. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  150. package/dist/ProgressBar/ProgressBar.js +6 -1
  151. package/dist/RadioList/RadioList.d.ts +2 -2
  152. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  153. package/dist/RadioList/RadioListItem.js +5 -5
  154. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  155. package/dist/Resizable/ResizeHandle.js +49 -19
  156. package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
  157. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  158. package/dist/SegmentedControl/SegmentedControlItem.js +5 -3
  159. package/dist/Selector/Selector.d.ts +8 -0
  160. package/dist/Selector/Selector.d.ts.map +1 -1
  161. package/dist/Selector/Selector.js +66 -17
  162. package/dist/SideNav/SideNav.d.ts.map +1 -1
  163. package/dist/SideNav/SideNav.js +5 -5
  164. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  165. package/dist/SideNav/SideNavCollapseButton.js +13 -10
  166. package/dist/SideNav/SideNavItem.d.ts +1 -1
  167. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  168. package/dist/SideNav/SideNavItem.js +12 -10
  169. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  170. package/dist/Skeleton/Skeleton.js +2 -2
  171. package/dist/Slider/Slider.d.ts.map +1 -1
  172. package/dist/Slider/Slider.js +87 -34
  173. package/dist/Spinner/Spinner.d.ts +3 -2
  174. package/dist/Spinner/Spinner.d.ts.map +1 -1
  175. package/dist/Spinner/Spinner.js +11 -2
  176. package/dist/Switch/Switch.d.ts +8 -1
  177. package/dist/Switch/Switch.d.ts.map +1 -1
  178. package/dist/Switch/Switch.js +171 -91
  179. package/dist/TabList/Tab.js +2 -2
  180. package/dist/TabList/TabList.d.ts +2 -11
  181. package/dist/TabList/TabList.d.ts.map +1 -1
  182. package/dist/TabList/TabList.js +5 -9
  183. package/dist/TabList/TabListContext.d.ts +0 -5
  184. package/dist/TabList/TabListContext.d.ts.map +1 -1
  185. package/dist/TabList/TabListContext.js +0 -5
  186. package/dist/TabList/TabMenu.js +1 -1
  187. package/dist/Table/BaseTable.d.ts.map +1 -1
  188. package/dist/Table/BaseTable.js +30 -4
  189. package/dist/Table/TableCell.js +3 -3
  190. package/dist/Table/TableHeaderCell.js +3 -3
  191. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  192. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +15 -11
  193. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  194. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +37 -27
  195. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  196. package/dist/Table/plugins/selection/useTableSelection.js +3 -0
  197. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  198. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +15 -7
  199. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  200. package/dist/Table/plugins/tree/useTableTreeData.js +29 -23
  201. package/dist/Table/types.d.ts +32 -0
  202. package/dist/Table/types.d.ts.map +1 -1
  203. package/dist/TextArea/TextArea.d.ts +10 -1
  204. package/dist/TextArea/TextArea.d.ts.map +1 -1
  205. package/dist/TextArea/TextArea.js +18 -19
  206. package/dist/TextInput/TextInput.d.ts +10 -2
  207. package/dist/TextInput/TextInput.d.ts.map +1 -1
  208. package/dist/TextInput/TextInput.js +20 -17
  209. package/dist/Thumbnail/Thumbnail.js +2 -2
  210. package/dist/TimeInput/TimeInput.d.ts +10 -2
  211. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  212. package/dist/TimeInput/TimeInput.js +17 -17
  213. package/dist/Timestamp/Timestamp.d.ts +31 -3
  214. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  215. package/dist/Timestamp/Timestamp.js +47 -76
  216. package/dist/Timestamp/formatInstant.d.ts +41 -0
  217. package/dist/Timestamp/formatInstant.d.ts.map +1 -0
  218. package/dist/Timestamp/formatInstant.js +177 -0
  219. package/dist/Timestamp/index.d.ts +1 -0
  220. package/dist/Timestamp/index.d.ts.map +1 -1
  221. package/dist/Timestamp/tooltipEntries.d.ts +56 -0
  222. package/dist/Timestamp/tooltipEntries.d.ts.map +1 -0
  223. package/dist/Timestamp/tooltipEntries.js +163 -0
  224. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  225. package/dist/Toast/ToastViewport.js +61 -9
  226. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  227. package/dist/ToggleButton/ToggleButton.js +3 -1
  228. package/dist/Token/Token.d.ts +34 -4
  229. package/dist/Token/Token.d.ts.map +1 -1
  230. package/dist/Token/Token.js +85 -45
  231. package/dist/Token/TokenLink.d.ts +62 -0
  232. package/dist/Token/TokenLink.d.ts.map +1 -0
  233. package/dist/Token/TokenLink.js +76 -0
  234. package/dist/Token/index.d.ts +1 -1
  235. package/dist/Token/index.d.ts.map +1 -1
  236. package/dist/Tokenizer/Tokenizer.d.ts +9 -2
  237. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  238. package/dist/Tokenizer/Tokenizer.js +4 -2
  239. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  240. package/dist/Tooltip/useTooltip.js +17 -1
  241. package/dist/TopNav/TopNavItem.d.ts +3 -1
  242. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  243. package/dist/TopNav/TopNavItem.js +30 -3
  244. package/dist/TreeList/TreeList.d.ts.map +1 -1
  245. package/dist/TreeList/TreeList.js +1 -0
  246. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  247. package/dist/TreeList/TreeListBranches.js +8 -6
  248. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  249. package/dist/TreeList/TreeListItem.js +32 -14
  250. package/dist/Typeahead/BaseTypeahead.d.ts +9 -0
  251. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  252. package/dist/Typeahead/BaseTypeahead.js +22 -11
  253. package/dist/Typeahead/Typeahead.d.ts +9 -2
  254. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  255. package/dist/Typeahead/Typeahead.js +11 -2
  256. package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
  257. package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
  258. package/dist/Typeahead/TypeaheadItem.js +20 -10
  259. package/dist/astryx.css +70 -30
  260. package/dist/astryx.umd.js +51 -51
  261. package/dist/astryx.umd.js.map +4 -4
  262. package/dist/hooks/index.d.ts +2 -0
  263. package/dist/hooks/index.d.ts.map +1 -1
  264. package/dist/hooks/index.js +1 -0
  265. package/dist/hooks/isRtlElement.d.ts +18 -0
  266. package/dist/hooks/isRtlElement.d.ts.map +1 -0
  267. package/dist/hooks/isRtlElement.js +27 -0
  268. package/dist/hooks/useAnnounce.d.ts +3 -0
  269. package/dist/hooks/useAnnounce.d.ts.map +1 -1
  270. package/dist/hooks/useAnnounce.js +39 -1
  271. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  272. package/dist/hooks/useFocusTrap.js +52 -11
  273. package/dist/hooks/useGridFocus.d.ts +6 -1
  274. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  275. package/dist/hooks/useGridFocus.js +12 -9
  276. package/dist/hooks/useHotkeys.d.ts +9 -0
  277. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  278. package/dist/hooks/useHotkeys.js +9 -0
  279. package/dist/hooks/useInputStatusIcon.d.ts +38 -0
  280. package/dist/hooks/useInputStatusIcon.d.ts.map +1 -0
  281. package/dist/hooks/useInputStatusIcon.js +158 -0
  282. package/dist/hooks/useKeyboardHint.d.ts +1 -1
  283. package/dist/hooks/useKeyboardHint.d.ts.map +1 -1
  284. package/dist/hooks/useKeyboardHint.js +4 -2
  285. package/dist/hooks/useListFocus.d.ts +39 -1
  286. package/dist/hooks/useListFocus.d.ts.map +1 -1
  287. package/dist/hooks/useListFocus.js +54 -9
  288. package/dist/i18n/InternationalizationContext.d.ts +1 -0
  289. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  290. package/dist/i18n/InternationalizationContext.js +3 -0
  291. package/dist/i18n/InternationalizationProvider.d.ts +8 -1
  292. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
  293. package/dist/i18n/InternationalizationProvider.js +5 -1
  294. package/dist/i18n/getLocaleDirection.d.ts +18 -0
  295. package/dist/i18n/getLocaleDirection.d.ts.map +1 -0
  296. package/dist/i18n/getLocaleDirection.js +29 -0
  297. package/dist/i18n/index.d.ts +6 -0
  298. package/dist/i18n/index.d.ts.map +1 -1
  299. package/dist/i18n/index.js +7 -1
  300. package/dist/i18n/useDirection.d.ts +2 -0
  301. package/dist/i18n/useDirection.d.ts.map +1 -0
  302. package/dist/i18n/useDirection.js +27 -0
  303. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  304. package/dist/theme/derivedVarRegistry.js +13 -0
  305. package/dist/utils/index.d.ts +1 -0
  306. package/dist/utils/index.d.ts.map +1 -1
  307. package/dist/utils/index.js +2 -1
  308. package/dist/utils/plainDate.d.ts +17 -0
  309. package/dist/utils/plainDate.d.ts.map +1 -1
  310. package/dist/utils/plainDate.js +23 -4
  311. package/dist/utils/rtlStyles.d.ts +24 -0
  312. package/dist/utils/rtlStyles.d.ts.map +1 -0
  313. package/dist/utils/rtlStyles.js +27 -0
  314. package/locales/en.json +112 -0
  315. package/locales/pseudo.json +84 -0
  316. package/package.json +6 -1
  317. package/src/Avatar/Avatar.doc.mjs +50 -3
  318. package/src/Avatar/Avatar.test.tsx +218 -0
  319. package/src/Avatar/Avatar.tsx +285 -79
  320. package/src/Avatar/AvatarStatusDot.doc.mjs +4 -4
  321. package/src/Avatar/AvatarStatusDot.tsx +6 -4
  322. package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -0
  323. package/src/AvatarGroup/AvatarGroup.test.tsx +162 -2
  324. package/src/AvatarGroup/AvatarGroup.tsx +58 -3
  325. package/src/AvatarGroup/AvatarGroupOverflow.tsx +5 -2
  326. package/src/Banner/Banner.tsx +6 -6
  327. package/src/Breadcrumbs/BreadcrumbItem.tsx +10 -10
  328. package/src/Breadcrumbs/Breadcrumbs.test.tsx +52 -1
  329. package/src/Breadcrumbs/index.ts +4 -0
  330. package/src/Button/Button.doc.mjs +0 -4
  331. package/src/Button/Button.test.tsx +16 -0
  332. package/src/Button/Button.tsx +6 -4
  333. package/src/Calendar/Calendar.test.tsx +170 -20
  334. package/src/Calendar/Calendar.tsx +73 -16
  335. package/src/Calendar/dayCellUtils.test.ts +18 -18
  336. package/src/Calendar/dayCellUtils.ts +2 -2
  337. package/src/Calendar/styles.ts +33 -39
  338. package/src/Card/Card.tsx +1 -1
  339. package/src/Carousel/Carousel.tsx +25 -6
  340. package/src/Chat/ChatComposer.doc.mjs +2 -2
  341. package/src/Chat/ChatComposerInput.doc.mjs +1 -1
  342. package/src/Chat/ChatComposerInput.tsx +2 -2
  343. package/src/Chat/ChatDictationButton.tsx +7 -1
  344. package/src/Chat/ChatLayout.tsx +4 -4
  345. package/src/Chat/ChatMessageBubble.tsx +15 -10
  346. package/src/Chat/ChatSystemMessage.test.tsx +5 -0
  347. package/src/Chat/ChatToolCalls.tsx +9 -2
  348. package/src/Chat/useTriggerMenu.tsx +1 -1
  349. package/src/CheckboxInput/CheckboxInput.doc.mjs +6 -0
  350. package/src/CheckboxInput/CheckboxInput.test.tsx +23 -0
  351. package/src/CheckboxInput/CheckboxInput.tsx +21 -6
  352. package/src/CheckboxList/CheckboxList.doc.mjs +6 -0
  353. package/src/CheckboxList/CheckboxList.test.tsx +94 -3
  354. package/src/CheckboxList/CheckboxListItem.tsx +17 -10
  355. package/src/Citation/Citation.doc.mjs +4 -3
  356. package/src/Citation/Citation.test.tsx +97 -0
  357. package/src/Citation/Citation.tsx +43 -11
  358. package/src/CodeBlock/CodeBlock.test.tsx +17 -0
  359. package/src/CodeBlock/CodeBlock.tsx +38 -11
  360. package/src/Collapsible/Collapsible.doc.mjs +1 -0
  361. package/src/Collapsible/Collapsible.test.tsx +7 -0
  362. package/src/Collapsible/Collapsible.tsx +16 -6
  363. package/src/CommandPalette/CommandPalette.test.tsx +95 -1
  364. package/src/CommandPalette/CommandPalette.tsx +41 -2
  365. package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
  366. package/src/ContextMenu/ContextMenu.test.tsx +59 -2
  367. package/src/ContextMenu/ContextMenu.tsx +22 -11
  368. package/src/ContextMenu/index.ts +5 -0
  369. package/src/DateInput/DateInput.doc.mjs +25 -0
  370. package/src/DateInput/DateInput.test.tsx +230 -0
  371. package/src/DateInput/DateInput.tsx +51 -29
  372. package/src/DateRangeInput/DateRangeInput.doc.mjs +16 -0
  373. package/src/DateRangeInput/DateRangeInput.test.tsx +140 -0
  374. package/src/DateRangeInput/DateRangeInput.tsx +42 -30
  375. package/src/DateTimeInput/DateTimeInput.doc.mjs +22 -1
  376. package/src/DateTimeInput/DateTimeInput.test.tsx +112 -0
  377. package/src/DateTimeInput/DateTimeInput.tsx +44 -39
  378. package/src/Divider/Divider.test.tsx +32 -8
  379. package/src/Divider/Divider.tsx +14 -1
  380. package/src/DropdownMenu/DropdownMenu.test.tsx +60 -0
  381. package/src/DropdownMenu/DropdownMenu.tsx +31 -12
  382. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +8 -2
  383. package/src/DropdownMenu/DropdownMenuItem.tsx +9 -3
  384. package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +4 -12
  385. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +9 -10
  386. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +9 -3
  387. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +20 -2
  388. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +88 -0
  389. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +635 -0
  390. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +553 -0
  391. package/src/DropdownMenu/index.ts +16 -0
  392. package/src/DropdownMenu/menuItemHover.ts +39 -0
  393. package/src/DropdownMenu/menuItemRoles.ts +9 -0
  394. package/src/DropdownMenu/renderDropdownItems.tsx +29 -15
  395. package/src/Field/Field.tsx +14 -9
  396. package/src/Field/FieldLabel.test.tsx +25 -0
  397. package/src/Field/FieldLabel.tsx +12 -3
  398. package/src/Field/inputStyles.stylex.ts +2 -0
  399. package/src/FieldStatus/FieldStatus.test.tsx +72 -0
  400. package/src/FieldStatus/FieldStatus.tsx +48 -2
  401. package/src/FileInput/FileInput.doc.mjs +23 -2
  402. package/src/FileInput/FileInput.test.tsx +104 -13
  403. package/src/FileInput/FileInput.tsx +106 -79
  404. package/src/HoverCard/useHoverCard.tsx +15 -3
  405. package/src/Icon/Icon.doc.mjs +13 -0
  406. package/src/Icon/Icon.test.tsx +89 -0
  407. package/src/Icon/Icon.tsx +51 -3
  408. package/src/Item/Item.doc.mjs +5 -0
  409. package/src/Item/Item.test.tsx +88 -0
  410. package/src/Item/Item.tsx +57 -11
  411. package/src/Layer/layerAnimations.stylex.ts +23 -0
  412. package/src/Lightbox/Lightbox.tsx +15 -7
  413. package/src/List/List.test.tsx +17 -29
  414. package/src/List/List.tsx +6 -1
  415. package/src/List/ListItem.doc.mjs +12 -0
  416. package/src/List/ListItem.tsx +13 -0
  417. package/src/Markdown/Markdown.test.tsx +21 -0
  418. package/src/Markdown/Markdown.tsx +4 -0
  419. package/src/MetadataList/MetadataList.test.tsx +24 -0
  420. package/src/MetadataList/MetadataList.tsx +6 -2
  421. package/src/MultiSelector/MultiSelector.doc.mjs +20 -0
  422. package/src/MultiSelector/MultiSelector.test.tsx +402 -0
  423. package/src/MultiSelector/MultiSelector.tsx +120 -59
  424. package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
  425. package/src/NumberInput/NumberInput.doc.mjs +21 -0
  426. package/src/NumberInput/NumberInput.test.tsx +71 -0
  427. package/src/NumberInput/NumberInput.tsx +35 -26
  428. package/src/Outline/Outline.test.tsx +12 -12
  429. package/src/Outline/Outline.tsx +2 -2
  430. package/src/Pagination/Pagination.tsx +11 -3
  431. package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
  432. package/src/PowerSearch/PowerSearch.test.tsx +23 -0
  433. package/src/PowerSearch/PowerSearch.tsx +10 -1
  434. package/src/ProgressBar/ProgressBar.test.tsx +34 -0
  435. package/src/ProgressBar/ProgressBar.tsx +16 -1
  436. package/src/RadioList/RadioList.doc.mjs +6 -0
  437. package/src/RadioList/RadioList.test.tsx +26 -4
  438. package/src/RadioList/RadioList.tsx +2 -2
  439. package/src/RadioList/RadioListItem.tsx +12 -5
  440. package/src/Resizable/ResizeHandle.test.tsx +94 -0
  441. package/src/Resizable/ResizeHandle.tsx +70 -20
  442. package/src/SegmentedControl/SegmentedControl.test.tsx +28 -0
  443. package/src/SegmentedControl/SegmentedControlItem.tsx +22 -2
  444. package/src/Selector/Selector.doc.mjs +15 -0
  445. package/src/Selector/Selector.test.tsx +370 -0
  446. package/src/Selector/Selector.tsx +88 -20
  447. package/src/SideNav/SideNav.tsx +1 -8
  448. package/src/SideNav/SideNavCollapseButton.tsx +9 -7
  449. package/src/SideNav/SideNavItem.tsx +5 -3
  450. package/src/Skeleton/Skeleton.test.tsx +16 -0
  451. package/src/Skeleton/Skeleton.tsx +13 -1
  452. package/src/Slider/Slider.doc.mjs +6 -0
  453. package/src/Slider/Slider.test.tsx +240 -12
  454. package/src/Slider/Slider.tsx +96 -23
  455. package/src/Spinner/Spinner.test.tsx +10 -8
  456. package/src/Spinner/Spinner.tsx +15 -5
  457. package/src/Switch/Switch.doc.mjs +142 -42
  458. package/src/Switch/Switch.test.tsx +111 -0
  459. package/src/Switch/Switch.tsx +149 -32
  460. package/src/TabList/Tab.tsx +2 -2
  461. package/src/TabList/TabList.doc.mjs +0 -6
  462. package/src/TabList/TabList.test.tsx +3 -15
  463. package/src/TabList/TabList.tsx +6 -17
  464. package/src/TabList/TabListContext.ts +0 -6
  465. package/src/TabList/TabMenu.tsx +2 -2
  466. package/src/Table/BaseTable.tsx +34 -2
  467. package/src/Table/Table.doc.mjs +11 -0
  468. package/src/Table/Table.test.tsx +85 -0
  469. package/src/Table/TableCell.tsx +3 -3
  470. package/src/Table/TableHeaderCell.tsx +3 -3
  471. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +9 -6
  472. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +19 -0
  473. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +27 -18
  474. package/src/Table/plugins/selection/useTableSelection.test.tsx +61 -3
  475. package/src/Table/plugins/selection/useTableSelection.tsx +3 -0
  476. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +38 -9
  477. package/src/Table/plugins/tree/useTableTreeData.tsx +17 -13
  478. package/src/Table/types.ts +33 -0
  479. package/src/Table/useTableRowStatus.doc.mjs +1 -1
  480. package/src/TextArea/TextArea.doc.mjs +21 -0
  481. package/src/TextArea/TextArea.test.tsx +23 -0
  482. package/src/TextArea/TextArea.tsx +27 -26
  483. package/src/TextInput/TextInput.doc.mjs +21 -0
  484. package/src/TextInput/TextInput.test.tsx +150 -0
  485. package/src/TextInput/TextInput.tsx +28 -25
  486. package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
  487. package/src/Thumbnail/Thumbnail.tsx +1 -1
  488. package/src/TimeInput/TimeInput.doc.mjs +21 -0
  489. package/src/TimeInput/TimeInput.test.tsx +23 -0
  490. package/src/TimeInput/TimeInput.tsx +24 -25
  491. package/src/Timestamp/Timestamp.doc.mjs +32 -6
  492. package/src/Timestamp/Timestamp.test.tsx +371 -0
  493. package/src/Timestamp/Timestamp.tsx +96 -93
  494. package/src/Timestamp/formatInstant.ts +218 -0
  495. package/src/Timestamp/index.ts +4 -0
  496. package/src/Timestamp/tooltipEntries.test.ts +552 -0
  497. package/src/Timestamp/tooltipEntries.ts +210 -0
  498. package/src/Toast/ToastViewport.test.tsx +218 -8
  499. package/src/Toast/ToastViewport.tsx +71 -12
  500. package/src/ToggleButton/ToggleButton.test.tsx +24 -0
  501. package/src/ToggleButton/ToggleButton.tsx +19 -1
  502. package/src/Token/Token.test.tsx +166 -15
  503. package/src/Token/Token.tsx +104 -47
  504. package/src/Token/TokenLink.tsx +107 -0
  505. package/src/Token/index.ts +1 -1
  506. package/src/Tokenizer/Tokenizer.doc.mjs +23 -1
  507. package/src/Tokenizer/Tokenizer.test.tsx +23 -0
  508. package/src/Tokenizer/Tokenizer.tsx +14 -2
  509. package/src/Tooltip/Tooltip.test.tsx +46 -0
  510. package/src/Tooltip/useTooltip.tsx +20 -0
  511. package/src/TopNav/TopNav.test.tsx +93 -2
  512. package/src/TopNav/TopNavItem.doc.mjs +3 -3
  513. package/src/TopNav/TopNavItem.tsx +35 -6
  514. package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +1 -1
  515. package/src/TreeList/TreeList.doc.mjs +6 -0
  516. package/src/TreeList/TreeList.test.tsx +50 -10
  517. package/src/TreeList/TreeList.tsx +5 -0
  518. package/src/TreeList/TreeListBranches.tsx +8 -6
  519. package/src/TreeList/TreeListItem.tsx +33 -11
  520. package/src/Typeahead/BaseTypeahead.tsx +42 -15
  521. package/src/Typeahead/Typeahead.doc.mjs +13 -0
  522. package/src/Typeahead/Typeahead.test.tsx +112 -0
  523. package/src/Typeahead/Typeahead.tsx +17 -1
  524. package/src/Typeahead/TypeaheadItem.tsx +2 -1
  525. package/src/__tests__/forcedColors.ts +60 -0
  526. package/src/__tests__/inputWidthContract.test.tsx +62 -0
  527. package/src/doc-mjs.d.ts +19 -0
  528. package/src/hooks/index.ts +6 -0
  529. package/src/hooks/isRtlElement.ts +27 -0
  530. package/src/hooks/useAnnounce.test.tsx +75 -2
  531. package/src/hooks/useAnnounce.ts +47 -1
  532. package/src/hooks/useFocusTrap.test.tsx +104 -0
  533. package/src/hooks/useFocusTrap.ts +61 -12
  534. package/src/hooks/useGridFocus.doc.mjs +3 -3
  535. package/src/hooks/useGridFocus.test.tsx +41 -0
  536. package/src/hooks/useGridFocus.ts +21 -10
  537. package/src/hooks/useHotkeys.ts +9 -0
  538. package/src/hooks/useInputStatusIcon.test.tsx +162 -0
  539. package/src/hooks/useInputStatusIcon.tsx +224 -0
  540. package/src/hooks/useKeyboardHint.test.tsx +22 -0
  541. package/src/hooks/useKeyboardHint.tsx +6 -2
  542. package/src/hooks/useListFocus.doc.mjs +25 -3
  543. package/src/hooks/useListFocus.test.tsx +153 -1
  544. package/src/hooks/useListFocus.ts +102 -9
  545. package/src/i18n/InternationalizationContext.ts +4 -0
  546. package/src/i18n/InternationalizationProvider.tsx +12 -2
  547. package/src/i18n/__tests__/getLocaleDirection.test.ts +40 -0
  548. package/src/i18n/__tests__/useDirection.test.tsx +66 -0
  549. package/src/i18n/getLocaleDirection.ts +29 -0
  550. package/src/i18n/index.ts +6 -0
  551. package/src/i18n/useDirection.ts +29 -0
  552. package/src/reset.css +0 -26
  553. package/src/reset.test.ts +60 -0
  554. package/src/theme/derivedVarRegistry.test.ts +1 -0
  555. package/src/theme/derivedVarRegistry.ts +6 -0
  556. package/src/theme/generateThemeRules.test.ts +42 -0
  557. package/src/utils/index.ts +2 -0
  558. package/src/utils/plainDate.test.ts +24 -6
  559. package/src/utils/plainDate.ts +18 -4
  560. package/src/utils/rtlStyles.ts +27 -0
@@ -16,7 +16,7 @@
16
16
  * - /packages/cli/templates/blocks/components/Timestamp/ (showcase blocks)
17
17
  */
18
18
 
19
- import {useEffect, useRef, useState, lazy, Suspense} from 'react';
19
+ import {useEffect, useRef, useState, lazy, Suspense, Fragment} from 'react';
20
20
  import * as stylex from '@stylexjs/stylex';
21
21
  import {Text} from '../Text';
22
22
  import type {TextType, TextSize, TextColor, TextWeight} from '../theme/types';
@@ -24,8 +24,10 @@ import {mergeProps, mergeRefs} from '../utils';
24
24
  import {useDevWarning} from '../hooks/useDevWarning';
25
25
  import type {BaseProps} from '../BaseProps';
26
26
  import {themeProps} from '../utils/themeProps';
27
- import {colorVars} from '../theme/tokens.stylex';
28
- import {SHARED_DATE_FORMAT_OPTIONS} from '../utils/plainDate';
27
+ import {colorVars, spacingVars} from '../theme/tokens.stylex';
28
+ import {formatInstant} from './formatInstant';
29
+ import {formatTooltipLines} from './tooltipEntries';
30
+ import type {TimestampTooltipEntry} from './tooltipEntries';
29
31
 
30
32
  const LazyXDSTooltip = lazy(async () =>
31
33
  import('../Tooltip/Tooltip').then(mod => ({default: mod.Tooltip})),
@@ -78,8 +80,35 @@ export interface TimestampProps extends BaseProps<HTMLTimeElement> {
78
80
  */
79
81
  hasTooltip?: boolean;
80
82
  /**
81
- * Whether to append the timezone abbreviation after the timestamp.
82
- * Applies to date_time, time, system_date_time, and system_time formats.
83
+ * Lines to show in the hover tooltip, so one instant can be read in several
84
+ * time zones and/or formats at once. Each entry is one line, rendered in the
85
+ * order given, with an optional label.
86
+ *
87
+ * Configuring entries also attaches the tooltip to absolute formats, which
88
+ * otherwise have no tooltip at all. `hasTooltip={false}` still suppresses it,
89
+ * and an empty array is treated as no configuration.
90
+ *
91
+ * @default undefined — a single line with the full absolute time in the
92
+ * viewer's own time zone
93
+ * @example
94
+ * ```
95
+ * <Timestamp
96
+ * value={savedAt}
97
+ * tooltipEntries={[
98
+ * {label: 'Your time'},
99
+ * {timezoneID: 'UTC', label: 'UTC'},
100
+ * ]}
101
+ * />
102
+ * ```
103
+ */
104
+ tooltipEntries?: ReadonlyArray<TimestampTooltipEntry>;
105
+ /**
106
+ * Whether to append the timezone abbreviation after the timestamp text.
107
+ * Applies to the date_time and time formats. The system_* formats stay
108
+ * machine-readable and never carry a timezone abbreviation.
109
+ *
110
+ * Affects the visible text only — use `tooltipEntries` to control the
111
+ * tooltip's time zones.
83
112
  * @default false
84
113
  */
85
114
  isTimezoneShown?: boolean;
@@ -137,6 +166,31 @@ const styles = stylex.create({
137
166
  ':focus-visible': '2px',
138
167
  },
139
168
  },
169
+ // Label/value pairs for a multi-entry tooltip. The label column is sized to
170
+ // its content, so when no entry carries a label it collapses to zero width
171
+ // and the values sit exactly where a plain list of lines would.
172
+ tooltipLines: {
173
+ display: 'grid',
174
+ gridTemplateColumns: 'auto 1fr',
175
+ rowGap: spacingVars['--spacing-0-5'],
176
+ marginBlock: 0,
177
+ marginInline: 0,
178
+ },
179
+ tooltipLabel: {
180
+ marginBlock: 0,
181
+ marginInline: 0,
182
+ // Only a label that actually has text earns the gutter, keeping the
183
+ // unlabeled case flush.
184
+ paddingInlineEnd: {
185
+ default: 0,
186
+ ':not(:empty)': spacingVars['--spacing-2'],
187
+ },
188
+ },
189
+ tooltipValue: {
190
+ marginBlock: 0,
191
+ // <dd> carries a 40px inline start margin from the UA stylesheet.
192
+ marginInline: 0,
193
+ },
140
194
  });
141
195
 
142
196
  // =============================================================================
@@ -244,89 +298,6 @@ function getRelativeTimeString(date: Date, now: Date): string {
244
298
  return `${years} ${years === 1 ? 'year' : 'years'} ago`;
245
299
  }
246
300
 
247
- function pad(n: number): string {
248
- return String(n).padStart(2, '0');
249
- }
250
-
251
- function formatTimestamp(
252
- date: Date,
253
- format: Exclude<TimestampFormat, 'relative' | 'auto'>,
254
- isTimezoneShown: boolean,
255
- ): string {
256
- switch (format) {
257
- case 'date':
258
- return new Intl.DateTimeFormat(
259
- undefined,
260
- SHARED_DATE_FORMAT_OPTIONS.date,
261
- ).format(date);
262
-
263
- case 'date_long':
264
- return new Intl.DateTimeFormat(
265
- undefined,
266
- SHARED_DATE_FORMAT_OPTIONS.date_long,
267
- ).format(date);
268
-
269
- case 'date_weekday':
270
- return new Intl.DateTimeFormat(
271
- undefined,
272
- SHARED_DATE_FORMAT_OPTIONS.date_weekday,
273
- ).format(date);
274
-
275
- case 'date_time':
276
- return new Intl.DateTimeFormat(undefined, {
277
- year: 'numeric',
278
- month: 'short',
279
- day: 'numeric',
280
- hour: 'numeric',
281
- minute: '2-digit',
282
- ...(isTimezoneShown ? {timeZoneName: 'short'} : {}),
283
- }).format(date);
284
-
285
- case 'time':
286
- return new Intl.DateTimeFormat(undefined, {
287
- hour: 'numeric',
288
- minute: '2-digit',
289
- ...(isTimezoneShown ? {timeZoneName: 'short'} : {}),
290
- }).format(date);
291
-
292
- case 'system_date': {
293
- const y = date.getFullYear();
294
- const m = pad(date.getMonth() + 1);
295
- const d = pad(date.getDate());
296
- return `${y}-${m}-${d}`;
297
- }
298
-
299
- case 'system_date_time': {
300
- const y = date.getFullYear();
301
- const m = pad(date.getMonth() + 1);
302
- const d = pad(date.getDate());
303
- const h = pad(date.getHours());
304
- const min = pad(date.getMinutes());
305
- const s = pad(date.getSeconds());
306
- return `${y}-${m}-${d} ${h}:${min}:${s}`;
307
- }
308
-
309
- case 'system_time': {
310
- const h = pad(date.getHours());
311
- const min = pad(date.getMinutes());
312
- const s = pad(date.getSeconds());
313
- return `${h}:${min}:${s}`;
314
- }
315
- }
316
- }
317
-
318
- function getFullAbsoluteString(date: Date): string {
319
- return new Intl.DateTimeFormat(undefined, {
320
- year: 'numeric',
321
- month: 'long',
322
- day: 'numeric',
323
- hour: 'numeric',
324
- minute: '2-digit',
325
- second: '2-digit',
326
- timeZoneName: 'short',
327
- }).format(date);
328
- }
329
-
330
301
  /** Returns the interval (in ms) at which a relative timestamp should update. */
331
302
  function getLiveInterval(diffSeconds: number): number {
332
303
  const absDiff = Math.abs(diffSeconds);
@@ -374,6 +345,7 @@ export function Timestamp({
374
345
  format = 'auto',
375
346
  autoThreshold = DEFAULT_AUTO_THRESHOLD,
376
347
  hasTooltip = true,
348
+ tooltipEntries,
377
349
  isTimezoneShown = false,
378
350
  isLive = false,
379
351
  type = 'supporting',
@@ -406,17 +378,18 @@ export function Timestamp({
406
378
  : 'date_time'
407
379
  : format;
408
380
 
409
- // Format the display text
381
+ // Format the display text. No time zone is passed: the visible text always
382
+ // reads in the viewer's own zone, and only the tooltip names others.
410
383
  const displayText = !isValidDate
411
384
  ? ''
412
385
  : effectiveFormat === 'relative'
413
386
  ? getRelativeTimeString(date, now)
414
387
  : isAbsoluteFormat(effectiveFormat)
415
- ? formatTimestamp(date, effectiveFormat, isTimezoneShown)
388
+ ? formatInstant(date, effectiveFormat, {isTimezoneShown})
416
389
  : '';
417
390
 
418
391
  // Full absolute text for tooltip and aria-label
419
- const fullAbsoluteText = isValidDate ? getFullAbsoluteString(date) : '';
392
+ const fullAbsoluteText = isValidDate ? formatInstant(date, 'full') : '';
420
393
 
421
394
  // Live updates
422
395
  useEffect(() => {
@@ -443,7 +416,19 @@ export function Timestamp({
443
416
  return null;
444
417
  }
445
418
 
446
- const showTooltip = hasTooltip && effectiveFormat === 'relative';
419
+ // An empty array is not a second way to spell "off" — `hasTooltip` stays the
420
+ // only on/off axis — so normalize it away before anything reads it.
421
+ const entries =
422
+ tooltipEntries !== undefined && tooltipEntries.length > 0
423
+ ? tooltipEntries
424
+ : undefined;
425
+
426
+ // Absolute formats have never carried a tooltip. Leaving that gate closed
427
+ // when a consumer has explicitly configured tooltip lines would let `format`
428
+ // silently suppress another prop's output, so entry presence opens it too.
429
+ // With no entries this reduces to the original condition exactly.
430
+ const showTooltip =
431
+ hasTooltip && (effectiveFormat === 'relative' || entries !== undefined);
447
432
 
448
433
  const timestampProps = mergeProps(
449
434
  themeProps('timestamp', {format: effectiveFormat}),
@@ -479,13 +464,31 @@ export function Timestamp({
479
464
  );
480
465
 
481
466
  if (showTooltip) {
467
+ // Built inside the branch so a timestamp without a tooltip allocates none
468
+ // of it. With no entries the content stays the bare string it has always
469
+ // been — no wrapper element is introduced around the default line.
470
+ const tooltipContent =
471
+ entries === undefined ? (
472
+ fullAbsoluteText
473
+ ) : (
474
+ <dl {...stylex.props(styles.tooltipLines)}>
475
+ {formatTooltipLines(date, entries).map((line, index) => (
476
+ // eslint-disable-next-line @eslint-react/no-array-index-key -- tooltip lines are fixed positional slots and two entries may legitimately be identical
477
+ <Fragment key={index}>
478
+ <dt {...stylex.props(styles.tooltipLabel)}>{line.label ?? ''}</dt>
479
+ <dd {...stylex.props(styles.tooltipValue)}>{line.value}</dd>
480
+ </Fragment>
481
+ ))}
482
+ </dl>
483
+ );
484
+
482
485
  return (
483
486
  <>
484
487
  {timeElement}
485
488
  <Suspense fallback={null}>
486
489
  <LazyXDSTooltip
487
490
  anchorRef={timeRef}
488
- content={fullAbsoluteText}
491
+ content={tooltipContent}
489
492
  placement="above"
490
493
  />
491
494
  </Suspense>
@@ -0,0 +1,218 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file formatInstant.ts
5
+ * @input A Date, one absolute format name, and an optional time zone
6
+ * @output That instant rendered as a string
7
+ * @position Leaf shared by Timestamp's visible text and each of its tooltip
8
+ * lines; owns every absolute format Timestamp can produce
9
+ *
10
+ * Timestamp renders the same instant on two surfaces — the visible text and,
11
+ * on hover, one line per configured time zone. They differ only in which zone
12
+ * they name and whether they carry a zone abbreviation, so they are one
13
+ * formatter parameterized by zone rather than two switches that have to be
14
+ * kept in step by hand. Adding a member to `TimestampFormat` now fails to
15
+ * compile in exactly one place.
16
+ *
17
+ * Each caller keeps its own policy for the zone abbreviation: the visible text
18
+ * takes it straight from the `isTimezoneShown` prop, a tooltip line derives it
19
+ * from how many zones are on screen (see tooltipEntries.ts). Only the
20
+ * rendering is shared, not the decision.
21
+ *
22
+ * Omitting `timeZone` means the viewer's own zone. That path hands `Intl` no
23
+ * `timeZone` and keeps `system_*` on plain `Date` getters, so it produces
24
+ * exactly what it produced before this module existed.
25
+ *
26
+ * SYNC: When modified, update these files to stay in sync:
27
+ * - /packages/core/src/Timestamp/Timestamp.tsx
28
+ * - /packages/core/src/Timestamp/tooltipEntries.ts
29
+ * - /packages/core/src/Timestamp/Timestamp.test.tsx
30
+ */
31
+
32
+ import {SHARED_DATE_FORMAT_OPTIONS, getTimeZoneParts} from '../utils/plainDate';
33
+ import type {TimestampFormat} from './Timestamp';
34
+
35
+ // =============================================================================
36
+ // Types
37
+ // =============================================================================
38
+
39
+ /**
40
+ * Every format that names a fixed instant, plus `'full'` — the long absolute
41
+ * style ("February 19, 2026 at 5:00:00 PM UTC") that backs a relative
42
+ * timestamp's accessible name and the tooltip's default line.
43
+ *
44
+ * `'relative'` and `'auto'` are excluded: a relative phrase names no instant,
45
+ * so a zone could not change what it says.
46
+ */
47
+ export type InstantFormat =
48
+ | Exclude<TimestampFormat, 'relative' | 'auto'>
49
+ | 'full';
50
+
51
+ export interface FormatInstantOptions {
52
+ /**
53
+ * IANA time zone identifier. Omit for the viewer's own zone — which is what
54
+ * `Intl` already does with no `timeZone`, so the omitted path never
55
+ * constructs an explicit-zone formatter and cannot drift from the host
56
+ * default.
57
+ *
58
+ * Must already be one the platform accepts. An identifier `Intl` does not
59
+ * recognize throws a `RangeError` from its constructor, before any
60
+ * formatting happens; deciding what to do about that belongs to whoever
61
+ * took the identifier from a consumer, not here (tooltipEntries resolves
62
+ * and warns in `resolveTimezoneID`, then passes only what survived).
63
+ */
64
+ timeZone?: string;
65
+ /**
66
+ * Whether to append the zone abbreviation. Honoured by `date_time` and
67
+ * `time` only: `'full'` always carries one because that is the style, and
68
+ * the `system_*` shapes never do — a trailing "PST" would break anything
69
+ * parsing them, which is why `isTimezoneShown` has never applied to them.
70
+ * @default false
71
+ */
72
+ isTimezoneShown?: boolean;
73
+ }
74
+
75
+ // =============================================================================
76
+ // Option bags
77
+ // =============================================================================
78
+
79
+ /** The long absolute style, with seconds and a zone name. */
80
+ const FULL_OPTIONS: Intl.DateTimeFormatOptions = {
81
+ year: 'numeric',
82
+ month: 'long',
83
+ day: 'numeric',
84
+ hour: 'numeric',
85
+ minute: '2-digit',
86
+ second: '2-digit',
87
+ timeZoneName: 'short',
88
+ };
89
+
90
+ /** The time-of-day part, shared by `time` and `date_time`. */
91
+ const TIME_OPTIONS: Intl.DateTimeFormatOptions = {
92
+ hour: 'numeric',
93
+ minute: '2-digit',
94
+ };
95
+
96
+ /**
97
+ * The date part here is spelled out rather than taken from
98
+ * `SHARED_DATE_FORMAT_OPTIONS.date`. That bag is shared with DateInput, and
99
+ * pointing `date_time` at it would mean a change made for date-only fields
100
+ * silently reshaped every date-and-time reading too. The two agree today; they
101
+ * are not the same decision.
102
+ */
103
+ const DATE_TIME_OPTIONS: Intl.DateTimeFormatOptions = {
104
+ year: 'numeric',
105
+ month: 'short',
106
+ day: 'numeric',
107
+ ...TIME_OPTIONS,
108
+ };
109
+
110
+ // =============================================================================
111
+ // Formatting
112
+ // =============================================================================
113
+
114
+ function pad(n: number): string {
115
+ return String(n).padStart(2, '0');
116
+ }
117
+
118
+ /** The fields a `system_*` string is assembled from. */
119
+ interface WallClock {
120
+ year: number;
121
+ month: number;
122
+ day: number;
123
+ hour: number;
124
+ minute: number;
125
+ second: number;
126
+ }
127
+
128
+ /**
129
+ * Wall-clock fields for an instant: in the named zone, or — with no zone —
130
+ * the viewer's own, read straight off the `Date`. The zone-less branch
131
+ * deliberately stays on plain getters so the default rendering never gains a
132
+ * dependency on `Intl` zone data it did not have before.
133
+ *
134
+ * The explicit return type is load-bearing: it is what forces the two branches
135
+ * to keep producing the same shape.
136
+ */
137
+ function getWallClock(date: Date, timeZone: string | undefined): WallClock {
138
+ return timeZone === undefined
139
+ ? {
140
+ year: date.getFullYear(),
141
+ month: date.getMonth() + 1,
142
+ day: date.getDate(),
143
+ hour: date.getHours(),
144
+ minute: date.getMinutes(),
145
+ second: date.getSeconds(),
146
+ }
147
+ : getTimeZoneParts(date.getTime(), timeZone);
148
+ }
149
+
150
+ /**
151
+ * Renders one instant in one absolute format.
152
+ *
153
+ * Pure: the same arguments always produce the same string for a given host
154
+ * locale (and, when no `timeZone` is given, host zone).
155
+ */
156
+ export function formatInstant(
157
+ date: Date,
158
+ format: InstantFormat,
159
+ {timeZone, isTimezoneShown = false}: FormatInstantOptions = {},
160
+ ): string {
161
+ const zone = timeZone === undefined ? {} : {timeZone};
162
+ const zoneName = isTimezoneShown ? {timeZoneName: 'short' as const} : {};
163
+
164
+ switch (format) {
165
+ case 'full':
166
+ return new Intl.DateTimeFormat(undefined, {
167
+ ...FULL_OPTIONS,
168
+ ...zone,
169
+ }).format(date);
170
+
171
+ case 'date':
172
+ return new Intl.DateTimeFormat(undefined, {
173
+ ...SHARED_DATE_FORMAT_OPTIONS.date,
174
+ ...zone,
175
+ }).format(date);
176
+
177
+ case 'date_long':
178
+ return new Intl.DateTimeFormat(undefined, {
179
+ ...SHARED_DATE_FORMAT_OPTIONS.date_long,
180
+ ...zone,
181
+ }).format(date);
182
+
183
+ case 'date_weekday':
184
+ return new Intl.DateTimeFormat(undefined, {
185
+ ...SHARED_DATE_FORMAT_OPTIONS.date_weekday,
186
+ ...zone,
187
+ }).format(date);
188
+
189
+ case 'date_time':
190
+ return new Intl.DateTimeFormat(undefined, {
191
+ ...DATE_TIME_OPTIONS,
192
+ ...zoneName,
193
+ ...zone,
194
+ }).format(date);
195
+
196
+ case 'time':
197
+ return new Intl.DateTimeFormat(undefined, {
198
+ ...TIME_OPTIONS,
199
+ ...zoneName,
200
+ ...zone,
201
+ }).format(date);
202
+
203
+ case 'system_date': {
204
+ const w = getWallClock(date, timeZone);
205
+ return `${w.year}-${pad(w.month)}-${pad(w.day)}`;
206
+ }
207
+
208
+ case 'system_date_time': {
209
+ const w = getWallClock(date, timeZone);
210
+ return `${w.year}-${pad(w.month)}-${pad(w.day)} ${pad(w.hour)}:${pad(w.minute)}:${pad(w.second)}`;
211
+ }
212
+
213
+ case 'system_time': {
214
+ const w = getWallClock(date, timeZone);
215
+ return `${pad(w.hour)}:${pad(w.minute)}:${pad(w.second)}`;
216
+ }
217
+ }
218
+ }
@@ -13,3 +13,7 @@
13
13
 
14
14
  export {Timestamp} from './Timestamp';
15
15
  export type {TimestampProps, TimestampFormat} from './Timestamp';
16
+ export type {
17
+ TimestampTooltipEntry,
18
+ TimestampTooltipFormat,
19
+ } from './tooltipEntries';