GenCN UI

Global Provider

Provider component for Chrome AI APIs (Summarizer, Writer, Rewriter, Language Detector, Proofreader).

Overview

The GencnUIProvider is a required context provider that enables Chrome AI APIs (Summarizer, Writer, Rewriter, Language Detector, and Proofreader) throughout your application. It manages the configuration and state for all GencnUI components and hooks.

You must wrap your application with GencnUIProvider before using any GencnUI components or hooks.

Installation

Setup Required: Make sure you have configured components.json first. See the installation guide for setup instructions.

npx shadcn@latest add @gencn-ui/gencn-ui-provider
"use client";

import {
  createContext,
  useState,
  useRef,
  useMemo,
  useCallback,
  type ReactNode,
} from "react";
import {
  AvailabilityStatus,
} from "@/registry/new-york/gencn-ui/items/shared/gencn-ui-types";
import { GencnUIDownloadWidget } from "@/registry/new-york/gencn-ui/items/shared/components/gencn-ui-download-widget";

export interface ServerModel {
  modelCode: string;
  modelLabel: string;
}

export interface ClientModel {
  modelCode: string;
  modelLabel: string;
}

export interface GencnUIContextValue {
  // Server LLM State
  enableServerLLM: boolean;
  setEnableServerLLM: (enabled: boolean) => void;
  dangerouslySetServerLLMKey: boolean;
  serverKey: string;
  serverModel: ServerModel | null;
  setServerModel: (model: ServerModel | null) => void;
  setServerKey: (key: string) => void;
  // Client Models
  clientModel: ClientModel | null;
  setClientModel: (model: ClientModel | null) => void;

  // Translation cache management (used by useTranslator hook)
  getTranslationCache: (
    text: string,
    targetLanguage: string,
    sourceLanguage?: string
  ) => string | "L" | null;
  getTranslationCacheKey: (
    text: string,
    targetLanguage: string,
    sourceLanguage?: string
  ) => string;
  updateTranslationCache: (key: string, value: string | "L") => void;
  deleteTranslationCache: (key: string) => void;

}

export const GencnUIContext = createContext<GencnUIContextValue | undefined>(
  undefined
);

export interface GencnUIProviderProps {
  children: ReactNode;
  enableServerLLM?: boolean;
  dangerouslySetServerLLMKey?: boolean;
  serverModel?: ServerModel;
  clientModel?: ClientModel;
}

