@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,60 @@
|
|
|
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 { blockClass, compassText } from "./Compass.shared.tsx";
|
|
7
|
+
import { type LiveActivityProps } from "./Compass.types.ts";
|
|
8
|
+
|
|
9
|
+
/** The lock screen Live Activity and the home screen widget layouts. */
|
|
10
|
+
export function LiveActivity({
|
|
11
|
+
label,
|
|
12
|
+
elapsed,
|
|
13
|
+
place,
|
|
14
|
+
nextShift,
|
|
15
|
+
nextTime,
|
|
16
|
+
onBreak = false,
|
|
17
|
+
onToggleBreak,
|
|
18
|
+
onClockOut,
|
|
19
|
+
}: LiveActivityProps): ReactElement {
|
|
20
|
+
const t = useT();
|
|
21
|
+
return (
|
|
22
|
+
<div className={cx("xos-compass flex flex-col gap-12", compassText)}>
|
|
23
|
+
<div
|
|
24
|
+
role="group"
|
|
25
|
+
aria-label={t("live.label")}
|
|
26
|
+
className="flex flex-col gap-8 w-(--ui-compass-card) max-w-full box-border p-16 rounded-widget bg-bg-raised shadow-menu"
|
|
27
|
+
>
|
|
28
|
+
<div className="flex items-center justify-between">
|
|
29
|
+
<span className="flex items-center gap-6">
|
|
30
|
+
<Icon
|
|
31
|
+
name={onBreak ? "Coffee" : "Clock"}
|
|
32
|
+
size={16}
|
|
33
|
+
className={onBreak ? "text-warning" : "text-success"}
|
|
34
|
+
/>
|
|
35
|
+
<strong>{label}</strong>
|
|
36
|
+
</span>
|
|
37
|
+
<span className="text-heading-24 font-semibold tabular-nums">{elapsed}</span>
|
|
38
|
+
</div>
|
|
39
|
+
<span className="text-text-secondary">{place}</span>
|
|
40
|
+
<div className="flex gap-8">
|
|
41
|
+
<Button size="lg" className={blockClass} onClick={onToggleBreak}>
|
|
42
|
+
{t(onBreak ? "clock.endBreak" : "clock.break")}
|
|
43
|
+
</Button>
|
|
44
|
+
<Button size="lg" variant="primary" className={blockClass} onClick={onClockOut}>
|
|
45
|
+
{t("clock.out")}
|
|
46
|
+
</Button>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
<div
|
|
50
|
+
role="group"
|
|
51
|
+
aria-label={t("widget.label")}
|
|
52
|
+
className="flex flex-col justify-end gap-2 size-(--ui-widget) box-border p-16 rounded-widget bg-bg-raised shadow-menu"
|
|
53
|
+
>
|
|
54
|
+
<span className="text-text-secondary">{t("widget.nextShift")}</span>
|
|
55
|
+
<strong>{nextShift}</strong>
|
|
56
|
+
<span className="tabular-nums">{nextTime}</span>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
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 { type OfflineBannerProps } from "./Compass.types.ts";
|
|
7
|
+
|
|
8
|
+
/** Offline state with the count of queued writes (Section 13). */
|
|
9
|
+
export function OfflineBanner({ message, queued, onView }: OfflineBannerProps): ReactElement {
|
|
10
|
+
const t = useT();
|
|
11
|
+
return (
|
|
12
|
+
<div
|
|
13
|
+
role="status"
|
|
14
|
+
className={cx(
|
|
15
|
+
"xos-compass flex items-center gap-8 w-(--ui-tabbar) max-w-full box-border px-12 py-8",
|
|
16
|
+
"bg-bg-surface border border-warning rounded-card text-text-14 text-text-primary",
|
|
17
|
+
)}
|
|
18
|
+
>
|
|
19
|
+
<Icon name="WifiOff" size={16} className="text-warning" />
|
|
20
|
+
<span className="flex-1">{message}</span>
|
|
21
|
+
<span className="inline-flex items-center h-(--ui-chip) px-6 rounded-chip bg-bg-hover text-text-12 font-medium tabular-nums">
|
|
22
|
+
{t("offline.queued", { n: queued })}
|
|
23
|
+
</span>
|
|
24
|
+
{onView ? (
|
|
25
|
+
<Button size="sm" variant="ghost" onClick={onView}>
|
|
26
|
+
{t("action.view")}
|
|
27
|
+
</Button>
|
|
28
|
+
) : null}
|
|
29
|
+
</div>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
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, IconButton } from "../Button/Button.tsx";
|
|
6
|
+
import { Phone } from "./Compass.shared.tsx";
|
|
7
|
+
import { type PhotoCaptureProps } from "./Compass.types.ts";
|
|
8
|
+
|
|
9
|
+
/** Photo proof: viewfinder, thumbnails of what is taken, annotate, shutter and Done. */
|
|
10
|
+
export function PhotoCapture({
|
|
11
|
+
frame,
|
|
12
|
+
hint,
|
|
13
|
+
count,
|
|
14
|
+
onCapture,
|
|
15
|
+
onAnnotate,
|
|
16
|
+
onDone,
|
|
17
|
+
camera,
|
|
18
|
+
}: PhotoCaptureProps): ReactElement {
|
|
19
|
+
const t = useT();
|
|
20
|
+
return (
|
|
21
|
+
<Phone frame={frame}>
|
|
22
|
+
<div className="flex flex-col">
|
|
23
|
+
<div
|
|
24
|
+
role="img"
|
|
25
|
+
aria-label={t("camera.viewfinder")}
|
|
26
|
+
className="relative grid place-items-center h-(--ui-photo-view) overflow-hidden bg-camera-bg"
|
|
27
|
+
>
|
|
28
|
+
{camera ? <div className="absolute inset-0">{camera}</div> : null}
|
|
29
|
+
<span className="absolute bottom-16 text-text-14 text-camera-ink">{hint}</span>
|
|
30
|
+
</div>
|
|
31
|
+
<div className="flex flex-col gap-12 p-16">
|
|
32
|
+
<div className="flex flex-wrap gap-8">
|
|
33
|
+
{Array.from({ length: count }, (_, i) => (
|
|
34
|
+
<span
|
|
35
|
+
key={i}
|
|
36
|
+
role="img"
|
|
37
|
+
aria-label={t("photo.n", { n: i + 1 })}
|
|
38
|
+
className="grid place-items-center size-(--ui-thumb) rounded-card bg-bg-hover text-text-tertiary"
|
|
39
|
+
>
|
|
40
|
+
<Icon name="Image" size={16} />
|
|
41
|
+
</span>
|
|
42
|
+
))}
|
|
43
|
+
</div>
|
|
44
|
+
<div className="flex items-center justify-between">
|
|
45
|
+
<IconButton
|
|
46
|
+
icon="PenLine"
|
|
47
|
+
variant="secondary"
|
|
48
|
+
label={t("photo.annotate")}
|
|
49
|
+
onClick={onAnnotate}
|
|
50
|
+
/>
|
|
51
|
+
<button
|
|
52
|
+
type="button"
|
|
53
|
+
aria-label={t("photo.take")}
|
|
54
|
+
onClick={onCapture}
|
|
55
|
+
className={cx(
|
|
56
|
+
"size-(--ui-shutter) rounded-full border-stroke-swatch border-text-primary bg-text-primary cursor-pointer",
|
|
57
|
+
"ring-(length:--stroke-width-accent) ring-inset ring-bg-canvas",
|
|
58
|
+
"focus-visible:outline-stroke-focus focus-visible:outline-offset-2 focus-visible:outline-focus-ring",
|
|
59
|
+
)}
|
|
60
|
+
/>
|
|
61
|
+
<Button variant="primary" onClick={onDone}>
|
|
62
|
+
{t("action.done")}
|
|
63
|
+
</Button>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</Phone>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
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 { Phone, SheetFrame } from "./Compass.shared.tsx";
|
|
6
|
+
import { type QuickIncidentSheetProps } from "./Compass.types.ts";
|
|
7
|
+
|
|
8
|
+
/** Step one of the three-step incident report: choose the type from a grid. */
|
|
9
|
+
export function QuickIncidentSheet({
|
|
10
|
+
frame,
|
|
11
|
+
location,
|
|
12
|
+
types,
|
|
13
|
+
onSelect,
|
|
14
|
+
}: QuickIncidentSheetProps): ReactElement {
|
|
15
|
+
const t = useT();
|
|
16
|
+
return (
|
|
17
|
+
<Phone frame={frame}>
|
|
18
|
+
<SheetFrame title={t("incident.title")} step={t("count.step", { n: 1, total: 3 })}>
|
|
19
|
+
<div className="grid grid-cols-3 gap-8">
|
|
20
|
+
{types.map((type) => (
|
|
21
|
+
<button
|
|
22
|
+
key={type.label}
|
|
23
|
+
type="button"
|
|
24
|
+
onClick={() => onSelect?.(type.label)}
|
|
25
|
+
className={cx(
|
|
26
|
+
"flex flex-col items-center justify-center gap-8 min-h-(--ui-compass-thumb) p-8",
|
|
27
|
+
"border rounded-card bg-bg-surface text-text-primary text-text-14 font-medium cursor-pointer",
|
|
28
|
+
"active:bg-bg-hover forced-colors:border-[CanvasText]",
|
|
29
|
+
"focus-visible:outline-stroke-focus focus-visible:outline-offset-2 focus-visible:outline-focus-ring",
|
|
30
|
+
type.critical ? "border-danger" : "border-border-control",
|
|
31
|
+
)}
|
|
32
|
+
>
|
|
33
|
+
<Icon name={type.icon} size={28} className={type.critical ? "text-danger" : ""} />
|
|
34
|
+
<span>{type.label}</span>
|
|
35
|
+
</button>
|
|
36
|
+
))}
|
|
37
|
+
</div>
|
|
38
|
+
<div className="flex items-center gap-6 text-text-secondary">
|
|
39
|
+
<Icon name="MapPin" size={16} />
|
|
40
|
+
{location}
|
|
41
|
+
</div>
|
|
42
|
+
<p className="m-0 text-text-12 text-text-secondary">{t("incident.help")}</p>
|
|
43
|
+
</SheetFrame>
|
|
44
|
+
</Phone>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
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, IconButton } from "../Button/Button.tsx";
|
|
6
|
+
import { SegmentedControl } from "../Navigation/Navigation.tsx";
|
|
7
|
+
import { Phone, blockClass } from "./Compass.shared.tsx";
|
|
8
|
+
import { type ScanSheetProps } from "./Compass.types.ts";
|
|
9
|
+
|
|
10
|
+
const SCAN_MODES = ["asset", "receiving", "credential"] as const;
|
|
11
|
+
|
|
12
|
+
/** The scan surface: mode switch, viewfinder, last result, running count and Done. */
|
|
13
|
+
export function ScanSheet({
|
|
14
|
+
frame,
|
|
15
|
+
mode,
|
|
16
|
+
hint,
|
|
17
|
+
count,
|
|
18
|
+
countLabel,
|
|
19
|
+
doneLabel,
|
|
20
|
+
last,
|
|
21
|
+
onModeChange,
|
|
22
|
+
onDone,
|
|
23
|
+
onNfc,
|
|
24
|
+
onTorch,
|
|
25
|
+
camera,
|
|
26
|
+
}: ScanSheetProps): ReactElement {
|
|
27
|
+
const t = useT();
|
|
28
|
+
return (
|
|
29
|
+
<Phone frame={frame}>
|
|
30
|
+
<div className="flex flex-col">
|
|
31
|
+
<div className="flex justify-center p-12">
|
|
32
|
+
<SegmentedControl
|
|
33
|
+
label={t("scan.mode")}
|
|
34
|
+
value={mode}
|
|
35
|
+
options={SCAN_MODES.map((m) => ({ value: m, label: t(`scan.${m}`) }))}
|
|
36
|
+
onChange={(next) => onModeChange?.(next as ScanSheetProps["mode"])}
|
|
37
|
+
/>
|
|
38
|
+
</div>
|
|
39
|
+
<div
|
|
40
|
+
aria-label={t("camera.viewfinder")}
|
|
41
|
+
className="relative grid place-items-center h-(--ui-scan-view) overflow-hidden bg-camera-bg"
|
|
42
|
+
>
|
|
43
|
+
{camera ? <div className="absolute inset-0">{camera}</div> : null}
|
|
44
|
+
<span className="relative w-(--ui-reticle-inline) h-(--ui-reticle-block) max-w-full box-border rounded-dialog ring-(length:--stroke-width-focus) ring-camera-ink" />
|
|
45
|
+
<span className="absolute bottom-16 text-text-14 text-camera-ink">{hint}</span>
|
|
46
|
+
</div>
|
|
47
|
+
<div className="flex flex-col gap-12 p-16">
|
|
48
|
+
{last ? (
|
|
49
|
+
<div
|
|
50
|
+
role="status"
|
|
51
|
+
className={cx(
|
|
52
|
+
"flex items-center gap-12 p-12 rounded-card bg-bg-surface ring-(length:--ui-hairline-half) ring-inset",
|
|
53
|
+
last.ok ? "ring-success" : "ring-danger",
|
|
54
|
+
)}
|
|
55
|
+
>
|
|
56
|
+
<Icon
|
|
57
|
+
name={last.ok ? "CircleCheck" : "CircleX"}
|
|
58
|
+
size={24}
|
|
59
|
+
className={last.ok ? "text-success" : "text-danger"}
|
|
60
|
+
/>
|
|
61
|
+
<div className="flex flex-col">
|
|
62
|
+
<strong>{last.title}</strong>
|
|
63
|
+
<span className="font-mono text-mono-12 text-text-secondary">{last.code}</span>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
) : null}
|
|
67
|
+
<div className="flex items-center justify-between">
|
|
68
|
+
<span role="status">
|
|
69
|
+
<strong className="text-heading-24 tabular-nums">{count}</strong> {countLabel}
|
|
70
|
+
</span>
|
|
71
|
+
<span className="flex items-center gap-8">
|
|
72
|
+
<IconButton icon="Nfc" label={t("scan.nfc")} onClick={onNfc} />
|
|
73
|
+
<IconButton icon="Flashlight" label={t("scan.torch")} onClick={onTorch} />
|
|
74
|
+
</span>
|
|
75
|
+
</div>
|
|
76
|
+
<Button variant="primary" size="lg" className={blockClass} onClick={onDone}>
|
|
77
|
+
{doneLabel}
|
|
78
|
+
</Button>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
</Phone>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type ReactElement, type ReactNode } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
4
|
+
import { StateChip } from "../Chips/Chips.tsx";
|
|
5
|
+
import { compassText } from "./Compass.shared.tsx";
|
|
6
|
+
import { type ShiftCardProps } from "./Compass.types.ts";
|
|
7
|
+
|
|
8
|
+
function Fact({ icon, children }: { icon: string; children: ReactNode }): ReactElement {
|
|
9
|
+
return (
|
|
10
|
+
<span className="flex items-center gap-6">
|
|
11
|
+
<Icon name={icon} size={16} className="text-text-secondary" />
|
|
12
|
+
{children}
|
|
13
|
+
</span>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** A shift with its state, countdown, role, date, time and place, and up to two actions. */
|
|
18
|
+
export function ShiftCard({
|
|
19
|
+
state,
|
|
20
|
+
stateLabel,
|
|
21
|
+
countdown,
|
|
22
|
+
role,
|
|
23
|
+
date,
|
|
24
|
+
time,
|
|
25
|
+
place,
|
|
26
|
+
actions,
|
|
27
|
+
}: ShiftCardProps): ReactElement {
|
|
28
|
+
return (
|
|
29
|
+
<article
|
|
30
|
+
className={cx(
|
|
31
|
+
"xos-compass flex flex-col gap-12 w-(--ui-compass-card) max-w-full box-border p-16",
|
|
32
|
+
"bg-bg-raised border border-border-subtle rounded-dialog forced-colors:border-[CanvasText]",
|
|
33
|
+
compassText,
|
|
34
|
+
)}
|
|
35
|
+
>
|
|
36
|
+
<header className="flex items-center justify-between gap-8">
|
|
37
|
+
<StateChip state={state} label={stateLabel} />
|
|
38
|
+
{countdown ? <span className="text-text-secondary tabular-nums">{countdown}</span> : null}
|
|
39
|
+
</header>
|
|
40
|
+
<strong className="text-heading-16 font-semibold">{role}</strong>
|
|
41
|
+
<div className="flex flex-col gap-6">
|
|
42
|
+
<Fact icon="Calendar">{date}</Fact>
|
|
43
|
+
<Fact icon="Clock">
|
|
44
|
+
<span className="tabular-nums">{time}</span>
|
|
45
|
+
</Fact>
|
|
46
|
+
<Fact icon="MapPin">{place}</Fact>
|
|
47
|
+
</div>
|
|
48
|
+
{actions ? (
|
|
49
|
+
<footer className="flex items-center gap-8 *:flex-1 *:justify-center *:min-h-touch-min">
|
|
50
|
+
{actions}
|
|
51
|
+
</footer>
|
|
52
|
+
) : null}
|
|
53
|
+
</article>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { useEffect, useRef, type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { Button } from "../Button/Button.tsx";
|
|
5
|
+
import { compassText } from "./Compass.shared.tsx";
|
|
6
|
+
import { type SignaturePadProps } from "./Compass.types.ts";
|
|
7
|
+
|
|
8
|
+
/** A drawn signature with its attestation; pointer input covers finger, stylus and mouse. */
|
|
9
|
+
export function SignaturePad({ label, attestation, onChange }: SignaturePadProps): ReactElement {
|
|
10
|
+
const t = useT();
|
|
11
|
+
const ref = useRef<HTMLCanvasElement>(null);
|
|
12
|
+
const onChangeRef = useRef(onChange);
|
|
13
|
+
onChangeRef.current = onChange;
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
const canvas = ref.current;
|
|
16
|
+
const ctx = canvas?.getContext("2d");
|
|
17
|
+
if (!canvas || !ctx) return;
|
|
18
|
+
let down = false;
|
|
19
|
+
ctx.lineWidth = 2;
|
|
20
|
+
ctx.lineCap = "round";
|
|
21
|
+
ctx.strokeStyle = getComputedStyle(canvas).color;
|
|
22
|
+
const pos = (e: PointerEvent): [number, number] => {
|
|
23
|
+
const r = canvas.getBoundingClientRect();
|
|
24
|
+
return [
|
|
25
|
+
((e.clientX - r.left) * canvas.width) / (r.width || 1),
|
|
26
|
+
((e.clientY - r.top) * canvas.height) / (r.height || 1),
|
|
27
|
+
];
|
|
28
|
+
};
|
|
29
|
+
canvas.onpointerdown = (e) => {
|
|
30
|
+
down = true;
|
|
31
|
+
const [x, y] = pos(e);
|
|
32
|
+
ctx.beginPath();
|
|
33
|
+
ctx.moveTo(x, y);
|
|
34
|
+
};
|
|
35
|
+
canvas.onpointermove = (e) => {
|
|
36
|
+
if (!down) return;
|
|
37
|
+
const [x, y] = pos(e);
|
|
38
|
+
ctx.lineTo(x, y);
|
|
39
|
+
ctx.stroke();
|
|
40
|
+
};
|
|
41
|
+
canvas.onpointerup = canvas.onpointerleave = () => {
|
|
42
|
+
if (!down) return;
|
|
43
|
+
down = false;
|
|
44
|
+
onChangeRef.current?.(canvas.toDataURL("image/png"));
|
|
45
|
+
};
|
|
46
|
+
}, []);
|
|
47
|
+
const clear = () => {
|
|
48
|
+
const canvas = ref.current;
|
|
49
|
+
canvas?.getContext("2d")?.clearRect(0, 0, canvas.width, canvas.height);
|
|
50
|
+
onChange?.(null);
|
|
51
|
+
};
|
|
52
|
+
return (
|
|
53
|
+
<div className={cx("xos-compass flex flex-col gap-6 w-(--ui-field) max-w-full", compassText)}>
|
|
54
|
+
<span className="text-label-13 font-medium">{label}</span>
|
|
55
|
+
<canvas
|
|
56
|
+
ref={ref}
|
|
57
|
+
width={720}
|
|
58
|
+
height={240}
|
|
59
|
+
role="img"
|
|
60
|
+
aria-label={t("signature.area")}
|
|
61
|
+
className="w-full h-(--ui-sigpad) bg-bg-surface border border-dashed border-border-strong rounded-card touch-none cursor-crosshair text-text-primary"
|
|
62
|
+
/>
|
|
63
|
+
<div className="flex items-center justify-between gap-8">
|
|
64
|
+
<span className="text-text-12 text-text-secondary">{attestation}</span>
|
|
65
|
+
<Button size="sm" variant="ghost" onClick={clear}>
|
|
66
|
+
{t("action.clear")}
|
|
67
|
+
</Button>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useId, useState, type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { Button } from "../Button/Button.tsx";
|
|
5
|
+
import { Phone, SheetFrame, blockClass } from "./Compass.shared.tsx";
|
|
6
|
+
import { type SyncConflictSheetProps } from "./Compass.types.ts";
|
|
7
|
+
|
|
8
|
+
/** Resolves an offline write that collided with a newer server value. */
|
|
9
|
+
export function SyncConflictSheet({
|
|
10
|
+
frame,
|
|
11
|
+
message,
|
|
12
|
+
field,
|
|
13
|
+
mine,
|
|
14
|
+
mineMeta,
|
|
15
|
+
theirs,
|
|
16
|
+
theirsMeta,
|
|
17
|
+
onKeep,
|
|
18
|
+
}: SyncConflictSheetProps): ReactElement {
|
|
19
|
+
const t = useT();
|
|
20
|
+
const [choice, setChoice] = useState<"mine" | "theirs">("mine");
|
|
21
|
+
const name = useId();
|
|
22
|
+
const options = [
|
|
23
|
+
{ value: "mine" as const, who: t("conflict.yours"), value_: mine, meta: mineMeta },
|
|
24
|
+
{ value: "theirs" as const, who: t("conflict.server"), value_: theirs, meta: theirsMeta },
|
|
25
|
+
];
|
|
26
|
+
return (
|
|
27
|
+
<Phone frame={frame}>
|
|
28
|
+
<SheetFrame title={t("conflict.title")}>
|
|
29
|
+
<p className="m-0 text-text-secondary">{message}</p>
|
|
30
|
+
<span className="text-label-13 font-medium">{field}</span>
|
|
31
|
+
{options.map((o) => (
|
|
32
|
+
<label
|
|
33
|
+
key={o.value}
|
|
34
|
+
className={cx(
|
|
35
|
+
"flex items-center gap-12 p-12 border rounded-card cursor-pointer",
|
|
36
|
+
choice === o.value ? "border-accent bg-bg-hover" : "border-border-control",
|
|
37
|
+
)}
|
|
38
|
+
>
|
|
39
|
+
<input
|
|
40
|
+
type="radio"
|
|
41
|
+
name={name}
|
|
42
|
+
checked={choice === o.value}
|
|
43
|
+
onChange={() => setChoice(o.value)}
|
|
44
|
+
className="size-icon-20 accent-(--color-accent-default)"
|
|
45
|
+
/>
|
|
46
|
+
<div className="flex flex-col">
|
|
47
|
+
<span className="text-text-secondary">
|
|
48
|
+
{o.who} · {o.meta}
|
|
49
|
+
</span>
|
|
50
|
+
<strong>{o.value_}</strong>
|
|
51
|
+
</div>
|
|
52
|
+
</label>
|
|
53
|
+
))}
|
|
54
|
+
<Button variant="primary" size="lg" className={blockClass} onClick={() => onKeep?.(choice)}>
|
|
55
|
+
{t("conflict.keep")}
|
|
56
|
+
</Button>
|
|
57
|
+
</SheetFrame>
|
|
58
|
+
</Phone>
|
|
59
|
+
);
|
|
60
|
+
}
|