fluent-styles 1.62.3 → 1.62.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/lib/commonjs/badge/index.js +13 -8
  2. package/lib/commonjs/badge/index.js.map +1 -1
  3. package/lib/commonjs/button/index.js +4 -3
  4. package/lib/commonjs/button/index.js.map +1 -1
  5. package/lib/commonjs/card/index.js +23 -15
  6. package/lib/commonjs/card/index.js.map +1 -1
  7. package/lib/commonjs/checkBox/index.js +5 -3
  8. package/lib/commonjs/checkBox/index.js.map +1 -1
  9. package/lib/commonjs/dropdown/index.js +10 -6
  10. package/lib/commonjs/dropdown/index.js.map +1 -1
  11. package/lib/commonjs/header/index.js +59 -55
  12. package/lib/commonjs/header/index.js.map +1 -1
  13. package/lib/commonjs/image/index.js +5 -3
  14. package/lib/commonjs/image/index.js.map +1 -1
  15. package/lib/commonjs/index.js +7 -0
  16. package/lib/commonjs/index.js.map +1 -1
  17. package/lib/commonjs/input/index.js +5 -3
  18. package/lib/commonjs/input/index.js.map +1 -1
  19. package/lib/commonjs/page/index.js +20 -4
  20. package/lib/commonjs/page/index.js.map +1 -1
  21. package/lib/commonjs/safeAreaView/index.js +4 -0
  22. package/lib/commonjs/safeAreaView/index.js.map +1 -1
  23. package/lib/commonjs/seperator/index.js +5 -3
  24. package/lib/commonjs/seperator/index.js.map +1 -1
  25. package/lib/commonjs/shape/cycle.js +5 -3
  26. package/lib/commonjs/shape/cycle.js.map +1 -1
  27. package/lib/commonjs/shape/index.js +6 -3
  28. package/lib/commonjs/shape/index.js.map +1 -1
  29. package/lib/commonjs/slider/index.js +72 -22
  30. package/lib/commonjs/slider/index.js.map +1 -1
  31. package/lib/commonjs/spinner/index.js +17 -11
  32. package/lib/commonjs/spinner/index.js.map +1 -1
  33. package/lib/commonjs/utiles/styled.js +14 -32
  34. package/lib/commonjs/utiles/styled.js.map +1 -1
  35. package/lib/module/badge/index.js +10 -8
  36. package/lib/module/badge/index.js.map +1 -1
  37. package/lib/module/button/index.js +4 -3
  38. package/lib/module/button/index.js.map +1 -1
  39. package/lib/module/card/index.js +20 -15
  40. package/lib/module/card/index.js.map +1 -1
  41. package/lib/module/checkBox/index.js +5 -4
  42. package/lib/module/checkBox/index.js.map +1 -1
  43. package/lib/module/dropdown/index.js +9 -7
  44. package/lib/module/dropdown/index.js.map +1 -1
  45. package/lib/module/header/index.js +52 -48
  46. package/lib/module/header/index.js.map +1 -1
  47. package/lib/module/image/index.js +4 -3
  48. package/lib/module/image/index.js.map +1 -1
  49. package/lib/module/index.js +1 -1
  50. package/lib/module/index.js.map +1 -1
  51. package/lib/module/input/index.js +5 -4
  52. package/lib/module/input/index.js.map +1 -1
  53. package/lib/module/page/index.js +21 -4
  54. package/lib/module/page/index.js.map +1 -1
  55. package/lib/module/safeAreaView/index.js +4 -0
  56. package/lib/module/safeAreaView/index.js.map +1 -1
  57. package/lib/module/seperator/index.js +4 -3
  58. package/lib/module/seperator/index.js.map +1 -1
  59. package/lib/module/shape/cycle.js +4 -3
  60. package/lib/module/shape/cycle.js.map +1 -1
  61. package/lib/module/shape/index.js +6 -3
  62. package/lib/module/shape/index.js.map +1 -1
  63. package/lib/module/slider/index.js +72 -22
  64. package/lib/module/slider/index.js.map +1 -1
  65. package/lib/module/spinner/index.js +13 -10
  66. package/lib/module/spinner/index.js.map +1 -1
  67. package/lib/module/utiles/styled.js +13 -31
  68. package/lib/module/utiles/styled.js.map +1 -1
  69. package/lib/typescript/badge/index.d.ts +13 -6
  70. package/lib/typescript/badge/index.d.ts.map +1 -1
  71. package/lib/typescript/button/index.d.ts +12 -8
  72. package/lib/typescript/button/index.d.ts.map +1 -1
  73. package/lib/typescript/card/index.d.ts +37 -10
  74. package/lib/typescript/card/index.d.ts.map +1 -1
  75. package/lib/typescript/checkBox/index.d.ts +12 -1
  76. package/lib/typescript/checkBox/index.d.ts.map +1 -1
  77. package/lib/typescript/dialog/index.d.ts +6 -3
  78. package/lib/typescript/dialog/index.d.ts.map +1 -1
  79. package/lib/typescript/divider/index.d.ts +6 -3
  80. package/lib/typescript/divider/index.d.ts.map +1 -1
  81. package/lib/typescript/dropdown/index.d.ts +12 -2
  82. package/lib/typescript/dropdown/index.d.ts.map +1 -1
  83. package/lib/typescript/header/index.d.ts +6 -8
  84. package/lib/typescript/header/index.d.ts.map +1 -1
  85. package/lib/typescript/image/index.d.ts +9 -4
  86. package/lib/typescript/image/index.d.ts.map +1 -1
  87. package/lib/typescript/index.d.ts +1 -1
  88. package/lib/typescript/index.d.ts.map +1 -1
  89. package/lib/typescript/input/index.d.ts +12 -1
  90. package/lib/typescript/input/index.d.ts.map +1 -1
  91. package/lib/typescript/page/index.d.ts +17 -7
  92. package/lib/typescript/page/index.d.ts.map +1 -1
  93. package/lib/typescript/pressable/index.d.ts +6 -3
  94. package/lib/typescript/pressable/index.d.ts.map +1 -1
  95. package/lib/typescript/safeAreaProvider/index.d.ts +6 -3
  96. package/lib/typescript/safeAreaProvider/index.d.ts.map +1 -1
  97. package/lib/typescript/safeAreaView/index.d.ts +6 -3
  98. package/lib/typescript/safeAreaView/index.d.ts.map +1 -1
  99. package/lib/typescript/scrollView/index.d.ts +6 -3
  100. package/lib/typescript/scrollView/index.d.ts.map +1 -1
  101. package/lib/typescript/seperator/index.d.ts +7 -2
  102. package/lib/typescript/seperator/index.d.ts.map +1 -1
  103. package/lib/typescript/shape/cycle.d.ts +12 -4
  104. package/lib/typescript/shape/cycle.d.ts.map +1 -1
  105. package/lib/typescript/shape/index.d.ts +7 -4
  106. package/lib/typescript/shape/index.d.ts.map +1 -1
  107. package/lib/typescript/slider/index.d.ts +27 -5
  108. package/lib/typescript/slider/index.d.ts.map +1 -1
  109. package/lib/typescript/spacer/index.d.ts +6 -3
  110. package/lib/typescript/spacer/index.d.ts.map +1 -1
  111. package/lib/typescript/spinner/index.d.ts +18 -3
  112. package/lib/typescript/spinner/index.d.ts.map +1 -1
  113. package/lib/typescript/stack/index.d.ts +18 -9
  114. package/lib/typescript/stack/index.d.ts.map +1 -1
  115. package/lib/typescript/text/index.d.ts +6 -3
  116. package/lib/typescript/text/index.d.ts.map +1 -1
  117. package/lib/typescript/utiles/styled.d.ts +7 -4
  118. package/lib/typescript/utiles/styled.d.ts.map +1 -1
  119. package/package.json +1 -1
  120. package/src/badge/index.tsx +7 -17
  121. package/src/button/index.tsx +7 -12
  122. package/src/card/index.tsx +21 -23
  123. package/src/checkBox/index.tsx +16 -21
  124. package/src/dropdown/index.tsx +59 -67
  125. package/src/header/index.tsx +119 -112
  126. package/src/image/index.tsx +2 -2
  127. package/src/index.ts +1 -1
  128. package/src/input/index.tsx +56 -59
  129. package/src/page/index.tsx +21 -3
  130. package/src/safeAreaView/index.tsx +6 -2
  131. package/src/seperator/index.tsx +4 -10
  132. package/src/shape/cycle.tsx +10 -12
  133. package/src/shape/index.tsx +7 -3
  134. package/src/slider/index.tsx +82 -46
  135. package/src/spinner/index.tsx +49 -55
  136. package/src/utiles/styled.tsx +14 -27
