mautourco-components 0.2.45 → 0.2.47

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 (39) hide show
  1. package/dist/components/atoms/Inputs/Input/Input.js +1 -1
  2. package/dist/components/molecules/AgeSelector/AgeSelector.d.ts +20 -0
  3. package/dist/components/molecules/AgeSelector/AgeSelector.js +84 -0
  4. package/dist/components/molecules/LocationDropdown/LocationDropdown.js +1 -1
  5. package/dist/components/organisms/PaxSelector/PaxSelector.d.ts +5 -0
  6. package/dist/components/organisms/PaxSelector/PaxSelector.js +100 -114
  7. package/dist/components/organisms/QuoteHeader/QuoteHeader.js +31 -6
  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/columns/booking-columns.js +1 -8
  13. package/dist/components/organisms/Table/columns/quotation-columns.js +1 -8
  14. package/dist/components/organisms/TransferLine/TransferLine.d.ts +9 -5
  15. package/dist/components/organisms/TransferLine/TransferLine.js +52 -35
  16. package/dist/index.d.ts +19 -16
  17. package/dist/index.js +3 -1
  18. package/dist/styles/components/molecule/age-selector.css +216 -0
  19. package/dist/styles/components/molecule/calendarInput.css +25 -6
  20. package/dist/styles/components/molecule/location-dropdown.css +16 -4
  21. package/dist/styles/components/organism/pax-selector.css +27 -189
  22. package/dist/styles/components/organism/transfer-line.css +40 -0
  23. package/dist/styles/mautourco.css +1 -0
  24. package/package.json +1 -1
  25. package/src/components/atoms/Inputs/Input/Input.tsx +1 -1
  26. package/src/components/molecules/AgeSelector/AgeSelector.tsx +172 -0
  27. package/src/components/molecules/LocationDropdown/LocationDropdown.tsx +1 -1
  28. package/src/components/organisms/PaxSelector/PaxSelector.tsx +132 -208
  29. package/src/components/organisms/QuoteHeader/QuoteHeader.tsx +37 -6
  30. package/src/components/organisms/RoundTrip/RoundTrip.tsx +7 -0
  31. package/src/components/organisms/SearchBarTransfer/SearchBarTransfer.tsx +34 -54
  32. package/src/components/organisms/Table/columns/booking-columns.tsx +1 -17
  33. package/src/components/organisms/Table/columns/quotation-columns.tsx +1 -17
  34. package/src/components/organisms/TransferLine/TransferLine.tsx +107 -85
  35. package/src/styles/components/molecule/age-selector.css +136 -0
  36. package/src/styles/components/molecule/calendarInput.css +12 -4
  37. package/src/styles/components/molecule/location-dropdown.css +9 -2
  38. package/src/styles/components/organism/pax-selector.css +25 -186
  39. package/src/styles/components/organism/transfer-line.css +31 -0
