@editora/ui-react

React wrappers, providers, and hooks for @editora/ui-core Web Components.

Overview

@editora/ui-react provides React-native ergonomics on top of Web Components from @editora/ui-core. It includes typed wrappers, hooks for common workflows, and providers for dialogs and theme state.

Installation

npm install @editora/ui-react @editora/ui-core

Peer dependencies: react, react-dom.

Quick Start

import { Button, Input, ThemeProvider } from '@editora/ui-react';

export function App() {
  return (
    <ThemeProvider>
      <div style={{ display: 'grid', gap: 12, maxWidth: 360 }}>
        <Input name="title" label="Title" placeholder="Untitled" clearable />
        <Button variant="primary">Save</Button>
      </div>
    </ThemeProvider>
  );
}

Import Rule

Prefer package-root imports from @editora/ui-react. If you deep-import wrappers directly, ensure @editora/ui-core is imported first so custom elements are registered.

Providers and Hooks

API Type Use Case
ThemeProvider, useTheme Provider + hook Token-based theming and persisted theme state.
DialogProvider, useDialog Provider + hook Promise-based confirm/prompt dialog workflows.
AlertDialogProvider, useAlertDialog Provider + hook Destructive/alert flow confirmations with accessibility defaults.
useForm Hook Validation, submit, dirty-state, reset, and value extraction from wrapped forms.

Common Patterns

1. Form + useForm

import { Form, Field, Input, Button, useForm } from '@editora/ui-react';

export function ProfileForm() {
  const { ref, submit, validate, getValues, reset, isDirty } = useForm();

  return (
    <Form
      ref={ref}
      autosave
      guardUnsaved
      onSubmit={(values) => console.log('submit', values)}
      onInvalid={(errors) => console.log('invalid', errors)}
    >
      <Field label="Full name" required>
        <Input name="fullName" required />
      </Field>

      <Field label="Email" required>
        <Input name="email" type="email" required />
      </Field>

      <Button onClick={() => submit()} disabled={!isDirty()}>Submit</Button>
      <Button variant="secondary" onClick={() => reset()}>Reset</Button>
      <Button variant="secondary" onClick={() => console.log(getValues())}>Values</Button>
    </Form>
  );
}

2. Dialog providers

import { DialogProvider, useDialog, AlertDialogProvider, useAlertDialog, Button } from '@editora/ui-react';

function Actions() {
  const dialog = useDialog();
  const alerts = useAlertDialog();

  return (
    <div style={{ display: 'flex', gap: 8 }}>
      <Button onClick={async () => {
        const res = await dialog.confirm({ title: 'Archive project?' });
        console.log(res);
      }}>Confirm</Button>

      <Button variant="secondary" onClick={async () => {
        const res = await alerts.prompt({ title: 'Rename' });
        console.log(res);
      }}>Prompt</Button>
    </div>
  );
}

export function DialogExample() {
  return (
    <DialogProvider>
      <AlertDialogProvider>
        <Actions />
      </AlertDialogProvider>
    </DialogProvider>
  );
}

3. Data table workflows

import { DataTable, Pagination } from '@editora/ui-react';
import { useState } from 'react';

export function UsersTable() {
  const [page, setPage] = useState(1);

  return (
    <div style={{ display: 'grid', gap: 10 }}>
      <DataTable
        sortable
        selectable
        page={page}
        pageSize={10}
        paginationId="users-pager"
        onPageChange={(d) => setPage(d.page)}
        onSortChange={(d) => console.log('sort', d)}
        onRowSelect={(d) => console.log('rows', d.indices)}
      >
        {/* table markup */}
      </DataTable>

      <Pagination id="users-pager" page={String(page)} />
    </div>
  );
}

4. Gantt planning workspace

Gantt provides an interactive project timeline for release plans, delivery roadmaps, and dependency-heavy schedules. It supports task, summary, and milestone rows; baselines; critical tasks; split segments; dependency links; drag/resize editing; keyboard selection; and virtualized rendering for large plans.

import { Gantt, type GanttLink, type GanttTask } from '@editora/ui-react';
import { useState } from 'react';

const initialTasks: GanttTask[] = [
  {
    id: 'foundation',
    label: 'Foundation build',
    start: '2026-02-01',
    end: '2026-02-18',
    progress: 68,
    baselineStart: '2026-01-29',
    baselineEnd: '2026-02-14',
    critical: true
  },
  {
    id: 'launch',
    label: 'Launch milestone',
    start: '2026-02-28',
    type: 'milestone',
    tone: 'success'
  }
];

const links: GanttLink[] = [
  { id: 'foundation-launch', source: 'foundation', target: 'launch', type: 'e2s' }
];

export function ReleasePlan() {
  const [tasks, setTasks] = useState(initialTasks);

  return (
    <Gantt
      tasks={tasks}
      links={links}
      zoom="week"
      sort="start"
      barVariant="soft"
      onTaskChange={({ id, start, end }) => {
        setTasks((items) => items.map((task) => (
          task.id === id ? { ...task, start: start ?? task.start, end: end ?? task.end } : task
        )));
      }}
      onTaskDelete={({ id }) => setTasks((items) => items.filter((task) => task.id !== id))}
      onLinkSelect={(detail) => console.log('dependency selected', detail)}
    />
  );
}
  • Dependency types: e2s, s2s, e2e, and s2e.
  • Bar variants: solid, soft, striped, outline, and glass.
  • Scale support: automatic row virtualization for large schedules, including the 10,000-task Storybook example.

Component Groups

  • Forms: Form, Field, Input, Textarea, Select, Combobox, Switch, Checkbox, DatePicker, ColorPicker
  • Data: DataTable, Pagination, Table, Calendar, Chart, Timeline, Gantt, Progress
  • Overlay: Dialog, AlertDialog, Popover, Tooltip, Dropdown, Drawer
  • Layout: Layout, Sidebar, Tabs, Grid, Flex, Container, Section

Theming

import { ThemeProvider } from '@editora/ui-react';

<ThemeProvider
  tokens={{
    colors: { primary: '#0f766e', text: '#0f172a', background: '#ffffff' },
    radius: '10px'
  }}
  storageKey="my-app.theme"
>
  {/** app */}
</ThemeProvider>

SSR and StrictMode Notes

  • Providers are SSR-safe and create host nodes on client mount.
  • Promise dialog providers are StrictMode-safe and clean up on unmount.
  • Avoid calling custom element imperative methods until component mount is complete.

Production Guidance

  • Keep root imports from @editora/ui-react to avoid registration drift.
  • Batch expensive state updates around large table operations.
  • Prefer declarative props over direct DOM mutation of wrapped components.

Related Docs