@@ -10,11 +10,33 @@
10
10
  * • gradient — gradient-filled track
11
11
  * • buffer — primary thumb + secondary buffer fill (media player style)
12
12
  *
13
- * Tooltip fix (three-layer layout):
14
- * Track fill lives in its own overflow:hidden View
15
- * Thumbs + tooltips live in a sibling overflow:visible wrapper
16
- * SVG <Path> triangle pointer never clips, always sharp
17
- * useNativeDriver: false for tooltipAnim so text colour renders correctly on iOS
13
+ * FIX (v1.1):
14
+ * The previous version had a useEffect(() => setLocalLow(value), [value])
15
+ * that created a feedback loop when used as a controlled component:
16
+ * onValueChange setState re-render value prop changes
17
+ * useEffect fires setLocalLow resets thumb snaps back
18
+ *
19
+ * Fix strategy:
20
+ * 1. useEffect only fires on MOUNT (empty dep array) — sets initial position once
21
+ * 2. External value changes are ignored while dragging (dragging ref guard)
22
+ * 3. External value changes ARE applied when not dragging (programmatic updates work)
23
+ * 4. onValueChange fires continuously during drag (for live display updates)
24
+ * 5. onSlidingComplete fires once on finger lift (for committing to state)
25
+ *
26
+ * Correct usage in parent (controlled, live display):
27
+ * const displayRef = useRef(initialValue) // never causes re-render
28
+ * const [display, setDisplay] = useState(initialValue)
29
+ * <StyledSlider
30
+ * value={initialValue} // ← frozen, never updated
31
+ * onValueChange={v => { displayRef.current = v; setDisplay(v) }}
32
+ * onSlidingComplete={v => commitToState(v)}
33
+ * />
34
+ *
35
+ * Simplest usage (fire-and-forget):
36
+ * <StyledSlider
37
+ * value={28}
38
+ * onSlidingComplete={v => saveValue(v)}
39
+ * />
18
40
  */
