npm package: @feedlog-ai/react
Description: React bindings for Feedlog Toolkit Web Components
Latest version: 0.0.51

# @feedlog-ai/react

React bindings for Feedlog Toolkit web components. Auto-generated from Stencil components with full TypeScript support.

## Features

- **React Components**: Native React components with JSX support
- **TypeScript Support**: Full type safety with TypeScript definitions
- **Auto-generated**: Generated from Stencil web components for consistency
- **Event Handling**: React-friendly event handling with proper typing
- **Peer Dependencies**: React >=17.0.0 and React DOM >=17.0.0
- **Tree Shakeable**: Only import the components you need

## Installation

```bash
npm install @feedlog-ai/react
```

## Components

### FeedlogIssuesClient

The main component for displaying GitHub issues with built-in SDK integration.

**Props:**

- `apiKey`: API key for Feedlog authentication (required)
- `type?`: Filter by issue type — `'bug'` or `'enhancement'`
- `limit?`: Maximum issues per page (1–100)
- `sortBy?`: `'createdAt'` or `'updatedAt'`
- `endpoint?`: Custom API endpoint
- `maxWidth?`: Container max width (default: `'42rem'`)
- `paginationType?`: `'load-more'` or `'prev-next'` (default: `'load-more'`)
- `loadMoreLabel?`: Load-more button label (default: `'Load More'`)
- `minSkeletonTime?`: Minimum ms for skeleton display (default: `250`)
- `theme?`: `'light'` or `'dark'` (default: `'light'`)
- `heading?` / `subtitle?`: Section heading and subtitle
- `emptyStateTitle?` / `emptyStateMessage?`: Empty-state copy
- `getIssueUrl?`: `(issue: FeedlogIssue) => string | null | undefined` when `githubIssueLink` is missing

**Events:**

- `onFeedlogUpvote`: Called when an issue is upvoted
- `onFeedlogError`: Called on errors

## Usage

```tsx
import React from 'react';
import { FeedlogIssuesClient } from '@feedlog-ai/react';

function App() {
  return (
    <div>
      <FeedlogIssuesClient
        apiKey="your-api-key"
        type="bug"
        limit={10}
        theme="light"
        maxWidth="42rem"
        onFeedlogUpvote={event => {
          console.log('Issue upvoted:', event.detail);
          // event.detail contains: { issueId, upvoted, upvoteCount }
        }}
        onFeedlogError={event => {
          console.error('Error occurred:', event.detail);
          // event.detail contains: { error, code? }
        }}
      />
    </div>
  );
}

export default App;
```

## Server-Side Rendering (SSR)

The components support Server-Side Rendering out of the box. `@feedlog-ai/core/ssr-globals` and the hook-free `@feedlog-ai/react/ssr-components` entry ensure Node does not throw on browser-only globals such as `self` when Stencil bundles load.

### Next.js (App Router or Pages Router)

Wrap your `next.config.js` or `next.config.ts` with our Next.js SSR helper:

```ts
// next.config.ts
import { withFeedlogSSR } from '@feedlog-ai/react/next';

const nextConfig = {
  // your existing config
};

export default withFeedlogSSR(nextConfig);
```

**App Router — Server Components:** The main package (`@feedlog-ai/react`) uses React hooks (`useEffect`, `useRef`) for custom-element registration and props. **Do not** import it from server components (pages or layouts without `"use client"`). For SSR-safe Badge, Button, and Card, import from `@feedlog-ai/react/ssr-components` instead. For interactive or full-featured wrappers (for example `FeedlogIssuesClient`), use a client boundary: put them in a file marked with `"use client"` and import from `@feedlog-ai/react` there.

### Vite / Remix

For Vite-based apps (like Remix or standard Vite React), add our Vite SSR plugin:

```ts
// vite.config.ts
import { defineConfig } from 'vite';
import { feedlogSSR } from '@feedlog-ai/react/vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react(), feedlogSSR()],
});
```

### TanStack Start

TanStack Start is Vite-based, so use the same compiler approach. Add `feedlogSSR()` to your Vite config **after** the React plugin:

```ts
// vite.config.ts
import { defineConfig } from 'vite';
import tsConfigPaths from 'vite-tsconfig-paths';
import { tanstackStart } from '@tanstack/react-start/plugin/vite';
import viteReact from '@vitejs/plugin-react';
import { feedlogSSR } from '@feedlog-ai/react/start';

export default defineConfig({
  server: { port: 3000 },
  plugins: [
    tsConfigPaths(),
    tanstackStart(),
    viteReact(), // must come after tanstackStart
    feedlogSSR(), // Stencil SSR for Feedlog components
  ],
});
```

**Note:** The SSR plugin requires `@stencil/ssr`, which declares `vite@^6.x` as a peer dependency. For Vite 7 projects, add this override to your `package.json` to avoid peer dependency conflicts:

```json
"overrides": {
  "@stencil/ssr": {
    "vite": "$vite"
  }
}
```

**Troubleshooting:** If you see `Expected ">" but found "{"` during the SSR build, the Stencil transform may be failing on complex TypeScript generics in files that import from `@feedlog-ai/react`. Refactor inline generics to type aliases, e.g.:

