Skip to content
This repository was archived by the owner on Oct 26, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/13453-providers-retire-trio.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@object-ui/providers": minor
---

Clause-②: no
Metadata-protocol: none

**Breaking:** removed `DataSourceProvider` / `useDataSource`, `MetadataProvider` / `useMetadata`, `ThemeProvider` / `useTheme` and the types `DataSourceProviderProps`, `MetadataProviderProps`, `ThemePreferenceProviderProps`, `ThemePreference` (objectui#13453). They duplicated names other ObjectUI packages publish with different implementations. Declared `minor` per the version-alignment policy (a changeset never declares `major`). `UploadProvider`, `useUpload` and the upload adapters are unchanged.

Migration: wrap the tree in `SchemaRendererProvider` from `@object-ui/react` (its `dataSource` prop) instead of `DataSourceProvider`, and pass the adapter to views as before; use `ThemeProvider` / `useTheme` from `@object-ui/react` (`defaultMode`, where the old `system` is `auto`; add `persist` to keep the choice in `localStorage`); use `MetadataProvider` / `useMetadata` from `@object-ui/app-shell`.
Original file line number Diff line number Diff line change
Expand Up @@ -404,11 +404,10 @@ prefix across the table.
| `FavoritesProvider` | `packages/app-shell/src/context/FavoritesProvider.tsx` | User's starred/pinned items |
| `ExpressionProvider` | `packages/app-shell/src/providers/ExpressionProvider.tsx` | Expression evaluator instance |

`MetadataProvider` is the one name with two hits in the repo. The console's is the
app-shell file above — it is what `ConsoleShell` / `ConnectedShell` mount and what
`@object-ui/app-shell` re-exports. `packages/providers/src/MetadataProvider.tsx` is an
unrelated, much smaller generic provider (static metadata or one fetch); nothing in the
console path uses it.
`MetadataProvider` is the app-shell file above — it is what `ConsoleShell` /
`ConnectedShell` mount and what `@object-ui/app-shell` re-exports. `@object-ui/providers`
used to publish an unrelated generic provider under the same name; it retired in
objectui#13453, so the app-shell one is the only `MetadataProvider` left.

## Key hooks

Expand Down
15 changes: 7 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Pick the path that matches where you are starting from:
| You want to… | Start here | Install |
|---|---|---|
| Render a JSON schema inside your React app | [`examples/hello-world`](examples/hello-world) | `@object-ui/react @object-ui/components` |
| Embed views in an existing app, against **your own** backend | [`examples/byo-backend-console`](examples/byo-backend-console) | `@object-ui/app-shell @object-ui/plugin-view @object-ui/providers` |
| Embed views in an existing app, against **your own** backend | [`examples/byo-backend-console`](examples/byo-backend-console) | `@object-ui/app-shell @object-ui/plugin-view @object-ui/react` |
| Stand up a complete console on an **ObjectStack** backend | [`examples/console-starter`](examples/console-starter) | fork the example |
| Build a UI from a JSON file, no React code at all | [`@object-ui/cli`](packages/cli) | `npm install -g @object-ui/cli` |

Expand Down Expand Up @@ -120,14 +120,14 @@ nothing thrown and one line on the console.
Use the shell and views without the full console infrastructure — your routing, your auth, your API:

```bash
npm install @object-ui/app-shell @object-ui/plugin-view @object-ui/providers
npm install @object-ui/app-shell @object-ui/plugin-view @object-ui/react
```

```tsx
import type { FC } from 'react';
import { AppShell } from '@object-ui/app-shell';
import { ObjectView } from '@object-ui/plugin-view';
import { ThemeProvider, DataSourceProvider, useDataSource } from '@object-ui/providers';
import { ThemeProvider, SchemaRendererProvider } from '@object-ui/react';
import type { DataSource } from '@object-ui/types';

// The two pieces you bring: the backend adapter you implement (see "Custom
Expand All @@ -138,19 +138,18 @@ declare const MySidebar: FC;
function MyConsole() {
return (
<ThemeProvider>
<DataSourceProvider dataSource={myAPI}>
<SchemaRendererProvider dataSource={myAPI}>
<AppShell sidebar={<MySidebar />}>
<ContactList />
</AppShell>
</DataSourceProvider>
</SchemaRendererProvider>
</ThemeProvider>
);
}

function ContactList() {
const dataSource = useDataSource();
return (
<ObjectView schema={{ type: 'object-view', objectName: 'contact' }} dataSource={dataSource} />
<ObjectView schema={{ type: 'object-view', objectName: 'contact' }} dataSource={myAPI} />
);
}
```
Expand Down Expand Up @@ -380,7 +379,7 @@ Grouped by dependency weight — atoms and fields stay light, heavy widgets live
| Package | Description |
|---------|-------------|
| **[@object-ui/app-shell](./packages/app-shell)** | Minimal application shell — the base of every console |
| **[@object-ui/providers](./packages/providers)** | Theme, data-source, and other reusable context providers |
| **[@object-ui/providers](./packages/providers)** | The upload adapter context the file and image fields upload through |
| **[@object-ui/auth](./packages/auth)** | `AuthProvider`, `useAuth`, `AuthGuard`, sign-in forms |
| **[@object-ui/permissions](./packages/permissions)** | Object / field / row-level permission guards and hooks |
| **[@object-ui/i18n](./packages/i18n)** | Language packs, RTL layout, date and currency formatting |
Expand Down
77 changes: 36 additions & 41 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,18 @@ This document describes the refactored architecture that enables third-party sys

### @object-ui/providers

**Purpose**: Reusable context providers
**Purpose**: The upload adapter context

**Exports**:
- `DataSourceProvider` - Generic data source context
- `MetadataProvider` - Schema/metadata management
- `ThemeProvider` - Theme management
- `UploadProvider` / `useUpload` - The ambient upload adapter the file and image fields upload through
- `createObjectStackUploadAdapter`, `createS3Adapter`, `createAzureBlobAdapter`, `createObjectUrlAdapter`

**Dependencies**: `@object-ui/types`
Its former `DataSourceProvider`, `MetadataProvider` and `ThemeProvider` retired
(objectui#13453). The data source is `SchemaRendererProvider` and the theme is
`ThemeProvider`, both from `@object-ui/react`; metadata is `MetadataProvider` from
`@object-ui/app-shell`.

**Bundle Size**: ~10KB
**Dependencies**: `@object-ui/types`

## Architecture Diagram

Expand All @@ -64,15 +66,10 @@ This document describes the refactored architecture that enables third-party sys
└────────────────┬────────────────────────┘
│
┌────────────────┴────────────────────────┐
│ @object-ui/providers │
│ - DataSourceProvider │
│ - MetadataProvider │
│ - ThemeProvider │
└────────────────┬────────────────────────┘
│
┌────────────────┴────────────────────────┐
│ @object-ui/react │
│ - SchemaRenderer │
│ - SchemaRendererProvider (data source) │
│ - ThemeProvider │
│ - useActionRunner │
│ - Component Registry │
└────────────────┬────────────────────────┘
Expand Down Expand Up @@ -115,10 +112,9 @@ apps/console (500KB+)
├── Page Rendering
└── Form Rendering

@object-ui/providers (10KB)
├── Generic DataSource
├── Metadata Management
└── Theme System
@object-ui/react
├── SchemaRendererProvider (generic DataSource)
└── ThemeProvider

Third-Party App
├── Custom Routing
Expand Down Expand Up @@ -162,32 +158,30 @@ Third-Party App
import { AppShell } from '@object-ui/app-shell';
import type { MinimalAppShellProps } from '@object-ui/app-shell';
import { ObjectView } from '@object-ui/plugin-view';
import { DataSourceProvider, useDataSource } from '@object-ui/providers';
import type { DataSourceProviderProps } from '@object-ui/providers';
import { SchemaRendererProvider } from '@object-ui/react';
import type { DataSource } from '@object-ui/types';

// The two things you bring. Both are typed from the surface these packages
// ship, so this snippet compiles on its own: `myAPI` is your backend adapter
// (the "Custom Data Source Interface" section below is the shape it needs at
// runtime — `DataSourceProvider` declares the prop `any`, so the annotation
// records where the value goes rather than checking it), and `MySidebar` is
// your own component, returning whatever `AppShell` accepts for `sidebar`.
declare const myAPI: DataSourceProviderProps['dataSource'];
// (the "Custom Data Source Interface" section below is the shape it needs),
// and `MySidebar` is your own component, returning whatever `AppShell`
// accepts for `sidebar`.
declare const myAPI: DataSource;
declare function MySidebar(): MinimalAppShellProps['sidebar'];

function MyConsole() {
return (
<DataSourceProvider dataSource={myAPI}>
<SchemaRendererProvider dataSource={myAPI}>
<AppShell sidebar={<MySidebar />}>
<ContactList />
</AppShell>
</DataSourceProvider>
</SchemaRendererProvider>
);
}

function ContactList() {
const dataSource = useDataSource();
return (
<ObjectView schema={{ type: 'object-view', objectName: 'contact' }} dataSource={dataSource} />
<ObjectView schema={{ type: 'object-view', objectName: 'contact' }} dataSource={myAPI} />
);
}
```
Expand All @@ -198,8 +192,8 @@ Both files below open with `'use client'`. Under the Next.js App Router every
module under `app/` is a **server** component by default, and the `@object-ui/*`
packages carry no `'use client'` banner of their own — so the client boundary has
to be declared here, in the files that import them. Without the directive the
layout's React context providers and the page's `useDataSource()` hook are both
asked to run on the server, where neither exists.
layout's React context providers and the page's client view are both asked to
run on the server, where neither exists.

`app/layout.tsx`:

Expand All @@ -208,7 +202,7 @@ asked to run on the server, where neither exists.

import { AppShell } from '@object-ui/app-shell';
import type { MinimalAppShellProps } from '@object-ui/app-shell';
import { ThemeProvider } from '@object-ui/providers';
import { ThemeProvider } from '@object-ui/react';

export default function RootLayout({ children }: { children: MinimalAppShellProps['children'] }) {
return (
Expand All @@ -225,43 +219,44 @@ export default function RootLayout({ children }: { children: MinimalAppShellProp
'use client';

import { ObjectView } from '@object-ui/plugin-view';
import { useDataSource } from '@object-ui/providers';
import type { DataSource } from '@object-ui/types';

// Your backend adapter, imported from your own module.
declare const myAPI: DataSource;

export default function Page({ params }: { params: { object: string } }) {
const dataSource = useDataSource();
return <ObjectView schema={{ type: 'object-view', objectName: params.object }} dataSource={dataSource} />;
return <ObjectView schema={{ type: 'object-view', objectName: params.object }} dataSource={myAPI} />;
}
```

### Example 3: Embedded Widget

```tsx
import { ObjectView } from '@object-ui/plugin-view';
import { DataSourceProvider, useDataSource } from '@object-ui/providers';
import type { DataSourceProviderProps } from '@object-ui/providers';
import { SchemaRendererProvider } from '@object-ui/react';
import type { DataSource } from '@object-ui/types';

// Your backend adapter, as in Example 1 — declared here because every block on
// this page compiles on its own.
declare const myAPI: DataSourceProviderProps['dataSource'];
declare const myAPI: DataSource;

function MyExistingApp() {
return (
<div className="my-app">
<header>My App Header</header>

{/* Embed ObjectUI widget */}
<DataSourceProvider dataSource={myAPI}>
<SchemaRendererProvider dataSource={myAPI}>
<ContactWidget />
</DataSourceProvider>
</SchemaRendererProvider>

<footer>My App Footer</footer>
</div>
);
}

