Remove twenty-ui reexport from the SDK and use twenty-ui directly (#22326)

## What & why

Removes the `twenty-sdk/ui` reexport. Apps now use Twenty UI by
installing
[`twenty-ui@1.0.0-alpha.1`](https://www.npmjs.com/package/twenty-ui/v/1.0.0-alpha.1)
from npm and importing its subpaths directly. The reexport re-exported
types that didn't resolve, forcing typecheck workarounds.

## Changes

- **twenty-sdk**: delete `src/ui/index.ts`, drop the `./ui` export,
remove it from the browser vite build, and rewire the CLI manifest-mock
to `twenty-ui` (`.css` falls through to the empty-CSS loader).
`twenty-ui` stays a devDependency for the CLI fixture tests.
- **Renderer + create-twenty-app template**: import from `twenty-ui`
subpaths; the template pins `twenty-ui@1.0.0-alpha.1`.
- **Docs**: new "Using Twenty UI components" section (install + subpath
imports + `useTheme()` for theme tokens), codex references, and the
cross-doc-contract validator.

The `twenty-for-twenty` / `twenty-slack` example apps are intentionally
left on `twenty-sdk/ui`: they consume the published SDK (which still
ships `./ui`), and `twenty-ui@1.0.0-alpha.1` requires react 19 + a
`monaco-editor` peer the react-18 apps can't satisfy. They migrate once
the SDK is republished.
This commit is contained in:
Raphaël Bosi
2026-06-30 11:17:48 +02:00
committed by GitHub
parent b0d7516951
commit 0dc6272da5
18 changed files with 163 additions and 600 deletions
@@ -16,22 +16,30 @@ type CompiledModuleWrapper = (
) => void;
const MANIFEST_MOCK_MODULES = [
'twenty-sdk/ui',
'twenty-ui',
'twenty-client-sdk/core',
'twenty-client-sdk/metadata',
];
const escapeRegExp = (value: string): string =>
value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const manifestMockPlugin: esbuild.Plugin = {
name: 'manifest-mock',
setup: (build) => {
const filter = new RegExp(
`^(${MANIFEST_MOCK_MODULES.map((module) => module.replace('/', '\\/')).join('|')})$`,
);
const escapedModules = MANIFEST_MOCK_MODULES.map(escapeRegExp);
const filter = new RegExp(`^(${escapedModules.join('|')})(/.*)?$`);
build.onResolve({ filter }, ({ path: modulePath }) => ({
path: modulePath,
namespace: 'manifest-mock',
}));
build.onResolve({ filter }, ({ path: modulePath }) => {
if (modulePath.endsWith('.css')) {
return null;
}
return {
path: modulePath,
namespace: 'manifest-mock',
};
});
build.onLoad({ filter: /.*/, namespace: 'manifest-mock' }, () => ({
contents: 'module.exports = new Proxy({}, { get: () => () => {} });',