npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gaddario98/react-core

v2.1.6

Published

A modular, type-safe React framework that unifies state management, forms, data fetching, page orchestration, localization, authentication, and notifications into a single cohesive package. Built on Jotai, TanStack Form, and TanStack Query.

Readme

@gaddario98/react-core

A modular, type-safe React framework that unifies state management, forms, data fetching, page orchestration, localization, authentication, and notifications into a single cohesive package. Built on Jotai, TanStack Form, and TanStack Query.

Version: 2.1.5 | License: MIT | Author: Giosuè Addario


Table of Contents


Overview

@gaddario98/react-core is composed of independent modules that share a common state layer (Jotai atoms). Each module can be imported individually via sub-path exports or consumed together through the root entry point.

Key design principles:

  • Atom-based state: Every module stores its configuration and runtime state in Jotai atoms via atomStateGenerator, enabling cross-module reactivity without React Context nesting
  • Platform-agnostic: No DOM or React Native imports — platform behavior is injected via configurable container components
  • Tree-shakeable: 10 independent sub-path exports; import only what you use
  • Zero-config defaults: Every module works out of the box with sensible defaults, customizable at any depth
  • TypeScript-first: Full generic type support with strict inference

Installation

npm install @gaddario98/react-core

Peer Dependencies

npm install react@">=18.0.0 <20.0.0"

All other dependencies (@tanstack/react-form, @tanstack/react-query, jotai, axios, fast-deep-equal, fflate) are bundled.


Architecture

@gaddario98/react-core
├── state/           ← Jotai atom factory + compressed storage
├── auth/            ← Authentication state (built on state/)
├── notifications/   ← Toast/notification state (built on state/)
├── localization/    ← i18n engine with ICU formatting (built on state/)
├── form/            ← Dynamic form builder (built on TanStack Form + state/)
├── queries/         ← Data fetching layer (built on TanStack Query + state/)
├── pages/           ← Page orchestrator (composes form/ + queries/ + state/)
├── providers/       ← Generic provider compositor
├── utiles/          ← Utility functions (classnames, memoization)
└── config/          ← useCoreConfig — unified setup hook

The dependency flow is bottom-up: state/ is the foundation, auth/, notifications/, and localization/ are state slices, form/ and queries/ are feature layers, and pages/ orchestrates everything. config/useCoreConfig wires all modules together in a single hook.


Quick Start — Unified Configuration

The useCoreConfig hook initializes all modules at once. Call it near the root of your app:

import { useCoreConfig, AppProviders, QueriesProvider } from "@gaddario98/react-core";

function CoreProvider({ children }: { children: React.ReactNode }) {
  useCoreConfig({
    localization: {
      defaultLocale: "en",
      supportedLocales: ["en", "it"],
      locales: {
        en: { common: { welcome: "Welcome" } },
        it: { common: { welcome: "Benvenuto" } },
      },
    },
    pages: {
      PageContainer: ({ children, id }) => <main id={id}>{children}</main>,
      BodyContainer: ({ children }) => <div className="body">{children}</div>,
      defaultMetadata: { title: "My App" },
    },
    form: {
      formFieldContainer: ({ children }) => <div className="field">{children}</div>,
    },
    apiConfig: {
      endpoints: { api: "https://api.example.com" },
    },
  });

  return <>{children}</>;
}

export default function App() {
  return (
    <AppProviders providers={[QueriesProvider]}>
      <CoreProvider>
        {/* your app */}
      </CoreProvider>
    </AppProviders>
  );
}

useCoreConfig automatically:

  • Wires translateText from the localization module into forms and pages
  • Wires showNotification into forms and queries
  • Sets the Authorization header from auth.token on all API requests
  • Passes authValues into pages for access control

Modules

State (/state)

The foundational layer. Provides a factory function to create Jotai atoms with optional compressed persistence to localStorage.

import { atomStateGenerator } from "@gaddario98/react-core/state";

const {
  atom: themeAtom,
  useValue: useThemeValue,     // read-only hook
  useState: useThemeState,     // [value, setter] hook
  useReset: useThemeReset,     // reset to default
} = atomStateGenerator<"light" | "dark">({
  key: "app-theme",
  defaultValue: "light",
  persist: true,  // compressed localStorage persistence
});

