@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.
- package/LICENSE +21 -0
- package/README.md +32 -2
- package/package.json +76 -4
- package/scripts/generate-stories.mjs +85 -0
- package/src/AIDisclosureBadge/README.md +7 -0
- package/src/AccessGridMatrix/README.md +3 -0
- package/src/Accordion/README.md +7 -0
- package/src/ActivityFeedItem/README.md +3 -0
- package/src/AgencySlate/README.md +3 -0
- package/src/AppShell/README.md +5 -0
- package/src/ApplicationForm/README.md +3 -0
- package/src/AssertionRankBadge/README.md +5 -0
- package/src/AvailabilityCalendar/README.md +3 -0
- package/src/Avatar/Avatar.tsx +56 -0
- package/src/Avatar/README.md +3 -0
- package/src/Avatar/avatar-class.ts +19 -0
- package/src/AvatarStack/README.md +3 -0
- package/src/Badge/README.md +3 -0
- package/src/Banner/README.md +3 -0
- package/src/BidSheet/README.md +3 -0
- package/src/Board/README.md +6 -0
- package/src/BrandMark/BrandMark.tsx +95 -0
- package/src/BrandMark/README.md +7 -0
- package/src/BrandSlot/README.md +6 -0
- package/src/Breadcrumbs/README.md +3 -0
- package/src/BudgetGrid/README.md +10 -0
- package/src/BulkActionBar/README.md +3 -0
- package/src/Button/Button.tsx +100 -0
- package/src/Button/README.md +10 -0
- package/src/Button/button-class.ts +54 -0
- package/src/ButtonLink/README.md +7 -0
- package/src/Calendar/README.md +3 -0
- package/src/Card/README.md +3 -0
- package/src/Chart/README.md +9 -0
- package/src/Charts/Calendar.tsx +228 -0
- package/src/Charts/Chart.tsx +547 -0
- package/src/Charts/Charts.tsx +20 -0
- package/src/Charts/Charts.types.ts +40 -0
- package/src/Charts/Gallery.tsx +25 -0
- package/src/Charts/Heatmap.tsx +116 -0
- package/src/Charts/OrgChart.tsx +53 -0
- package/src/Charts/ResourceSchedule.tsx +91 -0
- package/src/Charts/Sparkline.tsx +59 -0
- package/src/Charts/Timeline.tsx +777 -0
- package/src/Charts/categories.ts +21 -0
- package/src/Charts/timeline-plan.ts +191 -0
- package/src/Checkbox/README.md +6 -0
- package/src/ChecklistRunner/README.md +3 -0
- package/src/Chips/Badge.tsx +27 -0
- package/src/Chips/Chips.shared.tsx +34 -0
- package/src/Chips/Chips.tsx +21 -0
- package/src/Chips/Chips.types.ts +35 -0
- package/src/Chips/DepartmentChip.tsx +16 -0
- package/src/Chips/PhaseChip.tsx +16 -0
- package/src/Chips/PropertyChip.tsx +15 -0
- package/src/Chips/RecordKindChip.tsx +14 -0
- package/src/Chips/StateChip.tsx +19 -0
- package/src/Chips/Tag.tsx +47 -0
- package/src/Chips/URIDChip.tsx +14 -0
- package/src/Chips/chipClass.tsx +8 -0
- package/src/Chips/codeClass.tsx +6 -0
- package/src/ClockButton/README.md +6 -0
- package/src/CodeSample/README.md +7 -0
- package/src/ColorPicker/README.md +5 -0
- package/src/Combobox/README.md +7 -0
- package/src/CommandMenu/CommandMenu.tsx +179 -0
- package/src/CommandMenu/README.md +5 -0
- package/src/ComparisonTable/README.md +9 -0
- package/src/Compass/ChecklistRunner.tsx +128 -0
- package/src/Compass/ClockButton.tsx +57 -0
- package/src/Compass/Compass.shared.tsx +58 -0
- package/src/Compass/Compass.tsx +26 -0
- package/src/Compass/Compass.types.ts +79 -0
- package/src/Compass/DaySheetView.tsx +104 -0
- package/src/Compass/ForceUpdateScreen.tsx +29 -0
- package/src/Compass/LiveActivity.tsx +60 -0
- package/src/Compass/OfflineBanner.tsx +31 -0
- package/src/Compass/PhotoCapture.tsx +69 -0
- package/src/Compass/QuickIncidentSheet.tsx +46 -0
- package/src/Compass/ScanSheet.tsx +83 -0
- package/src/Compass/ShiftCard.tsx +55 -0
- package/src/Compass/SignaturePad.tsx +71 -0
- package/src/Compass/SyncConflictSheet.tsx +60 -0
- package/src/ConsentBanner/ConsentBanner.tsx +210 -0
- package/src/ConsentBanner/ConsentBannerStatic.tsx +163 -0
- package/src/ConsentBanner/ConsentSettings.tsx +213 -0
- package/src/ConsentBanner/README.md +101 -0
- package/src/ConsentBanner/consent.ts +238 -0
- package/src/ConsentBanner/index.ts +40 -0
- package/src/ConsentBanner/static.ts +11 -0
- package/src/ConsentBanner/useConsent.ts +160 -0
- package/src/ContextMenu/README.md +3 -0
- package/src/CoordinateMatrix/README.md +6 -0
- package/src/CredentialBadge/README.md +7 -0
- package/src/CurrencyInput/README.md +7 -0
- package/src/DataTable/DataTable.tsx +1034 -0
- package/src/DataTable/DataTableResizer.tsx +72 -0
- package/src/DataTable/DataTableVirtualizer.tsx +58 -0
- package/src/DataTable/README.md +9 -0
- package/src/DatePicker/README.md +5 -0
- package/src/DateRangePicker/README.md +3 -0
- package/src/DaySheetView/README.md +3 -0
- package/src/DepartmentChip/README.md +3 -0
- package/src/DepartmentGlyph/README.md +18 -0
- package/src/Dialog/README.md +3 -0
- package/src/DiffViewer/README.md +3 -0
- package/src/Divider/README.md +3 -0
- package/src/Drawer/README.md +3 -0
- package/src/DropdownMenu/README.md +3 -0
- package/src/EPKViewer/README.md +3 -0
- package/src/Editing/ColorPicker.tsx +125 -0
- package/src/Editing/DiffViewer.tsx +49 -0
- package/src/Editing/Editing.tsx +29 -0
- package/src/Editing/Editing.types.ts +71 -0
- package/src/Editing/FilterBuilder.tsx +72 -0
- package/src/Editing/QuickAdd.tsx +102 -0
- package/src/Editing/QuickAddChips.tsx +180 -0
- package/src/Editing/contrastRatio.tsx +11 -0
- package/src/Editing/parseQuickAdd.tsx +187 -0
- package/src/Editing/quickAddCore.ts +204 -0
- package/src/Editing/timeShorthand.ts +157 -0
- package/src/Editing/useQuickAdd.ts +201 -0
- package/src/EmergencyCodeCard/README.md +10 -0
- package/src/EmptyState/README.md +5 -0
- package/src/EngagementTimeline/README.md +3 -0
- package/src/ErrorState/README.md +3 -0
- package/src/FAQ/README.md +7 -0
- package/src/FeatureGrid/README.md +7 -0
- package/src/Feedback/Banner.tsx +40 -0
- package/src/Feedback/EmptyState.tsx +32 -0
- package/src/Feedback/ErrorState.tsx +32 -0
- package/src/Feedback/Feedback.shared.tsx +38 -0
- package/src/Feedback/Feedback.tsx +18 -0
- package/src/Feedback/Feedback.types.ts +40 -0
- package/src/Feedback/InlineAlert.tsx +19 -0
- package/src/Feedback/RefusalNotice.tsx +46 -0
- package/src/Feedback/RegionBoundary.tsx +102 -0
- package/src/Feedback/Toast.tsx +31 -0
- package/src/Feedback/ToastRegion.tsx +26 -0
- package/src/Feedback/UndoToast.tsx +97 -0
- package/src/FeedbackWidget/README.md +3 -0
- package/src/Field/Field.tsx +81 -0
- package/src/FileDrop/README.md +3 -0
- package/src/FilePreviewer/README.md +3 -0
- package/src/FilterBuilder/README.md +3 -0
- package/src/ForceUpdateScreen/README.md +3 -0
- package/src/Forms/Checkbox.tsx +14 -0
- package/src/Forms/CurrencyInput.tsx +40 -0
- package/src/Forms/Forms.shared.tsx +5 -0
- package/src/Forms/Forms.tsx +20 -0
- package/src/Forms/Forms.types.ts +33 -0
- package/src/Forms/Input.tsx +28 -0
- package/src/Forms/Money.tsx +15 -0
- package/src/Forms/NumberInput.tsx +85 -0
- package/src/Forms/Radio.tsx +31 -0
- package/src/Forms/Select.tsx +54 -0
- package/src/Forms/Switch.tsx +14 -0
- package/src/Forms/Textarea.tsx +30 -0
- package/src/Gallery/README.md +5 -0
- package/src/GateLifecycleRail/README.md +7 -0
- package/src/GateReadinessPanel/README.md +8 -0
- package/src/Gateway/AgencySlate.tsx +76 -0
- package/src/Gateway/ApplicationForm.tsx +48 -0
- package/src/Gateway/AvailabilityCalendar.tsx +82 -0
- package/src/Gateway/EPKViewer.tsx +77 -0
- package/src/Gateway/EngagementTimeline.tsx +43 -0
- package/src/Gateway/Gateway.shared.tsx +5 -0
- package/src/Gateway/Gateway.tsx +30 -0
- package/src/Gateway/Gateway.types.ts +69 -0
- package/src/Gateway/OnboardingPacket.tsx +61 -0
- package/src/Gateway/OpportunityCard.tsx +73 -0
- package/src/Gateway/OpportunityFilters.tsx +64 -0
- package/src/Gateway/PaymentTracker.tsx +71 -0
- package/src/Gateway/PayoutDetailsForm.tsx +62 -0
- package/src/Gateway/ProfileEditor.tsx +45 -0
- package/src/Gateway/ProgressBar.tsx +30 -0
- package/src/Gateway/RatingDialog.tsx +83 -0
- package/src/Gateway/UpNextCard.tsx +76 -0
- package/src/Glyphs/Glyphs.tsx +66 -0
- package/src/Grids/BidSheet.tsx +63 -0
- package/src/Grids/BudgetGrid.tsx +164 -0
- package/src/Grids/Grids.shared.tsx +5 -0
- package/src/Grids/Grids.tsx +11 -0
- package/src/Grids/Grids.types.ts +38 -0
- package/src/Grids/SpreadsheetGrid.tsx +445 -0
- package/src/Grids/columnTotal.tsx +14 -0
- package/src/Grids/glForCode.tsx +11 -0
- package/src/Grids/parseCell.tsx +16 -0
- package/src/Help/FeedbackWidget.tsx +89 -0
- package/src/Help/Help.tsx +14 -0
- package/src/Help/Help.types.ts +51 -0
- package/src/Help/HelpPanel.tsx +116 -0
- package/src/Help/NotificationCenter.tsx +100 -0
- package/src/Help/OnboardingChecklist.tsx +57 -0
- package/src/Help/ShortcutEditor.tsx +81 -0
- package/src/Help/WhatsNew.tsx +33 -0
- package/src/HelpPanel/README.md +5 -0
- package/src/HoverCard/README.md +3 -0
- package/src/Icon/Icon.tsx +47 -0
- package/src/Icon/README.md +9 -0
- package/src/IconButton/README.md +6 -0
- package/src/Identity/BrandSlot.tsx +20 -0
- package/src/Identity/BrandSlotFrame.tsx +38 -0
- package/src/Identity/CredentialBadge.tsx +92 -0
- package/src/Identity/Identity.tsx +14 -0
- package/src/Identity/Identity.types.ts +25 -0
- package/src/Identity/PresenceIndicator.tsx +37 -0
- package/src/Identity/QRCode.tsx +22 -0
- package/src/Identity/WhiteLabelPreview.tsx +33 -0
- package/src/Identity/qrPath.tsx +16 -0
- package/src/Identity/tokenVariable.tsx +9 -0
- package/src/InlineAlert/README.md +3 -0
- package/src/Input/README.md +8 -0
- package/src/Kbd/Kbd.tsx +30 -0
- package/src/Kbd/README.md +6 -0
- package/src/Layout/AppShell.tsx +151 -0
- package/src/Layout/Layout.tsx +14 -0
- package/src/Layout/Layout.types.ts +43 -0
- package/src/Layout/PageHeader.tsx +22 -0
- package/src/Layout/ResizablePanel.tsx +81 -0
- package/src/Layout/ScrollRegion.tsx +107 -0
- package/src/Layout/SplitView.tsx +78 -0
- package/src/Layout/Stepper.tsx +39 -0
- package/src/LegalText/LegalText.tsx +289 -0
- package/src/LegalText/README.md +10 -0
- package/src/LegalText/index.ts +29 -0
- package/src/LegalText/legal-markdown.ts +581 -0
- package/src/Link/Link.tsx +25 -0
- package/src/Link/README.md +5 -0
- package/src/Link/link-class.ts +10 -0
- package/src/LiveActivity/README.md +3 -0
- package/src/LogoSlotWall/README.md +7 -0
- package/src/MapView/README.md +5 -0
- package/src/Marketing/AIDisclosureBadge.tsx +31 -0
- package/src/Marketing/ButtonLink.tsx +32 -0
- package/src/Marketing/CodeSample.tsx +47 -0
- package/src/Marketing/ComparisonScroll.tsx +7 -0
- package/src/Marketing/ComparisonTable.tsx +104 -0
- package/src/Marketing/FAQ.tsx +26 -0
- package/src/Marketing/FeatureGrid.tsx +65 -0
- package/src/Marketing/GateLifecycleRail.tsx +52 -0
- package/src/Marketing/LogoSlotWall.tsx +53 -0
- package/src/Marketing/Marketing.tsx +49 -0
- package/src/Marketing/Marketing.types.ts +64 -0
- package/src/Marketing/MarketingFooter.tsx +88 -0
- package/src/Marketing/MarketingHero.tsx +45 -0
- package/src/Marketing/MarketingNav.tsx +76 -0
- package/src/Marketing/MarketingPoints.tsx +16 -0
- package/src/Marketing/MarketingSection.tsx +52 -0
- package/src/Marketing/PersonaSwitcher.tsx +137 -0
- package/src/Marketing/PriceDisplay.tsx +56 -0
- package/src/Marketing/PricingTable.tsx +122 -0
- package/src/Marketing/ProofStatStrip.tsx +35 -0
- package/src/Marketing/ScreenshotFrame.tsx +56 -0
- package/src/Marketing/SurfaceTriptych.tsx +43 -0
- package/src/Marketing/Testimonial.tsx +45 -0
- package/src/Marketing/marketing-copy.ts +25 -0
- package/src/Marketing/provided.tsx +36 -0
- package/src/MarketingFooter/README.md +7 -0
- package/src/MarketingHero/README.md +7 -0
- package/src/MarketingNav/README.md +7 -0
- package/src/MarketingSection/README.md +7 -0
- package/src/Media/FilePreviewer.tsx +86 -0
- package/src/Media/MapView.tsx +200 -0
- package/src/Media/Media.tsx +11 -0
- package/src/Media/Media.types.ts +47 -0
- package/src/Media/RichTextEditor.tsx +198 -0
- package/src/Media/toLngLat.tsx +13 -0
- package/src/Menus/ContextMenu.tsx +106 -0
- package/src/Menus/DropdownMenu.tsx +51 -0
- package/src/Menus/Menus.shared.tsx +67 -0
- package/src/Menus/Menus.tsx +13 -0
- package/src/Menus/Menus.types.ts +49 -0
- package/src/Menus/OrgSwitcher.tsx +69 -0
- package/src/Menus/compactTriggerClass.tsx +7 -0
- package/src/Menus/menuClass.tsx +4 -0
- package/src/Menus/menuItemClass.tsx +7 -0
- package/src/Menus/orgSwitcherTriggerClass.tsx +7 -0
- package/src/Money/README.md +6 -0
- package/src/MultiSelect/README.md +3 -0
- package/src/Navigation/Accordion.tsx +59 -0
- package/src/Navigation/Breadcrumbs.tsx +59 -0
- package/src/Navigation/MoreFields.tsx +42 -0
- package/src/Navigation/Navigation.shared.tsx +32 -0
- package/src/Navigation/Navigation.tsx +21 -0
- package/src/Navigation/Navigation.types.ts +63 -0
- package/src/Navigation/Pagination.tsx +30 -0
- package/src/Navigation/SegmentedControl.tsx +87 -0
- package/src/Navigation/Sidebar.tsx +106 -0
- package/src/Navigation/TabBar.tsx +61 -0
- package/src/Navigation/Tabs.tsx +79 -0
- package/src/Navigation/TopNav.tsx +86 -0
- package/src/Navigation/sidebar-classes.ts +18 -0
- package/src/NotificationCenter/README.md +3 -0
- package/src/NumberInput/README.md +3 -0
- package/src/OfflineBanner/README.md +3 -0
- package/src/OnboardingChecklist/README.md +3 -0
- package/src/OnboardingPacket/README.md +3 -0
- package/src/OpportunityCard/README.md +5 -0
- package/src/OpportunityFilters/README.md +3 -0
- package/src/OrgChart/README.md +5 -0
- package/src/OrgSwitcher/README.md +3 -0
- package/src/Overlays/Dialog.tsx +54 -0
- package/src/Overlays/Drawer.tsx +62 -0
- package/src/Overlays/HoverCard.tsx +59 -0
- package/src/Overlays/Overlays.shared.tsx +12 -0
- package/src/Overlays/Overlays.tsx +20 -0
- package/src/Overlays/Overlays.types.ts +66 -0
- package/src/Overlays/Popover.tsx +70 -0
- package/src/Overlays/PropertyList.tsx +19 -0
- package/src/Overlays/ShortcutSheet.tsx +62 -0
- package/src/Overlays/SidePeek.tsx +117 -0
- package/src/Overlays/Tooltip.tsx +73 -0
- package/src/Overlays/panelClass.tsx +6 -0
- package/src/Overlays/popoverPanelClass.tsx +6 -0
- package/src/PageHeader/README.md +3 -0
- package/src/Pagination/README.md +3 -0
- package/src/PaymentTracker/README.md +3 -0
- package/src/PayoutDetailsForm/README.md +3 -0
- package/src/PersonaSwitcher/README.md +7 -0
- package/src/PhaseChip/README.md +5 -0
- package/src/PhaseGlyph/README.md +17 -0
- package/src/PhotoCapture/README.md +3 -0
- package/src/Pickers/Combobox.tsx +91 -0
- package/src/Pickers/DatePicker.tsx +60 -0
- package/src/Pickers/DateRangePicker.tsx +78 -0
- package/src/Pickers/FileDrop.tsx +84 -0
- package/src/Pickers/MultiSelect.tsx +118 -0
- package/src/Pickers/Pickers.shared.tsx +337 -0
- package/src/Pickers/Pickers.tsx +17 -0
- package/src/Pickers/Pickers.types.ts +47 -0
- package/src/Pickers/Slider.tsx +59 -0
- package/src/Pickers/TimePicker.tsx +68 -0
- package/src/Pickers/rankOptions.tsx +12 -0
- package/src/Popover/README.md +3 -0
- package/src/PresenceIndicator/README.md +3 -0
- package/src/PriceDisplay/README.md +7 -0
- package/src/PricingTable/README.md +9 -0
- package/src/ProfileEditor/README.md +3 -0
- package/src/ProgressBar/README.md +3 -0
- package/src/ProofStatStrip/README.md +7 -0
- package/src/PropertyChip/README.md +3 -0
- package/src/ProvenanceBadge/README.md +3 -0
- package/src/QRCode/README.md +6 -0
- package/src/QuickAdd/README.md +5 -0
- package/src/QuickIncidentSheet/README.md +3 -0
- package/src/Radio/README.md +3 -0
- package/src/RadioChannelTable/README.md +7 -0
- package/src/RatingDialog/README.md +3 -0
- package/src/ReconciliationTable/README.md +3 -0
- package/src/RecordKindChip/README.md +3 -0
- package/src/RecordKindGlyph/README.md +34 -0
- package/src/RecordRow/README.md +7 -0
- package/src/RefusalNotice/README.md +5 -0
- package/src/ResizablePanel/README.md +3 -0
- package/src/ResourceSchedule/README.md +6 -0
- package/src/RichTextEditor/README.md +3 -0
- package/src/RichTextEditor/extensions.ts +217 -0
- package/src/RunOfShowLive/README.md +5 -0
- package/src/ScanSheet/README.md +3 -0
- package/src/ScreenshotFrame/README.md +7 -0
- package/src/ScrollRegion/README.md +9 -0
- package/src/SegmentedControl/README.md +5 -0
- package/src/Select/README.md +5 -0
- package/src/ShiftCard/README.md +3 -0
- package/src/ShortcutEditor/README.md +3 -0
- package/src/ShortcutSheet/README.md +3 -0
- package/src/SidePeek/README.md +6 -0
- package/src/Sidebar/README.md +5 -0
- package/src/SignaturePad/README.md +3 -0
- package/src/Skeleton/README.md +3 -0
- package/src/Slider/README.md +3 -0
- package/src/SplitView/README.md +3 -0
- package/src/SpreadsheetGrid/README.md +9 -0
- package/src/StalenessIndicator/README.md +3 -0
- package/src/StatTile/README.md +6 -0
- package/src/StateChip/README.md +6 -0
- package/src/StateIcon/README.md +6 -0
- package/src/StateIcon/StateIcon.tsx +127 -0
- package/src/StatusHeatmap/README.md +15 -0
- package/src/Stepper/README.md +3 -0
- package/src/Surface/Skeleton.tsx +21 -0
- package/src/Surface/Surface.tsx +63 -0
- package/src/SurfaceTriptych/README.md +7 -0
- package/src/Switch/README.md +5 -0
- package/src/SyncConflictSheet/README.md +3 -0
- package/src/TabBar/README.md +7 -0
- package/src/Tabs/README.md +6 -0
- package/src/Tag/README.md +3 -0
- package/src/TemplateAuth/README.md +6 -0
- package/src/TemplateCollection/README.md +6 -0
- package/src/TemplateDashboard/README.md +8 -0
- package/src/TemplateDocument/README.md +5 -0
- package/src/TemplateGatewayShell/README.md +5 -0
- package/src/TemplateGridEditor/README.md +3 -0
- package/src/TemplateRecord/README.md +3 -0
- package/src/TemplateSettings/README.md +5 -0
- package/src/TemplateSplitView/README.md +3 -0
- package/src/TemplateSystem/README.md +5 -0
- package/src/TemplateWizard/README.md +3 -0
- package/src/Templates/TemplateAuth.tsx +16 -0
- package/src/Templates/TemplateCollection.tsx +35 -0
- package/src/Templates/TemplateDashboard.tsx +200 -0
- package/src/Templates/TemplateDocument.tsx +24 -0
- package/src/Templates/TemplateGatewayShell.tsx +36 -0
- package/src/Templates/TemplateGridEditor.tsx +17 -0
- package/src/Templates/TemplateRecord.tsx +31 -0
- package/src/Templates/TemplateSettings.tsx +26 -0
- package/src/Templates/TemplateSplitView.tsx +27 -0
- package/src/Templates/TemplateSystem.tsx +19 -0
- package/src/Templates/TemplateSystemLink.tsx +55 -0
- package/src/Templates/TemplateWizard.tsx +43 -0
- package/src/Templates/Templates.tsx +29 -0
- package/src/Templates/Templates.types.ts +153 -0
- package/src/Testimonial/README.md +7 -0
- package/src/Textarea/README.md +3 -0
- package/src/TimePicker/README.md +5 -0
- package/src/Timeline/README.md +6 -0
- package/src/Toast/README.md +3 -0
- package/src/Tooltip/README.md +3 -0
- package/src/TopNav/README.md +5 -0
- package/src/TreeView/README.md +3 -0
- package/src/URIDChip/README.md +5 -0
- package/src/UndoToast/README.md +3 -0
- package/src/UpNextCard/README.md +6 -0
- package/src/Views/ActivityFeedItem.tsx +52 -0
- package/src/Views/Board.tsx +229 -0
- package/src/Views/BulkActionBar.tsx +76 -0
- package/src/Views/RecordList.tsx +146 -0
- package/src/Views/RecordRow.tsx +132 -0
- package/src/Views/StatTile.tsx +88 -0
- package/src/Views/TreeView.tsx +161 -0
- package/src/Views/Views.tsx +18 -0
- package/src/Views/Views.types.ts +99 -0
- package/src/WhatsNew/README.md +3 -0
- package/src/WhiteLabelPreview/README.md +8 -0
- package/src/XOS/AccessGridMatrix.tsx +111 -0
- package/src/XOS/AssertionRankBadge.tsx +27 -0
- package/src/XOS/CoordinateMatrix.tsx +123 -0
- package/src/XOS/EmergencyCodeCard.tsx +109 -0
- package/src/XOS/GateReadinessPanel.tsx +100 -0
- package/src/XOS/ProvenanceBadge.tsx +19 -0
- package/src/XOS/RadioChannelTable.tsx +50 -0
- package/src/XOS/ReconciliationTable.tsx +64 -0
- package/src/XOS/RunOfShowLive.tsx +97 -0
- package/src/XOS/StalenessIndicator.tsx +31 -0
- package/src/XOS/StatusHeatmap.tsx +200 -0
- package/src/XOS/XOS.shared.tsx +90 -0
- package/src/XOS/XOS.tsx +29 -0
- package/src/XOS/XOS.types.ts +99 -0
- package/src/XOS/resolveStep.tsx +16 -0
- package/src/brand/defaults/README.md +13 -0
- package/src/brand/defaults/app-icon.svg +6 -0
- package/src/brand/defaults/favicon.svg +6 -0
- package/src/brand/defaults/logo-dark.svg +6 -0
- package/src/brand/defaults/logo-light.svg +6 -0
- package/src/brand/defaults/splash.svg +6 -0
- package/src/index.ts +606 -0
- package/src/lib/context.tsx +156 -0
- package/src/lib/cx.ts +4 -0
- package/src/lib/format.ts +200 -0
- package/src/lib/hooks.ts +187 -0
- package/src/lib/i18n.ts +97 -0
- package/src/lib/icons.ts +45 -0
- package/src/lib/live.ts +92 -0
- package/src/lib/preferences.ts +242 -0
- package/src/lib/route-transition.tsx +22 -0
- package/src/lib/selection.ts +92 -0
- package/src/lib/shortcut-targets.ts +125 -0
- package/src/lib/theme.ts +50 -0
- package/src/lib/undo-stack.ts +125 -0
- package/src/marketing.ts +33 -0
- package/src/pwa/action-outcome.tsx +81 -0
- package/src/pwa/analytics.ts +236 -0
- package/src/pwa/browser-push.tsx +132 -0
- package/src/pwa/client.ts +126 -0
- package/src/pwa/index.ts +40 -0
- package/src/pwa/offline-key.ts +18 -0
- package/src/pwa/service-worker.ts +229 -0
- package/src/static.ts +10 -0
- package/src/styles/base.css +208 -0
- package/src/styles/components.css +453 -0
- package/src/styles/index.css +16 -0
- package/src/styles/marketing.css +1260 -0
- package/src/styles/reference.css +5792 -0
- package/src/types/reference.d.ts +1608 -0
- package/tailwind.config.cjs +3 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type {
|
|
3
|
+
AccordionProps as ReferenceAccordionProps,
|
|
4
|
+
BreadcrumbsProps as ReferenceBreadcrumbsProps,
|
|
5
|
+
IconName,
|
|
6
|
+
PaginationProps as ReferencePaginationProps,
|
|
7
|
+
SegmentedControlProps as ReferenceSegmentedControlProps,
|
|
8
|
+
SidebarProps as ReferenceSidebarProps,
|
|
9
|
+
TabBarProps as ReferenceTabBarProps,
|
|
10
|
+
TabsProps as ReferenceTabsProps,
|
|
11
|
+
TopNavProps as ReferenceTopNavProps,
|
|
12
|
+
} from "../types/reference";
|
|
13
|
+
|
|
14
|
+
export type TabsProps = ReferenceTabsProps & {
|
|
15
|
+
/** Panel content per tab value; each renders as a tabpanel labeled by its tab. */
|
|
16
|
+
panels?: Record<string, ReactNode>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type SegmentedControlProps = ReferenceSegmentedControlProps;
|
|
20
|
+
|
|
21
|
+
export type AccordionProps = ReferenceAccordionProps & {
|
|
22
|
+
/**
|
|
23
|
+
* Keeps closed sections in the DOM, hidden, instead of unmounting them. Use it for the More fields
|
|
24
|
+
* pattern inside a form, so collapsed fields keep their values and still submit with the form.
|
|
25
|
+
*/
|
|
26
|
+
keepMounted?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* The heading level of each section header, 3 by default. Pick the level that follows the heading
|
|
29
|
+
* above the accordion, so headings never skip a level (WCAG 1.3.1, axe heading-order).
|
|
30
|
+
*/
|
|
31
|
+
headingLevel?: 2 | 3 | 4 | 5 | 6;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type BreadcrumbsProps = ReferenceBreadcrumbsProps;
|
|
35
|
+
|
|
36
|
+
export type PaginationProps = ReferencePaginationProps;
|
|
37
|
+
|
|
38
|
+
export interface NavItem {
|
|
39
|
+
label: string;
|
|
40
|
+
icon?: IconName;
|
|
41
|
+
badge?: number;
|
|
42
|
+
href?: string;
|
|
43
|
+
onSelect?: () => void;
|
|
44
|
+
/** Items listed under this one in the Sidebar, indented one step (the recent projects under Projects). */
|
|
45
|
+
items?: NavItem[];
|
|
46
|
+
/** Names the list of `items` for screen readers. */
|
|
47
|
+
itemsLabel?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type SidebarProps = Omit<ReferenceSidebarProps, "groups"> & {
|
|
51
|
+
groups: { label?: string; collapsed?: boolean; items: NavItem[] }[];
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type TopNavProps = Omit<ReferenceTopNavProps, "items"> & {
|
|
55
|
+
items: (NavItem & { icon: IconName })[];
|
|
56
|
+
onSearch?: () => void;
|
|
57
|
+
onHelp?: () => void;
|
|
58
|
+
onAccount?: () => void;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export type TabBarProps = Omit<ReferenceTabBarProps, "items"> & {
|
|
62
|
+
items: (NavItem & { icon: IconName })[];
|
|
63
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { useT } from "../lib/context.tsx";
|
|
3
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
4
|
+
import { Button } from "../Button/Button.tsx";
|
|
5
|
+
import { type PaginationProps } from "./Navigation.types.ts";
|
|
6
|
+
|
|
7
|
+
/** Cursor paging: a summary and Previous and Next, never page numbers it cannot jump to. */
|
|
8
|
+
export function Pagination({
|
|
9
|
+
summary,
|
|
10
|
+
hasPrev,
|
|
11
|
+
hasNext,
|
|
12
|
+
onPrev,
|
|
13
|
+
onNext,
|
|
14
|
+
}: PaginationProps): ReactElement {
|
|
15
|
+
const t = useT();
|
|
16
|
+
return (
|
|
17
|
+
<nav aria-label={t("nav.pagination")} className="flex flex-wrap items-center justify-end gap-8">
|
|
18
|
+
<span className="text-text-secondary tabular-nums" aria-live="polite">
|
|
19
|
+
{summary}
|
|
20
|
+
</span>
|
|
21
|
+
<Button size="sm" icon="ChevronLeft" disabled={!hasPrev} onClick={onPrev}>
|
|
22
|
+
{t("nav.previous")}
|
|
23
|
+
</Button>
|
|
24
|
+
<Button size="sm" disabled={!hasNext} onClick={onNext}>
|
|
25
|
+
{t("nav.next")}
|
|
26
|
+
<Icon name="ChevronRight" size={14} />
|
|
27
|
+
</Button>
|
|
28
|
+
</nav>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useRef, type KeyboardEvent, type ReactElement } from "react";
|
|
2
|
+
import { Direction } from "radix-ui";
|
|
3
|
+
import { cx } from "../lib/cx.ts";
|
|
4
|
+
import { rovingIndex, useControllable } from "../lib/hooks.ts";
|
|
5
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
6
|
+
import { type SegmentedControlProps } from "./Navigation.types.ts";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Two to five peer options, such as the view switcher. Arrow keys, Home and End move focus; Enter,
|
|
10
|
+
* Space or a click turns a segment on; one segment is always on. It keeps the markup Radix's
|
|
11
|
+
* single toggle group rendered (a radiogroup of radio buttons with `data-state`) without the
|
|
12
|
+
* toggle group, roving focus and collection code, about 4 KB gzip on every page with a view
|
|
13
|
+
* switcher (gate 10).
|
|
14
|
+
*/
|
|
15
|
+
export function SegmentedControl({
|
|
16
|
+
label,
|
|
17
|
+
value,
|
|
18
|
+
options,
|
|
19
|
+
onChange,
|
|
20
|
+
}: SegmentedControlProps): ReactElement {
|
|
21
|
+
const dir = Direction.useDirection();
|
|
22
|
+
const [current, setCurrent] = useControllable<string>(
|
|
23
|
+
undefined,
|
|
24
|
+
value ?? options[0]?.value ?? "",
|
|
25
|
+
onChange,
|
|
26
|
+
);
|
|
27
|
+
const refs = useRef<(HTMLButtonElement | null)[]>([]);
|
|
28
|
+
// The tab stop is the segment that is on, or the first one when none matches.
|
|
29
|
+
const stop = Math.max(
|
|
30
|
+
0,
|
|
31
|
+
options.findIndex((o) => o.value === current),
|
|
32
|
+
);
|
|
33
|
+
const move = (event: KeyboardEvent<HTMLButtonElement>, index: number) => {
|
|
34
|
+
const key =
|
|
35
|
+
event.key === "ArrowDown"
|
|
36
|
+
? dir === "rtl"
|
|
37
|
+
? "ArrowLeft"
|
|
38
|
+
: "ArrowRight"
|
|
39
|
+
: event.key === "ArrowUp"
|
|
40
|
+
? dir === "rtl"
|
|
41
|
+
? "ArrowRight"
|
|
42
|
+
: "ArrowLeft"
|
|
43
|
+
: event.key;
|
|
44
|
+
const next = rovingIndex(key, index, options.length, "horizontal", dir);
|
|
45
|
+
if (next === null) return;
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
refs.current[next]?.focus();
|
|
48
|
+
};
|
|
49
|
+
return (
|
|
50
|
+
<div
|
|
51
|
+
role="radiogroup"
|
|
52
|
+
aria-label={label}
|
|
53
|
+
dir={dir}
|
|
54
|
+
className="inline-flex self-start max-w-full gap-2 p-2 rounded-control border border-border-control bg-bg-surface"
|
|
55
|
+
>
|
|
56
|
+
{options.map((o, i) => {
|
|
57
|
+
const on = o.value === current;
|
|
58
|
+
return (
|
|
59
|
+
<button
|
|
60
|
+
key={o.value}
|
|
61
|
+
ref={(el) => {
|
|
62
|
+
refs.current[i] = el;
|
|
63
|
+
}}
|
|
64
|
+
type="button"
|
|
65
|
+
role="radio"
|
|
66
|
+
aria-checked={on}
|
|
67
|
+
data-state={on ? "on" : "off"}
|
|
68
|
+
tabIndex={i === stop ? 0 : -1}
|
|
69
|
+
onClick={() => {
|
|
70
|
+
if (!on) setCurrent(o.value);
|
|
71
|
+
}}
|
|
72
|
+
onKeyDown={(event) => move(event, i)}
|
|
73
|
+
className={cx(
|
|
74
|
+
"inline-flex items-center gap-4 h-control-sm px-8 rounded-chip border-0 bg-transparent cursor-pointer",
|
|
75
|
+
"font-medium text-text-12 text-text-secondary",
|
|
76
|
+
"data-[state=on]:bg-bg-hover data-[state=on]:text-text-primary data-[state=on]:ring-(length:--stroke-width-hairline) data-[state=on]:ring-border-strong",
|
|
77
|
+
"pointer-coarse:min-h-target-coarse pointer-coarse:min-w-target-coarse",
|
|
78
|
+
)}
|
|
79
|
+
>
|
|
80
|
+
{o.icon ? <Icon name={o.icon} size={14} /> : null}
|
|
81
|
+
{o.label}
|
|
82
|
+
</button>
|
|
83
|
+
);
|
|
84
|
+
})}
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { useId, useState, type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
5
|
+
import { type NavItem, type SidebarProps } from "./Navigation.types.ts";
|
|
6
|
+
import { sidebarClass, sidebarItemClass } from "./sidebar-classes.ts";
|
|
7
|
+
|
|
8
|
+
function NavLink({
|
|
9
|
+
item,
|
|
10
|
+
active,
|
|
11
|
+
className,
|
|
12
|
+
}: {
|
|
13
|
+
item: NavItem;
|
|
14
|
+
active: boolean;
|
|
15
|
+
className: string;
|
|
16
|
+
}) {
|
|
17
|
+
const body = (
|
|
18
|
+
<>
|
|
19
|
+
{item.icon ? <Icon name={item.icon} /> : null}
|
|
20
|
+
<span className="flex-1 min-w-0 truncate" title={item.label}>
|
|
21
|
+
{item.label}
|
|
22
|
+
</span>
|
|
23
|
+
{item.badge !== undefined ? (
|
|
24
|
+
<span className="text-text-11 text-text-secondary tabular-nums">{item.badge}</span>
|
|
25
|
+
) : null}
|
|
26
|
+
</>
|
|
27
|
+
);
|
|
28
|
+
const current = active ? ("page" as const) : undefined;
|
|
29
|
+
return item.href ? (
|
|
30
|
+
<a href={item.href} aria-current={current} className={className} onClick={item.onSelect}>
|
|
31
|
+
{body}
|
|
32
|
+
</a>
|
|
33
|
+
) : (
|
|
34
|
+
<button type="button" aria-current={current} className={className} onClick={item.onSelect}>
|
|
35
|
+
{body}
|
|
36
|
+
</button>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The sitemap navigation. Group headings collapse and expand; the active item is the current page. An item may list
|
|
42
|
+
* items under it (the recent projects under Projects), indented one step. A label longer than the sidebar (a project
|
|
43
|
+
* name, a longer translation) shrinks with an ellipsis and keeps its whole text as a title (Section 15, gate 16).
|
|
44
|
+
*/
|
|
45
|
+
export function Sidebar({ label, active, groups }: SidebarProps): ReactElement {
|
|
46
|
+
const t = useT();
|
|
47
|
+
const base = useId().replace(/:/g, "");
|
|
48
|
+
const [collapsed, setCollapsed] = useState(() => groups.map((g) => g.collapsed ?? false));
|
|
49
|
+
return (
|
|
50
|
+
<nav aria-label={label ?? t("nav.main")} className={sidebarClass}>
|
|
51
|
+
{groups.map((g, gi) => {
|
|
52
|
+
const isCollapsed = collapsed[gi] ?? false;
|
|
53
|
+
const listId = `${base}-group-${gi}`;
|
|
54
|
+
return (
|
|
55
|
+
<div key={`${g.label ?? "group"}-${gi}`} className={g.label ? "mt-12" : undefined}>
|
|
56
|
+
{g.label ? (
|
|
57
|
+
<h2 className="m-0 mb-2">
|
|
58
|
+
<button
|
|
59
|
+
type="button"
|
|
60
|
+
aria-expanded={!isCollapsed}
|
|
61
|
+
aria-controls={listId}
|
|
62
|
+
onClick={() => setCollapsed((c) => c.map((v, i) => (i === gi ? !v : v)))}
|
|
63
|
+
className={cx(
|
|
64
|
+
"flex items-center gap-4 w-full px-8 py-2 bg-transparent border-0 cursor-pointer",
|
|
65
|
+
"text-text-11 font-medium text-text-secondary hover:text-text-primary pointer-coarse:min-h-target-coarse",
|
|
66
|
+
)}
|
|
67
|
+
>
|
|
68
|
+
<Icon name={isCollapsed ? "chevron-right" : "chevron-down"} size={12} />
|
|
69
|
+
{g.label}
|
|
70
|
+
</button>
|
|
71
|
+
</h2>
|
|
72
|
+
) : null}
|
|
73
|
+
<ul id={listId} hidden={isCollapsed} className="m-0 p-0 list-none">
|
|
74
|
+
{g.items.map((item) => (
|
|
75
|
+
<li key={item.label}>
|
|
76
|
+
<NavLink
|
|
77
|
+
item={item}
|
|
78
|
+
active={item.label === active}
|
|
79
|
+
className={sidebarItemClass}
|
|
80
|
+
/>
|
|
81
|
+
{item.items && item.items.length > 0 ? (
|
|
82
|
+
<ul
|
|
83
|
+
aria-label={item.itemsLabel}
|
|
84
|
+
data-sidebar-subitems=""
|
|
85
|
+
className="m-0 ps-16 py-0 pe-0 list-none"
|
|
86
|
+
>
|
|
87
|
+
{item.items.map((child) => (
|
|
88
|
+
<li key={`${child.label}-${child.href ?? ""}`}>
|
|
89
|
+
<NavLink
|
|
90
|
+
item={child}
|
|
91
|
+
active={child.label === active}
|
|
92
|
+
className={sidebarItemClass}
|
|
93
|
+
/>
|
|
94
|
+
</li>
|
|
95
|
+
))}
|
|
96
|
+
</ul>
|
|
97
|
+
) : null}
|
|
98
|
+
</li>
|
|
99
|
+
))}
|
|
100
|
+
</ul>
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
})}
|
|
104
|
+
</nav>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
5
|
+
import { Badge } from "../Chips/Chips.tsx";
|
|
6
|
+
import { ItemAction } from "./Navigation.shared.tsx";
|
|
7
|
+
import { type TabBarProps } from "./Navigation.types.ts";
|
|
8
|
+
|
|
9
|
+
/** The five-destination bottom bar for phones; targets meet touch-min (48 pt). */
|
|
10
|
+
export function TabBar({
|
|
11
|
+
label,
|
|
12
|
+
items,
|
|
13
|
+
active,
|
|
14
|
+
compass = false,
|
|
15
|
+
centerLabel,
|
|
16
|
+
}: TabBarProps): ReactElement {
|
|
17
|
+
const t = useT();
|
|
18
|
+
return (
|
|
19
|
+
<nav
|
|
20
|
+
aria-label={label}
|
|
21
|
+
className={cx(
|
|
22
|
+
"flex justify-around items-stretch w-(--ui-tabbar) max-w-full pt-6 pb-20 box-border bg-bg-surface border-t border-border-subtle",
|
|
23
|
+
compass && "xos-compass",
|
|
24
|
+
)}
|
|
25
|
+
>
|
|
26
|
+
{items.map((item) => {
|
|
27
|
+
const center = item.label === centerLabel;
|
|
28
|
+
return (
|
|
29
|
+
<ItemAction
|
|
30
|
+
key={item.label}
|
|
31
|
+
item={item}
|
|
32
|
+
active={item.label === active}
|
|
33
|
+
className={cx(
|
|
34
|
+
"flex flex-1 flex-col items-center justify-center gap-2 min-h-touch-min rounded-control no-underline",
|
|
35
|
+
"text-text-11 font-medium text-text-secondary aria-[current=page]:text-accent-text",
|
|
36
|
+
)}
|
|
37
|
+
>
|
|
38
|
+
<span
|
|
39
|
+
className={cx(
|
|
40
|
+
"relative inline-flex",
|
|
41
|
+
center &&
|
|
42
|
+
"p-8 -mt-20 rounded-full bg-accent text-accent-text-on ring-(length:--space-4) ring-bg-surface",
|
|
43
|
+
)}
|
|
44
|
+
>
|
|
45
|
+
<Icon name={item.icon} size={compass ? 24 : 20} />
|
|
46
|
+
{item.badge ? (
|
|
47
|
+
<Badge
|
|
48
|
+
count={item.badge}
|
|
49
|
+
tone="danger"
|
|
50
|
+
label={t("tabbar.badge", { n: item.badge })}
|
|
51
|
+
className="absolute -top-6 -end-12"
|
|
52
|
+
/>
|
|
53
|
+
) : null}
|
|
54
|
+
</span>
|
|
55
|
+
<span>{item.label}</span>
|
|
56
|
+
</ItemAction>
|
|
57
|
+
);
|
|
58
|
+
})}
|
|
59
|
+
</nav>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useId, useRef, type ReactElement } from "react";
|
|
2
|
+
import { Direction } from "radix-ui";
|
|
3
|
+
import { cx } from "../lib/cx.ts";
|
|
4
|
+
import { rovingIndex, useControllable } from "../lib/hooks.ts";
|
|
5
|
+
import { type TabsProps } from "./Navigation.types.ts";
|
|
6
|
+
|
|
7
|
+
/** Switches between sections of one object. Arrow keys move and select, Home and End jump. */
|
|
8
|
+
export function Tabs({ label, value, tabs, onChange, panels }: TabsProps): ReactElement {
|
|
9
|
+
const base = useId().replace(/:/g, "");
|
|
10
|
+
const dir = Direction.useDirection();
|
|
11
|
+
const [current, setCurrent] = useControllable<string>(
|
|
12
|
+
undefined,
|
|
13
|
+
value ?? tabs[0]?.value ?? "",
|
|
14
|
+
onChange,
|
|
15
|
+
);
|
|
16
|
+
const refs = useRef<(HTMLButtonElement | null)[]>([]);
|
|
17
|
+
return (
|
|
18
|
+
<div>
|
|
19
|
+
<div
|
|
20
|
+
role="tablist"
|
|
21
|
+
aria-label={label}
|
|
22
|
+
className="flex gap-16 max-w-full overflow-x-auto border-b border-border-subtle [scrollbar-width:none]"
|
|
23
|
+
>
|
|
24
|
+
{tabs.map((tab, i) => {
|
|
25
|
+
const selected = tab.value === current;
|
|
26
|
+
return (
|
|
27
|
+
<button
|
|
28
|
+
key={tab.value}
|
|
29
|
+
ref={(el) => {
|
|
30
|
+
refs.current[i] = el;
|
|
31
|
+
}}
|
|
32
|
+
type="button"
|
|
33
|
+
role="tab"
|
|
34
|
+
id={`${base}-tab-${i}`}
|
|
35
|
+
aria-selected={selected}
|
|
36
|
+
aria-controls={panels ? `${base}-panel-${i}` : undefined}
|
|
37
|
+
tabIndex={selected ? 0 : -1}
|
|
38
|
+
onClick={() => setCurrent(tab.value)}
|
|
39
|
+
onKeyDown={(e) => {
|
|
40
|
+
const next = rovingIndex(e.key, i, tabs.length, "horizontal", dir);
|
|
41
|
+
if (next === null) return;
|
|
42
|
+
e.preventDefault();
|
|
43
|
+
const target = tabs[next];
|
|
44
|
+
if (target) setCurrent(target.value);
|
|
45
|
+
refs.current[next]?.focus();
|
|
46
|
+
}}
|
|
47
|
+
className={cx(
|
|
48
|
+
"relative inline-flex flex-none items-center gap-6 py-8 bg-transparent border-0 whitespace-nowrap cursor-pointer",
|
|
49
|
+
"font-medium text-text-13 text-text-secondary aria-selected:text-text-primary",
|
|
50
|
+
"after:absolute after:inset-x-0 after:-bottom-(--stroke-width-hairline) after:h-(--stroke-width-focus) after:bg-transparent aria-selected:after:bg-accent",
|
|
51
|
+
"pointer-coarse:min-h-target-coarse pointer-coarse:min-w-target-coarse",
|
|
52
|
+
)}
|
|
53
|
+
>
|
|
54
|
+
{tab.label}
|
|
55
|
+
{tab.count !== undefined ? (
|
|
56
|
+
<span className="text-text-12 text-text-tertiary tabular-nums">{tab.count}</span>
|
|
57
|
+
) : null}
|
|
58
|
+
</button>
|
|
59
|
+
);
|
|
60
|
+
})}
|
|
61
|
+
</div>
|
|
62
|
+
{panels
|
|
63
|
+
? tabs.map((tab, i) => (
|
|
64
|
+
<div
|
|
65
|
+
key={tab.value}
|
|
66
|
+
role="tabpanel"
|
|
67
|
+
id={`${base}-panel-${i}`}
|
|
68
|
+
aria-labelledby={`${base}-tab-${i}`}
|
|
69
|
+
hidden={tab.value !== current}
|
|
70
|
+
tabIndex={0}
|
|
71
|
+
className="pt-16"
|
|
72
|
+
>
|
|
73
|
+
{panels[tab.value]}
|
|
74
|
+
</div>
|
|
75
|
+
))
|
|
76
|
+
: null}
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
5
|
+
import { IconButton } from "../Button/Button.tsx";
|
|
6
|
+
import { Badge } from "../Chips/Chips.tsx";
|
|
7
|
+
import { Avatar } from "../Avatar/Avatar.tsx";
|
|
8
|
+
import { BrandMark } from "../BrandMark/BrandMark.tsx";
|
|
9
|
+
import { ItemAction } from "./Navigation.shared.tsx";
|
|
10
|
+
import { type TopNavProps } from "./Navigation.types.ts";
|
|
11
|
+
|
|
12
|
+
/** The Gateway top bar on desktop: brand, the five destinations, search, help and the account menu. */
|
|
13
|
+
export function TopNav({
|
|
14
|
+
brand,
|
|
15
|
+
label,
|
|
16
|
+
person,
|
|
17
|
+
active,
|
|
18
|
+
items,
|
|
19
|
+
onSearch,
|
|
20
|
+
onHelp,
|
|
21
|
+
onAccount,
|
|
22
|
+
}: TopNavProps): ReactElement {
|
|
23
|
+
const t = useT();
|
|
24
|
+
return (
|
|
25
|
+
<header
|
|
26
|
+
className={cx(
|
|
27
|
+
"flex items-center justify-between gap-16 h-(--ui-topnav) px-20 max-lg:px-16 bg-bg-surface border-b border-border-subtle",
|
|
28
|
+
"print:hidden",
|
|
29
|
+
)}
|
|
30
|
+
>
|
|
31
|
+
<div className="flex items-center gap-24 max-lg:gap-12 min-w-0">
|
|
32
|
+
<span className="max-lg:[&_[aria-hidden]+[aria-hidden]]:hidden">
|
|
33
|
+
<BrandMark name={brand} size="sm" />
|
|
34
|
+
</span>
|
|
35
|
+
<nav
|
|
36
|
+
aria-label={label}
|
|
37
|
+
className="min-w-0 overflow-x-auto max-md:hidden [scrollbar-width:none]"
|
|
38
|
+
>
|
|
39
|
+
{/* The nav scrolls sideways, which clips on both axes: the list's padding holds the 2px focus outline and
|
|
40
|
+
its 2px offset inside the scroll box, so a focused link keeps its whole ring. */}
|
|
41
|
+
<ul className="flex gap-4 m-0 p-4 list-none">
|
|
42
|
+
{items.map((item) => (
|
|
43
|
+
<li key={item.label}>
|
|
44
|
+
<ItemAction
|
|
45
|
+
item={item}
|
|
46
|
+
active={item.label === active}
|
|
47
|
+
className={cx(
|
|
48
|
+
"inline-flex items-center gap-6 h-row-default px-12 max-lg:px-8 rounded-control no-underline",
|
|
49
|
+
"font-medium text-text-14 text-text-secondary hover:bg-bg-hover hover:text-text-primary",
|
|
50
|
+
"aria-[current=page]:bg-bg-hover aria-[current=page]:text-text-primary",
|
|
51
|
+
"pointer-coarse:min-h-target-coarse pointer-coarse:min-w-target-coarse",
|
|
52
|
+
)}
|
|
53
|
+
>
|
|
54
|
+
<Icon name={item.icon} size={16} />
|
|
55
|
+
{item.label}
|
|
56
|
+
{item.badge ? (
|
|
57
|
+
<Badge
|
|
58
|
+
count={item.badge}
|
|
59
|
+
tone="accent"
|
|
60
|
+
label={t("tabbar.badge", { n: item.badge })}
|
|
61
|
+
/>
|
|
62
|
+
) : null}
|
|
63
|
+
</ItemAction>
|
|
64
|
+
</li>
|
|
65
|
+
))}
|
|
66
|
+
</ul>
|
|
67
|
+
</nav>
|
|
68
|
+
</div>
|
|
69
|
+
<div className="flex flex-none items-center gap-8">
|
|
70
|
+
<IconButton icon="Search" label={t("command.label")} shortcut="⌘ K" onClick={onSearch} />
|
|
71
|
+
<IconButton icon="CircleHelp" label={t("help.title")} shortcut="?" onClick={onHelp} />
|
|
72
|
+
<button
|
|
73
|
+
type="button"
|
|
74
|
+
aria-haspopup="dialog"
|
|
75
|
+
aria-label={t("nav.account", { name: person })}
|
|
76
|
+
onClick={onAccount}
|
|
77
|
+
className="xos-hit grid place-items-center size-(--ui-avatar-lg) p-0 rounded-full border-0 bg-transparent cursor-pointer"
|
|
78
|
+
>
|
|
79
|
+
<span aria-hidden="true" className="contents">
|
|
80
|
+
<Avatar name={person} />
|
|
81
|
+
</span>
|
|
82
|
+
</button>
|
|
83
|
+
</div>
|
|
84
|
+
</header>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { cx } from "../lib/cx.ts";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* The Sidebar's classes in a module of their own, for lists built beside it (the Atlas Favorites, which reorder):
|
|
5
|
+
* a list loaded on demand can share them without pulling the Sidebar itself apart from the page that renders it.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** One sidebar item, for lists built beside the Sidebar (the Atlas Favorites, which reorder). */
|
|
9
|
+
export const sidebarItemClass = cx(
|
|
10
|
+
"flex items-center gap-8 w-full h-control-md px-8 rounded-control border-0 bg-transparent box-border",
|
|
11
|
+
"font-medium text-text-13 text-text-secondary text-start no-underline cursor-pointer",
|
|
12
|
+
"hover:bg-bg-hover hover:text-text-primary aria-[current=page]:bg-bg-hover aria-[current=page]:text-text-primary",
|
|
13
|
+
"pointer-coarse:min-h-target-coarse",
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
/** The sidebar's frame, for lists built beside the Sidebar so they match it. */
|
|
17
|
+
export const sidebarClass =
|
|
18
|
+
"w-(--layout-sidebar) max-w-full p-8 box-border bg-bg-surface border border-border-subtle rounded-card print:hidden";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { Dialog as RDialog } from "radix-ui";
|
|
3
|
+
import { cx } from "../lib/cx.ts";
|
|
4
|
+
import { useReturnFocus } from "../lib/hooks.ts";
|
|
5
|
+
import { scrimClass, useOverlayOpen } from "./Overlays.shared.tsx";
|
|
6
|
+
import { type DialogProps } from "./Overlays.types.ts";
|
|
7
|
+
import { panelClass } from "./panelClass.tsx";
|
|
8
|
+
|
|
9
|
+
/** For irreversible actions only; everything else uses Undo. Focus is trapped and Esc closes. */
|
|
10
|
+
export function Dialog({
|
|
11
|
+
title,
|
|
12
|
+
children,
|
|
13
|
+
actions,
|
|
14
|
+
description,
|
|
15
|
+
...control
|
|
16
|
+
}: DialogProps): ReactElement {
|
|
17
|
+
const [isOpen, setOpen] = useOverlayOpen(control);
|
|
18
|
+
const returnFocus = useReturnFocus(isOpen);
|
|
19
|
+
return (
|
|
20
|
+
<RDialog.Root open={isOpen} onOpenChange={setOpen}>
|
|
21
|
+
{control.trigger ? <RDialog.Trigger asChild>{control.trigger}</RDialog.Trigger> : null}
|
|
22
|
+
<RDialog.Portal>
|
|
23
|
+
<RDialog.Overlay className={scrimClass} />
|
|
24
|
+
{/* One row of minmax(0, 1fr): an auto row would grow to a tall panel, so max-h-full would not hold it to the viewport. */}
|
|
25
|
+
<div className="pointer-events-none fixed inset-0 z-dialog grid grid-rows-1 place-items-center p-16">
|
|
26
|
+
<RDialog.Content
|
|
27
|
+
onCloseAutoFocus={returnFocus}
|
|
28
|
+
className={cx(
|
|
29
|
+
panelClass,
|
|
30
|
+
"xos-anim-dialog pointer-events-auto w-(--ui-dialog) flex flex-col max-h-full",
|
|
31
|
+
)}
|
|
32
|
+
{...(description ? {} : { "aria-describedby": undefined })}
|
|
33
|
+
>
|
|
34
|
+
<header className="shrink-0 px-20 pt-20">
|
|
35
|
+
<RDialog.Title className="m-0 text-heading-16 font-semibold">{title}</RDialog.Title>
|
|
36
|
+
{description ? (
|
|
37
|
+
<RDialog.Description className="mt-4 mb-0 text-text-secondary">
|
|
38
|
+
{description}
|
|
39
|
+
</RDialog.Description>
|
|
40
|
+
) : null}
|
|
41
|
+
</header>
|
|
42
|
+
{/* The body scrolls so a long body never pushes the actions out of the viewport. */}
|
|
43
|
+
<div className="min-h-0 overflow-y-auto overscroll-contain px-20 pt-8 pb-20 text-text-secondary">
|
|
44
|
+
{children}
|
|
45
|
+
</div>
|
|
46
|
+
<footer className="shrink-0 flex flex-wrap justify-end gap-8 px-20 py-12 border-t border-border-subtle">
|
|
47
|
+
{actions}
|
|
48
|
+
</footer>
|
|
49
|
+
</RDialog.Content>
|
|
50
|
+
</div>
|
|
51
|
+
</RDialog.Portal>
|
|
52
|
+
</RDialog.Root>
|
|
53
|
+
);
|
|
54
|
+
}
|