@ghxstship/xos-ui 0.0.0-stage → 4.16.0

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 (487) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +32 -2
  3. package/package.json +76 -4
  4. package/scripts/generate-stories.mjs +85 -0
  5. package/src/AIDisclosureBadge/README.md +7 -0
  6. package/src/AccessGridMatrix/README.md +3 -0
  7. package/src/Accordion/README.md +7 -0
  8. package/src/ActivityFeedItem/README.md +3 -0
  9. package/src/AgencySlate/README.md +3 -0
  10. package/src/AppShell/README.md +5 -0
  11. package/src/ApplicationForm/README.md +3 -0
  12. package/src/AssertionRankBadge/README.md +5 -0
  13. package/src/AvailabilityCalendar/README.md +3 -0
  14. package/src/Avatar/Avatar.tsx +56 -0
  15. package/src/Avatar/README.md +3 -0
  16. package/src/Avatar/avatar-class.ts +19 -0
  17. package/src/AvatarStack/README.md +3 -0
  18. package/src/Badge/README.md +3 -0
  19. package/src/Banner/README.md +3 -0
  20. package/src/BidSheet/README.md +3 -0
  21. package/src/Board/README.md +6 -0
  22. package/src/BrandMark/BrandMark.tsx +95 -0
  23. package/src/BrandMark/README.md +7 -0
  24. package/src/BrandSlot/README.md +6 -0
  25. package/src/Breadcrumbs/README.md +3 -0
  26. package/src/BudgetGrid/README.md +10 -0
  27. package/src/BulkActionBar/README.md +3 -0
  28. package/src/Button/Button.tsx +100 -0
  29. package/src/Button/README.md +10 -0
  30. package/src/Button/button-class.ts +54 -0
  31. package/src/ButtonLink/README.md +7 -0
  32. package/src/Calendar/README.md +3 -0
  33. package/src/Card/README.md +3 -0
  34. package/src/Chart/README.md +9 -0
  35. package/src/Charts/Calendar.tsx +228 -0
  36. package/src/Charts/Chart.tsx +547 -0
  37. package/src/Charts/Charts.tsx +20 -0
  38. package/src/Charts/Charts.types.ts +40 -0
  39. package/src/Charts/Gallery.tsx +25 -0
  40. package/src/Charts/Heatmap.tsx +116 -0
  41. package/src/Charts/OrgChart.tsx +53 -0
  42. package/src/Charts/ResourceSchedule.tsx +91 -0
  43. package/src/Charts/Sparkline.tsx +59 -0
  44. package/src/Charts/Timeline.tsx +777 -0
  45. package/src/Charts/categories.ts +21 -0
  46. package/src/Charts/timeline-plan.ts +191 -0
  47. package/src/Checkbox/README.md +6 -0
  48. package/src/ChecklistRunner/README.md +3 -0
  49. package/src/Chips/Badge.tsx +27 -0
  50. package/src/Chips/Chips.shared.tsx +34 -0
  51. package/src/Chips/Chips.tsx +21 -0
  52. package/src/Chips/Chips.types.ts +35 -0
  53. package/src/Chips/DepartmentChip.tsx +16 -0
  54. package/src/Chips/PhaseChip.tsx +16 -0
  55. package/src/Chips/PropertyChip.tsx +15 -0
  56. package/src/Chips/RecordKindChip.tsx +14 -0
  57. package/src/Chips/StateChip.tsx +19 -0
  58. package/src/Chips/Tag.tsx +47 -0
  59. package/src/Chips/URIDChip.tsx +14 -0
  60. package/src/Chips/chipClass.tsx +8 -0
  61. package/src/Chips/codeClass.tsx +6 -0
  62. package/src/ClockButton/README.md +6 -0
  63. package/src/CodeSample/README.md +7 -0
  64. package/src/ColorPicker/README.md +5 -0
  65. package/src/Combobox/README.md +7 -0
  66. package/src/CommandMenu/CommandMenu.tsx +179 -0
  67. package/src/CommandMenu/README.md +5 -0
  68. package/src/ComparisonTable/README.md +9 -0
  69. package/src/Compass/ChecklistRunner.tsx +128 -0
  70. package/src/Compass/ClockButton.tsx +57 -0
  71. package/src/Compass/Compass.shared.tsx +58 -0
  72. package/src/Compass/Compass.tsx +26 -0
  73. package/src/Compass/Compass.types.ts +79 -0
  74. package/src/Compass/DaySheetView.tsx +104 -0
  75. package/src/Compass/ForceUpdateScreen.tsx +29 -0
  76. package/src/Compass/LiveActivity.tsx +60 -0
  77. package/src/Compass/OfflineBanner.tsx +31 -0
  78. package/src/Compass/PhotoCapture.tsx +69 -0
  79. package/src/Compass/QuickIncidentSheet.tsx +46 -0
  80. package/src/Compass/ScanSheet.tsx +83 -0
  81. package/src/Compass/ShiftCard.tsx +55 -0
  82. package/src/Compass/SignaturePad.tsx +71 -0
  83. package/src/Compass/SyncConflictSheet.tsx +60 -0
  84. package/src/ConsentBanner/ConsentBanner.tsx +210 -0
  85. package/src/ConsentBanner/ConsentBannerStatic.tsx +163 -0
  86. package/src/ConsentBanner/ConsentSettings.tsx +213 -0
  87. package/src/ConsentBanner/README.md +101 -0
  88. package/src/ConsentBanner/consent.ts +238 -0
  89. package/src/ConsentBanner/index.ts +40 -0
  90. package/src/ConsentBanner/static.ts +11 -0
  91. package/src/ConsentBanner/useConsent.ts +160 -0
  92. package/src/ContextMenu/README.md +3 -0
  93. package/src/CoordinateMatrix/README.md +6 -0
  94. package/src/CredentialBadge/README.md +7 -0
  95. package/src/CurrencyInput/README.md +7 -0
  96. package/src/DataTable/DataTable.tsx +1034 -0
  97. package/src/DataTable/DataTableResizer.tsx +72 -0
  98. package/src/DataTable/DataTableVirtualizer.tsx +58 -0
  99. package/src/DataTable/README.md +9 -0
  100. package/src/DatePicker/README.md +5 -0
  101. package/src/DateRangePicker/README.md +3 -0
  102. package/src/DaySheetView/README.md +3 -0
  103. package/src/DepartmentChip/README.md +3 -0
  104. package/src/DepartmentGlyph/README.md +18 -0
  105. package/src/Dialog/README.md +3 -0
  106. package/src/DiffViewer/README.md +3 -0
  107. package/src/Divider/README.md +3 -0
  108. package/src/Drawer/README.md +3 -0
  109. package/src/DropdownMenu/README.md +3 -0
  110. package/src/EPKViewer/README.md +3 -0
  111. package/src/Editing/ColorPicker.tsx +125 -0
  112. package/src/Editing/DiffViewer.tsx +49 -0
  113. package/src/Editing/Editing.tsx +29 -0
  114. package/src/Editing/Editing.types.ts +71 -0
  115. package/src/Editing/FilterBuilder.tsx +72 -0
  116. package/src/Editing/QuickAdd.tsx +102 -0
  117. package/src/Editing/QuickAddChips.tsx +180 -0
  118. package/src/Editing/contrastRatio.tsx +11 -0
  119. package/src/Editing/parseQuickAdd.tsx +187 -0
  120. package/src/Editing/quickAddCore.ts +204 -0
  121. package/src/Editing/timeShorthand.ts +157 -0
  122. package/src/Editing/useQuickAdd.ts +201 -0
  123. package/src/EmergencyCodeCard/README.md +10 -0
  124. package/src/EmptyState/README.md +5 -0
  125. package/src/EngagementTimeline/README.md +3 -0
  126. package/src/ErrorState/README.md +3 -0
  127. package/src/FAQ/README.md +7 -0
  128. package/src/FeatureGrid/README.md +7 -0
  129. package/src/Feedback/Banner.tsx +40 -0
  130. package/src/Feedback/EmptyState.tsx +32 -0
  131. package/src/Feedback/ErrorState.tsx +32 -0
  132. package/src/Feedback/Feedback.shared.tsx +38 -0
  133. package/src/Feedback/Feedback.tsx +18 -0
  134. package/src/Feedback/Feedback.types.ts +40 -0
  135. package/src/Feedback/InlineAlert.tsx +19 -0
  136. package/src/Feedback/RefusalNotice.tsx +46 -0
  137. package/src/Feedback/RegionBoundary.tsx +102 -0
  138. package/src/Feedback/Toast.tsx +31 -0
  139. package/src/Feedback/ToastRegion.tsx +26 -0
  140. package/src/Feedback/UndoToast.tsx +97 -0
  141. package/src/FeedbackWidget/README.md +3 -0
  142. package/src/Field/Field.tsx +81 -0
  143. package/src/FileDrop/README.md +3 -0
  144. package/src/FilePreviewer/README.md +3 -0
  145. package/src/FilterBuilder/README.md +3 -0
  146. package/src/ForceUpdateScreen/README.md +3 -0
  147. package/src/Forms/Checkbox.tsx +14 -0
  148. package/src/Forms/CurrencyInput.tsx +40 -0
  149. package/src/Forms/Forms.shared.tsx +5 -0
  150. package/src/Forms/Forms.tsx +20 -0
  151. package/src/Forms/Forms.types.ts +33 -0
  152. package/src/Forms/Input.tsx +28 -0
  153. package/src/Forms/Money.tsx +15 -0
  154. package/src/Forms/NumberInput.tsx +85 -0
  155. package/src/Forms/Radio.tsx +31 -0
  156. package/src/Forms/Select.tsx +54 -0
  157. package/src/Forms/Switch.tsx +14 -0
  158. package/src/Forms/Textarea.tsx +30 -0
  159. package/src/Gallery/README.md +5 -0
  160. package/src/GateLifecycleRail/README.md +7 -0
  161. package/src/GateReadinessPanel/README.md +8 -0
  162. package/src/Gateway/AgencySlate.tsx +76 -0
  163. package/src/Gateway/ApplicationForm.tsx +48 -0
  164. package/src/Gateway/AvailabilityCalendar.tsx +82 -0
  165. package/src/Gateway/EPKViewer.tsx +77 -0
  166. package/src/Gateway/EngagementTimeline.tsx +43 -0
  167. package/src/Gateway/Gateway.shared.tsx +5 -0
  168. package/src/Gateway/Gateway.tsx +30 -0
  169. package/src/Gateway/Gateway.types.ts +69 -0
  170. package/src/Gateway/OnboardingPacket.tsx +61 -0
  171. package/src/Gateway/OpportunityCard.tsx +73 -0
  172. package/src/Gateway/OpportunityFilters.tsx +64 -0
  173. package/src/Gateway/PaymentTracker.tsx +71 -0
  174. package/src/Gateway/PayoutDetailsForm.tsx +62 -0
  175. package/src/Gateway/ProfileEditor.tsx +45 -0
  176. package/src/Gateway/ProgressBar.tsx +30 -0
  177. package/src/Gateway/RatingDialog.tsx +83 -0
  178. package/src/Gateway/UpNextCard.tsx +76 -0
  179. package/src/Glyphs/Glyphs.tsx +66 -0
  180. package/src/Grids/BidSheet.tsx +63 -0
  181. package/src/Grids/BudgetGrid.tsx +164 -0
  182. package/src/Grids/Grids.shared.tsx +5 -0
  183. package/src/Grids/Grids.tsx +11 -0
  184. package/src/Grids/Grids.types.ts +38 -0
  185. package/src/Grids/SpreadsheetGrid.tsx +445 -0
  186. package/src/Grids/columnTotal.tsx +14 -0
  187. package/src/Grids/glForCode.tsx +11 -0
  188. package/src/Grids/parseCell.tsx +16 -0
  189. package/src/Help/FeedbackWidget.tsx +89 -0
  190. package/src/Help/Help.tsx +14 -0
  191. package/src/Help/Help.types.ts +51 -0
  192. package/src/Help/HelpPanel.tsx +116 -0
  193. package/src/Help/NotificationCenter.tsx +100 -0
  194. package/src/Help/OnboardingChecklist.tsx +57 -0
  195. package/src/Help/ShortcutEditor.tsx +81 -0
  196. package/src/Help/WhatsNew.tsx +33 -0
  197. package/src/HelpPanel/README.md +5 -0
  198. package/src/HoverCard/README.md +3 -0
  199. package/src/Icon/Icon.tsx +47 -0
  200. package/src/Icon/README.md +9 -0
  201. package/src/IconButton/README.md +6 -0
  202. package/src/Identity/BrandSlot.tsx +20 -0
  203. package/src/Identity/BrandSlotFrame.tsx +38 -0
  204. package/src/Identity/CredentialBadge.tsx +92 -0
  205. package/src/Identity/Identity.tsx +14 -0
  206. package/src/Identity/Identity.types.ts +25 -0
  207. package/src/Identity/PresenceIndicator.tsx +37 -0
  208. package/src/Identity/QRCode.tsx +22 -0
  209. package/src/Identity/WhiteLabelPreview.tsx +33 -0
  210. package/src/Identity/qrPath.tsx +16 -0
  211. package/src/Identity/tokenVariable.tsx +9 -0
  212. package/src/InlineAlert/README.md +3 -0
  213. package/src/Input/README.md +8 -0
  214. package/src/Kbd/Kbd.tsx +30 -0
  215. package/src/Kbd/README.md +6 -0
  216. package/src/Layout/AppShell.tsx +151 -0
  217. package/src/Layout/Layout.tsx +14 -0
  218. package/src/Layout/Layout.types.ts +43 -0
  219. package/src/Layout/PageHeader.tsx +22 -0
  220. package/src/Layout/ResizablePanel.tsx +81 -0
  221. package/src/Layout/ScrollRegion.tsx +107 -0
  222. package/src/Layout/SplitView.tsx +78 -0
  223. package/src/Layout/Stepper.tsx +39 -0
  224. package/src/LegalText/LegalText.tsx +289 -0
  225. package/src/LegalText/README.md +10 -0
  226. package/src/LegalText/index.ts +29 -0
  227. package/src/LegalText/legal-markdown.ts +581 -0
  228. package/src/Link/Link.tsx +25 -0
  229. package/src/Link/README.md +5 -0
  230. package/src/Link/link-class.ts +10 -0
  231. package/src/LiveActivity/README.md +3 -0
  232. package/src/LogoSlotWall/README.md +7 -0
  233. package/src/MapView/README.md +5 -0
  234. package/src/Marketing/AIDisclosureBadge.tsx +31 -0
  235. package/src/Marketing/ButtonLink.tsx +32 -0
  236. package/src/Marketing/CodeSample.tsx +47 -0
  237. package/src/Marketing/ComparisonScroll.tsx +7 -0
  238. package/src/Marketing/ComparisonTable.tsx +104 -0
  239. package/src/Marketing/FAQ.tsx +26 -0
  240. package/src/Marketing/FeatureGrid.tsx +65 -0
  241. package/src/Marketing/GateLifecycleRail.tsx +52 -0
  242. package/src/Marketing/LogoSlotWall.tsx +53 -0
  243. package/src/Marketing/Marketing.tsx +49 -0
  244. package/src/Marketing/Marketing.types.ts +64 -0
  245. package/src/Marketing/MarketingFooter.tsx +88 -0
  246. package/src/Marketing/MarketingHero.tsx +45 -0
  247. package/src/Marketing/MarketingNav.tsx +76 -0
  248. package/src/Marketing/MarketingPoints.tsx +16 -0
  249. package/src/Marketing/MarketingSection.tsx +52 -0
  250. package/src/Marketing/PersonaSwitcher.tsx +137 -0
  251. package/src/Marketing/PriceDisplay.tsx +56 -0
  252. package/src/Marketing/PricingTable.tsx +122 -0
  253. package/src/Marketing/ProofStatStrip.tsx +35 -0
  254. package/src/Marketing/ScreenshotFrame.tsx +56 -0
  255. package/src/Marketing/SurfaceTriptych.tsx +43 -0
  256. package/src/Marketing/Testimonial.tsx +45 -0
  257. package/src/Marketing/marketing-copy.ts +25 -0
  258. package/src/Marketing/provided.tsx +36 -0
  259. package/src/MarketingFooter/README.md +7 -0
  260. package/src/MarketingHero/README.md +7 -0
  261. package/src/MarketingNav/README.md +7 -0
  262. package/src/MarketingSection/README.md +7 -0
  263. package/src/Media/FilePreviewer.tsx +86 -0
  264. package/src/Media/MapView.tsx +200 -0
  265. package/src/Media/Media.tsx +11 -0
  266. package/src/Media/Media.types.ts +47 -0
  267. package/src/Media/RichTextEditor.tsx +198 -0
  268. package/src/Media/toLngLat.tsx +13 -0
  269. package/src/Menus/ContextMenu.tsx +106 -0
  270. package/src/Menus/DropdownMenu.tsx +51 -0
  271. package/src/Menus/Menus.shared.tsx +67 -0
  272. package/src/Menus/Menus.tsx +13 -0
  273. package/src/Menus/Menus.types.ts +49 -0
  274. package/src/Menus/OrgSwitcher.tsx +69 -0
  275. package/src/Menus/compactTriggerClass.tsx +7 -0
  276. package/src/Menus/menuClass.tsx +4 -0
  277. package/src/Menus/menuItemClass.tsx +7 -0
  278. package/src/Menus/orgSwitcherTriggerClass.tsx +7 -0
  279. package/src/Money/README.md +6 -0
  280. package/src/MultiSelect/README.md +3 -0
  281. package/src/Navigation/Accordion.tsx +59 -0
  282. package/src/Navigation/Breadcrumbs.tsx +59 -0
  283. package/src/Navigation/MoreFields.tsx +42 -0
  284. package/src/Navigation/Navigation.shared.tsx +32 -0
  285. package/src/Navigation/Navigation.tsx +21 -0
  286. package/src/Navigation/Navigation.types.ts +63 -0
  287. package/src/Navigation/Pagination.tsx +30 -0
  288. package/src/Navigation/SegmentedControl.tsx +87 -0
  289. package/src/Navigation/Sidebar.tsx +106 -0
  290. package/src/Navigation/TabBar.tsx +61 -0
  291. package/src/Navigation/Tabs.tsx +79 -0
  292. package/src/Navigation/TopNav.tsx +86 -0
  293. package/src/Navigation/sidebar-classes.ts +18 -0
  294. package/src/NotificationCenter/README.md +3 -0
  295. package/src/NumberInput/README.md +3 -0
  296. package/src/OfflineBanner/README.md +3 -0
  297. package/src/OnboardingChecklist/README.md +3 -0
  298. package/src/OnboardingPacket/README.md +3 -0
  299. package/src/OpportunityCard/README.md +5 -0
  300. package/src/OpportunityFilters/README.md +3 -0
  301. package/src/OrgChart/README.md +5 -0
  302. package/src/OrgSwitcher/README.md +3 -0
  303. package/src/Overlays/Dialog.tsx +54 -0
  304. package/src/Overlays/Drawer.tsx +62 -0
  305. package/src/Overlays/HoverCard.tsx +59 -0
  306. package/src/Overlays/Overlays.shared.tsx +12 -0
  307. package/src/Overlays/Overlays.tsx +20 -0
  308. package/src/Overlays/Overlays.types.ts +66 -0
  309. package/src/Overlays/Popover.tsx +70 -0
  310. package/src/Overlays/PropertyList.tsx +19 -0
  311. package/src/Overlays/ShortcutSheet.tsx +62 -0
  312. package/src/Overlays/SidePeek.tsx +117 -0
  313. package/src/Overlays/Tooltip.tsx +73 -0
  314. package/src/Overlays/panelClass.tsx +6 -0
  315. package/src/Overlays/popoverPanelClass.tsx +6 -0
  316. package/src/PageHeader/README.md +3 -0
  317. package/src/Pagination/README.md +3 -0
  318. package/src/PaymentTracker/README.md +3 -0
  319. package/src/PayoutDetailsForm/README.md +3 -0
  320. package/src/PersonaSwitcher/README.md +7 -0
  321. package/src/PhaseChip/README.md +5 -0
  322. package/src/PhaseGlyph/README.md +17 -0
  323. package/src/PhotoCapture/README.md +3 -0
  324. package/src/Pickers/Combobox.tsx +91 -0
  325. package/src/Pickers/DatePicker.tsx +60 -0
  326. package/src/Pickers/DateRangePicker.tsx +78 -0
  327. package/src/Pickers/FileDrop.tsx +84 -0
  328. package/src/Pickers/MultiSelect.tsx +118 -0
  329. package/src/Pickers/Pickers.shared.tsx +337 -0
  330. package/src/Pickers/Pickers.tsx +17 -0
  331. package/src/Pickers/Pickers.types.ts +47 -0
  332. package/src/Pickers/Slider.tsx +59 -0
  333. package/src/Pickers/TimePicker.tsx +68 -0
  334. package/src/Pickers/rankOptions.tsx +12 -0
  335. package/src/Popover/README.md +3 -0
  336. package/src/PresenceIndicator/README.md +3 -0
  337. package/src/PriceDisplay/README.md +7 -0
  338. package/src/PricingTable/README.md +9 -0
  339. package/src/ProfileEditor/README.md +3 -0
  340. package/src/ProgressBar/README.md +3 -0
  341. package/src/ProofStatStrip/README.md +7 -0
  342. package/src/PropertyChip/README.md +3 -0
  343. package/src/ProvenanceBadge/README.md +3 -0
  344. package/src/QRCode/README.md +6 -0
  345. package/src/QuickAdd/README.md +5 -0
  346. package/src/QuickIncidentSheet/README.md +3 -0
  347. package/src/Radio/README.md +3 -0
  348. package/src/RadioChannelTable/README.md +7 -0
  349. package/src/RatingDialog/README.md +3 -0
  350. package/src/ReconciliationTable/README.md +3 -0
  351. package/src/RecordKindChip/README.md +3 -0
  352. package/src/RecordKindGlyph/README.md +34 -0
  353. package/src/RecordRow/README.md +7 -0
  354. package/src/RefusalNotice/README.md +5 -0
  355. package/src/ResizablePanel/README.md +3 -0
  356. package/src/ResourceSchedule/README.md +6 -0
  357. package/src/RichTextEditor/README.md +3 -0
  358. package/src/RichTextEditor/extensions.ts +217 -0
  359. package/src/RunOfShowLive/README.md +5 -0
  360. package/src/ScanSheet/README.md +3 -0
  361. package/src/ScreenshotFrame/README.md +7 -0
  362. package/src/ScrollRegion/README.md +9 -0
  363. package/src/SegmentedControl/README.md +5 -0
  364. package/src/Select/README.md +5 -0
  365. package/src/ShiftCard/README.md +3 -0
  366. package/src/ShortcutEditor/README.md +3 -0
  367. package/src/ShortcutSheet/README.md +3 -0
  368. package/src/SidePeek/README.md +6 -0
  369. package/src/Sidebar/README.md +5 -0
  370. package/src/SignaturePad/README.md +3 -0
  371. package/src/Skeleton/README.md +3 -0
  372. package/src/Slider/README.md +3 -0
  373. package/src/SplitView/README.md +3 -0
  374. package/src/SpreadsheetGrid/README.md +9 -0
  375. package/src/StalenessIndicator/README.md +3 -0
  376. package/src/StatTile/README.md +6 -0
  377. package/src/StateChip/README.md +6 -0
  378. package/src/StateIcon/README.md +6 -0
  379. package/src/StateIcon/StateIcon.tsx +127 -0
  380. package/src/StatusHeatmap/README.md +15 -0
  381. package/src/Stepper/README.md +3 -0
  382. package/src/Surface/Skeleton.tsx +21 -0
  383. package/src/Surface/Surface.tsx +63 -0
  384. package/src/SurfaceTriptych/README.md +7 -0
  385. package/src/Switch/README.md +5 -0
  386. package/src/SyncConflictSheet/README.md +3 -0
  387. package/src/TabBar/README.md +7 -0
  388. package/src/Tabs/README.md +6 -0
  389. package/src/Tag/README.md +3 -0
  390. package/src/TemplateAuth/README.md +6 -0
  391. package/src/TemplateCollection/README.md +6 -0
  392. package/src/TemplateDashboard/README.md +8 -0
  393. package/src/TemplateDocument/README.md +5 -0
  394. package/src/TemplateGatewayShell/README.md +5 -0
  395. package/src/TemplateGridEditor/README.md +3 -0
  396. package/src/TemplateRecord/README.md +3 -0
  397. package/src/TemplateSettings/README.md +5 -0
  398. package/src/TemplateSplitView/README.md +3 -0
  399. package/src/TemplateSystem/README.md +5 -0
  400. package/src/TemplateWizard/README.md +3 -0
  401. package/src/Templates/TemplateAuth.tsx +16 -0
  402. package/src/Templates/TemplateCollection.tsx +35 -0
  403. package/src/Templates/TemplateDashboard.tsx +200 -0
  404. package/src/Templates/TemplateDocument.tsx +24 -0
  405. package/src/Templates/TemplateGatewayShell.tsx +36 -0
  406. package/src/Templates/TemplateGridEditor.tsx +17 -0
  407. package/src/Templates/TemplateRecord.tsx +31 -0
  408. package/src/Templates/TemplateSettings.tsx +26 -0
  409. package/src/Templates/TemplateSplitView.tsx +27 -0
  410. package/src/Templates/TemplateSystem.tsx +19 -0
  411. package/src/Templates/TemplateSystemLink.tsx +55 -0
  412. package/src/Templates/TemplateWizard.tsx +43 -0
  413. package/src/Templates/Templates.tsx +29 -0
  414. package/src/Templates/Templates.types.ts +153 -0
  415. package/src/Testimonial/README.md +7 -0
  416. package/src/Textarea/README.md +3 -0
  417. package/src/TimePicker/README.md +5 -0
  418. package/src/Timeline/README.md +6 -0
  419. package/src/Toast/README.md +3 -0
  420. package/src/Tooltip/README.md +3 -0
  421. package/src/TopNav/README.md +5 -0
  422. package/src/TreeView/README.md +3 -0
  423. package/src/URIDChip/README.md +5 -0
  424. package/src/UndoToast/README.md +3 -0
  425. package/src/UpNextCard/README.md +6 -0
  426. package/src/Views/ActivityFeedItem.tsx +52 -0
  427. package/src/Views/Board.tsx +229 -0
  428. package/src/Views/BulkActionBar.tsx +76 -0
  429. package/src/Views/RecordList.tsx +146 -0
  430. package/src/Views/RecordRow.tsx +132 -0
  431. package/src/Views/StatTile.tsx +88 -0
  432. package/src/Views/TreeView.tsx +161 -0
  433. package/src/Views/Views.tsx +18 -0
  434. package/src/Views/Views.types.ts +99 -0
  435. package/src/WhatsNew/README.md +3 -0
  436. package/src/WhiteLabelPreview/README.md +8 -0
  437. package/src/XOS/AccessGridMatrix.tsx +111 -0
  438. package/src/XOS/AssertionRankBadge.tsx +27 -0
  439. package/src/XOS/CoordinateMatrix.tsx +123 -0
  440. package/src/XOS/EmergencyCodeCard.tsx +109 -0
  441. package/src/XOS/GateReadinessPanel.tsx +100 -0
  442. package/src/XOS/ProvenanceBadge.tsx +19 -0
  443. package/src/XOS/RadioChannelTable.tsx +50 -0
  444. package/src/XOS/ReconciliationTable.tsx +64 -0
  445. package/src/XOS/RunOfShowLive.tsx +97 -0
  446. package/src/XOS/StalenessIndicator.tsx +31 -0
  447. package/src/XOS/StatusHeatmap.tsx +200 -0
  448. package/src/XOS/XOS.shared.tsx +90 -0
  449. package/src/XOS/XOS.tsx +29 -0
  450. package/src/XOS/XOS.types.ts +99 -0
  451. package/src/XOS/resolveStep.tsx +16 -0
  452. package/src/brand/defaults/README.md +13 -0
  453. package/src/brand/defaults/app-icon.svg +6 -0
  454. package/src/brand/defaults/favicon.svg +6 -0
  455. package/src/brand/defaults/logo-dark.svg +6 -0
  456. package/src/brand/defaults/logo-light.svg +6 -0
  457. package/src/brand/defaults/splash.svg +6 -0
  458. package/src/index.ts +606 -0
  459. package/src/lib/context.tsx +156 -0
  460. package/src/lib/cx.ts +4 -0
  461. package/src/lib/format.ts +200 -0
  462. package/src/lib/hooks.ts +187 -0
  463. package/src/lib/i18n.ts +97 -0
  464. package/src/lib/icons.ts +45 -0
  465. package/src/lib/live.ts +92 -0
  466. package/src/lib/preferences.ts +242 -0
  467. package/src/lib/route-transition.tsx +22 -0
  468. package/src/lib/selection.ts +92 -0
  469. package/src/lib/shortcut-targets.ts +125 -0
  470. package/src/lib/theme.ts +50 -0
  471. package/src/lib/undo-stack.ts +125 -0
  472. package/src/marketing.ts +33 -0
  473. package/src/pwa/action-outcome.tsx +81 -0
  474. package/src/pwa/analytics.ts +236 -0
  475. package/src/pwa/browser-push.tsx +132 -0
  476. package/src/pwa/client.ts +126 -0
  477. package/src/pwa/index.ts +40 -0
  478. package/src/pwa/offline-key.ts +18 -0
  479. package/src/pwa/service-worker.ts +229 -0
  480. package/src/static.ts +10 -0
  481. package/src/styles/base.css +208 -0
  482. package/src/styles/components.css +453 -0
  483. package/src/styles/index.css +16 -0
  484. package/src/styles/marketing.css +1260 -0
  485. package/src/styles/reference.css +5792 -0
  486. package/src/types/reference.d.ts +1608 -0
  487. package/tailwind.config.cjs +3 -0
