mautourco-components 0.2.46 → 0.2.48

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.
Files changed (44) hide show
  1. package/dist/components/molecules/AgeSelector/AgeSelector.d.ts +20 -0
  2. package/dist/components/molecules/AgeSelector/AgeSelector.js +84 -0
  3. package/dist/components/molecules/LocationDropdown/LocationDropdown.js +1 -1
  4. package/dist/components/molecules/Pagination/Pagination.css +27 -17
  5. package/dist/components/molecules/Pagination/Pagination.js +4 -4
  6. package/dist/components/organisms/PaxSelector/PaxSelector.d.ts +5 -0
  7. package/dist/components/organisms/PaxSelector/PaxSelector.js +100 -114
  8. package/dist/components/organisms/RoundTrip/RoundTrip.d.ts +2 -0
  9. package/dist/components/organisms/RoundTrip/RoundTrip.js +7 -7
  10. package/dist/components/organisms/SearchBarTransfer/SearchBarTransfer.d.ts +4 -0
  11. package/dist/components/organisms/SearchBarTransfer/SearchBarTransfer.js +19 -57
  12. package/dist/components/organisms/Table/Table.css +64 -53
  13. package/dist/components/organisms/Table/Table.d.ts +1 -0
  14. package/dist/components/organisms/Table/Table.js +2 -1
  15. package/dist/components/organisms/Table/columns/booking-columns.d.ts +1 -1
  16. package/dist/components/organisms/Table/columns/booking-columns.js +17 -2
  17. package/dist/components/organisms/Table/columns/index.d.ts +1 -1
  18. package/dist/components/organisms/TransferLine/TransferLine.d.ts +9 -5
  19. package/dist/components/organisms/TransferLine/TransferLine.js +52 -35
  20. package/dist/index.d.ts +19 -16
  21. package/dist/index.js +3 -1
  22. package/dist/styles/components/molecule/age-selector.css +216 -0
  23. package/dist/styles/components/molecule/calendarInput.css +25 -6
  24. package/dist/styles/components/molecule/location-dropdown.css +16 -4
  25. package/dist/styles/components/organism/pax-selector.css +27 -189
  26. package/dist/styles/components/organism/transfer-line.css +40 -0
  27. package/dist/styles/mautourco.css +1 -0
  28. package/package.json +1 -1
  29. package/src/components/molecules/AgeSelector/AgeSelector.tsx +172 -0
  30. package/src/components/molecules/LocationDropdown/LocationDropdown.tsx +1 -1
  31. package/src/components/molecules/Pagination/Pagination.css +27 -18
  32. package/src/components/molecules/Pagination/Pagination.tsx +9 -13
  33. package/src/components/organisms/PaxSelector/PaxSelector.tsx +132 -208
  34. package/src/components/organisms/RoundTrip/RoundTrip.tsx +7 -0
  35. package/src/components/organisms/SearchBarTransfer/SearchBarTransfer.tsx +34 -54
  36. package/src/components/organisms/Table/Table.css +64 -53
  37. package/src/components/organisms/Table/Table.tsx +22 -1
  38. package/src/components/organisms/Table/columns/booking-columns.tsx +40 -13
  39. package/src/components/organisms/TransferLine/TransferLine.tsx +107 -85
  40. package/src/styles/components/molecule/age-selector.css +136 -0
  41. package/src/styles/components/molecule/calendarInput.css +12 -4
  42. package/src/styles/components/molecule/location-dropdown.css +9 -2
  43. package/src/styles/components/organism/pax-selector.css +25 -186
  44. package/src/styles/components/organism/transfer-line.css +31 -0
@@ -1,7 +1,8 @@
1
- import React, { useEffect, useRef, useState } from 'react';
1
+ import React, { Fragment, useEffect, useRef, useState } from 'react';
2
2
  import { scrollIntoViewOnOpen } from '../../../lib/utils';
3
3
  import Icon from '../../atoms/Icon/Icon';
4
4
  import { Text } from '../../atoms/Typography/Typography';
5
+ import AgeSelector from '../../molecules/AgeSelector/AgeSelector';
5
6
 