function ContactWidget() {
const dataSource = useDataSource();
return <ObjectView schema={{ type: 'object-view', objectName: 'contact' }} dataSource={dataSource} />;
return <ObjectView schema={{ type: 'object-view', objectName: 'contact' }} dataSource={myAPI} />;
}
```

Expand Down
2 changes: 1 addition & 1 deletion docs/audits/2901-spec-enum-renderer-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ The #2897 shape. Validates, renders nothing, nobody knows it should be full.
| 7 chart types draw an **empty plot** | [AdvancedChartImpl.tsx:343](../../packages/plugin-charts/src/AdvancedChartImpl.tsx) | Grid, axes, tooltip and legend all render; every series mark hits `return null`. Looks like an empty dataset. |
| 6 of 9 animation presets do nothing | [useAnimation.ts:64](../../packages/react/src/hooks/useAnimation.ts) | `PRESET_CLASSES` is keyed in **hyphens** (`'slide-up'`), the spec enum in **underscores** (`slide_up`); `rotate`/`flip` absent entirely. Lookup misses → `''` → no animation. |
| 3 of 6 easings emit **invalid CSS** | [useAnimation.ts:112](../../packages/react/src/hooks/useAnimation.ts) | Same split, but `EASING_MAP[easing] \|\| easing` falls through to the raw string. `animationTimingFunction: 'ease_in_out'` — browser drops it, devtools shows the attribute populated. |
| `mode: 'auto'` breaks theming | [ThemeProvider.tsx:38](../../packages/app-shell/src/chrome/ThemeProvider.tsx) + [providers/ThemeProvider.tsx:33](../../packages/providers/src/ThemeProvider.tsx) | Renderer branches on `"system"`; spec says `auto`. `root.classList.add('auto')` matches no Tailwind variant → light theme, OS preference no longer followed, no error. |
| `mode: 'auto'` breaks theming | [ThemeProvider.tsx:38](../../packages/app-shell/src/chrome/ThemeProvider.tsx) + `providers/ThemeProvider.tsx` (retired in objectui#13453) | Renderer branches on `"system"`; spec says `auto`. `root.classList.add('auto')` matches no Tailwind variant → light theme, OS preference no longer followed, no error. |
| Export **PDF** downloads nothing | [ObjectGrid.tsx:1258](../../packages/plugin-grid/src/ObjectGrid.tsx), [ListView.tsx:1611](../../packages/plugin-list/src/ListView.tsx) | Excluded from `serverEligible` and absent from the client fallback. Popover closes, no file. `xlsx` does the same whenever the server path is unavailable. |
| Timeline `scale` blanks the axis | [renderer.tsx:270](../../packages/plugin-timeline/src/renderer.tsx) | `hour`/`quarter`/`year` produce zero header columns. All six are ignored entirely on the default `vertical` variant. |
| All 6 toast positions discarded | [toaster.tsx:15](../../packages/components/src/renderers/feedback/toaster.tsx) | `<SonnerToaster />` with no props, `inputs: []`. |
Expand Down
2 changes: 1 addition & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Runnable examples that show how to consume ObjectUI in different scenarios. Pick
| Example | Use it when… | Backend | Bundle | What it gives you |
|---|---|---|---|---|
| [`hello-world/`](./hello-world) | You want the smallest possible `<SchemaRenderer>` demo to see the JSON → React pipeline. | None (in-memory schema) | Tiny | A single `App.tsx` rendering one schema. |
| [`byo-backend-console/`](./byo-backend-console) | You want to **embed** ObjectUI into your own app and connect it to **your own** REST/GraphQL backend. | Bring-your-own (mock REST shown) | ~50 KB | `@object-ui/app-shell` + `@object-ui/providers`, custom router, custom `DataSource`. ~100 lines of integration code, no auth, no plugins. |
| [`byo-backend-console/`](./byo-backend-console) | You want to **embed** ObjectUI into your own app and connect it to **your own** REST/GraphQL backend. | Bring-your-own (mock REST shown) | ~50 KB | `@object-ui/app-shell` + `@object-ui/react`, custom router, custom `DataSource`. ~100 lines of integration code, no auth, no plugins. |
| [`console-starter/`](./console-starter) | You want a **fork-ready, opinionated console** with the full plugin set already wired against an **ObjectStack** backend. | ObjectStack (`/api/v1`) | Full | `@object-ui/app-shell` `ConsoleShell` + `AuthProvider` + every `@object-ui/plugin-*` (grid, kanban, calendar, charts, dashboard, designer, detail, form, list, report, view, chatbot). |

> **Rule of thumb:**
Expand Down
26 changes: 11 additions & 15 deletions examples/byo-backend-console/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This example demonstrates how third-party systems can integrate ObjectUI compone
- ✅ Custom data adapter (mock REST API, not ObjectStack)
- ✅ Using `@object-ui/app-shell` for the page shell
- ✅ Using `@object-ui/plugin-view` for object views (`ObjectView`)
- ✅ Using `@object-ui/providers` for context
- ✅ Using `@object-ui/react` for the theme and the ambient data source
- ✅ No console dependencies
- ✅ ~100 lines of integration code

Expand Down Expand Up @@ -65,18 +65,18 @@ object view:
import { Routes, Route, useParams } from 'react-router-dom';
import { AppShell } from '@object-ui/app-shell';
import { ObjectView } from '@object-ui/plugin-view';
import { ThemeProvider, DataSourceProvider } from '@object-ui/providers';
import { ThemeProvider, SchemaRendererProvider } from '@object-ui/react';

function App() {
return (
<ThemeProvider>
<DataSourceProvider dataSource={mockDataSource}>
<SchemaRendererProvider dataSource={mockDataSource}>
<AppShell sidebar={<MySidebar />}>
<Routes>
<Route path="/:objectName" element={<ObjectPage />} />
</Routes>
</AppShell>
</DataSourceProvider>
</SchemaRendererProvider>
</ThemeProvider>
);
}
Expand All @@ -101,7 +101,7 @@ function ObjectPage() {
Full control over routes - no predefined structure:

```tsx
import { useDataSource } from '@object-ui/providers';
import { mockDataSource } from './mockDataSource';

