@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,126 @@
1
+ /**
2
+ * Browser side of the installable apps (Section 4.10, A65-023, ADR 0052): registering the service worker after the
3
+ * page hydrates, asking it to keep a page for offline reading, clearing it on sign-out, and the browser's push
4
+ * subscription. No React and no imports, so it adds a few hundred bytes to a route.
5
+ */
6
+
7
+ const SW_PATH = "/sw.js";
8
+ const REMEMBER_GAP_MS = 10_000;
9
+ let lastRemembered = 0;
10
+
11
+ /** True when the browser can run the service worker. */
12
+ export function serviceWorkerSupported(): boolean {
13
+ return typeof navigator !== "undefined" && "serviceWorker" in navigator;
14
+ }
15
+
16
+ /** Runs `task` once the page has loaded and the browser is idle, so registration never competes with hydration. */
17
+ export function afterHydration(task: () => void): void {
18
+ const idle = () => {
19
+ const w = window as Window & {
20
+ requestIdleCallback?: (cb: () => void, o?: { timeout: number }) => number;
21
+ };
22
+ if (typeof w.requestIdleCallback === "function") w.requestIdleCallback(task, { timeout: 5000 });
23
+ else window.setTimeout(task, 1500);
24
+ };
25
+ if (document.readyState === "complete") idle();
26
+ else window.addEventListener("load", idle, { once: true });
27
+ }
28
+
29
+ /** Registers /sw.js for the whole origin; null where it cannot run or registration fails. */
30
+ export async function registerServiceWorker(): Promise<ServiceWorkerRegistration | null> {
31
+ if (!serviceWorkerSupported()) return null;
32
+ try {
33
+ return await navigator.serviceWorker.register(SW_PATH, { scope: "/" });
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ function post(message: Record<string, unknown>): void {
40
+ if (!serviceWorkerSupported()) return;
41
+ const controller = navigator.serviceWorker.controller;
42
+ if (controller) controller.postMessage(message);
43
+ else void navigator.serviceWorker.ready.then((r) => r.active?.postMessage(message));
44
+ }
45
+
46
+ /**
47
+ * Asks the service worker to keep the page at `path` for offline reading: a page reached by client-side navigation
48
+ * never passes through it as a document. At most one request every 10 seconds; the worker skips a page it saved in
49
+ * the last 30 minutes.
50
+ */
51
+ export function rememberPage(path: string, now = Date.now()): boolean {
52
+ if (now - lastRemembered < REMEMBER_GAP_MS) return false;
53
+ lastRemembered = now;
54
+ post({ type: "remember", url: path });
55
+ return true;
56
+ }
57
+
58
+ /** Tells the service worker the person signed out: it deletes every saved page and unsubscribes from push. */
59
+ export function forgetOfflinePages(): void {
60
+ post({ type: "sign-out" });
61
+ }
62
+
63
+ // Push ------------------------------------------------------------------------------------------------------------
64
+
65
+ /** True when this browser can subscribe to Web Push. */
66
+ export function pushSupported(): boolean {
67
+ return (
68
+ serviceWorkerSupported() &&
69
+ typeof window !== "undefined" &&
70
+ "PushManager" in window &&
71
+ "Notification" in window
72
+ );
73
+ }
74
+
75
+ /** The VAPID public key, base64url, as the bytes PushManager.subscribe takes. */
76
+ export function applicationServerKey(base64Url: string): Uint8Array<ArrayBuffer> {
77
+ const padded =
78
+ base64Url.replaceAll("-", "+").replaceAll("_", "/") + "===".slice((base64Url.length + 3) % 4);
79
+ const binary = atob(padded);
80
+ const out = new Uint8Array(new ArrayBuffer(binary.length));
81
+ for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);
82
+ return out;
83
+ }
84
+
85
+ /** The browser's current push subscription, or null. */
86
+ export async function currentPushSubscription(): Promise<PushSubscription | null> {
87
+ if (!pushSupported()) return null;
88
+ const registration = await navigator.serviceWorker.getRegistration("/");
89
+ return registration ? registration.pushManager.getSubscription() : null;
90
+ }
91
+
92
+ /** Asks for permission and subscribes; returns the subscription as JSON, or the reason it did not. */
93
+ export async function subscribeToPush(
94
+ vapidPublicKey: string,
95
+ ): Promise<
96
+ | { readonly ok: true; readonly subscription: PushSubscriptionJSON }
97
+ | { readonly ok: false; readonly reason: "unsupported" | "blocked" | "failed" }
98
+ > {
99
+ if (!pushSupported()) return { ok: false, reason: "unsupported" };
100
+ const permission =
101
+ Notification.permission === "default"
102
+ ? await Notification.requestPermission()
103
+ : Notification.permission;
104
+ if (permission !== "granted") return { ok: false, reason: "blocked" };
105
+ try {
106
+ const registration = (await registerServiceWorker()) ?? (await navigator.serviceWorker.ready);
107
+ const subscription =
108
+ (await registration.pushManager.getSubscription()) ??
109
+ (await registration.pushManager.subscribe({
110
+ userVisibleOnly: true,
111
+ applicationServerKey: applicationServerKey(vapidPublicKey),
112
+ }));
113
+ return { ok: true, subscription: subscription.toJSON() };
114
+ } catch {
115
+ return { ok: false, reason: "failed" };
116
+ }
117
+ }
118
+
119
+ /** Unsubscribes this browser; returns the endpoint it had, or null. */
120
+ export async function unsubscribeFromPush(): Promise<string | null> {
121
+ const subscription = await currentPushSubscription();
122
+ if (!subscription) return null;
123
+ const endpoint = subscription.endpoint;
124
+ await subscription.unsubscribe();
125
+ return endpoint;
126
+ }
@@ -0,0 +1,40 @@
1
+ import tokens from "@xos/tokens/tokens.json";
2
+
3
+ /**
4
+ * Installable web apps (Section 4.10, A65-023, ADR 0052): what Atlas and Gateway share on the server for their web
5
+ * manifest, service worker and offline page. Browser helpers live in ./client.ts.
6
+ */
7
+
8
+ export { serviceWorkerScript, type ServiceWorkerConfig } from "./service-worker.ts";
9
+ export { OFFLINE_KEY_HEADER, offlineKey } from "./offline-key.ts";
10
+
11
+ /** Where each app serves its offline page; under /auth, which every route guard lets through. */
12
+ export const OFFLINE_PATH = "/auth/offline";
13
+
14
+ type Theme = "dark" | "light" | "sunlight";
15
+ interface ColorToken {
16
+ readonly name: string;
17
+ readonly value: Readonly<Record<Theme, string>>;
18
+ }
19
+
20
+ /** A theme's color token, from the token source of truth (@xos/tokens). */
21
+ export function tokenColor(name: string, theme: Theme): string {
22
+ const token = (tokens.color.tokens as readonly ColorToken[]).find((t) => t.name === name);
23
+ const value = token?.value[theme];
24
+ if (!value) throw new Error(`No ${theme} value for color token ${name}`);
25
+ return value;
26
+ }
27
+
28
+ /** The manifest's background and theme colors: the page canvas of the app's default theme. */
29
+ export function manifestColors(theme: Theme): { background_color: string; theme_color: string } {
30
+ const canvas = tokenColor("bg-canvas", theme);
31
+ return { background_color: canvas, theme_color: canvas };
32
+ }
33
+
34
+ /** Browser toolbar colors for each color scheme, for a layout's viewport themeColor. */
35
+ export function themeColors(): { media: string; color: string }[] {
36
+ return [
37
+ { media: "(prefers-color-scheme: dark)", color: tokenColor("bg-canvas", "dark") },
38
+ { media: "(prefers-color-scheme: light)", color: tokenColor("bg-canvas", "light") },
39
+ ];
40
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The offline page cache key the proxies set (A96, ADR 0052). Its own module, so a proxy imports a few lines and
3
+ * none of the service worker source or the tokens.
4
+ */
5
+
6
+ /** Response header naming the signed-in person's offline cache: a hash, never the id itself. */
7
+ export const OFFLINE_KEY_HEADER = "x-xos-offline-key";
8
+
9
+ /**
10
+ * The key of a person's offline page cache: the first 128 bits of SHA-256 over their sign-in id, hex. The proxy sets
11
+ * it on the pages it serves to that person, so the service worker files each page under its own person.
12
+ */
13
+ export async function offlineKey(userId: string): Promise<string> {
14
+ const digest = new Uint8Array(
15
+ await crypto.subtle.digest("SHA-256", new TextEncoder().encode(`xos-offline:${userId}`)),
16
+ );
17
+ return Array.from(digest.slice(0, 16), (b) => b.toString(16).padStart(2, "0")).join("");
18
+ }
@@ -0,0 +1,229 @@
1
+ /**
2
+ * The service worker Atlas and Gateway serve at /sw.js (Section 4.10, A65-023, ADR 0052), as script source: each
3
+ * app's app/sw.js/route.ts answers with serviceWorkerScript(...). It is plain JavaScript with no imports, so the route
4
+ * budgets (ADR 0027) never count it, and it is registered only after hydration.
5
+ *
6
+ * What it caches, and what it never does:
7
+ * - Pages: a page loaded as a document is kept for offline reading only when the response names its signed-in
8
+ * person (the x-xos-offline-key header the proxy sets, a hash of the person's sign-in id). Pages live in a cache
9
+ * per person (xos-pages-<key>); a page of another person never lands in it, and the caches of everyone but the
10
+ * person last seen are deleted. At most 30 pages, the oldest dropped first.
11
+ * - Never: anything but a GET, any other origin, /auth, /api, token links (/advance, /sign, /ical, ?token=), React
12
+ * Server Component requests and every fetch the app makes itself. Server actions and API calls pass straight
13
+ * through, so no mutation and no API response is ever cached.
14
+ * - Build files under /_next/static are content-hashed and the same for everyone: cached on first use.
15
+ * - Sign-out (a POST to /auth/sign-out, or a "sign-out" message from the sign-in page) deletes every page cache
16
+ * and unsubscribes the browser from push, so the next person on the device sees nothing of the last.
17
+ * - Offline, a page navigation answers from the person's cache, else with the offline page precached at install.
18
+ * - Push: shows the notification the dispatcher sent (title, body, tag) and opens its path on this origin.
19
+ */
20
+
21
+ export interface ServiceWorkerConfig {
22
+ /** App name shown when a push carries no title. */
23
+ // The apps with a service worker, which equal app.shortcut_shell by coincidence; not that enum.
24
+ // eslint-disable-next-line xos/no-restated-enums
25
+ readonly app: "Atlas" | "Gateway";
26
+ /** Build release: a new value retires the previous build files' cache. */
27
+ readonly version: string;
28
+ /** Same-origin path of the offline page. */
29
+ readonly offlinePath: string;
30
+ /** Same-origin path of the notification icon. */
31
+ readonly icon: string;
32
+ }
33
+
34
+ const SOURCE = String.raw`"use strict";
35
+ const STATIC = "xos-static-" + CONFIG.version;
36
+ const OFFLINE = "xos-offline";
37
+ const META = "xos-meta";
38
+ const PAGES = "xos-pages-";
39
+ const USER = "/__xos/offline-user";
40
+ const KEY_HEADER = "x-xos-offline-key";
41
+ const SAVED_AT = "x-xos-saved-at";
42
+ const MAX_PAGES = 30;
43
+ const MAX_STATIC = 400;
44
+ const FRESH_MS = 30 * 60 * 1000;
45
+ const NEVER = /^\/(auth|api|advance|sign|shifts|onboard|forms|share|ical|\.well-known|__xos)(\/|$)|^\/(sw\.js|manifest\.webmanifest)$/;
46
+
47
+ function sameOrigin(url) {
48
+ return url.origin === self.location.origin;
49
+ }
50
+
51
+ function keepable(url) {
52
+ return sameOrigin(url) && !NEVER.test(url.pathname) && !url.searchParams.has("token") && !url.searchParams.has("_rsc");
53
+ }
54
+
55
+ function pageUrl(url) {
56
+ const copy = new URL(url.href);
57
+ copy.hash = "";
58
+ return copy.href;
59
+ }
60
+
61
+ async function currentUser() {
62
+ const meta = await caches.open(META);
63
+ const hit = await meta.match(USER);
64
+ return hit ? hit.text() : null;
65
+ }
66
+
67
+ async function setUser(key) {
68
+ const meta = await caches.open(META);
69
+ await meta.put(USER, new Response(key));
70
+ const names = await caches.keys();
71
+ await Promise.all(names.filter((n) => n.startsWith(PAGES) && n !== PAGES + key).map((n) => caches.delete(n)));
72
+ }
73
+
74
+ async function forget() {
75
+ const names = await caches.keys();
76
+ await Promise.all(names.filter((n) => n.startsWith(PAGES) || n === META).map((n) => caches.delete(n)));
77
+ try {
78
+ const subscription = await self.registration.pushManager.getSubscription();
79
+ if (subscription) await subscription.unsubscribe();
80
+ } catch (error) {
81
+ // Push may be unavailable; the caches are gone either way.
82
+ }
83
+ }
84
+
85
+ async function save(url, response) {
86
+ const key = response.headers.get(KEY_HEADER);
87
+ const type = response.headers.get("content-type") || "";
88
+ if (!key || !/^[0-9a-f]{32}$/.test(key) || response.status !== 200 || response.redirected || !type.includes("text/html")) {
89
+ return false;
90
+ }
91
+ if ((await currentUser()) !== key) await setUser(key);
92
+ const headers = new Headers(response.headers);
93
+ headers.set(SAVED_AT, String(Date.now()));
94
+ const body = await response.blob();
95
+ const cache = await caches.open(PAGES + key);
96
+ await cache.put(pageUrl(url), new Response(body, { status: 200, statusText: response.statusText, headers }));
97
+ const keys = await cache.keys();
98
+ for (const old of keys.slice(0, Math.max(0, keys.length - MAX_PAGES))) await cache.delete(old);
99
+ return true;
100
+ }
101
+
102
+ async function offlinePage(url) {
103
+ const user = await currentUser();
104
+ if (user) {
105
+ const hit = await (await caches.open(PAGES + user)).match(pageUrl(url), { ignoreVary: true });
106
+ if (hit) return hit;
107
+ }
108
+ const page = await (await caches.open(OFFLINE)).match(CONFIG.offlinePath, { ignoreVary: true });
109
+ return page || Response.error();
110
+ }
111
+
112
+ async function refreshOffline() {
113
+ try {
114
+ const response = await fetch(CONFIG.offlinePath, { credentials: "same-origin", cache: "no-store" });
115
+ if (response.status === 200) await (await caches.open(OFFLINE)).put(CONFIG.offlinePath, response);
116
+ } catch (error) {
117
+ // Offline at install: the next install or refresh tries again.
118
+ }
119
+ }
120
+
121
+ async function buildFile(request) {
122
+ const cache = await caches.open(STATIC);
123
+ const hit = await cache.match(request);
124
+ if (hit) return hit;
125
+ const response = await fetch(request);
126
+ if (response.status === 200) {
127
+ await cache.put(request, response.clone());
128
+ const keys = await cache.keys();
129
+ for (const old of keys.slice(0, Math.max(0, keys.length - MAX_STATIC))) await cache.delete(old);
130
+ }
131
+ return response;
132
+ }
133
+
134
+ async function remember(href) {
135
+ const url = new URL(href, self.location.origin);
136
+ if (!keepable(url)) return false;
137
+ const user = await currentUser();
138
+ if (user) {
139
+ const hit = await (await caches.open(PAGES + user)).match(pageUrl(url));
140
+ if (hit && Date.now() - Number(hit.headers.get(SAVED_AT)) < FRESH_MS) return false;
141
+ }
142
+ try {
143
+ const response = await fetch(url.href, { credentials: "same-origin", headers: { Accept: "text/html" } });
144
+ return await save(url, response);
145
+ } catch (error) {
146
+ return false;
147
+ }
148
+ }
149
+
150
+ self.addEventListener("install", (event) => {
151
+ event.waitUntil(refreshOffline().then(() => self.skipWaiting()));
152
+ });
153
+
154
+ self.addEventListener("activate", (event) => {
155
+ event.waitUntil(
156
+ (async () => {
157
+ const names = await caches.keys();
158
+ await Promise.all(names.filter((n) => n.startsWith("xos-static-") && n !== STATIC).map((n) => caches.delete(n)));
159
+ await self.clients.claim();
160
+ })(),
161
+ );
162
+ });
163
+
164
+ self.addEventListener("fetch", (event) => {
165
+ const request = event.request;
166
+ const url = new URL(request.url);
167
+ if (!sameOrigin(url)) return;
168
+ if (request.method !== "GET") {
169
+ if (request.method === "POST" && url.pathname === "/auth/sign-out") event.waitUntil(forget());
170
+ return;
171
+ }
172
+ if (url.pathname.startsWith("/_next/static/")) {
173
+ event.respondWith(buildFile(request));
174
+ return;
175
+ }
176
+ if (request.mode !== "navigate" || !keepable(url)) return;
177
+ event.respondWith(
178
+ (async () => {
179
+ try {
180
+ const response = await fetch(request);
181
+ event.waitUntil(save(url, response.clone()).catch(() => false));
182
+ return response;
183
+ } catch (error) {
184
+ return offlinePage(url);
185
+ }
186
+ })(),
187
+ );
188
+ });
189
+
190
+ self.addEventListener("message", (event) => {
191
+ const data = event.data || {};
192
+ if (data.type === "remember" && typeof data.url === "string") event.waitUntil(remember(data.url));
193
+ else if (data.type === "sign-out") event.waitUntil(forget());
194
+ else if (data.type === "refresh-offline") event.waitUntil(refreshOffline());
195
+ });
196
+
197
+ self.addEventListener("push", (event) => {
198
+ let data = {};
199
+ try {
200
+ data = event.data ? event.data.json() : {};
201
+ } catch (error) {
202
+ data = {};
203
+ }
204
+ const path = typeof data.url === "string" && data.url.startsWith("/") && !data.url.startsWith("//") ? data.url : "/";
205
+ const options = { body: typeof data.body === "string" ? data.body : "", data: { url: path }, icon: CONFIG.icon };
206
+ if (typeof data.tag === "string") options.tag = data.tag;
207
+ event.waitUntil(self.registration.showNotification(typeof data.title === "string" ? data.title : CONFIG.app, options));
208
+ });
209
+
210
+ self.addEventListener("notificationclick", (event) => {
211
+ event.notification.close();
212
+ const data = event.notification.data || {};
213
+ const target = new URL(typeof data.url === "string" ? data.url : "/", self.location.origin).href;
214
+ event.waitUntil(
215
+ (async () => {
216
+ const windows = await self.clients.matchAll({ type: "window", includeUncontrolled: true });
217
+ for (const client of windows) {
218
+ if (client.url === target && "focus" in client) return client.focus();
219
+ }
220
+ return self.clients.openWindow(target);
221
+ })(),
222
+ );
223
+ });
224
+ `;
225
+
226
+ /** The service worker's source for one app. */
227
+ export function serviceWorkerScript(config: ServiceWorkerConfig): string {
228
+ return `// XOS service worker for ${config.app} (A96, ADR 0052). Generated by @xos/ui/pwa; never cached by itself.\nconst CONFIG = ${JSON.stringify(config)};\n${SOURCE}`;
229
+ }
package/src/static.ts ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Components that render without hooks, context or event handlers, for React Server Components. A
3
+ * boundary that renders only these (a not-found page, a loading skeleton, a link styled as a Button)
4
+ * sends no JavaScript, while one that imports from "@xos/ui" needs a client module, which loads with
5
+ * every route (ADR 0027).
6
+ */
7
+ export { buttonClass } from "./Button/button-class.ts";
8
+ export { Skeleton, type SkeletonProps } from "./Surface/Skeleton.tsx";
9
+ export { TemplateSystemLink } from "./Templates/TemplateSystemLink.tsx";
10
+ export type { TemplateSystemLinkProps } from "./Templates/Templates.types.ts";
@@ -0,0 +1,208 @@
1
+ /* Base layer, ported from the design reference (components/bundle.css): the browser reset that the
2
+ Tailwind preflight does not cover, color-scheme per theme, the focus ring, platform defaults
3
+ (decision D7) and the component dimensions. Every value reads a token. */
4
+
5
+ /* Component dimensions. Sizes the token set does not name directly are derived from the 4 px space
6
+ scale here, once, so components never carry a raw length. */
7
+ :root {
8
+ --ui-hairline-half: calc(var(--stroke-width-hairline) * 1.5);
9
+ --ui-kbd: calc(var(--space-16) + var(--space-2));
10
+ --ui-tag: var(--space-20);
11
+ --ui-chip: calc(var(--space-20) + var(--space-2));
12
+ --ui-check: var(--space-16);
13
+ --ui-switch-knob: calc(var(--space-8) + var(--space-2));
14
+ --ui-avatar: var(--density-control-sm);
15
+ --ui-avatar-lg: var(--density-control-lg);
16
+ --ui-avatar-overlap: calc(var(--space-6) * -1);
17
+ --ui-dot: var(--space-6);
18
+ --ui-pip-inline: var(--space-4);
19
+ --ui-pip-block: calc(var(--space-8) + var(--space-2));
20
+ --ui-field: calc(var(--space-40) * 7);
21
+ --ui-alert: calc(var(--space-40) * 13);
22
+ --ui-empty: calc(var(--space-20) * 21);
23
+ --ui-skeleton-inline: calc(var(--space-40) * 4);
24
+ --ui-skeleton-block: var(--space-12);
25
+ --ui-command: var(--layout-peek);
26
+ --ui-dialog: var(--layout-peek-min);
27
+ --ui-drawer: var(--layout-auth);
28
+ --ui-popover: calc(var(--space-20) * 15);
29
+ --ui-hovercard: var(--layout-property-column);
30
+ --ui-menu-min: calc(var(--space-20) * 11);
31
+ --ui-listbox-max: calc(var(--space-40) * 6);
32
+ --ui-props-label: calc(var(--space-40) * 3);
33
+ --ui-sheet: var(--layout-form);
34
+ --ui-day-inline: calc(var(--space-32) + var(--space-2));
35
+ --ui-day-block: var(--space-32);
36
+ --ui-cmd-input: var(--space-48);
37
+ --ui-handle: var(--space-6);
38
+ --ui-split-list: calc(var(--space-20) * 15);
39
+ --ui-shell-head: calc(var(--space-40) + var(--space-4));
40
+ --ui-shell-min: calc(var(--space-20) * 21);
41
+ --ui-board-col: calc(var(--space-20) * 13);
42
+ --ui-tree: calc(var(--space-20) * 17);
43
+ --ui-rail-gap: var(--space-24);
44
+ --ui-topnav: calc(var(--space-48) + var(--space-8));
45
+ --ui-tabbar: calc(var(--space-64) * 6 + var(--space-6));
46
+ --ui-orgsw: var(--ui-field);
47
+ --ui-stat-min: calc(var(--space-40) * 5);
48
+ --ui-resizable-min: calc(var(--space-40) * 4);
49
+ --ui-split-min: calc(var(--space-40) * 7);
50
+ --ui-accordion-row: var(--space-40);
51
+ --ui-accordion-indent: calc(var(--space-12) + var(--icon-size-14) + var(--space-6));
52
+ --ui-step-line: var(--space-24);
53
+ --ui-peek-min: calc(var(--space-40) * 8);
54
+ --ui-settings-nav: calc(var(--space-20) * 11);
55
+ --ui-outline: calc(var(--space-20) * 9);
56
+ --ui-gateway-aside: calc(var(--space-20) * 19);
57
+
58
+ /* Compass: a 390 pt phone column with 16 pt gutters, 96 pt thumb controls. */
59
+ --ui-compass-card: calc(var(--ui-tabbar) - var(--space-32));
60
+ --ui-compass-thumb: calc(var(--space-48) * 2);
61
+ --ui-compass-card-min: calc(var(--space-40) * 4);
62
+ --ui-scan-view: calc(var(--space-20) * 15);
63
+ --ui-photo-view: calc(var(--space-20) * 21);
64
+ --ui-reticle-inline: calc(var(--space-20) * 11);
65
+ --ui-reticle-block: calc(var(--space-20) * 7);
66
+ --ui-grabber-inline: calc(var(--space-32) + var(--space-4));
67
+ --ui-grabber-block: calc(var(--space-4) + var(--stroke-width-hairline));
68
+ --ui-thumb: calc(var(--space-48) + var(--space-8));
69
+ --ui-shutter: calc(var(--space-64) + var(--space-8));
70
+ --ui-widget: calc(var(--space-40) * 4);
71
+ --ui-sigpad: calc(var(--space-40) * 3);
72
+ --ui-daysheet-time: calc(var(--space-64) + var(--space-8));
73
+ --ui-timer: var(--space-32);
74
+ }
75
+
76
+ @layer base {
77
+ html,
78
+ body {
79
+ background: var(--color-bg-canvas);
80
+ color: var(--color-text-primary);
81
+ }
82
+
83
+ /* Native controls, scrollbars and the overscroll canvas follow the theme, not the OS. */
84
+ :root,
85
+ [data-theme="dark"] {
86
+ color-scheme: dark;
87
+ }
88
+
89
+ [data-theme="light"],
90
+ [data-theme="sunlight"] {
91
+ color-scheme: light;
92
+ }
93
+
94
+ body {
95
+ margin: 0;
96
+ font: var(--typography-text-13);
97
+ -webkit-font-smoothing: antialiased;
98
+ }
99
+
100
+ /* Reset the defaults that differ between engines, matching the reference reset. */
101
+ :where(button) {
102
+ padding: 0;
103
+ font: inherit;
104
+ color: inherit;
105
+ }
106
+
107
+ :where(th, td) {
108
+ padding: 0;
109
+ }
110
+
111
+ :where(input, select, textarea) {
112
+ font: inherit;
113
+ padding: 0;
114
+ }
115
+
116
+ /* Focus is a 2 px focus-ring outline with a 2 px offset on every interactive element. */
117
+ :where(button, input, select, textarea, a, summary, [tabindex]):focus-visible {
118
+ outline: var(--stroke-width-focus) solid var(--color-focus-ring);
119
+ outline-offset: var(--space-2);
120
+ }
121
+
122
+ :where(input, select, textarea):focus-visible {
123
+ outline-offset: 0;
124
+ }
125
+ }
126
+
127
+ /* Reduced motion: movement becomes a short opacity fade or nothing. */
128
+ /* Phones show a sticky bottom tab bar (TabBar). Keyboard focus and scrollIntoView must stop above
129
+ it, or the bar hides the focused control (WCAG 2.4.11, A23-001). The bar is its top padding, one
130
+ touch target, its bottom padding and the device's safe area. */
131
+ :root {
132
+ --ui-bottom-bar: calc(
133
+ var(--space-6) + var(--density-touch-min) + var(--space-20) + env(safe-area-inset-bottom)
134
+ );
135
+ }
136
+
137
+ @media (width < 48rem) {
138
+ html:has([data-xos-bottom-bar]),
139
+ [data-xos-bottom-bar-scroll] {
140
+ scroll-padding-bottom: calc(var(--ui-bottom-bar) + var(--space-16));
141
+ }
142
+ }
143
+
144
+ @media (prefers-reduced-motion: reduce) {
145
+ :root:not([data-motion="full"]) *,
146
+ :root:not([data-motion="full"]) *::before,
147
+ :root:not([data-motion="full"]) *::after {
148
+ transition-duration: var(--motion-duration-reduced) !important;
149
+ animation-duration: var(--motion-duration-reduced) !important;
150
+ animation-iteration-count: 1 !important;
151
+ }
152
+ }
153
+
154
+ /* Display preferences (Section 4.5.6 Accessibility, A65-001), set on the document root from the person's
155
+ settings: me.reduced_motion reduce reduces motion whatever the device says (full keeps it even when the
156
+ device asks to reduce), me.high_contrast strengthens secondary text and borders, and me.text_size zooms the
157
+ page the way browser zoom does, since type sizes are fixed per token. */
158
+ :root[data-motion="reduce"] *,
159
+ :root[data-motion="reduce"] *::before,
160
+ :root[data-motion="reduce"] *::after {
161
+ transition-duration: var(--motion-duration-reduced) !important;
162
+ animation-duration: var(--motion-duration-reduced) !important;
163
+ animation-iteration-count: 1 !important;
164
+ }
165
+
166
+ :root[data-contrast="more"] {
167
+ --color-text-secondary: var(--color-text-primary);
168
+ --color-text-tertiary: var(--color-text-secondary);
169
+ --color-border-subtle: var(--color-border-strong);
170
+ --color-border-control: var(--color-border-strong);
171
+ }
172
+
173
+ :root[data-text-size="large"] body {
174
+ zoom: 1.125;
175
+ }
176
+
177
+ :root[data-text-size="larger"] body {
178
+ zoom: 1.25;
179
+ }
180
+
181
+ /* Forced colors: controls switch to system colors and keep borders and focus. */
182
+ @media (forced-colors: active) {
183
+ :where(button, input, [tabindex]):focus-visible {
184
+ outline-color: Highlight;
185
+ }
186
+
187
+ [aria-selected="true"],
188
+ [aria-current="page"] {
189
+ outline: var(--stroke-width-focus) solid Highlight;
190
+ }
191
+ }
192
+
193
+ /* Print: records, lists and reports on paper with no navigation chrome. */
194
+ @media print {
195
+ html,
196
+ body {
197
+ background: var(--color-paper) !important;
198
+ color: var(--color-paper-ink) !important;
199
+ }
200
+
201
+ table thead {
202
+ display: table-header-group;
203
+ }
204
+
205
+ table tr {
206
+ break-inside: avoid;
207
+ }
208
+ }