rnnovaui 0.8.7 → 0.8.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rnnovaui",
3
- "version": "0.8.7",
3
+ "version": "0.8.8",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "react-native": "src/index.js",
@@ -12,6 +12,10 @@ import { Pressable, StyleSheet, Text, View } from "react-native";
12
12
 
13
13
  import { useUITheme } from "../../theme";
14
14
 
15
+ /* =========================================================
16
+ CONSTANTS
17
+ ========================================================= */
18
+
15
19
  const RADIO_GROUP_ORIENTATIONS = {
16
20
  vertical: "vertical",
17
21
  horizontal: "horizontal",
@@ -23,6 +27,10 @@ const RADIO_GROUP_SIZES = {
23
27
  lg: "lg",
24
28
  };
25
29
 
30
+ /* =========================================================
31
+ CONTEXT
32
+ ========================================================= */
33
+
26
34
  const RadioGroupContext = createContext(null);
27
35
 
28
36
  /* =========================================================
@@ -38,8 +46,6 @@ const UIRadioGroupComponent = forwardRef(function UIRadioGroup(
38
46
 
39
47
  onChange,
40
48
 
41
- name,
42
-
43
49
  label,
44
50
  helperText,
45
51
  errorText,
@@ -55,7 +61,6 @@ const UIRadioGroupComponent = forwardRef(function UIRadioGroup(
55
61
  size = "md",
56
62
 
57
63
  gap = 12,
58
- optionGap,
59
64
 
60
65
  style,
61
66
  labelStyle,
@@ -78,9 +83,8 @@ const UIRadioGroupComponent = forwardRef(function UIRadioGroup(
78
83
 
79
84
  const selectedValue = isControlled ? value : internalValue;
80
85
 
81
- const resolvedOrientation = RADIO_GROUP_ORIENTATIONS[orientation]
82
- ? orientation
83
- : "vertical";
86
+ const resolvedOrientation =
87
+ orientation === "horizontal" ? "horizontal" : "vertical";
84
88
 
85
89
  const resolvedSize = RADIO_GROUP_SIZES[size] ? size : "md";
86
90
 
@@ -103,7 +107,7 @@ const UIRadioGroupComponent = forwardRef(function UIRadioGroup(
103
107
 
104
108
  const contextValue = useMemo(
105
109
  () => ({
106
- value: selectedValue,
110
+ selectedValue,
107
111
 
108
112
  onChange: handleChange,
109
113
 
@@ -122,8 +126,10 @@ const UIRadioGroupComponent = forwardRef(function UIRadioGroup(
122
126
  {...props}
123
127
  ref={ref}
124
128
  testID={testID}
125
- style={[styles.wrapper, style]}
129
+ style={[styles.container, style]}
126
130
  >
131
+ {/* GROUP LABEL */}
132
+
127
133
  {label ? (
128
134
  <Text
129
135
  style={[
@@ -138,7 +144,7 @@ const UIRadioGroupComponent = forwardRef(function UIRadioGroup(
138
144
  labelStyle,
139
145
  ]}
140
146
  >
141
- {label}
147
+ {String(label)}
142
148
 
143
149
  {required ? (
144
150
  <Text
@@ -152,22 +158,32 @@ const UIRadioGroupComponent = forwardRef(function UIRadioGroup(
152
158
  </Text>
153
159
  ) : null}
154
160
 
161
+ {/* OPTIONS */}
162
+
155
163
  <View
156
164
  style={[
157
165
  styles.options,
158
166
 
159
167
  resolvedOrientation === "horizontal"
160
- ? styles.horizontal
161
- : styles.vertical,
168
+ ? styles.optionsHorizontal
169
+ : styles.optionsVertical,
162
170
 
163
171
  {
164
- gap: optionGap ?? gap,
172
+ gap,
165
173
  },
166
174
  ]}
167
175
  >
168
- {children}
176
+ {React.Children.map(children, (child) => {
177
+ if (!React.isValidElement(child)) {
178
+ return null;
179
+ }
180
+
181
+ return child;
182
+ })}
169
183
  </View>
170
184
 
185
+ {/* ERROR */}
186
+
171
187
  {hasError ? (
172
188
  <Text
173
189
  style={[
@@ -180,7 +196,7 @@ const UIRadioGroupComponent = forwardRef(function UIRadioGroup(
180
196
  errorStyle,
181
197
  ]}
182
198
  >
183
- {errorText}
199
+ {String(errorText)}
184
200
  </Text>
185
201
  ) : helperText ? (
186
202
  <Text
@@ -194,7 +210,7 @@ const UIRadioGroupComponent = forwardRef(function UIRadioGroup(
194
210
  helperStyle,
195
211
  ]}
196
212
  >
197
- {helperText}
213
+ {String(helperText)}
198
214
  </Text>
199
215
  ) : null}
200
216
  </View>
@@ -208,8 +224,10 @@ const UIRadioGroupComponent = forwardRef(function UIRadioGroup(
208
224
 
209
225
  const UIRadioOptionComponent = function UIRadioOptionComponent({
210
226
  value,
227
+
211
228
  label = "",
212
- description,
229
+
230
+ description = "",
213
231
 
214
232
  disabled = false,
215
233
 
@@ -232,16 +250,16 @@ const UIRadioOptionComponent = function UIRadioOptionComponent({
232
250
  }
233
251
 
234
252
  const {
235
- value: selectedValue,
253
+ selectedValue,
236
254
  onChange,
237
255
  disabled: groupDisabled,
238
256
  size,
239
257
  error,
240
258
  } = context;
241
259
 
242
- const checked = selectedValue === value;
260
+ const selected = selectedValue === value;
243
261
 
244
- const isDisabled = groupDisabled || disabled;
262
+ const isDisabled = Boolean(groupDisabled || disabled);
245
263
 
246
264
  const radioSize = getRadioSize(size);
247
265
 
@@ -256,112 +274,116 @@ const UIRadioOptionComponent = function UIRadioOptionComponent({
256
274
  }, [isDisabled, onChange, value, onPress]);
257
275
 
258
276
  return (
259
- <View style={[styles.optionWrapper, style]}>
260
- <Pressable
261
- {...props}
262
- onPress={handlePress}
263
- disabled={isDisabled}
264
- accessibilityRole="radio"
265
- accessibilityState={{
266
- checked,
267
- disabled: isDisabled,
268
- }}
269
- style={({ pressed }) => [
270
- styles.optionPressable,
277
+ <Pressable
278
+ {...props}
279
+ onPress={handlePress}
280
+ disabled={isDisabled}
281
+ accessibilityRole="radio"
282
+ accessibilityState={{
283
+ checked: selected,
284
+
285
+ disabled: isDisabled,
286
+ }}
287
+ style={({ pressed }) => [
288
+ styles.option,
289
+
290
+ {
291
+ opacity: isDisabled ? 0.5 : pressed ? 0.7 : 1,
292
+ },
293
+
294
+ style,
295
+ ]}
296
+ >
297
+ {/* RADIO */}
298
+
299
+ <View
300
+ style={[
301
+ styles.radio,
271
302
 
272
303
  {
273
- opacity: isDisabled ? 0.5 : pressed ? 0.7 : 1,
304
+ width: radioSize.outer,
305
+
306
+ height: radioSize.outer,
307
+
308
+ borderRadius: radioSize.outer / 2,
309
+
310
+ borderWidth: selected ? 2 : 1.5,
311
+
312
+ borderColor: error
313
+ ? colors.danger || "#DC2626"
314
+ : selected
315
+ ? colors.primary || "#FF5A1F"
316
+ : colors.borderStrong || "#D4D4D4",
274
317
  },
275
318
  ]}
276
319
  >
277
- {/* RADIO CIRCLE */}
278
- <View
279
- style={[
280
- styles.radio,
320
+ {selected ? (
321
+ <View
322
+ style={[
323
+ styles.radioDot,
281
324
 
282
- {
283
- width: radioSize.outer,
325
+ {
326
+ width: radioSize.inner,
284
327
 
285
- height: radioSize.outer,
328
+ height: radioSize.inner,
286
329
 
287
- borderRadius: radioSize.outer / 2,
330
+ borderRadius: radioSize.inner / 2,
288
331
 
289
- borderColor: error
290
- ? colors.danger || "#DC2626"
291
- : checked
292
- ? colors.primary || "#FF5A1F"
293
- : colors.borderStrong || "#D4D4D4",
332
+ backgroundColor: error
333
+ ? colors.danger || "#DC2626"
334
+ : colors.primary || "#FF5A1F",
335
+ },
336
+ ]}
337
+ />
338
+ ) : null}
339
+ </View>
294
340
 
295
- borderWidth: checked ? 2 : 1.5,
296
- },
297
- ]}
298
- >
299
- {checked ? (
300
- <View
301
- style={[
302
- styles.radioDot,
341
+ {/* LABEL + DESCRIPTION */}
303
342
 
304
- {
305
- width: radioSize.inner,
343
+ <View style={styles.content}>
344
+ {label !== null && label !== undefined && String(label).length > 0 ? (
345
+ <Text
346
+ style={[
347
+ styles.optionLabel,
306
348
 
307
- height: radioSize.inner,
349
+ {
350
+ color: isDisabled
351
+ ? colors.textDisabled || "#A3A3A3"
352
+ : colors.text || "#111111",
308
353
 
309
- borderRadius: radioSize.inner / 2,
354
+ fontSize: radioSize.fontSize,
310
355
 
311
- backgroundColor: error
312
- ? colors.danger || "#DC2626"
313
- : colors.primary || "#FF5A1F",
314
- },
315
- ]}
316
- />
317
- ) : null}
318
- </View>
356
+ lineHeight: radioSize.lineHeight,
357
+ },
319
358
 
320
- {/* TEXT AREA */}
321
- <View style={styles.textContainer}>
322
- {label !== "" ? (
323
- <Text
324
- numberOfLines={0}
325
- style={[
326
- styles.optionLabel,
327
-
328
- {
329
- color: isDisabled
330
- ? colors.textDisabled || "#A3A3A3"
331
- : colors.text || "#111111",
332
-
333
- fontSize: radioSize.fontSize,
334
-
335
- lineHeight: radioSize.lineHeight,
336
- },
337
-
338
- labelStyle,
339
- ]}
340
- >
341
- {String(label)}
342
- </Text>
343
- ) : null}
344
-
345
- {description ? (
346
- <Text
347
- style={[
348
- styles.description,
349
-
350
- {
351
- color: isDisabled
352
- ? colors.textDisabled || "#A3A3A3"
353
- : colors.textSecondary || "#525252",
354
- },
355
-
356
- descriptionStyle,
357
- ]}
358
- >
359
- {String(description)}
360
- </Text>
361
- ) : null}
362
- </View>
363
- </Pressable>
364
- </View>
359
+ labelStyle,
360
+ ]}
361
+ >
362
+ {String(label)}
363
+ </Text>
364
+ ) : null}
365
+
366
+ {description !== null &&
367
+ description !== undefined &&
368
+ String(description).length > 0 ? (
369
+ <Text
370
+ style={[
371
+ styles.description,
372
+
373
+ {
374
+ color: isDisabled
375
+ ? colors.textDisabled || "#A3A3A3"
376
+ : colors.textSecondary || "#525252",
377
+ },
378
+
379
+ descriptionStyle,
380
+ ]}
381
+ >
382
+ {String(description)}
383
+ </Text>
384
+ ) : null}
385
+ </View>
386
+ </Pressable>
365
387
  );
366
388
  };
367
389
 
@@ -403,7 +425,7 @@ function getRadioSize(size) {
403
425
  ========================================================= */
404
426
 
405
427
  const styles = StyleSheet.create({
406
- wrapper: {
428
+ container: {
407
429
  width: "100%",
408
430
  },
409
431
 
@@ -423,30 +445,38 @@ const styles = StyleSheet.create({
423
445
  width: "100%",
424
446
  },
425
447
 
426
- vertical: {
448
+ optionsVertical: {
427
449
  flexDirection: "column",
450
+
451
+ alignItems: "stretch",
428
452
  },
429
453
 
430
- horizontal: {
454
+ optionsHorizontal: {
431
455
  flexDirection: "row",
432
456
 
433
457
  flexWrap: "wrap",
434
458
 
435
459
  alignItems: "flex-start",
436
- },
437
460
 
438
- optionWrapper: {
439
- width: "100%",
461
+ justifyContent: "flex-start",
440
462
  },
441
463
 
442
- optionPressable: {
443
- width: "100%",
444
-
445
- minHeight: 34,
446
-
464
+ option: {
447
465
  flexDirection: "row",
448
466
 
449
467
  alignItems: "flex-start",
468
+
469
+ /*
470
+ * IMPORTANT:
471
+ *
472
+ * No width: "100%" here.
473
+ *
474
+ * That was the reason horizontal
475
+ * layout was not working.
476
+ */
477
+ flexShrink: 0,
478
+
479
+ minHeight: 34,
450
480
  },
451
481
 
452
482
  radio: {
@@ -461,8 +491,8 @@ const styles = StyleSheet.create({
461
491
 
462
492
  radioDot: {},
463
493
 
464
- textContainer: {
465
- flex: 1,
494
+ content: {
495
+ flexShrink: 1,
466
496
 
467
497
  minWidth: 0,
468
498
 
@@ -12,6 +12,10 @@ import { Animated, PanResponder, StyleSheet, Text, View } from "react-native";
12
12
 
13
13
  import { useUITheme } from "../../theme";
14
14
 
15
+ // ============================================================
16
+ // CONSTANTS
17
+ // ============================================================
18
+
15
19
  const UISLIDER_SIZES = {
16
20
  sm: "sm",
17
21
  md: "md",
@@ -23,11 +27,15 @@ const UISLIDER_ORIENTATIONS = {
23
27
  vertical: "vertical",
24
28
  };
25
29
 
30
+ // ============================================================
31
+ // COMPONENT
32
+ // ============================================================
33
+
26
34
  const UISliderComponent = forwardRef(function UISlider(
27
35
  {
28
- // -----------------------------------------
36
+ // ------------------------------------------------------
29
37
  // VALUE
30
- // -----------------------------------------
38
+ // ------------------------------------------------------
31
39
 
32
40
  value,
33
41
  defaultValue = 0,
@@ -43,104 +51,138 @@ const UISliderComponent = forwardRef(function UISlider(
43
51
  onSlidingStart,
44
52
  onSlidingComplete,
45
53
 
46
- // -----------------------------------------
54
+ // ------------------------------------------------------
47
55
  // LABEL
48
- // -----------------------------------------
56
+ // ------------------------------------------------------
49
57
 
50
58
  label,
59
+
51
60
  showValue = false,
61
+
52
62
  valueFormatter,
53
63
 
54
64
  showMinMax = false,
65
+
55
66
  minLabel,
56
67
  maxLabel,
57
68
 
58
- // -----------------------------------------
69
+ // ------------------------------------------------------
59
70
  // SIZE
60
- // -----------------------------------------
71
+ // ------------------------------------------------------
61
72
 
62
73
  size = "md",
63
74
 
64
75
  orientation = "horizontal",
65
76
 
66
77
  width = "100%",
78
+
67
79
  height = 220,
68
80
 
69
81
  thumbSize,
82
+
70
83
  trackHeight,
71
84
 
72
- // -----------------------------------------
85
+ // ------------------------------------------------------
73
86
  // COLORS
74
- // -----------------------------------------
87
+ // ------------------------------------------------------
75
88
 
76
89
  minimumTrackColor,
90
+
77
91
  maximumTrackColor,
92
+
78
93
  thumbColor,
79
94
 
80
- // -----------------------------------------
95
+ // ------------------------------------------------------
81
96
  // STATE
82
- // -----------------------------------------
97
+ // ------------------------------------------------------
83
98
 
84
99
  disabled = false,
85
100
 
86
101
  error = false,
102
+
87
103
  errorText,
88
104
 
89
105
  helperText,
90
106
 
91
- // -----------------------------------------
107
+ // ------------------------------------------------------
92
108
  // STYLES
93
- // -----------------------------------------
109
+ // ------------------------------------------------------
94
110
 
95
111
  containerStyle,
112
+
96
113
  labelStyle,
114
+
97
115
  valueStyle,
116
+
98
117
  minMaxStyle,
118
+
99
119
  helperStyle,
120
+
100
121
  errorStyle,
101
122
 
102
123
  trackStyle,
124
+
103
125
  thumbStyle,
104
126
 
105
- // -----------------------------------------
127
+ // ------------------------------------------------------
106
128
  // ANIMATION
107
- // -----------------------------------------
129
+ // ------------------------------------------------------
108
130
 
109
131
  animated = false,
110
132
 
111
133
  animationDuration = 180,
112
134
 
113
135
  animateThumb = true,
136
+
114
137
  animateTrack = true,
138
+
115
139
  animatePress = true,
116
140
 
117
141
  pressScale = 1.12,
118
142
 
119
- // -----------------------------------------
143
+ // ------------------------------------------------------
120
144
  // ACCESSIBILITY
121
- // -----------------------------------------
145
+ // ------------------------------------------------------
122
146
 
123
147
  accessibilityLabel,
148
+
124
149
  testID,
125
150
 
151
+ // ------------------------------------------------------
152
+ // REST
153
+ // ------------------------------------------------------
154
+
126
155
  ...props
127
156
  },
157
+
128
158
  ref,
129
159
  ) {
160
+ // ========================================================
161
+ // THEME
162
+ // ========================================================
163
+
130
164
  const { theme } = useUITheme();
131
165
 
132
166
  const colors = theme?.colors || {};
133
167
 
134
- // -----------------------------------------
135
- // SAFE VALUES
136
- // -----------------------------------------
168
+ // ========================================================
169
+ // SAFE MIN
170
+ // ========================================================
137
171
 
138
172
  const safeMin = useMemo(() => {
139
173
  const numeric = Number(min);
140
174
 
141
- return Number.isFinite(numeric) ? numeric : 0;
175
+ if (Number.isFinite(numeric)) {
176
+ return numeric;
177
+ }
178
+
179
+ return 0;
142
180
  }, [min]);
143
181
 
182
+ // ========================================================
183
+ // SAFE MAX
184
+ // ========================================================
185
+
144
186
  const safeMax = useMemo(() => {
145
187
  const numeric = Number(max);
146
188
 
@@ -151,6 +193,10 @@ const UISliderComponent = forwardRef(function UISlider(
151
193
  return safeMin + 1;
152
194
  }, [max, safeMin]);
153
195
 
196
+ // ========================================================
197
+ // SAFE STEP
198
+ // ========================================================
199
+
154
200
  const safeStep = useMemo(() => {
155
201
  const numeric = Number(step);
156
202
 
@@ -161,18 +207,30 @@ const UISliderComponent = forwardRef(function UISlider(
161
207
  return 1;
162
208
  }, [step]);
163
209
 
210
+ // ========================================================
211
+ // RANGE
212
+ // ========================================================
213
+
164
214
  const range = safeMax - safeMin;
165
215
 
166
- // -----------------------------------------
216
+ // ========================================================
167
217
  // SIZE
168
- // -----------------------------------------
218
+ // ========================================================
169
219
 
170
220
  const safeSize = UISLIDER_SIZES[size] ? size : UISLIDER_SIZES.md;
171
221
 
222
+ // ========================================================
223
+ // ORIENTATION
224
+ // ========================================================
225
+
172
226
  const safeOrientation = UISLIDER_ORIENTATIONS[orientation]
173
227
  ? orientation
174
228
  : UISLIDER_ORIENTATIONS.horizontal;
175
229
 
230
+ // ========================================================
231
+ // DIMENSIONS
232
+ // ========================================================
233
+
176
234
  const dimensions = useMemo(() => getDimensions(safeSize), [safeSize]);
177
235
 
178
236
  const resolvedThumbSize = Number.isFinite(Number(thumbSize))
@@ -183,9 +241,9 @@ const UISliderComponent = forwardRef(function UISlider(
183
241
  ? Number(trackHeight)
184
242
  : dimensions.trackHeight;
185
243
 
186
- // -----------------------------------------
187
- // NORMALIZE
188
- // -----------------------------------------
244
+ // ========================================================
245
+ // NORMALIZE VALUE
246
+ // ========================================================
189
247
 
190
248
  const normalizeValue = useCallback(
191
249
  (input) => {
@@ -203,31 +261,50 @@ const UISliderComponent = forwardRef(function UISlider(
203
261
 
204
262
  return roundValue(Math.min(Math.max(snapped, safeMin), safeMax));
205
263
  },
264
+
206
265
  [safeMin, safeMax, safeStep],
207
266
  );
208
267
 
209
- // -----------------------------------------
210
- // VALUE STATE
211
- // -----------------------------------------
268
+ // ========================================================
269
+ // INITIAL VALUE
270
+ // ========================================================
212
271
 
213
272
  const initialValue = normalizeValue(
214
273
  value !== undefined ? value : defaultValue,
215
274
  );
216
275
 
276
+ // ========================================================
277
+ // INTERNAL VALUE
278
+ // ========================================================
279
+
217
280
  const [internalValue, setInternalValue] = useState(initialValue);
218
281
 
282
+ // ========================================================
283
+ // CURRENT VALUE
284
+ // ========================================================
285
+
219
286
  const currentValue =
220
287
  value !== undefined ? normalizeValue(value) : internalValue;
221
288
 
289
+ // ========================================================
290
+ // SYNC CONTROLLED VALUE
291
+ // ========================================================
292
+
222
293
  useEffect(() => {
223
294
  if (value !== undefined) {
224
295
  setInternalValue(normalizeValue(value));
225
296
  }
226
297
  }, [value, normalizeValue]);
227
298
 
228
- // -----------------------------------------
229
- // MEASUREMENT
230
- // -----------------------------------------
299
+ // ========================================================
300
+ // PERCENTAGE
301
+ // ========================================================
302
+
303
+ const percentage = range > 0 ? ((currentValue - safeMin) / range) * 100 : 0;
304
+
305
+ // ========================================================
306
+ // TRACK MEASUREMENT
307
+ // ========================================================
231
308
 
232
309
  const trackLength = useRef(1);
233
310
 
@@ -235,8 +312,11 @@ const UISliderComponent = forwardRef(function UISlider(
235
312
 
236
313
  const handleLayout = useCallback(
237
314
  (event) => {
238
- const { width: layoutWidth, height: layoutHeight } =
239
- event.nativeEvent.layout;
315
+ const {
316
+ width: layoutWidth,
317
+
318
+ height: layoutHeight,
319
+ } = event.nativeEvent.layout;
240
320
 
241
321
  const length =
242
322
  safeOrientation === UISLIDER_ORIENTATIONS.horizontal
@@ -249,18 +329,13 @@ const UISliderComponent = forwardRef(function UISlider(
249
329
 
250
330
  setMeasuredLength(safeLength);
251
331
  },
332
+
252
333
  [safeOrientation],
253
334
  );
254
335
 
255
- // -----------------------------------------
256
- // PERCENTAGE
257
- // -----------------------------------------
258
-
259
- const percentage = range > 0 ? ((currentValue - safeMin) / range) * 100 : 0;
260
-
261
- // -----------------------------------------
336
+ // ========================================================
262
337
  // ANIMATED VALUES
263
- // -----------------------------------------
338
+ // ========================================================
264
339
 
265
340
  const thumbProgress = useRef(new Animated.Value(percentage)).current;
266
341
 
@@ -268,14 +343,25 @@ const UISliderComponent = forwardRef(function UISlider(
268
343
 
269
344
  const thumbScale = useRef(new Animated.Value(1)).current;
270
345
 
346
+ // ========================================================
347
+ // PREVIOUS PERCENTAGE
348
+ // ========================================================
349
+
271
350
  const previousPercentage = useRef(percentage);
272
351
 
273
- // -----------------------------------------
274
- // KEEP ANIMATION DRIVER CONSISTENT
275
- // -----------------------------------------
352
+ // ========================================================
353
+ // ANIMATION FUNCTION
354
+ // ========================================================
276
355
 
277
356
  const runTiming = useCallback(
278
357
  (animatedValue, toValue) => {
358
+ /*
359
+ * Animation disabled.
360
+ *
361
+ * Immediately update the
362
+ * Animated.Value.
363
+ */
364
+
279
365
  if (!animated) {
280
366
  animatedValue.stopAnimation();
281
367
 
@@ -290,22 +376,23 @@ const UISliderComponent = forwardRef(function UISlider(
290
376
  duration: Math.max(0, Number(animationDuration) || 0),
291
377
 
292
378
  /*
293
- * IMPORTANT:
294
- *
295
- * Every Animated.Value in this
296
- * component uses JS driver.
379
+ * VERY IMPORTANT
297
380
  *
298
- * Do NOT change this to true.
381
+ * Keep this false for
382
+ * ALL Animated.Values
383
+ * in this component.
299
384
  */
385
+
300
386
  useNativeDriver: false,
301
387
  }).start();
302
388
  },
389
+
303
390
  [animated, animationDuration],
304
391
  );
305
392
 
306
- // -----------------------------------------
307
- // PROGRAMMATIC VALUE CHANGE
308
- // -----------------------------------------
393
+ // ========================================================
394
+ // PROGRAMMATIC ANIMATION
395
+ // ========================================================
309
396
 
310
397
  useEffect(() => {
311
398
  const nextPercentage =
@@ -317,10 +404,9 @@ const UISliderComponent = forwardRef(function UISlider(
317
404
 
318
405
  previousPercentage.current = nextPercentage;
319
406
 
320
- /*
321
- * During a programmatic value change,
322
- * animate only when requested.
323
- */
407
+ // ------------------------------------------------------
408
+ // THUMB
409
+ // ------------------------------------------------------
324
410
 
325
411
  if (animated && animateThumb) {
326
412
  runTiming(thumbProgress, nextPercentage);
@@ -330,6 +416,10 @@ const UISliderComponent = forwardRef(function UISlider(
330
416
  thumbProgress.setValue(nextPercentage);
331
417
  }
332
418
 
419
+ // ------------------------------------------------------
420
+ // TRACK
421
+ // ------------------------------------------------------
422
+
333
423
  if (animated && animateTrack) {
334
424
  runTiming(trackProgress, nextPercentage);
335
425
  } else {
@@ -339,22 +429,27 @@ const UISliderComponent = forwardRef(function UISlider(
339
429
  }
340
430
  }, [
341
431
  currentValue,
432
+
342
433
  safeMin,
434
+
343
435
  range,
344
436
 
345
437
  animated,
438
+
346
439
  animateThumb,
440
+
347
441
  animateTrack,
348
442
 
349
443
  runTiming,
350
444
 
351
445
  thumbProgress,
446
+
352
447
  trackProgress,
353
448
  ]);
354
449
 
355
- // -----------------------------------------
450
+ // ========================================================
356
451
  // COLORS
357
- // -----------------------------------------
452
+ // ========================================================
358
453
 
359
454
  const resolvedMinimumTrackColor =
360
455
  minimumTrackColor || colors.primary || "#FF5A1F";
@@ -364,9 +459,9 @@ const UISliderComponent = forwardRef(function UISlider(
364
459
 
365
460
  const resolvedThumbColor = thumbColor || colors.primary || "#FF5A1F";
366
461
 
367
- // -----------------------------------------
368
- // CHANGE
369
- // -----------------------------------------
462
+ // ========================================================
463
+ // EMIT CHANGE
464
+ // ========================================================
370
465
 
371
466
  const emitChange = useCallback(
372
467
  (nextValue) => {
@@ -380,12 +475,13 @@ const UISliderComponent = forwardRef(function UISlider(
380
475
 
381
476
  return normalized;
382
477
  },
478
+
383
479
  [normalizeValue, value, onChange],
384
480
  );
385
481
 
386
- // -----------------------------------------
387
- // POSITION -> VALUE
388
- // -----------------------------------------
482
+ // ========================================================
483
+ // POSITION TO VALUE
484
+ // ========================================================
389
485
 
390
486
  const positionToValue = useCallback(
391
487
  (position) => {
@@ -395,23 +491,35 @@ const UISliderComponent = forwardRef(function UISlider(
395
491
 
396
492
  ratio = Math.max(0, Math.min(ratio, 1));
397
493
 
494
+ /*
495
+ * Vertical slider:
496
+ *
497
+ * top = max
498
+ * bottom = min
499
+ */
500
+
398
501
  if (safeOrientation === UISLIDER_ORIENTATIONS.vertical) {
399
502
  ratio = 1 - ratio;
400
503
  }
401
504
 
402
505
  return safeMin + ratio * range;
403
506
  },
507
+
404
508
  [safeOrientation, safeMin, range],
405
509
  );
406
510
 
407
- // -----------------------------------------
408
- // DRAG UPDATE
409
- // -----------------------------------------
511
+ // ========================================================
512
+ // DRAGGING
513
+ // ========================================================
410
514
 
411
515
  const sliding = useRef(false);
412
516
 
413
517
  const lastGestureValue = useRef(currentValue);
414
518
 
519
+ // ========================================================
520
+ // UPDATE FROM POSITION
521
+ // ========================================================
522
+
415
523
  const updateFromPosition = useCallback(
416
524
  (position) => {
417
525
  const nextValue = positionToValue(position);
@@ -421,60 +529,37 @@ const UISliderComponent = forwardRef(function UISlider(
421
529
  lastGestureValue.current = normalized;
422
530
 
423
531
  /*
424
- * IMPORTANT:
425
- *
426
- * While dragging we update the
427
- * Animated.Values directly.
532
+ * Update animation values
533
+ * immediately during drag.
428
534
  *
429
- * We do NOT start timing animations
430
- * for every finger movement.
535
+ * We DO NOT run timing on
536
+ * every finger movement.
431
537
  */
538
+
432
539
  const nextPercentage =
433
540
  range > 0 ? ((normalized - safeMin) / range) * 100 : 0;
434
541
 
435
- if (animateThumb || animated) {
436
- thumbProgress.stopAnimation();
542
+ thumbProgress.stopAnimation();
437
543
 
438
- thumbProgress.setValue(nextPercentage);
439
- }
544
+ trackProgress.stopAnimation();
440
545
 
441
- if (animateTrack || animated) {
442
- trackProgress.stopAnimation();
546
+ thumbProgress.setValue(nextPercentage);
443
547
 
444
- trackProgress.setValue(nextPercentage);
445
- }
548
+ trackProgress.setValue(nextPercentage);
446
549
  },
447
- [
448
- positionToValue,
449
- emitChange,
450
- range,
451
- safeMin,
452
-
453
- animateThumb,
454
- animateTrack,
455
- animated,
456
550
 
457
- thumbProgress,
458
- trackProgress,
459
- ],
551
+ [positionToValue, emitChange, range, safeMin, thumbProgress, trackProgress],
460
552
  );
461
553
 
462
- // -----------------------------------------
463
- // PRESS ANIMATION
464
- // -----------------------------------------
554
+ // ========================================================
555
+ // PRESS IN ANIMATION
556
+ // ========================================================
465
557
 
466
558
  const animatePressIn = useCallback(() => {
467
559
  if (!animated || !animatePress) {
468
560
  return;
469
561
  }
470
562
 
471
- /*
472
- * IMPORTANT:
473
- *
474
- * useNativeDriver MUST remain false
475
- * because thumbScale uses the same
476
- * JS animation system as the slider.
477
- */
478
563
  Animated.spring(thumbScale, {
479
564
  toValue: pressScale,
480
565
 
@@ -482,10 +567,18 @@ const UISliderComponent = forwardRef(function UISlider(
482
567
 
483
568
  tension: 120,
484
569
 
570
+ /*
571
+ * MUST REMAIN FALSE.
572
+ */
573
+
485
574
  useNativeDriver: false,
486
575
  }).start();
487
576
  }, [animated, animatePress, pressScale, thumbScale]);
488
577
 
578
+ // ========================================================
579
+ // PRESS OUT ANIMATION
580
+ // ========================================================
581
+
489
582
  const animatePressOut = useCallback(() => {
490
583
  if (!animated || !animatePress) {
491
584
  return;
@@ -498,13 +591,17 @@ const UISliderComponent = forwardRef(function UISlider(
498
591
 
499
592
  tension: 120,
500
593
 
594
+ /*
595
+ * MUST REMAIN FALSE.
596
+ */
597
+
501
598
  useNativeDriver: false,
502
599
  }).start();
503
600
  }, [animated, animatePress, thumbScale]);
504
601
 
505
- // -----------------------------------------
602
+ // ========================================================
506
603
  // PAN RESPONDER
507
- // -----------------------------------------
604
+ // ========================================================
508
605
 
509
606
  const panResponder = useMemo(
510
607
  () =>
@@ -581,27 +678,33 @@ const UISliderComponent = forwardRef(function UISlider(
581
678
  onSlidingComplete?.(finalValue);
582
679
  },
583
680
  }),
681
+
584
682
  [
585
683
  disabled,
684
+
586
685
  currentValue,
587
686
 
588
687
  safeOrientation,
589
688
 
590
689
  animatePressIn,
690
+
591
691
  animatePressOut,
592
692
 
593
693
  updateFromPosition,
594
694
 
595
695
  onChangeStart,
696
+
596
697
  onSlidingStart,
698
+
597
699
  onChangeEnd,
700
+
598
701
  onSlidingComplete,
599
702
  ],
600
703
  );
601
704
 
602
- // -----------------------------------------
705
+ // ========================================================
603
706
  // DISPLAY VALUE
604
- // -----------------------------------------
707
+ // ========================================================
605
708
 
606
709
  const displayValue = valueFormatter
607
710
  ? valueFormatter(currentValue)
@@ -611,35 +714,15 @@ const UISliderComponent = forwardRef(function UISlider(
611
714
 
612
715
  const displayMax = maxLabel ?? formatValue(safeMax);
613
716
 
614
- // -----------------------------------------
615
- // TRACK LENGTH
616
- // -----------------------------------------
717
+ // ========================================================
718
+ // USABLE LENGTH
719
+ // ========================================================
617
720
 
618
721
  const usableLength = Math.max(measuredLength - resolvedThumbSize, 0);
619
722
 
620
- // -----------------------------------------
621
- // ACCESSIBILITY
622
- // -----------------------------------------
623
-
624
- const increase = useCallback(() => {
625
- if (disabled) {
626
- return;
627
- }
628
-
629
- emitChange(currentValue + safeStep);
630
- }, [disabled, emitChange, currentValue, safeStep]);
631
-
632
- const decrease = useCallback(() => {
633
- if (disabled) {
634
- return;
635
- }
636
-
637
- emitChange(currentValue - safeStep);
638
- }, [disabled, emitChange, currentValue, safeStep]);
639
-
640
- // -----------------------------------------
723
+ // ========================================================
641
724
  // RENDER
642
- // -----------------------------------------
725
+ // ========================================================
643
726
 
644
727
  return (
645
728
  <View
@@ -672,9 +755,9 @@ const UISliderComponent = forwardRef(function UISlider(
672
755
  now: currentValue,
673
756
  }}
674
757
  >
675
- {/* -------------------------------- */}
758
+ {/* ================================================= */}
676
759
  {/* HEADER */}
677
- {/* -------------------------------- */}
760
+ {/* ================================================= */}
678
761
 
679
762
  {label || showValue ? (
680
763
  <View style={styles.header}>
@@ -718,9 +801,9 @@ const UISliderComponent = forwardRef(function UISlider(
718
801
  </View>
719
802
  ) : null}
720
803
 
721
- {/* -------------------------------- */}
804
+ {/* ================================================= */}
722
805
  {/* SLIDER */}
723
- {/* -------------------------------- */}
806
+ {/* ================================================= */}
724
807
 
725
808
  <View
726
809
  style={[
@@ -756,9 +839,9 @@ const UISliderComponent = forwardRef(function UISlider(
756
839
  },
757
840
  ]}
758
841
  >
759
- {/* -------------------------------- */}
760
- {/* MAXIMUM TRACK */}
761
- {/* -------------------------------- */}
842
+ {/* ============================================ */}
843
+ {/* MAX TRACK */}
844
+ {/* ============================================ */}
762
845
 
763
846
  <View
764
847
  pointerEvents="none"
@@ -795,9 +878,9 @@ const UISliderComponent = forwardRef(function UISlider(
795
878
  ]}
796
879
  />
797
880
 
798
- {/* -------------------------------- */}
881
+ {/* ============================================ */}
799
882
  {/* ACTIVE TRACK */}
800
- {/* -------------------------------- */}
883
+ {/* ============================================ */}
801
884
 
802
885
  <Animated.View
803
886
  pointerEvents="none"
@@ -844,9 +927,9 @@ const UISliderComponent = forwardRef(function UISlider(
844
927
  ]}
845
928
  />
846
929
 
847
- {/* -------------------------------- */}
930
+ {/* ============================================ */}
848
931
  {/* THUMB */}
849
- {/* -------------------------------- */}
932
+ {/* ============================================ */}
850
933
 
851
934
  <Animated.View
852
935
  pointerEvents="none"
@@ -897,9 +980,9 @@ const UISliderComponent = forwardRef(function UISlider(
897
980
  </View>
898
981
  </View>
899
982
 
900
- {/* -------------------------------- */}
983
+ {/* ================================================= */}
901
984
  {/* MIN / MAX */}
902
- {/* -------------------------------- */}
985
+ {/* ================================================= */}
903
986
 
904
987
  {showMinMax ? (
905
988
  <View
@@ -941,9 +1024,9 @@ const UISliderComponent = forwardRef(function UISlider(
941
1024
  </View>
942
1025
  ) : null}
943
1026
 
944
- {/* -------------------------------- */}
1027
+ {/* ================================================= */}
945
1028
  {/* ERROR / HELPER */}
946
- {/* -------------------------------- */}
1029
+ {/* ================================================= */}
947
1030
 
948
1031
  {error || errorText ? (
949
1032
  <Text
@@ -974,33 +1057,13 @@ const UISliderComponent = forwardRef(function UISlider(
974
1057
  {helperText}
975
1058
  </Text>
976
1059
  ) : null}
977
-
978
- {/* -------------------------------- */}
979
- {/* ACCESSIBILITY BUTTONS */}
980
- {/* -------------------------------- */}
981
-
982
- {!disabled ? (
983
- <View style={styles.accessibilityActions}>
984
- <Pressable
985
- onPress={decrease}
986
- accessibilityRole="button"
987
- accessibilityLabel="Decrease slider value"
988
- />
989
-
990
- <Pressable
991
- onPress={increase}
992
- accessibilityRole="button"
993
- accessibilityLabel="Increase slider value"
994
- />
995
- </View>
996
- ) : null}
997
1060
  </View>
998
1061
  );
999
1062
  });
1000
1063
 
1001
- // ======================================================
1064
+ // ============================================================
1002
1065
  // HELPERS
1003
- // ======================================================
1066
+ // ============================================================
1004
1067
 
1005
1068
  function getDimensions(size) {
1006
1069
  switch (size) {
@@ -1017,6 +1080,7 @@ function getDimensions(size) {
1017
1080
  };
1018
1081
 
1019
1082
  case UISLIDER_SIZES.md:
1083
+
1020
1084
  default:
1021
1085
  return {
1022
1086
  thumbSize: 22,
@@ -1025,6 +1089,10 @@ function getDimensions(size) {
1025
1089
  }
1026
1090
  }
1027
1091
 
1092
+ // ============================================================
1093
+ // FORMAT VALUE
1094
+ // ============================================================
1095
+
1028
1096
  function formatValue(value) {
1029
1097
  if (Number.isInteger(value)) {
1030
1098
  return String(value);
@@ -1033,13 +1101,17 @@ function formatValue(value) {
1033
1101
  return String(Number(Number(value).toFixed(2)));
1034
1102
  }
1035
1103
 
1104
+ // ============================================================
1105
+ // ROUND
1106
+ // ============================================================
1107
+
1036
1108
  function roundValue(value) {
1037
1109
  return Number(Number(value).toFixed(10));
1038
1110
  }
1039
1111
 
1040
- // ======================================================
1112
+ // ============================================================
1041
1113
  // STYLES
1042
- // ======================================================
1114
+ // ============================================================
1043
1115
 
1044
1116
  const styles = StyleSheet.create({
1045
1117
  container: {
@@ -1146,20 +1218,12 @@ const styles = StyleSheet.create({
1146
1218
 
1147
1219
  includeFontPadding: false,
1148
1220
  },
1149
-
1150
- accessibilityActions: {
1151
- position: "absolute",
1152
-
1153
- width: 1,
1154
-
1155
- height: 1,
1156
-
1157
- opacity: 0,
1158
-
1159
- overflow: "hidden",
1160
- },
1161
1221
  });
1162
1222
 
1223
+ // ============================================================
1224
+ // EXPORT
1225
+ // ============================================================
1226
+
1163
1227
  export const UISlider = memo(UISliderComponent);
1164
1228
 
1165
1229
  UISlider.displayName = "UISlider";