# Addon React Integration - How It Works

## The Question

**"How can addon developers use React if we only ship built `app.js`?"**

You're absolutely right to question this! Let me clarify the architecture.

---

## Current Misunderstanding

**What I showed in examples:**
```tsx
// This WON'T work for external addons!
import { addonLoader, addFilter } from '@woonoow/hooks';
import { DestinationSearch } from './components/DestinationSearch';

addonLoader.register({
  id: 'rajaongkir-bridge',
  init: () => {
    addFilter('woonoow_order_form_after_shipping', (content) => {
      return <DestinationSearch />; // ❌ Can't do this!
    });
  }
});
```

**Problem:** External addons can't import React components because:
1. They don't have access to our build pipeline
2. They only get the compiled `app.js`
3. React is bundled, not exposed

---

## Solution: Three Integration Levels

### **Level 1: Vanilla JS/jQuery** (Basic)

**For simple addons that just need to inject HTML/JS**

```javascript
// addon-bridge.js (vanilla JS, no build needed)
(function() {
  // Wait for WooNooW to load
  window.addEventListener('woonoow:loaded', function() {
    // Access WooNooW hooks
    window.WooNooW.addFilter('woonoow_order_form_after_shipping', function(container, formData) {
      // Inject HTML
      const div = document.createElement('div');
      div.innerHTML = `
        <div class="rajaongkir-destination">
          <label>Shipping Destination</label>
          <select id="rajaongkir-dest">
            <option>Select destination...</option>
          </select>
        </div>
      `;
      container.appendChild(div);
      
      // Add event listeners
      document.getElementById('rajaongkir-dest').addEventListener('change', function(e) {
        // Update WooNooW state
        window.WooNooW.updateFormData({
          shipping: {
            ...formData.shipping,
            destination_id: e.target.value
          }
        });
      });
      
      return container;
    });
  });
})();
```

**Pros:**
- ✅ No build process needed
- ✅ Works immediately
- ✅ Easy for PHP developers
- ✅ No dependencies

**Cons:**
- ❌ No React benefits
- ❌ Manual DOM manipulation
- ❌ No type safety

---

### **Level 2: Exposed React Runtime** (Recommended)

**WooNooW exposes React on window for addons to use**

#### WooNooW Core Setup:

```typescript
// admin-spa/src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';

// Expose React for addons
window.WooNooW = {
  React: React,
  ReactDOM: ReactDOM,
  hooks: {
    addFilter: addFilter,
    addAction: addAction,
    // ... other hooks
  },
  components: {
    // Expose common components
    Button: Button,
    Input: Input,
    Select: Select,
    // ... other UI components
  }
};
```

#### Addon Development (with build):

```javascript
// addon-bridge.js (built with Vite/Webpack)
const { React, hooks, components } = window.WooNooW;
const { addFilter } = hooks;
const { Button, Select } = components;

// Addon can now use React!
function DestinationSearch({ value, onChange }) {
  const [destinations, setDestinations] = React.useState([]);
  const [loading, setLoading] = React.useState(false);
  
  React.useEffect(() => {
    // Fetch destinations
    fetch('/wp-json/rajaongkir/v1/destinations')
      .then(res => res.json())
      .then(data => setDestinations(data));
  }, []);
  
  return React.createElement('div', { className: 'rajaongkir-search' },
    React.createElement('label', null, 'Shipping Destination'),
    React.createElement(Select, {
      value: value,
      onChange: onChange,
      options: destinations,
      loading: loading
    })
  );
}

// Register with WooNooW
addFilter('woonoow_order_form_after_shipping', function(container, formData, setFormData) {
  const root = ReactDOM.createRoot(container);
  root.render(
    React.createElement(DestinationSearch, {
      value: formData.shipping?.destination_id,
      onChange: (value) => setFormData({
        ...formData,
        shipping: { ...formData.shipping, destination_id: value }
      })
    })
  );
  return container;
});
```

**Addon Build Setup:**

```javascript
// vite.config.js
export default {
  build: {
    lib: {
      entry: 'src/addon.js',
      name: 'RajaongkirBridge',
      fileName: 'addon'
    },
    rollupOptions: {
      external: ['react', 'react-dom'], // Don't bundle React
      output: {
        globals: {
          react: 'window.WooNooW.React',
          'react-dom': 'window.WooNooW.ReactDOM'
        }
      }
    }
  }
};
```

**Pros:**
- ✅ Can use React
- ✅ Access to WooNooW components
- ✅ Better DX
- ✅ Type safety (with TypeScript)

**Cons:**
- ❌ Requires build process
- ❌ More complex setup

---

### **Level 3: Slot-Based Rendering** (Advanced)

**WooNooW renders addon components via slots**

#### WooNooW Core:

```typescript
// OrderForm.tsx
function OrderForm() {
  // ... form logic
  
  return (
    <div>
      {/* ... shipping fields ... */}
      
      {/* Slot for addons to inject */}
      <AddonSlot 
        name="order_form_after_shipping"
        props={{ formData, setFormData }}
      />
    </div>
  );
}

// AddonSlot.tsx
function AddonSlot({ name, props }) {
  const slots = useAddonSlots(name);
  
  return (
    <>
      {slots.map((slot, index) => (
        <div key={index} data-addon-slot={slot.id}>
          {slot.component(props)}
        </div>
      ))}
    </>
  );
}
```

#### Addon Registration (PHP):

