@shortstravelmgmt/component-lib 0.2.11 → 0.2.12-canary.30.g1e89a1a
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/README.md +54 -7
- package/dist/index.d.ts +925 -56
- package/dist/index.esm.js +377 -30
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +377 -30
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -12,18 +12,19 @@ import React, { createContext, useContext, useState, useEffect, useMemo, useCall
|
|
|
12
12
|
// BRAND COLORS
|
|
13
13
|
// ============================================================================
|
|
14
14
|
const brandColors = {
|
|
15
|
-
blue: '#
|
|
16
|
-
blueDeep: '#
|
|
17
|
-
blueTint: '#
|
|
15
|
+
blue: '#19345F', // Short's Blue
|
|
16
|
+
blueDeep: '#0C1E3E',
|
|
17
|
+
blueTint: '#E4F1F8',
|
|
18
18
|
};
|
|
19
19
|
// ============================================================================
|
|
20
20
|
// PRIMARY COLORS (action / link / focus)
|
|
21
21
|
// ============================================================================
|
|
22
|
+
// Short's Blue navy carries interactive text/fills — ~11:1 on white (WCAG AA).
|
|
22
23
|
const primaryColors = {
|
|
23
|
-
primary: '#
|
|
24
|
-
primaryDark: '#
|
|
25
|
-
primaryLight: '#
|
|
26
|
-
primaryLightHover: '#
|
|
24
|
+
primary: '#19345F',
|
|
25
|
+
primaryDark: '#0C1E3E',
|
|
26
|
+
primaryLight: '#E4F1F8',
|
|
27
|
+
primaryLightHover: '#D3E4F0',
|
|
27
28
|
};
|
|
28
29
|
// ============================================================================
|
|
29
30
|
// NEUTRAL SURFACES
|
|
@@ -54,16 +55,36 @@ const textColors = {
|
|
|
54
55
|
// ============================================================================
|
|
55
56
|
// STATUS COLORS
|
|
56
57
|
// ============================================================================
|
|
58
|
+
// Foreground/text values stay AA-safe on light surfaces. The *Accent values are
|
|
59
|
+
// the Short's-aligned hues for SOLID FILLS + decorative use — on light they fall
|
|
60
|
+
// below 3:1, so meaningful non-text indicators (thin borders/standalone icons)
|
|
61
|
+
// use the base status colour or the *Ink values, never the accent.
|
|
57
62
|
const statusColors = {
|
|
58
63
|
success: '#138660',
|
|
59
64
|
warning: '#9F5500',
|
|
60
65
|
gold: '#FFC179',
|
|
61
66
|
error: '#940000',
|
|
67
|
+
// AA-safe status text ON the light success/warning tint fills (chips/badges);
|
|
68
|
+
// success/warning above dip below 4.5:1 on those tints.
|
|
69
|
+
successInk: '#0F7350',
|
|
70
|
+
warningInk: '#8F4C00',
|
|
71
|
+
successAccent: '#2E9E6B',
|
|
72
|
+
warningAccent: '#E8A13A',
|
|
73
|
+
dangerAccent: '#D7503A', // fills/rules/borders (≥3:1 on white)
|
|
74
|
+
dangerAccentStrong: '#C0402C', // darker brick for solid fills that carry white text (≥4.5:1)
|
|
75
|
+
dangerAccentStrongHover: '#A33524', // hover for the strong danger fill
|
|
62
76
|
};
|
|
63
77
|
// ============================================================================
|
|
64
78
|
// ACCENT COLORS
|
|
65
79
|
// ============================================================================
|
|
66
80
|
const accentColors = {
|
|
81
|
+
// Short's Teal — the reserved spark (rules, eyebrows, stats, focus rings).
|
|
82
|
+
// Never a text color on light (teal-on-white fails AA).
|
|
83
|
+
teal: '#00BCD0',
|
|
84
|
+
tealHover: '#00AEEF',
|
|
85
|
+
tealContrast: '#0C1E3E', // navy text ON a teal fill
|
|
86
|
+
tealInk: '#009AAB', // teal ink for light: 3.10:1 on --bg-page #F5F5F5 (3.38:1 on white) — clears the 3:1 UI/focus bar on the real surface, deliberately under the 4.5:1 text bar (brand-forward tradeoff)
|
|
87
|
+
tealGlow: 'rgba(0, 188, 208, 0.35)', // focus ring
|
|
67
88
|
mint: '#37C3A4',
|
|
68
89
|
forest: '#003E1B',
|
|
69
90
|
forestLight: '#E2F0EC',
|
|
@@ -97,7 +118,7 @@ const vendorColors = {
|
|
|
97
118
|
HA: { bg: '#660099', fg: '#FFFFFF' },
|
|
98
119
|
};
|
|
99
120
|
const gradients = {
|
|
100
|
-
avatar: 'linear-gradient(135deg, #
|
|
121
|
+
avatar: 'linear-gradient(135deg, #19345F 0%, #00BCD0 100%)',
|
|
101
122
|
};
|
|
102
123
|
// ============================================================================
|
|
103
124
|
// ALERT TOKENS
|
|
@@ -147,9 +168,12 @@ const semanticColors = {
|
|
|
147
168
|
// ============================================================================
|
|
148
169
|
// TYPOGRAPHY
|
|
149
170
|
// ============================================================================
|
|
171
|
+
// Inter = body & UI · Montserrat = display & stats · Roboto Condensed = chrome
|
|
172
|
+
// (eyebrows, buttons, badges, footer content).
|
|
150
173
|
const fontFamily = {
|
|
151
|
-
base: "'
|
|
152
|
-
display: "'
|
|
174
|
+
base: "'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif",
|
|
175
|
+
display: "'Montserrat', system-ui, -apple-system, sans-serif",
|
|
176
|
+
label: "'Roboto Condensed', system-ui, -apple-system, sans-serif",
|
|
153
177
|
mono: "'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, Consolas, monospace",
|
|
154
178
|
};
|
|
155
179
|
const fontSize = {
|
|
@@ -274,6 +298,22 @@ const darkTheme = {
|
|
|
274
298
|
...lightTheme,
|
|
275
299
|
colors: {
|
|
276
300
|
...lightTheme.colors,
|
|
301
|
+
// Interactive colors stay a visible blue on dark surfaces. Light-mode navy
|
|
302
|
+
// would collide with the dark fills; a navy-first dark theme is a dedicated
|
|
303
|
+
// follow-up needing split surface/inverse and interactive tokens.
|
|
304
|
+
primary: {
|
|
305
|
+
primary: '#0A53EF',
|
|
306
|
+
primaryDark: '#1A43D1',
|
|
307
|
+
primaryLight: '#E6ECFB',
|
|
308
|
+
primaryLightHover: '#DAE3F8',
|
|
309
|
+
},
|
|
310
|
+
// On dark surfaces the brand teal is the label/focus ink — #00BCD0 reads
|
|
311
|
+
// cleanly on the dark page (7.55:1 on #1a1a1a). Mirrors the CSS
|
|
312
|
+
// --color-accent-ink dark override so both token sources stay in parity.
|
|
313
|
+
accent: {
|
|
314
|
+
...accentColors,
|
|
315
|
+
tealInk: '#00BCD0',
|
|
316
|
+
},
|
|
277
317
|
neutral: {
|
|
278
318
|
basecolor: '#1a1a1a',
|
|
279
319
|
subtle: '#2a2a2a',
|
|
@@ -301,8 +341,8 @@ const darkTheme = {
|
|
|
301
341
|
3: '#a0a0a0',
|
|
302
342
|
4: '#808080',
|
|
303
343
|
disabled: '#606060',
|
|
304
|
-
link:
|
|
305
|
-
linkHover:
|
|
344
|
+
link: '#0A53EF',
|
|
345
|
+
linkHover: '#1A43D1',
|
|
306
346
|
},
|
|
307
347
|
bg: {
|
|
308
348
|
page: '#1a1a1a',
|
|
@@ -690,64 +730,124 @@ function styled(factory) {
|
|
|
690
730
|
return factory;
|
|
691
731
|
}
|
|
692
732
|
|
|
733
|
+
/**
|
|
734
|
+
* Builds an icon component from raw SVG path content.
|
|
735
|
+
*
|
|
736
|
+
* Internal to this module -- every exported icon is produced by it, which is
|
|
737
|
+
* what keeps the whole set consistent in viewBox, stroke weight, and sizing.
|
|
738
|
+
*/
|
|
693
739
|
const createIcon = (children, displayName) => {
|
|
694
740
|
const Icon = ({ size = 24, color = 'currentColor', ...props }) => (jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", width: size, height: size, ...props, children: children }));
|
|
695
741
|
Icon.displayName = displayName;
|
|
696
742
|
return Icon;
|
|
697
743
|
};
|
|
698
744
|
// Travel / segment type icons
|
|
745
|
+
/** Air segment (travel type `A`). */
|
|
699
746
|
const PlaneIcon$3 = createIcon(jsx("path", { d: "M17.8 19.2 16 11l3.5-3.5C21 6 21.5 4 21 3c-1-.5-3 0-4.5 1.5L13 8 4.8 6.2c-.5-.1-.9.1-1.1.5l-.3.5c-.2.5-.1 1 .3 1.3L9 12l-2 3H4l-1 1 3 2 2 3 1-1v-3l3-2 3.5 5.3c.3.4.8.5 1.3.3l.5-.2c.4-.3.6-.7.5-1.2z" }), 'PlaneIcon');
|
|
747
|
+
/** Rental car segment (travel type `C`). */
|
|
700
748
|
const CarIcon$1 = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M19 17h2c.6 0 1-.4 1-1v-3c0-.9-.7-1.7-1.5-1.9C18.7 10.6 16 10 16 10s-1.3-1.4-2.2-2.3c-.5-.4-1.1-.7-1.8-.7H5c-.6 0-1.1.4-1.4.9l-1.4 2.9A3.7 3.7 0 0 0 2 12v4c0 .6.4 1 1 1h2" }), jsx("circle", { cx: "7", cy: "17", r: "2" }), jsx("path", { d: "M9 17h6" }), jsx("circle", { cx: "17", cy: "17", r: "2" })] }), 'CarIcon');
|
|
749
|
+
/** Hotel segment (travel type `H`). */
|
|
701
750
|
const HotelIcon$3 = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M10 22v-6.57" }), jsx("path", { d: "M12 11h.01" }), jsx("path", { d: "M12 7h.01" }), jsx("path", { d: "M14 15.43V22" }), jsx("path", { d: "M15 16a5 5 0 0 0-6 0" }), jsx("path", { d: "M16 11h.01" }), jsx("path", { d: "M16 7h.01" }), jsx("path", { d: "M8 11h.01" }), jsx("path", { d: "M8 7h.01" }), jsx("rect", { x: "4", y: "2", width: "16", height: "20", rx: "2" })] }), 'HotelIcon');
|
|
751
|
+
/** Limo or black car segment (travel type `L`). */
|
|
702
752
|
const LimoIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "m21 8-2 2-1.5-3.7A2 2 0 0 0 15.646 5H8.4a2 2 0 0 0-1.903 1.257L5 10 3 8" }), jsx("path", { d: "M7 14h.01" }), jsx("path", { d: "M17 14h.01" }), jsx("rect", { width: "18", height: "8", x: "3", y: "10", rx: "2" }), jsx("path", { d: "M5 18v2" }), jsx("path", { d: "M19 18v2" })] }), 'LimoIcon');
|
|
753
|
+
/** Rail segment (travel type `R`). */
|
|
703
754
|
const RailIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M8 3.1V7a4 4 0 0 0 8 0V3.1" }), jsx("path", { d: "m9 15-1-1" }), jsx("path", { d: "m15 15 1-1" }), jsx("path", { d: "M9 19c-2.8 0-5-2.2-5-5v-4a8 8 0 0 1 16 0v4c0 2.8-2.2 5-5 5Z" }), jsx("path", { d: "m8 19-2 3" }), jsx("path", { d: "m16 19 2 3" })] }), 'RailIcon');
|
|
755
|
+
/** Motorcoach segment (travel type `B`), including team charters. */
|
|
704
756
|
const BusIcon$2 = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M8 6v6" }), jsx("path", { d: "M15 6v6" }), jsx("path", { d: "M2 12h19.6" }), jsx("path", { d: "M18 18h3s.5-1.7.8-2.8c.1-.4.2-.8.2-1.2 0-.4-.1-.8-.2-1.2l-1.4-5C20.1 6.8 19.1 6 18 6H4a2 2 0 0 0-2 2v10h3" }), jsx("circle", { cx: "7", cy: "18", r: "2" }), jsx("path", { d: "M9 18h5" }), jsx("circle", { cx: "16", cy: "18", r: "2" })] }), 'BusIcon');
|
|
705
757
|
// Control / chrome icons
|
|
758
|
+
/** Magnifying glass, for search inputs and filter triggers. */
|
|
706
759
|
const SearchIcon$1 = createIcon(jsxs(Fragment, { children: [jsx("circle", { cx: "11", cy: "11", r: "8" }), jsx("path", { d: "m21 21-4.3-4.3" })] }), 'SearchIcon');
|
|
760
|
+
/** Downward chevron, for expanding a section or opening a dropdown. */
|
|
707
761
|
const ChevronDownIcon$1 = createIcon(jsx("path", { d: "m6 9 6 6 6-6" }), 'ChevronDownIcon');
|
|
762
|
+
/** Upward chevron, for collapsing an expanded section. */
|
|
708
763
|
const ChevronUpIcon = createIcon(jsx("path", { d: "m18 15-6-6-6 6" }), 'ChevronUpIcon');
|
|
764
|
+
/** Rightward chevron, for drill-in navigation and breadcrumbs. */
|
|
709
765
|
const ChevronRightIcon$1 = createIcon(jsx("path", { d: "m9 18 6-6-6-6" }), 'ChevronRightIcon');
|
|
766
|
+
/** Leftward chevron, for back navigation and carousels. */
|
|
710
767
|
const ChevronLeftIcon = createIcon(jsx("path", { d: "m15 18-6-6 6-6" }), 'ChevronLeftIcon');
|
|
768
|
+
/** Outbound arrow, for departing legs and external links. */
|
|
711
769
|
const ArrowUpRightIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M7 7h10v10" }), jsx("path", { d: "M7 17 17 7" })] }), 'ArrowUpRightIcon');
|
|
770
|
+
/** Inbound arrow, for returning legs. */
|
|
712
771
|
const ArrowDownLeftIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M17 7 7 17" }), jsx("path", { d: "M17 17H7V7" })] }), 'ArrowDownLeftIcon');
|
|
772
|
+
/** Eye, for view-only actions and visibility toggles. */
|
|
713
773
|
const EyeIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0" }), jsx("circle", { cx: "12", cy: "12", r: "3" })] }), 'EyeIcon');
|
|
774
|
+
/** Download, for exporting reports and manifests. */
|
|
714
775
|
const DownloadIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), jsx("polyline", { points: "7 10 12 15 17 10" }), jsx("line", { x1: "12", x2: "12", y1: "15", y2: "3" })] }), 'DownloadIcon');
|
|
776
|
+
/** Upload, for importing rosters and attaching files. */
|
|
715
777
|
const UploadIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), jsx("polyline", { points: "17 8 12 3 7 8" }), jsx("line", { x1: "12", x2: "12", y1: "3", y2: "15" })] }), 'UploadIcon');
|
|
778
|
+
/** Funnel, for opening filter controls. */
|
|
716
779
|
const FilterIcon$1 = createIcon(jsx("polygon", { points: "22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" }), 'FilterIcon');
|
|
780
|
+
/** Calendar, for date pickers and schedule views. */
|
|
717
781
|
const CalendarIcon$1 = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M8 2v4" }), jsx("path", { d: "M16 2v4" }), jsx("rect", { width: "18", height: "18", x: "3", y: "4", rx: "2" }), jsx("path", { d: "M3 10h18" })] }), 'CalendarIcon');
|
|
782
|
+
/** Single person, for a traveler or profile. */
|
|
718
783
|
const UserIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" }), jsx("circle", { cx: "12", cy: "7", r: "4" })] }), 'UserIcon');
|
|
784
|
+
/** Group of people, for teams, rosters, and group travel. */
|
|
719
785
|
const UsersIcon$1 = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }), jsx("circle", { cx: "9", cy: "7", r: "4" }), jsx("path", { d: "M22 21v-2a4 4 0 0 0-3-3.87" }), jsx("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })] }), 'UsersIcon');
|
|
786
|
+
/** Envelope, for email addresses and send actions. */
|
|
720
787
|
const MailIcon = createIcon(jsxs(Fragment, { children: [jsx("rect", { width: "20", height: "16", x: "2", y: "4", rx: "2" }), jsx("path", { d: "m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" })] }), 'MailIcon');
|
|
788
|
+
/** Handset, for phone numbers. */
|
|
721
789
|
const PhoneIcon = createIcon(jsx("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" }), 'PhoneIcon');
|
|
790
|
+
/** Agent headset, for travel agent contact and support. */
|
|
722
791
|
const HeadsetIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M4 13v-1a8 8 0 0 1 16 0v1" }), jsx("rect", { x: "2", y: "13", width: "4", height: "6", rx: "1" }), jsx("rect", { x: "18", y: "13", width: "4", height: "6", rx: "1" }), jsx("path", { d: "M4 19v1a2 2 0 0 0 2 2h4" })] }), 'HeadsetIcon');
|
|
792
|
+
/** Printer, for print actions. */
|
|
723
793
|
const PrinterIcon = createIcon(jsxs(Fragment, { children: [jsx("polyline", { points: "6 9 6 2 18 2 18 9" }), jsx("path", { d: "M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2" }), jsx("rect", { width: "12", height: "8", x: "6", y: "14" })] }), 'PrinterIcon');
|
|
794
|
+
/** Circular arrows, for reloading data and retrying a failed request. */
|
|
724
795
|
const RefreshIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }), jsx("path", { d: "M21 3v5h-5" }), jsx("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }), jsx("path", { d: "M8 16H3v5" })] }), 'RefreshIcon');
|
|
796
|
+
/** Warning triangle, for warning and error states. */
|
|
725
797
|
const WarningIcon$1 = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" }), jsx("path", { d: "M12 9v4" }), jsx("path", { d: "M12 17h.01" })] }), 'WarningIcon');
|
|
798
|
+
/** Checkmark, for success states and confirmed selections. */
|
|
726
799
|
const CheckIcon$2 = createIcon(jsx("polyline", { points: "20 6 9 17 4 12" }), 'CheckIcon');
|
|
800
|
+
/** Cross, for clearing a value or marking a negative state. */
|
|
727
801
|
const XIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M18 6 6 18" }), jsx("path", { d: "m6 6 12 12" })] }), 'XIcon');
|
|
802
|
+
/** Plus, for add and create actions. */
|
|
728
803
|
const PlusIcon$2 = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M5 12h14" }), jsx("path", { d: "M12 5v14" })] }), 'PlusIcon');
|
|
804
|
+
/** Minus, for remove and decrement actions. */
|
|
729
805
|
const MinusIcon = createIcon(jsx("path", { d: "M5 12h14" }), 'MinusIcon');
|
|
806
|
+
/** Hamburger, for opening navigation on small screens. */
|
|
730
807
|
const MenuIcon = createIcon(jsxs(Fragment, { children: [jsx("line", { x1: "4", x2: "20", y1: "12", y2: "12" }), jsx("line", { x1: "4", x2: "20", y1: "6", y2: "6" }), jsx("line", { x1: "4", x2: "20", y1: "18", y2: "18" })] }), 'MenuIcon');
|
|
808
|
+
/** Lightbulb, for tips and informational callouts. */
|
|
731
809
|
const LightbulbIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5" }), jsx("path", { d: "M9 18h6" }), jsx("path", { d: "M10 22h4" })] }), 'LightbulbIcon');
|
|
810
|
+
/** Megaphone, for announcements and broadcast banners. */
|
|
732
811
|
const MegaphoneIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "m3 11 18-5v12L3 13v-2z" }), jsx("path", { d: "M11.6 16.8a3 3 0 1 1-5.8-1.6" })] }), 'MegaphoneIcon');
|
|
733
812
|
// Additional icons
|
|
813
|
+
/** Close, for dismissing modals, drawers, and alerts. */
|
|
734
814
|
const CloseIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M18 6 6 18" }), jsx("path", { d: "m6 6 12 12" })] }), 'CloseIcon');
|
|
815
|
+
/** Dashboard, for the home and overview destinations. */
|
|
735
816
|
const DashboardIcon = createIcon(jsxs(Fragment, { children: [jsx("rect", { width: "7", height: "9", x: "3", y: "3", rx: "1" }), jsx("rect", { width: "7", height: "5", x: "14", y: "3", rx: "1" }), jsx("rect", { width: "7", height: "9", x: "14", y: "12", rx: "1" }), jsx("rect", { width: "7", height: "5", x: "3", y: "16", rx: "1" })] }), 'DashboardIcon');
|
|
817
|
+
/** Report, for reporting destinations and exports. */
|
|
736
818
|
const ReportIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7l-5-5z" }), jsx("path", { d: "M14 2v5h5" }), jsx("path", { d: "M10 9h4" }), jsx("path", { d: "M10 13h4" }), jsx("path", { d: "M10 17h4" })] }), 'ReportIcon');
|
|
819
|
+
/** Gear, for settings and configuration. */
|
|
737
820
|
const SettingsIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" }), jsx("circle", { cx: "12", cy: "12", r: "3" })] }), 'SettingsIcon');
|
|
821
|
+
/** Short's Travel mark, for brand placements and app headers. */
|
|
738
822
|
const LogoIcon = createIcon(jsxs(Fragment, { children: [jsx("circle", { cx: "12", cy: "12", r: "10" }), jsx("path", { d: "M12 6v6l4 2" })] }), 'LogoIcon');
|
|
823
|
+
/** Rising trend line, for a metric moving up. */
|
|
739
824
|
const TrendUpIcon = createIcon(jsxs(Fragment, { children: [jsx("polyline", { points: "22 7 13.5 15.5 8.5 10.5 2 17" }), jsx("polyline", { points: "16 7 22 7 22 13" })] }), 'TrendUpIcon');
|
|
825
|
+
/** Falling trend line, for a metric moving down. */
|
|
740
826
|
const TrendDownIcon = createIcon(jsxs(Fragment, { children: [jsx("polyline", { points: "22 17 13.5 8.5 8.5 13.5 2 7" }), jsx("polyline", { points: "16 17 22 17 22 11" })] }), 'TrendDownIcon');
|
|
827
|
+
/** Information, for help text and info banners. */
|
|
741
828
|
const InfoIcon$1 = createIcon(jsxs(Fragment, { children: [jsx("circle", { cx: "12", cy: "12", r: "10" }), jsx("path", { d: "M12 16v-4" }), jsx("path", { d: "M12 8h.01" })] }), 'InfoIcon');
|
|
829
|
+
/** Document, for itineraries, invoices, and attachments. */
|
|
742
830
|
const DocumentIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z" }), jsx("path", { d: "M14 2v6h6" }), jsx("path", { d: "M16 13H8" }), jsx("path", { d: "M16 17H8" })] }), 'DocumentIcon');
|
|
831
|
+
/** Building, for schools, venues, and vendor offices. */
|
|
743
832
|
const BuildingIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M6 22V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v18Z" }), jsx("path", { d: "M6 12H4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2" }), jsx("path", { d: "M18 9h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-2" }), jsx("path", { d: "M10 6h4" }), jsx("path", { d: "M10 10h4" }), jsx("path", { d: "M10 14h4" }), jsx("path", { d: "M10 18h4" })] }), 'BuildingIcon');
|
|
833
|
+
/** Grid, for switching to a card or tile layout. */
|
|
744
834
|
const GridIcon = createIcon(jsxs(Fragment, { children: [jsx("rect", { width: "7", height: "7", x: "3", y: "3", rx: "1" }), jsx("rect", { width: "7", height: "7", x: "14", y: "3", rx: "1" }), jsx("rect", { width: "7", height: "7", x: "14", y: "14", rx: "1" }), jsx("rect", { width: "7", height: "7", x: "3", y: "14", rx: "1" })] }), 'GridIcon');
|
|
835
|
+
/** Pencil, for edit actions. */
|
|
745
836
|
const EditIcon$2 = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" }), jsx("path", { d: "m15 5 4 4" })] }), 'EditIcon');
|
|
837
|
+
/** House, for the home destination. */
|
|
746
838
|
const HomeIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "m3 11 9-8 9 8" }), jsx("path", { d: "M5 10v10h14V10" }), jsx("path", { d: "M9 20v-6h6v6" })] }), 'HomeIcon');
|
|
839
|
+
/** Cube, for packages, equipment, and bundled services. */
|
|
747
840
|
const CubeIcon = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "m21 16-9 5-9-5V8l9-5 9 5z" }), jsx("path", { d: "m3.3 7 8.7 5 8.7-5" }), jsx("path", { d: "M12 22V12" })] }), 'CubeIcon');
|
|
841
|
+
/** Padlock, for restricted access and locked records. */
|
|
748
842
|
const LockIcon$1 = createIcon(jsxs(Fragment, { children: [jsx("rect", { width: "18", height: "11", x: "3", y: "11", rx: "2" }), jsx("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })] }), 'LockIcon');
|
|
843
|
+
/** Trash can, for delete actions. */
|
|
749
844
|
const TrashIcon$2 = createIcon(jsxs(Fragment, { children: [jsx("path", { d: "M3 6h18" }), jsx("path", { d: "M8 6V4h8v2" }), jsx("path", { d: "m19 6-1 15H6L5 6" }), jsx("path", { d: "M10 11v5" }), jsx("path", { d: "M14 11v5" })] }), 'TrashIcon');
|
|
750
|
-
|
|
845
|
+
/**
|
|
846
|
+
* Every icon keyed by name, for choosing one at runtime.
|
|
847
|
+
*
|
|
848
|
+
* Use a direct import when the icon is known at author time; reach for this
|
|
849
|
+
* only when the name arrives as data (a nav config, an API response).
|
|
850
|
+
*/
|
|
751
851
|
const Icons = {
|
|
752
852
|
Plane: PlaneIcon$3,
|
|
753
853
|
Car: CarIcon$1,
|
|
@@ -806,6 +906,10 @@ const variantIcons$1 = {
|
|
|
806
906
|
warning: WarningIcon$1,
|
|
807
907
|
error: WarningIcon$1,
|
|
808
908
|
};
|
|
909
|
+
/**
|
|
910
|
+
* Inline message calling out status or guidance in place, without interrupting the user.
|
|
911
|
+
* Use a modal instead when the user has to act before continuing.
|
|
912
|
+
*/
|
|
809
913
|
const Alert = ({ variant = 'primary', title, children, dismissible = false, onDismiss, className = '', }) => {
|
|
810
914
|
const IconComponent = variantIcons$1[variant];
|
|
811
915
|
return (jsx("div", { className: `${styles$1I.alert} ${styles$1I[variant]} ${className}`, role: "alert", children: jsxs("div", { className: styles$1I.content, children: [jsx(IconComponent, { className: styles$1I.icon, size: 20 }), jsxs("div", { className: styles$1I.body, children: [title && jsx("h4", { className: styles$1I.title, children: title }), jsx("div", { className: styles$1I.message, children: children })] }), dismissible && onDismiss && (jsx("button", { type: "button", onClick: onDismiss, className: styles$1I.dismissButton, "aria-label": "Dismiss alert", children: jsx(CloseIcon, { size: 16 }) }))] }) }));
|
|
@@ -992,6 +1096,10 @@ const Avatar = ({ src, alt, initials, name, size = 'md', className = '', style,
|
|
|
992
1096
|
return (jsx("div", { className: className, "data-avatar-size": size, style: toInlineStyle(merge(getAvatarStyle(theme, size), style)), ...props, children: src ? (jsx("img", { src: src, alt: alt || name || 'Avatar', style: toInlineStyle(avatarImageStyle) })) : (jsx("span", { style: toInlineStyle(getAvatarInitialsStyle(theme)), children: displayInitials })) }));
|
|
993
1097
|
};
|
|
994
1098
|
Avatar.displayName = 'Avatar';
|
|
1099
|
+
/**
|
|
1100
|
+
* Row of overlapping avatars for a team or traveler party.
|
|
1101
|
+
* Collapses everything past `max` into a +N counter so the row keeps a fixed footprint.
|
|
1102
|
+
*/
|
|
995
1103
|
const AvatarGroup = ({ max = 4, className = '', children, style, ...props }) => {
|
|
996
1104
|
const { theme } = useTheme();
|
|
997
1105
|
const childArray = React.Children.toArray(children);
|
|
@@ -1010,6 +1118,7 @@ const badgeBaseStyle = (theme) => css({
|
|
|
1010
1118
|
alignItems: 'center',
|
|
1011
1119
|
gap: theme.spacing['1.5'],
|
|
1012
1120
|
borderRadius: theme.radius.full,
|
|
1121
|
+
fontFamily: theme.typography.fontFamily.label,
|
|
1013
1122
|
fontWeight: theme.typography.fontWeight.medium,
|
|
1014
1123
|
whiteSpace: 'nowrap',
|
|
1015
1124
|
});
|
|
@@ -1030,19 +1139,20 @@ const badgeVariantStyles = (theme) => ({
|
|
|
1030
1139
|
}),
|
|
1031
1140
|
success: css({
|
|
1032
1141
|
background: theme.colors.accent.forestLight,
|
|
1033
|
-
color: theme.colors.status.
|
|
1142
|
+
color: theme.colors.status.successInk,
|
|
1034
1143
|
}),
|
|
1035
1144
|
warning: css({
|
|
1036
1145
|
background: theme.colors.accent.tangerineLight,
|
|
1037
|
-
color: theme.colors.status.
|
|
1146
|
+
color: theme.colors.status.warningInk,
|
|
1038
1147
|
}),
|
|
1039
1148
|
error: css({
|
|
1040
1149
|
background: theme.colors.alert.error.bg,
|
|
1041
1150
|
color: theme.colors.status.error,
|
|
1042
1151
|
}),
|
|
1043
1152
|
info: css({
|
|
1153
|
+
// "New"-style badge reads clearly blue, distinct from the neutral-gray default
|
|
1044
1154
|
background: theme.colors.primary.primaryLight,
|
|
1045
|
-
color: theme.colors.primary.
|
|
1155
|
+
color: theme.colors.primary.primary,
|
|
1046
1156
|
}),
|
|
1047
1157
|
});
|
|
1048
1158
|
const badgeDotColors = (theme) => ({
|
|
@@ -1158,11 +1268,11 @@ const variantStyles = (theme) => ({
|
|
|
1158
1268
|
color: theme.colors.semantic.fg[1],
|
|
1159
1269
|
}),
|
|
1160
1270
|
danger: css({
|
|
1161
|
-
backgroundColor: theme.colors.status.
|
|
1271
|
+
backgroundColor: theme.colors.status.dangerAccentStrong,
|
|
1162
1272
|
color: 'white',
|
|
1163
1273
|
}),
|
|
1164
1274
|
dangerHover: css({
|
|
1165
|
-
backgroundColor:
|
|
1275
|
+
backgroundColor: theme.colors.status.dangerAccentStrongHover,
|
|
1166
1276
|
}),
|
|
1167
1277
|
// --------------------------------------------------------------------------
|
|
1168
1278
|
// Variants ported from Hub (frontend/src/styles/dynamic/Button.ts) so the
|
|
@@ -1244,7 +1354,8 @@ const squareStyles = (_theme) => ({
|
|
|
1244
1354
|
const baseButtonStyle = (theme) => merge(buttonReset, flexCenter, css({
|
|
1245
1355
|
gap: theme.spacing[2],
|
|
1246
1356
|
borderRadius: theme.radius.full,
|
|
1247
|
-
fontFamily: theme.typography.fontFamily.
|
|
1357
|
+
fontFamily: theme.typography.fontFamily.label,
|
|
1358
|
+
letterSpacing: '0.02em',
|
|
1248
1359
|
fontWeight: theme.typography.fontWeight.medium,
|
|
1249
1360
|
cursor: 'pointer',
|
|
1250
1361
|
transition: `all ${theme.transition.fast}`,
|
|
@@ -1273,8 +1384,9 @@ const activeStyle = css({
|
|
|
1273
1384
|
// FOCUS STYLES
|
|
1274
1385
|
// ============================================================================
|
|
1275
1386
|
const focusVisibleStyle = (theme) => css({
|
|
1276
|
-
outline: `2px solid ${theme.colors.
|
|
1387
|
+
outline: `2px solid ${theme.colors.accent.tealInk}`,
|
|
1277
1388
|
outlineOffset: '2px',
|
|
1389
|
+
boxShadow: `0 0 0 3px ${theme.colors.accent.tealGlow}`,
|
|
1278
1390
|
});
|
|
1279
1391
|
// ============================================================================
|
|
1280
1392
|
// SPINNER STYLES
|
|
@@ -1520,6 +1632,9 @@ const Input = forwardRef(({ size = 'md', label, helperText, error, leftIcon, rig
|
|
|
1520
1632
|
return (jsxs("div", { className: wrapperClasses, children: [label && (jsx("label", { htmlFor: inputId, className: styles$1E.label, children: label })), jsxs("div", { className: inputWrapperClasses, children: [leftIcon && jsx("span", { className: styles$1E.icon, children: leftIcon }), jsx("input", { ref: ref, id: inputId, className: styles$1E.input, disabled: disabled, "aria-invalid": !!error, "aria-describedby": error ? `${inputId}-error` : helperText ? `${inputId}-helper` : undefined, ...props }), rightIcon && jsx("span", { className: styles$1E.icon, children: rightIcon })] }), error && (jsx("span", { id: `${inputId}-error`, className: styles$1E.errorText, children: error })), helperText && !error && (jsx("span", { id: `${inputId}-helper`, className: styles$1E.helperText, children: helperText }))] }));
|
|
1521
1633
|
});
|
|
1522
1634
|
Input.displayName = 'Input';
|
|
1635
|
+
/**
|
|
1636
|
+
* Multi-line text field sharing the Input label, helper text, and error treatment.
|
|
1637
|
+
*/
|
|
1523
1638
|
const Textarea = forwardRef(({ size = 'md', label, helperText, error, fullWidth = false, className = '', id, disabled, rows = 4, ...props }, ref) => {
|
|
1524
1639
|
const textareaId = id || `textarea-${Math.random().toString(36).substr(2, 9)}`;
|
|
1525
1640
|
const wrapperClasses = [
|
|
@@ -1601,6 +1716,10 @@ Select.displayName = 'Select';
|
|
|
1601
1716
|
|
|
1602
1717
|
var styles$1B = {"spinner":"Spinner-module_spinner__OZwmB","svg":"Spinner-module_svg__Tusqk","spin":"Spinner-module_spin__YAPc9","track":"Spinner-module_track__NxLfV","indicator":"Spinner-module_indicator__gSUxF","xs":"Spinner-module_xs__4-WEg","sm":"Spinner-module_sm__enoDn","md":"Spinner-module_md__6axf9","lg":"Spinner-module_lg__EvJyC","xl":"Spinner-module_xl__yIXoK","srOnly":"Spinner-module_srOnly__WnZYf"};
|
|
1603
1718
|
|
|
1719
|
+
/**
|
|
1720
|
+
* Indeterminate loading indicator for waits with no known duration.
|
|
1721
|
+
* Exposes its label to screen readers, so give it one that says what is loading.
|
|
1722
|
+
*/
|
|
1604
1723
|
const Spinner = ({ size = 'md', className = '', color, label = 'Loading...', }) => {
|
|
1605
1724
|
return (jsxs("span", { className: `${styles$1B.spinner} ${styles$1B[size]} ${className}`, role: "status", "aria-label": label, style: color ? { color } : undefined, children: [jsxs("svg", { className: styles$1B.svg, xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [jsx("circle", { className: styles$1B.track, cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), jsx("path", { className: styles$1B.indicator, fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }), jsx("span", { className: styles$1B.srOnly, children: label })] }));
|
|
1606
1725
|
};
|
|
@@ -1608,7 +1727,7 @@ const Spinner = ({ size = 'md', className = '', color, label = 'Loading...', })
|
|
|
1608
1727
|
const statusVariantStyles = (theme) => ({
|
|
1609
1728
|
ticketed: css({
|
|
1610
1729
|
backgroundColor: theme.colors.accent.forestLight,
|
|
1611
|
-
color: theme.colors.status.
|
|
1730
|
+
color: theme.colors.status.successInk,
|
|
1612
1731
|
}),
|
|
1613
1732
|
itinerary: css({
|
|
1614
1733
|
backgroundColor: theme.colors.primary.primaryLight,
|
|
@@ -1616,7 +1735,7 @@ const statusVariantStyles = (theme) => ({
|
|
|
1616
1735
|
}),
|
|
1617
1736
|
'not-ticketed': css({
|
|
1618
1737
|
backgroundColor: theme.colors.accent.tangerineLight,
|
|
1619
|
-
color: theme.colors.status.
|
|
1738
|
+
color: theme.colors.status.warningInk,
|
|
1620
1739
|
}),
|
|
1621
1740
|
submitted: css({
|
|
1622
1741
|
backgroundColor: theme.colors.primary.primaryLight,
|
|
@@ -1650,6 +1769,7 @@ function getStatusBadgeStyle(theme, status) {
|
|
|
1650
1769
|
justifyContent: 'center',
|
|
1651
1770
|
padding: `${theme.spacing[1]} 10px`,
|
|
1652
1771
|
borderRadius: theme.radius.full,
|
|
1772
|
+
fontFamily: theme.typography.fontFamily.label,
|
|
1653
1773
|
fontSize: theme.typography.fontSize.xs,
|
|
1654
1774
|
fontWeight: theme.typography.fontWeight.semibold,
|
|
1655
1775
|
lineHeight: 1,
|
|
@@ -1669,6 +1789,10 @@ const statusLabels = {
|
|
|
1669
1789
|
rejected: 'Rejected',
|
|
1670
1790
|
'in-review': 'In Review',
|
|
1671
1791
|
};
|
|
1792
|
+
/**
|
|
1793
|
+
* Badge for a travel record status, styled per status so the same state always reads the same.
|
|
1794
|
+
* Falls back to a formatted version of the status code when no label is given.
|
|
1795
|
+
*/
|
|
1672
1796
|
const StatusBadge = ({ status, label, className = '', style, ...props }) => {
|
|
1673
1797
|
const { theme } = useTheme();
|
|
1674
1798
|
const displayLabel = label || statusLabels[status] || status;
|
|
@@ -1683,11 +1807,11 @@ const tagSizeStyles = {
|
|
|
1683
1807
|
function getTagVariantStyles(theme) {
|
|
1684
1808
|
return {
|
|
1685
1809
|
default: css({ backgroundColor: theme.colors.neutral.secondary, color: theme.colors.semantic.fg[2] }),
|
|
1686
|
-
primary: css({ backgroundColor:
|
|
1687
|
-
success: css({ backgroundColor:
|
|
1688
|
-
warning: css({ backgroundColor:
|
|
1689
|
-
error: css({ backgroundColor:
|
|
1690
|
-
info: css({ backgroundColor:
|
|
1810
|
+
primary: css({ backgroundColor: theme.colors.primary.primaryLight, color: theme.colors.primary.primary }),
|
|
1811
|
+
success: css({ backgroundColor: theme.colors.accent.forestLight, color: theme.colors.status.successInk }),
|
|
1812
|
+
warning: css({ backgroundColor: theme.colors.accent.tangerineLight, color: theme.colors.status.warningInk }),
|
|
1813
|
+
error: css({ backgroundColor: theme.colors.alert.error.bg, color: theme.colors.status.error }),
|
|
1814
|
+
info: css({ backgroundColor: theme.colors.primary.primaryLight, color: theme.colors.primary.primaryDark }),
|
|
1691
1815
|
// Deliberately paints nothing: `plain` exists so the tag can be used as a
|
|
1692
1816
|
// bare inline grouping element that takes its colour from its surroundings.
|
|
1693
1817
|
plain: css({ backgroundColor: 'transparent', color: 'inherit' }),
|
|
@@ -1699,12 +1823,13 @@ function getTagStyle(theme, variant, size, isClickable, isFocusVisible) {
|
|
|
1699
1823
|
alignItems: 'center',
|
|
1700
1824
|
gap: theme.spacing[1],
|
|
1701
1825
|
borderRadius: theme.radius.md,
|
|
1826
|
+
fontFamily: theme.typography.fontFamily.label,
|
|
1702
1827
|
fontWeight: theme.typography.fontWeight.medium,
|
|
1703
1828
|
lineHeight: 1,
|
|
1704
1829
|
whiteSpace: 'nowrap',
|
|
1705
1830
|
transition: `all ${theme.transition.fast}`,
|
|
1706
1831
|
cursor: isClickable ? 'pointer' : 'default',
|
|
1707
|
-
}), tagSizeStyles[size], getTagVariantStyles(theme)[variant], isFocusVisible && css({ outline: `2px solid ${theme.colors.
|
|
1832
|
+
}), tagSizeStyles[size], getTagVariantStyles(theme)[variant], isFocusVisible && css({ outline: `2px solid ${theme.colors.accent.tealInk}`, outlineOffset: '2px', boxShadow: `0 0 0 3px ${theme.colors.accent.tealGlow}` }));
|
|
1708
1833
|
}
|
|
1709
1834
|
const tagContentStyle = css({ display: 'inline-flex', alignItems: 'center', gap: '4px' });
|
|
1710
1835
|
function getRemoveButtonStyle(theme, isHovered) {
|
|
@@ -1731,6 +1856,10 @@ function getRemoveIconStyle(size) {
|
|
|
1731
1856
|
return removeIconSizeStyles[size];
|
|
1732
1857
|
}
|
|
1733
1858
|
|
|
1859
|
+
/**
|
|
1860
|
+
* Compact label for keywords, categories, and applied filters.
|
|
1861
|
+
* Becomes a button when clickable, and can carry a remove affordance.
|
|
1862
|
+
*/
|
|
1734
1863
|
const Tag = React.forwardRef(({ children, variant = 'default', size = 'md', removable = false, onRemove, onClick, className = '', style, }, ref) => {
|
|
1735
1864
|
const { theme } = useTheme();
|
|
1736
1865
|
const [isRemoveHovered, setIsRemoveHovered] = useState(false);
|
|
@@ -1800,11 +1929,14 @@ function getToggleStyle(theme, size, checked, disabled, isFocusVisible) {
|
|
|
1800
1929
|
width: config.width,
|
|
1801
1930
|
height: config.height,
|
|
1802
1931
|
borderRadius: theme.radius.full,
|
|
1803
|
-
|
|
1932
|
+
// Teal is the earned on-state for the switch (white thumb kept). The track
|
|
1933
|
+
// is a graphical indicator, held to the 3:1 UI bar (not the 4.5:1 text bar),
|
|
1934
|
+
// so tealInk (#009AAB, 3.10:1 on the #F5F5F5 page in light) clears it.
|
|
1935
|
+
backgroundColor: checked ? theme.colors.accent.tealInk : '#d1d5db',
|
|
1804
1936
|
transition: `background-color ${theme.transition.fast}`,
|
|
1805
1937
|
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
1806
1938
|
opacity: disabled ? 0.5 : 1,
|
|
1807
|
-
}), isFocusVisible && css({ outline: `2px solid ${theme.colors.
|
|
1939
|
+
}), isFocusVisible && css({ outline: `2px solid ${theme.colors.accent.tealInk}`, outlineOffset: '2px', boxShadow: `0 0 0 3px ${theme.colors.accent.tealGlow}` }));
|
|
1808
1940
|
}
|
|
1809
1941
|
function getToggleThumbStyle(theme, size, checked) {
|
|
1810
1942
|
const config = toggleSizeConfigs[size];
|
|
@@ -1859,6 +1991,10 @@ const toggleHiddenInputStyle = css({
|
|
|
1859
1991
|
border: 0,
|
|
1860
1992
|
});
|
|
1861
1993
|
|
|
1994
|
+
/**
|
|
1995
|
+
* Switch for a setting that applies immediately, with no separate save step.
|
|
1996
|
+
* Use a checkbox instead when the change is submitted with a form.
|
|
1997
|
+
*/
|
|
1862
1998
|
const Toggle = ({ checked, onChange, disabled = false, size = 'md', label, labelPosition = 'right', className = '', 'aria-label': ariaLabel, name, id, wrapperClassName = '', disabledIcon, }) => {
|
|
1863
1999
|
const { theme } = useTheme();
|
|
1864
2000
|
const [isFocusVisible, setIsFocusVisible] = useState(false);
|
|
@@ -1889,6 +2025,10 @@ const Toggle = ({ checked, onChange, disabled = false, size = 'md', label, label
|
|
|
1889
2025
|
|
|
1890
2026
|
var styles$1y = {"wrapper":"Tooltip-module_wrapper__9SUwl","tooltip":"Tooltip-module_tooltip__KQ7km","fadeIn":"Tooltip-module_fadeIn__dL8S5","content":"Tooltip-module_content__kO8yx","dark":"Tooltip-module_dark__Y66ss","light":"Tooltip-module_light__mItfR","semantic":"Tooltip-module_semantic__shhec","primary":"Tooltip-module_primary__no1LJ","secondary":"Tooltip-module_secondary__HEoKK","success":"Tooltip-module_success__EG2f-","warning":"Tooltip-module_warning__1zoqE","error":"Tooltip-module_error__Nn6y6","top":"Tooltip-module_top__1jrIn","bottom":"Tooltip-module_bottom__99YBc","left":"Tooltip-module_left__ZNd1H","right":"Tooltip-module_right__r0j5Q","arrow":"Tooltip-module_arrow__qcKWx","arrowTop":"Tooltip-module_arrowTop__k13dt","arrowBottom":"Tooltip-module_arrowBottom__FP-w2","arrowLeft":"Tooltip-module_arrowLeft__7T1uO","arrowRight":"Tooltip-module_arrowRight__FbPdB"};
|
|
1891
2027
|
|
|
2028
|
+
/**
|
|
2029
|
+
* Hover and focus label for a control whose purpose is not obvious from its face.
|
|
2030
|
+
* Supplementary only -- never put information here that a user must have.
|
|
2031
|
+
*/
|
|
1892
2032
|
const Tooltip = ({ content, children, position = 'top', variant = 'dark', delay = 200, disabled = false, className = '', }) => {
|
|
1893
2033
|
const [isVisible, setIsVisible] = useState(false);
|
|
1894
2034
|
const [actualPosition, setActualPosition] = useState(position);
|
|
@@ -2041,6 +2181,10 @@ const typeIcons$1 = {
|
|
|
2041
2181
|
B: (jsx("path", { d: "M4 16c0 .88.39 1.67 1 2.22V20c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1h8v1c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1.78c.61-.55 1-1.34 1-2.22V6c0-3.5-3.58-4-8-4s-8 .5-8 4v10zm3.5 1c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm9 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm1.5-6H6V6h12v5z" })),
|
|
2042
2182
|
U: (jsx("path", { d: "M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z" })),
|
|
2043
2183
|
};
|
|
2184
|
+
/**
|
|
2185
|
+
* Segment icon that identifies the vendor as well as the travel type.
|
|
2186
|
+
* Shows the vendor mark when one is known, and can flag a multi-segment leg.
|
|
2187
|
+
*/
|
|
2044
2188
|
const TravelServiceIcon = ({ type, vendor, mode = 'icon', size = 28, multi = false, className = '', style, onMouseEnter, onMouseLeave, ...props }) => {
|
|
2045
2189
|
const { theme } = useTheme();
|
|
2046
2190
|
const [isHovered, setIsHovered] = useState(false);
|
|
@@ -2102,6 +2246,10 @@ const typeIcons = {
|
|
|
2102
2246
|
B: (jsx("path", { d: "M4 16c0 .88.39 1.67 1 2.22V20c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1h8v1c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1.78c.61-.55 1-1.34 1-2.22V6c0-3.5-3.58-4-8-4s-8 .5-8 4v10zm3.5 1c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm9 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm1.5-6H6V6h12v5z" })),
|
|
2103
2247
|
U: (jsx("path", { d: "M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z" })),
|
|
2104
2248
|
};
|
|
2249
|
+
/**
|
|
2250
|
+
* Segment icon keyed to a travel type code, color-coded per type.
|
|
2251
|
+
* Use TravelServiceIcon when the vendor matters as well as the type.
|
|
2252
|
+
*/
|
|
2105
2253
|
const TypeIcon = ({ type, size = 18, showTooltip = true, className = '', style, onMouseEnter, onMouseLeave, ...props }) => {
|
|
2106
2254
|
const { theme } = useTheme();
|
|
2107
2255
|
const [isHovered, setIsHovered] = useState(false);
|
|
@@ -2140,6 +2288,10 @@ Accordion.displayName = 'Accordion';
|
|
|
2140
2288
|
var styles$1w = {"selector":"CalendarSelectors-module_selector__1nDos","item":"CalendarSelectors-module_item__CoR5s","active":"CalendarSelectors-module_active__u4w6Z","sm":"CalendarSelectors-module_sm__ju5t-","withLabel":"CalendarSelectors-module_withLabel__Jr9Re","md":"CalendarSelectors-module_md__a-U38","lg":"CalendarSelectors-module_lg__WHvAF","iconOnly":"CalendarSelectors-module_iconOnly__cAjyD"};
|
|
2141
2289
|
|
|
2142
2290
|
const ListIcon = () => (jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: [jsx("line", { x1: "8", y1: "6", x2: "21", y2: "6" }), jsx("line", { x1: "8", y1: "12", x2: "21", y2: "12" }), jsx("line", { x1: "8", y1: "18", x2: "21", y2: "18" }), jsx("circle", { cx: "3", cy: "6", r: "1", fill: "currentColor", stroke: "none" }), jsx("circle", { cx: "3", cy: "12", r: "1", fill: "currentColor", stroke: "none" }), jsx("circle", { cx: "3", cy: "18", r: "1", fill: "currentColor", stroke: "none" })] }));
|
|
2291
|
+
/**
|
|
2292
|
+
* Single-select control rendering its options as one connected row of buttons.
|
|
2293
|
+
* Backs the calendar selectors below; use those when their options fit.
|
|
2294
|
+
*/
|
|
2143
2295
|
const SegmentedSelector = ({ options, value, onChange, disabled = false, size = 'md', className = '', ariaLabel = 'View options', dataTest, itemClassName = '', activeItemClassName = '', iconPosition = 'left', }) => (jsx("div", { className: [styles$1w.selector, className].filter(Boolean).join(' '), role: "group", "aria-label": ariaLabel, "data-test": dataTest, children: options.map((option) => {
|
|
2144
2296
|
const active = option.id === value;
|
|
2145
2297
|
const accessibleName = option.alt ?? option.label ?? option.id;
|
|
@@ -2152,11 +2304,17 @@ const SegmentedSelector = ({ options, value, onChange, disabled = false, size =
|
|
|
2152
2304
|
active ? activeItemClassName : '',
|
|
2153
2305
|
].filter(Boolean).join(' '), onClick: () => onChange?.(option.id), children: [iconPosition === 'left' && option.icon, option.label && jsx("span", { children: option.label }), iconPosition === 'right' && option.icon] }, option.id));
|
|
2154
2306
|
}) }));
|
|
2307
|
+
/**
|
|
2308
|
+
* Chooses how the team travel calendar lays out: calendar grid, cards, or list.
|
|
2309
|
+
*/
|
|
2155
2310
|
const CalendarViewSelector = ({ value, onChange, ...props }) => (jsx(SegmentedSelector, { ...props, ariaLabel: "Calendar view", dataTest: "calendar-view-selector", value: value, onChange: (nextValue) => onChange?.(nextValue), options: [
|
|
2156
2311
|
{ id: 'calendar', alt: 'Calendar', icon: jsx(CalendarIcon$1, { size: 20 }) },
|
|
2157
2312
|
{ id: 'card', alt: 'Card', icon: jsx(GridIcon, { size: 20 }) },
|
|
2158
2313
|
{ id: 'list', alt: 'List', icon: jsx(ListIcon, {}) },
|
|
2159
2314
|
] }));
|
|
2315
|
+
/**
|
|
2316
|
+
* Chooses what the team travel calendar plots -- trips or due dates.
|
|
2317
|
+
*/
|
|
2160
2318
|
const CalendarTypeSelector = ({ value, onChange, ...props }) => (jsx(SegmentedSelector, { ...props, ariaLabel: "Calendar item type", dataTest: "calendar-type-selector", value: value, onChange: (nextValue) => onChange?.(nextValue), options: [
|
|
2161
2319
|
{ id: 'trips', label: 'Trips' },
|
|
2162
2320
|
{ id: 'due_dates', label: 'Due Dates' },
|
|
@@ -2211,6 +2369,10 @@ DetailList.displayName = 'DetailList';
|
|
|
2211
2369
|
|
|
2212
2370
|
var styles$1t = {"dropdown":"Dropdown-module_dropdown__K4-yz","arrow":"Dropdown-module_arrow__2Xuwf","arrowOpen":"Dropdown-module_arrowOpen__5g2iY","menu":"Dropdown-module_menu__dCgm8","menuOpen":"Dropdown-module_menuOpen__-IXFR","left":"Dropdown-module_left__tnNcS","center":"Dropdown-module_center__s9zhj","right":"Dropdown-module_right__s71gz","item":"Dropdown-module_item__R008o","itemDisabled":"Dropdown-module_itemDisabled__XIuNm","itemIcon":"Dropdown-module_itemIcon__DbSnD"};
|
|
2213
2371
|
|
|
2372
|
+
/**
|
|
2373
|
+
* Button that reveals a menu of actions, closing on outside click or Escape.
|
|
2374
|
+
* Compose the menu from DropdownItem; for choosing a value, use Segment or FilterChip instead.
|
|
2375
|
+
*/
|
|
2214
2376
|
const Dropdown = ({ label, children, alignment = 'left', width, className = '', disabled = false, trigger, }) => {
|
|
2215
2377
|
const [isOpen, setIsOpen] = useState(false);
|
|
2216
2378
|
const dropdownRef = useRef(null);
|
|
@@ -2280,6 +2442,10 @@ FileUploadButton.displayName = 'FileUploadButton';
|
|
|
2280
2442
|
|
|
2281
2443
|
var styles$1p = {"wrapper":"FilterChip-module_wrapper__YDRSW","chip":"FilterChip-module_chip__pF7K5","open":"FilterChip-module_open__EYBp7","active":"FilterChip-module_active__JEkku","label":"FilterChip-module_label__tRr-y","value":"FilterChip-module_value__0EcVu","chevron":"FilterChip-module_chevron__kh13z","rotated":"FilterChip-module_rotated__U-FzI","dropdown":"FilterChip-module_dropdown__w3ytW","infoMessage":"FilterChip-module_infoMessage__0TzcA","searchWrapper":"FilterChip-module_searchWrapper__VHOSK","searchIcon":"FilterChip-module_searchIcon__jJ2K-","searchInput":"FilterChip-module_searchInput__FqwvR","optionsList":"FilterChip-module_optionsList__P0dgd","option":"FilterChip-module_option__DMuqM","selected":"FilterChip-module_selected__ltt9Y","noResults":"FilterChip-module_noResults__QGNao"};
|
|
2282
2444
|
|
|
2445
|
+
/**
|
|
2446
|
+
* Compact single-select filter showing its current value on the chip itself.
|
|
2447
|
+
* Can filter its own options when the list is long enough to need searching.
|
|
2448
|
+
*/
|
|
2283
2449
|
const FilterChip = ({ label, value, options, onChange, searchable = false, searchPlaceholder = 'Search...', infoMessage, disabled = false, className, }) => {
|
|
2284
2450
|
const [open, setOpen] = useState(false);
|
|
2285
2451
|
const [searchQuery, setSearchQuery] = useState('');
|
|
@@ -2327,6 +2493,11 @@ const FilterChip = ({ label, value, options, onChange, searchable = false, searc
|
|
|
2327
2493
|
|
|
2328
2494
|
var styles$1o = {"formField":"FormField-module_formField__VhLhK","label":"FormField-module_label__CNCs6","required":"FormField-module_required__HkPQf","inputElement":"FormField-module_inputElement__9uvGR","inputError":"FormField-module_inputError__xD7fk","helperText":"FormField-module_helperText__D99kd","errorText":"FormField-module_errorText__8mXAJ","visuallyHidden":"FormField-module_visuallyHidden__YQc7S"};
|
|
2329
2495
|
|
|
2496
|
+
/**
|
|
2497
|
+
* Pairs a labelled control with its helper text and error message, wiring up the
|
|
2498
|
+
* accessible associations between them.
|
|
2499
|
+
* Renders an Input or Textarea via `as`, or any control passed as children.
|
|
2500
|
+
*/
|
|
2330
2501
|
const FormField = forwardRef(({ label, helperText, error, required = false, hideLabel = false, className, as = 'input', inputProps, textareaProps, children, }, ref) => {
|
|
2331
2502
|
const generatedId = useId();
|
|
2332
2503
|
const inputId = inputProps?.id || textareaProps?.id || generatedId;
|
|
@@ -2467,6 +2638,10 @@ InfoTile.displayName = 'InfoTile';
|
|
|
2467
2638
|
|
|
2468
2639
|
var styles$1k = {"toggle":"ManifestViewToggle-module_toggle__sHnAd","lockedToggle":"ManifestViewToggle-module_lockedToggle__m70h9","tab":"ManifestViewToggle-module_tab__qcwg7","active":"ManifestViewToggle-module_active__ln3B8","locked":"ManifestViewToggle-module_locked__Udun8","lockedActive":"ManifestViewToggle-module_lockedActive__kYSaF","count":"ManifestViewToggle-module_count__M-8a8"};
|
|
2469
2640
|
|
|
2641
|
+
/**
|
|
2642
|
+
* Tabs switching a charter manifest between its passenger and equipment lists,
|
|
2643
|
+
* each showing its current count.
|
|
2644
|
+
*/
|
|
2470
2645
|
const ManifestViewToggle = ({ view, onView, paxCount, eqCount, locked, className = '', }) => {
|
|
2471
2646
|
const tabs = [
|
|
2472
2647
|
{ key: 'passengers', label: 'Passengers', count: paxCount, icon: UsersIcon$1 },
|
|
@@ -2631,6 +2806,11 @@ MultiUserSearch.displayName = 'MultiUserSearch';
|
|
|
2631
2806
|
|
|
2632
2807
|
var styles$1i = {"navItem":"NavItem-module_navItem__4PpZU","disabled":"NavItem-module_disabled__uYqez","default":"NavItem-module_default__VB92P","active":"NavItem-module_active__3bcnW","pill":"NavItem-module_pill__pn5gl","icon":"NavItem-module_icon__j9VQ5","label":"NavItem-module_label__3S3KY","sm":"NavItem-module_sm__1oeZI","md":"NavItem-module_md__ySO90","lg":"NavItem-module_lg__OmaBw","collapsed":"NavItem-module_collapsed__ciZ6-","iconSm":"NavItem-module_iconSm__UvWnu","iconMd":"NavItem-module_iconMd__uAMlQ","iconLg":"NavItem-module_iconLg__PFPKD","badge":"NavItem-module_badge__oP9u2"};
|
|
2633
2808
|
|
|
2809
|
+
/**
|
|
2810
|
+
* One destination in a navigation list, with an optional icon and badge.
|
|
2811
|
+
* Renders as a link when given `href`, otherwise as a button.
|
|
2812
|
+
* Collapses to icon-only, keeping its label available to screen readers.
|
|
2813
|
+
*/
|
|
2634
2814
|
const NavItem = ({ icon, label, active = false, collapsed = false, variant = 'default', size = 'md', badge, badgeVariant = 'default', onClick, disabled = false, href, external = false, className, 'aria-label': ariaLabel, }) => {
|
|
2635
2815
|
const content = (jsxs(Fragment, { children: [icon && jsx("span", { className: `${styles$1i.icon} ${styles$1i[`icon${size.charAt(0).toUpperCase()}${size.slice(1)}`]}`, "aria-hidden": "true", children: icon }), !collapsed && (jsx("span", { className: styles$1i.label, children: label })), badge !== undefined && !collapsed && (jsx(Badge, { variant: badgeVariant, className: styles$1i.badge, children: badge }))] }));
|
|
2636
2816
|
const classNames = [
|
|
@@ -2728,10 +2908,17 @@ const strokeWidths = {
|
|
|
2728
2908
|
md: 5,
|
|
2729
2909
|
lg: 6,
|
|
2730
2910
|
};
|
|
2911
|
+
/**
|
|
2912
|
+
* Horizontal bar for determinate progress -- a known percentage of a known total.
|
|
2913
|
+
* Use Spinner when the duration is unknown.
|
|
2914
|
+
*/
|
|
2731
2915
|
const ProgressBar = ({ value, max = 100, size = 'md', variant = 'primary', showLabel = false, className = '', }) => {
|
|
2732
2916
|
const percentage = Math.min(Math.max((value / max) * 100, 0), 100);
|
|
2733
2917
|
return (jsxs("div", { className: `${styles$1f.barContainer} ${styles$1f[`bar${size}`]} ${className}`, children: [jsx("div", { className: styles$1f.barTrack, children: jsx("div", { className: `${styles$1f.barFill} ${styles$1f[variant]}`, style: { width: `${percentage}%` }, role: "progressbar", "aria-valuenow": value, "aria-valuemin": 0, "aria-valuemax": max }) }), showLabel && (jsxs("span", { className: styles$1f.barLabel, children: [Math.round(percentage), "%"] }))] }));
|
|
2734
2918
|
};
|
|
2919
|
+
/**
|
|
2920
|
+
* Ring showing determinate progress, for tighter spaces than ProgressBar fits.
|
|
2921
|
+
*/
|
|
2735
2922
|
const ProgressCircle = ({ value, max = 100, size = 'md', variant = 'primary', showLabel = false, className = '', diameter, }) => {
|
|
2736
2923
|
const percentage = Math.min(Math.max((value / max) * 100, 0), 100);
|
|
2737
2924
|
const dimension = diameter ?? dimensions[size];
|
|
@@ -2744,6 +2931,9 @@ const ProgressCircle = ({ value, max = 100, size = 'md', variant = 'primary', sh
|
|
|
2744
2931
|
return (jsxs("div", { className: `${styles$1f.circleContainer} ${className}`, style: { width: dimension, height: dimension }, children: [jsxs("svg", { width: dimension, height: dimension, className: styles$1f.circleSvg, children: [jsx("circle", { className: styles$1f.circleTrack, cx: dimension / 2, cy: dimension / 2, r: radius, strokeWidth: strokeWidth, fill: "transparent" }), jsx("circle", { className: `${styles$1f.circleFill} ${styles$1f[variant]}`, cx: dimension / 2, cy: dimension / 2, r: radius, strokeWidth: strokeWidth, fill: "transparent", strokeDasharray: circumference, strokeDashoffset: strokeDashoffset, strokeLinecap: "round", role: "progressbar", "aria-valuenow": value, "aria-valuemin": 0, "aria-valuemax": max })] }), showLabel && (jsxs("span", { className: styles$1f.circleLabel, style: { fontSize: size === 'xs' ? '8px' : size === 'sm' ? '10px' : size === 'md' ? '12px' : '14px' }, children: [Math.round(percentage), "%"] }))] }));
|
|
2745
2932
|
};
|
|
2746
2933
|
// Combined export
|
|
2934
|
+
/**
|
|
2935
|
+
* Namespace bundling the progress indicators as `Progress.Bar` and `Progress.Circle`.
|
|
2936
|
+
*/
|
|
2747
2937
|
const Progress = {
|
|
2748
2938
|
Bar: ProgressBar,
|
|
2749
2939
|
Circle: ProgressCircle,
|
|
@@ -2775,6 +2965,11 @@ RosterToolbar.displayName = 'RosterToolbar';
|
|
|
2775
2965
|
|
|
2776
2966
|
var styles$1d = {"searchField":"SearchField-module_searchField__c7gUE","inputWrapper":"SearchField-module_inputWrapper__SUzHv","searchIcon":"SearchField-module_searchIcon__MOZ2m","input":"SearchField-module_input__abJcl","clearButton":"SearchField-module_clearButton__RMIg2","sm":"SearchField-module_sm__-sayT","lg":"SearchField-module_lg__QKacI"};
|
|
2777
2967
|
|
|
2968
|
+
/**
|
|
2969
|
+
* Search input with clear and submit affordances.
|
|
2970
|
+
* Works controlled via `value` or uncontrolled via `defaultValue`; `onChange` fires
|
|
2971
|
+
* per keystroke while `onSearch` fires only on submit.
|
|
2972
|
+
*/
|
|
2778
2973
|
const SearchField = forwardRef(({ placeholder = 'Search...', value, defaultValue = '', onChange, onSearch, onClear, size = 'md', disabled = false, showClear = true, showButton = true, className, id, 'aria-label': ariaLabel = 'Search', ...props }, ref) => {
|
|
2779
2974
|
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
2780
2975
|
const currentValue = value !== undefined ? value : internalValue;
|
|
@@ -2815,6 +3010,10 @@ const SchoolContactForm = ({ mode, createFromPortalUser, firstNameField, middleI
|
|
|
2815
3010
|
|
|
2816
3011
|
var styles$1b = {"segment":"Segment-module_segment__UF-SG","fullWidth":"Segment-module_fullWidth__Hi19i","option":"Segment-module_option__UJUhj","disabled":"Segment-module_disabled__CSxuQ","selected":"Segment-module_selected__gRnVj","sm":"Segment-module_sm__h8S7Z","md":"Segment-module_md__4uTae","lg":"Segment-module_lg__zL0Hv","icon":"Segment-module_icon__ZHRr6"};
|
|
2817
3012
|
|
|
3013
|
+
/**
|
|
3014
|
+
* Segmented control for picking one of a few options that are all worth showing.
|
|
3015
|
+
* Prefer a Dropdown once the list outgrows the available width.
|
|
3016
|
+
*/
|
|
2818
3017
|
const Segment = ({ options, value, onChange, size = 'md', fullWidth = false, className = '', 'aria-label': ariaLabel, }) => {
|
|
2819
3018
|
return (jsx("div", { className: `${styles$1b.segment} ${styles$1b[size]} ${fullWidth ? styles$1b.fullWidth : ''} ${className}`, role: "radiogroup", "aria-label": ariaLabel, children: options.map((option) => (jsxs("button", { type: "button", className: `${styles$1b.option} ${value === option.value ? styles$1b.selected : ''} ${option.disabled ? styles$1b.disabled : ''}`, onClick: () => !option.disabled && onChange(option.value), disabled: option.disabled, role: "radio", "aria-checked": value === option.value, children: [option.icon && jsx("span", { className: styles$1b.icon, children: option.icon }), option.label] }, option.value))) }));
|
|
2820
3019
|
};
|
|
@@ -2923,6 +3122,9 @@ ServiceToggleList.displayName = 'ServiceToggleList';
|
|
|
2923
3122
|
|
|
2924
3123
|
var styles$18 = {"toggle":"SupplierTypeToggle-module_toggle__x4pTJ","active":"SupplierTypeToggle-module_active__8BGSe"};
|
|
2925
3124
|
|
|
3125
|
+
/**
|
|
3126
|
+
* The selectable supplier types, without the "All" entry the toggle adds.
|
|
3127
|
+
*/
|
|
2926
3128
|
const SUPPLIER_TYPE_OPTIONS = [
|
|
2927
3129
|
{ value: 'A', label: 'Air' },
|
|
2928
3130
|
{ value: 'C', label: 'Car' },
|
|
@@ -2932,6 +3134,10 @@ const OPTIONS = [
|
|
|
2932
3134
|
{ value: '', label: 'All' },
|
|
2933
3135
|
...SUPPLIER_TYPE_OPTIONS,
|
|
2934
3136
|
];
|
|
3137
|
+
/**
|
|
3138
|
+
* Filters a supplier list down to air, car, or hotel.
|
|
3139
|
+
* Works controlled via `value` or uncontrolled via `defaultValue`.
|
|
3140
|
+
*/
|
|
2935
3141
|
const SupplierTypeToggle = ({ value, defaultValue = '', onChange, disabled = false, className = '', }) => {
|
|
2936
3142
|
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
2937
3143
|
const activeValue = value ?? internalValue;
|
|
@@ -3399,6 +3605,10 @@ Topbar.displayName = 'Topbar';
|
|
|
3399
3605
|
|
|
3400
3606
|
var styles$10 = {"appLayout":"AppLayout-module_appLayout__NFbZk","mainArea":"AppLayout-module_mainArea__t-6oq","content":"AppLayout-module_content__5kV7S"};
|
|
3401
3607
|
|
|
3608
|
+
/**
|
|
3609
|
+
* Generic page frame: sidebar, top bar, and content area.
|
|
3610
|
+
* Use HubAppShell for Hub screens -- it adds the Hub navigation and branding.
|
|
3611
|
+
*/
|
|
3402
3612
|
const AppLayout = ({ navItems = [], activeNavKey, logo, collapsedLogo, account, defaultExpanded = true, onNavItemClick, onAccountClick, children, navFooter, topbarActions, className, }) => {
|
|
3403
3613
|
return (jsxs("div", { className: `${styles$10.appLayout} ${className || ''}`, children: [jsx(Sidenav, { items: navItems, activeKey: activeNavKey, defaultExpanded: defaultExpanded, onItemClick: onNavItemClick, logo: logo, logoCollapsed: collapsedLogo, footer: navFooter }), jsxs("div", { className: styles$10.mainArea, children: [jsx(Topbar, { account: account, onAccountClick: onAccountClick, actions: topbarActions }), jsx("main", { className: styles$10.content, children: children })] })] }));
|
|
3404
3614
|
};
|
|
@@ -3421,16 +3631,25 @@ const Card = forwardRef(({ variant = 'default', padding = 'md', interactive = fa
|
|
|
3421
3631
|
return (jsx("div", { ref: ref, className: classNames, ...props, children: children }));
|
|
3422
3632
|
});
|
|
3423
3633
|
Card.displayName = 'Card';
|
|
3634
|
+
/**
|
|
3635
|
+
* Top of a Card: title, subtitle, and any header actions.
|
|
3636
|
+
*/
|
|
3424
3637
|
const CardHeader = ({ title, subtitle, actions, className = '', children, ...props }) => {
|
|
3425
3638
|
const classNames = [styles$$.header, className].filter(Boolean).join(' ');
|
|
3426
3639
|
return (jsxs("div", { className: classNames, ...props, children: [jsxs("div", { className: styles$$.headerContent, children: [title && jsx("h3", { className: styles$$.title, children: title }), subtitle && jsx("p", { className: styles$$.subtitle, children: subtitle }), children] }), actions && jsx("div", { className: styles$$.actions, children: actions })] }));
|
|
3427
3640
|
};
|
|
3428
3641
|
CardHeader.displayName = 'CardHeader';
|
|
3642
|
+
/**
|
|
3643
|
+
* Main content region of a Card, carrying the card padding.
|
|
3644
|
+
*/
|
|
3429
3645
|
const CardBody = ({ className = '', children, ...props }) => {
|
|
3430
3646
|
const classNames = [styles$$.body, className].filter(Boolean).join(' ');
|
|
3431
3647
|
return (jsx("div", { className: classNames, ...props, children: children }));
|
|
3432
3648
|
};
|
|
3433
3649
|
CardBody.displayName = 'CardBody';
|
|
3650
|
+
/**
|
|
3651
|
+
* Bottom of a Card, for actions and summary detail.
|
|
3652
|
+
*/
|
|
3434
3653
|
const CardFooter = ({ className = '', children, ...props }) => {
|
|
3435
3654
|
const classNames = [styles$$.footer, className].filter(Boolean).join(' ');
|
|
3436
3655
|
return (jsx("div", { className: classNames, ...props, children: children }));
|
|
@@ -3798,9 +4017,22 @@ ContactList.displayName = 'ContactList';
|
|
|
3798
4017
|
|
|
3799
4018
|
var styles$Y = {"container":"Drawer-module_container__hXuOY","backdrop":"Drawer-module_backdrop__MIipQ","fadeIn":"Drawer-module_fadeIn__QsuvQ","backdropOpen":"Drawer-module_backdropOpen__YpH--","drawer":"Drawer-module_drawer__EHbbs","right":"Drawer-module_right__x6P6Q","drawerOpen":"Drawer-module_drawerOpen__KTgFg","left":"Drawer-module_left__aVF9t","top":"Drawer-module_top__wuvhi","bottom":"Drawer-module_bottom__rt-VZ","sizeSm":"Drawer-module_sizeSm__LFrm3","sizeMd":"Drawer-module_sizeMd__A1QTQ","sizeLg":"Drawer-module_sizeLg__6laD8","sizeXl":"Drawer-module_sizeXl__FY9mZ","sizeFull":"Drawer-module_sizeFull__BGQ1q","header":"Drawer-module_header__MpR14","headerContent":"Drawer-module_headerContent__dFcLH","title":"Drawer-module_title__0AmOX","closeButton":"Drawer-module_closeButton__VuXsE","body":"Drawer-module_body__GLUGo","footer":"Drawer-module_footer__K5ekS"};
|
|
3800
4019
|
|
|
4020
|
+
/**
|
|
4021
|
+
* Top of a Drawer: title and the close affordance.
|
|
4022
|
+
*/
|
|
3801
4023
|
const DrawerHeader = ({ title, children, showClose = true, onClose, className = '', }) => (jsxs("div", { className: `${styles$Y.header} ${className}`, children: [jsxs("div", { className: styles$Y.headerContent, children: [title && jsx("h2", { className: styles$Y.title, children: title }), children] }), showClose && (jsx("button", { type: "button", className: styles$Y.closeButton, onClick: onClose, "aria-label": "Close drawer", children: jsx("svg", { width: "20", height: "20", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) }))] }));
|
|
4024
|
+
/**
|
|
4025
|
+
* Scrollable content region of a Drawer.
|
|
4026
|
+
*/
|
|
3802
4027
|
const DrawerBody = ({ children, className = '' }) => (jsx("div", { className: `${styles$Y.body} ${className}`, children: children }));
|
|
4028
|
+
/**
|
|
4029
|
+
* Bottom of a Drawer, for actions that stay visible while the body scrolls.
|
|
4030
|
+
*/
|
|
3803
4031
|
const DrawerFooter = ({ children, className = '' }) => (jsx("div", { className: `${styles$Y.footer} ${className}`, children: children }));
|
|
4032
|
+
/**
|
|
4033
|
+
* Panel sliding in from an edge for secondary work that keeps the page behind it
|
|
4034
|
+
* in context. Traps focus while open and closes on Escape or backdrop click.
|
|
4035
|
+
*/
|
|
3804
4036
|
const Drawer = ({ isOpen, onClose, position = 'right', size = 'md', children, closeOnBackdropClick = true, closeOnEscape = true, showBackdrop = true, className = '', }) => {
|
|
3805
4037
|
const handleEscape = useCallback((e) => {
|
|
3806
4038
|
if (closeOnEscape && e.key === 'Escape') {
|
|
@@ -3843,6 +4075,11 @@ Drawer.Footer = DrawerFooter;
|
|
|
3843
4075
|
|
|
3844
4076
|
var styles$X = {"drawer":"DueDatesDrawer-module_drawer__TqC4Q","open":"DueDatesDrawer-module_open__Yblf3","body":"DueDatesDrawer-module_body__OwwF-","search":"DueDatesDrawer-module_search__g7-Rl","cards":"DueDatesDrawer-module_cards__bFG90","empty":"DueDatesDrawer-module_empty__K2ULN","card":"DueDatesDrawer-module_card__4Os-5","cardTitle":"DueDatesDrawer-module_cardTitle__fU-cP","status":"DueDatesDrawer-module_status__dXifz","completed":"DueDatesDrawer-module_completed__jWoYi","pastDue":"DueDatesDrawer-module_pastDue__TSikC","tags":"DueDatesDrawer-module_tags__8P87y","completion":"DueDatesDrawer-module_completion__mIrWm","readOnlyStatus":"DueDatesDrawer-module_readOnlyStatus__23fdg"};
|
|
3845
4077
|
|
|
4078
|
+
/**
|
|
4079
|
+
* Whether a task counts as done.
|
|
4080
|
+
* Treats a completion timestamp as authoritative, since the source systems do not
|
|
4081
|
+
* always write the status text back.
|
|
4082
|
+
*/
|
|
3846
4083
|
const isTravelDueDateCompleted = (item) => item.status.trim().toLowerCase() === 'completed' || !!item.completeddatetime;
|
|
3847
4084
|
const isTravelDueDateOverdue = (item) => !item.completeddatetime && !!item.pastdue;
|
|
3848
4085
|
const parseLocalDate$1 = (value) => {
|
|
@@ -3955,9 +4192,15 @@ GridTable.displayName = 'GridTable';
|
|
|
3955
4192
|
|
|
3956
4193
|
var styles$V = {"shell":"HubAppShell-module_shell__Y13Fo","main":"HubAppShell-module_main__OvnjA","beta":"HubAppShell-module_beta__V8Dzh","sidebar":"HubAppShell-module_sidebar__73gt6","shellExpanded":"HubAppShell-module_shellExpanded__z9cLL","expandButton":"HubAppShell-module_expandButton__hyYi-","logo":"HubAppShell-module_logo__iylLM","defaultLogo":"HubAppShell-module_defaultLogo__tVCz-","desktopNav":"HubAppShell-module_desktopNav__-ZRGD","navItem":"HubAppShell-module_navItem__FKkXN","active":"HubAppShell-module_active__zu1-B","navIcon":"HubAppShell-module_navIcon__QRImh","disabledNav":"HubAppShell-module_disabledNav__zj07n","sidebarFooter":"HubAppShell-module_sidebarFooter__kA2bq","profile":"HubAppShell-module_profile__JCGL5","avatar":"HubAppShell-module_avatar__V-lFG","profileMenu":"HubAppShell-module_profileMenu__qqWSu","topbar":"HubAppShell-module_topbar__U4w0A","defaultAccount":"HubAppShell-module_defaultAccount__3vohz","defaultActions":"HubAppShell-module_defaultActions__wAEJb","mobileActions":"HubAppShell-module_mobileActions__W6Rf9","content":"HubAppShell-module_content__yCgGs","contentDisabled":"HubAppShell-module_contentDisabled__btmCY","mobileNav":"HubAppShell-module_mobileNav__X0zBs","mobileNavItem":"HubAppShell-module_mobileNavItem__1x94j","mobileExtras":"HubAppShell-module_mobileExtras__xo3qI","mobilePrimary":"HubAppShell-module_mobilePrimary__p5PCn","mobileFooter":"HubAppShell-module_mobileFooter__QvsE-","loading":"HubAppShell-module_loading__V8RiG"};
|
|
3957
4194
|
|
|
4195
|
+
/**
|
|
4196
|
+
* Individual Travel entry, kept separate because not every account has it.
|
|
4197
|
+
*/
|
|
3958
4198
|
const HUB_INDIVIDUAL_TRAVEL_ITEM = { key: 'individual-travel', label: 'Individual Travel', path: '/individual-travel', icon: jsx(UserIcon, { size: 24 }) };
|
|
3959
4199
|
/** Canonical navigation identity for the carrier-facing STM Charters portal. */
|
|
3960
4200
|
const HUB_STM_CHARTERS_ITEM = { key: 'stm-charters', label: 'STM Charters', path: '/stm-charters', icon: jsx(PlaneIcon$3, { size: 24 }) };
|
|
4201
|
+
/**
|
|
4202
|
+
* The default primary navigation, in display order.
|
|
4203
|
+
*/
|
|
3961
4204
|
const HUB_NAV_ITEMS = [
|
|
3962
4205
|
{ key: 'home', label: 'Home', path: '/home', icon: jsx(HomeIcon, { size: 24 }) },
|
|
3963
4206
|
{ key: 'team-travel-calendar', label: 'Team Travel Calendar', path: '/team-travel-calendar', icon: jsx(CalendarIcon$1, { size: 24 }) },
|
|
@@ -3965,7 +4208,13 @@ const HUB_NAV_ITEMS = [
|
|
|
3965
4208
|
{ key: 'team-management', label: 'Team Management', path: '/team-management', icon: jsx(UsersIcon$1, { size: 24 }) },
|
|
3966
4209
|
HUB_STM_CHARTERS_ITEM,
|
|
3967
4210
|
];
|
|
4211
|
+
/**
|
|
4212
|
+
* Administration entry, shown in the footer to admins.
|
|
4213
|
+
*/
|
|
3968
4214
|
const HUB_ADMIN_ITEM = { key: 'administration', label: 'Administration', path: '/administration', icon: jsx(SettingsIcon, { size: 24 }) };
|
|
4215
|
+
/**
|
|
4216
|
+
* Agent workspace entry, shown in the footer to admins.
|
|
4217
|
+
*/
|
|
3969
4218
|
const HUB_AGENTS_ITEM = { key: 'agents', label: 'Agents', path: '/agents', icon: jsx(HeadsetIcon, { size: 24 }) };
|
|
3970
4219
|
/**
|
|
3971
4220
|
* Sourcing sits with the admin-gated footer items rather than in `HUB_NAV_ITEMS`: the
|
|
@@ -4367,6 +4616,11 @@ const ManifestCapacityStats = ({ paxCount, seats, paxWeight, cargoWeight, payloa
|
|
|
4367
4616
|
|
|
4368
4617
|
var styles$Q = {"overlay":"Modal-module_overlay__n7Paz","fadeIn":"Modal-module_fadeIn__upWKg","modal":"Modal-module_modal__YZQ-K","slideIn":"Modal-module_slideIn__mtAFr","sm":"Modal-module_sm__QSWSJ","md":"Modal-module_md__6t9J8","lg":"Modal-module_lg__5r3uQ","xl":"Modal-module_xl__JPpjn","full":"Modal-module_full__y9leS","header":"Modal-module_header__xTw6j","title":"Modal-module_title__KvPHy","closeButton":"Modal-module_closeButton__JoRui","body":"Modal-module_body__K3swC","footer":"Modal-module_footer__Z1UcB","footerButtons":"Modal-module_footerButtons__u-Ayv","confirmMessage":"Modal-module_confirmMessage__ZlKV8"};
|
|
4369
4618
|
|
|
4619
|
+
/**
|
|
4620
|
+
* Dialog that interrupts the page until the user resolves it.
|
|
4621
|
+
* Traps focus, closes on Escape, and restores focus to the trigger on close.
|
|
4622
|
+
* Use an Alert instead when the user does not have to act.
|
|
4623
|
+
*/
|
|
4370
4624
|
const Modal = ({ isOpen, onClose, title, children, size = 'md', showCloseButton = true, closeOnBackdropClick = true, closeOnEscape = true, footer, className = '', }) => {
|
|
4371
4625
|
const handleEscape = useCallback((e) => {
|
|
4372
4626
|
if (closeOnEscape && e.key === 'Escape') {
|
|
@@ -4392,7 +4646,14 @@ const Modal = ({ isOpen, onClose, title, children, size = 'md', showCloseButton
|
|
|
4392
4646
|
return null;
|
|
4393
4647
|
return (jsx("div", { className: styles$Q.overlay, onClick: handleBackdropClick, children: jsxs("div", { className: `${styles$Q.modal} ${styles$Q[size]} ${className}`, role: "dialog", "aria-modal": "true", "aria-labelledby": title ? 'modal-title' : undefined, children: [(title || showCloseButton) && (jsxs("div", { className: styles$Q.header, children: [title && (jsx("h2", { id: "modal-title", className: styles$Q.title, children: title })), showCloseButton && (jsx("button", { type: "button", className: styles$Q.closeButton, onClick: onClose, "aria-label": "Close modal", children: jsx("svg", { width: "20", height: "20", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) }))] })), jsx("div", { className: styles$Q.body, children: children }), footer && jsx("div", { className: styles$Q.footer, children: footer })] }) }));
|
|
4394
4648
|
};
|
|
4649
|
+
/**
|
|
4650
|
+
* Action row for the bottom of a Modal, keeping button order consistent across dialogs.
|
|
4651
|
+
*/
|
|
4395
4652
|
const ModalFooter = ({ children, className = '' }) => (jsx("div", { className: `${styles$Q.footerButtons} ${className}`, children: children }));
|
|
4653
|
+
/**
|
|
4654
|
+
* Modal preset for confirming a single action, with the confirm and cancel
|
|
4655
|
+
* buttons already wired.
|
|
4656
|
+
*/
|
|
4396
4657
|
const ConfirmModal = ({ message, confirmText = 'Confirm', cancelText = 'Cancel', onConfirm, onClose, destructive = false, loading = false, ...props }) => (jsx(Modal, { ...props, onClose: onClose, size: "sm", footer: jsxs(ModalFooter, { children: [jsx(Button, { variant: "secondary", onClick: onClose, children: cancelText }), jsx(Button, { variant: destructive ? 'danger' : 'primary', onClick: onConfirm, disabled: loading, children: loading ? 'Loading...' : confirmText })] }), children: jsx("div", { className: styles$Q.confirmMessage, children: message }) }));
|
|
4397
4658
|
|
|
4398
4659
|
var styles$P = {"module":"Module-module_module__1Lglz","header":"Module-module_header__-qP6m","closed":"Module-module_closed__J5FYJ","sm":"Module-module_sm__g-iVI","md":"Module-module_md__zmKQE","lg":"Module-module_lg__5uVgV","titleRow":"Module-module_titleRow__3upJc","icon":"Module-module_icon__MXVy7","iconSpaced":"Module-module_iconSpaced__O8F0i","title":"Module-module_title__Qdyv0","badge":"Module-module_badge__zoNEC","tools":"Module-module_tools__w6Z1b","toggleBtn":"Module-module_toggleBtn__VxH2u","bodyWrapper":"Module-module_bodyWrapper__IogVT","body":"Module-module_body__O9n9B","hidden":"Module-module_hidden__mmUYg","footer":"Module-module_footer__hrUY9","divider":"Module-module_divider__YQKdf","dark":"Module-module_dark__w8Fb-","verticalDivider":"Module-module_verticalDivider__t3g-3"};
|
|
@@ -4438,6 +4699,9 @@ const decodeEntities = (value) => {
|
|
|
4438
4699
|
element.innerHTML = value;
|
|
4439
4700
|
return element.value;
|
|
4440
4701
|
};
|
|
4702
|
+
/**
|
|
4703
|
+
* Stacked notices for the top of a page: platform notices first, then travel alerts.
|
|
4704
|
+
*/
|
|
4441
4705
|
const PageBanners = ({ systemBanners, alertBanners, className = '', }) => {
|
|
4442
4706
|
const [dismissed, setDismissed] = useState(new Set());
|
|
4443
4707
|
const previousSystem = useRef(systemBanners);
|
|
@@ -4828,6 +5092,9 @@ RegularSeasonBidsTable.displayName = 'RegularSeasonBidsTable';
|
|
|
4828
5092
|
|
|
4829
5093
|
var styles$H = {"wrapper":"Table-module_wrapper__1klo5","table":"Table-module_table__fkuUB","header":"Table-module_header__vRy6j","headerCell":"Table-module_headerCell__2KzYn","headerContent":"Table-module_headerContent__HPl8-","sortable":"Table-module_sortable__NiS6E","sortIcon":"Table-module_sortIcon__Fy6z7","body":"Table-module_body__Wt52U","row":"Table-module_row__4GEgX","cell":"Table-module_cell__Xr-7H","selectCell":"Table-module_selectCell__lJC7I","selected":"Table-module_selected__a-Gft","striped":"Table-module_striped__6TMF-","hoverable":"Table-module_hoverable__KN5Fp","alignLeft":"Table-module_alignLeft__FtI9E","alignCenter":"Table-module_alignCenter__p8Tr8","alignRight":"Table-module_alignRight__Ca7Yr","bordered":"Table-module_bordered__9bM3L","compact":"Table-module_compact__opzS-","clickable":"Table-module_clickable__2ummV","loading":"Table-module_loading__tFELE","empty":"Table-module_empty__urRiw","pulse":"Table-module_pulse__t32v9"};
|
|
4830
5094
|
|
|
5095
|
+
/**
|
|
5096
|
+
* Data table with sorting, selection, and empty and loading states.
|
|
5097
|
+
*/
|
|
4831
5098
|
const Table = ({ columns, data, rowKey = 'id', bordered = false, striped = false, hoverable = true, compact = false, loading = false, emptyMessage = 'No data available', emptyContent, selectable = false, selectedRowKeys, defaultSelectedRowKeys = [], onSelectionChange, isRowSelectable, rowSelectionLabel, selectAllLabel = 'Select all rows', onRowClick, className = '', }) => {
|
|
4832
5099
|
const [sortColumn, setSortColumn] = useState(null);
|
|
4833
5100
|
const [sortDirection, setSortDirection] = useState('asc');
|
|
@@ -5111,6 +5378,10 @@ const ContactPicker = ({ title, contacts, selectedId, onSelect, allowNone = true
|
|
|
5111
5378
|
};
|
|
5112
5379
|
return (jsxs("div", { className: styles$E.picker, ref: containerRef, "data-test": dataTestId, children: [jsx("div", { className: styles$E.fieldLabel, children: title }), jsxs("div", { className: [styles$E.contactSegment, compact ? styles$E.compactSegment : ''].filter(Boolean).join(' '), children: [!compact && selected && jsx(Avatar, { className: styles$E.contactAvatar, name: selected.name, size: "sm" }), jsxs("div", { className: styles$E.contactDetails, children: [jsxs("button", { type: "button", className: [styles$E.contactTrigger, !selected ? styles$E.emptyContact : '', selected?.active === false ? styles$E.inactiveContact : ''].filter(Boolean).join(' '), disabled: disabled || pending, "data-test": `${dataTestId}-trigger`, "aria-expanded": open, "aria-haspopup": "listbox", "aria-busy": pending, "aria-label": `${title}: ${selected?.name ?? `Select ${title}`}`, onClick: () => setOpen((current) => !current), children: [jsx("span", { children: selected?.name ?? `Select ${title}` }), selected?.active === false && (jsx(Tooltip, { content: "A contact displayed in red is no longer an active portal user and must be replaced by an active user to ensure the accurate delivery of documents and notifications.", position: "right", variant: "error", delay: 0, children: jsx(WarningIcon$1, { size: 16, "aria-label": "Inactive portal user" }) })), pending ? jsx(Spinner, { size: "sm", label: `Updating ${title}` }) : open ? jsx(ChevronUpIcon, { size: 16 }) : jsx(ChevronDownIcon$1, { size: 16 })] }), !compact && selected?.title && jsx("span", { className: styles$E.contactTitle, children: selected.title }), !compact && selected?.phone && jsxs("a", { href: `tel:${selected.phone}`, className: styles$E.contactLink, children: [jsx(PhoneIcon, { size: 20 }), " ", selected.phone] }), !compact && selected?.email && jsxs("a", { href: `mailto:${selected.email}`, className: styles$E.contactLink, children: [jsx(MailIcon, { size: 20 }), " ", selected.email] })] })] }), open && (jsxs("div", { className: [styles$E.contactMenu, compact ? styles$E.compactMenu : ''].filter(Boolean).join(' '), role: "listbox", "aria-label": `${title} options`, children: [jsx("div", { className: styles$E.searchRow, children: jsx(Input, { size: "xs", fullWidth: true, autoFocus: true, value: search, placeholder: "Search contacts", "aria-label": `Search ${title}`, "data-test": `${dataTestId}-search`, leftIcon: jsx(SearchIcon$1, { size: 15 }), onChange: (event) => setSearch(event.target.value) }) }), jsx("div", { className: styles$E.menuDivider }), jsxs("div", { className: styles$E.contactOptions, children: [allowNone && selected && (jsxs("button", { type: "button", className: styles$E.clearContact, "data-test": `${dataTestId}-clear`, disabled: selecting, onClick: () => void select(undefined), children: [jsx("span", { className: styles$E.clearIcon, children: jsx(TrashIcon$2, { size: 16 }) }), jsxs("span", { children: ["Clear ", title] })] })), filteredContacts.map((contact) => (jsxs("button", { type: "button", role: "option", "aria-selected": false, className: styles$E.contactOption, "data-test": `${dataTestId}-option-${contact.id}`, disabled: selecting, onClick: () => void select(contact.id), children: [jsx(Avatar, { className: styles$E.optionAvatar, name: contact.name, size: "sm" }), jsxs("span", { children: [jsx("strong", { children: contact.name }), contact.title && jsx("small", { children: contact.title })] })] }, contact.id))), !filteredContacts.length && jsx("div", { className: styles$E.emptyOptions, children: "No matching contacts" })] })] }))] }));
|
|
5113
5380
|
};
|
|
5381
|
+
/**
|
|
5382
|
+
* Assigns a team's primary, secondary, and copied travel contacts.
|
|
5383
|
+
* Each slot saves independently, so `loading` is per slot rather than per panel.
|
|
5384
|
+
*/
|
|
5114
5385
|
const TeamContactsPanel = ({ contacts, value, onChange, disabled = false, loading = {}, dataTestId = 'team-contacts', className = '', }) => {
|
|
5115
5386
|
const ccContactIds = Array.from({ length: 4 }, (_, index) => value.ccContactIds?.[index]);
|
|
5116
5387
|
const updateCC = (index, id) => {
|
|
@@ -12076,6 +12347,10 @@ const NewEventRow = ({ values: initialValues, opponentOptions, onSave, onCancel,
|
|
|
12076
12347
|
setValues({ ...values, opponent, eventTitle: values.eventTitle || opponent });
|
|
12077
12348
|
}, required: true, fullWidth: true }), jsx("datalist", { id: "team-schedule-new-opponents", children: opponentOptions.map((option) => jsx("option", { value: option }, option)) })] }), jsx("div", { className: styles$A.cell, "data-label": "Event Title", children: jsx(Input, { "aria-label": "Event Title", size: "sm", value: values.eventTitle, onChange: (event) => setValues({ ...values, eventTitle: event.target.value }), required: true, fullWidth: true }) }), jsx("div", { className: styles$A.cell, "data-label": "Hm/Awy", children: jsx(Select, { "aria-label": "Home or Away", size: "sm", options: ['Home', 'Away', 'Neutral'].map((option) => ({ label: option, value: option })), value: values.homeOrAway, onChange: (event) => setValues({ ...values, homeOrAway: event.target.value }), fullWidth: true }) }), jsxs("div", { className: `${styles$A.cell} ${styles$A.actionsCell}`, children: [jsx(Button, { type: "submit", variant: "ghost", size: "sm", square: true, "aria-label": "Save new event", children: jsx(CheckIcon$2, { size: 17 }) }), jsx(Button, { type: "button", variant: "ghost", size: "sm", square: true, "aria-label": "Cancel new event", onClick: onCancel, children: jsx(XIcon, { size: 17 }) })] })] }));
|
|
12078
12349
|
};
|
|
12350
|
+
/**
|
|
12351
|
+
* Inline editor for a team's season: trips, and the events inside each trip.
|
|
12352
|
+
* Works controlled via `rows` or uncontrolled via `initialRows`.
|
|
12353
|
+
*/
|
|
12079
12354
|
const TeamScheduleEditor = ({ rows, initialRows = [], opponentOptions = [], onChange, onSaveTrip, onDeleteTrip, onSaveEvent, onDeleteEvent, onOpenGroupTravelRequest, onSelectedTripsChange, onSelectedEventsChange, className, }) => {
|
|
12080
12355
|
const [internalRows, setInternalRows] = useState(initialRows);
|
|
12081
12356
|
const [editState, setEditState] = useState(null);
|
|
@@ -12234,6 +12509,10 @@ const sportColor = (sportCode) => {
|
|
|
12234
12509
|
return '#D1C1C3';
|
|
12235
12510
|
return '#8AC6D9';
|
|
12236
12511
|
};
|
|
12512
|
+
/**
|
|
12513
|
+
* Period controls shared by the calendar views: previous, next, today, and month/week.
|
|
12514
|
+
* Stateless -- the host owns the active date and passes the label back in.
|
|
12515
|
+
*/
|
|
12237
12516
|
const TeamTravelCalendarToolbar = ({ duration, label = '', navigation, onDurationChange, onToday, onPrevious, onNext, className = '', }) => (jsxs("div", { className: [styles$z.toolbar, className].filter(Boolean).join(' '), "data-test": "calendar-toolbar", children: [jsx("button", { type: "button", className: styles$z.todayButton, onClick: onToday, "data-test": "calendar-today", children: "Today" }), jsx(SegmentedSelector, { value: duration, size: "sm", ariaLabel: "Calendar duration", onChange: (value) => onDurationChange?.(value), options: [{ id: 'month', label: 'Month' }, { id: 'week', label: 'Week' }] }), navigation ?? (jsxs("div", { className: styles$z.periodNavigation, children: [jsx("button", { type: "button", className: styles$z.navigationButton, "aria-label": `Previous ${duration}`, onClick: onPrevious, children: jsx(ChevronLeft$1, {}) }), jsx("button", { type: "button", className: styles$z.periodButton, children: label }), jsx("button", { type: "button", className: styles$z.navigationButton, "aria-label": `Next ${duration}`, onClick: onNext, children: jsx(ChevronRight$2, {}) })] }))] }));
|
|
12238
12517
|
const getVisibleDates = (activeDate, duration) => {
|
|
12239
12518
|
const active = parseDate(activeDate);
|
|
@@ -12249,6 +12528,9 @@ const getVisibleDates = (activeDate, duration) => {
|
|
|
12249
12528
|
const length = Math.round((last.getTime() - first.getTime()) / 86400000) + 1;
|
|
12250
12529
|
return Array.from({ length }, (_, index) => addDays(first, index));
|
|
12251
12530
|
};
|
|
12531
|
+
/**
|
|
12532
|
+
* Month or week grid plotting a team's trips or task due dates onto calendar days.
|
|
12533
|
+
*/
|
|
12252
12534
|
const TeamTravelCalendarView = ({ activeDate, duration = 'month', type = 'trips', trips = [], dueDates = [], today, toolbar, onTripClick, onDueDateClick, onDueDateToggle, className = '', }) => {
|
|
12253
12535
|
const active = parseDate(activeDate);
|
|
12254
12536
|
const visibleDates = getVisibleDates(activeDate, duration);
|
|
@@ -12300,6 +12582,10 @@ const DueDateCard = ({ dueDate, onClick, onToggle }) => {
|
|
|
12300
12582
|
onToggle?.();
|
|
12301
12583
|
}, children: completed ? jsx(CheckGlyph, {}) : jsx(CircleGlyph, {}) }), jsxs("div", { className: styles$z.dueCardCopy, children: [jsx("strong", { children: dueDate.tasktitle }), dueDate.description && jsx("span", { children: dueDate.description }), jsxs("small", { children: [dueDate.tripName, dueDate.tripStart ? ` • ${formatShortDate(dueDate.tripStart)}` : ''] })] })] }));
|
|
12302
12584
|
};
|
|
12585
|
+
/**
|
|
12586
|
+
* The same travel plotted as cards grouped by sport, for scanning across sports
|
|
12587
|
+
* rather than across dates.
|
|
12588
|
+
*/
|
|
12303
12589
|
const TeamTravelCalendarCardView = ({ groups, type = 'trips', toolbar, onTripClick, onDueDateClick, onDueDateToggle, className = '', }) => (jsxs("section", { className: [styles$z.cardView, className].filter(Boolean).join(' '), "aria-label": "Team travel cards", children: [toolbar, jsx("div", { className: styles$z.teamGroups, children: groups.map((group) => {
|
|
12304
12590
|
const groupDueDates = group.trips.flatMap((trip) => (trip.duedates ?? []).map((dueDate) => ({
|
|
12305
12591
|
...dueDate,
|
|
@@ -12318,6 +12604,10 @@ const TeamTravelCalendarCardView = ({ groups, type = 'trips', toolbar, onTripCli
|
|
|
12318
12604
|
const StatusPill$1 = ({ status }) => status
|
|
12319
12605
|
? jsx("span", { className: styles$z.tableStatus, children: status })
|
|
12320
12606
|
: jsx("span", { className: styles$z.tableRequest, children: "Request" });
|
|
12607
|
+
/**
|
|
12608
|
+
* The same travel as a dense chronological list, for long periods that a grid
|
|
12609
|
+
* cannot show at once.
|
|
12610
|
+
*/
|
|
12321
12611
|
const TeamTravelCalendarListView = ({ trips, type = 'trips', toolbar, periodLabel = '', upcomingTrips = trips.length, onTripClick, onDueDatesClick, onDueDateClick, onDueDateToggle, className = '', }) => {
|
|
12322
12612
|
const dueDates = trips.flatMap((trip) => (trip.duedates ?? []).map((dueDate) => ({
|
|
12323
12613
|
...dueDate,
|
|
@@ -12335,6 +12625,10 @@ const TeamTravelCalendarListView = ({ trips, type = 'trips', toolbar, periodLabe
|
|
|
12335
12625
|
return (jsxs("tr", { children: [jsx("td", { children: jsx("button", { type: "button", className: styles$z.tableLink, onClick: () => onDueDateClick?.(dueDate), children: dueDate.tasktitle }) }), jsx("td", { children: dueDate.description || '–' }), jsx("td", { children: formatLongDate(dueDate.duedate) }), jsx("td", { children: dueDate.tripName }), jsx("td", { children: formatLongDate(dueDate.tripStart) }), jsx("td", { children: dueDate.servicetype || '–' }), jsx("td", { children: jsx("button", { type: "button", className: [styles$z.listStatusButton, completed ? styles$z.completeStatus : ''].filter(Boolean).join(' '), "aria-label": `${completed ? 'Mark incomplete' : 'Mark complete'}: ${dueDate.tasktitle}`, onClick: () => onDueDateToggle?.(dueDate), children: completed ? jsx(CheckGlyph, {}) : jsx(CircleGlyph, {}) }) })] }, `${dueDate.masterTripGUID}-${dueDate.taskid}`));
|
|
12336
12626
|
}) })] }) })] }))] }));
|
|
12337
12627
|
};
|
|
12628
|
+
/**
|
|
12629
|
+
* Formats the heading for a calendar period -- "March 2026" for a month,
|
|
12630
|
+
* a date range for a week.
|
|
12631
|
+
*/
|
|
12338
12632
|
const getTeamTravelCalendarPeriodLabel = (activeDate, duration) => {
|
|
12339
12633
|
const active = parseDate(activeDate);
|
|
12340
12634
|
if (duration === 'month')
|
|
@@ -12347,6 +12641,10 @@ const getTeamTravelCalendarPeriodLabel = (activeDate, duration) => {
|
|
|
12347
12641
|
: last.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
|
12348
12642
|
return `${firstLabel} – ${lastLabel}`;
|
|
12349
12643
|
};
|
|
12644
|
+
/**
|
|
12645
|
+
* Steps a date forward or back by whole periods, returning the new active date.
|
|
12646
|
+
* Pass a negative `amount` to step backwards.
|
|
12647
|
+
*/
|
|
12350
12648
|
const moveTeamTravelCalendarPeriod = (activeDate, duration, amount) => {
|
|
12351
12649
|
const active = parseDate(activeDate);
|
|
12352
12650
|
if (duration === 'week')
|
|
@@ -12386,10 +12684,17 @@ const EMPTY_EQUIPMENT = {
|
|
|
12386
12684
|
width: '',
|
|
12387
12685
|
depth: '',
|
|
12388
12686
|
};
|
|
12687
|
+
/**
|
|
12688
|
+
* Adds or edits a piece of team equipment, including the dimensions and weight
|
|
12689
|
+
* that charter payload planning depends on.
|
|
12690
|
+
*/
|
|
12389
12691
|
const TeamEquipmentForm = ({ mode = 'Add', values, initialValues, onChange, onSubmit, onCancel, showActions = true, disabled = false, className, }) => {
|
|
12390
12692
|
const [formValues, updateValues] = useManagedValues(values, { ...EMPTY_EQUIPMENT, ...initialValues }, onChange);
|
|
12391
12693
|
return (jsx(FormShell, { ariaLabel: `${mode} equipment`, className: className, disabled: disabled, onCancel: onCancel, onSubmit: onSubmit, showActions: showActions, values: formValues, children: jsxs("div", { className: styles$y.stack, children: [jsx(Input, { label: "Item Name *", value: formValues.description, onChange: (event) => updateValues({ description: event.target.value }), required: true, disabled: disabled, fullWidth: true }), jsxs("div", { className: styles$y.twoColumnGrid, children: [jsx(Input, { label: "Weight (lbs) *", type: "number", min: "0", step: "0.1", value: formValues.weight, onChange: (event) => updateValues({ weight: numericValue$1(event.target.value) }), required: true, disabled: disabled, fullWidth: true }), jsx(Input, { label: "Quantity *", type: "number", min: "1", step: "1", value: formValues.quantity, onChange: (event) => updateValues({ quantity: numericValue$1(event.target.value) }), required: true, disabled: disabled, fullWidth: true }), jsx(Input, { label: "Height (inches)", type: "number", min: "0", step: "0.1", value: formValues.height, onChange: (event) => updateValues({ height: numericValue$1(event.target.value) }), disabled: disabled, fullWidth: true }), jsx(Input, { label: "Width (inches)", type: "number", min: "0", step: "0.1", value: formValues.width, onChange: (event) => updateValues({ width: numericValue$1(event.target.value) }), disabled: disabled, fullWidth: true }), jsx(Input, { label: "Depth (inches)", type: "number", min: "0", step: "0.1", value: formValues.depth, onChange: (event) => updateValues({ depth: numericValue$1(event.target.value) }), disabled: disabled, fullWidth: true })] })] }) }));
|
|
12392
12694
|
};
|
|
12695
|
+
/**
|
|
12696
|
+
* Grants an existing portal user access to a team.
|
|
12697
|
+
*/
|
|
12393
12698
|
const TeamUserAccessForm = ({ options, values, initialValues, onChange, onSubmit, onCancel, showActions = true, disabled = false, className, }) => {
|
|
12394
12699
|
const [formValues, updateValues] = useManagedValues(values, { userId: '', ...initialValues }, onChange);
|
|
12395
12700
|
return (jsx(FormShell, { ariaLabel: "Add team access", className: className, disabled: disabled, onCancel: onCancel, onSubmit: onSubmit, showActions: showActions, values: formValues, children: jsx(Select, { label: "Available Users *", placeholder: "Select a school contact", options: options, value: formValues.userId, onChange: (event) => updateValues({ userId: event.target.value }), required: true, disabled: disabled, fullWidth: true }) }));
|
|
@@ -12411,6 +12716,9 @@ const DEFAULT_SUPPLIERS = {
|
|
|
12411
12716
|
{ label: 'Marriott', value: 'Marriott' },
|
|
12412
12717
|
],
|
|
12413
12718
|
};
|
|
12719
|
+
/**
|
|
12720
|
+
* Records a loyalty or corporate program number the team travels under.
|
|
12721
|
+
*/
|
|
12414
12722
|
const TeamProgramForm = ({ values, initialValues, onChange, onSubmit, onCancel, showActions = true, disabled = false, className, supplierOptions, }) => {
|
|
12415
12723
|
const [formValues, updateValues] = useManagedValues(values, { type: 'Air', supplier: '', accountNumber: '', ...initialValues }, onChange);
|
|
12416
12724
|
const options = { ...DEFAULT_SUPPLIERS, ...supplierOptions };
|
|
@@ -12462,6 +12770,10 @@ const SectionBadge = ({ complete, optional, label }) => {
|
|
|
12462
12770
|
return jsxs("span", { className: `${styles$y.badge} ${styles$y.incompleteBadge}`, children: [jsx(WarningIcon$1, { size: 12 }), label ?? 'Incomplete'] });
|
|
12463
12771
|
};
|
|
12464
12772
|
const SectionCard = ({ icon, title, subtitle, badge, blue = false, children, }) => (jsxs("section", { className: `${styles$y.sectionCard} ${blue ? styles$y.blueSection : ''}`, children: [jsxs("div", { className: styles$y.sectionHeader, children: [jsx("div", { className: styles$y.sectionIcon, children: icon }), jsxs("div", { className: styles$y.sectionHeading, children: [jsx("h3", { children: title }), jsx("p", { children: subtitle })] }), badge] }), children] }));
|
|
12773
|
+
/**
|
|
12774
|
+
* Adds or edits a roster member, including the identity details carriers require
|
|
12775
|
+
* for ticketing. Can prefill from a linked portal user.
|
|
12776
|
+
*/
|
|
12465
12777
|
const TeamRosterMemberForm = ({ mode = 'Add', values, initialValues, onChange, onSubmit, onCancel, showActions = true, disabled = false, className, portalUsers = [], airlineOptions = DEFAULT_AIRLINES, travelerTypeOptions = DEFAULT_TRAVELER_TYPES, }) => {
|
|
12466
12778
|
const [formValues, updateValues] = useManagedValues(values, { ...EMPTY_ROSTER_MEMBER, ...initialValues }, onChange);
|
|
12467
12779
|
const minBirthDate = new Date();
|
|
@@ -12507,6 +12819,9 @@ const IMPORT_COPY = {
|
|
|
12507
12819
|
],
|
|
12508
12820
|
},
|
|
12509
12821
|
};
|
|
12822
|
+
/**
|
|
12823
|
+
* Bulk-loads roster or equipment records from an uploaded file.
|
|
12824
|
+
*/
|
|
12510
12825
|
const TeamImportForm = ({ kind, onSubmit, onCancel, disabled = false, className = '' }) => {
|
|
12511
12826
|
const [file, setFile] = useState(null);
|
|
12512
12827
|
const copy = IMPORT_COPY[kind];
|
|
@@ -12525,6 +12840,10 @@ const numericValue = (value) => {
|
|
|
12525
12840
|
const parsed = Number(String(value).replace(/[^0-9.-]/g, ''));
|
|
12526
12841
|
return Number.isFinite(parsed) ? parsed : undefined;
|
|
12527
12842
|
};
|
|
12843
|
+
/**
|
|
12844
|
+
* Formats a trip cost for a metric tile, abbreviating thousands so long figures
|
|
12845
|
+
* do not wrap.
|
|
12846
|
+
*/
|
|
12528
12847
|
const formatCompactTripCost = (value) => {
|
|
12529
12848
|
const cost = numericValue(value);
|
|
12530
12849
|
if (cost === undefined)
|
|
@@ -12533,6 +12852,9 @@ const formatCompactTripCost = (value) => {
|
|
|
12533
12852
|
return `${(cost / 1000000).toFixed(2)}M`;
|
|
12534
12853
|
return `${Math.floor(cost / 1000)}K`;
|
|
12535
12854
|
};
|
|
12855
|
+
/**
|
|
12856
|
+
* Season-at-a-glance tiles: trips taken, trips remaining, spend, and overdue tasks.
|
|
12857
|
+
*/
|
|
12536
12858
|
const TravelSummaryMetrics = ({ tripsTraveled, remainingTrips, seasonTripCosts, seasonLabel, overdueActions, onOverdueActionsClick, className = '', }) => {
|
|
12537
12859
|
const overdueCount = numericValue(overdueActions) ?? 0;
|
|
12538
12860
|
return (jsxs("div", { className: [styles$x.grid, className].filter(Boolean).join(' '), children: [jsx(Metric, { value: tripsTraveled, label: "Trips Travelled" }), jsx(Metric, { value: remainingTrips, label: "Remaining Trips" }), jsx(Metric, { value: formatCompactTripCost(seasonTripCosts), label: `${seasonLabel} Trip Costs`, prefix: "$" }), jsx(Metric, { value: overdueActions, label: "Overdue Actions", warning: overdueCount > 0, dark: true, onClick: onOverdueActionsClick })] }));
|
|
@@ -12587,6 +12909,9 @@ const resolveStatus = (status) => {
|
|
|
12587
12909
|
return { variant: 'itinerary', label: status.trim() || 'Unknown' };
|
|
12588
12910
|
};
|
|
12589
12911
|
const getLegacyIdentifier = (trip, requested) => (requested ? trip.reqId || trip.id : trip.pnr || trip.id);
|
|
12912
|
+
/**
|
|
12913
|
+
* Trip listing with the segment, status, and date columns the travel screens share.
|
|
12914
|
+
*/
|
|
12590
12915
|
const TripTable = ({ trips, variant = 'current', density = 'comfortable', vendorMode = 'icon', useServiceColumn = false, onSelectTrip, onViewTrip, emptyMessage, className, }) => {
|
|
12591
12916
|
const isRequested = variant === 'requested';
|
|
12592
12917
|
const isCompact = density === 'compact';
|
|
@@ -13871,6 +14196,11 @@ const RequestSummary = ({ values, enabled }) => {
|
|
|
13871
14196
|
const populated = sections.filter((section) => section.rows.some(([, value]) => Boolean(value)));
|
|
13872
14197
|
return jsxs("div", { className: styles$h.summaryCard, children: [jsx("h2", { children: "Request Summary" }), populated.map((section) => jsxs("section", { className: styles$h.summarySection, children: [jsx("h3", { children: section.title }), section.rows.map(([label, value]) => jsx(SummaryRow, { label: label, value: value }, label))] }, section.key)), !populated.length && jsx("p", { className: styles$h.emptySummary, children: "No services selected" })] });
|
|
13873
14198
|
};
|
|
14199
|
+
/**
|
|
14200
|
+
* Multi-step wizard for requesting travel for a whole team.
|
|
14201
|
+
* Collects the trip, the services needed, and the traveling party, and hands the
|
|
14202
|
+
* completed request to the host through `onSubmit`.
|
|
14203
|
+
*/
|
|
13874
14204
|
const GroupTravelRequestPage = ({ eventName = 'New Trip', totalPages = 1, onSubmit, onCancel, onChange, initialValues = {}, contacts = [], cateringOptions = DEFAULT_CATERING, schoolAddress = '', services, summarySections, className = '', }) => {
|
|
13875
14205
|
const resolvedServices = services ?? DEFAULT_SERVICES;
|
|
13876
14206
|
const [currentPage, setCurrentPage] = useState(1);
|
|
@@ -14044,6 +14374,10 @@ const matchesLegacyFilters = (trip, filters) => {
|
|
|
14044
14374
|
return false;
|
|
14045
14375
|
return true;
|
|
14046
14376
|
};
|
|
14377
|
+
/**
|
|
14378
|
+
* Landing page for a single traveler's own requests, listing what they have raised
|
|
14379
|
+
* and offering a new one.
|
|
14380
|
+
*/
|
|
14047
14381
|
const IndividualTravelPage = ({ trips, tabCounts, enabledTabs = ['current', 'past'], activeTab, onTabChange, filters, defaultFilters, onFiltersChange, pagination, onPageChange, loading = false, refreshing = false, error, onRetry, exporting = false, onExportFiltered, onSelectTrip, onSelectRequest, onCreateRequest, emptyMessage, searchLabel = 'Search trips', searchPlaceholder = 'Search traveler, PNR, route…', currentTrips = [], pastTrips = [], requestedTrips, sportOptions = defaultSportOptions, travelerOptions, initialTab = 'current', density = 'comfortable', vendorMode = 'icon', useServiceColumn = false, onViewTrip, onViewRequest, onExport, showTravelerScopeInfo = false, className, }) => {
|
|
14048
14382
|
const serverMode = trips !== undefined;
|
|
14049
14383
|
const hasRequestedSource = serverMode || requestedTrips !== undefined;
|
|
@@ -14723,6 +15057,12 @@ const QuestionField = ({ question, value, onChange, disabled, dataTest, error, }
|
|
|
14723
15057
|
return (jsx(Field, { label: question.label, value: typeof value === 'string' ? value : '', onChange: onChange, options: question.type === 'single-select' ? question.options ?? [] : undefined, required: question.required, disabled: disabled, help: question.description, error: error, maxLength: question.maxLength, dataTest: dataTest }));
|
|
14724
15058
|
};
|
|
14725
15059
|
const Section = ({ title, description, children, action, dataTest, }) => (jsxs("section", { className: styles$f.section, "data-test": dataTest, children: [jsxs("div", { className: styles$f.sectionHeader, children: [jsxs("div", { children: [jsx("h2", { className: styles$f.sectionTitle, children: title }), description && jsx("p", { className: styles$f.sectionDescription, children: description })] }), action] }), children] }));
|
|
15060
|
+
/**
|
|
15061
|
+
* Form for one traveler to request their own travel.
|
|
15062
|
+
* The questions asked come from the account configuration, so the host supplies
|
|
15063
|
+
* them rather than the page assuming a fixed set.
|
|
15064
|
+
* Renders read-only when no `onSubmit` is given.
|
|
15065
|
+
*/
|
|
14726
15066
|
const IndividualTravelRequestFormPage = ({ currentTraveler, configuration, values, initialValues, onChange, onSubmit, onCancel, loading = false, submitting = false, error, fieldErrors, onRetry, notice, submitLabel = 'Submit travel request', className, }) => {
|
|
14727
15067
|
const [internalValues, setInternalValues] = useState(() => (createInitialValues(configuration, initialValues)));
|
|
14728
15068
|
const [internalSubmitting, setInternalSubmitting] = useState(false);
|
|
@@ -15189,6 +15529,10 @@ OffFleetSubmissionDetailPage.displayName = 'OffFleetSubmissionDetailPage';
|
|
|
15189
15529
|
|
|
15190
15530
|
var styles$8 = {"page":"RosterProgramNumbersPage-module_page__eNDG8","header":"RosterProgramNumbersPage-module_header__1YtCr","heading":"RosterProgramNumbersPage-module_heading__6tBIK","tableWrap":"RosterProgramNumbersPage-module_tableWrap__l0smr","table":"RosterProgramNumbersPage-module_table__6UGEu","traveler":"RosterProgramNumbersPage-module_traveler__7ZbBS","supplier":"RosterProgramNumbersPage-module_supplier__EEXuR","inputCell":"RosterProgramNumbersPage-module_inputCell__OaiTN","empty":"RosterProgramNumbersPage-module_empty__iFweL","footer":"RosterProgramNumbersPage-module_footer__p4K-j"};
|
|
15191
15531
|
|
|
15532
|
+
/**
|
|
15533
|
+
* Edits the loyalty and corporate program numbers a team travels under, saving them
|
|
15534
|
+
* as one set.
|
|
15535
|
+
*/
|
|
15192
15536
|
const RosterProgramNumbersPage = ({ programs, loading = false, saving = false, onBack, onSubmit, }) => {
|
|
15193
15537
|
const initialValues = useMemo(() => Object.fromEntries(programs.map((program) => [String(program.id), program.accountNumber])), [programs]);
|
|
15194
15538
|
const [values, setValues] = useState(initialValues);
|
|
@@ -15239,6 +15583,9 @@ RegularSeasonBidsPage.displayName = 'RegularSeasonBidsPage';
|
|
|
15239
15583
|
|
|
15240
15584
|
var styles$6 = {"page":"RosterReportsPage-module_page__ZU5hz","header":"RosterReportsPage-module_header__FFSTB","heading":"RosterReportsPage-module_heading__rIwdQ","list":"RosterReportsPage-module_list__9K8tF","report":"RosterReportsPage-module_report__iXROM","details":"RosterReportsPage-module_details__WZ6cT","empty":"RosterReportsPage-module_empty__Nrynv"};
|
|
15241
15585
|
|
|
15586
|
+
/**
|
|
15587
|
+
* Lists the roster reports a user can run, and reports progress while one runs.
|
|
15588
|
+
*/
|
|
15242
15589
|
const RosterReportsPage = ({ reports, runningReportId, onBack, onRun }) => (jsxs("section", { className: styles$6.page, "data-test": "roster-reports-page", children: [jsxs("header", { className: styles$6.header, children: [jsxs("div", { className: styles$6.heading, children: [jsx("h1", { children: "Roster Reports" }), jsx("p", { children: "Run the available reports for the selected team roster." })] }), jsx(Button, { type: "button", variant: "outline", size: "sm", "data-test": "roster-reports-back", onClick: onBack, children: "Back to Roster" })] }), jsx(Module, { title: "Team Reports", useToggle: false, children: reports.length ? (jsx("div", { className: styles$6.list, "data-test": "roster-report-list", children: reports.map((report) => (jsxs("article", { className: styles$6.report, "data-test": `roster-report-${report.id}`, children: [jsxs("div", { className: styles$6.details, children: [jsx("h2", { children: report.title }), report.description && jsx("p", { children: report.description })] }), jsx(Button, { type: "button", variant: "outline", size: "sm", loading: runningReportId === report.id, disabled: Boolean(runningReportId) && runningReportId !== report.id, "data-test": `run-roster-report-${report.id}`, onClick: () => void onRun?.(report), children: "Run Report" })] }, report.id))) })) : (jsx("div", { className: styles$6.empty, children: "No roster reports are currently available." })) })] }));
|
|
15243
15590
|
RosterReportsPage.displayName = 'RosterReportsPage';
|
|
15244
15591
|
|