@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,76 @@
1
+ "use client";
2
+
3
+ import { useId, useState, type ReactElement } from "react";
4
+ import { cx } from "../lib/cx.ts";
5
+ import { useT } from "../lib/context.tsx";
6
+ import { iconButtonClass } from "../Button/button-class.ts";
7
+ import { Icon } from "../Icon/Icon.tsx";
8
+ import { type MarketingNavProps } from "./Marketing.types.ts";
9
+
10
+ function NavLinks({ links }: { links: MarketingNavProps["links"] }): ReactElement {
11
+ return (
12
+ <ul>
13
+ {links.map((link) => (
14
+ <li key={link.label}>
15
+ <a href={link.href} aria-current={link.current ? "page" : undefined}>
16
+ {link.label}
17
+ </a>
18
+ </li>
19
+ ))}
20
+ </ul>
21
+ );
22
+ }
23
+
24
+ /**
25
+ * The sticky header of a public page: skip link, brand, section links and the primary call to
26
+ * action. From bp-lg the links sit in the bar; below it they move into a panel opened by a labeled
27
+ * toggle. `actions` stays visible at every width.
28
+ */
29
+ export function MarketingNav({
30
+ brand,
31
+ homeHref = "/",
32
+ label,
33
+ links,
34
+ actions,
35
+ secondaryActions,
36
+ skipHref = "#main",
37
+ }: MarketingNavProps): ReactElement {
38
+ const t = useT();
39
+ const [open, setOpen] = useState(false);
40
+ const panelId = useId();
41
+ return (
42
+ <header className="xos-mkt-nav">
43
+ <a className="xos-mkt-skip" href={skipHref}>
44
+ {t("mk.skip")}
45
+ </a>
46
+ <div className="xos-mkt-wrap xos-mkt-nav-bar">
47
+ <a className="xos-mkt-nav-brand" href={homeHref}>
48
+ {brand}
49
+ </a>
50
+ <nav className="xos-mkt-nav-links" aria-label={label ?? t("nav.main")}>
51
+ <NavLinks links={links} />
52
+ </nav>
53
+ <div className="xos-mkt-nav-actions">
54
+ {secondaryActions ? (
55
+ <div className="xos-mkt-nav-secondary">{secondaryActions}</div>
56
+ ) : null}
57
+ {actions}
58
+ <button
59
+ type="button"
60
+ className={cx(iconButtonClass("ghost"), "xos-mkt-nav-toggle")}
61
+ aria-expanded={open}
62
+ aria-controls={panelId}
63
+ aria-label={t(open ? "mk.nav.close" : "mk.nav.menu")}
64
+ onClick={() => setOpen(!open)}
65
+ >
66
+ <Icon name={open ? "X" : "Menu"} />
67
+ </button>
68
+ </div>
69
+ </div>
70
+ <nav id={panelId} className="xos-mkt-nav-panel" hidden={!open} aria-label={t("mk.nav.menu")}>
71
+ <NavLinks links={links} />
72
+ {secondaryActions ? <div className="xos-mkt-actions">{secondaryActions}</div> : null}
73
+ </nav>
74
+ </header>
75
+ );
76
+ }
@@ -0,0 +1,16 @@
1
+ import { type ReactElement } from "react";
2
+ import { Icon } from "../Icon/Icon.tsx";
3
+
4
+ /** A checked list of short claims, shared by the persona, surface and plan cards. */
5
+ export function MarketingPoints({ points }: { points: string[] }): ReactElement {
6
+ return (
7
+ <ul className="xos-mkt-points">
8
+ {points.map((point) => (
9
+ <li key={point}>
10
+ <Icon name="Check" size={16} />
11
+ <span>{point}</span>
12
+ </li>
13
+ ))}
14
+ </ul>
15
+ );
16
+ }
@@ -0,0 +1,52 @@
1
+ import { type ReactElement } from "react";
2
+ import { cx } from "../lib/cx.ts";
3
+ import { Icon } from "../Icon/Icon.tsx";
4
+ import { type MarketingSectionProps } from "./Marketing.types.ts";
5
+
6
+ /**
7
+ * One section of a public page: eyebrow, heading, the direct answer that opens it, then its
8
+ * content. The heading labels the section when the section has an id.
9
+ */
10
+ export function MarketingSection({
11
+ id,
12
+ eyebrow,
13
+ glyph,
14
+ title,
15
+ lead,
16
+ badge,
17
+ tone = "canvas",
18
+ align = "start",
19
+ headingLevel = 2,
20
+ children,
21
+ }: MarketingSectionProps): ReactElement {
22
+ const Heading = `h${headingLevel}` as const;
23
+ const titleId = id ? `${id}-title` : undefined;
24
+ return (
25
+ <section
26
+ id={id}
27
+ aria-labelledby={titleId}
28
+ className={cx(
29
+ "xos-mkt-section",
30
+ tone === "surface" && "xos-mkt-section-surface",
31
+ align === "center" && "xos-mkt-center",
32
+ )}
33
+ >
34
+ <div className="xos-mkt-wrap">
35
+ <header className="xos-mkt-section-head">
36
+ {eyebrow ? (
37
+ <p className="xos-mkt-eyebrow">
38
+ {glyph ? <Icon name={glyph} size={14} /> : null}
39
+ {eyebrow}
40
+ </p>
41
+ ) : null}
42
+ <Heading id={titleId} className="xos-mkt-display-40">
43
+ {title}
44
+ </Heading>
45
+ {lead ? <p className="xos-mkt-lead">{lead}</p> : null}
46
+ {badge ?? null}
47
+ </header>
48
+ {children}
49
+ </div>
50
+ </section>
51
+ );
52
+ }
@@ -0,0 +1,137 @@
1
+ "use client";
2
+
3
+ import { useEffect, useId, useRef, useState, type KeyboardEvent, type ReactElement } from "react";
4
+ import { cx } from "../lib/cx.ts";
5
+ import { Icon } from "../Icon/Icon.tsx";
6
+ import { cardClass } from "../Surface/Surface.tsx";
7
+ import { ButtonLink } from "./ButtonLink.tsx";
8
+ import { MarketingPoints } from "./MarketingPoints.tsx";
9
+ import { type PersonaSwitcherProps } from "./Marketing.types.ts";
10
+
11
+ /**
12
+ * Tabs by audience. Every panel is rendered, so each audience's copy is in the document; the hash
13
+ * keeps the choice linkable (#for-finance). Arrow keys, Home and End move between tabs.
14
+ */
15
+ export function PersonaSwitcher({
16
+ label,
17
+ personas,
18
+ value,
19
+ hash = true,
20
+ hashPrefix = "for-",
21
+ onChange,
22
+ }: PersonaSwitcherProps): ReactElement {
23
+ const base = useId();
24
+ const [current, setCurrent] = useState(value ?? personas[0]?.value ?? "");
25
+ const tabs = useRef(new Map<string, HTMLButtonElement>());
26
+ const values = personas.map((persona) => persona.value).join("\n");
27
+
28
+ useEffect(() => {
29
+ if (!hash) return undefined;
30
+ const read = () => {
31
+ const target = decodeURIComponent(window.location.hash.replace(/^#/, ""));
32
+ const match = values.split("\n").find((v) => hashPrefix + v === target);
33
+ if (match !== undefined) setCurrent(match);
34
+ };
35
+ read();
36
+ window.addEventListener("hashchange", read);
37
+ return () => window.removeEventListener("hashchange", read);
38
+ }, [hash, hashPrefix, values]);
39
+
40
+ const pick = (next: string, focus: boolean) => {
41
+ setCurrent(next);
42
+ if (hash) {
43
+ try {
44
+ window.history.replaceState(null, "", `#${hashPrefix}${next}`);
45
+ } catch {
46
+ // A sandboxed frame refuses history writes; the tab still changes.
47
+ }
48
+ }
49
+ onChange?.(next);
50
+ if (focus) tabs.current.get(next)?.focus();
51
+ };
52
+
53
+ const onKeyDown = (event: KeyboardEvent<HTMLButtonElement>, index: number) => {
54
+ const count = personas.length;
55
+ const rtl = event.currentTarget.closest("[dir]")?.getAttribute("dir") === "rtl";
56
+ const step = event.key === "ArrowRight" ? 1 : event.key === "ArrowLeft" ? -1 : 0;
57
+ const next =
58
+ event.key === "Home"
59
+ ? 0
60
+ : event.key === "End"
61
+ ? count - 1
62
+ : step !== 0
63
+ ? (index + (rtl ? -step : step) + count) % count
64
+ : -1;
65
+ const persona = personas[next];
66
+ if (persona === undefined) return;
67
+ event.preventDefault();
68
+ pick(persona.value, true);
69
+ };
70
+
71
+ return (
72
+ <div className="xos-mkt-persona">
73
+ <div className="xos-mkt-persona-tabs" role="tablist" aria-label={label}>
74
+ {personas.map((persona, index) => {
75
+ const on = current === persona.value;
76
+ return (
77
+ <button
78
+ key={persona.value}
79
+ type="button"
80
+ role="tab"
81
+ id={`${base}t${index}`}
82
+ className="xos-mkt-persona-tab"
83
+ aria-selected={on}
84
+ aria-controls={`${base}p${index}`}
85
+ tabIndex={on ? 0 : -1}
86
+ ref={(el) => {
87
+ if (el) tabs.current.set(persona.value, el);
88
+ else tabs.current.delete(persona.value);
89
+ }}
90
+ onClick={() => pick(persona.value, false)}
91
+ onKeyDown={(event) => onKeyDown(event, index)}
92
+ >
93
+ {persona.icon ? <Icon name={persona.icon} size={14} /> : null}
94
+ {persona.label}
95
+ </button>
96
+ );
97
+ })}
98
+ </div>
99
+ {personas.map((persona, index) => (
100
+ <div
101
+ key={persona.value}
102
+ role="tabpanel"
103
+ id={`${base}p${index}`}
104
+ aria-labelledby={`${base}t${index}`}
105
+ className="xos-mkt-persona-panel"
106
+ hidden={current !== persona.value}
107
+ tabIndex={0}
108
+ >
109
+ <div className="xos-mkt-persona-copy">
110
+ <h3>{persona.title}</h3>
111
+ <p>{persona.body}</p>
112
+ {persona.primary || persona.secondary ? (
113
+ <div className="xos-mkt-actions">
114
+ {persona.primary ? (
115
+ <ButtonLink href={persona.primary.href} variant="primary" size="xl">
116
+ {persona.primary.label}
117
+ </ButtonLink>
118
+ ) : null}
119
+ {persona.secondary ? (
120
+ <ButtonLink href={persona.secondary.href} size="xl">
121
+ {persona.secondary.label}
122
+ </ButtonLink>
123
+ ) : null}
124
+ </div>
125
+ ) : null}
126
+ </div>
127
+ {persona.points ? (
128
+ <div className={cx(cardClass, "xos-mkt-persona-points")}>
129
+ {persona.pointsTitle ? <p className="xos-mkt-label">{persona.pointsTitle}</p> : null}
130
+ <MarketingPoints points={persona.points} />
131
+ </div>
132
+ ) : null}
133
+ </div>
134
+ ))}
135
+ </div>
136
+ );
137
+ }
@@ -0,0 +1,56 @@
1
+ import { type ReactElement } from "react";
2
+ import { marketingCopy } from "./marketing-copy.ts";
3
+ import { type PriceDisplayProps } from "./Marketing.types.ts";
4
+
5
+ /**
6
+ * One price with its billing period and tax label. A null amount is unpriced and renders Quoted,
7
+ * never zero; a plan sold by quote shows its starting price with "From". Whole amounts print
8
+ * without decimals.
9
+ */
10
+ export function PriceDisplay({
11
+ amount,
12
+ currency = "USD",
13
+ period,
14
+ taxMode,
15
+ from = false,
16
+ locale,
17
+ messages,
18
+ }: PriceDisplayProps): ReactElement {
19
+ const copy = marketingCopy({ locale, messages });
20
+ const { t } = copy;
21
+ const unpriced = amount === null || amount === undefined;
22
+ const digits = unpriced || Math.round(amount) === amount ? 0 : 2;
23
+ const money = unpriced
24
+ ? null
25
+ : new Intl.NumberFormat(copy.locale, {
26
+ style: "currency",
27
+ currency,
28
+ minimumFractionDigits: digits,
29
+ maximumFractionDigits: digits,
30
+ }).format(amount);
31
+ return (
32
+ <p className="xos-mkt-price">
33
+ <span className="xos-mkt-price-amount tabular-nums">
34
+ {money === null ? (
35
+ <span className="text-text-secondary not-italic">{t("mk.price.quoted")}</span>
36
+ ) : from ? (
37
+ t("mk.price.from", { price: money })
38
+ ) : (
39
+ money
40
+ )}
41
+ </span>
42
+ {money !== null && period ? (
43
+ <span className="xos-mkt-price-period">
44
+ {t(period === "year" ? "mk.price.perYear" : "mk.price.perMonth")}
45
+ </span>
46
+ ) : null}
47
+ {taxMode ? (
48
+ <span className="xos-mkt-price-tax">
49
+ {t(taxMode === "inclusive" ? "mk.price.taxInclusive" : "mk.price.taxExclusive", {
50
+ currency,
51
+ })}
52
+ </span>
53
+ ) : null}
54
+ </p>
55
+ );
56
+ }
@@ -0,0 +1,122 @@
1
+ "use client";
2
+
3
+ import { useState, type CSSProperties, type ReactElement } from "react";
4
+ import { cx } from "../lib/cx.ts";
5
+ import { useLocale, useMessages, useT } from "../lib/context.tsx";
6
+ import { SegmentedControl } from "../Navigation/SegmentedControl.tsx";
7
+ import { cardClass } from "../Surface/Surface.tsx";
8
+ import { ButtonLink } from "./ButtonLink.tsx";
9
+ import { MarketingPoints } from "./MarketingPoints.tsx";
10
+ import { PriceDisplay } from "./PriceDisplay.tsx";
11
+ import { type PricingTableProps } from "./Marketing.types.ts";
12
+
13
+ /**
14
+ * Plans side by side. The billing toggle announces its change, the terms sit with the plans, and
15
+ * no plan is preselected. A plan with no price for the period is unpriced and reads Quoted.
16
+ */
17
+ export function PricingTable({
18
+ periods,
19
+ period,
20
+ currency,
21
+ taxMode,
22
+ plans,
23
+ terms,
24
+ onChange,
25
+ }: PricingTableProps): ReactElement {
26
+ const t = useT();
27
+ const locale = useLocale();
28
+ const messages = useMessages();
29
+ const [selected, setSelected] = useState(period ?? periods[0]?.value ?? "");
30
+ const [announcement, setAnnouncement] = useState("");
31
+ const current = periods.find((p) => p.value === selected) ?? periods[0];
32
+
33
+ const change = (next: string) => {
34
+ setSelected(next);
35
+ const chosen = periods.find((p) => p.value === next);
36
+ if (chosen) setAnnouncement(t("mk.pricing.changed", { period: chosen.label }));
37
+ onChange?.(next);
38
+ };
39
+
40
+ return (
41
+ <div className="xos-mkt-pricing">
42
+ <div className="xos-mkt-pricing-bar">
43
+ <SegmentedControl
44
+ label={t("mk.pricing.period")}
45
+ value={selected}
46
+ options={periods.map((p) => ({ value: p.value, label: p.label }))}
47
+ onChange={change}
48
+ />
49
+ {periods.map((p) =>
50
+ p.note ? (
51
+ <span key={p.value} className="xos-mkt-note">
52
+ {p.note}
53
+ </span>
54
+ ) : null,
55
+ )}
56
+ <span className="sr-only" role="status" aria-live="polite">
57
+ {announcement}
58
+ </span>
59
+ </div>
60
+ <ul className="xos-mkt-plans" style={{ "--xos-mkt-n": plans.length } as CSSProperties}>
61
+ {plans.map((plan) => {
62
+ const quoted = plan.quoteFrom !== undefined;
63
+ const amount = plan.quoteFrom ?? plan.prices?.[selected] ?? null;
64
+ const free = amount === 0;
65
+ return (
66
+ <li
67
+ key={plan.name}
68
+ className={cx(cardClass, "xos-mkt-plan", plan.recommended && "xos-mkt-plan-rec")}
69
+ >
70
+ <div className="xos-mkt-plan-head">
71
+ <h3>{plan.name}</h3>
72
+ {plan.recommended ? (
73
+ <span className="xos-mkt-tag">{t("mk.pricing.recommended")}</span>
74
+ ) : null}
75
+ </div>
76
+ <p className="xos-mkt-plan-blurb">{plan.blurb}</p>
77
+ <PriceDisplay
78
+ amount={amount}
79
+ from={quoted}
80
+ period={free ? null : quoted ? "month" : (current?.unit ?? null)}
81
+ taxMode={free ? null : (taxMode ?? null)}
82
+ locale={locale}
83
+ messages={messages}
84
+ {...(currency === undefined ? {} : { currency })}
85
+ />
86
+ {plan.note ? <p className="xos-mkt-note">{plan.note}</p> : null}
87
+ {plan.cta ? (
88
+ <ButtonLink
89
+ href={plan.cta.href}
90
+ variant={plan.recommended ? "primary" : "secondary"}
91
+ size="xl"
92
+ className="xos-mkt-plan-cta"
93
+ >
94
+ {plan.cta.label}
95
+ </ButtonLink>
96
+ ) : null}
97
+ {plan.limits ? (
98
+ <dl className="xos-mkt-plan-limits">
99
+ {plan.limits.map((limit) => (
100
+ <div key={limit.label}>
101
+ <dt>{limit.label}</dt>
102
+ <dd className="tabular-nums">{limit.value}</dd>
103
+ </div>
104
+ ))}
105
+ </dl>
106
+ ) : null}
107
+ {plan.features ? (
108
+ <div className="xos-mkt-plan-features">
109
+ {plan.featuresTitle ? (
110
+ <p className="xos-mkt-label">{plan.featuresTitle}</p>
111
+ ) : null}
112
+ <MarketingPoints points={plan.features} />
113
+ </div>
114
+ ) : null}
115
+ </li>
116
+ );
117
+ })}
118
+ </ul>
119
+ {terms ? <p className="xos-mkt-note xos-mkt-pricing-terms">{terms}</p> : null}
120
+ </div>
121
+ );
122
+ }
@@ -0,0 +1,35 @@
1
+ import { type CSSProperties, type ReactElement } from "react";
2
+ import { formatNumber } from "../lib/format.ts";
3
+ import { marketingCopy } from "./marketing-copy.ts";
4
+ import { type ProofStatStripProps } from "./Marketing.types.ts";
5
+
6
+ /** Verifiable figures. Each one links to the file that proves it. */
7
+ export function ProofStatStrip({
8
+ label,
9
+ items,
10
+ locale,
11
+ messages,
12
+ }: ProofStatStripProps): ReactElement {
13
+ const copy = marketingCopy({ locale, messages });
14
+ return (
15
+ <ul
16
+ className="xos-mkt-proof"
17
+ aria-label={label}
18
+ style={{ "--xos-mkt-n": items.length } as CSSProperties}
19
+ >
20
+ {items.map((item) => (
21
+ <li key={item.label}>
22
+ <strong className="xos-mkt-proof-value tabular-nums">
23
+ {typeof item.value === "number" ? formatNumber(copy.locale, item.value) : item.value}
24
+ </strong>
25
+ <span className="xos-mkt-proof-label">{item.label}</span>
26
+ {item.source ? (
27
+ <a className="xos-mkt-proof-src" href={item.source.href}>
28
+ {copy.t("mk.proof.source", { label: item.source.label })}
29
+ </a>
30
+ ) : null}
31
+ </li>
32
+ ))}
33
+ </ul>
34
+ );
35
+ }
@@ -0,0 +1,56 @@
1
+ import { type ReactElement } from "react";
2
+ import { type ScreenshotFrameProps } from "./Marketing.types.ts";
3
+
4
+ /**
5
+ * A product image in a window frame, or live XOS components standing in for one. Live content is
6
+ * inert and exposed as one image named by `alt`, so it adds no tab stops and reads as a picture.
7
+ */
8
+ export function ScreenshotFrame({
9
+ src,
10
+ alt,
11
+ width,
12
+ height,
13
+ ratio = "16 / 10",
14
+ title,
15
+ chrome = true,
16
+ eager = false,
17
+ caption,
18
+ children,
19
+ }: ScreenshotFrameProps): ReactElement {
20
+ return (
21
+ <figure className="xos-mkt-shot">
22
+ {chrome ? (
23
+ <div className="xos-mkt-shot-bar" aria-hidden="true">
24
+ <i />
25
+ <i />
26
+ <i />
27
+ {title ? <span>{title}</span> : null}
28
+ </div>
29
+ ) : null}
30
+ {src ? (
31
+ <div className="xos-mkt-shot-view" style={{ aspectRatio: ratio }}>
32
+ <img
33
+ src={src}
34
+ alt={alt}
35
+ width={width}
36
+ height={height}
37
+ loading={eager ? "eager" : "lazy"}
38
+ decoding="async"
39
+ />
40
+ </div>
41
+ ) : (
42
+ <div
43
+ className="xos-mkt-shot-view xos-mkt-shot-live"
44
+ role="img"
45
+ aria-label={alt}
46
+ style={height === undefined ? undefined : { blockSize: height }}
47
+ >
48
+ <div inert aria-hidden="true">
49
+ {children}
50
+ </div>
51
+ </div>
52
+ )}
53
+ {caption ? <figcaption>{caption}</figcaption> : null}
54
+ </figure>
55
+ );
56
+ }
@@ -0,0 +1,43 @@
1
+ import { type ReactElement } from "react";
2
+ import { cx } from "../lib/cx.ts";
3
+ import { Icon } from "../Icon/Icon.tsx";
4
+ import { Tag } from "../Chips/Tag.tsx";
5
+ import { cardClass } from "../Surface/Surface.tsx";
6
+ import { linkClass } from "../Link/link-class.ts";
7
+ import { MarketingPoints } from "./MarketingPoints.tsx";
8
+ import { type SurfaceTriptychProps } from "./Marketing.types.ts";
9
+
10
+ /** The three surfaces side by side, each with its audience, its status and what it covers. */
11
+ export function SurfaceTriptych({ items }: SurfaceTriptychProps): ReactElement {
12
+ return (
13
+ <ul className="xos-mkt-grid xos-mkt-grid-3">
14
+ {items.map((item) => (
15
+ <li key={item.name} className={cx(cardClass, "xos-mkt-feature")}>
16
+ <div className="xos-mkt-feature-head">
17
+ {item.icon ? (
18
+ <span className="xos-mkt-tile" aria-hidden="true">
19
+ <Icon name={item.icon} size={16} />
20
+ </span>
21
+ ) : null}
22
+ <h3>{item.name}</h3>
23
+ {item.status ? (
24
+ <span className="xos-mkt-feature-status">
25
+ <Tag {...(item.status.tone === undefined ? {} : { tone: item.status.tone })}>
26
+ {item.status.label}
27
+ </Tag>
28
+ </span>
29
+ ) : null}
30
+ </div>
31
+ {item.audience ? <p className="xos-mkt-feature-aud">{item.audience}</p> : null}
32
+ <p>{item.body}</p>
33
+ {item.points ? <MarketingPoints points={item.points} /> : null}
34
+ {item.link ? (
35
+ <a href={item.link.href} className={cx(linkClass, "xos-mkt-feature-link")}>
36
+ {item.link.label}
37
+ </a>
38
+ ) : null}
39
+ </li>
40
+ ))}
41
+ </ul>
42
+ );
43
+ }
@@ -0,0 +1,45 @@
1
+ import { type ReactElement } from "react";
2
+ import { cx } from "../lib/cx.ts";
3
+ import { Icon } from "../Icon/Icon.tsx";
4
+ import { avatarClass, initials } from "../Avatar/avatar-class.ts";
5
+ import { cardClass } from "../Surface/Surface.tsx";
6
+ import { type TestimonialProps } from "./Marketing.types.ts";
7
+
8
+ /**
9
+ * A customer's words. The disclosure line is required: it states the speaker's connection to the
10
+ * publisher.
11
+ */
12
+ export function Testimonial({
13
+ quote,
14
+ name,
15
+ role,
16
+ org,
17
+ disclosure,
18
+ }: TestimonialProps): ReactElement {
19
+ return (
20
+ <figure className={cx(cardClass, "xos-mkt-quote")}>
21
+ <blockquote>
22
+ <p>{quote}</p>
23
+ </blockquote>
24
+ <figcaption>
25
+ <span
26
+ role="img"
27
+ aria-label={name}
28
+ title={name}
29
+ className={cx(avatarClass, "size-(--ui-avatar) text-text-11")}
30
+ >
31
+ {initials(name)}
32
+ </span>
33
+ <span className="xos-mkt-quote-who">
34
+ <strong>{name}</strong>
35
+ <span>{role}</span>
36
+ {org ? <span>{org}</span> : null}
37
+ </span>
38
+ </figcaption>
39
+ <p className="xos-mkt-quote-disclosure">
40
+ <Icon name="Info" size={12} />
41
+ <span>{disclosure}</span>
42
+ </p>
43
+ </figure>
44
+ );
45
+ }
@@ -0,0 +1,25 @@
1
+ import { currentConfig, translate, type Messages, type MessageVars } from "../lib/i18n.ts";
2
+
3
+ /** A locale and a `t` bound to it, for components that render without hooks or context. */
4
+ export interface MarketingCopy {
5
+ locale: string;
6
+ t: (key: string, vars?: MessageVars) => string;
7
+ }
8
+
9
+ /**
10
+ * Resolves the shared Marketing strings without a provider: the `locale` and `messages` props when
11
+ * the page gives them, otherwise what `configure` set. It reads no context, so a server component
12
+ * can call it (ADR 0027).
13
+ */
14
+ export function marketingCopy({
15
+ locale,
16
+ messages,
17
+ }: {
18
+ locale: string | undefined;
19
+ messages: Messages | undefined;
20
+ }): MarketingCopy {
21
+ const config = currentConfig();
22
+ const resolved = locale ?? config.locale;
23
+ const merged = messages === undefined ? config.messages : { ...config.messages, ...messages };
24
+ return { locale: resolved, t: (key, vars) => translate(resolved, key, vars, merged) };
25
+ }