```php
// rajaongkir-bridge.php
add_filter('woonoow/addon_slots', function($slots) {
    $slots['order_form_after_shipping'][] = [
        'id' => 'rajaongkir-destination',
        'component' => 'RajaongkirDestination', // Component name
        'script' => plugin_dir_url(__FILE__) . 'dist/addon.js',
        'priority' => 10,
    ];
    return $slots;
});
```

#### Addon Component (React with build):

```typescript
// addon/src/DestinationSearch.tsx
import React, { useState, useEffect } from 'react';

export function RajaongkirDestination({ formData, setFormData }) {
  const [destinations, setDestinations] = useState([]);
  
  useEffect(() => {
    fetch('/wp-json/rajaongkir/v1/destinations')
      .then(res => res.json())
      .then(setDestinations);
  }, []);
  
  return (
    <div className="rajaongkir-destination">
      <label>Shipping Destination</label>
      <select
        value={formData.shipping?.destination_id || ''}
        onChange={(e) => setFormData({
          ...formData,
          shipping: {
            ...formData.shipping,
            destination_id: e.target.value
          }
        })}
      >
        <option value="">Select destination...</option>
        {destinations.map(dest => (
          <option key={dest.id} value={dest.id}>
            {dest.label}
          </option>
        ))}
      </select>
    </div>
  );
}

// Export for WooNooW to load
window.WooNooWAddons = window.WooNooWAddons || {};
window.WooNooWAddons.RajaongkirDestination = RajaongkirDestination;
```

**Pros:**
- ✅ Full React support
- ✅ Type safety
- ✅ Modern DX
- ✅ Proper component lifecycle

**Cons:**
- ❌ Most complex
- ❌ Requires build process
- ❌ More WooNooW core complexity

---

## Recommended Approach: Level 2 (Exposed React)

### Implementation in WooNooW Core:

```typescript
// admin-spa/src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { QueryClient } from '@tanstack/react-query';

// UI Components
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Select } from '@/components/ui/select';
import { Label } from '@/components/ui/label';
// ... other components

// Hooks
import { addFilter, addAction, applyFilters, doAction } from '@/lib/hooks';

// Expose WooNooW API
window.WooNooW = {
  // React runtime
  React: React,
  ReactDOM: ReactDOM,
  
  // Hooks system
  hooks: {
    addFilter,
    addAction,
    applyFilters,
    doAction,
  },
  
  // UI Components (shadcn/ui)
  components: {
    Button,
    Input,
    Select,
    Label,
    // ... expose commonly used components
  },
  
  // Utilities
  utils: {
    api: api, // API client
    toast: toast, // Toast notifications
  },
  
  // Version
  version: '1.0.0',
};

// Emit loaded event
window.dispatchEvent(new CustomEvent('woonoow:loaded'));
```

### Addon Developer Experience:

#### Option 1: Vanilla JS (No Build)

```javascript
// addon.js
(function() {
  const { React, hooks, components } = window.WooNooW;
  const { addFilter } = hooks;
  const { Select } = components;
  
  addFilter('woonoow_order_form_after_shipping', function(container, props) {
    // Use React.createElement (no JSX)
    const element = React.createElement(Select, {
      label: 'Destination',
      options: [...],
      value: props.formData.shipping?.destination_id,
      onChange: (value) => props.setFormData({...})
    });
    
    const root = ReactDOM.createRoot(container);
    root.render(element);
    
    return container;
  });
})();
```

#### Option 2: With Build (JSX Support)

```typescript
// addon/src/index.tsx
const { React, hooks, components } = window.WooNooW;
const { addFilter } = hooks;
const { Select } = components;

function DestinationSearch({ formData, setFormData }) {
  return (
    <Select
      label="Destination"
      options={[...]}
      value={formData.shipping?.destination_id}
      onChange={(value) => setFormData({
        ...formData,
        shipping: { ...formData.shipping, destination_id: value }
      })}
    />
  );
}

addFilter('woonoow_order_form_after_shipping', (container, props) => {
  const root = ReactDOM.createRoot(container);
  root.render(<DestinationSearch {...props} />);
  return container;
});
```

```javascript
// vite.config.js
export default {
  build: {
    lib: {
      entry: 'src/index.tsx',
      formats: ['iife'],
      name: 'RajaongkirAddon'
    },
    rollupOptions: {
      external: ['react', 'react-dom'],
      output: {
        globals: {
          react: 'window.WooNooW.React',
          'react-dom': 'window.WooNooW.ReactDOM'
        }
      }
    }
  }
};
```

---

## Documentation for Addon Developers

### Quick Start Guide:

```markdown
# WooNooW Addon Development

## Level 1: Vanilla JS (Easiest)

No build process needed. Just use `window.WooNooW` API.

## Level 2: React with Build (Recommended)

1. Setup project:
   npm init
   npm install --save-dev vite @types/react

2. Configure vite.config.js (see example above)

3. Use WooNooW's React:
   const { React } = window.WooNooW;

4. Build:
   npm run build

5. Enqueue in WordPress:
   wp_enqueue_script('my-addon', plugin_dir_url(__FILE__) . 'dist/addon.js', ['woonoow-admin'], '1.0.0', true);
```

---

## Summary

**Your concern was valid!** ✅

**Solution:**
1. ✅ Expose React on `window.WooNooW.React`
2. ✅ Expose common components on `window.WooNooW.components`
3. ✅ Addons can use vanilla JS (no build) or React (with build)
4. ✅ Addons don't bundle React (use ours)
5. ✅ Proper documentation for developers

**Result:**
- Simple addons: Vanilla JS, no build
- Advanced addons: React with build, external React
- Best of both worlds!