6
7
  export type ClientType = 'Standard client' | 'VIP' | 'VVIP' | 'Honeymooners';
7
8
 
@@ -65,8 +66,12 @@ export interface PaxSelectorProps {
65
66
  onRemoveRoom?: (roomId: string) => void;
66
67
  /** Default pax data for single room mode (will trigger onChange on mount) */
67
68
  defaultPaxData?: PaxData;
69
+ /** Whether the selector is disabled */
70
+ disabled?: boolean;
68
71
  /** Whether to scroll to the input when the dropdown opens */
69
72
  scrollOnOpen?: boolean;
73
+ /** Age range for child categories */
74
+ ageRange?: number[];
70
75
  }
71
76
 
72
77
  const DEFAULT_PAX_DATA: PaxData = {
@@ -94,178 +99,7 @@ export const DEFAULT_PAX_DATA_WITH_ADULTS: PaxData = {
94
99
  const CLIENT_TYPES: ClientType[] = ['Standard client', 'VIP', 'VVIP', 'Honeymooners'];
95
100
 
96
101
  // Age range for all child categories (teens, children, infants)
97
- const CHILD_CATEGORY_AGES = Array.from({ length: 18 }, (_, i) => i + 1); // 1-18 years
98
-
99
- interface AgeSelectorProps {
100
- label: string;
101
- value: number | undefined;
102
- onChange: (age: number) => void;
103
- ageRange: number[];
104
- required?: boolean;
105
- }
106
-
107
- const AgeSelector: React.FC<AgeSelectorProps> = ({
108
- label,
109
- value,
110
- onChange,
111
- ageRange,
112
- required,
113
- }) => {
114
- const [isOpen, setIsOpen] = useState(false);
115
- const [inputValue, setInputValue] = useState<string>(
116
- value !== undefined ? value.toString() : ''
117
- );
118
- const containerRef = useRef<HTMLDivElement>(null);
119
- const inputRef = useRef<HTMLInputElement>(null);
120
-
121
- // Sync input value when prop value changes
122
- useEffect(() => {
123
- setInputValue(value !== undefined ? value.toString() : '');
124
- }, [value]);
125
-
126
- useEffect(() => {
127
- const handleClickOutside = (event: MouseEvent) => {
128
- if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
129
- setIsOpen(false);
130
- }
131
- };
132
-
133
- if (isOpen) {
134
- document.addEventListener('mousedown', handleClickOutside);
135
- }
136
-
137
- return () => {
138
- document.removeEventListener('mousedown', handleClickOutside);
139
- };
140
- }, [isOpen]);
141
-
142
- const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
143
- const newValue = e.target.value;
144
-
145
- // Only allow numeric input or empty string
146
- if (newValue === '' || /^\d+$/.test(newValue)) {
147
- setInputValue(newValue);
148
-
149
- // Only update if it's a valid number within range
150
- const numValue = parseInt(newValue, 10);
151
- if (newValue === '') {
152
- // Allow empty input - don't update onChange
153
- return;
154
- } else if (!isNaN(numValue) && ageRange.includes(numValue)) {
155
- onChange(numValue);
156
- }
157
- }
158
- };
159
-
160
- const handleInputBlur = () => {
161
- // Validate and set to valid value or clear if invalid
162
- const numValue = parseInt(inputValue, 10);
163
- if (inputValue === '') {
164
- // Keep empty if user cleared it
165
- return;
166
- } else if (isNaN(numValue) || !ageRange.includes(numValue)) {
167
- // Reset to current value if invalid
168
- setInputValue(value !== undefined ? value.toString() : '');
169
- } else {
170
- // Ensure the input value matches the validated value
171
- setInputValue(numValue.toString());
172
- }
173
- };
174
-
175
- const handleInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
176
- if (e.key === 'Enter') {
177
- e.preventDefault();
178
- inputRef.current?.blur();
179
- }
180
- };
181
-
182
- const handleSelect = (age: string) => {
183
- const numAge = parseInt(age, 10);
184
- onChange(numAge);
185
- setIsOpen(false);
186
- setInputValue(age);
187
- };
188
-
189
- const handleDropdownToggle = () => {
190
- setIsOpen(!isOpen);
191
- };
192
-
193
- const ageOptions = ageRange.map((age) => age.toString());
194
- const displayValue = inputValue || undefined;
195
-
196
- return (
197
- <div className="pax-selector__age-selector" ref={containerRef}>
198
- <Text size="sm" variant="regular" className="pax-selector__age-label">
199
- {label}
200
- {required && <span className="pax-selector__age-required"> *</span>}
201
- </Text>
202
- <div className="dropdown-container pax-selector__age-dropdown-container">
203
- <div
204
- className={`dropdown-input ${isOpen ? 'dropdown-input--open pax-selector__age-dropdown-input--open' : ''} ${value !== undefined ? 'dropdown-input--selected' : 'dropdown-input--default'} pax-selector__age-dropdown-input`}>
205
- <input
206
- ref={inputRef}
207
- type="text"
208
- inputMode="numeric"
209
- className="dropdown-input__text pax-selector__age-input-text"
210
- value={inputValue}
211
- onChange={handleInputChange}
212
- onBlur={handleInputBlur}
213
- onKeyDown={handleInputKeyDown}
214
- onFocus={() => setIsOpen(false)}
215
- placeholder="--"
216
- aria-label={`${label} age`}
217
- style={{
218
- background: 'transparent',
219
- border: 'none',
220
- outline: 'none',
221
- width: '100%',
222
- cursor: 'text',
223
- }}
224
- />
225
- <button
226
- type="button"
227
- className="pax-selector__age-dropdown-btn"
228
- onClick={(e) => {
229
- e.preventDefault();
230
- e.stopPropagation();
231
- handleDropdownToggle();
232
- }}
233
- aria-expanded={isOpen}
234
- aria-haspopup="listbox"
235
- aria-label="Open age dropdown"
236
- style={{
237
- background: 'transparent',
238
- border: 'none',
239
- cursor: 'pointer',
240
- padding: 0,
241
- display: 'flex',
242
- alignItems: 'center',
243
- }}>
244
- <Icon
245
- name="chevron-down"
246
- size="sm"
247
- className="dropdown-input__icon dropdown-input__icon--chevron"
248
- />
249
- </button>
250
- </div>
251
- {isOpen && (
252
- <div className="dropdown-menu" role="listbox">
253
- {ageOptions.map((age) => (
254
- <div
255
- key={age}
256
- className={`dropdown-option ${value?.toString() === age ? 'dropdown-option--selected' : ''}`}
257
- onClick={() => handleSelect(age)}
258
- role="option"
259
- aria-selected={value?.toString() === age}>
260
- {age}
261
- </div>
262
- ))}
263
- </div>
264
- )}
265
- </div>
266
- </div>
267
- );
268
- };
102
+ export const CHILD_CATEGORY_AGES = Array.from({ length: 18 }, (_, i) => i + 1); // 1-18 years
269
103
 
