react-native-gleam 1.0.0-beta.7 → 1.0.0

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/README.md CHANGED
@@ -20,7 +20,7 @@ npm install react-native-gleam
20
20
 
21
21
  ### Bare React Native
22
22
 
23
- Run `pod install` in your `ios/` directory.
23
+ Run `pod install` in your `ios/` directory. Android requires no additional setup — autolinking and codegen handle everything.
24
24
 
25
25
  ### Expo
26
26
 
@@ -33,6 +33,14 @@ npx expo prebuild
33
33
 
34
34
  No config plugin needed — autolinking and codegen handle everything.
35
35
 
36
+ ### Claude Code
37
+
38
+ Install the plugin to help Claude guide your first implementation — it knows every prop, pattern, and pitfall.
39
+
40
+ ```sh
41
+ claude plugin add --from github:RamboWasReal/react-native-gleam
42
+ ```
43
+
36
44
  ## Usage
37
45
 
38
46
  ```tsx
@@ -119,8 +127,8 @@ Every `GleamView` provides context to its subtree. A `GleamView.Line` always bin
119
127
  | `transitionDuration` | `number` | `300` | Duration of the transition from shimmer to content (ms). `0` = instant |
120
128
  | `transitionType` | `GleamTransition` | `Fade` | Transition style when loading ends |
121
129
  | `intensity` | `number` | `1` | Highlight strength (0-1). Lower = more subtle shimmer |
122
- | `baseColor` | `string` | `#E0E0E0` | Background color of the shimmer |
123
- | `highlightColor` | `string` | `#F5F5F5` | Color of the moving highlight |
130
+ | `baseColor` | `ColorValue` | `#E0E0E0` | Background color of the shimmer |
131
+ | `highlightColor` | `ColorValue` | `#F5F5F5` | Color of the moving highlight |
124
132
  | `onTransitionEnd` | `function` | — | Called when the transition completes or is interrupted. Receives `{ nativeEvent: { finished: boolean } }` — `true` if completed, `false` if interrupted (e.g., `loading` toggled back to `true`) |
125
133
 
126
134
  All standard `View` props are also supported (`style`, `testID`, etc.). Note: the shimmer overlay supports uniform `borderRadius` only — per-corner radii are not applied to the shimmer.
@@ -183,10 +191,6 @@ All shimmer instances sharing the same `speed` are automatically synchronized vi
183
191
 
184
192
  The shimmer respects uniform `borderRadius` and standard view styles.
185
193
 
186
- ## Breaking changes (beta)
187
-
188
- - When `GleamView.Line` children are present, the parent `GleamView` renders as a plain `View` container. `onTransitionEnd` on the parent is ignored in this mode — use `onTransitionEnd` on individual `GleamView.Line` components instead. A dev warning is emitted if this happens.
189
-
190
194
  ## Limitations
191
195
 
192
196
  - The shimmer overlay supports uniform `borderRadius` only — per-corner radii are not applied to the shimmer.
@@ -12,6 +12,7 @@ import android.graphics.Shader
12
12
  import android.os.SystemClock
13
13
  import android.view.Choreographer
14
14
  import android.view.animation.DecelerateInterpolator
15
+ import androidx.annotation.UiThread
15
16
  import com.facebook.react.bridge.Arguments
16
17
  import com.facebook.react.bridge.ReactContext
17
18
  import com.facebook.react.bridge.WritableMap
@@ -158,6 +159,7 @@ class GleamView(context: Context) : ReactViewGroup(context) {
158
159
  super.onDetachedFromWindow()
159
160
  unregisterClock()
160
161
  isTransitioning = false
162
+ transitionAnimator?.removeAllListeners()
161
163
  transitionAnimator?.cancel()
162
164
  transitionAnimator = null
163
165
  }