Storage features:

  • Data < 1 KB stored as raw JSON; larger payloads are deflated (fflate) and base64-encoded
  • Writes are debounced (50 ms) and flushed on beforeunload / visibilitychange
  • Swap the storage backend via setCustomStorage(myStorage) (e.g., AsyncStorage for React Native)

Exports:

| Export | Description | |---|---| | atomStateGenerator<T>(options) | Creates an atom with useValue, useState, useReset hooks | | storage | Default compressed storage singleton | | setCustomStorage(s) | Replace the storage backend |


Auth (/auth)

A persisted authentication state slice.

import { useAuthState, useAuthValue } from "@gaddario98/react-core/auth";

// Read auth state
const auth = useAuthValue();
console.log(auth?.token, auth?.isLogged);

// Update auth state
const [auth, setAuth] = useAuthState();
setAuth({ id: "user-1", token: "jwt...", isLogged: true });

// Clear on logout
setAuth(null);

AuthState type:

type AuthState = {
  id: string;
  accountVerified?: boolean;
  isLogged?: boolean;
  token?: string;
  phoneNumber?: string;
  email?: string;
}

The atom is persisted under the key "reactAuthStore" using compressed storage.


Notifications (/notifications)

In-memory notification state for toast/snackbar systems.

import { useNotification } from "@gaddario98/react-core/notifications";

const { showNotification, clearNotification } = useNotification("myPage");

showNotification({
  message: "Profile updated!",
  type: "success",
  autoHideDuration: 3000,
});

NotificationMessage type:

interface NotificationMessage {
  id: string;
  message: string;
  type: "success" | "error" | "info" | "warning";
  autoHideDuration?: number;
  textTransOption?: Record<string, unknown>;
  ns?: string;
}

Exports:

| Export | Description | |---|---| | useNotification(ns?) | Returns { showNotification, clearNotification } | | useNotificationValue() | Read current notification | | useNotificationState() | [notification, setter] tuple | | notificationAtom | Raw Jotai atom |


Localization (/localization)

A built-in i18n engine with no external library dependencies. Supports ICU-style interpolation, pluralization, gender selection, and number/date/currency formatting.

import { useTranslation, useLocalizationActions } from "@gaddario98/react-core/localization";

// Initialize locales at app startup
const { initializeLocale, switchLocale, addLocale } = useLocalizationActions();

initializeLocale({
  defaultLocale: "en",
  supportedLocales: ["en", "it"],
  locales: {
    en: { shop: { items: "{{count, plural, =0{No items} one{1 item} other{# items}}}" } },
    it: { shop: { items: "{{count, plural, =0{Nessun articolo} one{1 articolo} other{# articoli}}}" } },
  },
});

// Use translations
const { t, locale } = useTranslation("shop");
t("items", { count: 5 }); // "5 items"

Supported interpolation patterns:

  • {{name}} — simple variable substitution
  • {{count, number}} — number formatting (locale-aware)
  • {{date, date}} — date formatting
  • {{price, currency}} — currency formatting
  • {{count, plural, =0{...} one{...} other{...}}} — ICU plural rules
  • {{gender, select, male{...} female{...} other{...}}} — gender/select

Server-side usage (outside React):

import { createServerTranslator } from "@gaddario98/react-core/localization";

const { t } = createServerTranslator(resources, "en");
t("shop.items", { count: 3 }); // "3 items"

Form (/form)

A dynamic, type-safe form builder on top of TanStack React Form. Renders fields from a declarative configuration array.

import { FormManager } from "@gaddario98/react-core/form";

interface ContactForm {
  name: string;
  email: string;
}

<FormManager<ContactForm>
  defaultValues={{ name: "", email: "" }}
  data={[
    {
      name: "name",
      label: "Full Name",
      rules: { onChange: (val) => (!val ? "Required" : undefined) },
      component: (props) => <input value={props.value} onChange={(e) => props.onChange(e.target.value)} />,
    },
    {
      name: "email",
      label: "Email",
      component: (props) => <input value={props.value} onChange={(e) => props.onChange(e.target.value)} />,
    },
  ]}
  submit={[
    {
      component: ({ onClick }) => <button onClick={onClick}>Save</button>,
      onSuccess: async (values) => console.log(values),
    },
  ]}
/>

Key features:

  • Static or dynamic field definitions (factory functions with { get, set } access to current values)
  • Partial form submission — validate only a subset of fields via values: ["field1", "field2"]
  • Custom layout containers via viewSettings (dialogs, cards, drawers)
  • Built-in notification integration for success/error feedback
  • Headless alternative via useFormManager hook