270
104
  interface StepperRowProps {
271
105
  label: string;
@@ -410,6 +244,8 @@ interface RoomEditorProps {
410
244
  maxInfants: number;
411
245
  onChange: (room: RoomData) => void;
412
246
  onRemove: () => void;
247
+ scrollToRef?: React.RefObject<HTMLDivElement | null>;
248
+ ageRange: number[];
413
249
  }
414
250
 
415
251
  const RoomEditor: React.FC<RoomEditorProps> = ({
@@ -422,7 +258,12 @@ const RoomEditor: React.FC<RoomEditorProps> = ({
422
258
  maxInfants,
423
259
  onChange,
424
260
  onRemove,
261
+ scrollToRef,
262
+ ageRange,
425
263
  }) => {
264
+ const roomAgesSectionRef = useRef<HTMLDivElement>(null);
265
+ const previousRoomCounts = useRef({ teens: 0, children: 0, infants: 0 });
266
+
426
267
  const handleFieldChange = (
427
268
  field: keyof PaxData,
428
269
  value: number | ClientType | number[]
@@ -440,6 +281,38 @@ const RoomEditor: React.FC<RoomEditorProps> = ({
440
281
  handleFieldChange(category, ages);
441
282
  };
442
283
 
284
+ // Scroll to age section when new age inputs are added in this room
285
+ useEffect(() => {
286
+ const prev = previousRoomCounts.current;
287
+ const curr = {
288
+ teens: room.teens,
289
+ children: room.children,
290
+ infants: room.infants,
291
+ };
292
+
293
+ // Check if any count increased
294
+ const hasIncrease =
295
+ curr.teens > prev.teens ||
296
+ curr.children > prev.children ||
297
+ curr.infants > prev.infants;
298
+
299
+ if (hasIncrease && roomAgesSectionRef.current) {
300
+ // Scroll to the age section after a short delay to ensure DOM is updated
301
+ setTimeout(() => {
302
+ if (roomAgesSectionRef.current) {
303
+ roomAgesSectionRef.current.scrollIntoView({
304
+ behavior: 'smooth',
305
+ block: 'nearest',
306
+ inline: 'nearest',
307
+ });
308
+ }
309
+ }, 100);
310
+ }
311
+
312
+ // Update previous counts
313
+ previousRoomCounts.current = curr;
314
+ }, [room.teens, room.children, room.infants]);
315
+
443
316
  // Generate age arrays based on counts
444
317
  useEffect(() => {
445
318
  const teenAges = room.teenAges || [];
@@ -491,7 +364,7 @@ const RoomEditor: React.FC<RoomEditorProps> = ({
491
364
  const infantAgeChunks = chunkAges(room.infantAges || [], 'Infant');
492
365
 
493
366
  return (
494
- <div className="pax-selector__room-container">
367
+ <div className="pax-selector__room-container" ref={scrollToRef}>
495
368
  <div className="pax-selector__room-header">
496
369
  <div className="pax-selector__room-title">
497
370
  <Text
@@ -545,7 +418,7 @@ const RoomEditor: React.FC<RoomEditorProps> = ({
545
418
 
546
419
  {/* Age specification section */}
547
420
  {(room.teens > 0 || room.children > 0 || room.infants > 0) && (
548
- <div className="pax-selector__age-section">
421
+ <div className="pax-selector__age-section" ref={roomAgesSectionRef}>
549
422
  <Text
550
423
  size="base"
551
424
  variant="bold"
@@ -558,7 +431,7 @@ const RoomEditor: React.FC<RoomEditorProps> = ({
558
431
  {/* Teen ages */}
559
432
  {room.teens > 0 &&
560
433
  teenAgeChunks.map((chunk, chunkIndex) => (
561
- <div key={`teen-chunk-${chunkIndex}`} className="pax-selector__age-row">
434
+ <Fragment key={`teen-chunk-${chunkIndex}`}>
562
435
  {chunk.map((age, ageIndex) => {
563
436
  const actualIndex = chunkIndex * 2 + ageIndex;
564
437
  return (
@@ -569,20 +442,18 @@ const RoomEditor: React.FC<RoomEditorProps> = ({
569
442
  onChange={(selectedAge) =>
570
443
  handleAgeChange('teenAges', actualIndex, selectedAge)
571
444
  }
572
- ageRange={CHILD_CATEGORY_AGES}
445
+ ageRange={ageRange}
573
446
  required
574
447
  />
575
448
  );
576
449
  })}
577
- </div>
450
+ </Fragment>
578
451
  ))}
579
452
 
580
453
  {/* Child ages */}
581
454
  {room.children > 0 &&
582
455
  childAgeChunks.map((chunk, chunkIndex) => (
583
- <div
584
- key={`child-chunk-${chunkIndex}`}
585
- className="pax-selector__age-row">
456
+ <Fragment key={`child-chunk-${chunkIndex}`}>
586
457
  {chunk.map((age, ageIndex) => {
587
458
  const actualIndex = chunkIndex * 2 + ageIndex;
588
459
  return (
@@ -593,20 +464,18 @@ const RoomEditor: React.FC<RoomEditorProps> = ({
593
464
  onChange={(selectedAge) =>
594
465
  handleAgeChange('childAges', actualIndex, selectedAge)
595
466
  }
596
- ageRange={CHILD_CATEGORY_AGES}
467
+ ageRange={ageRange}
597
468
  required
598
469
  />
599
470
  );
600
471
  })}
601
- </div>
472
+ </Fragment>
602
473
  ))}
603
474
 
604
475
  {/* Infant ages */}
605
476
  {room.infants > 0 &&
606
477
  infantAgeChunks.map((chunk, chunkIndex) => (
607
- <div
608
- key={`infant-chunk-${chunkIndex}`}
609
- className="pax-selector__age-row">
478
+ <Fragment key={`infant-chunk-${chunkIndex}`}>
610
479
  {chunk.map((age, ageIndex) => {
611
480
  const actualIndex = chunkIndex * 2 + ageIndex;
612
481
  return (
@@ -617,12 +486,12 @@ const RoomEditor: React.FC<RoomEditorProps> = ({
617
486
  onChange={(selectedAge) =>
618
487
  handleAgeChange('infantAges', actualIndex, selectedAge)
619
488
  }
620
- ageRange={CHILD_CATEGORY_AGES}
489
+ ageRange={ageRange}
621
490
  required
622
491
  />
623
492
  );
624
493
  })}
625
- </div>
494
+ </Fragment>
626
495
  ))}
627
496
  </div>
628
497
  </div>
@@ -655,7 +524,9 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
655
524
  onRoomsChange,
656
525
  onRemoveRoom,
657
526
  defaultPaxData = DEFAULT_PAX_DATA_WITH_ADULTS,
527
+ ageRange = CHILD_CATEGORY_AGES,
658
528
  scrollOnOpen = false,
529
+ disabled = false,
659
530
  }) => {
660
531
  const [isOpen, setIsOpen] = useState(false);
661
532
  const [internalData, setInternalData] = useState<PaxData>(
@@ -667,6 +538,9 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
667
538
  const containerRef = useRef<HTMLDivElement>(null);
668
539
  const triggerRef = useRef<HTMLButtonElement>(null);
669
540
  const hasInitialized = useRef(false);
541
+ const lastRoomRef = useRef<HTMLDivElement>(null);
542
+ const agesSectionRef = useRef<HTMLDivElement>(null);
543
+ const previousCounts = useRef({ teens: 0, children: 0, infants: 0 });
670
544
 
671
545
  // Sync internal data with external value prop
672
546
  useEffect(() => {
@@ -765,6 +639,46 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
765
639
  scrollIntoViewOnOpen(triggerRef, isOpen, scrollOnOpen);
766
640
  }, [isOpen, scrollOnOpen]);
767
641
 
642
+ // Scroll to age section when new age inputs are added (single room mode)
643
+ useEffect(() => {
644
+ if (!multipleRooms && isOpen) {
645
+ const prev = previousCounts.current;
646
+ const curr = {
647
+ teens: internalData.teens,
648
+ children: internalData.children,
649
+ infants: internalData.infants,
650
+ };
651
+
652
+ // Check if any count increased
653
+ const hasIncrease =
654
+ curr.teens > prev.teens ||
655
+ curr.children > prev.children ||
656
+ curr.infants > prev.infants;
657
+
658
+ if (hasIncrease && agesSectionRef.current) {
659
+ // Scroll to the age section after a short delay to ensure DOM is updated
660
+ setTimeout(() => {
661
+ if (agesSectionRef.current) {
662
+ agesSectionRef.current.scrollIntoView({
663
+ behavior: 'smooth',
664
+ block: 'nearest',
665
+ inline: 'nearest',
666
+ });
667
+ }
668
+ }, 100);
669
+ }
670
+
671
+ // Update previous counts
672
+ previousCounts.current = curr;
673
+ }
674
+ }, [
675
+ internalData.teens,
676
+ internalData.children,
677
+ internalData.infants,
678
+ multipleRooms,
679
+ isOpen,
680
+ ]);
681
+
768
682
  const handleDataChange = (
769
683
  field: keyof PaxData,
770
684
  newValue: number | ClientType | number[]
@@ -803,6 +717,17 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
803
717
  setRooms(updatedRooms);
804
718
  onRoomsChange?.(updatedRooms);
805
719
  onAddRoom?.();
720
+
721
+ // Scroll to the newly added room after a short delay
722
+ setTimeout(() => {
723
+ if (lastRoomRef.current) {
724
+ lastRoomRef.current.scrollIntoView({
725
+ behavior: 'smooth',
726
+ block: 'nearest',
727
+ inline: 'nearest',
728
+ });
729
+ }
730
+ }, 100);
806
731
  };
807
732
 
808
733
  const handleRemoveRoom = (roomId: string) => {
@@ -842,19 +767,22 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
842
767
  const hasPax = getTotalPax() > 0;
843
768
 
844
769
  return (
845
- <div className={`pax-selector ${className}`} ref={containerRef}>
770
+ <div
771
+ className={`pax-selector ${disabled ? 'pax-selector--disabled' : ''} ${className}`}
772
+ ref={containerRef}>
846
773
  <button
847
774
  ref={triggerRef}
848
775
  type="button"
849
776
  className="pax-selector__trigger"
850
- onClick={() => setIsOpen(!isOpen)}
777
+ onClick={() => !disabled && setIsOpen(!isOpen)}
851
778
  aria-expanded={isOpen}
852
- aria-haspopup="true">
779
+ aria-haspopup="true"
780
+ disabled={disabled}>
853
781
  <Text size="sm" variant="regular" className="pax-selector__label">
854
782
  {label}
855
783
  </Text>
856
784
  <div
857
- className={`pax-selector__input ${isOpen ? 'pax-selector__input--active' : ''}`}>
785
+ className={`pax-selector__input ${isOpen ? 'pax-selector__input--active' : ''} ${disabled ? 'pax-selector__input--disabled' : ''}`}>
858
786
  <div className="pax-selector__input-content">
859
787
  <Icon name="user-icon" size="sm" className="pax-selector__input-icon" />
860
788
  <span
@@ -899,6 +827,8 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
899
827
  maxInfants={maxInfants}
900
828
  onChange={(updatedRoom) => handleRoomChange(room.roomId, updatedRoom)}
901
829
  onRemove={() => handleRemoveRoom(room.roomId)}
830
+ scrollToRef={index === rooms.length - 1 ? lastRoomRef : undefined}
831
+ ageRange={ageRange}
902
832
  />
903
833
  ))}
904
834
  </div>
@@ -937,7 +867,7 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
937
867
  {(internalData.teens > 0 ||
938
868
  internalData.children > 0 ||
939
869
  internalData.infants > 0) && (
940
- <div className="pax-selector__age-section">
870
+ <div className="pax-selector__age-section" ref={agesSectionRef}>
941
871
  <Text
942
872
  size="base"
943
873
  variant="bold"
@@ -988,9 +918,7 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
988
918
  {/* Teen ages */}
989
919
  {internalData.teens > 0 &&
990
920
  teenAgeChunks.map((chunk, chunkIndex) => (
991
- <div
992
- key={`teen-chunk-${chunkIndex}`}
993
- className="pax-selector__age-row">
921
+ <Fragment key={`teen-chunk-${chunkIndex}`}>
994
922
  {chunk.map((age, ageIndex) => {
995
923
  const actualIndex = chunkIndex * 2 + ageIndex;
996
924
  return (
@@ -1005,20 +933,18 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
1005
933
  selectedAge
1006
934
  )
1007
935
  }
1008
- ageRange={CHILD_CATEGORY_AGES}
936
+ ageRange={ageRange}
1009
937
  required
1010
938
  />
1011
939
  );
1012
940
  })}
1013
- </div>
941
+ </Fragment>
1014
942
  ))}
1015
943
 
1016
944
  {/* Child ages */}
1017
945
  {internalData.children > 0 &&
1018
946
  childAgeChunks.map((chunk, chunkIndex) => (
1019
- <div
1020
- key={`child-chunk-${chunkIndex}`}
1021
- className="pax-selector__age-row">
947
+ <Fragment key={`child-chunk-${chunkIndex}`}>
1022
948
  {chunk.map((age, ageIndex) => {
1023
949
  const actualIndex = chunkIndex * 2 + ageIndex;
1024
950
  return (
@@ -1033,20 +959,18 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
1033
959
  selectedAge
1034
960
  )
1035
961
  }
1036
- ageRange={CHILD_CATEGORY_AGES}
962
+ ageRange={ageRange}
1037
963
  required
1038
964
  />
1039
965
  );
1040
966
  })}
1041
- </div>
967
+ </Fragment>
1042
968
  ))}
1043
969
 
1044
970
  {/* Infant ages */}
1045
971
  {internalData.infants > 0 &&
1046
972
  infantAgeChunks.map((chunk, chunkIndex) => (
1047
- <div
1048
- key={`infant-chunk-${chunkIndex}`}
1049
- className="pax-selector__age-row">
973
+ <Fragment key={`infant-chunk-${chunkIndex}`}>
1050
974
  {chunk.map((age, ageIndex) => {
1051
975
  const actualIndex = chunkIndex * 2 + ageIndex;
1052
976
  return (
@@ -1061,12 +985,12 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
1061
985
  selectedAge
1062
986
  )
1063
987
  }
1064
- ageRange={CHILD_CATEGORY_AGES}
988
+ ageRange={ageRange}
1065
989
  required
1066
990
  />
1067
991
  );
1068
992
  })}
1069
- </div>
993
+ </Fragment>
1070
994
  ))}
1071
995
  </>
1072
996
  );
@@ -62,6 +62,8 @@ export interface RoundTripProps {
62
62
  className?: string;
63
63
  /** Whether to check if inputs are empty */
64
64
  checkEmpty?: boolean;
65
+ /** Whether to scroll to the input when the calendar opens */
66
+ scrollOnOpen?: boolean;
65
67
  }
66
68
 
67
69
  const RoundTrip: React.FC<RoundTripProps> = ({
@@ -79,6 +81,7 @@ const RoundTrip: React.FC<RoundTripProps> = ({
79
81
  onChange,
80
82
  className = "",
81
83
  checkEmpty = false,
84
+ scrollOnOpen = false,
82
85
  }) => {
83
86
  const [internalPaxData, setInternalPaxData] = useState<PaxData | undefined>(
84
87
  paxData
@@ -299,6 +302,7 @@ const RoundTrip: React.FC<RoundTripProps> = ({
299
302
  onChange={handlePaxChange}
300
303
  placeholder="2 pax"
301
304
  className={isPaxEmpty ? 'pax-selector--error' : ''}
305
+ scrollOnOpen={scrollOnOpen}
302
306
  />
303
307
  </div>
304
308
 
@@ -318,6 +322,7 @@ const RoundTrip: React.FC<RoundTripProps> = ({
318
322
  defaultValue={internalArrivalDate && internalDepartureDate ? [internalArrivalDate, internalDepartureDate] : undefined}
319
323
  inputClassName="round-trip__date-picker--input"
320
324
  state={isDateEmpty ? 'error' : undefined}
325
+ scrollOnOpen={scrollOnOpen}
321
326
  />
322
327
  </div>
323
328
  <div className="round-trip__field round-trip__field--pickup-dropoff">
@@ -332,6 +337,7 @@ const RoundTrip: React.FC<RoundTripProps> = ({
332
337
  type="airport-port"
333
338
  showGroupTitles={true}
334
339
  error={isPickupDropoffEmpty}
340
+ scrollOnOpen={scrollOnOpen}
335
341
  />
336
342
  </div>
337
343
 
@@ -347,6 +353,7 @@ const RoundTrip: React.FC<RoundTripProps> = ({
347
353
  type="accommodation"
348
354
  showGroupTitles={false}
349
355
  error={isAccommodationEmpty}
356
+ scrollOnOpen={scrollOnOpen}
350
357
  />
351
358
  </div>
352
359
  </div>