19
41
 
20
42
  import React, { useCallback, useRef, useState, useEffect } from "react";
@@ -117,11 +139,6 @@ function snapToStep(
117
139
  }
118
140
 
119
141
  // ─── Tooltip ──────────────────────────────────────────────────────────────────
120
- //
121
- // Self-measuring: measures its own width after first layout, then applies
122
- // translateX = -(width/2) to centre precisely over the thumb.
123
- // Uses useNativeDriver: false for opacity so iOS renders text colour correctly.
124
- // SVG Path triangle — never clips, always pixel-perfect.
125
142
 
126
143
  const Tooltip: React.FC<{
127
144
  visible: Animated.Value;
@@ -158,7 +175,7 @@ const Tooltip: React.FC<{
158
175
  borderRadius={4}
159
176
  alignItems="center"
160
177
  justifyContent="center"
161
- minWidth={label.length * 18} // rough guess to prevent excessive shrinking for short labels
178
+ minWidth={label.length * 18}
162
179
  >
163
180
  <StyledText
164
181
  numberOfLines={1}
@@ -230,9 +247,7 @@ const Thumb: React.FC<ThumbProps> = ({
230
247
  onMove,
231
248
  onEnd,
232
249
  }) => {
233
- // scaleAnim uses native driver (transform only — safe)
234
250
  const scaleAnim = useRef(new Animated.Value(1)).current;
235
- // tooltipAnim uses JS driver (opacity — required for text colour on iOS)
236
251
  const tooltipAnim = useRef(new Animated.Value(alwaysTooltip ? 1 : 0)).current;
237
252
  const dragging = useRef(false);
238
253
 
@@ -254,7 +269,7 @@ const Thumb: React.FC<ThumbProps> = ({
254
269
  Animated.timing(tooltipAnim, {
255
270
  toValue: alwaysTooltip ? 1 : 0,
256
271
  duration: 150,
257
- useNativeDriver: false, // JS driver — keeps text colour correct on iOS
272
+ useNativeDriver: false,
258
273
  }),
259
274
  ]).start();
260
275
  };
@@ -293,10 +308,10 @@ const Thumb: React.FC<ThumbProps> = ({
293
308
  style={{
294
309
  position: "absolute",
295
310
  left,
296
- top: 0, // wrapper height = thumbD, centred
311
+ top: 0,
297
312
  width: thumbD,
298
313
  height: thumbD,
299
- overflow: "visible", // tooltip floats up freely
314
+ overflow: "visible",
300
315
  transform: [{ scale: scaleAnim }],
301
316
  }}
302
317
  >
@@ -309,7 +324,6 @@ const Thumb: React.FC<ThumbProps> = ({
309
324
  />
310
325
  )}
311
326
 
312
- {/* Thumb circle */}
313
327
  <View
314
328
  style={{
315
329
  width: thumbD,
@@ -393,28 +407,56 @@ export const StyledSlider: React.FC<StyledSliderProps> = ({
393
407
  const [trackW, setTrackW] = useState(widthProp ?? 0);
394
408
  const barW = widthProp ?? trackW;
395
409
 
396
- const [localLow, setLocalLow] = useState(value);
410
+ const [localLow, setLocalLow] = useState(value);
397
411
  const [localHigh, setLocalHigh] = useState(valueHigh ?? max);
398
- const [bufLocal, setBufLocal] = useState(bufferValue ?? value);
399
-
412
+ const [bufLocal, setBufLocal] = useState(bufferValue ?? value);
413
+
414
+ // ─── FIX: track whether a thumb is currently being dragged ───────────────
415
+ // When dragging, we IGNORE external value prop changes entirely.
416
+ // This prevents the feedback loop:
417
+ // onValueChange → parent setState → value prop changes
418
+ // → useEffect → setLocalLow resets thumb → snap-back
419
+ const isDraggingLow = useRef(false);
420
+ const isDraggingHigh = useRef(false);
421
+
422
+ // Sync localLow from external value prop ONLY when not dragging.
423
+ // On mount (prevValue is undefined) we always sync.
424
+ const prevValueRef = useRef<number | undefined>(undefined);
400
425
  useEffect(() => {
426
+ if (isDraggingLow.current) return; // ← guard: ignore during drag
427
+ if (prevValueRef.current === value) return; // ← no-op if value unchanged
428
+ prevValueRef.current = value;
401
429
  setLocalLow(value);
402
430
  }, [value]);
431
+
432
+ // Sync localHigh from external valueHigh prop ONLY when not dragging.
433
+ const prevHighRef = useRef<number | undefined>(undefined);
403
434
  useEffect(() => {
404
- if (valueHigh !== undefined) setLocalHigh(valueHigh);
435
+ if (isDraggingHigh.current) return;
436
+ if (valueHigh === undefined) return;
437
+ if (prevHighRef.current === valueHigh) return;
438
+ prevHighRef.current = valueHigh;
439
+ setLocalHigh(valueHigh);
405
440
  }, [valueHigh]);
441
+
442
+ // bufferValue sync is safe — no thumb drag involved
406
443
  useEffect(() => {
407
444
  if (bufferValue !== undefined) setBufLocal(bufferValue);
408
445
  }, [bufferValue]);
409
446
 
410
447
  const range = max - min;
411
- const lowF = clamp((localLow - min) / range, 0, 1);
448
+ const lowF = clamp((localLow - min) / range, 0, 1);
412
449
  const highF = clamp((localHigh - min) / range, 0, 1);
413
- const bufF = clamp((bufLocal - min) / range, 0, 1);
450
+ const bufF = clamp((bufLocal - min) / range, 0, 1);
414
451
 
415
452
  const effectiveStep =
416
453
  variant === "stepped" ? (max - min) / (steps - 1) : step;
417
454
 
455
+ // ─── Low thumb handlers ───────────────────────────────────────────────────
456
+ const handleLowStart = useCallback(() => {
457
+ isDraggingLow.current = true;
458
+ }, []);
459
+
418
460
  const handleLowMove = useCallback(
419
461
  (frac: number) => {
420
462
  const snapped = snapToStep(
@@ -427,22 +469,22 @@ export const StyledSlider: React.FC<StyledSliderProps> = ({
427
469
  onValueChange?.(snapped);
428
470
  if (variant === "range") onRangeChange?.(snapped, localHigh);
429
471
  },
430
- [
431
- min,
432
- range,
433
- effectiveStep,
434
- localHigh,
435
- variant,
436
- onValueChange,
437
- onRangeChange,
438
- ],
472
+ [min, range, effectiveStep, localHigh, variant, onValueChange, onRangeChange],
439
473
  );
440
474
 
441
475
  const handleLowEnd = useCallback(() => {
476
+ isDraggingLow.current = false;
477
+ // Update prevValueRef so the next external change is not swallowed
478
+ prevValueRef.current = localLow;
442
479
  onSlidingComplete?.(localLow);
443
480
  if (variant === "range") onRangeComplete?.(localLow, localHigh);
444
481
  }, [localLow, localHigh, variant, onSlidingComplete, onRangeComplete]);
445
482
 
483
+ // ─── High thumb handlers (range variant) ─────────────────────────────────
484
+ const handleHighStart = useCallback(() => {
485
+ isDraggingHigh.current = true;
486
+ }, []);
487
+
446
488
  const handleHighMove = useCallback(
447
489
  (frac: number) => {
448
490
  const snapped = snapToStep(
@@ -458,6 +500,8 @@ export const StyledSlider: React.FC<StyledSliderProps> = ({
458
500
  );
459
501
 
460
502
  const handleHighEnd = useCallback(() => {
503
+ isDraggingHigh.current = false;
504
+ prevHighRef.current = localHigh;
461
505
  onRangeComplete?.(localLow, localHigh);
462
506
  }, [localLow, localHigh, onRangeComplete]);
463
507
 
@@ -486,16 +530,11 @@ export const StyledSlider: React.FC<StyledSliderProps> = ({
486
530
  paddingBottom: showMinMax ? 20 : 8,
487
531
  }}
488
532
  >
489
- {/* ── Three-layer layout ──
490
- Layer 1: track fills (overflow hidden — clips fill bars only)
491
- Layer 2: tick marks (overflow visible — poke above/below)
492
- Layer 3: thumbs (overflow visible — tooltips float freely)
493
- ── */}
494
533
  <View
495
534
  style={{
496
535
  width: barW,
497
536
  height: thumbD,
498
- overflow: "visible", // thumbs + tooltips escape freely
537
+ overflow: "visible",
499
538
  justifyContent: "center",
500
539
  }}
501
540
  >
@@ -508,10 +547,9 @@ export const StyledSlider: React.FC<StyledSliderProps> = ({
508
547
  height: trackH,
509
548
  borderRadius: trackBR,
510
549
  backgroundColor: C.track,
511
- overflow: "hidden", // only fills are clipped
550
+ overflow: "hidden",
512
551
  }}
513
552
  >
514
- {/* Buffer fill */}
515
553
  {variant === "buffer" && (
516
554
  <View
517
555
  style={{
@@ -526,7 +564,6 @@ export const StyledSlider: React.FC<StyledSliderProps> = ({
526
564
  />
527
565
  )}
528
566
 
529
- {/* Range fill */}
530
567
  {variant === "range" ? (
531
568
  <View
532
569
  style={{
@@ -579,7 +616,7 @@ export const StyledSlider: React.FC<StyledSliderProps> = ({
579
616
  />
580
617
  ))}
581
618
 
582
- {/* ── Layer 3: Thumbs (tooltips float up from here) ── */}
619
+ {/* ── Layer 3: Thumbs ── */}
583
620
  <Thumb
584
621
  position={lowF}
585
622
  trackWidth={barW}
@@ -593,7 +630,7 @@ export const StyledSlider: React.FC<StyledSliderProps> = ({
593
630
  tooltipBg={C.tooltipBg}
594
631
  tooltipText={C.tooltipText}
595
632
  disabled={disabled}
596
- onStart={() => {}}
633
+ onStart={handleLowStart}
597
634
  onMove={handleLowMove}
598
635
  onEnd={handleLowEnd}
599
636
  />
@@ -612,14 +649,13 @@ export const StyledSlider: React.FC<StyledSliderProps> = ({
612
649
  tooltipBg={C.tooltipBg}
613
650
  tooltipText={C.tooltipText}
614
651
  disabled={disabled}
615
- onStart={() => {}}
652
+ onStart={handleHighStart}
616
653
  onMove={handleHighMove}
617
654
  onEnd={handleHighEnd}
618
655
  />
619
656
  )}
620
657
  </View>
621
658
 
622
- {/* Min / max labels */}
623
659
  {showMinMax && (
624
660
  <Stack horizontal justifyContent="space-between" marginTop={6}>
625
661
  <StyledText fontSize={11} color={C.rangeLabel}>
@@ -634,4 +670,4 @@ export const StyledSlider: React.FC<StyledSliderProps> = ({
634
670
  );
635
671
  };
636
672
 
637
- export default StyledSlider;
673
+ export default StyledSlider;
@@ -1,4 +1,4 @@
1
- import React, { forwardRef } from 'react';
1
+ import React from 'react';
2
2
  import {
3
3
  ActivityIndicator,
4
4
  ActivityIndicatorProps,
@@ -94,22 +94,21 @@ const StyledActivityIndicator = styled<any>(ActivityIndicator, {
94
94
  * - Theme integration
95
95
  * - Accessibility support
96
96
  */
97
- const StyledSpinner = forwardRef<any, SpinnerProps>(
98
- (
99
- {
100
- size = 'medium',
101
- variant = 'primary',
102
- color,
103
- overlay = false,
104
- overlayColor = 'rgba(0, 0, 0, 0.3)',
105
- label,
106
- labelColor,
107
- labelSize = 14,
108
- accessibilityLabel = 'Loading',
109
- ...rest
110
- },
111
- ref
112
- ) => {
97
+ const StyledSpinner = (
98
+ {
99
+ size = 'medium',
100
+ variant = 'primary',
101
+ color,
102
+ overlay = false,
103
+ overlayColor = 'rgba(0, 0, 0, 0.3)',
104
+ label,
105
+ labelColor,
106
+ labelSize = 14,
107
+ accessibilityLabel = 'Loading',
108
+ ref,
109
+ ...rest
110
+ }: SpinnerProps & { ref?: React.Ref<any> }
111
+ ) => {
113
112
  // Determine size
114
113
  const finalSize = typeof size === 'number' ? size : sizeConfig[size];
115
114
 
@@ -178,8 +177,7 @@ const StyledSpinner = forwardRef<any, SpinnerProps>(
178
177
  </YStack>
179
178
  </YStack>
180
179
  );
181
- }
182
- );
180
+ };
183
181
 
184
182
  StyledSpinner.displayName = 'StyledSpinner';
185
183
 
@@ -198,22 +196,21 @@ interface SpinnerContainerProps extends Omit<SpinnerProps, 'ref' | 'overlay'> {
198
196
  *
199
197
  * Use for: Page loading, data fetching, async operations
200
198
  */
201
- const SpinnerContainer = forwardRef<any, SpinnerContainerProps>(
202
- (
203
- {
204
- isVisible = true,
205
- size = 'large',
206
- variant = 'primary',
207
- color,
208
- backdropColor = 'rgba(0, 0, 0, 0.5)',
209
- message,
210
- labelColor,
211
- labelSize = 14,
212
- onBackdropPress,
213
- ...rest
214
- },
215
- ref
216
- ) => {
199
+ const SpinnerContainer = (
200
+ {
201
+ isVisible = true,
202
+ size = 'large',
203
+ variant = 'primary',
204
+ color,
205
+ backdropColor = 'rgba(0, 0, 0, 0.5)',
206
+ message,
207
+ labelColor,
208
+ labelSize = 14,
209
+ onBackdropPress,
210
+ ref,
211
+ ...rest
212
+ }: SpinnerContainerProps & { ref?: React.Ref<any> }
213
+ ) => {
217
214
  if (!isVisible) return null;
218
215
 
219
216
  // Determine size
@@ -283,8 +280,7 @@ const SpinnerContainer = forwardRef<any, SpinnerContainerProps>(
283
280
  {spinnerContent}
284
281
  </StyledButton>
285
282
  );
286
- }
287
- );
283
+ };
288
284
 
289
285
  SpinnerContainer.displayName = 'SpinnerContainer';
290
286
 
@@ -302,22 +298,21 @@ interface InlineSpinnerProps extends Omit<SpinnerProps, 'overlay'> {
302
298
  *
303
299
  * Use for: Button loading states, inline operations, compact loading indicators
304
300
  */
305
- const InlineSpinner = forwardRef<any, InlineSpinnerProps>(
306
- (
307
- {
308
- size = 'small',
309
- variant = 'primary',
310
- color,
311
- text,
312
- labelColor,
313
- labelSize = 12,
314
- direction = 'row',
315
- gap = 8,
316
- accessibilityLabel = 'Loading',
317
- ...rest
318
- },
319
- ref
320
- ) => {
301
+ const InlineSpinner = (
302
+ {
303
+ size = 'small',
304
+ variant = 'primary',
305
+ color,
306
+ text,
307
+ labelColor,
308
+ labelSize = 12,
309
+ direction = 'row',
310
+ gap = 8,
311
+ accessibilityLabel = 'Loading',
312
+ ref,
313
+ ...rest
314
+ }: InlineSpinnerProps & { ref?: React.Ref<any> }
315
+ ) => {
321
316
  // Determine size
322
317
  const finalSize = typeof size === 'number' ? size : sizeConfig[size];
323
318
 
@@ -348,8 +343,7 @@ const InlineSpinner = forwardRef<any, InlineSpinnerProps>(
348
343
  )}
349
344
  </StackComponent>
350
345
  );
351
- }
352
- );
346
+ };
353
347
 
354
348
  InlineSpinner.displayName = 'InlineSpinner';
355
349
 
@@ -1,5 +1,5 @@
1
1
 
2
- import React, { ComponentType, Ref, forwardRef } from "react";
2
+ import React, { ComponentType } from "react";
3
3
  import { ViewStyle, TextStyle, ImageStyle } from "react-native";
4
4
 
5
5
  type Style = ViewStyle | TextStyle | ImageStyle;
@@ -13,52 +13,39 @@ interface StyledOptions {
13
13
  };
14
14
  }
15
15
 
16
- // React 19 passes ref as a regular prop; React 18 and below do not.
17
- const isReact19 = typeof React.version === "string" && parseInt(React.version) >= 19;
18
-
19
16
  const styled = <P extends object>(
20
17
  Component: ComponentType<P>,
21
18
  { base, variants }: StyledOptions = {}
22
19
  ) => {
23
- function buildStyles(options: Record<string, any>): Style {
20
+ const StyledComponent = (props: P & { ref?: React.Ref<any> }) => {
24
21
  const styles: Style = { ...(base || {}) };
22
+ const options = props as Record<string, any>;
23
+ const cleanProps = { ...options };
25
24
 
26
25
  if (variants) {
27
26
  Object.keys(variants).forEach((category) => {
27
+ delete cleanProps[category];
28
28
  const variantSelected = options[category];
29
29
  const variantValue = variants[category];
30
30
 
31
31
  if (typeof variantValue === "function") {
32
32
  const style = variantValue(variantSelected, options);
33
33
  if (style) Object.assign(styles, style);
34
- } else if (variantValue && variantValue[variantSelected]) {
34
+ } else if (variantValue?.[variantSelected]) {
35
35
  const value = variantValue[variantSelected];
36
- Object.assign(
37
- styles,
38
- typeof value === "function" ? value(variantSelected, options) : value
39
- );
36
+ Object.assign(styles, typeof value === "function" ? value(variantSelected, options) : value);
40
37
  }
41
38
  });
42
39
  }
43
40
 
44
- return styles;
45
- }
41
+ return <Component {...(cleanProps as P)} style={styles} />;
42
+ };
46
43
 
47
- if (isReact19) {
48
- // React 19: ref is a plain prop
49
- function StyledComponent19(props: P & { ref?: Ref<any> }) {
50
- const { ref, ...rest } = props as any;
51
- const styles = buildStyles(rest);
52
- return <Component {...(rest as any)} style={styles} ref={ref} />;
53
- }
54
- return StyledComponent19;
55
- }
44
+ StyledComponent.displayName = `Styled(${
45
+ typeof Component === "string" ? Component : Component.displayName ?? Component.name ?? "Component"
46
+ })`;
56
47
 
57
- // React 18 and below: use forwardRef
58
- return forwardRef<any, P>((props, ref) => {
59
- const styles = buildStyles(props as Record<string, any>);
60
- return <Component {...(props as any)} style={styles} ref={ref} />;
61
- });
48
+ return StyledComponent;
62
49
  };
63
50
 
64
- export { styled };
51
+ export { styled };