Global configuration:

import { useFormConfigState } from "@gaddario98/react-core/form";

const [, setFormConfig] = useFormConfigState();
setFormConfig((prev) => ({
  ...prev,
  translateText: (key, opts) => t(key, opts),
  formFieldContainer: MyFieldWrapper,
  showNotification: (msg) => toast(msg.message),
}));

For full API details, see github.com/gaddario98/react-form.


Queries (/queries)

A unified data fetching layer on top of TanStack React Query and Jotai. Manages queries, mutations, and WebSockets through a single declarative API.

import { useApi } from "@gaddario98/react-core/queries";
import type { QueriesArray } from "@gaddario98/react-core/queries";

const queries = [
  {
    type: "query",
    key: "products",
    queryConfig: {
      endpoint: ["api", "v1/products"],
      queryKey: ["products"],
    },
  },
  {
    type: "mutation",
    key: "addProduct",
    mutationConfig: {
      endpoint: ["api", "v1/products"],
      method: "POST",
      queryKeyToInvalidate: ["products"],
    },
  },
] as const satisfies QueriesArray;

const { allQuery, allMutation, refreshQueries } = useApi(queries, {
  scopeId: "product-page",
});

const products = allQuery.products.data;
allMutation.addProduct.mutate({ body: { name: "New Product" } });

Key features:

  • Typed allQuery / allMutation / allWebSocket maps from the configuration array
  • Automatic Jotai atom sync — query results are accessible cross-component without refetching
  • Fine-grained subscriptions via useApiValues (re-render only on specific path changes)
  • Built-in WebSocket support alongside REST queries
  • Payload encryption/decryption (AES-GCM)
  • Offline persistence via TanStack Query Persist
  • Standalone useQueryApi / useMutateApi hooks for simpler one-off usage

Global configuration:

import { useApiConfigState } from "@gaddario98/react-core/queries";

const [, setApiConfig] = useApiConfigState();
setApiConfig({
  endpoints: { api: "https://api.example.com" },
  defaultHeaders: { "Cache-Control": "no-cache" },
  validateAuthFn: () => !!localStorage.getItem("token"),
  queryClient: new QueryClient({ defaultOptions: { queries: { retry: 2 } } }),
});

Wrap your app with QueriesProvider to initialize the TanStack QueryClient:

import { QueriesProvider } from "@gaddario98/react-core/queries";

<QueriesProvider>
  <App />
</QueriesProvider>

For full API details, see github.com/gaddario98/react-queries.


Pages (/pages)

A page orchestrator that composes forms, queries, metadata, lazy loading, and layout into a single PageProps configuration. Works on both web and React Native.

import { PageGenerator } from "@gaddario98/react-core/pages";
import type { PageProps, QueryDefinition } from "@gaddario98/react-core/pages";

interface MyForm { search: string }
type MyQueries = [QueryDefinition<"results", "query", never, Product[]>];

const props: PageProps<MyForm, MyQueries> = {
  id: "search-page",
  meta: { title: "Search", description: "Find products" },
  form: {
    defaultValues: { search: "" },
    data: [{ name: "search", debounceDelay: 300, component: SearchInput }],
  },
  queries: [
    {
      type: "query",
      key: "results",
      queryConfig: ({ get }) => ({
        queryKey: ["results", get("form", "search")],
        queryFn: () => fetchProducts(get("form", "search")),
        enabled: get("form", "search", "").length > 2,
      }),
    },
  ],
  contents: [
    {
      type: "custom",
      component: ({ get }) => {
        const results = get("query", "results.data", []);
        return <ProductList products={results} />;
      },
    },
  ],
};

<PageGenerator<MyForm, MyQueries> {...props} />;

Key features:

  • get() / set() API with automatic dependency tracking (90% fewer re-renders)
  • Dynamic SEO metadata (Open Graph, Twitter Card, JSON-LD, AI hints, robots)
  • Lazy loading with viewport, interaction, or conditional triggers
  • Lifecycle callbacks (onMountComplete, onQuerySuccess, onQueryError, onFormSubmit, onValuesChange)
  • Authentication gate via enableAuthControl
  • Platform overrides via platformOverrides: { web: {...}, native: {...} }

