related-ui-components 4.2.2 → 4.2.4

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.
@@ -6,10 +6,12 @@ import Animated, {
6
6
  useAnimatedStyle,
7
7
  useSharedValue,
8
8
  } from "react-native-reanimated";
9
- import { SliderLabels } from "./SliderLabel";
10
9
  import { ThemeType, useTheme } from "../../theme";
10
+ import { SliderLabels } from "./SliderLabel";
11
+ import { Input } from "../Input";
11
12
 
12
13
  const THUMB_SIZE = 28;
14
+ const THUMB_RADIUS = THUMB_SIZE / 2;
13
15
  const RAIL_HEIGHT = 6;
14
16
  const LABEL_HEIGHT = 26;
15
17
 
@@ -25,11 +27,17 @@ interface RangeSliderProps {
25
27
  onValueChange: (values: { min: number; max: number }) => void;
26
28
  theme?: ThemeType;
27
29
  scale?: ScaleType;
28
- /**
29
- * For percentile scale: array of all values in your dataset
30
- * The slider will distribute positions based on data density
31
- */
32
30
  dataPoints?: number[];
31
+ showCustomInputs?: boolean;
32
+ inputPlaceholders?: {
33
+ min?: string;
34
+ max?: string;
35
+ };
36
+ inputLabels?: {
37
+ min?: string;
38
+ max?: string;
39
+ };
40
+ isBottomSheet?: boolean;
33
41
  }
34
42
 
