@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,179 @@
|
|
|
1
|
+
import { useState, type ReactElement, type ReactNode } from "react";
|
|
2
|
+
import { Command } from "cmdk";
|
|
3
|
+
import { Dialog as RDialog } from "radix-ui";
|
|
4
|
+
import type {
|
|
5
|
+
CommandMenuProps as ReferenceCommandMenuProps,
|
|
6
|
+
IconName,
|
|
7
|
+
RecordState,
|
|
8
|
+
} from "../types/reference";
|
|
9
|
+
import { cx } from "../lib/cx.ts";
|
|
10
|
+
import { useT } from "../lib/context.tsx";
|
|
11
|
+
import { useControllable, useHotkey, useReturnFocus } from "../lib/hooks.ts";
|
|
12
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
13
|
+
import { Kbd, Keys } from "../Kbd/Kbd.tsx";
|
|
14
|
+
import { StateIcon } from "../StateIcon/StateIcon.tsx";
|
|
15
|
+
import { panelClass } from "../Overlays/Overlays.tsx";
|
|
16
|
+
|
|
17
|
+
export interface CommandItem {
|
|
18
|
+
label: string;
|
|
19
|
+
code?: string;
|
|
20
|
+
icon?: IconName;
|
|
21
|
+
state?: RecordState;
|
|
22
|
+
shortcut?: string;
|
|
23
|
+
selected?: boolean;
|
|
24
|
+
onSelect?: () => void;
|
|
25
|
+
/** Keeps the menu open after the item runs, for an item that edits the search (an operator hint). */
|
|
26
|
+
keepOpen?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type CommandMenuProps = Omit<ReferenceCommandMenuProps, "groups"> & {
|
|
30
|
+
groups: { label: string; items: CommandItem[] }[];
|
|
31
|
+
/** Called as the search text changes, for server-side results. With `query`, the text is controlled. */
|
|
32
|
+
onQueryChange?: (query: string) => void;
|
|
33
|
+
/** Shown between the search field and the results, for example the filters a query recognized. */
|
|
34
|
+
header?: ReactNode;
|
|
35
|
+
/** Dialog mode: the menu opens over the page. Omit `open` to render the palette inline. */
|
|
36
|
+
open?: boolean;
|
|
37
|
+
onOpenChange?: (open: boolean) => void;
|
|
38
|
+
/** In dialog mode, Cmd or Ctrl+K toggles the menu (on by default). */
|
|
39
|
+
hotkey?: boolean;
|
|
40
|
+
/** Turn off client filtering when the results come from a server search. */
|
|
41
|
+
filter?: boolean;
|
|
42
|
+
/** Names the menu for assistive technology; the command menu's own name by default. */
|
|
43
|
+
label?: string;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
function itemValue(group: string, item: CommandItem): string {
|
|
47
|
+
return `${group} ${item.label} ${item.code ?? ""}`.trim();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function Palette({
|
|
51
|
+
query,
|
|
52
|
+
placeholder: hint,
|
|
53
|
+
groups,
|
|
54
|
+
onQueryChange,
|
|
55
|
+
filter = true,
|
|
56
|
+
header,
|
|
57
|
+
label,
|
|
58
|
+
onClose,
|
|
59
|
+
}: CommandMenuProps & { onClose?: () => void }) {
|
|
60
|
+
const t = useT();
|
|
61
|
+
const [search, setSearch] = useControllable<string>(query, "", onQueryChange);
|
|
62
|
+
const selected = groups.flatMap((g) =>
|
|
63
|
+
g.items.filter((i) => i.selected).map((i) => itemValue(g.label, i)),
|
|
64
|
+
)[0];
|
|
65
|
+
// With server results (filter off) nothing re-ranks the list, so a new search, or new results for it,
|
|
66
|
+
// move the highlight to the first item, and Enter runs what the person sees first.
|
|
67
|
+
const lead =
|
|
68
|
+
selected ?? groups.flatMap((g) => g.items.map((i) => itemValue(g.label, i)))[0] ?? "";
|
|
69
|
+
const [highlight, setHighlight] = useState(lead);
|
|
70
|
+
const [highlightFor, setHighlightFor] = useState(`${search}\u0000${lead}`);
|
|
71
|
+
if (!filter && highlightFor !== `${search}\u0000${lead}`) {
|
|
72
|
+
setHighlightFor(`${search}\u0000${lead}`);
|
|
73
|
+
setHighlight(lead);
|
|
74
|
+
}
|
|
75
|
+
return (
|
|
76
|
+
<Command
|
|
77
|
+
label={label ?? t("command.label")}
|
|
78
|
+
shouldFilter={filter}
|
|
79
|
+
loop
|
|
80
|
+
{...(filter
|
|
81
|
+
? selected
|
|
82
|
+
? { defaultValue: selected }
|
|
83
|
+
: {}
|
|
84
|
+
: { value: highlight, onValueChange: setHighlight })}
|
|
85
|
+
className={cx(panelClass, "xos-anim-dialog w-(--ui-command) overflow-hidden")}
|
|
86
|
+
>
|
|
87
|
+
<div className="flex items-center gap-8 h-(--ui-cmd-input) px-16 border-b border-border-subtle text-text-14">
|
|
88
|
+
<Icon name="search" color="var(--color-text-secondary)" />
|
|
89
|
+
<Command.Input
|
|
90
|
+
value={search}
|
|
91
|
+
onValueChange={setSearch}
|
|
92
|
+
placeholder={hint}
|
|
93
|
+
className="flex-1 min-w-0 bg-transparent border-0 outline-none text-text-primary placeholder:text-text-tertiary"
|
|
94
|
+
/>
|
|
95
|
+
<Kbd>{t("key.esc")}</Kbd>
|
|
96
|
+
</div>
|
|
97
|
+
{header}
|
|
98
|
+
<Command.Empty className="px-16 py-12 text-text-secondary">{t("list.noMatch")}</Command.Empty>
|
|
99
|
+
<Command.List
|
|
100
|
+
label={t("command.results")}
|
|
101
|
+
className="max-h-(--ui-listbox-max) overflow-y-auto p-8 pt-4"
|
|
102
|
+
>
|
|
103
|
+
{groups.map((g, groupIndex) => (
|
|
104
|
+
<Command.Group
|
|
105
|
+
// Two groups may share a label (a caller's own results and pages); the index keeps them apart.
|
|
106
|
+
key={`${groupIndex}:${g.label}`}
|
|
107
|
+
heading={g.label}
|
|
108
|
+
className="[&_[cmdk-group-heading]]:mx-8 [&_[cmdk-group-heading]]:mt-8 [&_[cmdk-group-heading]]:mb-4 [&_[cmdk-group-heading]]:text-text-11 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-text-secondary"
|
|
109
|
+
>
|
|
110
|
+
{g.items.map((item) => (
|
|
111
|
+
<Command.Item
|
|
112
|
+
key={itemValue(g.label, item)}
|
|
113
|
+
value={itemValue(g.label, item)}
|
|
114
|
+
onSelect={() => {
|
|
115
|
+
item.onSelect?.();
|
|
116
|
+
if (!item.keepOpen) onClose?.();
|
|
117
|
+
}}
|
|
118
|
+
className={cx(
|
|
119
|
+
"flex items-center gap-8 h-row-default px-8 rounded-control text-text-primary cursor-pointer",
|
|
120
|
+
"data-[selected=true]:bg-bg-hover pointer-coarse:min-h-target-coarse [&_svg]:text-text-secondary",
|
|
121
|
+
)}
|
|
122
|
+
>
|
|
123
|
+
{item.state ? (
|
|
124
|
+
<StateIcon state={item.state} />
|
|
125
|
+
) : (
|
|
126
|
+
<Icon name={item.icon ?? "chevron-right"} />
|
|
127
|
+
)}
|
|
128
|
+
<span>{item.label}</span>
|
|
129
|
+
{item.code ? (
|
|
130
|
+
<span className="font-mono text-text-12 text-text-secondary">{item.code}</span>
|
|
131
|
+
) : null}
|
|
132
|
+
{item.shortcut ? (
|
|
133
|
+
<span className="ms-auto">
|
|
134
|
+
<Keys keys={item.shortcut} />
|
|
135
|
+
</span>
|
|
136
|
+
) : null}
|
|
137
|
+
</Command.Item>
|
|
138
|
+
))}
|
|
139
|
+
</Command.Group>
|
|
140
|
+
))}
|
|
141
|
+
</Command.List>
|
|
142
|
+
</Command>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Finds records, people, pages, settings and actions. Inline by default; with `open` it is a dialog
|
|
148
|
+
* that Cmd or Ctrl+K toggles. Arrow keys move, Enter runs, Esc closes.
|
|
149
|
+
*/
|
|
150
|
+
export function CommandMenu({
|
|
151
|
+
open,
|
|
152
|
+
onOpenChange,
|
|
153
|
+
hotkey = true,
|
|
154
|
+
...props
|
|
155
|
+
}: CommandMenuProps): ReactElement {
|
|
156
|
+
const t = useT();
|
|
157
|
+
const dialog = open !== undefined;
|
|
158
|
+
const [isOpen, setOpen] = useControllable(open, false, onOpenChange);
|
|
159
|
+
useHotkey("k", () => setOpen(!isOpen), { mod: true, enabled: dialog && hotkey });
|
|
160
|
+
const returnFocus = useReturnFocus(dialog && isOpen);
|
|
161
|
+
if (!dialog) return <Palette {...props} />;
|
|
162
|
+
return (
|
|
163
|
+
<RDialog.Root open={isOpen} onOpenChange={setOpen}>
|
|
164
|
+
<RDialog.Portal>
|
|
165
|
+
<RDialog.Overlay className="xos-anim-fade fixed inset-0 z-command bg-scrim opacity-scrim-dark in-data-[theme=light]:opacity-scrim-light in-data-[theme=sunlight]:opacity-scrim-light" />
|
|
166
|
+
<div className="pointer-events-none fixed inset-0 z-command flex justify-center px-16 pt-64">
|
|
167
|
+
<RDialog.Content
|
|
168
|
+
aria-describedby={undefined}
|
|
169
|
+
onCloseAutoFocus={returnFocus}
|
|
170
|
+
className="pointer-events-auto h-fit max-w-full"
|
|
171
|
+
>
|
|
172
|
+
<RDialog.Title className="sr-only">{props.label ?? t("command.label")}</RDialog.Title>
|
|
173
|
+
<Palette {...props} onClose={() => setOpen(false)} />
|
|
174
|
+
</RDialog.Content>
|
|
175
|
+
</div>
|
|
176
|
+
</RDialog.Portal>
|
|
177
|
+
</RDialog.Root>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# ComparisonTable
|
|
2
|
+
|
|
3
|
+
ComparisonTable compares one product with others, feature by feature, in a real table.
|
|
4
|
+
|
|
5
|
+
Every cell carries a word beside its icon: Yes, Partial, No or Unpublished. Unpublished means the other product's public pages do not state the feature; it never means the feature is absent. The caption states when the cells were last verified, and a cell may link to its source. The own-product column is marked with `highlight`.
|
|
6
|
+
|
|
7
|
+
From bp-md the table scrolls inside a labeled region with sticky row headers. Below bp-md it stacks into one card per feature with each product on its own labeled line, and explicit table roles keep it a table for screen readers. Sorting is off by design.
|
|
8
|
+
|
|
9
|
+
The consumer provides only rows where its own product is shipped and each other cell has a dated source. Other products' names appear in plain text, never as logos. The preview uses neutral product names.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { useEffect, 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 { Button } from "../Button/Button.tsx";
|
|
6
|
+
import { Textarea } from "../Forms/Forms.tsx";
|
|
7
|
+
import { Phone } from "./Compass.shared.tsx";
|
|
8
|
+
import { type ChecklistRunnerProps } from "./Compass.types.ts";
|
|
9
|
+
|
|
10
|
+
function BigChoice({
|
|
11
|
+
pass,
|
|
12
|
+
on,
|
|
13
|
+
label,
|
|
14
|
+
onClick,
|
|
15
|
+
}: {
|
|
16
|
+
pass: boolean;
|
|
17
|
+
on: boolean;
|
|
18
|
+
label: string;
|
|
19
|
+
onClick: () => void;
|
|
20
|
+
}): ReactElement {
|
|
21
|
+
return (
|
|
22
|
+
<button
|
|
23
|
+
type="button"
|
|
24
|
+
aria-pressed={on}
|
|
25
|
+
onClick={onClick}
|
|
26
|
+
className={cx(
|
|
27
|
+
"flex flex-col items-center justify-center gap-4 h-(--ui-compass-thumb) border-0 rounded-dialog",
|
|
28
|
+
"text-heading-20 font-semibold cursor-pointer text-text-primary forced-colors:border forced-colors:border-[CanvasText]",
|
|
29
|
+
"focus-visible:outline-stroke-focus focus-visible:outline-offset-2 focus-visible:outline-focus-ring",
|
|
30
|
+
on
|
|
31
|
+
? cx(
|
|
32
|
+
"bg-bg-hover ring-(length:--stroke-width-focus) ring-inset",
|
|
33
|
+
pass ? "ring-success" : "ring-danger",
|
|
34
|
+
)
|
|
35
|
+
: "bg-bg-surface ring-(length:--ui-hairline-half) ring-inset ring-border-control",
|
|
36
|
+
)}
|
|
37
|
+
>
|
|
38
|
+
<Icon
|
|
39
|
+
name={pass ? "Check" : "X"}
|
|
40
|
+
size={28}
|
|
41
|
+
className={pass ? "text-success" : "text-danger"}
|
|
42
|
+
/>
|
|
43
|
+
{label}
|
|
44
|
+
</button>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Inspection runner: one item per card, large Pass and Fail; a Fail asks for a photo and a note. */
|
|
49
|
+
export function ChecklistRunner({
|
|
50
|
+
frame,
|
|
51
|
+
title,
|
|
52
|
+
index,
|
|
53
|
+
items,
|
|
54
|
+
onResult,
|
|
55
|
+
onAddPhoto,
|
|
56
|
+
onNoteChange,
|
|
57
|
+
}: ChecklistRunnerProps): ReactElement {
|
|
58
|
+
const t = useT();
|
|
59
|
+
const [results, setResults] = useState(() => items.map((i) => i.result));
|
|
60
|
+
useEffect(() => setResults(items.map((i) => i.result)), [items]);
|
|
61
|
+
const item = items[index];
|
|
62
|
+
const done = results.filter(Boolean).length;
|
|
63
|
+
const percent = items.length ? Math.round((done / items.length) * 100) : 0;
|
|
64
|
+
const result = results[index] ?? null;
|
|
65
|
+
const choose = (next: "pass" | "fail") => {
|
|
66
|
+
if (!item) return;
|
|
67
|
+
setResults((prev) => prev.map((r, i) => (i === index ? next : r)));
|
|
68
|
+
onResult?.(item.code, next);
|
|
69
|
+
};
|
|
70
|
+
return (
|
|
71
|
+
<Phone frame={frame}>
|
|
72
|
+
<div className="flex flex-col gap-12 p-16">
|
|
73
|
+
<div className="flex justify-between text-text-12 text-text-secondary">
|
|
74
|
+
<strong className="text-text-primary">{title}</strong>
|
|
75
|
+
<span className="tabular-nums">
|
|
76
|
+
{t("count.of", { n: index + 1, total: items.length })}
|
|
77
|
+
</span>
|
|
78
|
+
</div>
|
|
79
|
+
<div
|
|
80
|
+
role="progressbar"
|
|
81
|
+
aria-label={title}
|
|
82
|
+
aria-valuemin={0}
|
|
83
|
+
aria-valuemax={100}
|
|
84
|
+
aria-valuenow={percent}
|
|
85
|
+
className="h-4 rounded-pill bg-bg-hover overflow-hidden"
|
|
86
|
+
>
|
|
87
|
+
<div
|
|
88
|
+
className="h-full rounded-pill bg-accent forced-colors:bg-[CanvasText]"
|
|
89
|
+
style={{ inlineSize: `${percent}%` }}
|
|
90
|
+
/>
|
|
91
|
+
</div>
|
|
92
|
+
{item ? (
|
|
93
|
+
<article className="flex flex-col gap-8 p-20 min-h-(--ui-compass-card-min) bg-bg-raised border border-border-subtle rounded-dialog">
|
|
94
|
+
<span className="font-mono text-mono-12 text-text-secondary">{item.code}</span>
|
|
95
|
+
<strong className="text-heading-20 font-semibold">{item.label}</strong>
|
|
96
|
+
{item.help ? <span className="text-text-secondary">{item.help}</span> : null}
|
|
97
|
+
{result === "fail" ? (
|
|
98
|
+
<div className="flex flex-col gap-8">
|
|
99
|
+
<Button icon="Camera" size="lg" onClick={() => onAddPhoto?.(item.code)}>
|
|
100
|
+
{t("inspection.addPhoto")}
|
|
101
|
+
</Button>
|
|
102
|
+
<Textarea
|
|
103
|
+
label={t("inspection.whatFailed")}
|
|
104
|
+
width="100%"
|
|
105
|
+
onChange={(e) => onNoteChange?.(item.code, e.target.value)}
|
|
106
|
+
/>
|
|
107
|
+
</div>
|
|
108
|
+
) : null}
|
|
109
|
+
</article>
|
|
110
|
+
) : null}
|
|
111
|
+
<div className="grid grid-cols-2 gap-12">
|
|
112
|
+
<BigChoice
|
|
113
|
+
pass={false}
|
|
114
|
+
on={result === "fail"}
|
|
115
|
+
label={t("inspection.fail")}
|
|
116
|
+
onClick={() => choose("fail")}
|
|
117
|
+
/>
|
|
118
|
+
<BigChoice
|
|
119
|
+
pass
|
|
120
|
+
on={result === "pass"}
|
|
121
|
+
label={t("inspection.pass")}
|
|
122
|
+
onClick={() => choose("pass")}
|
|
123
|
+
/>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</Phone>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
4
|
+
import { compassText } from "./Compass.shared.tsx";
|
|
5
|
+
import { type ClockButtonProps } from "./Compass.types.ts";
|
|
6
|
+
|
|
7
|
+
const CLOCK_STATE: Record<NonNullable<ClockButtonProps["state"]>, string> = {
|
|
8
|
+
out: "bg-accent text-accent-text-on",
|
|
9
|
+
on: "bg-bg-raised text-text-primary ring-(length:--stroke-width-focus) ring-inset ring-success",
|
|
10
|
+
break:
|
|
11
|
+
"bg-bg-raised text-text-primary ring-(length:--stroke-width-focus) ring-inset ring-warning",
|
|
12
|
+
blocked:
|
|
13
|
+
"bg-bg-surface text-text-secondary ring-(length:--stroke-width-hairline) ring-inset ring-border-strong cursor-not-allowed",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/** The Today screen's one primary control; it changes with the person's state. */
|
|
17
|
+
export function ClockButton({
|
|
18
|
+
state = "out",
|
|
19
|
+
label,
|
|
20
|
+
detail,
|
|
21
|
+
timer,
|
|
22
|
+
geofence,
|
|
23
|
+
geofenceOk,
|
|
24
|
+
onClick,
|
|
25
|
+
}: ClockButtonProps): ReactElement {
|
|
26
|
+
const blocked = state === "blocked";
|
|
27
|
+
return (
|
|
28
|
+
<div
|
|
29
|
+
className={cx(
|
|
30
|
+
"xos-compass flex flex-col items-stretch gap-8 w-(--ui-compass-card) max-w-full",
|
|
31
|
+
compassText,
|
|
32
|
+
)}
|
|
33
|
+
>
|
|
34
|
+
{geofence ? (
|
|
35
|
+
<span className="inline-flex items-center gap-6 text-text-14 text-text-secondary">
|
|
36
|
+
<Icon name="MapPin" size={16} className={geofenceOk ? "text-success" : "text-warning"} />
|
|
37
|
+
{geofence}
|
|
38
|
+
</span>
|
|
39
|
+
) : null}
|
|
40
|
+
<button
|
|
41
|
+
type="button"
|
|
42
|
+
aria-disabled={blocked ? true : undefined}
|
|
43
|
+
onClick={blocked ? undefined : onClick}
|
|
44
|
+
className={cx(
|
|
45
|
+
"flex flex-col items-center justify-center gap-4 w-full min-h-(--ui-compass-thumb) p-16 border-0 rounded-dialog",
|
|
46
|
+
"text-heading-20 font-semibold cursor-pointer",
|
|
47
|
+
"focus-visible:outline-stroke-focus focus-visible:outline-offset-2 focus-visible:outline-focus-ring",
|
|
48
|
+
CLOCK_STATE[state],
|
|
49
|
+
)}
|
|
50
|
+
>
|
|
51
|
+
{timer ? <span className="text-heading-32 tabular-nums">{timer}</span> : null}
|
|
52
|
+
<span>{label}</span>
|
|
53
|
+
{detail ? <small className="text-text-14 font-regular">{detail}</small> : null}
|
|
54
|
+
</button>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type ReactElement, type ReactNode } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
|
|
4
|
+
export const compassText = "font-sans text-text-16 text-text-primary";
|
|
5
|
+
|
|
6
|
+
export const blockClass = "w-full justify-center";
|
|
7
|
+
|
|
8
|
+
export function Phone({
|
|
9
|
+
frame,
|
|
10
|
+
tall,
|
|
11
|
+
children,
|
|
12
|
+
}: {
|
|
13
|
+
frame?: boolean | undefined;
|
|
14
|
+
tall?: boolean;
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
}): ReactElement {
|
|
17
|
+
return (
|
|
18
|
+
<div
|
|
19
|
+
className={cx(
|
|
20
|
+
"xos-compass",
|
|
21
|
+
compassText,
|
|
22
|
+
frame &&
|
|
23
|
+
"flex flex-col justify-end w-(--ui-tabbar) max-w-full box-border overflow-hidden bg-bg-canvas border border-border-subtle rounded-device",
|
|
24
|
+
frame && tall && "min-h-(--ui-photo-view)",
|
|
25
|
+
)}
|
|
26
|
+
>
|
|
27
|
+
{children}
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function SheetFrame({
|
|
33
|
+
title,
|
|
34
|
+
step,
|
|
35
|
+
children,
|
|
36
|
+
}: {
|
|
37
|
+
title: string;
|
|
38
|
+
step?: string;
|
|
39
|
+
children: ReactNode;
|
|
40
|
+
}): ReactElement {
|
|
41
|
+
return (
|
|
42
|
+
<div
|
|
43
|
+
role="dialog"
|
|
44
|
+
aria-label={title}
|
|
45
|
+
className="flex flex-col gap-16 px-16 pt-8 pb-24 bg-bg-raised rounded-t-dialog shadow-dialog"
|
|
46
|
+
>
|
|
47
|
+
<span
|
|
48
|
+
aria-hidden="true"
|
|
49
|
+
className="self-center w-(--ui-grabber-inline) h-(--ui-grabber-block) rounded-pill bg-border-strong"
|
|
50
|
+
/>
|
|
51
|
+
<header className="flex items-baseline justify-between">
|
|
52
|
+
<strong className="text-heading-20 font-semibold">{title}</strong>
|
|
53
|
+
{step ? <span className="text-text-secondary tabular-nums">{step}</span> : null}
|
|
54
|
+
</header>
|
|
55
|
+
{children}
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export {
|
|
2
|
+
type ClockButtonProps,
|
|
3
|
+
type ScanSheetProps,
|
|
4
|
+
type OfflineBannerProps,
|
|
5
|
+
type QuickIncidentSheetProps,
|
|
6
|
+
type ChecklistRunnerProps,
|
|
7
|
+
type ShiftCardProps,
|
|
8
|
+
type DaySheetViewProps,
|
|
9
|
+
type SignaturePadProps,
|
|
10
|
+
type PhotoCaptureProps,
|
|
11
|
+
type LiveActivityProps,
|
|
12
|
+
type ForceUpdateScreenProps,
|
|
13
|
+
type SyncConflictSheetProps,
|
|
14
|
+
} from "./Compass.types.ts";
|
|
15
|
+
export { ClockButton } from "./ClockButton.tsx";
|
|
16
|
+
export { ScanSheet } from "./ScanSheet.tsx";
|
|
17
|
+
export { OfflineBanner } from "./OfflineBanner.tsx";
|
|
18
|
+
export { QuickIncidentSheet } from "./QuickIncidentSheet.tsx";
|
|
19
|
+
export { ChecklistRunner } from "./ChecklistRunner.tsx";
|
|
20
|
+
export { ShiftCard } from "./ShiftCard.tsx";
|
|
21
|
+
export { DaySheetView } from "./DaySheetView.tsx";
|
|
22
|
+
export { SignaturePad } from "./SignaturePad.tsx";
|
|
23
|
+
export { PhotoCapture } from "./PhotoCapture.tsx";
|
|
24
|
+
export { LiveActivity } from "./LiveActivity.tsx";
|
|
25
|
+
export { ForceUpdateScreen } from "./ForceUpdateScreen.tsx";
|
|
26
|
+
export { SyncConflictSheet } from "./SyncConflictSheet.tsx";
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type {
|
|
3
|
+
ChecklistRunnerProps as ReferenceChecklistRunnerProps,
|
|
4
|
+
ClockButtonProps as ReferenceClockButtonProps,
|
|
5
|
+
DaySheetViewProps as ReferenceDaySheetViewProps,
|
|
6
|
+
ForceUpdateScreenProps as ReferenceForceUpdateScreenProps,
|
|
7
|
+
LiveActivityProps as ReferenceLiveActivityProps,
|
|
8
|
+
OfflineBannerProps as ReferenceOfflineBannerProps,
|
|
9
|
+
PhotoCaptureProps as ReferencePhotoCaptureProps,
|
|
10
|
+
QuickIncidentSheetProps as ReferenceQuickIncidentSheetProps,
|
|
11
|
+
ScanSheetProps as ReferenceScanSheetProps,
|
|
12
|
+
ShiftCardProps as ReferenceShiftCardProps,
|
|
13
|
+
SignaturePadProps as ReferenceSignaturePadProps,
|
|
14
|
+
SyncConflictSheetProps as ReferenceSyncConflictSheetProps,
|
|
15
|
+
} from "../types/reference";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Compass components on the web (RRR-75): the same surfaces Compass draws natively in
|
|
19
|
+
* @xos/ui-native, for Atlas previews, the Gateway crew view and Storybook. Each one marks its root
|
|
20
|
+
* `xos-compass`, which raises every target to touch-min (48 pt). Props are the reference contracts
|
|
21
|
+
* plus the callbacks a product screen needs; `frame` draws the documentation phone frame and is for
|
|
22
|
+
* previews only.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
export type ClockButtonProps = ReferenceClockButtonProps;
|
|
26
|
+
|
|
27
|
+
export type ScanSheetProps = ReferenceScanSheetProps & {
|
|
28
|
+
onModeChange?: (mode: ReferenceScanSheetProps["mode"]) => void;
|
|
29
|
+
onDone?: () => void;
|
|
30
|
+
onNfc?: () => void;
|
|
31
|
+
onTorch?: () => void;
|
|
32
|
+
/** The live camera feed, drawn inside the viewfinder under the reticle. */
|
|
33
|
+
camera?: ReactNode;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type OfflineBannerProps = ReferenceOfflineBannerProps;
|
|
37
|
+
|
|
38
|
+
export type QuickIncidentSheetProps = ReferenceQuickIncidentSheetProps & {
|
|
39
|
+
onSelect?: (label: string) => void;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export type ChecklistRunnerProps = ReferenceChecklistRunnerProps & {
|
|
43
|
+
onResult?: (code: string, result: "pass" | "fail") => void;
|
|
44
|
+
onAddPhoto?: (code: string) => void;
|
|
45
|
+
onNoteChange?: (code: string, note: string) => void;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type ShiftCardProps = ReferenceShiftCardProps;
|
|
49
|
+
|
|
50
|
+
export type DaySheetViewProps = ReferenceDaySheetViewProps & {
|
|
51
|
+
onCall?: (name: string) => void;
|
|
52
|
+
onMessage?: (name: string) => void;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export type SignaturePadProps = ReferenceSignaturePadProps & {
|
|
56
|
+
/** A PNG data URL of the signature, or null after Clear. */
|
|
57
|
+
onChange?: (signature: string | null) => void;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export type PhotoCaptureProps = ReferencePhotoCaptureProps & {
|
|
61
|
+
onCapture?: () => void;
|
|
62
|
+
onAnnotate?: () => void;
|
|
63
|
+
onDone?: () => void;
|
|
64
|
+
camera?: ReactNode;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export type LiveActivityProps = ReferenceLiveActivityProps & {
|
|
68
|
+
/** Break, or End Break while on break. */
|
|
69
|
+
onToggleBreak?: () => void;
|
|
70
|
+
onClockOut?: () => void;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export type ForceUpdateScreenProps = ReferenceForceUpdateScreenProps & {
|
|
74
|
+
onUpdate?: () => void;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export type SyncConflictSheetProps = ReferenceSyncConflictSheetProps & {
|
|
78
|
+
onKeep?: (choice: "mine" | "theirs") => void;
|
|
79
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { IconButton } from "../Button/Button.tsx";
|
|
5
|
+
import { Tag } from "../Chips/Chips.tsx";
|
|
6
|
+
import { Avatar } from "../Avatar/Avatar.tsx";
|
|
7
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
8
|
+
import { TL_CATEGORY } from "../Charts/categories.ts";
|
|
9
|
+
import { Phone } from "./Compass.shared.tsx";
|
|
10
|
+
import { type DaySheetViewProps } from "./Compass.types.ts";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The day sheet: schedule with the current entry marked, and contacts with call and message. `dayTypes` names what
|
|
14
|
+
* the day is (B4), as text with an icon and a categorical swatch.
|
|
15
|
+
*/
|
|
16
|
+
export function DaySheetView({
|
|
17
|
+
frame,
|
|
18
|
+
date,
|
|
19
|
+
title,
|
|
20
|
+
venue,
|
|
21
|
+
entries,
|
|
22
|
+
contacts,
|
|
23
|
+
dayTypes = [],
|
|
24
|
+
onCall,
|
|
25
|
+
onMessage,
|
|
26
|
+
}: DaySheetViewProps): ReactElement {
|
|
27
|
+
const t = useT();
|
|
28
|
+
return (
|
|
29
|
+
<Phone frame={frame}>
|
|
30
|
+
<div className="flex flex-col gap-16 p-16">
|
|
31
|
+
<header className="flex flex-col gap-2">
|
|
32
|
+
<span className="text-text-secondary">{date}</span>
|
|
33
|
+
<strong className="text-heading-20 font-semibold">{title}</strong>
|
|
34
|
+
<span className="text-text-secondary">{venue}</span>
|
|
35
|
+
{dayTypes.length > 0 ? (
|
|
36
|
+
<ul
|
|
37
|
+
className="m-0 flex list-none flex-wrap gap-4 p-0"
|
|
38
|
+
aria-label={t("daysheet.dayTypes")}
|
|
39
|
+
>
|
|
40
|
+
{dayTypes.map((d) => (
|
|
41
|
+
<li
|
|
42
|
+
key={d.label}
|
|
43
|
+
className="inline-flex items-center gap-4 rounded-chip bg-bg-surface px-6 text-text-12"
|
|
44
|
+
>
|
|
45
|
+
<span
|
|
46
|
+
aria-hidden="true"
|
|
47
|
+
className={cx(
|
|
48
|
+
"inline-block size-(--space-8) rounded-mark",
|
|
49
|
+
TL_CATEGORY[d.category],
|
|
50
|
+
)}
|
|
51
|
+
/>
|
|
52
|
+
{d.icon ? <Icon name={d.icon} size={12} /> : null}
|
|
53
|
+
{d.label}
|
|
54
|
+
</li>
|
|
55
|
+
))}
|
|
56
|
+
</ul>
|
|
57
|
+
) : null}
|
|
58
|
+
</header>
|
|
59
|
+
<ol className="m-0 p-0 list-none">
|
|
60
|
+
{entries.map((e, i) => (
|
|
61
|
+
<li
|
|
62
|
+
key={i}
|
|
63
|
+
aria-current={e.now ? "time" : undefined}
|
|
64
|
+
className={cx(
|
|
65
|
+
"grid grid-cols-[var(--ui-daysheet-time)_1fr_auto] items-center min-h-touch-min border-b border-border-subtle",
|
|
66
|
+
e.now && "font-semibold",
|
|
67
|
+
)}
|
|
68
|
+
>
|
|
69
|
+
<span className="text-text-secondary tabular-nums">{e.time}</span>
|
|
70
|
+
<span>{e.label}</span>
|
|
71
|
+
{e.now ? <Tag tone="accent">{t("daysheet.now")}</Tag> : null}
|
|
72
|
+
</li>
|
|
73
|
+
))}
|
|
74
|
+
</ol>
|
|
75
|
+
<section className="flex flex-col">
|
|
76
|
+
<h4 className="m-0 text-text-12 font-medium text-text-secondary">
|
|
77
|
+
{t("daysheet.contacts")}
|
|
78
|
+
</h4>
|
|
79
|
+
{contacts.map((c) => (
|
|
80
|
+
<div key={c.name} className="flex items-center gap-8 py-6">
|
|
81
|
+
<Avatar name={c.name} />
|
|
82
|
+
<div className="flex flex-col flex-1">
|
|
83
|
+
<strong>{c.name}</strong>
|
|
84
|
+
<span className="text-text-secondary">{c.role}</span>
|
|
85
|
+
</div>
|
|
86
|
+
<IconButton
|
|
87
|
+
icon="Phone"
|
|
88
|
+
variant="secondary"
|
|
89
|
+
label={t("contact.call", { name: c.name })}
|
|
90
|
+
onClick={() => onCall?.(c.name)}
|
|
91
|
+
/>
|
|
92
|
+
<IconButton
|
|
93
|
+
icon="MessageSquare"
|
|
94
|
+
variant="secondary"
|
|
95
|
+
label={t("contact.message", { name: c.name })}
|
|
96
|
+
onClick={() => onMessage?.(c.name)}
|
|
97
|
+
/>
|
|
98
|
+
</div>
|
|
99
|
+
))}
|
|
100
|
+
</section>
|
|
101
|
+
</div>
|
|
102
|
+
</Phone>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
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 { Phone, blockClass } from "./Compass.shared.tsx";
|
|
6
|
+
import { type ForceUpdateScreenProps } from "./Compass.types.ts";
|
|
7
|
+
|
|
8
|
+
/** Blocks the app below the forced minimum version (Section 5.1) until the person updates. */
|
|
9
|
+
export function ForceUpdateScreen({
|
|
10
|
+
frame,
|
|
11
|
+
message,
|
|
12
|
+
version,
|
|
13
|
+
onUpdate,
|
|
14
|
+
}: ForceUpdateScreenProps): ReactElement {
|
|
15
|
+
const t = useT();
|
|
16
|
+
return (
|
|
17
|
+
<Phone frame={frame} tall>
|
|
18
|
+
<div className="flex flex-1 flex-col items-center justify-center gap-12 px-24 py-32 text-center">
|
|
19
|
+
<Icon name="Smartphone" size={28} className="text-text-secondary" />
|
|
20
|
+
<strong className="text-heading-20 font-semibold">{t("update.title")}</strong>
|
|
21
|
+
<p className="m-0 text-text-secondary">{message}</p>
|
|
22
|
+
<span className="font-mono text-mono-12 text-text-secondary">{version}</span>
|
|
23
|
+
<Button variant="primary" size="lg" className={blockClass} onClick={onUpdate}>
|
|
24
|
+
{t("update.action")}
|
|
25
|
+
</Button>
|
|
26
|
+
</div>
|
|
27
|
+
</Phone>
|
|
28
|
+
);
|
|
29
|
+
}
|