function AppRoutes() {
return (
Expand All @@ -114,15 +114,13 @@ function AppRoutes() {
);
}

// One small component per object. Inside `DataSourceProvider`, `useDataSource()`
// supplies the data source that `ObjectView` requires.
// One small component per object. `ObjectView` requires its `dataSource`
// prop, so pass your adapter in.
function ObjectListPage({ objectName }: { objectName: string }) {
const dataSource = useDataSource();

return (
<ObjectView
schema={{ type: 'object-view', objectName }}
dataSource={dataSource}
dataSource={mockDataSource}
/>
);
}
Expand All @@ -143,11 +141,9 @@ export default function RootLayout({ children }: { children: React.ReactNode })
// app/[object]/page.tsx
'use client';
import { ObjectView } from '@object-ui/plugin-view';
import { useDataSource } from '@object-ui/providers';
import { dataSource } from '../../lib/dataSource'; // your adapter

export default function ObjectPage({ params }: { params: { object: string } }) {
const dataSource = useDataSource();

return (
<ObjectView
schema={{ type: 'object-view', objectName: params.object }}
Expand Down Expand Up @@ -182,11 +178,11 @@ function App() {
}

return (
<DataSourceProvider dataSource={myDataSource}>
<SchemaRendererProvider dataSource={myDataSource}>
<AppShell sidebar={<Sidebar onLogout={logout} />}>
{/* ... */}
</AppShell>
</DataSourceProvider>
</SchemaRendererProvider>
);
}
```
Expand Down
1 change: 0 additions & 1 deletion examples/byo-backend-console/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
"@object-ui/components": "workspace:*",
"@object-ui/plugin-form": "workspace:*",
"@object-ui/plugin-view": "workspace:*",
"@object-ui/providers": "workspace:*",
"@object-ui/react": "workspace:*",
"@object-ui/types": "workspace:*",
"react": "19.3.0",
Expand Down
Loading
Loading