```ts
// Instead of: useState<Record<string, MyType>>(...)
type MyState = Record<string, MyType>
const [state, setState] = useState<MyState>(...)

// Instead of: event: CustomEvent<{ a: string; b: number }>
interface EventDetail { a: string; b: number }
event: CustomEvent<EventDetail>
```

### SSR Limitations

The compiler-based SSR (used by Vite, Remix, and Next.js with `feedlogSSR` / `withFeedlogSSR`) performs **static AST analysis at build time** and cannot resolve runtime values. Dynamic props such as `apiKey={apiKey}` or `theme={theme}` are serialized as their identifier names instead of actual values, which causes broken API calls and incorrect display.

- **SSR-safe components** (pre-rendered with Declarative Shadow DOM): `FeedlogBadge`, `FeedlogButton`, `FeedlogCard`
- **Excluded from SSR** (rendered at request time by React; no pre-rendered DSD): `FeedlogIssuesClient`, `FeedlogIssueComponent`, `FeedlogIssues`, `FeedlogIssuesList` — these receive props correctly at runtime but may show a brief empty state before client hydration

This is a [documented limitation](https://stenciljs.com/docs/server-side-rendering) of Stencil's compiler approach ("Static props only").

### Build your own changelog

- [Build Feedlog](../../README.md#build-feedlog) — three tiers (client, composable, core-only) and AI copy-paste blocks
- [Top-level client](./BUILD_FEEDLOG_CLIENT.md) — `FeedlogIssuesClient`
- [Composable + your data](./BUILD_FEEDLOG_COMPOSABLE.md) — `FeedlogSDK` + `FeedlogIssues` (full SSR, loaders)

### Event Handling

```tsx
import React, { useCallback } from 'react';
import { FeedlogIssuesClient } from '@feedlog-ai/react';

function IssuesComponent() {
  const handleUpvote = useCallback((event: CustomEvent) => {
    const { issueId, upvoted, upvoteCount } = event.detail;
    console.log(`Issue ${issueId} ${upvoted ? 'upvoted' : 'unvoted'}`);
    console.log(`New upvote count: ${upvoteCount}`);
  }, []);

  const handleError = useCallback((event: CustomEvent) => {
    const { error, code } = event.detail;
    console.error(`Feedlog error (${code}):`, error);
    // Handle error in your UI
  }, []);

  return (
    <FeedlogIssuesClient
      apiKey="your-api-key"
      onFeedlogUpvote={handleUpvote}
      onFeedlogError={handleError}
    />
  );
}
```

### With State Management

```tsx
import React, { useState, useCallback } from 'react';
import { FeedlogIssuesClient } from '@feedlog-ai/react';

function IssuesWithState() {
  const [theme, setTheme] = useState<'light' | 'dark'>('light');
  const [error, setError] = useState<string | null>(null);

  const handleError = useCallback((event: CustomEvent) => {
    setError(event.detail.error);
    // Clear error after 5 seconds
    setTimeout(() => setError(null), 5000);
  }, []);

  return (
    <div>
      {error && <div className="error-banner">Error: {error}</div>}

      <FeedlogIssuesClient apiKey="your-api-key" theme={theme} onFeedlogError={handleError} />
    </div>
  );
}
```

### Other Components

The package also includes React bindings for additional UI components:

```tsx
import {
  FeedlogBadge,
  FeedlogButton,
  FeedlogCard,
  FeedlogIssueComponent,
  FeedlogIssues,
  FeedlogIssuesList,
} from '@feedlog-ai/react';

// Badge component (variants: default | destructive | enhancement | secondary)
<FeedlogBadge variant="enhancement">New</FeedlogBadge>

// Button component (variants: default | outline | ghost | destructive)
<FeedlogButton variant="default" size="lg" onFeedlogClick={handleClick}>
  Click me
</FeedlogButton>

// Card component
<FeedlogCard>
  <h3>Card Title</h3>
  <p>Card content</p>
</FeedlogCard>
```

## TypeScript Support

All components are fully typed. Import types from the core package if needed:

```tsx
import { FeedlogIssue } from '@feedlog-ai/core';
import { FeedlogIssuesClient } from '@feedlog-ai/react';

// Type-safe event handling
const handleUpvote = (
  event: CustomEvent<{
    issueId: string;
    upvoted: boolean;
    upvoteCount: number;
  }>
) => {
  // Fully typed event detail
  console.log(event.detail.issueId);
  console.log(event.detail.upvoted);
  console.log(event.detail.upvoteCount);
};
```

## Requirements

- React >= 17.0.0
- React DOM >= 17.0.0
- Modern browsers with Web Components support

## Browser Support

Same as the underlying web components:

- Chrome 61+
- Firefox 63+
- Safari 11+
- Edge 79+

## Migration from Direct Web Components

If you're migrating from using web components directly:

```tsx
// Before (direct web component)
<feedlog-issues-client
  api-key="key"
  onFeedlogUpvote={(e) => console.log(e.detail)}
/>

// After (React component)
<FeedlogIssuesClient
  apiKey="key"
  onFeedlogUpvote={(e) => console.log(e.detail)}
/>
```

**Key differences:**

- `api-key` → `apiKey` (camelCase)
- Event handlers follow React conventions
- All props are properly typed

## License

MIT