For full API details, see github.com/gaddario98/react-pages.


Providers (/providers)

A utility component that composes multiple React providers without deep nesting.

import { AppProviders } from "@gaddario98/react-core/providers";

<AppProviders
  providers={[
    QueriesProvider,
    [ThemeProvider, { theme: "dark" }],
    [IntlProvider, { locale: "en" }],
  ]}
>
  <App />
</AppProviders>

Supports both bare components and [Component, props] tuples. Providers are composed in declaration order (first = outermost).


Utilities (/utiles)

General-purpose React and JavaScript utilities.

import { cn, withMemo } from "@gaddario98/react-core/utiles";

| Export | Description | |---|---| | cn(...inputs) | Combines clsx + tailwind-merge for safe Tailwind class merging | | withMemo(Component, areEqual?) | Type-safe React.memo wrapper that preserves generic types | | createExtractor(data, cache?, keys?) | Picks a subset of keys from an object with stable reference caching |


Config (/config)

The unified configuration hook that wires all modules together.

import { useCoreConfig } from "@gaddario98/react-core/config";

CoreConfig interface:

interface CoreConfig {
  form?: Partial<FormConfigProps>;
  localization?: LocalizationConfigProps;
  pages?: Partial<PageConfigProps>;
  apiConfig?: Partial<ApiConfig>;
}

See Quick Start for usage.

What useCoreConfig wires automatically:

| Source | Target | What | |---|---|---| | localization | form, pages | translateText function | | notifications | form, queries | showNotification handler | | auth | queries | Authorization header (Bearer token) | | auth | queries | validateAuthFn (auth validation) | | auth | pages | authValues (access control) |


Entry Points

The package exposes 10 sub-path exports for tree-shaking:

| Import Path | Module | Typical Use | |---|---|---| | @gaddario98/react-core | All modules | Full framework access | | @gaddario98/react-core/state | State | Atom factory, storage | | @gaddario98/react-core/auth | Auth | Authentication state | | @gaddario98/react-core/notifications | Notifications | Toast state | | @gaddario98/react-core/localization | Localization | i18n engine | | @gaddario98/react-core/form | Form | Form builder | | @gaddario98/react-core/queries | Queries | Data fetching | | @gaddario98/react-core/pages | Pages | Page orchestrator | | @gaddario98/react-core/providers | Providers | Provider compositor | | @gaddario98/react-core/utiles | Utilities | Helpers |


Cross-Platform Support

The entire package is platform-agnostic. No module imports react-dom or react-native directly.

Web: Works out of the box. Metadata is written to document.head.

React Native: Replace the storage backend and layout containers:

import { setCustomStorage } from "@gaddario98/react-core/state";
import { usePageConfigState } from "@gaddario98/react-core/pages";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { View, ScrollView } from "react-native";

// Swap storage for React Native
setCustomStorage({
  getItem: (key) => AsyncStorage.getItem(key) ?? null,
  setItem: (key, val) => { AsyncStorage.setItem(key, val) },
  removeItem: (key) => { AsyncStorage.removeItem(key) },
});

// Swap layout containers
const [, setPageConfig] = usePageConfigState();
setPageConfig((prev) => ({
  ...prev,
  PageContainer: ({ children, id }) => <View style={{ flex: 1 }}>{children}</View>,
  BodyContainer: ({ children }) => <ScrollView>{children}</ScrollView>,
  HeaderContainer: ({ children }) => <View>{children}</View>,
  FooterContainer: ({ children }) => <View>{children}</View>,
  ItemsContainer: ({ children }) => <View>{children}</View>,
}));

See the React Native Integration Strategy in the pages documentation for a full setup guide.


TypeScript Support

All modules are fully typed with generics. Key generic interfaces:

// Form — generic over field values
FormManager<F extends FieldValues>
FormManagerProps<F extends FieldValues>

// Queries — generic over query array definition
useApi<Q extends QueriesArray>(queries: Q, options)
QueriesArray  // tuple of query/mutation/websocket definitions

// Pages — generic over form, queries, and page variables
PageGenerator<F extends FieldValues, Q extends QueriesArray, V extends Record<string, unknown>>
PageProps<F, Q, V>
FunctionProps<F, Q, V>  // the { get, set } interface

// State — generic over atom value type
atomStateGenerator<T>(options): AtomState<T>

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.


License

MIT