35
43
  /**
@@ -39,12 +47,10 @@ interface RangeSliderProps {
39
47
  function createPercentileBreakpoints(data: number[]): number[] {
40
48
  const sorted = [...new Set(data)].sort((a, b) => a - b);
41
49
 
42
- // If small dataset, use all unique values
43
50
  if (sorted.length <= 100) {
44
51
  return sorted;
45
52
  }
46
53
 
47
- // For larger datasets, sample at percentile intervals
48
54
  const breakpoints: number[] = [];
49
55
  const numBreakpoints = 100;
50
56
 
@@ -90,6 +96,10 @@ const RangeSlider: React.FC<RangeSliderProps> = ({
90
96
  theme,
91
97
  scale = "linear",
92
98
  dataPoints,
99
+ showCustomInputs = false,
100
+ inputPlaceholders,
101
+ inputLabels,
102
+ isBottomSheet = false,
93
103
  }) => {
94
104
  const { theme: defaultTheme } = useTheme();
95
105
  const currTheme = theme || defaultTheme;
@@ -98,9 +108,20 @@ const RangeSlider: React.FC<RangeSliderProps> = ({
98
108
 
99
109
  const [leftLabel, setLeftLabel] = useState(initialMinValue.toLocaleString());
100
110
  const [rightLabel, setRightLabel] = useState(
101
- initialMaxValue.toLocaleString()
111
+ initialMaxValue.toLocaleString(),
112
+ );
113
+
114
+ // State for custom input fields
115
+ const [minInputValue, setMinInputValue] = useState(
116
+ initialMinValue.toString(),
117
+ );
118
+ const [maxInputValue, setMaxInputValue] = useState(
119
+ initialMaxValue.toString(),
102
120
  );
103
121
 
122
+ // The effective track width (where thumb CENTER can travel)
123
+ const effectiveWidth = sliderWidth - THUMB_SIZE;
124
+
104
125
  // Pre-compute breakpoints for percentile scale
105
126
  const breakpoints = useMemo(() => {
106
127
  if (scale === "percentile" && dataPoints?.length) {
@@ -117,7 +138,6 @@ const RangeSlider: React.FC<RangeSliderProps> = ({
117
138
  let percentage: number;
118
139
 
119
140
  if (scale === "percentile" && breakpoints.length > 1) {
120
- // Find where this value falls in the breakpoints
121
141
  const index = findBreakpointIndex(breakpoints, value);
122
142
 
123
143
  if (index === 0) {
@@ -125,7 +145,6 @@ const RangeSlider: React.FC<RangeSliderProps> = ({
125
145
  } else if (index >= breakpoints.length - 1) {
126
146
  percentage = 1;
127
147
  } else {
128
- // Interpolate between breakpoints
129
148
  const lowerVal = breakpoints[index - 1];
130
149
  const upperVal = breakpoints[index];
131
150
  const lowerPct = (index - 1) / (breakpoints.length - 1);
@@ -147,41 +166,52 @@ const RangeSlider: React.FC<RangeSliderProps> = ({
147
166
  percentage = (value - min) / (max - min);
148
167
  }
149
168
 
150
- return isRTL ? (1 - percentage) * sliderWidth : percentage * sliderWidth;
169
+ // Map to effective width, offset by thumb radius
170
+ const position = percentage * effectiveWidth + THUMB_RADIUS;
171
+ return isRTL ? sliderWidth - position : position;
151
172
  },
152
- [min, max, safeMin, sliderWidth, isRTL, scale, breakpoints]
173
+ [min, max, safeMin, sliderWidth, effectiveWidth, isRTL, scale, breakpoints],
153
174
  );
154
175
 
155
176
  const positionToValue = useCallback(
156
177
  (position: number) => {
157
178
  "worklet";
158
- const percentage = isRTL
159
- ? 1 - position / sliderWidth
160
- : position / sliderWidth;
179
+ // Convert position to percentage using effective width
180
+ const adjustedPosition = isRTL ? sliderWidth - position : position;
181
+ const percentage = (adjustedPosition - THUMB_RADIUS) / effectiveWidth;
182
+ const clampedPercentage = Math.max(0, Math.min(1, percentage));
161
183
 
162
184
  let rawValue: number;
163
185
 
164
186
  if (scale === "percentile" && breakpoints.length > 1) {
165
- // Map percentage to breakpoint index
166
- const exactIndex = percentage * (breakpoints.length - 1);
187
+ const exactIndex = clampedPercentage * (breakpoints.length - 1);
167
188
  const lowerIndex = Math.floor(exactIndex);
168
189
  const upperIndex = Math.min(lowerIndex + 1, breakpoints.length - 1);
169
190
  const ratio = exactIndex - lowerIndex;
170
-
171
191
  rawValue =
172
192
  breakpoints[lowerIndex] +
173
193
  ratio * (breakpoints[upperIndex] - breakpoints[lowerIndex]);
174
194
  } else if (scale === "logarithmic") {
175
195
  const logMin = Math.log(safeMin);
176
196
  const logMax = Math.log(max);
177
- rawValue = Math.exp(logMin + percentage * (logMax - logMin));
197
+ rawValue = Math.exp(logMin + clampedPercentage * (logMax - logMin));
178
198
  } else {
179
- rawValue = percentage * (max - min) + min;
199
+ rawValue = clampedPercentage * (max - min) + min;
180
200
  }
181
201
 
182
202
  return Math.round(rawValue / step) * step;
183
203
  },
184
- [min, max, safeMin, step, sliderWidth, isRTL, scale, breakpoints]
204
+ [
205
+ min,
206
+ max,
207
+ safeMin,
208
+ step,
209
+ sliderWidth,
210
+ effectiveWidth,
211
+ isRTL,
212
+ scale,
213
+ breakpoints,
214
+ ],
185
215
  );
186
216
 
187
217
  const leftPosition = useSharedValue(valueToPosition(initialMinValue));
@@ -206,21 +236,29 @@ const RangeSlider: React.FC<RangeSliderProps> = ({
206
236
  const newPos = context.value.x + e.translationX;
207
237
 
208
238
  if (activeThumb.value === "left") {
209
- const lowerBound = isRTL ? rightPosition.value + THUMB_SIZE : 0;
239
+ const lowerBound = isRTL
240
+ ? rightPosition.value + THUMB_SIZE
241
+ : THUMB_RADIUS;
210
242
  const upperBound = isRTL
211
- ? sliderWidth
243
+ ? sliderWidth - THUMB_RADIUS
212
244
  : rightPosition.value - THUMB_SIZE;
213
245
  const clampedPos = Math.max(Math.min(newPos, upperBound), lowerBound);
214
246
  leftPosition.value = clampedPos;
215
- runOnJS(setLeftLabel)(positionToValue(clampedPos).toLocaleString());
247
+ const newValue = positionToValue(clampedPos);
248
+ runOnJS(setLeftLabel)(newValue.toLocaleString());
249
+ runOnJS(setMinInputValue)(newValue.toString());
216
250
  } else {
217
- const lowerBound = isRTL ? 0 : leftPosition.value + THUMB_SIZE;
251
+ const lowerBound = isRTL
252
+ ? THUMB_RADIUS
253
+ : leftPosition.value + THUMB_SIZE;
218
254
  const upperBound = isRTL
219
255
  ? leftPosition.value - THUMB_SIZE
220
- : sliderWidth;
256
+ : sliderWidth - THUMB_RADIUS;
221
257
  const clampedPos = Math.max(Math.min(newPos, upperBound), lowerBound);
222
258
  rightPosition.value = clampedPos;
223
- runOnJS(setRightLabel)(positionToValue(clampedPos).toLocaleString());
259
+ const newValue = positionToValue(clampedPos);
260
+ runOnJS(setRightLabel)(newValue.toLocaleString());
261
+ runOnJS(setMaxInputValue)(newValue.toString());
224
262
  }
225
263
  })
226
264
  .onEnd(() => {
@@ -231,12 +269,99 @@ const RangeSlider: React.FC<RangeSliderProps> = ({
231
269
  activeThumb.value = null;
232
270
  });
233
271
 
272
+ // Handlers for custom input fields
273
+ const handleMinInputChange = useCallback((text: string) => {
274
+ // Allow only numeric input (with optional decimal)
275
+ const sanitized = text.replace(/[^0-9.]/g, "");
276
+ setMinInputValue(sanitized);
277
+ }, []);
278
+
279
+ const handleMaxInputChange = useCallback((text: string) => {
280
+ const sanitized = text.replace(/[^0-9.]/g, "");
281
+ setMaxInputValue(sanitized);
282
+ }, []);
283
+
284
+ const handleMinInputSubmit = useCallback(() => {
285
+ const parsed = parseFloat(minInputValue);
286
+ if (isNaN(parsed)) {
287
+ // Reset to current slider value
288
+ const currentValue = positionToValue(leftPosition.value);
289
+ setMinInputValue(currentValue.toString());
290
+ return;
291
+ }
292
+
293
+ // Clamp value: must be >= min and <= current max value
294
+ const currentMaxValue = positionToValue(rightPosition.value);
295
+ const clampedValue = Math.max(
296
+ min,
297
+ Math.min(parsed, currentMaxValue - step),
298
+ );
299
+ const steppedValue = Math.round(clampedValue / step) * step;
300
+
301
+ // Update input display
302
+ setMinInputValue(steppedValue.toString());
303
+ setLeftLabel(steppedValue.toLocaleString());
304
+
305
+ // Update slider position
306
+ leftPosition.value = valueToPosition(steppedValue);
307
+
308
+ // Trigger callback
309
+ onValueChange({ min: steppedValue, max: currentMaxValue });
310
+ }, [
311
+ minInputValue,
312
+ min,
313
+ step,
314
+ leftPosition,
315
+ rightPosition,
316
+ positionToValue,
317
+ valueToPosition,
318
+ onValueChange,
319
+ ]);
320
+
321
+ const handleMaxInputSubmit = useCallback(() => {
322
+ const parsed = parseFloat(maxInputValue);
323
+ if (isNaN(parsed)) {
324
+ // Reset to current slider value
325
+ const currentValue = positionToValue(rightPosition.value);
326
+ setMaxInputValue(currentValue.toString());
327
+ return;
328
+ }
329
+
330
+ // Clamp value: must be <= max and >= current min value
331
+ const currentMinValue = positionToValue(leftPosition.value);
332
+ const clampedValue = Math.min(
333
+ max,
334
+ Math.max(parsed, currentMinValue + step),
335
+ );
336
+ const steppedValue = Math.round(clampedValue / step) * step;
337
+
338
+ // Update input display
339
+ setMaxInputValue(steppedValue.toString());
340
+ setRightLabel(steppedValue.toLocaleString());
341
+
342
+ // Update slider position
343
+ rightPosition.value = valueToPosition(steppedValue);
344
+
345
+ // Trigger callback
346
+ onValueChange({ min: currentMinValue, max: steppedValue });
347
+ }, [
348
+ maxInputValue,
349
+ max,
350
+ step,
351
+ leftPosition,
352
+ rightPosition,
353
+ positionToValue,
354
+ valueToPosition,
355
+ onValueChange,
356
+ ]);
357
+
358
+ // Thumb position = center of thumb, so offset by radius to get left edge
234
359
  const animatedLeftThumbStyle = useAnimatedStyle(() => ({
235
- transform: [{ translateX: leftPosition.value - (isRTL ? THUMB_SIZE : 0) }],
360
+ transform: [{ translateX: leftPosition.value - THUMB_RADIUS }],
236
361
  }));
237
362
 
238
363
  const animatedRightThumbStyle = useAnimatedStyle(() => ({
239
- transform: [{ translateX: rightPosition.value - (isRTL ? 0 : THUMB_SIZE) }],
364
+ transform: [{ translateX: rightPosition.value - THUMB_RADIUS }],
240
365
  }));
241
366
 
242
367
  const animatedActiveRailStyle = useAnimatedStyle(() => {
@@ -249,15 +374,53 @@ const RangeSlider: React.FC<RangeSliderProps> = ({
249
374
  });
250
375
 
251
376
  return (
252
- <View style={[styles.container, { width: sliderWidth }]}>
253
- <SliderLabels
254
- leftValue={leftLabel}
255
- rightValue={rightLabel}
256
- leftPosition={leftPosition}
257
- rightPosition={rightPosition}
258
- sliderWidth={sliderWidth}
259
- thumbSize={THUMB_SIZE}
260
- />
377
+ <View
378
+ style={[
379
+ showCustomInputs ? styles.containerWithInputs : styles.container,
380
+ { width: sliderWidth },
381
+ ]}
382
+ >
383
+ {showCustomInputs ? (
384
+ <View style={styles.inputsContainer}>
385
+ <View style={styles.inputWrapper}>
386
+ <Input
387
+ label={inputLabels?.min ?? "Min"}
388
+ value={minInputValue}
389
+ onChangeText={handleMinInputChange}
390
+ onBlur={handleMinInputSubmit}
391
+ onSubmitEditing={handleMinInputSubmit}
392
+ keyboardType="numeric"
393
+ placeholder={inputPlaceholders?.min}
394
+ placeholderTextColor={currTheme.surfaceVariant}
395
+ returnKeyType="done"
396
+ isBottomSheet={isBottomSheet}
397
+ />
398
+ </View>
399
+ <View style={styles.inputWrapper}>
400
+ <Input
401
+ label={inputLabels?.max ?? "Max"}
402
+ value={maxInputValue}
403
+ onChangeText={handleMaxInputChange}
404
+ onBlur={handleMaxInputSubmit}
405
+ onSubmitEditing={handleMaxInputSubmit}
406
+ keyboardType="numeric"
407
+ placeholder={inputPlaceholders?.max}
408
+ placeholderTextColor={currTheme.surfaceVariant}
409
+ returnKeyType="done"
410
+ isBottomSheet={isBottomSheet}
411
+ />
412
+ </View>
413
+ </View>
414
+ ) : (
415
+ <SliderLabels
416
+ leftValue={leftLabel}
417
+ rightValue={rightLabel}
418
+ leftPosition={leftPosition}
419
+ rightPosition={rightPosition}
420
+ sliderWidth={sliderWidth}
421
+ thumbSize={THUMB_SIZE}
422
+ />
423
+ )}
261
424
 
262
425
  <GestureDetector gesture={panGesture}>
263
426
  <View style={styles.railContainer}>
@@ -289,6 +452,9 @@ const getStyles = (theme: ThemeType) =>
289
452
  marginTop: LABEL_HEIGHT,
290
453
  direction: "ltr",
291
454
  },
455
+ containerWithInputs: {
456
+ direction: "ltr",
457
+ },
292
458
  railContainer: {
293
459
  justifyContent: "center",
294
460
  height: THUMB_SIZE,
@@ -318,6 +484,34 @@ const getStyles = (theme: ThemeType) =>
318
484
  borderColor: theme.primary,
319
485
  borderWidth: 5,
320
486
  },
487
+ inputsContainer: {
488
+ flexDirection: "row",
489
+ justifyContent: "space-between",
490
+ gap: 16,
491
+ marginBottom: 12,
492
+ direction: I18nManager.isRTL ? "rtl" : "ltr",
493
+ },
494
+ inputWrapper: {
495
+ flex: 1,
496
+ },
497
+ inputLabel: {
498
+ color: theme.onSurface,
499
+ fontSize: 13,
500
+ fontFamily: "DinMedium",
501
+ marginBottom: 6,
502
+ },
503
+ input: {
504
+ backgroundColor: theme.background,
505
+ paddingHorizontal: 16,
506
+ paddingVertical: 10,
507
+ borderRadius: 8,
508
+ borderWidth: 1,
509
+ borderColor: theme.surfaceVariant,
510
+ color: theme.onSurface,
511
+ fontSize: 15,
512
+ fontFamily: "DinBold",
513
+ textAlign: "center",
514
+ },
321
515
  });
322
516
 
323
- export default RangeSlider;
517
+ export default RangeSlider;
@@ -1,14 +1,16 @@
1
1
  import React from "react";
2
2
  import { I18nManager, StyleSheet, Text, View } from "react-native";
3
3
  import Animated, {
4
- SharedValue,
5
- useAnimatedStyle,
6
- useDerivedValue,
7
- useSharedValue,
4
+ SharedValue,
5
+ useAnimatedStyle,
6
+ useDerivedValue,
7
+ useSharedValue,
8
8
  } from "react-native-reanimated";
9
9
  import { ThemeType, useTheme } from "../../theme";
10
10
 
11
11
  const LABEL_HEIGHT = 26;
12
+ const LABEL_PADDING = 8;
13
+ const MIN_GAP = 4;
12
14
 
13
15
  interface SliderLabelsProps {
14
16
  leftValue: string;
@@ -17,51 +19,100 @@ interface SliderLabelsProps {
17
19
  rightPosition: SharedValue<number>;
18
20
  sliderWidth: number;
19
21
  thumbSize: number;
20
- theme?: ThemeType
22
+ theme?: ThemeType;
21
23
  }
22
24
 
23
- interface CenteredLabelProps {
25
+ interface SingleLabelProps {
24
26
  value: string;
25
27
  position: SharedValue<number>;
26
28
  sliderWidth: number;
27
- thumbSize: number;
28
- theme?: ThemeType
29
+ onWidthChange: (width: number) => void;
30
+ isVisible: SharedValue<boolean>;
31
+ theme: ThemeType;
32
+ }
29
33
 
34
+ interface MergedLabelProps {
35
+ leftValue: string;
36
+ rightValue: string;
37
+ leftPosition: SharedValue<number>;
38
+ rightPosition: SharedValue<number>;
39
+ sliderWidth: number;
40
+ isVisible: SharedValue<boolean>;
41
+ theme: ThemeType;
30
42
  }
31
43
 
32
- const CenteredLabel: React.FC<CenteredLabelProps> = ({
44
+ const SingleLabel: React.FC<SingleLabelProps> = ({
33
45
  value,
34
46
  position,
35
47
  sliderWidth,
36
- thumbSize,
37
- theme
48
+ onWidthChange,
49
+ isVisible,
50
+ theme,
38
51
  }) => {
39
- const labelWidth = useSharedValue(0);
40
- const {theme: defaultTheme} = useTheme();
41
- const currTheme = theme || defaultTheme;
42
- const styles = getStyles(currTheme);
52
+ const styles = getStyles(theme);
53
+ const localWidth = useSharedValue(0);
43
54
 
44
- const animatedLabelStyle = useAnimatedStyle(() => {
45
- const rawCenter = position.value + thumbSize / 2;
46
- const shifted = rawCenter - labelWidth.value / 2;
55
+ const animatedStyle = useAnimatedStyle(() => {
56
+ const halfLabel = localWidth.value / 2;
57
+ const rawCenter = position.value;
58
+ const shifted = rawCenter - halfLabel;
59
+ const left = Math.min(Math.max(shifted, 0), sliderWidth - localWidth.value);
47
60
 
61
+ return {
62
+ left,
63
+ opacity: isVisible.value ? 1 : 0,
64
+ };
65
+ });
66
+
67
+ return (
68
+ <Animated.View
69
+ style={[styles.labelContainer, animatedStyle]}
70
+ onLayout={(e) => {
71
+ const width = e.nativeEvent.layout.width;
72
+ localWidth.value = width;
73
+ onWidthChange(width);
74
+ }}
75
+ >
76
+ <Text style={styles.labelText}>{value}</Text>
77
+ </Animated.View>
78
+ );
79
+ };
80
+
81
+ const MergedLabel: React.FC<MergedLabelProps> = ({
82
+ leftValue,
83
+ rightValue,
84
+ leftPosition,
85
+ rightPosition,
86
+ sliderWidth,
87
+ isVisible,
88
+ theme,
89
+ }) => {
90
+ const styles = getStyles(theme);
91
+ const labelWidth = useSharedValue(0);
92
+
93
+ const animatedStyle = useAnimatedStyle(() => {
94
+ const centerPosition = (leftPosition.value + rightPosition.value) / 2;
95
+ const halfLabel = labelWidth.value / 2;
96
+ const shifted = centerPosition - halfLabel;
48
97
  const left = Math.min(Math.max(shifted, 0), sliderWidth - labelWidth.value);
49
98
 
50
99
  return {
51
- left: left,
100
+ left,
101
+ opacity: isVisible.value ? 1 : 0,
52
102
  };
53
103
  });
54
104
 
105
+ const displayText =
106
+ leftValue === rightValue ? leftValue : `${leftValue} - ${rightValue}`;
107
+
55
108
  return (
56
109
  <Animated.View
57
- style={[styles.labelContainer, animatedLabelStyle]}
110
+ style={[styles.labelContainer, animatedStyle]}
58
111
  onLayout={(e) => {
59
112
  labelWidth.value = e.nativeEvent.layout.width;
60
113
  }}
61
114
  >
62
- <Text style={styles.labelText}>
63
- {value}
64
- </Text>
115
+ <Text style={styles.labelText}>{displayText}</Text>
65
116
  </Animated.View>
66
117
  );
67
118
  };
@@ -77,29 +128,62 @@ export const SliderLabels: React.FC<SliderLabelsProps> = ({
77
128
  }) => {
78
129
  const { theme: defaultTheme } = useTheme();
79
130
  const currTheme = theme || defaultTheme;
80
- const styles = getStyles(currTheme);
81
- const rightThumbLeftPosition = useDerivedValue(() => {
82
- return rightPosition.value - thumbSize;
83
- });
84
- const leftThumbLeftPosition = useDerivedValue(() => {
85
- return leftPosition.value - thumbSize;
131
+ const isRTL = I18nManager.isRTL;
132
+
133
+ // Track label widths in parent for overlap calculation
134
+ const leftLabelWidth = useSharedValue(0);
135
+ const rightLabelWidth = useSharedValue(0);
136
+
137
+ const shouldMerge = useDerivedValue(() => {
138
+ const leftCenter = leftPosition.value;
139
+ const rightCenter = rightPosition.value;
140
+
141
+ const leftEnd = leftCenter + leftLabelWidth.value / 2;
142
+ const rightStart = rightCenter - rightLabelWidth.value / 2;
143
+
144
+ if (isRTL) {
145
+ const rtlLeftEnd = rightCenter + rightLabelWidth.value / 2;
146
+ const rtlRightStart = leftCenter - leftLabelWidth.value / 2;
147
+ return rtlRightStart - rtlLeftEnd < MIN_GAP;
148
+ }
149
+
150
+ return rightStart - leftEnd < MIN_GAP;
86
151
  });
87
152
 
88
- const isRTL = I18nManager.isRTL;
153
+ const showSeparate = useDerivedValue(() => !shouldMerge.value);
154
+ const showMerged = useDerivedValue(() => shouldMerge.value);
89
155
 
90
156
  return (
91
- <View style={styles.wrapper} pointerEvents="none">
92
- <CenteredLabel
157
+ <View style={getStyles(currTheme).wrapper} pointerEvents="none">
158
+ <SingleLabel
93
159
  value={leftValue}
94
- thumbSize={thumbSize}
95
- position={isRTL ? leftThumbLeftPosition : leftPosition}
160
+ position={leftPosition}
96
161
  sliderWidth={sliderWidth}
162
+ onWidthChange={(width) => {
163
+ leftLabelWidth.value = width;
164
+ }}
165
+ isVisible={showSeparate}
166
+ theme={currTheme}
97
167
  />
98
- <CenteredLabel
168
+ <SingleLabel
99
169
  value={rightValue}
100
- thumbSize={thumbSize}
101
- position={isRTL ? rightPosition : rightThumbLeftPosition}
170
+ position={rightPosition}
171
+ sliderWidth={sliderWidth}
172
+ onWidthChange={(width) => {
173
+ rightLabelWidth.value = width;
174
+ }}
175
+ isVisible={showSeparate}
176
+ theme={currTheme}
177
+ />
178
+
179
+ <MergedLabel
180
+ leftValue={leftValue}
181
+ rightValue={rightValue}
182
+ leftPosition={leftPosition}
183
+ rightPosition={rightPosition}
102
184
  sliderWidth={sliderWidth}
185
+ isVisible={showMerged}
186
+ theme={currTheme}
103
187
  />
104
188
  </View>
105
189
  );
@@ -119,7 +203,7 @@ const getStyles = (theme: ThemeType) =>
119
203
  },
120
204
  labelText: {
121
205
  backgroundColor: theme.surface,
122
- paddingHorizontal: 8,
206
+ paddingHorizontal: LABEL_PADDING,
123
207
  paddingVertical: 4,
124
208
  borderRadius: 4,
125
209
  color: theme.onSurface,
@@ -297,8 +297,8 @@ export const useModal = () => {
297
297
 
298
298
  const styles = StyleSheet.create({
299
299
  overlayWrapper: {
300
- zIndex: 1000,
301
- elevation: 1000,
300
+ // zIndex: 1000,
301
+ // elevation: 1000,
302
302
  },
303
303
  backdrop: {
304
304
  backgroundColor: "rgba(0, 0, 0, 0.6)",