@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,111 @@
|
|
|
1
|
+
import { 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 { ScrollRegion } from "../Layout/Layout.tsx";
|
|
6
|
+
import { useGridFocus } from "./XOS.shared.tsx";
|
|
7
|
+
import { type AccessGridMatrixProps } from "./XOS.types.ts";
|
|
8
|
+
|
|
9
|
+
const CAT: Record<number, string> = {
|
|
10
|
+
1: cx("bg-viz-cat-1"),
|
|
11
|
+
2: cx("bg-viz-cat-2"),
|
|
12
|
+
3: cx("bg-viz-cat-3"),
|
|
13
|
+
4: cx("bg-viz-cat-4"),
|
|
14
|
+
5: cx("bg-viz-cat-5"),
|
|
15
|
+
6: cx("bg-viz-cat-6"),
|
|
16
|
+
7: cx("bg-viz-cat-7"),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Which credential categories enter which zones; Compass validates scans against it offline. An
|
|
21
|
+
* ARIA grid: arrows move, Space or Enter toggles a grant.
|
|
22
|
+
*/
|
|
23
|
+
export function AccessGridMatrix({
|
|
24
|
+
label,
|
|
25
|
+
zones,
|
|
26
|
+
categories,
|
|
27
|
+
grants,
|
|
28
|
+
onChange,
|
|
29
|
+
}: AccessGridMatrixProps): ReactElement {
|
|
30
|
+
const t = useT();
|
|
31
|
+
const [granted, setGranted] = useState(grants);
|
|
32
|
+
const grid = useGridFocus(categories.length, zones.length);
|
|
33
|
+
const has = (cat: string, zone: string) => granted.includes(`${cat}|${zone}`);
|
|
34
|
+
const toggle = (cat: string, zone: string) => {
|
|
35
|
+
const key = `${cat}|${zone}`;
|
|
36
|
+
const next = has(cat, zone) ? granted.filter((g) => g !== key) : [...granted, key];
|
|
37
|
+
setGranted(next);
|
|
38
|
+
onChange?.(next);
|
|
39
|
+
};
|
|
40
|
+
return (
|
|
41
|
+
<ScrollRegion label={label}>
|
|
42
|
+
<table
|
|
43
|
+
role="grid"
|
|
44
|
+
aria-label={label}
|
|
45
|
+
className="border-separate border-spacing-2 text-text-12"
|
|
46
|
+
>
|
|
47
|
+
<caption className="pb-8 text-start text-text-13 font-semibold">{label}</caption>
|
|
48
|
+
<thead>
|
|
49
|
+
<tr>
|
|
50
|
+
<th scope="col" className="p-4 text-start font-medium text-text-secondary">
|
|
51
|
+
{t("access.credential")}
|
|
52
|
+
</th>
|
|
53
|
+
{zones.map((z) => (
|
|
54
|
+
<th key={z} scope="col" className="p-4 font-medium text-text-secondary">
|
|
55
|
+
{z}
|
|
56
|
+
</th>
|
|
57
|
+
))}
|
|
58
|
+
</tr>
|
|
59
|
+
</thead>
|
|
60
|
+
<tbody>
|
|
61
|
+
{categories.map((cat, ri) => (
|
|
62
|
+
<tr key={cat.name}>
|
|
63
|
+
<th scope="row" className="pe-12 text-start font-medium whitespace-nowrap">
|
|
64
|
+
<span className="inline-flex items-center gap-6">
|
|
65
|
+
<span
|
|
66
|
+
aria-hidden="true"
|
|
67
|
+
className={cx(
|
|
68
|
+
"inline-block size-(--ui-switch-knob) rounded-mark",
|
|
69
|
+
CAT[cat.color],
|
|
70
|
+
)}
|
|
71
|
+
/>
|
|
72
|
+
{cat.name}
|
|
73
|
+
</span>
|
|
74
|
+
</th>
|
|
75
|
+
{zones.map((zone, ci) => {
|
|
76
|
+
const on = has(cat.name, zone);
|
|
77
|
+
return (
|
|
78
|
+
<td
|
|
79
|
+
key={zone}
|
|
80
|
+
ref={grid.register(ri, ci)}
|
|
81
|
+
role="gridcell"
|
|
82
|
+
aria-selected={on}
|
|
83
|
+
aria-label={t(on ? "access.allowed" : "access.denied", { cat: cat.name, zone })}
|
|
84
|
+
tabIndex={grid.tabIndex(ri, ci)}
|
|
85
|
+
onFocus={() => grid.setActive([ri, ci])}
|
|
86
|
+
onClick={() => toggle(cat.name, zone)}
|
|
87
|
+
onKeyDown={(e) => {
|
|
88
|
+
if (e.key === " " || e.key === "Enter") {
|
|
89
|
+
e.preventDefault();
|
|
90
|
+
toggle(cat.name, zone);
|
|
91
|
+
} else grid.onKeyDown(e, ri, ci);
|
|
92
|
+
}}
|
|
93
|
+
className={cx(
|
|
94
|
+
"xos-hit w-(--space-40) h-control-md rounded-chip text-center cursor-pointer",
|
|
95
|
+
on
|
|
96
|
+
? "bg-bg-hover text-success ring-(length:--stroke-width-hairline) ring-inset ring-success"
|
|
97
|
+
: "bg-bg-surface text-text-tertiary ring-(length:--stroke-width-hairline) ring-inset ring-border-subtle",
|
|
98
|
+
"forced-colors:border",
|
|
99
|
+
)}
|
|
100
|
+
>
|
|
101
|
+
<Icon name={on ? "Check" : "Minus"} size={14} />
|
|
102
|
+
</td>
|
|
103
|
+
);
|
|
104
|
+
})}
|
|
105
|
+
</tr>
|
|
106
|
+
))}
|
|
107
|
+
</tbody>
|
|
108
|
+
</table>
|
|
109
|
+
</ScrollRegion>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { chipClass } from "../Chips/Chips.tsx";
|
|
5
|
+
import { type AssertionRankBadgeProps } from "./XOS.types.ts";
|
|
6
|
+
|
|
7
|
+
/** An assertion value with four pips for its rank from 4 down to 0. */
|
|
8
|
+
export function AssertionRankBadge({ label, rank }: AssertionRankBadgeProps): ReactElement {
|
|
9
|
+
const t = useT();
|
|
10
|
+
const on = rank === 4 ? "bg-success" : rank <= 1 ? "bg-warning" : "bg-text-secondary";
|
|
11
|
+
return (
|
|
12
|
+
<span role="img" aria-label={t("assertion.aria", { label, rank })} className={chipClass}>
|
|
13
|
+
<span aria-hidden="true" className="inline-flex gap-2">
|
|
14
|
+
{[1, 2, 3, 4].map((i) => (
|
|
15
|
+
<span
|
|
16
|
+
key={i}
|
|
17
|
+
className={cx(
|
|
18
|
+
"w-(--ui-pip-inline) h-(--ui-pip-block) rounded-mark",
|
|
19
|
+
i <= rank ? on : "bg-border-strong",
|
|
20
|
+
)}
|
|
21
|
+
/>
|
|
22
|
+
))}
|
|
23
|
+
</span>
|
|
24
|
+
<span aria-hidden="true">{label}</span>
|
|
25
|
+
</span>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useFormat, useT } from "../lib/context.tsx";
|
|
4
|
+
import { DepartmentGlyph, PhaseGlyph } from "../Glyphs/Glyphs.tsx";
|
|
5
|
+
import { ScrollRegion } from "../Layout/Layout.tsx";
|
|
6
|
+
import { useGridFocus } from "./XOS.shared.tsx";
|
|
7
|
+
import { type CoordinateMatrixProps } from "./XOS.types.ts";
|
|
8
|
+
|
|
9
|
+
const SEQ: Record<number, string> = {
|
|
10
|
+
2: cx("bg-viz-seq-2 text-viz-ink"),
|
|
11
|
+
3: cx("bg-viz-seq-3 text-viz-ink"),
|
|
12
|
+
4: cx("bg-viz-seq-4 text-viz-ink"),
|
|
13
|
+
5: cx("bg-viz-seq-5 text-viz-ink"),
|
|
14
|
+
6: cx("bg-viz-seq-6 text-accent-text-on"),
|
|
15
|
+
7: cx("bg-viz-seq-7 text-accent-text-on"),
|
|
16
|
+
8: cx("bg-viz-seq-8 text-accent-text-on"),
|
|
17
|
+
9: cx("bg-viz-seq-9 text-accent-text-on"),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The 10 departments crossed with the 9 phases. An ARIA grid: arrows move between cells, Enter
|
|
22
|
+
* drills into a coordinate's records. Empty coordinates are outlined, not filled.
|
|
23
|
+
*/
|
|
24
|
+
export function CoordinateMatrix({
|
|
25
|
+
label,
|
|
26
|
+
corner,
|
|
27
|
+
rows,
|
|
28
|
+
cols,
|
|
29
|
+
cells,
|
|
30
|
+
onCellSelect,
|
|
31
|
+
}: CoordinateMatrixProps): ReactElement {
|
|
32
|
+
const t = useT();
|
|
33
|
+
const fmt = useFormat();
|
|
34
|
+
const grid = useGridFocus(rows.length, cols.length);
|
|
35
|
+
const max = Math.max(0, ...Object.values(cells));
|
|
36
|
+
const step = (v: number) => (v ? Math.min(9, 2 + Math.round((v / max) * 6)) : 0);
|
|
37
|
+
return (
|
|
38
|
+
<ScrollRegion label={label}>
|
|
39
|
+
<table
|
|
40
|
+
role="grid"
|
|
41
|
+
aria-label={label}
|
|
42
|
+
className="border-separate border-spacing-2 text-text-12"
|
|
43
|
+
>
|
|
44
|
+
<caption className="pb-8 text-start text-text-13 font-semibold">{label}</caption>
|
|
45
|
+
<thead>
|
|
46
|
+
<tr>
|
|
47
|
+
<th scope="col" className="p-4 text-start font-medium text-text-secondary">
|
|
48
|
+
{corner}
|
|
49
|
+
</th>
|
|
50
|
+
{cols.map((c) => (
|
|
51
|
+
<th
|
|
52
|
+
key={c.code}
|
|
53
|
+
scope="col"
|
|
54
|
+
title={c.name}
|
|
55
|
+
className="p-4 font-medium text-text-secondary text-center"
|
|
56
|
+
>
|
|
57
|
+
<span className="flex flex-col items-center gap-2">
|
|
58
|
+
<PhaseGlyph
|
|
59
|
+
code={c.code}
|
|
60
|
+
size={14}
|
|
61
|
+
label={t("phase.gateName", { n: c.gate, name: c.name })}
|
|
62
|
+
/>
|
|
63
|
+
<span aria-hidden="true" className="tabular-nums">
|
|
64
|
+
{c.gate}
|
|
65
|
+
</span>
|
|
66
|
+
</span>
|
|
67
|
+
</th>
|
|
68
|
+
))}
|
|
69
|
+
</tr>
|
|
70
|
+
</thead>
|
|
71
|
+
<tbody>
|
|
72
|
+
{rows.map((r, ri) => (
|
|
73
|
+
<tr key={r.code}>
|
|
74
|
+
<th scope="row" className="pe-12 text-start font-medium whitespace-nowrap">
|
|
75
|
+
<span className="inline-flex items-center gap-6">
|
|
76
|
+
<DepartmentGlyph code={r.code} size={14} color="var(--color-text-secondary)" />
|
|
77
|
+
<span>{r.name}</span>
|
|
78
|
+
<span className="font-mono text-text-secondary">{r.code}</span>
|
|
79
|
+
</span>
|
|
80
|
+
</th>
|
|
81
|
+
{cols.map((c, ci) => {
|
|
82
|
+
const v = cells[`${r.code}|${c.code}`] ?? 0;
|
|
83
|
+
const s = step(v);
|
|
84
|
+
const name = v
|
|
85
|
+
? t("matrix.cell", { row: r.name, col: c.name, n: fmt.number(v) })
|
|
86
|
+
: t("matrix.empty", { row: r.name, col: c.name });
|
|
87
|
+
return (
|
|
88
|
+
<td
|
|
89
|
+
key={c.code}
|
|
90
|
+
ref={grid.register(ri, ci)}
|
|
91
|
+
role="gridcell"
|
|
92
|
+
tabIndex={grid.tabIndex(ri, ci)}
|
|
93
|
+
aria-label={name}
|
|
94
|
+
onFocus={() => grid.setActive([ri, ci])}
|
|
95
|
+
onKeyDown={(e) => {
|
|
96
|
+
if ((e.key === "Enter" || e.key === " ") && v) {
|
|
97
|
+
e.preventDefault();
|
|
98
|
+
onCellSelect?.(r.code, c.code);
|
|
99
|
+
} else grid.onKeyDown(e, ri, ci);
|
|
100
|
+
}}
|
|
101
|
+
onClick={() => (v ? onCellSelect?.(r.code, c.code) : undefined)}
|
|
102
|
+
className={cx(
|
|
103
|
+
"xos-hit w-(--space-48) h-control-md rounded-chip text-center font-semibold tabular-nums",
|
|
104
|
+
v
|
|
105
|
+
? cx(
|
|
106
|
+
SEQ[s],
|
|
107
|
+
"cursor-pointer hover:outline-solid hover:outline-stroke-focus hover:outline-text-primary",
|
|
108
|
+
)
|
|
109
|
+
: "ring-(length:--stroke-width-hairline) ring-inset ring-border-subtle",
|
|
110
|
+
"forced-colors:border",
|
|
111
|
+
)}
|
|
112
|
+
>
|
|
113
|
+
{v ? <span aria-hidden="true">{fmt.number(v)}</span> : null}
|
|
114
|
+
</td>
|
|
115
|
+
);
|
|
116
|
+
})}
|
|
117
|
+
</tr>
|
|
118
|
+
))}
|
|
119
|
+
</tbody>
|
|
120
|
+
</table>
|
|
121
|
+
</ScrollRegion>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
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 { SERVICES } from "./XOS.shared.tsx";
|
|
6
|
+
import { type EmergencyCodeCardProps } from "./XOS.types.ts";
|
|
7
|
+
import { resolveStep } from "./resolveStep.tsx";
|
|
8
|
+
|
|
9
|
+
const SWATCH: Record<EmergencyCodeCardProps["swatch"], string> = {
|
|
10
|
+
"ecode-red": cx("bg-ecode-red border-t-ecode-red"),
|
|
11
|
+
"ecode-orange": cx("bg-ecode-orange border-t-ecode-orange"),
|
|
12
|
+
"ecode-yellow": cx("bg-ecode-yellow border-t-ecode-yellow"),
|
|
13
|
+
"ecode-green": cx("bg-ecode-green border-t-ecode-green"),
|
|
14
|
+
"ecode-blue": cx("bg-ecode-blue border-t-ecode-blue"),
|
|
15
|
+
"ecode-purple": cx("bg-ecode-purple border-t-ecode-purple"),
|
|
16
|
+
"ecode-white": cx("bg-ecode-white border-t-ecode-white"),
|
|
17
|
+
"ecode-black": cx("bg-ecode-black border-t-ecode-black"),
|
|
18
|
+
"ecode-pink": cx("bg-ecode-pink border-t-ecode-pink"),
|
|
19
|
+
"ecode-indigo": cx("bg-ecode-indigo border-t-ecode-indigo"),
|
|
20
|
+
"ecode-silver": cx("bg-ecode-silver border-t-ecode-silver"),
|
|
21
|
+
"ecode-grey": cx("bg-ecode-grey border-t-ecode-grey"),
|
|
22
|
+
"ecode-amber": cx("bg-ecode-amber border-t-ecode-amber"),
|
|
23
|
+
"ecode-adam": cx("bg-ecode-adam border-t-ecode-adam"),
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* One global emergency code's protocol for one operational domain. The code word is always written;
|
|
28
|
+
* the swatch is for recognition only. Steps name services; the jurisdiction supplies the agencies.
|
|
29
|
+
*/
|
|
30
|
+
export function EmergencyCodeCard({
|
|
31
|
+
authorities,
|
|
32
|
+
recordKey,
|
|
33
|
+
code,
|
|
34
|
+
name,
|
|
35
|
+
swatch,
|
|
36
|
+
domain,
|
|
37
|
+
steps,
|
|
38
|
+
channel,
|
|
39
|
+
}: EmergencyCodeCardProps): ReactElement {
|
|
40
|
+
const t = useT();
|
|
41
|
+
const used = SERVICES.filter((s) => steps.some((step) => step.includes(`{${s}}`)));
|
|
42
|
+
const listed = (authorities ?? [])
|
|
43
|
+
.filter((a) => used.includes(a.service))
|
|
44
|
+
.sort((a, b) => SERVICES.indexOf(a.service) - SERVICES.indexOf(b.service));
|
|
45
|
+
const tone = SWATCH[swatch] ?? SWATCH["ecode-red"];
|
|
46
|
+
return (
|
|
47
|
+
<article
|
|
48
|
+
aria-labelledby={`${recordKey ?? code}-title`}
|
|
49
|
+
className={cx(
|
|
50
|
+
"flex flex-col gap-8 w-(--ui-popover) max-w-full p-16 box-border rounded-card bg-bg-raised",
|
|
51
|
+
"border border-border-subtle border-t-stroke-swatch",
|
|
52
|
+
tone.split(" ")[1],
|
|
53
|
+
)}
|
|
54
|
+
>
|
|
55
|
+
<header className="flex items-center gap-8">
|
|
56
|
+
<span
|
|
57
|
+
aria-hidden="true"
|
|
58
|
+
className={cx(
|
|
59
|
+
"flex-none size-icon-24 rounded-chip ring-(length:--stroke-width-hairline) ring-inset ring-border-control",
|
|
60
|
+
tone.split(" ")[0],
|
|
61
|
+
)}
|
|
62
|
+
/>
|
|
63
|
+
<div className="flex flex-col">
|
|
64
|
+
<strong id={`${recordKey ?? code}-title`} className="text-heading-16 font-semibold">
|
|
65
|
+
{code}
|
|
66
|
+
</strong>
|
|
67
|
+
<span>{name}</span>
|
|
68
|
+
</div>
|
|
69
|
+
{recordKey ? (
|
|
70
|
+
<span className="ms-auto font-mono text-text-12 text-text-secondary">{recordKey}</span>
|
|
71
|
+
) : null}
|
|
72
|
+
</header>
|
|
73
|
+
{domain ? (
|
|
74
|
+
<span className="text-text-12 font-medium text-text-secondary">{domain}</span>
|
|
75
|
+
) : null}
|
|
76
|
+
<ol className="flex flex-col gap-4 m-0 ps-20">
|
|
77
|
+
{steps.map((step, i) => (
|
|
78
|
+
<li key={i}>{resolveStep(step, authorities, t)}</li>
|
|
79
|
+
))}
|
|
80
|
+
</ol>
|
|
81
|
+
{listed.length ? (
|
|
82
|
+
<dl
|
|
83
|
+
aria-label={t("ecode.authorities")}
|
|
84
|
+
className="flex flex-col gap-4 m-0 pt-8 border-t border-border-subtle"
|
|
85
|
+
>
|
|
86
|
+
{listed.map((a) => (
|
|
87
|
+
<div key={a.service} className="flex gap-8">
|
|
88
|
+
<dt className="flex-none w-(--ui-props-label) text-text-12 font-medium text-text-secondary">
|
|
89
|
+
{t(`ecode.role.${a.service}`)}
|
|
90
|
+
</dt>
|
|
91
|
+
<dd className="m-0">
|
|
92
|
+
{a.agency}
|
|
93
|
+
{a.contact ? (
|
|
94
|
+
<span className="text-text-secondary tabular-nums"> · {a.contact}</span>
|
|
95
|
+
) : null}
|
|
96
|
+
</dd>
|
|
97
|
+
</div>
|
|
98
|
+
))}
|
|
99
|
+
</dl>
|
|
100
|
+
) : null}
|
|
101
|
+
{channel ? (
|
|
102
|
+
<footer className="flex items-center gap-6 text-text-12 text-text-secondary">
|
|
103
|
+
<Icon name="Radio" size={14} />
|
|
104
|
+
<span>{channel}</span>
|
|
105
|
+
</footer>
|
|
106
|
+
) : null}
|
|
107
|
+
</article>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
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 { Button } from "../Button/Button.tsx";
|
|
6
|
+
import { PhaseGlyph } from "../Glyphs/Glyphs.tsx";
|
|
7
|
+
import { Tag, chipClass } from "../Chips/Chips.tsx";
|
|
8
|
+
import { cardBodyClass, cardClass, cardFootClass, cardHeadClass } from "../Surface/Surface.tsx";
|
|
9
|
+
import { ResultIcon } from "./XOS.shared.tsx";
|
|
10
|
+
import { type GateReadinessPanelProps } from "./XOS.types.ts";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A gate's criteria as a checklist with evidence, blocking flags and the action that clears each
|
|
14
|
+
* gap. The next-gate button enables when the last blocking criterion is met.
|
|
15
|
+
*/
|
|
16
|
+
export function GateReadinessPanel({
|
|
17
|
+
gate,
|
|
18
|
+
code,
|
|
19
|
+
name,
|
|
20
|
+
nextLabel,
|
|
21
|
+
criteria,
|
|
22
|
+
onAdvance,
|
|
23
|
+
onCriterionAction,
|
|
24
|
+
}: GateReadinessPanelProps): ReactElement {
|
|
25
|
+
const t = useT();
|
|
26
|
+
const met = criteria.filter((c) => c.result === "met").length;
|
|
27
|
+
const blockers = criteria.filter((c) => c.blocking && c.result !== "met").length;
|
|
28
|
+
return (
|
|
29
|
+
<section aria-label={t("gate.readiness")} className={cx(cardClass, "max-w-(--layout-form)")}>
|
|
30
|
+
<header className={cardHeadClass}>
|
|
31
|
+
<span className="flex items-center gap-8">
|
|
32
|
+
<PhaseGlyph code={code} color="var(--color-text-secondary)" />
|
|
33
|
+
<strong className="font-semibold">{t("phase.gateName", { n: gate, name })}</strong>
|
|
34
|
+
</span>
|
|
35
|
+
<span className="text-text-secondary tabular-nums">
|
|
36
|
+
{t("gate.metCount", { met, total: criteria.length })}
|
|
37
|
+
</span>
|
|
38
|
+
</header>
|
|
39
|
+
<div className={cardBodyClass}>
|
|
40
|
+
<div
|
|
41
|
+
role="progressbar"
|
|
42
|
+
aria-label={t("gate.criteriaMet")}
|
|
43
|
+
aria-valuenow={met}
|
|
44
|
+
aria-valuemin={0}
|
|
45
|
+
aria-valuemax={criteria.length}
|
|
46
|
+
className="h-(--space-4) rounded-pill bg-bg-hover overflow-hidden"
|
|
47
|
+
>
|
|
48
|
+
<div
|
|
49
|
+
className="h-full rounded-pill bg-success forced-colors:bg-[Highlight]"
|
|
50
|
+
style={{ inlineSize: `${criteria.length ? (met / criteria.length) * 100 : 0}%` }}
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
<ul className="xos-criteria m-0 p-0 list-none">
|
|
54
|
+
{criteria.map((c) => (
|
|
55
|
+
<li
|
|
56
|
+
key={c.code ?? c.label}
|
|
57
|
+
className="flex items-center gap-8 min-h-(--space-40) border-b border-border-subtle last:border-b-0"
|
|
58
|
+
>
|
|
59
|
+
<ResultIcon result={c.result} t={t} />
|
|
60
|
+
{c.code ? (
|
|
61
|
+
<span className="font-mono text-text-12 text-text-secondary">{c.code}</span>
|
|
62
|
+
) : null}
|
|
63
|
+
<span className="xos-criteria-label flex-1">{c.label}</span>
|
|
64
|
+
{c.blocking ? (
|
|
65
|
+
<Tag tone={c.result === "met" ? "neutral" : "danger"}>{t("gate.blocking")}</Tag>
|
|
66
|
+
) : null}
|
|
67
|
+
{c.evidence ? (
|
|
68
|
+
<span className={chipClass}>
|
|
69
|
+
<Icon name="Paperclip" size={12} />
|
|
70
|
+
{c.evidence}
|
|
71
|
+
</span>
|
|
72
|
+
) : c.result !== "met" && c.action ? (
|
|
73
|
+
<Button size="sm" onClick={() => onCriterionAction?.(c.code, c.label)}>
|
|
74
|
+
{c.action}
|
|
75
|
+
</Button>
|
|
76
|
+
) : null}
|
|
77
|
+
</li>
|
|
78
|
+
))}
|
|
79
|
+
</ul>
|
|
80
|
+
</div>
|
|
81
|
+
{/* On a narrow card the action takes its own full-width line under the count (A59-023). */}
|
|
82
|
+
<footer className={cx(cardFootClass, "justify-between flex-wrap")}>
|
|
83
|
+
<span className="text-text-secondary" aria-live="polite">
|
|
84
|
+
{blockers
|
|
85
|
+
? t(blockers === 1 ? "gate.openOne" : "gate.openMany", { n: blockers })
|
|
86
|
+
: t("gate.allMet")}
|
|
87
|
+
</span>
|
|
88
|
+
<Button
|
|
89
|
+
variant="primary"
|
|
90
|
+
disabled={blockers > 0}
|
|
91
|
+
shortcut="⌘↵"
|
|
92
|
+
onClick={onAdvance}
|
|
93
|
+
className="max-sm:w-full"
|
|
94
|
+
>
|
|
95
|
+
{nextLabel}
|
|
96
|
+
</Button>
|
|
97
|
+
</footer>
|
|
98
|
+
</section>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { useT } from "../lib/context.tsx";
|
|
3
|
+
import { chipClass, codeClass } from "../Chips/Chips.tsx";
|
|
4
|
+
import { type ProvenanceBadgeProps } from "./XOS.types.ts";
|
|
5
|
+
|
|
6
|
+
/** Who wrote a canon field and its provenance rank. */
|
|
7
|
+
export function ProvenanceBadge({ source, rank }: ProvenanceBadgeProps): ReactElement {
|
|
8
|
+
const t = useT();
|
|
9
|
+
return (
|
|
10
|
+
<span className={chipClass} title={t("provenance.rank", { rank })}>
|
|
11
|
+
<span className="text-text-secondary">{t("provenance.source")}</span>
|
|
12
|
+
<span>{source}</span>
|
|
13
|
+
<span className={codeClass}>
|
|
14
|
+
<span className="sr-only">{t("provenance.rank", { rank })}</span>
|
|
15
|
+
<span aria-hidden="true">{rank}</span>
|
|
16
|
+
</span>
|
|
17
|
+
</span>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { codeClass } from "../Chips/Chips.tsx";
|
|
5
|
+
import { ScrollRegion } from "../Layout/Layout.tsx";
|
|
6
|
+
import { tableClass, tdClass, thClass } from "./XOS.shared.tsx";
|
|
7
|
+
import { type RadioChannelTableProps } from "./XOS.types.ts";
|
|
8
|
+
|
|
9
|
+
/** The radio plan, always sorted by zone then channel; notes wrap so it reads on a phone. */
|
|
10
|
+
export function RadioChannelTable({ caption, channels }: RadioChannelTableProps): ReactElement {
|
|
11
|
+
const t = useT();
|
|
12
|
+
const sorted = [...channels].sort((a, b) => a.zone - b.zone || a.channel - b.channel);
|
|
13
|
+
return (
|
|
14
|
+
<ScrollRegion label={caption ?? t("scroll.region")}>
|
|
15
|
+
<table className={tableClass}>
|
|
16
|
+
{caption ? <caption className="pb-8 text-start font-semibold">{caption}</caption> : null}
|
|
17
|
+
<thead>
|
|
18
|
+
<tr>
|
|
19
|
+
{["radio.zone", "radio.channel", "radio.assignment", "radio.notes"].map((k) => (
|
|
20
|
+
<th key={k} scope="col" className={thClass}>
|
|
21
|
+
{t(k)}
|
|
22
|
+
</th>
|
|
23
|
+
))}
|
|
24
|
+
</tr>
|
|
25
|
+
</thead>
|
|
26
|
+
<tbody>
|
|
27
|
+
{sorted.map((c) => (
|
|
28
|
+
<tr key={`${c.zone}.${c.channel}`}>
|
|
29
|
+
<td className={cx(tdClass, "tabular-nums")}>{c.zone}</td>
|
|
30
|
+
<td className={tdClass}>
|
|
31
|
+
<span className={codeClass}>{c.channel}</span>
|
|
32
|
+
</td>
|
|
33
|
+
<td className={tdClass}>
|
|
34
|
+
<strong className="font-semibold">{c.assignment}</strong>
|
|
35
|
+
</td>
|
|
36
|
+
<td
|
|
37
|
+
className={cx(
|
|
38
|
+
tdClass,
|
|
39
|
+
"whitespace-normal py-8 min-w-(--ui-skeleton-inline) text-text-secondary",
|
|
40
|
+
)}
|
|
41
|
+
>
|
|
42
|
+
{c.notes}
|
|
43
|
+
</td>
|
|
44
|
+
</tr>
|
|
45
|
+
))}
|
|
46
|
+
</tbody>
|
|
47
|
+
</table>
|
|
48
|
+
</ScrollRegion>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { chipClass } from "../Chips/Chips.tsx";
|
|
5
|
+
import { ScrollRegion } from "../Layout/Layout.tsx";
|
|
6
|
+
import { RESULT, ResultIcon, tableClass, tdClass, thClass } from "./XOS.shared.tsx";
|
|
7
|
+
import { type ReconciliationTableProps, type Result } from "./XOS.types.ts";
|
|
8
|
+
|
|
9
|
+
/** A row's outcome as the props carry it: Met, Gap or Unknown. */
|
|
10
|
+
type RowResult = ReconciliationTableProps["rows"][number]["result"];
|
|
11
|
+
|
|
12
|
+
/** Requirements against venue capability as Met, Gap or Unknown, with counts. */
|
|
13
|
+
export function ReconciliationTable({ label, rows }: ReconciliationTableProps): ReactElement {
|
|
14
|
+
const t = useT();
|
|
15
|
+
const counts: Record<RowResult, number> = { Met: 0, Gap: 0, Unknown: 0 };
|
|
16
|
+
for (const r of rows) counts[r.result] += 1;
|
|
17
|
+
const lower = (r: RowResult) => r.toLowerCase() as Result;
|
|
18
|
+
return (
|
|
19
|
+
<div className="flex flex-col gap-12">
|
|
20
|
+
<div className="flex flex-wrap items-center gap-8">
|
|
21
|
+
{(Object.keys(counts) as RowResult[]).map((k) => (
|
|
22
|
+
<span key={k} className={chipClass}>
|
|
23
|
+
<ResultIcon result={lower(k)} t={t} labeled={false} />
|
|
24
|
+
{t(RESULT[lower(k)].key)}
|
|
25
|
+
<span className="tabular-nums text-text-secondary">{counts[k]}</span>
|
|
26
|
+
</span>
|
|
27
|
+
))}
|
|
28
|
+
</div>
|
|
29
|
+
<ScrollRegion label={label ?? t("scroll.region")}>
|
|
30
|
+
<table className={tableClass}>
|
|
31
|
+
<thead>
|
|
32
|
+
<tr>
|
|
33
|
+
<th scope="col" className={thClass}>
|
|
34
|
+
{t("recon.requirement")}
|
|
35
|
+
</th>
|
|
36
|
+
<th scope="col" className={thClass}>
|
|
37
|
+
{t("recon.capability")}
|
|
38
|
+
</th>
|
|
39
|
+
<th scope="col" className={thClass}>
|
|
40
|
+
{t("recon.result")}
|
|
41
|
+
</th>
|
|
42
|
+
</tr>
|
|
43
|
+
</thead>
|
|
44
|
+
<tbody>
|
|
45
|
+
{rows.map((r, i) => (
|
|
46
|
+
<tr key={`${r.requirement}-${i}`} className="hover:bg-bg-hover">
|
|
47
|
+
<td className={tdClass}>{r.requirement}</td>
|
|
48
|
+
<td className={cx(tdClass, !r.capability && "text-text-secondary")}>
|
|
49
|
+
{r.capability ?? t("recon.notDeclared")}
|
|
50
|
+
</td>
|
|
51
|
+
<td className={tdClass}>
|
|
52
|
+
<span className="inline-flex items-center gap-6">
|
|
53
|
+
<ResultIcon result={lower(r.result)} t={t} labeled={false} />
|
|
54
|
+
{t(RESULT[lower(r.result)].key)}
|
|
55
|
+
</span>
|
|
56
|
+
</td>
|
|
57
|
+
</tr>
|
|
58
|
+
))}
|
|
59
|
+
</tbody>
|
|
60
|
+
</table>
|
|
61
|
+
</ScrollRegion>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|