mautourco-components 0.2.46 → 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.
- package/dist/components/molecules/AgeSelector/AgeSelector.d.ts +20 -0
- package/dist/components/molecules/AgeSelector/AgeSelector.js +84 -0
- package/dist/components/molecules/LocationDropdown/LocationDropdown.js +1 -1
- package/dist/components/organisms/PaxSelector/PaxSelector.d.ts +5 -0
- package/dist/components/organisms/PaxSelector/PaxSelector.js +100 -114
- package/dist/components/organisms/RoundTrip/RoundTrip.d.ts +2 -0
- package/dist/components/organisms/RoundTrip/RoundTrip.js +7 -7
- package/dist/components/organisms/SearchBarTransfer/SearchBarTransfer.d.ts +4 -0
- package/dist/components/organisms/SearchBarTransfer/SearchBarTransfer.js +19 -57
- package/dist/components/organisms/TransferLine/TransferLine.d.ts +9 -5
- package/dist/components/organisms/TransferLine/TransferLine.js +52 -35
- package/dist/index.d.ts +19 -16
- package/dist/index.js +3 -1
- package/dist/styles/components/molecule/age-selector.css +216 -0
- package/dist/styles/components/molecule/calendarInput.css +25 -6
- package/dist/styles/components/molecule/location-dropdown.css +16 -4
- package/dist/styles/components/organism/pax-selector.css +27 -189
- package/dist/styles/components/organism/transfer-line.css +40 -0
- package/dist/styles/mautourco.css +1 -0
- package/package.json +1 -1
- package/src/components/molecules/AgeSelector/AgeSelector.tsx +172 -0
- package/src/components/molecules/LocationDropdown/LocationDropdown.tsx +1 -1
- package/src/components/organisms/PaxSelector/PaxSelector.tsx +132 -208
- package/src/components/organisms/RoundTrip/RoundTrip.tsx +7 -0
- package/src/components/organisms/SearchBarTransfer/SearchBarTransfer.tsx +34 -54
- package/src/components/organisms/TransferLine/TransferLine.tsx +107 -85
- package/src/styles/components/molecule/age-selector.css +136 -0
- package/src/styles/components/molecule/calendarInput.css +12 -4
- package/src/styles/components/molecule/location-dropdown.css +9 -2
- package/src/styles/components/organism/pax-selector.css +25 -186
- package/src/styles/components/organism/transfer-line.css +31 -0
|
@@ -234,23 +234,42 @@
|
|
|
234
234
|
/* Disabled state */
|
|
235
235
|
|
|
236
236
|
.calendar-input--disabled {
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
cursor: not-allowed;
|
|
238
|
+
--tw-border-opacity: 1;
|
|
239
|
+
border-color: rgb(209 213 219 / var(--tw-border-opacity, 1));
|
|
240
|
+
--tw-bg-opacity: 1;
|
|
241
|
+
background-color: rgb(251 251 251 / var(--tw-bg-opacity, 1));
|
|
239
242
|
}
|
|
240
243
|
|
|
241
244
|
.calendar-input--disabled .calendar-input__field {
|
|
242
245
|
cursor: not-allowed;
|
|
243
|
-
|
|
246
|
+
--tw-text-opacity: 1;
|
|
247
|
+
color: rgb(163 163 163 / var(--tw-text-opacity, 1));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.calendar-input--disabled .calendar-input__field::placeholder {
|
|
251
|
+
--tw-text-opacity: 1;
|
|
252
|
+
color: rgb(163 163 163 / var(--tw-text-opacity, 1));
|
|
244
253
|
}
|
|
245
254
|
|
|
246
255
|
.calendar-input--disabled .calendar-input__icon-button {
|
|
256
|
+
cursor: not-allowed;
|
|
247
257
|
background-image: none !important;
|
|
248
|
-
|
|
258
|
+
--tw-text-opacity: 1 !important;
|
|
259
|
+
color: rgb(163 163 163 / var(--tw-text-opacity, 1)) !important;
|
|
249
260
|
}
|
|
250
261
|
|
|
251
262
|
.calendar-input--disabled .calendar-input__icon-button--full-bg {
|
|
252
|
-
|
|
253
|
-
|
|
263
|
+
cursor: not-allowed;
|
|
264
|
+
--tw-bg-opacity: 1 !important;
|
|
265
|
+
background-color: rgb(209 213 219 / var(--tw-bg-opacity, 1)) !important;
|
|
266
|
+
--tw-text-opacity: 1 !important;
|
|
267
|
+
color: rgb(163 163 163 / var(--tw-text-opacity, 1)) !important;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.calendar-input--disabled .calendar-input__chevron {
|
|
271
|
+
--tw-text-opacity: 1;
|
|
272
|
+
color: rgb(163 163 163 / var(--tw-text-opacity, 1));
|
|
254
273
|
}
|
|
255
274
|
|
|
256
275
|
/* Responsive design */
|
|
@@ -132,15 +132,27 @@
|
|
|
132
132
|
|
|
133
133
|
.location-dropdown__input--disabled {
|
|
134
134
|
cursor: not-allowed;
|
|
135
|
-
border-
|
|
136
|
-
|
|
137
|
-
opacity:
|
|
135
|
+
--tw-border-opacity: 1;
|
|
136
|
+
border-color: rgb(209 213 219 / var(--tw-border-opacity, 1));
|
|
137
|
+
--tw-bg-opacity: 1;
|
|
138
|
+
background-color: rgb(251 251 251 / var(--tw-bg-opacity, 1));
|
|
138
139
|
}
|
|
139
140
|
|
|
140
141
|
.location-dropdown__input--disabled .location-dropdown__input-text,
|
|
141
142
|
.location-dropdown__input--disabled .location-dropdown__input-icon,
|
|
142
143
|
.location-dropdown__input--disabled .location-dropdown__input-chevron {
|
|
143
|
-
|
|
144
|
+
--tw-text-opacity: 1;
|
|
145
|
+
color: rgb(163 163 163 / var(--tw-text-opacity, 1));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* Disabled label - override all text elements */
|
|
149
|
+
|
|
150
|
+
.location-dropdown--disabled .location-dropdown__label,
|
|
151
|
+
.location-dropdown--disabled .location-dropdown__label p,
|
|
152
|
+
.location-dropdown--disabled .location-dropdown__label * {
|
|
153
|
+
font-weight: 400 !important;
|
|
154
|
+
--tw-text-opacity: 1 !important;
|
|
155
|
+
color: rgb(163 163 163 / var(--tw-text-opacity, 1)) !important;
|
|
144
156
|
}
|
|
145
157
|
|
|
146
158
|
/* Dropdown Panel */
|
|
@@ -102,6 +102,31 @@
|
|
|
102
102
|
transform: rotate(180deg)!important;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
/* Disabled state */
|
|
106
|
+
|
|
107
|
+
.pax-selector--disabled .pax-selector__label {
|
|
108
|
+
color: #a3a3a3;
|
|
109
|
+
font-weight: 400;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.pax-selector--disabled .pax-selector__input {
|
|
113
|
+
background: #fbfbfb;
|
|
114
|
+
border-color: #d1d5db;
|
|
115
|
+
cursor: not-allowed;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.pax-selector--disabled .pax-selector__input-icon,
|
|
119
|
+
.pax-selector--disabled .pax-selector__input-text,
|
|
120
|
+
.pax-selector--disabled .pax-selector__chevron {
|
|
121
|
+
color: #a3a3a3;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.pax-selector__input--disabled {
|
|
125
|
+
background: #fbfbfb;
|
|
126
|
+
border-color: #d1d5db;
|
|
127
|
+
cursor: not-allowed;
|
|
128
|
+
}
|
|
129
|
+
|
|
105
130
|
/* Dropdown Panel */
|
|
106
131
|
|
|
107
132
|
.pax-selector__dropdown {
|
|
@@ -413,187 +438,6 @@
|
|
|
413
438
|
z-index: 50;
|
|
414
439
|
}
|
|
415
440
|
|
|
416
|
-
/* Age Selector Styles */
|
|
417
|
-
|
|
418
|
-
.pax-selector__age-selector {
|
|
419
|
-
display: flex;
|
|
420
|
-
flex-direction: column;
|
|
421
|
-
gap: 8px;
|
|
422
|
-
width: 80px;
|
|
423
|
-
position: relative;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
.pax-selector__age-label {
|
|
427
|
-
font-family: var(--typography-body-family, 'Satoshi', sans-serif);
|
|
428
|
-
font-weight: var(--font-weight-font-normal, 400);
|
|
429
|
-
font-size: 14px;
|
|
430
|
-
line-height: 20px;
|
|
431
|
-
color: var(--dropdown-color-label-default, #262626);
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
.pax-selector__age-required {
|
|
435
|
-
color: var(--chip-color-red-outline-foreground, #991b1b);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
/* Age Selector using DropdownInput structure */
|
|
439
|
-
|
|
440
|
-
.pax-selector__age-dropdown-container {
|
|
441
|
-
width: 100%;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
.pax-selector__age-dropdown-input {
|
|
445
|
-
min-height: auto;
|
|
446
|
-
padding: 12px 8px 12px 16px;
|
|
447
|
-
border: 1px solid var(--dropdown-color-border-value, #262626);
|
|
448
|
-
border-radius: 12px;
|
|
449
|
-
cursor: default;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
.pax-selector__age-dropdown-input:hover {
|
|
453
|
-
border-color: var(--dropdown-color-border-hover, #0f7173);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
.pax-selector__age-dropdown-input:focus-within {
|
|
457
|
-
border-color: var(--dropdown-color-border-hover, #0f7173);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
.pax-selector__age-input-text {
|
|
461
|
-
padding: 0;
|
|
462
|
-
background: transparent;
|
|
463
|
-
border: none;
|
|
464
|
-
outline: none;
|
|
465
|
-
font-family: var(--font-font-family-body, "Satoshi"), "Satoshi", "Inter", "Segoe UI", "system-ui", sans-serif;
|
|
466
|
-
font-weight: var(--font-weight-font-medium, 500);
|
|
467
|
-
font-size: 14px;
|
|
468
|
-
line-height: 20px;
|
|
469
|
-
color: var(--dropdown-color-foreground-value, #262626);
|
|
470
|
-
white-space: nowrap;
|
|
471
|
-
overflow: visible;
|
|
472
|
-
text-overflow: clip;
|
|
473
|
-
cursor: text;
|
|
474
|
-
width: 100%;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
.pax-selector__age-input-text::placeholder {
|
|
478
|
-
color: var(--dropdown-selector-color-filled-foreground-default, #737373);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
.pax-selector__age-dropdown-btn {
|
|
482
|
-
display: flex;
|
|
483
|
-
align-items: center;
|
|
484
|
-
justify-content: center;
|
|
485
|
-
padding: 0;
|
|
486
|
-
margin-left: 8px;
|
|
487
|
-
background: transparent;
|
|
488
|
-
border: none;
|
|
489
|
-
cursor: pointer;
|
|
490
|
-
transition: all 0.2s ease;
|
|
491
|
-
flex-shrink: 0;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
.pax-selector__age-dropdown-btn:hover {
|
|
495
|
-
opacity: 0.8;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
.pax-selector__age-dropdown-btn .dropdown-input__icon--chevron {
|
|
499
|
-
transition: transform 0.2s ease;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
.pax-selector__age-dropdown-input--open .pax-selector__age-dropdown-btn .dropdown-input__icon--chevron {
|
|
503
|
-
transform: rotate(180deg);
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
.pax-selector__age-trigger {
|
|
507
|
-
display: flex;
|
|
508
|
-
align-items: center;
|
|
509
|
-
justify-content: space-between;
|
|
510
|
-
gap: 8px;
|
|
511
|
-
width: 100%;
|
|
512
|
-
padding: 12px 16px;
|
|
513
|
-
background: var(--dropdown-color-background-value, #ffffff);
|
|
514
|
-
border: 1px solid var(--dropdown-color-border-value, #262626);
|
|
515
|
-
border-radius: 12px;
|
|
516
|
-
cursor: pointer;
|
|
517
|
-
font-family: var(--font-font-family-body, "Satoshi"), "Satoshi", "Inter", "Segoe UI", "system-ui", sans-serif;
|
|
518
|
-
font-weight: var(--font-weight-font-medium, 500);
|
|
519
|
-
font-size: 14px;
|
|
520
|
-
line-height: 20px;
|
|
521
|
-
color: var(--dropdown-color-foreground-value, #262626);
|
|
522
|
-
transition: all 0.2s ease;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
.pax-selector__age-trigger:hover {
|
|
526
|
-
border-color: var(--dropdown-color-border-hover, #0f7173);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
.pax-selector__age-value {
|
|
530
|
-
flex: 1;
|
|
531
|
-
text-align: left;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
.pax-selector__age-chevron {
|
|
535
|
-
color: var(--color-text-default, #262626);
|
|
536
|
-
transition: transform 0.2s ease;
|
|
537
|
-
flex-shrink: 0;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
.pax-selector__age-chevron--open {
|
|
541
|
-
transform: rotate(180deg);
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
/* Use dropdown-menu from dropdown.css, but add custom styles for age selector */
|
|
545
|
-
|
|
546
|
-
.pax-selector__age-dropdown-container .dropdown-menu {
|
|
547
|
-
max-height: 200px;
|
|
548
|
-
z-index: 110;
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
.pax-selector__age-dropdown-container .dropdown-option--selected {
|
|
552
|
-
background-color: var(--dropdown-selector-color-select-item-background-selected, #0f7173);
|
|
553
|
-
color: #ffffff;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
.pax-selector__age-dropdown-container .dropdown-option--selected:hover {
|
|
557
|
-
background-color: var(--dropdown-selector-color-select-item-background-selected, #0f7173);
|
|
558
|
-
color: #ffffff;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
@keyframes pax-selector-age-dropdown-enter {
|
|
562
|
-
from {
|
|
563
|
-
opacity: 0;
|
|
564
|
-
transform: translateY(-4px);
|
|
565
|
-
}
|
|
566
|
-
to {
|
|
567
|
-
opacity: 1;
|
|
568
|
-
transform: translateY(0);
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
.pax-selector__age-option {
|
|
573
|
-
width: 100%;
|
|
574
|
-
padding: 8px 12px;
|
|
575
|
-
background: var(--dropdown-selector-color-select-item-background-default, #ffffff);
|
|
576
|
-
border: none;
|
|
577
|
-
cursor: pointer;
|
|
578
|
-
text-align: left;
|
|
579
|
-
font-family: var(--font-font-family-body, "Satoshi"), "Satoshi", "Inter", "Segoe UI", "system-ui", sans-serif;
|
|
580
|
-
font-weight: 400;
|
|
581
|
-
font-size: 14px;
|
|
582
|
-
line-height: 20px;
|
|
583
|
-
color: var(--color-text-default, #262626);
|
|
584
|
-
transition: all 0.2s ease;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
.pax-selector__age-option:hover {
|
|
588
|
-
background: var(--dropdown-selector-color-select-item-background-hover, #115b5e);
|
|
589
|
-
color: #ffffff;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
.pax-selector__age-option--selected {
|
|
593
|
-
background: var(--dropdown-selector-color-select-item-background-selected, #0f7173);
|
|
594
|
-
color: #ffffff;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
441
|
/* Age Section */
|
|
598
442
|
|
|
599
443
|
.pax-selector__age-section {
|
|
@@ -610,14 +454,8 @@
|
|
|
610
454
|
|
|
611
455
|
.pax-selector__age-groups {
|
|
612
456
|
display: flex;
|
|
613
|
-
flex-
|
|
614
|
-
gap:
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
.pax-selector__age-row {
|
|
618
|
-
display: flex;
|
|
619
|
-
gap: 16px;
|
|
620
|
-
align-items: flex-start;
|
|
457
|
+
flex-wrap: wrap;
|
|
458
|
+
gap: 1rem;
|
|
621
459
|
}
|
|
622
460
|
|
|
623
461
|
/* Multiple Rooms Styles */
|
|
@@ -137,4 +137,44 @@
|
|
|
137
137
|
|
|
138
138
|
.transfer-line__date-picker {
|
|
139
139
|
height: 2.75rem;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* Disabled state */
|
|
143
|
+
|
|
144
|
+
.transfer-line--disabled {
|
|
145
|
+
pointer-events: none;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.transfer-line--disabled .transfer-line__field-label {
|
|
149
|
+
font-weight: 400;
|
|
150
|
+
--tw-text-opacity: 1;
|
|
151
|
+
color: rgb(163 163 163 / var(--tw-text-opacity, 1));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* Match Figma design colors for disabled inputs */
|
|
155
|
+
|
|
156
|
+
.transfer-line--disabled .location-dropdown__input,
|
|
157
|
+
.transfer-line--disabled .calendar-input,
|
|
158
|
+
.transfer-line--disabled .pax-selector__input {
|
|
159
|
+
--tw-border-opacity: 1;
|
|
160
|
+
border-color: rgb(209 213 219 / var(--tw-border-opacity, 1));
|
|
161
|
+
--tw-bg-opacity: 1;
|
|
162
|
+
background-color: rgb(251 251 251 / var(--tw-bg-opacity, 1));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.transfer-line--disabled .location-dropdown__label,
|
|
166
|
+
.transfer-line--disabled .location-dropdown__label p,
|
|
167
|
+
.transfer-line--disabled .location-dropdown__input-text,
|
|
168
|
+
.transfer-line--disabled .location-dropdown__input-icon,
|
|
169
|
+
.transfer-line--disabled .location-dropdown__input-chevron,
|
|
170
|
+
.transfer-line--disabled .calendar-input__field,
|
|
171
|
+
.transfer-line--disabled .calendar-input__icon-button,
|
|
172
|
+
.transfer-line--disabled .calendar-input__chevron,
|
|
173
|
+
.transfer-line--disabled .pax-selector__input-icon,
|
|
174
|
+
.transfer-line--disabled .pax-selector__input-text,
|
|
175
|
+
.transfer-line--disabled .pax-selector__chevron,
|
|
176
|
+
.transfer-line--disabled .pax-selector__label {
|
|
177
|
+
font-weight: 400 !important;
|
|
178
|
+
--tw-text-opacity: 1 !important;
|
|
179
|
+
color: rgb(163 163 163 / var(--tw-text-opacity, 1)) !important;
|
|
140
180
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
@import "./components/forms.css";
|
|
11
11
|
@import "./components/illustration.css";
|
|
12
12
|
@import "./components/molecule/accomodation-docket.css";
|
|
13
|
+
@import "./components/molecule/age-selector.css";
|
|
13
14
|
@import "./components/molecule/calendarInput.css";
|
|
14
15
|
@import "./components/molecule/dateTime.css";
|
|
15
16
|
@import "./components/molecule/docket-prices.css";
|
package/package.json
CHANGED
|
@@ -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">
|