@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,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time shorthand for the schedule grid (B4, G-41): what a planner types into a Time or Duration cell, read without
|
|
3
|
+
* chrono so a server and a browser read it the same way. `@xos/ui/quick-add` re-exports this file.
|
|
4
|
+
*
|
|
5
|
+
* en 8, 8a, 8am, 830p, 8:30 pm, 20:30, noon, midnight; ranges 8a-5p, 8-11:30p (the end's meridiem carries back to
|
|
6
|
+
* the start when that keeps the start first), 9 to 5
|
|
7
|
+
* es 8 a. m., 8:30 p. m., 20 h, mediodía, medianoche; ranges 8 a 10, 9 hasta 17
|
|
8
|
+
*
|
|
9
|
+
* An end at or before the start rolls to the next day (endDayOffset 1), so 22-2 runs past midnight. Times come back
|
|
10
|
+
* as 24-hour HH:MM on the wall clock; the grid reads them in the project's zone.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export interface TimeShorthand {
|
|
14
|
+
/** Start as HH:MM, 24-hour. */
|
|
15
|
+
readonly start: string;
|
|
16
|
+
/** End as HH:MM, 24-hour; null for a single time. */
|
|
17
|
+
readonly end: string | null;
|
|
18
|
+
/** 1 when the end falls on the next day. */
|
|
19
|
+
readonly endDayOffset: 0 | 1;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface TimeShorthandOptions {
|
|
23
|
+
/** en-US or es-US; both languages' words are read either way, the locale only breaks ties. */
|
|
24
|
+
readonly locale?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
type Meridiem = "a" | "p" | "h" | null;
|
|
28
|
+
|
|
29
|
+
interface Clock {
|
|
30
|
+
readonly h: number;
|
|
31
|
+
readonly m: number;
|
|
32
|
+
readonly meridiem: Meridiem;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const WORDS: Readonly<Record<string, Clock>> = {
|
|
36
|
+
noon: { h: 12, m: 0, meridiem: "h" },
|
|
37
|
+
midday: { h: 12, m: 0, meridiem: "h" },
|
|
38
|
+
midnight: { h: 0, m: 0, meridiem: "h" },
|
|
39
|
+
mediodía: { h: 12, m: 0, meridiem: "h" },
|
|
40
|
+
mediodia: { h: 12, m: 0, meridiem: "h" },
|
|
41
|
+
medianoche: { h: 0, m: 0, meridiem: "h" },
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const ONE =
|
|
45
|
+
/^(\d{1,4})(?:[:.h](\d{2}))?\s*(a|am|a\.m\.|a\.\s?m\.|p|pm|p\.m\.|p\.\s?m\.|h|hrs|horas)?$/u;
|
|
46
|
+
|
|
47
|
+
function normalize(text: string): string {
|
|
48
|
+
return text
|
|
49
|
+
.toLowerCase()
|
|
50
|
+
.replace(/\u00a0/g, " ")
|
|
51
|
+
.replace(/\s+/g, " ")
|
|
52
|
+
.trim();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function readOne(raw: string): Clock | null {
|
|
56
|
+
const text = normalize(raw);
|
|
57
|
+
const word = WORDS[text];
|
|
58
|
+
if (word) return word;
|
|
59
|
+
const match = ONE.exec(text);
|
|
60
|
+
if (!match) return null;
|
|
61
|
+
const digits = match[1] ?? "";
|
|
62
|
+
let h: number;
|
|
63
|
+
let m: number;
|
|
64
|
+
if (match[2] !== undefined) {
|
|
65
|
+
h = Number(digits);
|
|
66
|
+
m = Number(match[2]);
|
|
67
|
+
} else if (digits.length >= 3) {
|
|
68
|
+
h = Number(digits.slice(0, -2));
|
|
69
|
+
m = Number(digits.slice(-2));
|
|
70
|
+
} else {
|
|
71
|
+
h = Number(digits);
|
|
72
|
+
m = 0;
|
|
73
|
+
}
|
|
74
|
+
const suffix = match[3] ?? "";
|
|
75
|
+
const meridiem: Meridiem = suffix.startsWith("a")
|
|
76
|
+
? "a"
|
|
77
|
+
: suffix.startsWith("p")
|
|
78
|
+
? "p"
|
|
79
|
+
: suffix
|
|
80
|
+
? "h"
|
|
81
|
+
: null;
|
|
82
|
+
if (m > 59) return null;
|
|
83
|
+
if (meridiem === "a" || meridiem === "p") {
|
|
84
|
+
if (h < 1 || h > 12) return null;
|
|
85
|
+
} else if (h > 24 || (h === 24 && m > 0)) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return { h, m, meridiem };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function to24(c: Clock, meridiem: Meridiem): number {
|
|
92
|
+
const h = c.h === 24 ? 0 : c.h;
|
|
93
|
+
if (meridiem === "a") return (h % 12) * 60 + c.m;
|
|
94
|
+
if (meridiem === "p") return ((h % 12) + 12) * 60 + c.m;
|
|
95
|
+
return h * 60 + c.m;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function hhmm(minutes: number): string {
|
|
99
|
+
const within = ((minutes % 1440) + 1440) % 1440;
|
|
100
|
+
return `${String(Math.floor(within / 60)).padStart(2, "0")}:${String(within % 60).padStart(2, "0")}`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const RANGE = /\s*(?:-|\u2013|\u2014|\bto\b|\bhasta\b|\s(?:a)\s(?=\d))\s*/u;
|
|
104
|
+
|
|
105
|
+
/** Reads a time or a time range typed as shorthand, or null when the text is not shorthand. */
|
|
106
|
+
export function parseTimeShorthand(
|
|
107
|
+
text: string,
|
|
108
|
+
options: TimeShorthandOptions = {},
|
|
109
|
+
): TimeShorthand | null {
|
|
110
|
+
void options;
|
|
111
|
+
const value = normalize(text);
|
|
112
|
+
if (value === "") return null;
|
|
113
|
+
const parts = value.split(RANGE).filter((p) => p !== "");
|
|
114
|
+
if (parts.length === 1) {
|
|
115
|
+
const one = readOne(parts[0] ?? "");
|
|
116
|
+
return one ? { start: hhmm(to24(one, one.meridiem)), end: null, endDayOffset: 0 } : null;
|
|
117
|
+
}
|
|
118
|
+
if (parts.length !== 2) return null;
|
|
119
|
+
const start = readOne(parts[0] ?? "");
|
|
120
|
+
const end = readOne(parts[1] ?? "");
|
|
121
|
+
if (!start || !end) return null;
|
|
122
|
+
const endMinutes = to24(end, end.meridiem);
|
|
123
|
+
let startMinutes = to24(start, start.meridiem);
|
|
124
|
+
// The end's meridiem carries back to a bare start (8-11:30p is 20:00 to 23:30), unless that would put the start
|
|
125
|
+
// after the end (10-2p is 10:00 to 14:00).
|
|
126
|
+
if (start.meridiem === null && (end.meridiem === "a" || end.meridiem === "p") && start.h <= 12) {
|
|
127
|
+
const carried = to24(start, end.meridiem);
|
|
128
|
+
const other = to24(start, end.meridiem === "a" ? "p" : "a");
|
|
129
|
+
startMinutes = carried <= endMinutes ? carried : other <= endMinutes ? other : carried;
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
start: hhmm(startMinutes),
|
|
133
|
+
end: hhmm(endMinutes),
|
|
134
|
+
endDayOffset: endMinutes <= startMinutes ? 1 : 0,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Reads a length typed as shorthand, in whole minutes: 45, 45m, 45 min, 90 min, 1h, 1 h, 1h30, 1:30, 1.5h. Null when
|
|
140
|
+
* the text is not a length.
|
|
141
|
+
*/
|
|
142
|
+
export function parseDuration(text: string): number | null {
|
|
143
|
+
const value = normalize(text).replace(/\s+/g, "");
|
|
144
|
+
if (value === "") return null;
|
|
145
|
+
let match = /^(\d+)(?:m|min|mins|minutes|minutos)?$/u.exec(value);
|
|
146
|
+
if (match) return Number(match[1]);
|
|
147
|
+
match = /^(\d+):(\d{2})$/u.exec(value);
|
|
148
|
+
if (match) return Number(match[2]) > 59 ? null : Number(match[1]) * 60 + Number(match[2]);
|
|
149
|
+
match = /^(\d+(?:[.,]\d+)?)(?:h|hr|hrs|hora|horas)(?:(\d{1,2})(?:m|min)?)?$/u.exec(value);
|
|
150
|
+
if (match) {
|
|
151
|
+
const hours = Number((match[1] ?? "0").replace(",", "."));
|
|
152
|
+
const minutes = match[2] ? Number(match[2]) : 0;
|
|
153
|
+
if (minutes > 59) return null;
|
|
154
|
+
return Math.round(hours * 60) + minutes;
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { useLocale } from "../lib/context.tsx";
|
|
3
|
+
import type { parseQuickAdd } from "./parseQuickAdd.tsx";
|
|
4
|
+
import {
|
|
5
|
+
finalizeQuickAdd,
|
|
6
|
+
quickAddKey,
|
|
7
|
+
tidyTitle,
|
|
8
|
+
type QuickAddParse,
|
|
9
|
+
type QuickAddResolution,
|
|
10
|
+
type QuickAddResolver,
|
|
11
|
+
type QuickAddResult,
|
|
12
|
+
type QuickAddToken,
|
|
13
|
+
} from "./quickAddCore.ts";
|
|
14
|
+
|
|
15
|
+
export interface UseQuickAddOptions {
|
|
16
|
+
/** The line as typed; the caller owns the input. */
|
|
17
|
+
text: string;
|
|
18
|
+
referenceDate?: Date;
|
|
19
|
+
/** The language of date phrases; the provider's locale by default. */
|
|
20
|
+
locale?: string;
|
|
21
|
+
/** The IANA zone date phrases are read in; the device's by default. */
|
|
22
|
+
timeZone?: string;
|
|
23
|
+
/** Resolves people, tags, kinds and scopes; without one, every token applies as typed. */
|
|
24
|
+
resolve?: QuickAddResolver;
|
|
25
|
+
/** How long typing pauses before tokens are resolved, in milliseconds. */
|
|
26
|
+
delay?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface QuickAddController {
|
|
30
|
+
parse: QuickAddParse;
|
|
31
|
+
/** Resolutions by token key, or undefined when there is no resolver. */
|
|
32
|
+
resolutions: Readonly<Record<string, QuickAddResolution>> | undefined;
|
|
33
|
+
/** True while a token of the line waits for its resolution. */
|
|
34
|
+
pending: boolean;
|
|
35
|
+
/** Candidates the person chose for ambiguous tokens, by token key. */
|
|
36
|
+
choices: Readonly<Record<string, string>>;
|
|
37
|
+
/** Turns a token back into text. */
|
|
38
|
+
dismiss: (token: QuickAddToken) => void;
|
|
39
|
+
/** Picks one candidate of an ambiguous token. */
|
|
40
|
+
choose: (token: QuickAddToken, id: string) => void;
|
|
41
|
+
/** The line to save: waits for any resolution still out, then folds unresolved tokens back. */
|
|
42
|
+
finalize: () => Promise<QuickAddResult>;
|
|
43
|
+
/** Forgets dismissed tokens and choices, after a save. */
|
|
44
|
+
reset: () => void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const resolvable = (t: QuickAddToken) => t.type !== "date";
|
|
48
|
+
|
|
49
|
+
type Parser = typeof parseQuickAdd;
|
|
50
|
+
|
|
51
|
+
let parserModule: Promise<Parser> | null = null;
|
|
52
|
+
let loadedParser: Parser | null = null;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The parser and its date library (chrono-node, English and Spanish) load with the first
|
|
56
|
+
* character typed or the field's focus, not with the page that shows a quick add (ADR 0027). Until
|
|
57
|
+
* then the line is plain text, with no chips.
|
|
58
|
+
*/
|
|
59
|
+
export function loadQuickAddParser(): Promise<Parser> {
|
|
60
|
+
parserModule ??= import("./parseQuickAdd.tsx").then(
|
|
61
|
+
(m) => (loadedParser = m.parseQuickAdd),
|
|
62
|
+
(error: unknown) => {
|
|
63
|
+
// A failed chunk fetch (offline, a new deploy) may succeed on the next attempt.
|
|
64
|
+
parserModule = null;
|
|
65
|
+
throw error;
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
return parserModule;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const plainParse = (text: string): QuickAddParse => ({ text, title: tidyTitle(text), tokens: [] });
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Quick add state for any input (Section 11.7): the parse of the current line in the person's
|
|
75
|
+
* language and the org's zone, resolutions fetched once per token after typing pauses, dismissed
|
|
76
|
+
* tokens and chosen candidates. `QuickAdd` uses it with its own input; the Atlas Create menu uses it
|
|
77
|
+
* with the command menu's.
|
|
78
|
+
*/
|
|
79
|
+
export function useQuickAdd({
|
|
80
|
+
text,
|
|
81
|
+
referenceDate,
|
|
82
|
+
locale,
|
|
83
|
+
timeZone,
|
|
84
|
+
resolve,
|
|
85
|
+
delay = 250,
|
|
86
|
+
}: UseQuickAddOptions): QuickAddController {
|
|
87
|
+
const contextLocale = useLocale();
|
|
88
|
+
const [dismissed, setDismissed] = useState<readonly string[]>([]);
|
|
89
|
+
const [choices, setChoices] = useState<Readonly<Record<string, string>>>({});
|
|
90
|
+
const [cache, setCache] = useState<Readonly<Record<string, QuickAddResolution>>>({});
|
|
91
|
+
const cacheRef = useRef(cache);
|
|
92
|
+
const inFlight = useRef(new Map<string, Promise<void>>());
|
|
93
|
+
const resolveRef = useRef(resolve);
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
resolveRef.current = resolve;
|
|
96
|
+
}, [resolve]);
|
|
97
|
+
|
|
98
|
+
const [parser, setParser] = useState<Parser | null>(() => loadedParser);
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
if (parser !== null || text === "") return undefined;
|
|
101
|
+
let live = true;
|
|
102
|
+
loadQuickAddParser().then(
|
|
103
|
+
(p) => {
|
|
104
|
+
if (live) setParser(() => p);
|
|
105
|
+
},
|
|
106
|
+
(error: unknown) => console.error("Could not load the quick add parser", error),
|
|
107
|
+
);
|
|
108
|
+
return () => {
|
|
109
|
+
live = false;
|
|
110
|
+
};
|
|
111
|
+
}, [parser, text]);
|
|
112
|
+
|
|
113
|
+
const parseWith = useCallback(
|
|
114
|
+
(p: Parser | null) =>
|
|
115
|
+
p === null
|
|
116
|
+
? plainParse(text)
|
|
117
|
+
: p(text, {
|
|
118
|
+
locale: locale ?? contextLocale,
|
|
119
|
+
dismissed,
|
|
120
|
+
...(referenceDate ? { referenceDate } : {}),
|
|
121
|
+
...(timeZone ? { timeZone } : {}),
|
|
122
|
+
}),
|
|
123
|
+
[text, locale, contextLocale, dismissed, referenceDate, timeZone],
|
|
124
|
+
);
|
|
125
|
+
const parse = useMemo(() => parseWith(parser), [parseWith, parser]);
|
|
126
|
+
|
|
127
|
+
/** Resolves the tokens with no answer yet; tokens already asked about wait for that answer. */
|
|
128
|
+
const fetchMissing = useCallback((tokens: readonly QuickAddToken[]): Promise<void> => {
|
|
129
|
+
const fn = resolveRef.current;
|
|
130
|
+
if (fn === undefined) return Promise.resolve();
|
|
131
|
+
const waiting: Promise<void>[] = [];
|
|
132
|
+
const ask: QuickAddToken[] = [];
|
|
133
|
+
for (const token of tokens) {
|
|
134
|
+
const key = quickAddKey(token);
|
|
135
|
+
if (key in cacheRef.current) continue;
|
|
136
|
+
const flying = inFlight.current.get(key);
|
|
137
|
+
if (flying) waiting.push(flying);
|
|
138
|
+
else if (!ask.some((t) => quickAddKey(t) === key)) ask.push(token);
|
|
139
|
+
}
|
|
140
|
+
if (ask.length > 0) {
|
|
141
|
+
const request = fn(ask)
|
|
142
|
+
.catch(() => ({}) as Readonly<Record<string, QuickAddResolution>>)
|
|
143
|
+
.then((answer) => {
|
|
144
|
+
const next = { ...cacheRef.current };
|
|
145
|
+
for (const token of ask) {
|
|
146
|
+
const key = quickAddKey(token);
|
|
147
|
+
next[key] = answer[key] ?? { status: "unresolved" };
|
|
148
|
+
inFlight.current.delete(key);
|
|
149
|
+
}
|
|
150
|
+
cacheRef.current = next;
|
|
151
|
+
setCache(next);
|
|
152
|
+
});
|
|
153
|
+
for (const token of ask) inFlight.current.set(quickAddKey(token), request);
|
|
154
|
+
waiting.push(request);
|
|
155
|
+
}
|
|
156
|
+
return Promise.all(waiting).then(() => undefined);
|
|
157
|
+
}, []);
|
|
158
|
+
|
|
159
|
+
const wanted = parse.tokens.filter(resolvable);
|
|
160
|
+
const wantedKeys = wanted.map(quickAddKey).join("\u0000");
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
if (resolveRef.current === undefined || wantedKeys === "") return undefined;
|
|
163
|
+
const timer = setTimeout(() => void fetchMissing(wanted), delay);
|
|
164
|
+
return () => clearTimeout(timer);
|
|
165
|
+
// `wanted` changes with its keys: it is derived from the same parse.
|
|
166
|
+
}, [wantedKeys, delay, fetchMissing]);
|
|
167
|
+
|
|
168
|
+
const resolutions = resolve === undefined ? undefined : cache;
|
|
169
|
+
const pending = resolve !== undefined && wanted.some((t) => !(quickAddKey(t) in cache));
|
|
170
|
+
|
|
171
|
+
const finalize = useCallback(async (): Promise<QuickAddResult> => {
|
|
172
|
+
// A line saved before the parser arrived is read once it has.
|
|
173
|
+
const line = parser === null ? parseWith(await loadQuickAddParser()) : parse;
|
|
174
|
+
await fetchMissing(line.tokens.filter(resolvable));
|
|
175
|
+
return finalizeQuickAdd(
|
|
176
|
+
line,
|
|
177
|
+
resolveRef.current === undefined ? undefined : cacheRef.current,
|
|
178
|
+
choices,
|
|
179
|
+
);
|
|
180
|
+
}, [fetchMissing, parse, parser, parseWith, choices]);
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
parse,
|
|
184
|
+
resolutions,
|
|
185
|
+
pending,
|
|
186
|
+
choices,
|
|
187
|
+
dismiss: useCallback(
|
|
188
|
+
(token: QuickAddToken) => setDismissed((d) => [...d, quickAddKey(token)]),
|
|
189
|
+
[],
|
|
190
|
+
),
|
|
191
|
+
choose: useCallback(
|
|
192
|
+
(token: QuickAddToken, id: string) => setChoices((c) => ({ ...c, [quickAddKey(token)]: id })),
|
|
193
|
+
[],
|
|
194
|
+
),
|
|
195
|
+
finalize,
|
|
196
|
+
reset: useCallback(() => {
|
|
197
|
+
setDismissed([]);
|
|
198
|
+
setChoices({});
|
|
199
|
+
}, []),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# EmergencyCodeCard
|
|
2
|
+
|
|
3
|
+
EmergencyCodeCard shows one emergency code's protocol for one operational domain, readable offline in Compass Reference.
|
|
4
|
+
|
|
5
|
+
- Emergency codes are global (decision D15). The 14 codes (Code Red through Code Adam) and their protocol per operational domain (Site, Stage, Food & Beverage, Guest Experience, Back of House, Front of House Operations) are one Standard Library shared by every organization and project. Record keys sort in numeric order (EMG-001 onward).
|
|
6
|
+
- Protocol steps never name an agency. They name a service as `{fire}`, `{ems}`, `{lawEnforcement}`, `{bombSquad}` or `{federal}`, and the card resolves each from `authorities`, the responding agencies for the project's jurisdiction. Matching agencies are listed under the steps with their contact. Without a jurisdiction, the generic service name renders ("local law enforcement"), so the card is always correct.
|
|
7
|
+
- The radio channel is a project join from Radio Channels, not part of the code.
|
|
8
|
+
- `swatch` names an `ecode-*` token. The swatch is for recognition only; the code name is always written out, so color never carries the meaning alone.
|
|
9
|
+
- The preview shows Standard Library rows EMG-001, EMG-007 and EMG-025 with the CSMIA26 venue jurisdiction (Mana Wynwood, US-FL-MIAMI-DADE in Bible tab 11). EMG-025 has no authorities passed and shows the generic service name.
|
|
10
|
+
- This card is text. Never draw or approximate a regulatory safety symbol (ISO 7010, ISA) here; licensed marks go in their own slot.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# FAQ
|
|
2
|
+
|
|
3
|
+
FAQ lists questions and answers, built on Accordion.
|
|
4
|
+
|
|
5
|
+
Each question is a heading inside its disclosure button, and every answer stays in the document while closed, so search and answer engines read the full text. The visible text must match the page's FAQPage structured data word for word.
|
|
6
|
+
|
|
7
|
+
Write questions the way a buyer asks them, and answer in the first sentence. The consumer provides eight to ten items; open the first.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# FeatureGrid
|
|
2
|
+
|
|
3
|
+
FeatureGrid arranges short feature cards in two to five columns.
|
|
4
|
+
|
|
5
|
+
An item with a department `code` draws that department's glyph and prints the code in a mono chip beside the name, so a code never appears alone; coded items stay in numeric order. Other items take any Lucide `icon`. Columns collapse to two from bp-sm and one below.
|
|
6
|
+
|
|
7
|
+
The consumer provides a title, one sentence of body copy and, where it helps, one link per item.
|
|
@@ -0,0 +1,40 @@
|
|
|
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 { TONE_ICON, TONE_ICON_CLASS } from "./Feedback.shared.tsx";
|
|
7
|
+
import { type BannerProps } from "./Feedback.types.ts";
|
|
8
|
+
|
|
9
|
+
/** A page-wide condition across the top of a page; at most one per page. */
|
|
10
|
+
export function Banner({
|
|
11
|
+
tone = "info",
|
|
12
|
+
icon,
|
|
13
|
+
children,
|
|
14
|
+
actionLabel,
|
|
15
|
+
onAction,
|
|
16
|
+
onDismiss,
|
|
17
|
+
}: BannerProps): ReactElement {
|
|
18
|
+
const t = useT();
|
|
19
|
+
return (
|
|
20
|
+
<div
|
|
21
|
+
role={tone === "danger" ? "alert" : "status"}
|
|
22
|
+
className={cx(
|
|
23
|
+
"flex items-center gap-8 px-12 py-8 bg-bg-surface border-b border-border-subtle print:hidden",
|
|
24
|
+
tone === "warning" && "border-s-stroke-accent border-s-warning",
|
|
25
|
+
tone === "danger" && "border-s-stroke-accent border-s-danger",
|
|
26
|
+
)}
|
|
27
|
+
>
|
|
28
|
+
<span className={TONE_ICON_CLASS[tone]}>
|
|
29
|
+
<Icon name={icon ?? TONE_ICON[tone]} />
|
|
30
|
+
</span>
|
|
31
|
+
<span className="flex-1">{children}</span>
|
|
32
|
+
{actionLabel ? (
|
|
33
|
+
<Button size="sm" onClick={onAction}>
|
|
34
|
+
{actionLabel}
|
|
35
|
+
</Button>
|
|
36
|
+
) : null}
|
|
37
|
+
{onDismiss ? <IconButton icon="X" label={t("action.dismiss")} onClick={onDismiss} /> : null}
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
3
|
+
import { Button } from "../Button/Button.tsx";
|
|
4
|
+
import { stateClass } from "./Feedback.shared.tsx";
|
|
5
|
+
import { type EmptyStateProps } from "./Feedback.types.ts";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* One sentence and one button: "No shifts yet. Post a crew call." The button is secondary when the
|
|
9
|
+
* page header already holds the primary action (actionVariant), so a screen has one primary.
|
|
10
|
+
*/
|
|
11
|
+
export function EmptyState({
|
|
12
|
+
sentence,
|
|
13
|
+
actionLabel,
|
|
14
|
+
icon,
|
|
15
|
+
shortcut,
|
|
16
|
+
onAction,
|
|
17
|
+
actionVariant = "primary",
|
|
18
|
+
}: EmptyStateProps): ReactElement {
|
|
19
|
+
return (
|
|
20
|
+
<div className={stateClass}>
|
|
21
|
+
{icon ? (
|
|
22
|
+
<span className="text-text-tertiary">
|
|
23
|
+
<Icon name={icon} size={24} />
|
|
24
|
+
</span>
|
|
25
|
+
) : null}
|
|
26
|
+
<p className="m-0 text-text-14 text-text-secondary">{sentence}</p>
|
|
27
|
+
<Button variant={actionVariant} onClick={onAction} {...(shortcut ? { shortcut } : {})}>
|
|
28
|
+
{actionLabel}
|
|
29
|
+
</Button>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
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 { stateClass } from "./Feedback.shared.tsx";
|
|
6
|
+
import { type ErrorStateProps } from "./Feedback.types.ts";
|
|
7
|
+
|
|
8
|
+
/** A failed load: what happened, a retry and the reference to quote to support. */
|
|
9
|
+
export function ErrorState({
|
|
10
|
+
title,
|
|
11
|
+
sentence,
|
|
12
|
+
actionLabel,
|
|
13
|
+
reference,
|
|
14
|
+
onRetry,
|
|
15
|
+
}: ErrorStateProps): ReactElement {
|
|
16
|
+
const t = useT();
|
|
17
|
+
return (
|
|
18
|
+
<div className={stateClass} role="alert">
|
|
19
|
+
<span className="text-danger">
|
|
20
|
+
<Icon name="CircleAlert" size={24} />
|
|
21
|
+
</span>
|
|
22
|
+
<strong className="text-heading-16 font-semibold">{title}</strong>
|
|
23
|
+
<p className="m-0 text-text-14 text-text-secondary">{sentence}</p>
|
|
24
|
+
<Button variant="primary" icon="RefreshCw" onClick={onRetry}>
|
|
25
|
+
{actionLabel ?? t("action.retry")}
|
|
26
|
+
</Button>
|
|
27
|
+
{reference ? (
|
|
28
|
+
<span className="font-mono text-text-12 text-text-secondary">{reference}</span>
|
|
29
|
+
) : null}
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createContext } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { type Tone } from "./Feedback.types.ts";
|
|
4
|
+
|
|
5
|
+
export const TONE_ICON: Record<Tone, string> = {
|
|
6
|
+
info: "Info",
|
|
7
|
+
success: "CircleCheck",
|
|
8
|
+
warning: "TriangleAlert",
|
|
9
|
+
danger: "OctagonAlert",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const TONE_ICON_CLASS: Record<Tone, string> = {
|
|
13
|
+
info: cx("text-state-scheduled"),
|
|
14
|
+
success: cx("text-success"),
|
|
15
|
+
warning: cx("text-warning"),
|
|
16
|
+
danger: cx("text-danger"),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const alertClass = cx(
|
|
20
|
+
"flex gap-8 p-12 max-w-(--ui-alert) rounded-card border border-border-subtle bg-bg-surface",
|
|
21
|
+
"forced-colors:border-[CanvasText]",
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export const stateClass = cx(
|
|
25
|
+
"flex flex-col items-center gap-12 p-40 max-w-(--ui-empty) text-center rounded-card",
|
|
26
|
+
"border border-dashed border-border-strong",
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* Inside a ToastRegion the region is the live region, mounted before any toast arrives, so a toast
|
|
31
|
+
* added later is announced (4.1.3, A23-014). A toast outside one keeps its own status role.
|
|
32
|
+
*/
|
|
33
|
+
export const InToastRegion = createContext(false);
|
|
34
|
+
|
|
35
|
+
export const toastClass = cx(
|
|
36
|
+
"xos-anim-fade relative inline-flex items-center gap-12 overflow-hidden py-8 ps-12 pe-8",
|
|
37
|
+
"rounded-card bg-bg-raised shadow-menu print:hidden forced-colors:border",
|
|
38
|
+
);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export {
|
|
2
|
+
type EmptyStateProps,
|
|
3
|
+
type ErrorStateProps,
|
|
4
|
+
type RefusalNoticeProps,
|
|
5
|
+
type InlineAlertProps,
|
|
6
|
+
type BannerProps,
|
|
7
|
+
type ToastProps,
|
|
8
|
+
type UndoToastProps,
|
|
9
|
+
} from "./Feedback.types.ts";
|
|
10
|
+
export { EmptyState } from "./EmptyState.tsx";
|
|
11
|
+
export { ErrorState } from "./ErrorState.tsx";
|
|
12
|
+
export { RefusalNotice } from "./RefusalNotice.tsx";
|
|
13
|
+
export { InlineAlert } from "./InlineAlert.tsx";
|
|
14
|
+
export { Banner } from "./Banner.tsx";
|
|
15
|
+
export { Toast } from "./Toast.tsx";
|
|
16
|
+
export { UndoToast } from "./UndoToast.tsx";
|
|
17
|
+
export { ToastRegion } from "./ToastRegion.tsx";
|
|
18
|
+
export { RegionBoundary, RegionError, type RegionBoundaryProps } from "./RegionBoundary.tsx";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BannerProps as ReferenceBannerProps,
|
|
3
|
+
EmptyStateProps as ReferenceEmptyStateProps,
|
|
4
|
+
ErrorStateProps as ReferenceErrorStateProps,
|
|
5
|
+
InlineAlertProps as ReferenceInlineAlertProps,
|
|
6
|
+
RefusalNoticeProps as ReferenceRefusalNoticeProps,
|
|
7
|
+
ToastProps as ReferenceToastProps,
|
|
8
|
+
UndoToastProps as ReferenceUndoToastProps,
|
|
9
|
+
} from "../types/reference";
|
|
10
|
+
|
|
11
|
+
export type EmptyStateProps = ReferenceEmptyStateProps & {
|
|
12
|
+
/**
|
|
13
|
+
* Weight of the action button. Primary by default; pass "secondary" when the page header already
|
|
14
|
+
* carries the same primary action, so the screen keeps one primary action (Section 18 gate 27).
|
|
15
|
+
*/
|
|
16
|
+
actionVariant?: "primary" | "secondary";
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type ErrorStateProps = ReferenceErrorStateProps;
|
|
20
|
+
|
|
21
|
+
export type RefusalNoticeProps = ReferenceRefusalNoticeProps & {
|
|
22
|
+
/**
|
|
23
|
+
* The outcome in words ("Refused"), shown instead of the outcome code, so the code never stands
|
|
24
|
+
* alone in product copy (Section 11.10 item 2). Without it the chip shows the code.
|
|
25
|
+
*/
|
|
26
|
+
outcomeLabel?: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type InlineAlertProps = ReferenceInlineAlertProps;
|
|
30
|
+
|
|
31
|
+
export type BannerProps = ReferenceBannerProps;
|
|
32
|
+
|
|
33
|
+
export type ToastProps = ReferenceToastProps;
|
|
34
|
+
|
|
35
|
+
export type UndoToastProps = ReferenceUndoToastProps & {
|
|
36
|
+
/** Called once when the countdown ends without an undo. */
|
|
37
|
+
onExpire?: () => void;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type Tone = "info" | "success" | "warning" | "danger";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
3
|
+
import { TONE_ICON, TONE_ICON_CLASS, alertClass } from "./Feedback.shared.tsx";
|
|
4
|
+
import { type InlineAlertProps } from "./Feedback.types.ts";
|
|
5
|
+
|
|
6
|
+
/** An inline message in context; danger is announced as an alert, the rest as status. */
|
|
7
|
+
export function InlineAlert({ tone = "info", title, children }: InlineAlertProps): ReactElement {
|
|
8
|
+
return (
|
|
9
|
+
<div className={alertClass} role={tone === "danger" ? "alert" : "status"}>
|
|
10
|
+
<span className={TONE_ICON_CLASS[tone]}>
|
|
11
|
+
<Icon name={TONE_ICON[tone]} />
|
|
12
|
+
</span>
|
|
13
|
+
<div className="flex flex-col gap-2">
|
|
14
|
+
{title ? <div className="font-semibold">{title}</div> : null}
|
|
15
|
+
<div className="text-text-secondary">{children}</div>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
4
|
+
import { Button } from "../Button/Button.tsx";
|
|
5
|
+
import { alertClass } from "./Feedback.shared.tsx";
|
|
6
|
+
import { type RefusalNoticeProps } from "./Feedback.types.ts";
|
|
7
|
+
|
|
8
|
+
/** A refusal (NO_ANSWER, UNRATIFIED or REFUSE) with its reason, never an empty or invented answer. */
|
|
9
|
+
export function RefusalNotice({
|
|
10
|
+
outcome,
|
|
11
|
+
outcomeLabel,
|
|
12
|
+
title,
|
|
13
|
+
reason,
|
|
14
|
+
actionLabel,
|
|
15
|
+
onAction,
|
|
16
|
+
}: RefusalNoticeProps): ReactElement {
|
|
17
|
+
return (
|
|
18
|
+
<div className={cx(alertClass, "border-dashed")} role="status">
|
|
19
|
+
<span className="text-text-secondary">
|
|
20
|
+
<Icon name="info" />
|
|
21
|
+
</span>
|
|
22
|
+
<div className="flex flex-col gap-4">
|
|
23
|
+
<div className="flex flex-wrap items-center gap-6">
|
|
24
|
+
{outcomeLabel ? (
|
|
25
|
+
<span className="px-4 rounded-chip border border-border-strong text-text-11 font-medium text-text-primary">
|
|
26
|
+
{outcomeLabel}
|
|
27
|
+
</span>
|
|
28
|
+
) : (
|
|
29
|
+
<span className="px-4 rounded-chip border border-border-strong font-mono text-text-11 font-medium tracking-wide text-text-primary">
|
|
30
|
+
{outcome}
|
|
31
|
+
</span>
|
|
32
|
+
)}
|
|
33
|
+
<span className="font-semibold">{title}</span>
|
|
34
|
+
</div>
|
|
35
|
+
<div className="text-text-secondary">{reason}</div>
|
|
36
|
+
{actionLabel ? (
|
|
37
|
+
<div>
|
|
38
|
+
<Button size="sm" onClick={onAction}>
|
|
39
|
+
{actionLabel}
|
|
40
|
+
</Button>
|
|
41
|
+
</div>
|
|
42
|
+
) : null}
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
}
|