# React Native Animated Glow v3.0.1

<div align="center">

[![NPM Version](https://img.shields.io/npm/v/react-native-animated-glow.svg)](https://www.npmjs.com/package/react-native-animated-glow)
[![NPM License](https://img.shields.io/npm/l/react-native-animated-glow.svg)](https://github.com/realimposter/react-native-animated-glow/blob/main/LICENSE)
[![NPM Downloads](https://img.shields.io/npm/dt/react-native-animated-glow.svg)](https://www.npmjs.com/package/react-native-animated-glow)
<br/>
<a href="https://github.com/realimposter/react-native-animated-glow">
  <img src="https://img.shields.io/github/stars/realimposter/react-native-animated-glow?style=social" alt="GitHub stars">
</a>

</div>

A performant, highly-customizable animated glow effect component for React Native, powered by **Skia** and **Reanimated 3**.

![React Native Animated Glow Demo](https://raw.githubusercontent.com/realimposter/react-native-animated-glow/main/assets/react-native-glow-demo.gif)

## Live Demo & Builder

Check out the **[live web demo and interactive builder](https://reactnativeglow.com/)** to see the component in action, browse tutorials, and create your own presets.

## Features

-   **GPU-Powered Performance:** Built with Skia for smooth, 60 FPS animations that run on the UI thread.
-   **Intelligent State Blending:** Responds to `hover` and `press` events by smoothly interpolating between different glow configurations.
-   **Highly Customizable:** Control colors, speed, shape, size, opacity, and more through a flexible `glowLayers` API.
-   **Advanced Effects:**
    -   Create flowing **gradient glows and borders**.
    -   Render glows `behind`, `inside` (clipped), or `over` your component.
    -   Achieve "comet trail" effects with variable `glowSize` arrays.
-   **Easy Web Setup:** Skia's CanvasKit WASM file is loaded automatically from a CDN, no extra configuration needed.
-   **Presets Included:** Ships with professionally designed presets to get you started instantly.

## Installation

**1. Install the library:**

```bash
npm install react-native-animated-glow
```

**2. Install Peer Dependencies:**

The library depends on Skia, Reanimated, and Gesture Handler.

```bash
npm install @shopify/react-native-skia react-native-reanimated react-native-gesture-handler
```

**3. Configure Dependencies:**

You must follow the installation guides for the peer dependencies to ensure they are configured correctly for your project.
- [React Native Skia Docs](https://shopify.github.io/react-native-skia/docs/getting-started/installation)
- [Reanimated Docs](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started/#installation) (Remember to add the Babel plugin!)
- [Gesture Handler Docs](https://docs.swmansion.com/react-native-gesture-handler/docs/fundamentals/installation) (Remember to add `GestureHandlerRootView`!)

## Usage

The best way to use the component is with a `PresetConfig` object, which makes your styles reusable and type-safe.

```jsx
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import AnimatedGlow, { type PresetConfig } from 'react-native-animated-glow';

// 1. Define your preset
const myCoolPreset: PresetConfig = {
  metadata: { 
    name: 'My Cool Preset', 
    textColor: '#FFFFFF', 
    category: 'Custom',
    tags: ['interactive']
  },
  states: [
    {
      name: 'default', // The base style for the component
      preset: {
        cornerRadius: 50,
        outlineWidth: 2,
        borderColor: '#E0FFFF',
        glowLayers: [
          { colors: ['#00BFFF', '#87CEEB'], opacity: 0.5, glowSize: 30 },
        ]
      }
    },
    // 2. Define interactive states
    { 
      name: 'hover', 
      transition: 300, // 300ms transition into this state
      preset: { 
        glowLayers: [{ glowSize: 40 }] // On hover, make the glow bigger
      } 
    },
    { 
      name: 'press', 
      transition: 100, // A faster transition for press
      preset: { 
        glowLayers: [{ glowSize: 45, opacity: 0.6 }] 
      } 
    }
  ]
};

// 3. Use it in your component
export default function MyGlowingComponent() {
  return (
    <AnimatedGlow preset={myCoolPreset}>
      <View style={styles.box}>
        <Text style={styles.text}>I'm Interactive!</Text>
      </View>
    </AnimatedGlow>
  );
}

const styles = StyleSheet.create({
  box: { paddingVertical: 20, paddingHorizontal: 40, backgroundColor: '#222' },
  text: { color: 'white', fontWeight: 'bold' }
});
```

## Controlling States

The `AnimatedGlow` component is stateless by default and is controlled via the `activeState` prop. This gives you complete control to connect it to any gesture or state management system.

The recommended way to handle user interactions is to wrap your content in a `Pressable` and use `React.useState` and `React.useRef` to manage the component's state between `'default'`, `'hover'`, and `'press'`.

Here is a robust example demonstrating how to handle both press and hover events correctly:

```jsx
import React, { useState, useRef } from 'react';
import { View, Text, StyleSheet, Pressable } from 'react-native';
// Import the GlowEvent type for type safety
import AnimatedGlow, { glowPresets, type GlowEvent } from 'react-native-animated-glow';

export default function MyInteractiveButton() {
  // 1. State for the active glow effect ('default', 'hover', 'press')
  const [glowState, setGlowState] = useState<GlowEvent>('default');
  // 2. Ref to track if the cursor is currently hovering over the element
  const isHovered = useRef(false);

  return (
    <AnimatedGlow 
      preset={glowPresets.defaultRainbow}
      // 3. Pass the state to the activeState prop to control the glow
      activeState={glowState}
    >
      <Pressable
        style={styles.button}
        onPress={() => console.log('Button Pressed!')}
        
        // --- Press Events ---
        onPressIn={() => setGlowState('press')}
        onPressOut={() => {
          // When the press is released, transition to 'hover' if the cursor
          // is still over the button, otherwise return to 'default'.
          setGlowState(isHovered.current ? 'hover' : 'default');
        }}
        
        // --- Hover Events (for Web, macOS, Windows) ---
        onHoverIn={() => {
          isHovered.current = true;
          // Only transition to hover state if not being actively pressed.
          if (glowState !== 'press') {
            setGlowState('hover');
          }
        }}
        onHoverOut={() => {
          isHovered.current = false;
          // Only transition to default state if not being actively pressed.
          if (glowState !== 'press') {
            setGlowState('default');
          }
        }}
      >
        <Text style={styles.buttonText}>Tap or Hover Me</Text>
      </Pressable>
    </AnimatedGlow>
  );
}

const styles = StyleSheet.create({
  button: { 
    paddingVertical: 20, 
    paddingHorizontal: 40,
    backgroundColor: '#222'
  },
  buttonText: { 
    color: 'white', 
    fontWeight: 'bold', 
    textAlign: 'center'
  }
});
```

## API Reference

For a complete list of all available props and their descriptions, please see the **[Docs Tab](https://reactnativeglow.com/docs)** in the live demo app.

## Changelog

### `v3.1.0`
-   Fixed Samsung/Adreno freezes by keeping SkSL color math on `half4` precision.
-   Fixed Android Expo dev OOMs by avoiding native lazy loading for the Skia renderer.
-   Fixed Web `WithSkiaWeb` loading so Metro no longer emits the `_ref` runtime error.
-   Added `react-native` and `default` package export conditions for newer Metro/Expo compatibility.
-   Added `wrapperStyle` for styling the inner content wrapper.

### `v3.0.1`
-   Added `activeState` prop.
-   Removed insternal state management

### `v3.0.0` (Breaking Changes)
This version introduces a more powerful and intelligent animation system along with a complete restructuring of the preset API for better organization and type safety.

-   **New Feature: Intelligent Animation Blending:** A new animation system powered by Reanimated worklets smoothly interpolates *between* state configurations. When you hover, press, or return to default, every animatable property (colors, sizes, opacity, etc.) will transition gracefully over the specified duration.
-   **New Feature: Reworked State Management API:** The `preset` prop now expects a `PresetConfig` object with a `states` array. All visual styles, including the `default` look, are defined within this array. This makes presets more organized and powerful.
-   **Architectural Improvement:** All glow layers, placements (`behind`, `inside`, `over`), and the animated border are now rendered in a single, unified Skia shader for maximum efficiency.
-   **BREAKING CHANGE:** The `preset` prop format has been completely overhauled. Old flat preset objects are incompatible and must be migrated to the new `PresetConfig` structure, which includes a `metadata` object and a `states` array.
-   **BREAKING CHANGE:** The `randomness` prop has been removed from the core API.

### `v2.0.0`
This version marked a complete architectural rewrite for maximum performance and flexibility.

-   **Complete Rewrite with Skia:** The library is now powered by **Skia** and **Reanimated 3**, running animations smoothly on the UI thread.
-   **Interactive States:** Added support for `hover` and `press` events with configurable transitions using `react-native-gesture-handler`.
-   **BREAKING CHANGE:** The library now requires `@shopify/react-native-skia`, `react-native-reanimated`, and `react-native-gesture-handler` as peer dependencies. The old props (`glowColor`, `glowSize`, etc.) have been replaced by the `glowLayers` API.

### `v1.0.0`
-   Initial release using glow particles and reanimated

## License
This project is licensed under the MIT License.