@@ -173,6 +175,7 @@ class GleamView(context: Context) : ReactViewGroup(context) {
173
175
  fun cleanup() {
174
176
  unregisterClock()
175
177
  isTransitioning = false
178
+ transitionAnimator?.removeAllListeners()
176
179
  transitionAnimator?.cancel()
177
180
  transitionAnimator = null
178
181
  }
@@ -412,9 +415,9 @@ class GleamView(context: Context) : ReactViewGroup(context) {
412
415
  */
413
416
  companion object SharedClock {
414
417
  private val views = mutableListOf<GleamView>()
415
- private val iterationSnapshot = mutableListOf<GleamView>()
416
418
  private var frameCallback: Choreographer.FrameCallback? = null
417
419
 
420
+ @UiThread
418
421
  fun register(view: GleamView) {
419
422
  if (!views.contains(view)) {
420
423
  views.add(view)
@@ -422,6 +425,7 @@ class GleamView(context: Context) : ReactViewGroup(context) {
422
425
  if (views.size == 1) start()
423
426
  }
424
427
 
428
+ @UiThread
425
429
  fun unregister(view: GleamView) {
426
430
  views.remove(view)
427
431
  if (views.isEmpty()) stop()
@@ -430,9 +434,10 @@ class GleamView(context: Context) : ReactViewGroup(context) {
430
434
  private fun start() {
431
435
  frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
432
436
  val timeMs = frameTimeNanos / 1_000_000f
433
- iterationSnapshot.clear()
434
- iterationSnapshot.addAll(views)
435
- iterationSnapshot.forEach { it.onFrame(timeMs) }
437
+ val snapshot = views.toList()
438
+ for (i in snapshot.indices.reversed()) {
439
+ snapshot[i].onFrame(timeMs)
440
+ }
436
441
  frameCallback?.let { Choreographer.getInstance().postFrameCallback(it) }
437
442
  }
438
443
  Choreographer.getInstance().postFrameCallback(frameCallback!!)
package/ios/GleamView.mm CHANGED
@@ -223,6 +223,12 @@ static void _unregisterView(GleamView *view) {
223
223
  _didInitialSetup = NO;
224
224
  }
225
225
 
226
+ // Invariant: a registered view (_isRegistered=YES) is held by the static
227
+ // __strong _views array, which prevents ARC dealloc while registered.
228
+ // Off-main dealloc with _isRegistered=YES should therefore be unreachable.
229
+ // If the invariant is violated in release, we skip _unregisterView to avoid
230
+ // racing on the statics (_views, _viewCount, _displayLink) that are read/written
231
+ // by the display link on the main thread. The view leaks in _views but no crash.
226
232
  - (void)dealloc
227
233
  {
228
234
  if (_isRegistered) {
@@ -230,9 +236,7 @@ static void _unregisterView(GleamView *view) {
230
236
  if ([NSThread isMainThread]) {
231
237
  _unregisterView(self);
232
238
  } else {
233
- dispatch_async(dispatch_get_main_queue(), ^{
234
- _stopDisplayLinkIfNeeded();
235
- });
239
+ NSAssert(NO, @"GleamView deallocated off main thread — static __strong array should prevent this");
236
240
  }
237
241
  }
238
242
  }
@@ -1 +1 @@
1
- {"version":3,"names":["useContext","useLayoutEffect","View","NativeGleamView","GleamContext","jsx","_jsx","GleamLine","children","style","testID","delay","onTransitionEnd","accessibilityProps","ctx","register","registerLine","__DEV__","console","warn","loading","speed","direction","transitionDuration","transitionType","intensity","baseColor","highlightColor"],"sourceRoot":"../../src","sources":["GleamLine.tsx"],"mappings":";;AAAA,SAASA,UAAU,EAAEC,eAAe,QAAwB,OAAO;AACnE,SACEC,IAAI,QAIC,cAAc;AACrB,OAAOC,eAAe,MAA4B,4BAA4B;AAC9E,SAASC,YAAY,QAAQ,mBAAgB;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAU9C,OAAO,SAASC,SAASA,CAAC;EACxBC,QAAQ;EACRC,KAAK;EACLC,MAAM;EACNC,KAAK;EACLC,eAAe;EACf,GAAGC;AACW,CAAC,EAAE;EACjB,MAAMC,GAAG,GAAGd,UAAU,CAACI,YAAY,CAAC;EACpC,MAAMW,QAAQ,GAAGD,GAAG,EAAEE,YAAY;EAElCf,eAAe,CAAC,MAAM;IACpB,IAAI,CAACc,QAAQ,EAAE;IACf,OAAOA,QAAQ,CAAC,CAAC;EACnB,CAAC,EAAE,CAACA,QAAQ,CAAC,CAAC;EAEd,IAAI,CAACD,GAAG,EAAE;IACR,IAAIG,OAAO,EAAE;MACXC,OAAO,CAACC,IAAI,CAAC,gDAAgD,CAAC;IAChE;IACA,oBACEb,IAAA,CAACJ,IAAI;MAACO,KAAK,EAAEA,KAAM;MAACC,MAAM,EAAEA,MAAO;MAAA,GAAKG,kBAAkB;MAAAL,QAAA,EACvDA;IAAQ,CACL,CAAC;EAEX;EAEA,oBACEF,IAAA,CAACH,eAAe;IACdiB,OAAO,EAAEN,GAAG,CAACM,OAAQ;IACrBC,KAAK,EAAEP,GAAG,CAACO,KAAM;IACjBC,SAAS,EAAER,GAAG,CAACQ,SAAU;IACzBX,KAAK,EAAEA,KAAM;IACbY,kBAAkB,EAAET,GAAG,CAACS,kBAAmB;IAC3CC,cAAc,EAAEV,GAAG,CAACU,cAAe;IACnCC,SAAS,EAAEX,GAAG,CAACW,SAAU;IACzBC,SAAS,EAAEZ,GAAG,CAACY,SAAU;IACzBC,cAAc,EAAEb,GAAG,CAACa,cAAe;IACnCf,eAAe,EAAEA,eAAgB;IACjCH,KAAK,EAAEA,KAAM;IACbC,MAAM,EAAEA,MAAO;IAAA,GACXG,kBAAkB;IAAAL,QAAA,EAErBA;EAAQ,CACM,CAAC;AAEtB","ignoreList":[]}
1
+ {"version":3,"names":["useContext","useLayoutEffect","View","NativeGleamView","GleamContext","jsx","_jsx","GleamLine","children","style","testID","delay","onTransitionEnd","accessibilityProps","ctx","register","registerLine","__DEV__","console","warn","loading","speed","direction","transitionDuration","transitionType","intensity","baseColor","highlightColor"],"sourceRoot":"../../src","sources":["GleamLine.tsx"],"mappings":";;AAAA,SAASA,UAAU,EAAEC,eAAe,QAAwB,OAAO;AACnE,SACEC,IAAI,QAIC,cAAc;AACrB,OAAOC,eAAe,MAA4B,4BAA4B;AAC9E,SAASC,YAAY,QAAQ,mBAAgB;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAa9C,OAAO,SAASC,SAASA,CAAC;EACxBC,QAAQ;EACRC,KAAK;EACLC,MAAM;EACNC,KAAK;EACLC,eAAe;EACf,GAAGC;AACW,CAAC,EAAE;EACjB,MAAMC,GAAG,GAAGd,UAAU,CAACI,YAAY,CAAC;EACpC,MAAMW,QAAQ,GAAGD,GAAG,EAAEE,YAAY;EAElCf,eAAe,CAAC,MAAM;IACpB,IAAI,CAACc,QAAQ,EAAE;IACf,OAAOA,QAAQ,CAAC,CAAC;EACnB,CAAC,EAAE,CAACA,QAAQ,CAAC,CAAC;EAEd,IAAI,CAACD,GAAG,EAAE;IACR,IAAIG,OAAO,EAAE;MACXC,OAAO,CAACC,IAAI,CAAC,gDAAgD,CAAC;IAChE;IACA,oBACEb,IAAA,CAACJ,IAAI;MAACO,KAAK,EAAEA,KAAM;MAACC,MAAM,EAAEA,MAAO;MAAA,GAAKG,kBAAkB;MAAAL,QAAA,EACvDA;IAAQ,CACL,CAAC;EAEX;EAEA,oBACEF,IAAA,CAACH,eAAe;IACdiB,OAAO,EAAEN,GAAG,CAACM,OAAQ;IACrBC,KAAK,EAAEP,GAAG,CAACO,KAAM;IACjBC,SAAS,EAAER,GAAG,CAACQ,SAAU;IACzBX,KAAK,EAAEA,KAAM;IACbY,kBAAkB,EAAET,GAAG,CAACS,kBAAmB;IAC3CC,cAAc,EAAEV,GAAG,CAACU,cAAe;IACnCC,SAAS,EAAEX,GAAG,CAACW,SAAU;IACzBC,SAAS,EAAEZ,GAAG,CAACY,SAAU;IACzBC,cAAc,EAAEb,GAAG,CAACa,cAAe;IACnCf,eAAe,EAAEA,eAAgB;IACjCH,KAAK,EAAEA,KAAM;IACbC,MAAM,EAAEA,MAAO;IAAA,GACXG,kBAAkB;IAAAL,QAAA,EAErBA;EAAQ,CACM,CAAC;AAEtB","ignoreList":[]}
@@ -6,18 +6,28 @@ import {
6
6
  } from 'react-native';
7
7
 
8
8
  export interface NativeProps extends ViewProps {
9
+ /** Toggle shimmer on/off. @default true */
9
10
  loading?: CodegenTypes.WithDefault<boolean, true>;
11
+ /** Duration of one shimmer cycle in milliseconds. @default 1000 */
10
12
  speed?: CodegenTypes.WithDefault<CodegenTypes.Float, 1000>;
13
+ /** Animation sweep direction. @default 'ltr' */
11
14
  direction?: CodegenTypes.WithDefault<'ltr' | 'rtl' | 'ttb', 'ltr'>;
15
+ /** Phase offset in milliseconds — use to stagger multiple shimmers. @default 0 */
12
16
  delay?: CodegenTypes.WithDefault<CodegenTypes.Float, 0>;
17
+ /** Duration of the loading-to-content transition in milliseconds. `0` = instant. @default 300 */
13
18
  transitionDuration?: CodegenTypes.WithDefault<CodegenTypes.Float, 300>;
19
+ /** Transition style when loading ends. @default 'fade' */
14
20
  transitionType?: CodegenTypes.WithDefault<
15
21
  'fade' | 'shrink' | 'collapse',
16
22
  'fade'
17
23
  >;
24
+ /** Highlight strength (0–1). Lower values produce a more subtle shimmer. @default 1 */
18
25
  intensity?: CodegenTypes.WithDefault<CodegenTypes.Float, 1>;
26
+ /** Background color of the shimmer. @default '#E0E0E0' */
19
27
  baseColor?: ColorValue;
28
+ /** Color of the moving highlight. @default '#F5F5F5' */
20
29
  highlightColor?: ColorValue;
30
+ /** Called when the transition completes or is interrupted. `finished` is `true` if completed, `false` if interrupted. */
21
31
  onTransitionEnd?: CodegenTypes.DirectEventHandler<
22
32
  Readonly<{ finished: boolean }>
23
33
  >;
@@ -25,19 +25,12 @@ export let GleamTransition = /*#__PURE__*/function (GleamTransition) {
25
25
  return GleamTransition;
26
26
  }({});
27
27
 
28
- // Shimmer-specific prop keys to exclude when rendering as a plain View container.
29
- // Typed against NativeProps so a missing key triggers a compile error.
30
- const SHIMMER_KEY_LIST = ['loading', 'speed', 'direction', 'delay', 'transitionDuration', 'transitionType', 'intensity', 'baseColor', 'highlightColor', 'onTransitionEnd', 'children'];
31
- const SHIMMER_KEYS = new Set(SHIMMER_KEY_LIST);
32
- function pickViewProps(props) {
33
- const viewProps = {};
34
- for (const key of Object.keys(props)) {
35
- if (!SHIMMER_KEYS.has(key)) {
36
- viewProps[key] = props[key];
37
- }
38
- }
39
- return viewProps;
40
- }
28
+ // Shimmer-specific keys that must be destructured from props before spreading
29
+ // viewProps onto <View> in Line mode.
30
+ // Direction 1 (compile-time): `satisfies` catches stale/typo keys.
31
+ // Direction 2 (DEV runtime): check inside GleamViewComponent catches
32
+ // new NativeProps keys that weren't added to this list or destructured.
33
+ const SHIMMER_KEYS = new Set(['loading', 'speed', 'direction', 'delay', 'transitionDuration', 'transitionType', 'intensity', 'baseColor', 'highlightColor', 'onTransitionEnd']);
41
34
  function hasLineChildren(children) {
42
35
  let found = false;
43
36
  React.Children.forEach(children, child => {
@@ -64,13 +57,24 @@ function GleamViewComponent({
64
57
  loading,
65
58
  speed,
66
59
  direction,
60
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
61
+ delay,
67
62
  transitionDuration,
68
63
  transitionType,
69
64
  intensity,
70
65
  baseColor,
71
66
  highlightColor,
72
- children
67
+ onTransitionEnd,
68
+ children,
69
+ ...viewProps
73
70
  } = props;
71
+ if (__DEV__) {
72
+ for (const key of Object.keys(viewProps)) {
73
+ if (SHIMMER_KEYS.has(key)) {
74
+ console.error(`GleamView: shimmer prop "${key}" leaked into viewProps. ` + 'Add it to the destructuring in GleamViewComponent and to SHIMMER_KEYS.');
75
+ }
76
+ }
77
+ }
74
78
  const lineCountRef = useRef(0);
75
79
  const warnedTransitionRef = useRef(false);
76
80
  const [hasLines, setHasLines] = useState(() => hasLineChildren(children));
@@ -80,8 +84,12 @@ function GleamViewComponent({
80
84
  return () => {
81
85
  lineCountRef.current--;
82
86
  if (lineCountRef.current === 0) {
83
- setHasLines(false);
84
- warnedTransitionRef.current = false;
87
+ queueMicrotask(() => {
88
+ if (lineCountRef.current === 0) {
89
+ setHasLines(false);
90
+ warnedTransitionRef.current = false;
91
+ }
92
+ });
85
93
  }
86
94
  };
87
95
  }, []);
@@ -101,7 +109,7 @@ function GleamViewComponent({
101
109
  // but that type isn't publicly exported from react-native. Safe at runtime.
102
110
  const nativeRef = ref;
103
111
  if (hasLines) {
104
- if (__DEV__ && props.onTransitionEnd && !warnedTransitionRef.current) {
112
+ if (__DEV__ && onTransitionEnd && !warnedTransitionRef.current) {
105
113
  warnedTransitionRef.current = true;
106
114
  console.warn('GleamView: onTransitionEnd is ignored when GleamView.Line children are present. ' + 'Use onTransitionEnd on individual GleamView.Line components instead.');
107
115
  }
@@ -109,7 +117,7 @@ function GleamViewComponent({
109
117
  value: contextValue,
110
118
  children: /*#__PURE__*/_jsx(View, {
111
119
  ref: nativeRef,
112
- ...pickViewProps(props),
120
+ ...viewProps,
113
121
  children: children
114
122
  })
115
123
  });
@@ -1 +1 @@
1
- {"version":3,"names":["React","useCallback","useMemo","useRef","useState","View","NativeGleamView","GleamContext","GleamLine","jsx","_jsx","GleamDirection","GleamTransition","SHIMMER_KEY_LIST","SHIMMER_KEYS","Set","pickViewProps","props","viewProps","key","Object","keys","has","hasLineChildren","children","found","Children","forEach","child","isValidElement","type","Fragment","GleamViewComponent","ref","loading","speed","direction","transitionDuration","transitionType","intensity","baseColor","highlightColor","lineCountRef","warnedTransitionRef","hasLines","setHasLines","registerLine","current","contextValue","nativeRef","__DEV__","onTransitionEnd","console","warn","Provider","value","displayName","GleamView","assign","Line"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["React","useCallback","useMemo","useRef","useState","View","NativeGleamView","GleamContext","GleamLine","jsx","_jsx","GleamDirection","GleamTransition","SHIMMER_KEYS","Set","hasLineChildren","children","found","Children","forEach","child","isValidElement","type","Fragment","props","GleamViewComponent","ref","loading","speed","direction","delay","transitionDuration","transitionType","intensity","baseColor","highlightColor","onTransitionEnd","viewProps","__DEV__","key","Object","keys","has","console","error","lineCountRef","warnedTransitionRef","hasLines","setHasLines","registerLine","current","queueMicrotask","contextValue","nativeRef","warn","Provider","value","displayName","GleamView","assign","Line"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
@@ -3,9 +3,12 @@ import { type AccessibilityProps, type StyleProp, type ViewStyle } from 'react-n
3
3
  import { type NativeProps } from './GleamViewNativeComponent';
4
4
  export interface GleamLineProps extends AccessibilityProps {
5
5
  children?: ReactNode;
6
+ /** Style for the shimmer bar (height, width, borderRadius, etc.). */
6
7
  style?: StyleProp<ViewStyle>;
7
8
  testID?: string;
9
+ /** Phase offset in milliseconds — overrides the parent's delay for this line. */
8
10
  delay?: NativeProps['delay'];
11
+ /** Called when this line's transition completes or is interrupted. */
9
12
  onTransitionEnd?: NativeProps['onTransitionEnd'];
10
13
  }
11
14
  export declare function GleamLine({ children, style, testID, delay, onTransitionEnd, ...accessibilityProps }: GleamLineProps): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"GleamLine.d.ts","sourceRoot":"","sources":["../../../src/GleamLine.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACpE,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AACtB,OAAwB,EAAE,KAAK,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAG/E,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACxD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,eAAe,CAAC,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAC;CAClD;AAED,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,KAAK,EACL,MAAM,EACN,KAAK,EACL,eAAe,EACf,GAAG,kBAAkB,EACtB,EAAE,cAAc,2CAuChB"}
1
+ {"version":3,"file":"GleamLine.d.ts","sourceRoot":"","sources":["../../../src/GleamLine.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACpE,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AACtB,OAAwB,EAAE,KAAK,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAG/E,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACxD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,qEAAqE;IACrE,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,sEAAsE;IACtE,eAAe,CAAC,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAC;CAClD;AAED,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,KAAK,EACL,MAAM,EACN,KAAK,EACL,eAAe,EACf,GAAG,kBAAkB,EACtB,EAAE,cAAc,2CAuChB"}
@@ -1,14 +1,24 @@
1
1
  import { type ColorValue, type ViewProps, type CodegenTypes } from 'react-native';
2
2
  export interface NativeProps extends ViewProps {
3
+ /** Toggle shimmer on/off. @default true */
3
4
  loading?: CodegenTypes.WithDefault<boolean, true>;
5
+ /** Duration of one shimmer cycle in milliseconds. @default 1000 */
4
6
  speed?: CodegenTypes.WithDefault<CodegenTypes.Float, 1000>;
7
+ /** Animation sweep direction. @default 'ltr' */
5
8
  direction?: CodegenTypes.WithDefault<'ltr' | 'rtl' | 'ttb', 'ltr'>;
9
+ /** Phase offset in milliseconds — use to stagger multiple shimmers. @default 0 */
6
10
  delay?: CodegenTypes.WithDefault<CodegenTypes.Float, 0>;
11
+ /** Duration of the loading-to-content transition in milliseconds. `0` = instant. @default 300 */
7
12
  transitionDuration?: CodegenTypes.WithDefault<CodegenTypes.Float, 300>;
13
+ /** Transition style when loading ends. @default 'fade' */
8
14
  transitionType?: CodegenTypes.WithDefault<'fade' | 'shrink' | 'collapse', 'fade'>;
15
+ /** Highlight strength (0–1). Lower values produce a more subtle shimmer. @default 1 */
9
16
  intensity?: CodegenTypes.WithDefault<CodegenTypes.Float, 1>;
17
+ /** Background color of the shimmer. @default '#E0E0E0' */
10
18
  baseColor?: ColorValue;
19
+ /** Color of the moving highlight. @default '#F5F5F5' */
11
20
  highlightColor?: ColorValue;
21
+ /** Called when the transition completes or is interrupted. `finished` is `true` if completed, `false` if interrupted. */
12
22
  onTransitionEnd?: CodegenTypes.DirectEventHandler<Readonly<{
13
23
  finished: boolean;
14
24
  }>>;
@@ -1 +1 @@
1
- {"version":3,"file":"GleamViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/GleamViewNativeComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,OAAO,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClD,KAAK,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC3D,SAAS,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,KAAK,GAAG,KAAK,GAAG,KAAK,EAAE,KAAK,CAAC,CAAC;IACnE,KAAK,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACxD,kBAAkB,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACvE,cAAc,CAAC,EAAE,YAAY,CAAC,WAAW,CACvC,MAAM,GAAG,QAAQ,GAAG,UAAU,EAC9B,MAAM,CACP,CAAC;IACF,SAAS,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC5D,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,eAAe,CAAC,EAAE,YAAY,CAAC,kBAAkB,CAC/C,QAAQ,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC,CAChC,CAAC;CACH;;AAED,wBAAgE"}
1
+ {"version":3,"file":"GleamViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/GleamViewNativeComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,2CAA2C;IAC3C,OAAO,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClD,mEAAmE;IACnE,KAAK,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC3D,gDAAgD;IAChD,SAAS,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,KAAK,GAAG,KAAK,GAAG,KAAK,EAAE,KAAK,CAAC,CAAC;IACnE,kFAAkF;IAClF,KAAK,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACxD,iGAAiG;IACjG,kBAAkB,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACvE,0DAA0D;IAC1D,cAAc,CAAC,EAAE,YAAY,CAAC,WAAW,CACvC,MAAM,GAAG,QAAQ,GAAG,UAAU,EAC9B,MAAM,CACP,CAAC;IACF,uFAAuF;IACvF,SAAS,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC5D,0DAA0D;IAC1D,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,wDAAwD;IACxD,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,yHAAyH;IACzH,eAAe,CAAC,EAAE,YAAY,CAAC,kBAAkB,CAC/C,QAAQ,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC,CAChC,CAAC;CACH;;AAED,wBAAgE"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AACtE,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAwB,EAAE,KAAK,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE/E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,YAAY,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG;IACzC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;CACvB,CAAC;AAEF,oBAAY,cAAc;IACxB,WAAW,QAAQ;IACnB,WAAW,QAAQ;IACnB,WAAW,QAAQ;CACpB;AAED,oBAAY,eAAe;IACzB,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,QAAQ,aAAa;CACtB;AAkDD,iBAAS,kBAAkB,CAAC,EAC1B,GAAG,EACH,GAAG,KAAK,EACT,EAAE,WAAW,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;CAAE,2CAkF5C;kBArFQ,kBAAkB;;;AAyF3B,eAAO,MAAM,SAAS;;CAEpB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AACtE,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAwB,EAAE,KAAK,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE/E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,YAAY,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG;IACzC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;CACvB,CAAC;AAEF,oBAAY,cAAc;IACxB,WAAW,QAAQ;IACnB,WAAW,QAAQ;IACnB,WAAW,QAAQ;CACpB;AAED,oBAAY,eAAe;IACzB,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,QAAQ,aAAa;CACtB;AAwCD,iBAAS,kBAAkB,CAAC,EAC1B,GAAG,EACH,GAAG,KAAK,EACT,EAAE,WAAW,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;CAAE,2CAqG5C;kBAxGQ,kBAAkB;;;AA4G3B,eAAO,MAAM,SAAS;;CAEpB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-gleam",
3
- "version": "1.0.0-beta.7",
3
+ "version": "1.0.0",
4
4
  "description": "Native-powered shimmer loading effect for React Native",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
package/src/GleamLine.tsx CHANGED
@@ -10,9 +10,12 @@ import { GleamContext } from './GleamContext';
10
10
 
11
11
  export interface GleamLineProps extends AccessibilityProps {
12
12
  children?: ReactNode;
13
+ /** Style for the shimmer bar (height, width, borderRadius, etc.). */
13
14
  style?: StyleProp<ViewStyle>;
14
15
  testID?: string;
16
+ /** Phase offset in milliseconds — overrides the parent's delay for this line. */
15
17
  delay?: NativeProps['delay'];
18
+ /** Called when this line's transition completes or is interrupted. */
16
19
  onTransitionEnd?: NativeProps['onTransitionEnd'];
17
20
  }
18
21
 
@@ -6,18 +6,28 @@ import {
6
6
  } from 'react-native';
7
7
 
8
8
  export interface NativeProps extends ViewProps {
9
+ /** Toggle shimmer on/off. @default true */
9
10
  loading?: CodegenTypes.WithDefault<boolean, true>;
11
+ /** Duration of one shimmer cycle in milliseconds. @default 1000 */
10
12
  speed?: CodegenTypes.WithDefault<CodegenTypes.Float, 1000>;
13
+ /** Animation sweep direction. @default 'ltr' */
11
14
  direction?: CodegenTypes.WithDefault<'ltr' | 'rtl' | 'ttb', 'ltr'>;
15
+ /** Phase offset in milliseconds — use to stagger multiple shimmers. @default 0 */
12
16
  delay?: CodegenTypes.WithDefault<CodegenTypes.Float, 0>;
17
+ /** Duration of the loading-to-content transition in milliseconds. `0` = instant. @default 300 */
13
18
  transitionDuration?: CodegenTypes.WithDefault<CodegenTypes.Float, 300>;
19
+ /** Transition style when loading ends. @default 'fade' */
14
20
  transitionType?: CodegenTypes.WithDefault<
15
21
  'fade' | 'shrink' | 'collapse',
16
22
  'fade'
17
23
  >;
24
+ /** Highlight strength (0–1). Lower values produce a more subtle shimmer. @default 1 */
18
25
  intensity?: CodegenTypes.WithDefault<CodegenTypes.Float, 1>;
26
+ /** Background color of the shimmer. @default '#E0E0E0' */
19
27
  baseColor?: ColorValue;
28
+ /** Color of the moving highlight. @default '#F5F5F5' */
20
29
  highlightColor?: ColorValue;
30
+ /** Called when the transition completes or is interrupted. `finished` is `true` if completed, `false` if interrupted. */
21
31
  onTransitionEnd?: CodegenTypes.DirectEventHandler<
22
32
  Readonly<{ finished: boolean }>
23
33
  >;
package/src/index.tsx CHANGED
@@ -28,9 +28,12 @@ export enum GleamTransition {
28
28
  Collapse = 'collapse',
29
29
  }
30
30
 
31
- // Shimmer-specific prop keys to exclude when rendering as a plain View container.
32
- // Typed against NativeProps so a missing key triggers a compile error.
33
- const SHIMMER_KEY_LIST = [
31
+ // Shimmer-specific keys that must be destructured from props before spreading
32
+ // viewProps onto <View> in Line mode.
33
+ // Direction 1 (compile-time): `satisfies` catches stale/typo keys.
34
+ // Direction 2 (DEV runtime): check inside GleamViewComponent catches
35
+ // new NativeProps keys that weren't added to this list or destructured.
36
+ const SHIMMER_KEYS: ReadonlySet<string> = new Set([
34
37
  'loading',
35
38
  'speed',
36
39
  'direction',
@@ -41,20 +44,7 @@ const SHIMMER_KEY_LIST = [
41
44
  'baseColor',
42
45
  'highlightColor',
43
46
  'onTransitionEnd',
44
- 'children',
45
- ] as const satisfies ReadonlyArray<keyof NativeProps | 'children'>;
46
-
47
- const SHIMMER_KEYS: ReadonlySet<string> = new Set(SHIMMER_KEY_LIST);
48
-
49
- function pickViewProps(props: NativeProps) {
50
- const viewProps: Record<string, unknown> = {};
51
- for (const key of Object.keys(props)) {
52
- if (!SHIMMER_KEYS.has(key)) {
53
- viewProps[key] = (props as Record<string, unknown>)[key];
54
- }
55
- }
56
- return viewProps;
57
- }
47
+ ] as const satisfies ReadonlyArray<keyof NativeProps>);
58
48
 
59
49
  function hasLineChildren(children: React.ReactNode): boolean {
60
50
  let found = false;
@@ -84,14 +74,29 @@ function GleamViewComponent({
84
74
  loading,
85
75
  speed,
86
76
  direction,
77
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
78
+ delay,
87
79
  transitionDuration,
88
80
  transitionType,
89
81
  intensity,
90
82
  baseColor,
91
83
  highlightColor,
84
+ onTransitionEnd,
92
85
  children,
86
+ ...viewProps
93
87
  } = props;
94
88
 
89
+ if (__DEV__) {
90
+ for (const key of Object.keys(viewProps)) {
91
+ if (SHIMMER_KEYS.has(key)) {
92
+ console.error(
93
+ `GleamView: shimmer prop "${key}" leaked into viewProps. ` +
94
+ 'Add it to the destructuring in GleamViewComponent and to SHIMMER_KEYS.'
95
+ );
96
+ }
97
+ }
98
+ }
99
+
95
100
  const lineCountRef = useRef(0);
96
101
  const warnedTransitionRef = useRef(false);
97
102
  const [hasLines, setHasLines] = useState(() => hasLineChildren(children));
@@ -102,8 +107,12 @@ function GleamViewComponent({
102
107
  return () => {
103
108
  lineCountRef.current--;
104
109
  if (lineCountRef.current === 0) {
105
- setHasLines(false);
106
- warnedTransitionRef.current = false;
110
+ queueMicrotask(() => {
111
+ if (lineCountRef.current === 0) {
112
+ setHasLines(false);
113
+ warnedTransitionRef.current = false;
114
+ }
115
+ });
107
116
  }
108
117
  };
109
118
  }, []);
@@ -138,7 +147,7 @@ function GleamViewComponent({
138
147
  const nativeRef = ref as any;
139
148
 
140
149
  if (hasLines) {
141
- if (__DEV__ && props.onTransitionEnd && !warnedTransitionRef.current) {
150
+ if (__DEV__ && onTransitionEnd && !warnedTransitionRef.current) {
142
151
  warnedTransitionRef.current = true;
143
152
  console.warn(
144
153
  'GleamView: onTransitionEnd is ignored when GleamView.Line children are present. ' +
@@ -147,7 +156,7 @@ function GleamViewComponent({
147
156
  }
148
157
  return (
149
158
  <GleamContext.Provider value={contextValue}>
150
- <View ref={nativeRef} {...pickViewProps(props)}>
159
+ <View ref={nativeRef} {...viewProps}>
151
160
  {children}
152
161
  </View>
153
162
  </GleamContext.Provider>