@ecohouse/ui 0.1.24 → 0.1.26
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/index.cjs +207 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -1
- package/dist/index.d.ts +35 -1
- package/dist/index.js +207 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/DatePicker/DatePicker.stories.tsx +34 -0
- package/src/components/DatePicker/DatePicker.tsx +165 -11
- package/src/components/DatePicker/index.ts +1 -0
- package/src/components/SegmentedToggle/SegmentedToggle.stories.tsx +48 -1
- package/src/components/SegmentedToggle/SegmentedToggle.tsx +63 -23
- package/src/components/index.ts +1 -0
- package/src/index.ts +1 -0
- package/src/theme/colors.ts +1 -0
- package/src/theme/typography.ts +21 -0
package/package.json
CHANGED
|
@@ -68,6 +68,40 @@ export const RangeInProgress: Story = {
|
|
|
68
68
|
},
|
|
69
69
|
};
|
|
70
70
|
|
|
71
|
+
const bookingRange = {
|
|
72
|
+
start: new Date(2026, 7, 15),
|
|
73
|
+
end: new Date(2026, 7, 15),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const formatBookingDate = (date: Date) =>
|
|
77
|
+
`${String(date.getDate()).padStart(2, "0")}/${String(date.getMonth() + 1).padStart(2, "0")}/${date.getFullYear()}`;
|
|
78
|
+
|
|
79
|
+
export const RangeHorizontal: Story = {
|
|
80
|
+
args: {
|
|
81
|
+
range: true,
|
|
82
|
+
variant: "range-horizontal",
|
|
83
|
+
startLabel: "ՄՈՒՏՔ",
|
|
84
|
+
endLabel: "ԵԼՔ",
|
|
85
|
+
startTime: "10:00",
|
|
86
|
+
endTime: "22:00",
|
|
87
|
+
defaultValue: bookingRange,
|
|
88
|
+
formatValue: formatBookingDate,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export const RangeVertical: Story = {
|
|
93
|
+
args: {
|
|
94
|
+
range: true,
|
|
95
|
+
variant: "range-vertical",
|
|
96
|
+
startLabel: "ՄՈՒՏՔ",
|
|
97
|
+
endLabel: "ԵԼՔ",
|
|
98
|
+
startTime: "10:00",
|
|
99
|
+
endTime: "22:00",
|
|
100
|
+
defaultValue: bookingRange,
|
|
101
|
+
formatValue: formatBookingDate,
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
|
|
71
105
|
export const MinMaxDate: Story = {
|
|
72
106
|
args: {
|
|
73
107
|
defaultOpen: true,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
type ViewProps,
|
|
18
18
|
type ViewStyle,
|
|
19
19
|
} from "react-native";
|
|
20
|
-
import { CalendarOutlineIcon, ChevronLeftIcon } from "../../icons";
|
|
20
|
+
import { CalendarOutlineIcon, ChevronLeftIcon, ClockFilledIcon } from "../../icons";
|
|
21
21
|
import { colors, datePickerTypography } from "../../theme";
|
|
22
22
|
import {
|
|
23
23
|
addMonths,
|
|
@@ -52,11 +52,23 @@ const DEFAULT_MONTH_NAMES = [
|
|
|
52
52
|
const DEFAULT_WEEKDAY_LABELS = ["ԵՐ", "ԵՔ", "ՉՐ", "ՀՆ", "ՈՒՐ", "ՇԲ", "ԿՐ"];
|
|
53
53
|
|
|
54
54
|
export type DateRange = { start: Date | null; end: Date | null };
|
|
55
|
+
export type DatePickerVariant = "default" | "range-horizontal" | "range-vertical";
|
|
55
56
|
|
|
56
57
|
const EMPTY_RANGE: DateRange = { start: null, end: null };
|
|
57
58
|
|
|
58
59
|
type DatePickerBaseProps = Omit<ViewProps, "style" | "children"> & {
|
|
59
60
|
placeholder?: string;
|
|
61
|
+
/** Trigger presentation. Range variants display separate start/end fields. */
|
|
62
|
+
variant?: DatePickerVariant;
|
|
63
|
+
/** Labels shown above the start/end values in range trigger variants. */
|
|
64
|
+
startLabel?: string;
|
|
65
|
+
endLabel?: string;
|
|
66
|
+
/** Optional supplementary times shown beside the start/end dates. */
|
|
67
|
+
startTime?: string;
|
|
68
|
+
endTime?: string;
|
|
69
|
+
/** Per-field placeholders used by range trigger variants. */
|
|
70
|
+
startPlaceholder?: string;
|
|
71
|
+
endPlaceholder?: string;
|
|
60
72
|
open?: boolean;
|
|
61
73
|
defaultOpen?: boolean;
|
|
62
74
|
onOpenChange?: (open: boolean) => void;
|
|
@@ -101,6 +113,7 @@ export type DatePickerRangeProps = DatePickerBaseProps & {
|
|
|
101
113
|
export type DatePickerProps = DatePickerSingleProps | DatePickerRangeProps;
|
|
102
114
|
|
|
103
115
|
const DEFAULT_WIDTH = 380;
|
|
116
|
+
const RANGE_TRIGGER_WIDTH = 382;
|
|
104
117
|
const TRIGGER_HEIGHT = 44;
|
|
105
118
|
const TRIGGER_RADIUS = 60;
|
|
106
119
|
const MENU_RADIUS = 20;
|
|
@@ -109,10 +122,46 @@ const NAV_ICON_SIZE = 20;
|
|
|
109
122
|
const DAY_CELL_HEIGHT = 44;
|
|
110
123
|
const DAY_CIRCLE_SIZE = 44;
|
|
111
124
|
|
|
125
|
+
function RangeTriggerField({
|
|
126
|
+
label,
|
|
127
|
+
value,
|
|
128
|
+
time,
|
|
129
|
+
}: {
|
|
130
|
+
label: string;
|
|
131
|
+
value: string;
|
|
132
|
+
time?: string;
|
|
133
|
+
}) {
|
|
134
|
+
return (
|
|
135
|
+
<View style={styles.rangeField}>
|
|
136
|
+
<Text numberOfLines={1} style={styles.rangeLabel}>
|
|
137
|
+
{label}
|
|
138
|
+
</Text>
|
|
139
|
+
<View style={styles.rangeValueRow}>
|
|
140
|
+
<Text numberOfLines={1} style={styles.rangeDate}>
|
|
141
|
+
{value}
|
|
142
|
+
</Text>
|
|
143
|
+
{time ? (
|
|
144
|
+
<View style={styles.rangeTimeWrap}>
|
|
145
|
+
<ClockFilledIcon color={colors.lightGrey} size={16} />
|
|
146
|
+
<Text style={styles.rangeTime}>{time}</Text>
|
|
147
|
+
</View>
|
|
148
|
+
) : null}
|
|
149
|
+
</View>
|
|
150
|
+
</View>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
112
154
|
export const DatePicker = forwardRef<ComponentRef<typeof View>, DatePickerProps>(
|
|
113
155
|
function DatePicker(props, forwardedRef) {
|
|
114
156
|
const {
|
|
115
157
|
placeholder = "Select date",
|
|
158
|
+
variant = "default",
|
|
159
|
+
startLabel = "Start",
|
|
160
|
+
endLabel = "End",
|
|
161
|
+
startTime,
|
|
162
|
+
endTime,
|
|
163
|
+
startPlaceholder = placeholder,
|
|
164
|
+
endPlaceholder = placeholder,
|
|
116
165
|
open: openProp,
|
|
117
166
|
defaultOpen = false,
|
|
118
167
|
onOpenChange,
|
|
@@ -298,8 +347,18 @@ export const DatePicker = forwardRef<ComponentRef<typeof View>, DatePickerProps>
|
|
|
298
347
|
? formatValue(singleValue)
|
|
299
348
|
: placeholder;
|
|
300
349
|
|
|
301
|
-
const
|
|
350
|
+
const usesRangeTrigger = isRange && variant !== "default";
|
|
351
|
+
const usesVerticalRangeTrigger = usesRangeTrigger && variant === "range-vertical";
|
|
352
|
+
const triggerBorderColor = usesRangeTrigger
|
|
353
|
+
? isOpen
|
|
354
|
+
? colors.primary
|
|
355
|
+
: colors.grey500
|
|
356
|
+
: isOpen
|
|
357
|
+
? colors.primaryMuted
|
|
358
|
+
: colors.grey700;
|
|
302
359
|
const triggerTextColor = hasValue ? colors.white : colors.grey100;
|
|
360
|
+
const startValue = rangeValue.start ? formatValue(rangeValue.start) : startPlaceholder;
|
|
361
|
+
const endValue = rangeValue.end ? formatValue(rangeValue.end) : endPlaceholder;
|
|
303
362
|
|
|
304
363
|
const resolvedAccessibilityLabel = accessibilityLabel ?? placeholder;
|
|
305
364
|
|
|
@@ -307,7 +366,13 @@ export const DatePicker = forwardRef<ComponentRef<typeof View>, DatePickerProps>
|
|
|
307
366
|
<View
|
|
308
367
|
{...rest}
|
|
309
368
|
ref={setRootRef}
|
|
310
|
-
style={[
|
|
369
|
+
style={[
|
|
370
|
+
styles.root,
|
|
371
|
+
usesRangeTrigger && styles.rangeRoot,
|
|
372
|
+
isOpen && styles.rootOpen,
|
|
373
|
+
disabled && styles.disabled,
|
|
374
|
+
style,
|
|
375
|
+
]}
|
|
311
376
|
accessibilityState={{ disabled, expanded: isOpen }}
|
|
312
377
|
>
|
|
313
378
|
<View style={[styles.triggerWrap, isOpen && styles.triggerWrapOpen]}>
|
|
@@ -320,19 +385,43 @@ export const DatePicker = forwardRef<ComponentRef<typeof View>, DatePickerProps>
|
|
|
320
385
|
accessibilityState={{ disabled, expanded: isOpen }}
|
|
321
386
|
style={[
|
|
322
387
|
styles.trigger,
|
|
323
|
-
|
|
388
|
+
usesRangeTrigger && styles.rangeTrigger,
|
|
389
|
+
usesRangeTrigger &&
|
|
390
|
+
(usesVerticalRangeTrigger
|
|
391
|
+
? styles.rangeTriggerVertical
|
|
392
|
+
: styles.rangeTriggerHorizontal),
|
|
393
|
+
{
|
|
394
|
+
borderColor: triggerBorderColor,
|
|
395
|
+
backgroundColor: usesRangeTrigger ? colors.grey800 : colors.grey700,
|
|
396
|
+
},
|
|
324
397
|
]}
|
|
325
398
|
>
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
399
|
+
{usesRangeTrigger ? (
|
|
400
|
+
<>
|
|
401
|
+
<RangeTriggerField label={startLabel} time={startTime} value={startValue} />
|
|
402
|
+
<View
|
|
403
|
+
style={
|
|
404
|
+
usesVerticalRangeTrigger
|
|
405
|
+
? styles.rangeDividerVertical
|
|
406
|
+
: styles.rangeDividerHorizontal
|
|
407
|
+
}
|
|
408
|
+
/>
|
|
409
|
+
<RangeTriggerField label={endLabel} time={endTime} value={endValue} />
|
|
410
|
+
</>
|
|
411
|
+
) : (
|
|
412
|
+
<>
|
|
413
|
+
<Text style={[styles.triggerText, { color: triggerTextColor }]} numberOfLines={1}>
|
|
414
|
+
{triggerLabel}
|
|
415
|
+
</Text>
|
|
416
|
+
<View style={styles.iconSlot}>
|
|
417
|
+
<CalendarOutlineIcon size={ICON_SIZE} color={colors.grey100} />
|
|
418
|
+
</View>
|
|
419
|
+
</>
|
|
420
|
+
)}
|
|
332
421
|
</Pressable>
|
|
333
422
|
|
|
334
423
|
{isOpen ? (
|
|
335
|
-
<View style={[styles.menu, calendarStyle]}>
|
|
424
|
+
<View style={[styles.menu, usesRangeTrigger && styles.rangeMenu, calendarStyle]}>
|
|
336
425
|
<View style={styles.calendarHeader}>
|
|
337
426
|
<Pressable
|
|
338
427
|
onPress={handlePrevMonth}
|
|
@@ -502,6 +591,9 @@ const styles = StyleSheet.create({
|
|
|
502
591
|
rootOpen: {
|
|
503
592
|
zIndex: 30,
|
|
504
593
|
},
|
|
594
|
+
rangeRoot: {
|
|
595
|
+
width: RANGE_TRIGGER_WIDTH,
|
|
596
|
+
},
|
|
505
597
|
disabled: {
|
|
506
598
|
opacity: 0.6,
|
|
507
599
|
},
|
|
@@ -528,6 +620,65 @@ const styles = StyleSheet.create({
|
|
|
528
620
|
flex: 1,
|
|
529
621
|
minWidth: 0,
|
|
530
622
|
},
|
|
623
|
+
rangeTrigger: {
|
|
624
|
+
paddingVertical: 0,
|
|
625
|
+
paddingHorizontal: 0,
|
|
626
|
+
borderRadius: 15,
|
|
627
|
+
gap: 0,
|
|
628
|
+
},
|
|
629
|
+
rangeTriggerHorizontal: {
|
|
630
|
+
height: 78,
|
|
631
|
+
flexDirection: "row",
|
|
632
|
+
},
|
|
633
|
+
rangeTriggerVertical: {
|
|
634
|
+
height: 156,
|
|
635
|
+
flexDirection: "column",
|
|
636
|
+
},
|
|
637
|
+
rangeField: {
|
|
638
|
+
flex: 1,
|
|
639
|
+
alignSelf: "stretch",
|
|
640
|
+
minWidth: 0,
|
|
641
|
+
justifyContent: "center",
|
|
642
|
+
gap: 8,
|
|
643
|
+
paddingVertical: 12,
|
|
644
|
+
paddingHorizontal: 16,
|
|
645
|
+
},
|
|
646
|
+
rangeLabel: {
|
|
647
|
+
...datePickerTypography.rangeLabel,
|
|
648
|
+
color: colors.whiteAlpha60,
|
|
649
|
+
},
|
|
650
|
+
rangeValueRow: {
|
|
651
|
+
minWidth: 0,
|
|
652
|
+
flexDirection: "row",
|
|
653
|
+
alignItems: "center",
|
|
654
|
+
justifyContent: "space-between",
|
|
655
|
+
gap: 12,
|
|
656
|
+
},
|
|
657
|
+
rangeDate: {
|
|
658
|
+
...datePickerTypography.rangeDate,
|
|
659
|
+
flexShrink: 1,
|
|
660
|
+
color: colors.white,
|
|
661
|
+
},
|
|
662
|
+
rangeTimeWrap: {
|
|
663
|
+
flexShrink: 0,
|
|
664
|
+
flexDirection: "row",
|
|
665
|
+
alignItems: "center",
|
|
666
|
+
gap: 3,
|
|
667
|
+
},
|
|
668
|
+
rangeTime: {
|
|
669
|
+
...datePickerTypography.rangeTime,
|
|
670
|
+
color: colors.lightGrey,
|
|
671
|
+
},
|
|
672
|
+
rangeDividerHorizontal: {
|
|
673
|
+
width: 1,
|
|
674
|
+
alignSelf: "stretch",
|
|
675
|
+
backgroundColor: colors.grey500,
|
|
676
|
+
},
|
|
677
|
+
rangeDividerVertical: {
|
|
678
|
+
height: 1,
|
|
679
|
+
alignSelf: "stretch",
|
|
680
|
+
backgroundColor: colors.grey500,
|
|
681
|
+
},
|
|
531
682
|
iconSlot: {
|
|
532
683
|
width: ICON_SIZE,
|
|
533
684
|
height: ICON_SIZE,
|
|
@@ -555,6 +706,9 @@ const styles = StyleSheet.create({
|
|
|
555
706
|
},
|
|
556
707
|
}),
|
|
557
708
|
},
|
|
709
|
+
rangeMenu: {
|
|
710
|
+
width: RANGE_TRIGGER_WIDTH,
|
|
711
|
+
},
|
|
558
712
|
calendarHeader: {
|
|
559
713
|
height: 36,
|
|
560
714
|
flexDirection: "row",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
3
3
|
import { StyleSheet, View } from "react-native";
|
|
4
|
-
import { LayoutGridIcon } from "../../icons";
|
|
4
|
+
import { LayoutGridIcon, ListViewIcon, MapViewIcon } from "../../icons";
|
|
5
5
|
import { SegmentedToggle } from "./SegmentedToggle";
|
|
6
6
|
|
|
7
7
|
const optionsWithIcons = [
|
|
@@ -14,6 +14,21 @@ const optionsWithoutIcons = [
|
|
|
14
14
|
{ value: "second", label: "Label" },
|
|
15
15
|
] as const;
|
|
16
16
|
|
|
17
|
+
const multilingualOptions = [
|
|
18
|
+
{ value: "daily", label: "Օրավարձ" },
|
|
19
|
+
{ value: "overnight", label: "Գիշերակաց երկար տարբերակ" },
|
|
20
|
+
] as const;
|
|
21
|
+
|
|
22
|
+
const multilingualIconOptions = [
|
|
23
|
+
{ value: "list", label: "Ցուցակի տարբերակ", icon: LayoutGridIcon },
|
|
24
|
+
{ value: "map", label: "Քարտեզի շատ երկար տարբերակ", icon: LayoutGridIcon },
|
|
25
|
+
] as const;
|
|
26
|
+
|
|
27
|
+
const armenianViewOptions = [
|
|
28
|
+
{ value: "list", label: "Ցանկ", icon: ListViewIcon },
|
|
29
|
+
{ value: "map", label: "Քարտեզ", icon: MapViewIcon },
|
|
30
|
+
] as const;
|
|
31
|
+
|
|
17
32
|
const meta = {
|
|
18
33
|
title: "Components/SegmentedToggle",
|
|
19
34
|
component: SegmentedToggle,
|
|
@@ -39,6 +54,38 @@ export const ContentWidth: Story = {
|
|
|
39
54
|
args: { fullWidth: false },
|
|
40
55
|
};
|
|
41
56
|
|
|
57
|
+
export const MultilingualContentWidth: Story = {
|
|
58
|
+
args: {
|
|
59
|
+
options: multilingualOptions,
|
|
60
|
+
defaultValue: "daily",
|
|
61
|
+
fullWidth: false,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const MultilingualIconsContentWidth: Story = {
|
|
66
|
+
args: {
|
|
67
|
+
options: multilingualIconOptions,
|
|
68
|
+
defaultValue: "list",
|
|
69
|
+
fullWidth: false,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const ArmenianViewMode: Story = {
|
|
74
|
+
args: {
|
|
75
|
+
options: armenianViewOptions,
|
|
76
|
+
defaultValue: "list",
|
|
77
|
+
fullWidth: false,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const ArmenianViewModeMapSelected: Story = {
|
|
82
|
+
args: {
|
|
83
|
+
options: armenianViewOptions,
|
|
84
|
+
defaultValue: "map",
|
|
85
|
+
fullWidth: false,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
42
89
|
export const In400PixelContainer: Story = {
|
|
43
90
|
render: () => (
|
|
44
91
|
<View style={storyStyles.container}>
|
|
@@ -37,7 +37,9 @@ export interface SegmentedToggleProps extends Omit<ViewProps, "style" | "childre
|
|
|
37
37
|
const ICON_SIZE = 20;
|
|
38
38
|
const ANIMATION_DURATION = 200;
|
|
39
39
|
const OPTION_HORIZONTAL_PADDING = 16;
|
|
40
|
+
const OPTION_CONTENT_GAP = 12;
|
|
40
41
|
const OPTION_MIN_WIDTH = 97;
|
|
42
|
+
const OPTION_MEASUREMENT_TOLERANCE = 0.5;
|
|
41
43
|
|
|
42
44
|
export const SegmentedToggle = forwardRef<ComponentRef<typeof View>, SegmentedToggleProps>(
|
|
43
45
|
function SegmentedToggle(
|
|
@@ -70,15 +72,20 @@ export const SegmentedToggle = forwardRef<ComponentRef<typeof View>, SegmentedTo
|
|
|
70
72
|
const [contentWidths, setContentWidths] = useState<[number, number]>([0, 0]);
|
|
71
73
|
const [containerWidth, setContainerWidth] = useState(0);
|
|
72
74
|
const availableOptionWidth = Math.max(0, (containerWidth - 12) / 2);
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
const resolveContentOptionWidth = (contentWidth: number) =>
|
|
76
|
+
contentWidth > 0
|
|
77
|
+
? Math.max(
|
|
78
|
+
OPTION_MIN_WIDTH,
|
|
79
|
+
contentWidth + OPTION_HORIZONTAL_PADDING * 2 + OPTION_MEASUREMENT_TOLERANCE,
|
|
80
|
+
)
|
|
77
81
|
: 0;
|
|
78
|
-
const
|
|
82
|
+
const optionWidths: [number, number] = fullWidth
|
|
83
|
+
? [availableOptionWidth, availableOptionWidth]
|
|
84
|
+
: [resolveContentOptionWidth(contentWidths[0]), resolveContentOptionWidth(contentWidths[1])];
|
|
85
|
+
const selectedOptionWidth = optionWidths[selectedIndex];
|
|
79
86
|
const indicatorTranslateX = progress.interpolate({
|
|
80
87
|
inputRange: [0, 1],
|
|
81
|
-
outputRange: [0,
|
|
88
|
+
outputRange: [0, optionWidths[0] + 4],
|
|
82
89
|
});
|
|
83
90
|
|
|
84
91
|
useApplyWebClassName(containerRef, resolvedClassName);
|
|
@@ -120,12 +127,36 @@ export const SegmentedToggle = forwardRef<ComponentRef<typeof View>, SegmentedTo
|
|
|
120
127
|
]}
|
|
121
128
|
accessibilityRole="radiogroup"
|
|
122
129
|
>
|
|
123
|
-
{
|
|
130
|
+
{!fullWidth
|
|
131
|
+
? options.map(({ value: optionValue, label, icon: Icon }, index) => (
|
|
132
|
+
<View
|
|
133
|
+
key={`${optionValue}-measurement`}
|
|
134
|
+
pointerEvents="none"
|
|
135
|
+
aria-hidden
|
|
136
|
+
accessibilityElementsHidden
|
|
137
|
+
importantForAccessibility="no-hide-descendants"
|
|
138
|
+
onLayout={(event) => {
|
|
139
|
+
const nextWidth = event.nativeEvent.layout.width;
|
|
140
|
+
setContentWidths((currentWidths) => {
|
|
141
|
+
if (currentWidths[index] === nextWidth) return currentWidths;
|
|
142
|
+
const nextWidths: [number, number] = [currentWidths[0], currentWidths[1]];
|
|
143
|
+
nextWidths[index] = nextWidth;
|
|
144
|
+
return nextWidths;
|
|
145
|
+
});
|
|
146
|
+
}}
|
|
147
|
+
style={styles.optionMeasurement}
|
|
148
|
+
>
|
|
149
|
+
{Icon ? <Icon size={ICON_SIZE} /> : null}
|
|
150
|
+
<Text style={[styles.label, styles.contentWidthLabel]}>{label}</Text>
|
|
151
|
+
</View>
|
|
152
|
+
))
|
|
153
|
+
: null}
|
|
154
|
+
{selectedOptionWidth > 0 ? (
|
|
124
155
|
<Animated.View
|
|
125
156
|
pointerEvents="none"
|
|
126
157
|
style={[
|
|
127
158
|
styles.activeIndicator,
|
|
128
|
-
{ width:
|
|
159
|
+
{ width: selectedOptionWidth, transform: [{ translateX: indicatorTranslateX }] },
|
|
129
160
|
]}
|
|
130
161
|
/>
|
|
131
162
|
) : null}
|
|
@@ -147,23 +178,22 @@ export const SegmentedToggle = forwardRef<ComponentRef<typeof View>, SegmentedTo
|
|
|
147
178
|
styles.option,
|
|
148
179
|
fullWidth
|
|
149
180
|
? styles.optionFullWidth
|
|
150
|
-
: [
|
|
181
|
+
: [
|
|
182
|
+
styles.optionContentWidth,
|
|
183
|
+
optionWidths[index] > 0 && { width: optionWidths[index] },
|
|
184
|
+
],
|
|
151
185
|
]}
|
|
152
186
|
>
|
|
153
|
-
<View
|
|
154
|
-
onLayout={(event) => {
|
|
155
|
-
const nextWidth = event.nativeEvent.layout.width;
|
|
156
|
-
setContentWidths((currentWidths) => {
|
|
157
|
-
if (currentWidths[index] === nextWidth) return currentWidths;
|
|
158
|
-
const nextWidths: [number, number] = [currentWidths[0], currentWidths[1]];
|
|
159
|
-
nextWidths[index] = nextWidth;
|
|
160
|
-
return nextWidths;
|
|
161
|
-
});
|
|
162
|
-
}}
|
|
163
|
-
style={styles.optionContent}
|
|
164
|
-
>
|
|
187
|
+
<View style={styles.optionContent}>
|
|
165
188
|
{Icon ? <Icon size={ICON_SIZE} color={iconColor} /> : null}
|
|
166
|
-
<Text
|
|
189
|
+
<Text
|
|
190
|
+
numberOfLines={fullWidth ? 1 : undefined}
|
|
191
|
+
style={[
|
|
192
|
+
styles.label,
|
|
193
|
+
!fullWidth && styles.contentWidthLabel,
|
|
194
|
+
{ color: labelColor },
|
|
195
|
+
]}
|
|
196
|
+
>
|
|
167
197
|
{label}
|
|
168
198
|
</Text>
|
|
169
199
|
</View>
|
|
@@ -207,7 +237,14 @@ const styles = StyleSheet.create({
|
|
|
207
237
|
maxWidth: "100%",
|
|
208
238
|
flexDirection: "row",
|
|
209
239
|
alignItems: "center",
|
|
210
|
-
gap:
|
|
240
|
+
gap: OPTION_CONTENT_GAP,
|
|
241
|
+
},
|
|
242
|
+
optionMeasurement: {
|
|
243
|
+
position: "absolute",
|
|
244
|
+
flexDirection: "row",
|
|
245
|
+
alignItems: "center",
|
|
246
|
+
gap: OPTION_CONTENT_GAP,
|
|
247
|
+
opacity: 0,
|
|
211
248
|
},
|
|
212
249
|
optionFullWidth: {
|
|
213
250
|
flex: 1,
|
|
@@ -228,4 +265,7 @@ const styles = StyleSheet.create({
|
|
|
228
265
|
...segmentedToggleTypography,
|
|
229
266
|
flexShrink: 1,
|
|
230
267
|
},
|
|
268
|
+
contentWidthLabel: {
|
|
269
|
+
flexShrink: 0,
|
|
270
|
+
},
|
|
231
271
|
});
|
package/src/components/index.ts
CHANGED
package/src/index.ts
CHANGED
package/src/theme/colors.ts
CHANGED
package/src/theme/typography.ts
CHANGED
|
@@ -196,6 +196,27 @@ export const datePickerTypography = {
|
|
|
196
196
|
lineHeight: 12,
|
|
197
197
|
letterSpacing: 0.36,
|
|
198
198
|
},
|
|
199
|
+
rangeLabel: {
|
|
200
|
+
fontFamily: fonts.sans,
|
|
201
|
+
fontSize: 13,
|
|
202
|
+
fontWeight: "500" as const,
|
|
203
|
+
lineHeight: 13,
|
|
204
|
+
letterSpacing: 0,
|
|
205
|
+
},
|
|
206
|
+
rangeDate: {
|
|
207
|
+
fontFamily: fonts.sans,
|
|
208
|
+
fontSize: 16,
|
|
209
|
+
fontWeight: "500" as const,
|
|
210
|
+
lineHeight: 16,
|
|
211
|
+
letterSpacing: 0,
|
|
212
|
+
},
|
|
213
|
+
rangeTime: {
|
|
214
|
+
fontFamily: fonts.sans,
|
|
215
|
+
fontSize: 14,
|
|
216
|
+
fontWeight: "400" as const,
|
|
217
|
+
lineHeight: 14,
|
|
218
|
+
letterSpacing: 0,
|
|
219
|
+
},
|
|
199
220
|
/** Calendar month/year heading — Bold, centered, White. */
|
|
200
221
|
monthHeading: {
|
|
201
222
|
fontFamily: fonts.sans,
|