@@ -0,0 +1,172 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import '../../../styles/components/molecule/age-selector.css';
3
+ import Icon from '../../atoms/Icon/Icon';
4
+ import { Text } from '../../atoms/Typography/Typography';
5
+
6
+ export interface AgeSelectorProps {
7
+ /** Label for the selector */
8
+ label: string;
9
+ /** Current selected age value */
10
+ value: number | undefined;
11
+ /** Callback when age changes */
12
+ onChange: (age: number) => void;
13
+ /** Available age range */
14
+ ageRange: number[];
15
+ /** Whether the field is required */
16
+ required?: boolean;
17
+ /** Additional CSS classes */
18
+ className?: string;
19
+ /** Placeholder text */
20
+ placeholder?: string;
21
+ }
22
+
23
+ const AgeSelector: React.FC<AgeSelectorProps> = ({
24
+ label,
25
+ value,
26
+ onChange,
27
+ ageRange,
28
+ required = false,
29
+ className = '',
30
+ placeholder = '--',
31
+ }) => {
32
+ const [isOpen, setIsOpen] = useState(false);
33
+ const [inputValue, setInputValue] = useState<string>(
34
+ value !== undefined ? value.toString() : ''
35
+ );
36
+ const containerRef = useRef<HTMLDivElement>(null);
37
+ const inputRef = useRef<HTMLInputElement>(null);
38
+
39
+ // Sync input value when prop value changes
40
+ useEffect(() => {
41
+ setInputValue(value !== undefined ? value.toString() : '');
42
+ }, [value]);
43
+
44
+ useEffect(() => {
45
+ const handleClickOutside = (event: MouseEvent) => {
46
+ if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
47
+ setIsOpen(false);
48
+ }
49
+ };
50
+
51
+ if (isOpen) {
52
+ document.addEventListener('mousedown', handleClickOutside);
53
+ }
54
+
55
+ return () => {
56
+ document.removeEventListener('mousedown', handleClickOutside);
57
+ };
58
+ }, [isOpen]);
59
+
60
+ const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
61
+ const newValue = e.target.value;
62
+
63
+ // Only allow numeric input or empty string
64
+ if (newValue === '' || /^\d+$/.test(newValue)) {
65
+ setInputValue(newValue);
66
+
67
+ // Only update if it's a valid number within range
68
+ const numValue = parseInt(newValue, 10);
69
+ if (newValue === '') {
70
+ // Allow empty input - don't update onChange
71
+ return;
72
+ } else if (!isNaN(numValue) && ageRange.includes(numValue)) {
73
+ onChange(numValue);
74
+ }
75
+ }
76
+ };
77
+
78
+ const handleInputBlur = () => {
79
+ // Validate and set to valid value or clear if invalid
80
+ const numValue = parseInt(inputValue, 10);
81
+ if (inputValue === '') {
82
+ // Keep empty if user cleared it
83
+ return;
84
+ } else if (isNaN(numValue) || !ageRange.includes(numValue)) {
85
+ // Reset to current value if invalid
86
+ setInputValue(value !== undefined ? value.toString() : '');
87
+ } else {
88
+ // Ensure the input value matches the validated value
89
+ setInputValue(numValue.toString());
90
+ }
91
+ };
92
+
93
+ const handleInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
94
+ if (e.key === 'Enter') {
95
+ e.preventDefault();
96
+ inputRef.current?.blur();
97
+ }
98
+ };
99
+
100
+ const handleSelect = (age: string) => {
101
+ const numAge = parseInt(age, 10);
102
+ onChange(numAge);
103
+ setIsOpen(false);
104
+ setInputValue(age);
105
+ };
106
+
107
+ const handleDropdownToggle = () => {
108
+ setIsOpen(!isOpen);
109
+ };
110
+
111
+ const ageOptions = ageRange.map((age) => age.toString());
112
+
113
+ return (
114
+ <div className={`age-selector ${className}`} ref={containerRef}>
115
+ <Text size="sm" variant="regular" className="age-selector__label">
116
+ {label}
117
+ {required && <span className="age-selector__required"> *</span>}
118
+ </Text>
119
+ <div className="age-selector__container">
120
+ <div
121
+ className={`age-selector__input ${isOpen ? 'age-selector__input--open' : ''} ${value !== undefined ? 'age-selector__input--selected' : 'age-selector__input--default'}`}>
122
+ <input
123
+ ref={inputRef}
124
+ type="text"
125
+ inputMode="numeric"
126
+ className="age-selector__input-field"
127
+ value={inputValue}
128
+ onChange={handleInputChange}
129
+ onBlur={handleInputBlur}
130
+ onKeyDown={handleInputKeyDown}
131
+ onFocus={() => setIsOpen(false)}
132
+ placeholder={placeholder}
133
+ aria-label={`${label} age`}
134
+ />
135
+ <button
136
+ type="button"
137
+ className="age-selector__dropdown-btn"
138
+ onClick={(e) => {
139
+ e.preventDefault();
140
+ e.stopPropagation();
141
+ handleDropdownToggle();
142
+ }}
143
+ aria-expanded={isOpen}
144
+ aria-haspopup="listbox"
145
+ aria-label="Open age dropdown">
146
+ <Icon
147
+ name="chevron-down"
148
+ size="sm"
149
+ className={`age-selector__icon ${isOpen ? 'age-selector__icon--open' : ''}`}
150
+ />
151
+ </button>
152
+ </div>
153
+ {isOpen && (
154
+ <div className="age-selector__dropdown" role="listbox">
155
+ {ageOptions.map((age) => (
156
+ <div
157
+ key={age}
158
+ className={`age-selector__option ${value?.toString() === age ? 'age-selector__option--selected' : ''}`}
159
+ onClick={() => handleSelect(age)}
160
+ role="option"
161
+ aria-selected={value?.toString() === age}>
162
+ {age}
163
+ </div>
164
+ ))}
165
+ </div>
166
+ )}
167
+ </div>
168
+ </div>
169
+ );
170
+ };
171
+
172
+ export default AgeSelector;
@@ -189,7 +189,7 @@ const LocationDropdown: React.FC<LocationDropdownProps> = ({
189
189
  return (
190
190
  <div
191
191
  ref={dropdownRef}
192
- className={`location-dropdown location-dropdown--${type} ${className}`}>
192
+ className={`location-dropdown location-dropdown--${type} ${disabled ? 'location-dropdown--disabled' : ''} ${className}`}>
193
193
  {label && (
194
194
  <div className="location-dropdown__label">
195
195
  <Text size="sm" variant="medium">