export function GencnUIProvider({
  children,
  enableServerLLM = true,
  dangerouslySetServerLLMKey = false,
  serverModel,
  clientModel,
}: GencnUIProviderProps) {
  // ============================================================================
  // STATE DECLARATIONS
  // ============================================================================

  // Server LLM State
  const [enableServerLLMState, setEnableServerLLMState] =
    useState<boolean>(enableServerLLM);
  const [serverModelState, setServerModelState] = useState<ServerModel | null>(serverModel || null);
  const [serverKey, setServerKey] = useState<string>("");
  
  // Client Model State
  const [clientModelState, setClientModelState] = useState<ClientModel | null>(clientModel || null);

  // Translation cache: Map<key, value> where value is "L" for loading or the translated text
  // Use state to make it reactive so components can react to cache updates
  const [translationCache, setTranslationCache] = useState<
    Map<string, string | "L">
  >(new Map());


  // Generate cache key from text, sourceLanguage, and targetLanguage
  const getTranslationCacheKey = useCallback(
    (text: string, targetLanguage: string, sourceLanguage?: string): string => {
      // Simple hash function for cache key
      const keyString = `${text}|${sourceLanguage || "auto"}|${targetLanguage}`;
      // Use a simple hash (in production, you might want a more robust hash)
      let hash = 0;
      for (let i = 0; i < keyString.length; i++) {
        const char = keyString.charCodeAt(i);
        hash = (hash << 5) - hash + char;
        hash = hash & hash; // Convert to 32-bit integer
      }
      return `trans_${Math.abs(hash)}`;
    },
    []
  );

  // Get translation from cache - returns current cache value for specific translation
  const getTranslationCache = useCallback(
    (
      text: string,
      targetLanguage: string,
      sourceLanguage?: string
    ): string | "L" | null => {
      const key = getTranslationCacheKey(text, targetLanguage, sourceLanguage);
      return translationCache.get(key) || null;
    },
    [getTranslationCacheKey, translationCache]
  );

  // Update cache helper - updates state reactively
  const updateTranslationCache = useCallback(
    (key: string, value: string | "L") => {
      setTranslationCache((prev) => {
        // Only update if value actually changed to avoid unnecessary re-renders
        const currentValue = prev.get(key);
        if (currentValue === value) {
          return prev; // Return same reference if value unchanged
        }
        const newCache = new Map(prev);
        newCache.set(key, value);
        return newCache;
      });
    },
    []
  );

  // Delete from cache helper
  const deleteTranslationCache = useCallback((key: string) => {
    setTranslationCache((prev) => {
      if (!prev.has(key)) {
        return prev; // Return same reference if key doesn't exist
      }
      const newCache = new Map(prev);
      newCache.delete(key);
      return newCache;
    });
  }, []);



  // Memoize context value to prevent unnecessary re-renders of consumers
  // Only recreate when actual values change, not on every render
  const value: GencnUIContextValue = useMemo(
    () => ({
      // Server LLM
      enableServerLLM: enableServerLLMState,
      setEnableServerLLM: setEnableServerLLMState,
      dangerouslySetServerLLMKey,
      serverKey,
      serverModel: serverModelState,
      setServerModel: setServerModelState,
      setServerKey,
      clientModel: clientModelState,
      setClientModel: setClientModelState,
      // Translation cache
      getTranslationCache,
      getTranslationCacheKey,
      updateTranslationCache,
      deleteTranslationCache,
    }),
    [
      // Only include values that actually change
      enableServerLLMState,
      serverKey,
      serverModelState,
      clientModelState,
      dangerouslySetServerLLMKey,
      getTranslationCache, // Changes when translationCache changes
      // Setters and stable callbacks are excluded - they never change
      // but included in object for API consistency
    ]
  );

  return (
    <GencnUIContext.Provider value={value}>
      {children}
      <GencnUIDownloadWidget />
    </GencnUIContext.Provider>
  );
}

Usage

Wrap your application with GencnUIProvider at the root level of your app. Once wrapped, you can use GencnUI components and hooks throughout your application.

In Next.js, wrap your application in the root layout file:

import { GencnUIProvider } from "@/registry/new-york/gencn-ui/items/shared/provider/gencn-ui-provider";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <GencnUIProvider>{children}</GencnUIProvider>
      </body>
    </html>
  );
}

If you're using the App Router, make sure to add 'use client' if the layout file needs to be a client component:

"use client";

import { GencnUIProvider } from "@/registry/new-york/gencn-ui/items/shared/provider/gencn-ui-provider";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <GencnUIProvider>{children}</GencnUIProvider>
      </body>
    </html>
  );
}

In a standard React application, wrap your app component:

import { GencnUIProvider } from "@/registry/new-york/gencn-ui/items/shared/provider/gencn-ui-provider";

function App() {
  return <GencnUIProvider>{/* Your app components */}</GencnUIProvider>;
}

export default App;

Or in your main entry file:

import React from "react";
import ReactDOM from "react-dom/client";
import { GencnUIProvider } from "@/registry/new-york/gencn-ui/items/shared/provider/gencn-ui-provider";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <GencnUIProvider>
      <App />
    </GencnUIProvider>
  </React.StrictMode>
);

After wrapping your application with GencnUIProvider, you can start using GencnUI components (like GencnUIInput, GencnUITextarea) and hooks (like useGencnUIChat, useGencnUISummarizer) throughout your application.

Component API