@@ -0,0 +1,102 @@
1
+ import { Component, type ErrorInfo, type ReactElement, type ReactNode } from "react";
2
+ import { useT } from "../lib/context.tsx";
3
+ import { Icon } from "../Icon/Icon.tsx";
4
+ import { Button } from "../Button/Button.tsx";
5
+ import { TONE_ICON, TONE_ICON_CLASS, alertClass } from "./Feedback.shared.tsx";
6
+
7
+ export interface RegionBoundaryProps {
8
+ children: ReactNode;
9
+ /** Replaces the default title ("This section did not load"), for example with the tile's name. */
10
+ title?: string;
11
+ /** Called once per caught error, for the app's error reporting. Pass-through errors are not reported. */
12
+ onError?: (error: unknown, info: ErrorInfo) => void;
13
+ /**
14
+ * Retry calls this with `reset`, so the app can fetch the region again and clear the error in one
15
+ * step (a router refresh and `reset` in one transition). Without it, Retry calls `reset` alone.
16
+ */
17
+ onRetry?: (reset: () => void) => void;
18
+ /**
19
+ * Errors that are control flow, not failures (a framework's redirect or not found), which the
20
+ * boundary throws on to the boundaries above it instead of showing Retry.
21
+ */
22
+ passThrough?: (error: unknown) => boolean;
23
+ /** The error clears when this changes, such as the route's path after a navigation. */
24
+ resetKey?: unknown;
25
+ }
26
+
27
+ interface State {
28
+ failed: boolean;
29
+ error: unknown;
30
+ resetKey: unknown;
31
+ }
32
+
33
+ /**
34
+ * One region of a page (a dashboard tile, a record panel, a peek section) that fails on its own: an
35
+ * error thrown while it renders replaces the region with a short alert and Retry, reported through
36
+ * `onError`, and the rest of the page keeps working. Retry renders the region again.
37
+ */
38
+ export class RegionBoundary extends Component<RegionBoundaryProps, State> {
39
+ override state: State = { failed: false, error: null, resetKey: this.props.resetKey };
40
+
41
+ static getDerivedStateFromError(error: unknown): Partial<State> {
42
+ return { failed: true, error };
43
+ }
44
+
45
+ static getDerivedStateFromProps(props: RegionBoundaryProps, state: State): Partial<State> | null {
46
+ if (Object.is(props.resetKey, state.resetKey)) return null;
47
+ return { failed: false, error: null, resetKey: props.resetKey };
48
+ }
49
+
50
+ override componentDidCatch(error: unknown, info: ErrorInfo): void {
51
+ if (this.props.passThrough?.(error)) return;
52
+ this.props.onError?.(error, info);
53
+ }
54
+
55
+ reset = (): void => {
56
+ this.setState({ failed: false, error: null });
57
+ };
58
+
59
+ retry = (): void => {
60
+ if (this.props.onRetry) this.props.onRetry(this.reset);
61
+ else this.reset();
62
+ };
63
+
64
+ override render(): ReactNode {
65
+ if (!this.state.failed) return this.props.children;
66
+ // Thrown from render, so the nearest boundary above this one catches it.
67
+ if (this.props.passThrough?.(this.state.error)) throw this.state.error;
68
+ return (
69
+ <RegionError
70
+ {...(this.props.title ? { title: this.props.title } : {})}
71
+ onRetry={this.retry}
72
+ />
73
+ );
74
+ }
75
+ }
76
+
77
+ /** What a failed region shows: the danger icon, what happened, that the page still works, and Retry. */
78
+ export function RegionError({
79
+ title,
80
+ onRetry,
81
+ }: {
82
+ title?: string;
83
+ onRetry: () => void;
84
+ }): ReactElement {
85
+ const t = useT();
86
+ return (
87
+ <div className={alertClass} role="alert">
88
+ <span className={TONE_ICON_CLASS.danger}>
89
+ <Icon name={TONE_ICON.danger} />
90
+ </span>
91
+ <div className="flex flex-col items-start gap-8">
92
+ <div className="flex flex-col gap-2">
93
+ <div className="font-semibold">{title ?? t("region.title")}</div>
94
+ <div className="text-text-secondary">{t("region.body")}</div>
95
+ </div>
96
+ <Button size="sm" icon="RefreshCw" onClick={onRetry}>
97
+ {t("action.retry")}
98
+ </Button>
99
+ </div>
100
+ </div>
101
+ );
102
+ }
@@ -0,0 +1,31 @@
1
+ import { useContext, type ReactElement } from "react";
2
+ import { Button } from "../Button/Button.tsx";
3
+ import { InToastRegion, toastClass } from "./Feedback.shared.tsx";
4
+ import { type ToastProps } from "./Feedback.types.ts";
5
+
6
+ /** Confirms a completed action, with an optional action and its shortcut. Announced politely. */
7
+ export function Toast({
8
+ message,
9
+ actionLabel,
10
+ actionIcon,
11
+ shortcut,
12
+ onAction,
13
+ }: ToastProps): ReactElement {
14
+ const inRegion = useContext(InToastRegion);
15
+ return (
16
+ <div className={toastClass} {...(inRegion ? {} : { role: "status" })}>
17
+ <span>{message}</span>
18
+ {actionLabel ? (
19
+ <Button
20
+ size="sm"
21
+ variant="ghost"
22
+ onClick={onAction}
23
+ {...(actionIcon ? { icon: actionIcon } : {})}
24
+ {...(shortcut ? { shortcut } : {})}
25
+ >
26
+ {actionLabel}
27
+ </Button>
28
+ ) : null}
29
+ </div>
30
+ );
31
+ }
@@ -0,0 +1,26 @@
1
+ import { type ReactElement, type ReactNode } from "react";
2
+ import { InToastRegion } from "./Feedback.shared.tsx";
3
+
4
+ /**
5
+ * A polite live region that stacks toasts at the bottom of the viewport. Mount it for the life of
6
+ * the page and render toasts into it: a live region added together with its content is often not
7
+ * announced.
8
+ */
9
+ export function ToastRegion({
10
+ label,
11
+ children,
12
+ }: {
13
+ label: string;
14
+ children?: ReactNode;
15
+ }): ReactElement {
16
+ return (
17
+ <section
18
+ aria-label={label}
19
+ aria-live="polite"
20
+ aria-atomic="false"
21
+ className="fixed bottom-16 end-16 z-toast flex flex-col items-end gap-8 max-w-[calc(100vw-var(--space-32))]"
22
+ >
23
+ <InToastRegion.Provider value={true}>{children}</InToastRegion.Provider>
24
+ </section>
25
+ );
26
+ }
@@ -0,0 +1,97 @@
1
+ import {
2
+ useContext,
3
+ useEffect,
4
+ useRef,
5
+ useState,
6
+ type CSSProperties,
7
+ type ReactElement,
8
+ } from "react";
9
+ import { useT } from "../lib/context.tsx";
10
+ import { Button } from "../Button/Button.tsx";
11
+ import { InToastRegion, toastClass } from "./Feedback.shared.tsx";
12
+ import { type UndoToastProps } from "./Feedback.types.ts";
13
+
14
+ /**
15
+ * Replaces a confirmation for a reversible action: 8 seconds with a visible timer, Undo on the
16
+ * button and on Cmd or Ctrl+Z. Shift+Cmd or Ctrl+Z is redo, not undo, and inside a text field the
17
+ * keys stay the field's own. The timer pauses while the pointer is over the toast or focus is in it
18
+ * (WCAG 2.2.1, Timing Adjustable), and resumes with the time that was left.
19
+ */
20
+ export function UndoToast({
21
+ message,
22
+ seconds = 8,
23
+ onUndo,
24
+ onExpire,
25
+ undoLabel,
26
+ }: UndoToastProps): ReactElement {
27
+ const t = useT();
28
+ const inRegion = useContext(InToastRegion);
29
+ const [done, setDone] = useState(false);
30
+ const [paused, setPaused] = useState(false);
31
+ // Milliseconds still left on the timer, kept across pauses.
32
+ const left = useRef(seconds * 1000);
33
+ useEffect(() => {
34
+ if (done || paused) return undefined;
35
+ const started = Date.now();
36
+ const timer = setTimeout(() => {
37
+ setDone(true);
38
+ onExpire?.();
39
+ }, left.current);
40
+ const onKey = (e: KeyboardEvent) => {
41
+ if (
42
+ (e.metaKey || e.ctrlKey) &&
43
+ !e.shiftKey &&
44
+ e.key.toLowerCase() === "z" &&
45
+ // In a text field (anything editable: :read-write) the keys stay the field's own undo.
46
+ !(e.target as Element).matches?.(":read-write")
47
+ ) {
48
+ e.preventDefault();
49
+ setDone(true);
50
+ onUndo?.();
51
+ }
52
+ };
53
+ document.addEventListener("keydown", onKey);
54
+ return () => {
55
+ clearTimeout(timer);
56
+ left.current = Math.max(0, left.current - (Date.now() - started));
57
+ document.removeEventListener("keydown", onKey);
58
+ };
59
+ }, [done, paused, onUndo, onExpire]);
60
+ return (
61
+ <div
62
+ className={toastClass}
63
+ {...(inRegion ? {} : { role: "status" })}
64
+ onPointerEnter={() => setPaused(true)}
65
+ onPointerLeave={() => setPaused(false)}
66
+ onFocus={() => setPaused(true)}
67
+ onBlur={(e) => {
68
+ if (!e.currentTarget.contains(e.relatedTarget as Node | null)) setPaused(false);
69
+ }}
70
+ >
71
+ <span>{message}</span>
72
+ <Button
73
+ size="sm"
74
+ variant="ghost"
75
+ icon="Undo2"
76
+ shortcut="⌘Z"
77
+ disabled={done}
78
+ onClick={() => {
79
+ setDone(true);
80
+ onUndo?.();
81
+ }}
82
+ >
83
+ {undoLabel ?? t("action.undo")}
84
+ </Button>
85
+ <span
86
+ aria-hidden="true"
87
+ className="xos-anim-drain absolute start-0 bottom-0 h-(--stroke-width-focus) w-full bg-accent"
88
+ style={
89
+ {
90
+ "--xos-seconds": seconds,
91
+ animationPlayState: paused ? "paused" : "running",
92
+ } as CSSProperties
93
+ }
94
+ />
95
+ </div>
96
+ );
97
+ }
@@ -0,0 +1,3 @@
1
+ # FeedbackWidget
2
+
3
+ FeedbackWidget sends a message and an optional screenshot to the platform team and never captures anything the person did not approve.
@@ -0,0 +1,81 @@
1
+ import { useId, type CSSProperties, type ReactElement, type ReactNode } from "react";
2
+ import { cx } from "../lib/cx.ts";
3
+ import { Icon } from "../Icon/Icon.tsx";
4
+
5
+ /** Label, control and help or error, shared by every form field. */
6
+ export const fieldClass = cx("flex flex-col gap-4 w-(--ui-field) max-w-full box-border");
7
+ export const labelClass = cx("text-text-12 font-medium text-text-secondary");
8
+ export const helpClass = cx("text-text-12 text-text-secondary max-w-full");
9
+ export const errorClass = cx("flex items-center gap-4 text-text-12 text-danger-text");
10
+
11
+ /** The bordered control box shared by inputs, selects and triggers. */
12
+ export const controlClass = cx(
13
+ "h-control-md px-8 rounded-control border border-border-control bg-bg-surface text-text-primary",
14
+ "font-sans text-text-13 placeholder:text-text-tertiary",
15
+ "hover:not-focus-visible:border-text-tertiary focus-visible:border-transparent",
16
+ "aria-invalid:border-danger disabled:opacity-disabled disabled:cursor-not-allowed",
17
+ "pointer-coarse:min-h-target-coarse forced-colors:border-[CanvasText]",
18
+ "in-data-[theme=sunlight]:border-stroke-focus",
19
+ );
20
+
21
+ export function useFieldId(id: string | undefined): string {
22
+ const generated = useId();
23
+ return id ?? `xos-${generated.replace(/:/g, "")}`;
24
+ }
25
+
26
+ /** Ids for the help or error line that a control's aria-describedby points to. */
27
+ export function describedBy(id: string, help: string | undefined, error: string | undefined) {
28
+ return error ? `${id}-err` : help ? `${id}-help` : undefined;
29
+ }
30
+
31
+ export function widthStyle(width: number | string | undefined): CSSProperties | undefined {
32
+ return width === undefined ? undefined : { inlineSize: width };
33
+ }
34
+
35
+ export interface FieldProps {
36
+ id: string;
37
+ label?: ReactNode | undefined;
38
+ help?: ReactNode | undefined;
39
+ error?: ReactNode | undefined;
40
+ width?: number | string | undefined;
41
+ /** Renders the label as a plain caption when the control is not labelable (a group). */
42
+ labelFor?: boolean;
43
+ children: ReactNode;
44
+ }
45
+
46
+ export function Field({
47
+ id,
48
+ label,
49
+ help,
50
+ error,
51
+ width,
52
+ labelFor = true,
53
+ children,
54
+ }: FieldProps): ReactElement {
55
+ return (
56
+ <div className={fieldClass} style={widthStyle(width)}>
57
+ {label ? (
58
+ labelFor ? (
59
+ <label className={labelClass} htmlFor={id} id={`${id}-label`}>
60
+ {label}
61
+ </label>
62
+ ) : (
63
+ <span className={labelClass} id={`${id}-label`}>
64
+ {label}
65
+ </span>
66
+ )
67
+ ) : null}
68
+ {children}
69
+ {error ? (
70
+ <div className={errorClass} id={`${id}-err`}>
71
+ <Icon name="alert" size={12} />
72
+ {error}
73
+ </div>
74
+ ) : help ? (
75
+ <div className={helpClass} id={`${id}-help`}>
76
+ {help}
77
+ </div>
78
+ ) : null}
79
+ </div>
80
+ );
81
+ }
@@ -0,0 +1,3 @@
1
+ # FileDrop
2
+
3
+ FileDrop accepts files by drag or browse, with a keyboard-reachable input and a list of what was added.
@@ -0,0 +1,3 @@
1
+ # FilePreviewer
2
+
3
+ FilePreviewer shows PDF, image, video and Office files (through server conversion) with page thumbnails, zoom and download.
@@ -0,0 +1,3 @@
1
+ # FilterBuilder
2
+
3
+ FilterBuilder adds, edits and removes filters as chips and saves the result as a view.
@@ -0,0 +1,3 @@
1
+ # ForceUpdateScreen
2
+
3
+ ForceUpdateScreen blocks only when the installed version can no longer sync, and keeps the offline queue.
@@ -0,0 +1,14 @@
1
+ import { type ReactElement } from "react";
2
+ import { cx } from "../lib/cx.ts";
3
+ import { checkLabelClass } from "./Forms.shared.tsx";
4
+ import { type CheckboxProps } from "./Forms.types.ts";
5
+
6
+ /** A native checkbox with its label; the whole label is the target. */
7
+ export function Checkbox({ label, className, ...rest }: CheckboxProps): ReactElement {
8
+ return (
9
+ <label className={cx(checkLabelClass, className)}>
10
+ <input type="checkbox" {...rest} className="xos-check-input" />
11
+ {label}
12
+ </label>
13
+ );
14
+ }
@@ -0,0 +1,40 @@
1
+ import { useState, type ReactElement } from "react";
2
+ import { cx } from "../lib/cx.ts";
3
+ import { useT } from "../lib/context.tsx";
4
+ import { Field, controlClass, describedBy, useFieldId } from "../Field/Field.tsx";
5
+ import { type CurrencyInputProps } from "./Forms.types.ts";
6
+
7
+ /** A NULL-aware amount field: blank is unpriced and never coerced to 0. */
8
+ export function CurrencyInput({
9
+ label,
10
+ value,
11
+ currency = "USD",
12
+ help,
13
+ unpricedLabel,
14
+ id,
15
+ onChange,
16
+ }: CurrencyInputProps): ReactElement {
17
+ const t = useT();
18
+ const fieldId = useFieldId(id);
19
+ const [blank, setBlank] = useState(value === null || value === undefined);
20
+ const helpText = help ?? (blank ? t("money.blankHelp") : undefined);
21
+ return (
22
+ <Field id={fieldId} label={label} help={helpText}>
23
+ <div className="flex items-center gap-6">
24
+ <input
25
+ id={fieldId}
26
+ className={cx(controlClass, "flex-1 min-w-0 text-end tabular-nums")}
27
+ inputMode="decimal"
28
+ placeholder={unpricedLabel ?? t("money.unpriced")}
29
+ defaultValue={value === null || value === undefined ? "" : String(value)}
30
+ aria-describedby={describedBy(fieldId, helpText, undefined)}
31
+ onChange={(e) => {
32
+ setBlank(e.target.value.trim() === "");
33
+ onChange?.(e);
34
+ }}
35
+ />
36
+ <span className="text-text-12 text-text-tertiary">{currency}</span>
37
+ </div>
38
+ </Field>
39
+ );
40
+ }
@@ -0,0 +1,5 @@
1
+ import { cx } from "../lib/cx.ts";
2
+
3
+ export const checkLabelClass = cx(
4
+ "xos-check inline-flex items-center gap-8 cursor-pointer text-text-13",
5
+ );
@@ -0,0 +1,20 @@
1
+ export {
2
+ type InputProps,
3
+ type TextareaProps,
4
+ type SelectProps,
5
+ type CheckboxProps,
6
+ type SwitchProps,
7
+ type RadioProps,
8
+ type NumberInputProps,
9
+ type CurrencyInputProps,
10
+ type MoneyProps,
11
+ } from "./Forms.types.ts";
12
+ export { Input } from "./Input.tsx";
13
+ export { Textarea } from "./Textarea.tsx";
14
+ export { Select } from "./Select.tsx";
15
+ export { Checkbox } from "./Checkbox.tsx";
16
+ export { Switch } from "./Switch.tsx";
17
+ export { Radio } from "./Radio.tsx";
18
+ export { NumberInput } from "./NumberInput.tsx";
19
+ export { Money } from "./Money.tsx";
20
+ export { CurrencyInput } from "./CurrencyInput.tsx";
@@ -0,0 +1,33 @@
1
+ import type {
2
+ CheckboxProps as ReferenceCheckboxProps,
3
+ CurrencyInputProps as ReferenceCurrencyInputProps,
4
+ InputProps as ReferenceInputProps,
5
+ MoneyProps as ReferenceMoneyProps,
6
+ NumberInputProps as ReferenceNumberInputProps,
7
+ RadioProps as ReferenceRadioProps,
8
+ SelectProps as ReferenceSelectProps,
9
+ SwitchProps as ReferenceSwitchProps,
10
+ TextareaProps as ReferenceTextareaProps,
11
+ } from "../types/reference";
12
+
13
+ export type InputProps = ReferenceInputProps;
14
+
15
+ export type TextareaProps = ReferenceTextareaProps;
16
+
17
+ export type SelectProps = ReferenceSelectProps & { id?: string; name?: string };
18
+
19
+ export type CheckboxProps = ReferenceCheckboxProps;
20
+
21
+ export type SwitchProps = ReferenceSwitchProps;
22
+
23
+ export type RadioProps = ReferenceRadioProps;
24
+
25
+ export type NumberInputProps = ReferenceNumberInputProps & {
26
+ id?: string;
27
+ min?: number;
28
+ max?: number;
29
+ };
30
+
31
+ export type CurrencyInputProps = ReferenceCurrencyInputProps;
32
+
33
+ export type MoneyProps = ReferenceMoneyProps;
@@ -0,0 +1,28 @@
1
+ import { type ReactElement } from "react";
2
+ import { cx } from "../lib/cx.ts";
3
+ import { Field, controlClass, describedBy, useFieldId } from "../Field/Field.tsx";
4
+ import { type InputProps } from "./Forms.types.ts";
5
+
6
+ /** A labeled single-line field with help text or an inline error naming the field, problem and fix. */
7
+ export function Input({
8
+ label,
9
+ help,
10
+ error,
11
+ id,
12
+ width,
13
+ className,
14
+ ...rest
15
+ }: InputProps): ReactElement {
16
+ const fieldId = useFieldId(id);
17
+ return (
18
+ <Field id={fieldId} label={label} help={help} error={error} width={width}>
19
+ <input
20
+ id={fieldId}
21
+ aria-invalid={error ? true : undefined}
22
+ aria-describedby={describedBy(fieldId, help, error)}
23
+ {...rest}
24
+ className={cx(controlClass, className)}
25
+ />
26
+ </Field>
27
+ );
28
+ }
@@ -0,0 +1,15 @@
1
+ import { type ReactElement } from "react";
2
+ import { useFormat, useT } from "../lib/context.tsx";
3
+ import { type MoneyProps } from "./Forms.types.ts";
4
+
5
+ /** An amount with tabular numerals, or Unpriced when null. A blank price is Unpriced; a zero is a claim. */
6
+ export function Money({ amount, currency, unpricedLabel }: MoneyProps): ReactElement {
7
+ const t = useT();
8
+ const fmt = useFormat();
9
+ if (amount === null || amount === undefined) {
10
+ return (
11
+ <span className="text-text-secondary not-italic">{unpricedLabel ?? t("money.unpriced")}</span>
12
+ );
13
+ }
14
+ return <span className="tabular-nums">{fmt.currency(amount, currency)}</span>;
15
+ }
@@ -0,0 +1,85 @@
1
+ import { useState, type ChangeEvent, type ReactElement } from "react";
2
+ import { cx } from "../lib/cx.ts";
3
+ import { useT } from "../lib/context.tsx";
4
+ import { Icon } from "../Icon/Icon.tsx";
5
+ import { iconButtonClass } from "../Button/Button.tsx";
6
+ import { Field, controlClass, describedBy, useFieldId } from "../Field/Field.tsx";
7
+ import { type NumberInputProps } from "./Forms.types.ts";
8
+
9
+ function parseNumber(text: string): number | null {
10
+ if (text.trim() === "") return null;
11
+ const n = Number(text);
12
+ return Number.isFinite(n) ? n : null;
13
+ }
14
+
15
+ /** A number with units and steppers. Blank stays null, never 0; Arrow Up and Down step. */
16
+ export function NumberInput({
17
+ label,
18
+ help,
19
+ value,
20
+ unit,
21
+ step = 1,
22
+ placeholder: hint,
23
+ onChange,
24
+ id,
25
+ min,
26
+ max,
27
+ }: NumberInputProps): ReactElement {
28
+ const t = useT();
29
+ const fieldId = useFieldId(id);
30
+ const [current, setCurrent] = useState<number | null>(value ?? null);
31
+ const [text, setText] = useState(value === null || value === undefined ? "" : String(value));
32
+ const clamp = (n: number) => Math.min(max ?? Infinity, Math.max(min ?? -Infinity, n));
33
+ const set = (n: number | null) => {
34
+ const next = n === null ? null : clamp(n);
35
+ setCurrent(next);
36
+ setText(next === null ? "" : String(next));
37
+ onChange?.(next);
38
+ };
39
+ return (
40
+ <Field id={fieldId} label={label} help={help}>
41
+ <div className="flex items-center gap-4">
42
+ <button
43
+ type="button"
44
+ className={iconButtonClass()}
45
+ aria-label={t("number.decrease")}
46
+ onClick={() => set((current ?? 0) - step)}
47
+ >
48
+ <Icon name="Minus" size={14} />
49
+ </button>
50
+ <input
51
+ id={fieldId}
52
+ className={cx(controlClass, "flex-1 min-w-0 text-end tabular-nums")}
53
+ inputMode="decimal"
54
+ value={text}
55
+ placeholder={hint}
56
+ aria-describedby={describedBy(fieldId, help, undefined)}
57
+ onChange={(e: ChangeEvent<HTMLInputElement>) => {
58
+ setText(e.target.value);
59
+ const n = parseNumber(e.target.value);
60
+ setCurrent(n);
61
+ onChange?.(n);
62
+ }}
63
+ onKeyDown={(e) => {
64
+ if (e.key === "ArrowUp") {
65
+ e.preventDefault();
66
+ set((current ?? 0) + step);
67
+ } else if (e.key === "ArrowDown") {
68
+ e.preventDefault();
69
+ set((current ?? 0) - step);
70
+ }
71
+ }}
72
+ />
73
+ {unit ? <span className="text-text-12 text-text-tertiary">{unit}</span> : null}
74
+ <button
75
+ type="button"
76
+ className={iconButtonClass()}
77
+ aria-label={t("number.increase")}
78
+ onClick={() => set((current ?? 0) + step)}
79
+ >
80
+ <Icon name="Plus" size={14} />
81
+ </button>
82
+ </div>
83
+ </Field>
84
+ );
85
+ }
@@ -0,0 +1,31 @@
1
+ import { type ReactElement } from "react";
2
+ import { cx } from "../lib/cx.ts";
3
+ import { helpClass, labelClass, useFieldId } from "../Field/Field.tsx";
4
+ import { checkLabelClass } from "./Forms.shared.tsx";
5
+ import { type RadioProps } from "./Forms.types.ts";
6
+
7
+ /** A group of native radios in a fieldset; arrow keys move between options as the platform does. */
8
+ export function Radio({ label, name, value, options, onChange }: RadioProps): ReactElement {
9
+ const groupName = useFieldId(name);
10
+ return (
11
+ <fieldset className="flex flex-col gap-8 m-0 p-0 border-0">
12
+ <legend className={cx(labelClass, "mb-8")}>{label}</legend>
13
+ {options.map((o) => (
14
+ <label key={o.value} className={cx(checkLabelClass, "items-start")}>
15
+ <input
16
+ type="radio"
17
+ name={groupName}
18
+ value={o.value}
19
+ defaultChecked={value === o.value}
20
+ onChange={onChange}
21
+ className="xos-check-input"
22
+ />
23
+ <span className="flex flex-col">
24
+ <span>{o.label}</span>
25
+ {o.help ? <span className={helpClass}>{o.help}</span> : null}
26
+ </span>
27
+ </label>
28
+ ))}
29
+ </fieldset>
30
+ );
31
+ }