diff --git a/.gitignore b/.gitignore
index 33946f6..7cc67a7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,8 @@ node_modules
dist
*.tsbuildinfo
+examples/**/dist
+
.DS_Store
Thumbs.db
@@ -11,4 +13,3 @@ Thumbs.db
!.yarn/releases
!.yarn/sdks
!.yarn/versions
-.pnp.*
diff --git a/.yarnrc.yml b/.yarnrc.yml
new file mode 100644
index 0000000..3186f3f
--- /dev/null
+++ b/.yarnrc.yml
@@ -0,0 +1 @@
+nodeLinker: node-modules
diff --git a/README.md b/README.md
index d7ae673..4ac519a 100644
--- a/README.md
+++ b/README.md
@@ -99,6 +99,23 @@ yarn typecheck # type-only check
Outputs land in `dist/`: ESM (`.js`), CJS (`.cjs`), declarations (`.d.ts`), and the editor stylesheet.
+## Demo app
+
+A tiny Vite playground lives in [`examples/demo`](./examples/demo). It mounts
+` ` against a stub adapter with a minimal XRD + Composition so
+you can drive the UI end-to-end without a host application. It's wired up as a
+Yarn workspace, so `yarn install` at the repo root sets it up alongside the
+library.
+
+```bash
+yarn install # installs the library + demo workspace
+yarn demo # starts the Vite dev server
+yarn demo:build # production build of the demo
+```
+
+The demo imports the library straight from `../../src`, so editing files under
+`src/` hot-reloads inside the demo.
+
## License
MIT
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 3589ef7..173421e 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -6,13 +6,20 @@ import globals from 'globals';
export default tseslint.config(
{
- ignores: ['dist/**', 'node_modules/**', '.yarn/**', '.claude/**'],
+ ignores: [
+ 'dist/**',
+ 'node_modules/**',
+ '.yarn/**',
+ '.claude/**',
+ 'examples/**/dist/**',
+ 'examples/**/node_modules/**',
+ ],
},
js.configs.recommended,
...tseslint.configs.recommended,
react.configs.flat.recommended,
{
- files: ['src/**/*.{ts,tsx}'],
+ files: ['src/**/*.{ts,tsx}', 'examples/**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
diff --git a/examples/demo/README.md b/examples/demo/README.md
new file mode 100644
index 0000000..52abf5e
--- /dev/null
+++ b/examples/demo/README.md
@@ -0,0 +1,46 @@
+# composer-demo
+
+Tiny Vite + React app for poking at `@overlock-studio/composer` without a host.
+It's a Yarn workspace under the parent repo and imports the library directly
+from `../../src`, so edits to the library hot-reload.
+
+## Run
+
+From the repo root:
+
+```bash
+yarn install # installs the workspace, hoists everything to ./node_modules
+yarn demo # vite dev server, opens http://localhost:5173
+yarn demo:build
+```
+
+Or from inside this folder:
+
+```bash
+yarn dev
+yarn build
+```
+
+## What it does
+
+- Loads a minimal Crossplane bundle (`crossplane.yaml` + XRD + one Composition with a `nop` managed resource).
+- Mounts ` ` with a stubbed `EditorDataAdapter`.
+- Captures the `onSave` payload and renders it in a side panel for inspection.
+- A header button calls the imperative `editorRef.current?.save()` to exercise the ref handle.
+
+## Editing the library
+
+Source resolution goes through Vite aliases in `vite.config.ts`:
+
+| Import | Resolves to |
+| ----------------------------------------------- | ------------------------------------ |
+| `@overlock-studio/composer` | `../../src/index.ts` |
+| `@overlock-studio/composer/styles/editor.css` | `../../src/styles/editor.css` |
+
+So any change in `composer/src/**` triggers HMR in the demo.
+
+## Tailwind
+
+The library ships utility classes. Tailwind is configured locally
+(`tailwind.config.ts`) to scan both demo and library sources, and
+`src/index.css` defines the shadcn-style HSL CSS variables the library expects.
diff --git a/examples/demo/index.html b/examples/demo/index.html
new file mode 100644
index 0000000..d146106
--- /dev/null
+++ b/examples/demo/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Composer Demo
+
+
+
+
+
+
diff --git a/examples/demo/package.json b/examples/demo/package.json
new file mode 100644
index 0000000..f2c4869
--- /dev/null
+++ b/examples/demo/package.json
@@ -0,0 +1,27 @@
+{
+ "name": "@overlock-studio/composer-demo",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@overlock-studio/composer": "workspace:*",
+ "@xyflow/react": "^12.10.0",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
+ },
+ "devDependencies": {
+ "@types/react": "^19.1.10",
+ "@types/react-dom": "^19.0.2",
+ "@vitejs/plugin-react": "^4.3.4",
+ "autoprefixer": "^10.4.20",
+ "postcss": "^8.4.49",
+ "tailwindcss": "^3.4.17",
+ "typescript": "^5.6.3",
+ "vite": "^6.0.7"
+ }
+}
diff --git a/examples/demo/postcss.config.js b/examples/demo/postcss.config.js
new file mode 100644
index 0000000..2aa7205
--- /dev/null
+++ b/examples/demo/postcss.config.js
@@ -0,0 +1,6 @@
+export default {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+};
diff --git a/examples/demo/src/App.tsx b/examples/demo/src/App.tsx
new file mode 100644
index 0000000..b3b45b9
--- /dev/null
+++ b/examples/demo/src/App.tsx
@@ -0,0 +1,111 @@
+import { useEffect, useRef, useState } from 'react';
+import {
+ Button,
+ ComposerEditor,
+ type ComposerEditorHandle,
+ type ComposerSavePayload,
+} from '@overlock-studio/composer';
+import '@overlock-studio/composer/styles/editor.css';
+import '@xyflow/react/dist/style.css';
+
+import { demoAdapter } from './adapter';
+import { sampleFiles, sampleHashes, sampleLayout } from './sample';
+
+type Theme = 'light' | 'dark';
+
+export default function App() {
+ const editorRef = useRef(null);
+ const [lastSave, setLastSave] = useState(null);
+ const [showPayload, setShowPayload] = useState(false);
+ const [theme, setTheme] = useState(() =>
+ document.documentElement.classList.contains('dark') ? 'dark' : 'light',
+ );
+
+ useEffect(() => {
+ document.documentElement.classList.toggle('dark', theme === 'dark');
+ localStorage.setItem('composer-demo-theme', theme);
+ }, [theme]);
+
+ const handleSave = (payload: ComposerSavePayload) => {
+ setLastSave(payload);
+ setShowPayload(true);
+ console.log('[composer-demo] onSave payload', payload);
+ };
+
+ return (
+
+
+
+
Composer demo
+
+ Mounts ComposerEditor with a minimal XRD + Composition.
+
+
+
+ editorRef.current?.save()}
+ >
+ Trigger save() via ref
+
+ setShowPayload((v) => !v)}
+ >
+ {showPayload ? 'Hide' : 'Show'} last payload
+
+
+ setTheme((t) => (t === 'dark' ? 'light' : 'dark'))
+ }
+ >
+ {theme === 'dark' ? 'Light' : 'Dark'} mode
+
+
+
+
+
+
+
+
+ {showPayload && (
+
+
+ onSave payload
+ setShowPayload(false)}
+ >
+ close
+
+
+ {lastSave ? (
+
+ {JSON.stringify(lastSave, null, 2)}
+
+ ) : (
+
+ Click save (header icon inside the editor, or the button above)
+ to capture a payload.
+
+ )}
+
+ )}
+
+
+ );
+}
diff --git a/examples/demo/src/adapter.ts b/examples/demo/src/adapter.ts
new file mode 100644
index 0000000..8f8c8cc
--- /dev/null
+++ b/examples/demo/src/adapter.ts
@@ -0,0 +1,79 @@
+import {
+ crossplaneCoreBlockTypes,
+ isCrossplaneCoreUrl,
+ type BlockType,
+ type ConfigurationDB,
+ type CrossplaneProviderDB,
+ type EditorDataAdapter,
+} from '@overlock-studio/composer';
+
+import { sampleDependencies } from './sample';
+
+const providers: CrossplaneProviderDB[] = sampleDependencies
+ .filter((d) => d.kind === 'provider')
+ .map((d, idx) => ({
+ _id: `${idx + 1}`,
+ title: d.package.split('/').pop() ?? d.package,
+ description: `Demo provider entry parsed from crossplane.yaml (${d.package})`,
+ icon: '',
+ family: d.package.split('/').slice(-2, -1)[0] ?? 'provider',
+ familyName: d.package.split('/').slice(-2, -1)[0] ?? undefined,
+ url: d.package,
+ version: d.version.replace(/^[>=<~^ ]+/, '') || undefined,
+ }));
+
+const configuration: ConfigurationDB = {
+ _id: 'composer',
+ name: 'demo-configuration',
+ providers: providers.map((p) => p._id),
+ functions: [],
+ deployId: null,
+};
+
+const fetchFromServer = async (url: string): Promise => {
+ const res = await fetch(
+ `/api/blocktypes?url=${encodeURIComponent(url)}`,
+ );
+ if (!res.ok) {
+ const body = await res.text();
+ throw new Error(
+ `/api/blocktypes ${res.status}: ${body || res.statusText}`,
+ );
+ }
+ return (await res.json()) as BlockType[];
+};
+
+export const demoAdapter: EditorDataAdapter = {
+ getBlocks: async () => [],
+ updateBlocks: async () => true,
+ getBlockTypes: async (url) => {
+ if (isCrossplaneCoreUrl(url)) {
+ return crossplaneCoreBlockTypes;
+ }
+ try {
+ return await fetchFromServer(url);
+ } catch (err) {
+ console.warn(`[composer-demo] getBlockTypes(${url}) failed:`, err);
+ return [];
+ }
+ },
+ getConfiguration: async (id) =>
+ id === configuration._id ? configuration : null,
+ getTemplate: async () => null,
+ listCrossplaneProviders: async () => ({
+ crossplaneProviders: providers,
+ totalCount: providers.length,
+ }),
+ getConfigurationData: async () => ({
+ compositions: [],
+ xrdBlockType: [],
+ providerUrls: providers.map((p) =>
+ p.version ? `${p.url}:${p.version}` : p.url,
+ ),
+ functionUrls: [],
+ }),
+ createConfiguration: async () => configuration._id,
+ updateConfiguration: async () => undefined,
+ createProvidersFromUrls: async (urls) => urls,
+ createFunctionsFromUrls: async (urls) => urls,
+};
diff --git a/examples/demo/src/index.css b/examples/demo/src/index.css
new file mode 100644
index 0000000..989a1b0
--- /dev/null
+++ b/examples/demo/src/index.css
@@ -0,0 +1,78 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ :root {
+ --background: 0 0% 100%;
+ --foreground: 240 10% 3.9%;
+ --card: 0 0% 100%;
+ --card-foreground: 240 10% 3.9%;
+ --popover: 0 0% 100%;
+ --popover-foreground: 240 10% 3.9%;
+ --primary: 240 5.9% 10%;
+ --primary-foreground: 0 0% 98%;
+ --secondary: 240 4.8% 95.9%;
+ --secondary-foreground: 240 5.9% 10%;
+ --muted: 240 4.8% 95.9%;
+ --muted-foreground: 240 3.8% 46.1%;
+ --accent: 240 4.8% 95.9%;
+ --accent-foreground: 240 5.9% 10%;
+ --destructive: 0 84.2% 60.2%;
+ --destructive-foreground: 0 0% 98%;
+ --border: 240 5.9% 90%;
+ --input: 240 5.9% 90%;
+ --ring: 240 5.9% 10%;
+ --radius: 0.5rem;
+
+ --sidebar-background: 0 0% 98%;
+ --sidebar-foreground: 240 5.3% 26.1%;
+ --sidebar-primary: 240 5.9% 10%;
+ --sidebar-primary-foreground: 0 0% 98%;
+ --sidebar-accent: 240 4.8% 95.9%;
+ --sidebar-accent-foreground: 240 5.9% 10%;
+ --sidebar-border: 220 13% 91%;
+ --sidebar-ring: 217.2 91.2% 59.8%;
+ }
+
+ .dark {
+ --background: 240 10% 3.9%;
+ --foreground: 0 0% 98%;
+ --card: 240 10% 5.9%;
+ --card-foreground: 0 0% 98%;
+ --popover: 240 10% 5.9%;
+ --popover-foreground: 0 0% 98%;
+ --primary: 0 0% 98%;
+ --primary-foreground: 240 5.9% 10%;
+ --secondary: 240 3.7% 15.9%;
+ --secondary-foreground: 0 0% 98%;
+ --muted: 240 3.7% 15.9%;
+ --muted-foreground: 240 5% 64.9%;
+ --accent: 240 3.7% 15.9%;
+ --accent-foreground: 0 0% 98%;
+ --destructive: 0 62.8% 30.6%;
+ --destructive-foreground: 0 0% 98%;
+ --border: 240 3.7% 15.9%;
+ --input: 240 3.7% 15.9%;
+ --ring: 240 4.9% 83.9%;
+
+ --sidebar-background: 240 5.9% 10%;
+ --sidebar-foreground: 240 4.8% 95.9%;
+ --sidebar-primary: 224.3 76.3% 48%;
+ --sidebar-primary-foreground: 0 0% 100%;
+ --sidebar-accent: 240 3.7% 15.9%;
+ --sidebar-accent-foreground: 240 4.8% 95.9%;
+ --sidebar-border: 240 3.7% 15.9%;
+ --sidebar-ring: 217.2 91.2% 59.8%;
+ }
+
+ html,
+ body,
+ #root {
+ height: 100%;
+ }
+
+ body {
+ @apply bg-background text-foreground;
+ }
+}
diff --git a/examples/demo/src/main.tsx b/examples/demo/src/main.tsx
new file mode 100644
index 0000000..3abae10
--- /dev/null
+++ b/examples/demo/src/main.tsx
@@ -0,0 +1,19 @@
+import { StrictMode } from 'react';
+import { createRoot } from 'react-dom/client';
+import App from './App';
+import './index.css';
+
+const rootEl = document.getElementById('root');
+if (!rootEl) {
+ throw new Error('Missing #root element');
+}
+
+const stored = localStorage.getItem('composer-demo-theme');
+const initialTheme = stored === 'light' ? 'light' : 'dark';
+document.documentElement.classList.toggle('dark', initialTheme === 'dark');
+
+createRoot(rootEl).render(
+
+
+ ,
+);
diff --git a/examples/demo/src/sample.ts b/examples/demo/src/sample.ts
new file mode 100644
index 0000000..3386754
--- /dev/null
+++ b/examples/demo/src/sample.ts
@@ -0,0 +1,29 @@
+import {
+ parseCrossplaneDependencies,
+ type CrossplaneFile,
+ type LayoutByComposition,
+ type PackageDependency,
+} from '@overlock-studio/composer';
+
+import crossplaneYaml from './samples/crossplane.yaml?raw';
+import xrdYaml from './samples/xrd.yaml?raw';
+import compositionYaml from './samples/composition.yaml?raw';
+import layoutJson from './samples/layout.json';
+
+export const sampleFiles: CrossplaneFile[] = [
+ { name: 'crossplane.yaml', content: crossplaneYaml },
+ { name: 'xrd.yaml', content: xrdYaml },
+ { name: 'composition.yaml', content: compositionYaml },
+];
+
+export const sampleLayout: LayoutByComposition =
+ layoutJson as LayoutByComposition;
+
+export const sampleHashes: Record = {
+ 'crossplane.yaml': 'h-crossplane-1',
+ 'xrd.yaml': 'h-xrd-1',
+ 'composition.yaml': 'h-composition-1',
+};
+
+export const sampleDependencies: PackageDependency[] =
+ parseCrossplaneDependencies(crossplaneYaml);
diff --git a/examples/demo/src/samples/composition.yaml b/examples/demo/src/samples/composition.yaml
new file mode 100644
index 0000000..46075bb
--- /dev/null
+++ b/examples/demo/src/samples/composition.yaml
@@ -0,0 +1,23 @@
+apiVersion: apiextensions.crossplane.io/v1
+kind: Composition
+metadata:
+ name: demo-app-composition
+spec:
+ compositeTypeRef:
+ apiVersion: demo.example.org/v1alpha1
+ kind: XDemoApp
+ resources:
+ - name: nop-resource
+ base:
+ apiVersion: nop.crossplane.io/v1alpha1
+ kind: NopResource
+ spec:
+ forProvider:
+ conditionAfter:
+ - conditionType: Ready
+ conditionStatus: "True"
+ time: 5s
+ patches:
+ - type: FromCompositeFieldPath
+ fromFieldPath: spec.size
+ toFieldPath: spec.forProvider.fields.size
diff --git a/examples/demo/src/samples/crossplane.yaml b/examples/demo/src/samples/crossplane.yaml
new file mode 100644
index 0000000..9667d67
--- /dev/null
+++ b/examples/demo/src/samples/crossplane.yaml
@@ -0,0 +1,12 @@
+apiVersion: meta.pkg.crossplane.io/v1
+kind: Configuration
+metadata:
+ name: demo-configuration
+spec:
+ crossplane:
+ version: ">=v1.14.0"
+ dependsOn:
+ - provider: xpkg.upbound.io/crossplane-contrib/provider-nop
+ version: ">=v0.4.0"
+ - provider: xpkg.upbound.io/upbound/provider-family-gcp
+ version: ">=v2.5.3"
diff --git a/examples/demo/src/samples/layout.json b/examples/demo/src/samples/layout.json
new file mode 100644
index 0000000..10d447c
--- /dev/null
+++ b/examples/demo/src/samples/layout.json
@@ -0,0 +1,6 @@
+{
+ "demo-app-composition": {
+ "_self": { "x": 80, "y": 80, "width": 480, "height": 360 },
+ "nop-resource": { "x": 40, "y": 80 }
+ }
+}
diff --git a/examples/demo/src/samples/xrd.yaml b/examples/demo/src/samples/xrd.yaml
new file mode 100644
index 0000000..ce818a0
--- /dev/null
+++ b/examples/demo/src/samples/xrd.yaml
@@ -0,0 +1,28 @@
+apiVersion: apiextensions.crossplane.io/v1
+kind: CompositeResourceDefinition
+metadata:
+ name: xdemoapps.demo.example.org
+spec:
+ group: demo.example.org
+ names:
+ kind: XDemoApp
+ plural: xdemoapps
+ claimNames:
+ kind: DemoApp
+ plural: demoapps
+ versions:
+ - name: v1alpha1
+ served: true
+ referenceable: true
+ schema:
+ openAPIV3Schema:
+ type: object
+ properties:
+ spec:
+ type: object
+ properties:
+ size:
+ type: string
+ description: t-shirt size of the app
+ required:
+ - size
diff --git a/examples/demo/src/vite-env.d.ts b/examples/demo/src/vite-env.d.ts
new file mode 100644
index 0000000..8e9fc56
--- /dev/null
+++ b/examples/demo/src/vite-env.d.ts
@@ -0,0 +1,6 @@
+///
+
+declare module '*.yaml?raw' {
+ const content: string;
+ export default content;
+}
diff --git a/examples/demo/tailwind.config.ts b/examples/demo/tailwind.config.ts
new file mode 100644
index 0000000..7554d20
--- /dev/null
+++ b/examples/demo/tailwind.config.ts
@@ -0,0 +1,67 @@
+import type { Config } from 'tailwindcss';
+
+const config: Config = {
+ darkMode: ['class'],
+ content: [
+ './index.html',
+ './src/**/*.{ts,tsx}',
+ '../../src/**/*.{ts,tsx}',
+ ],
+ theme: {
+ extend: {
+ colors: {
+ border: 'hsl(var(--border))',
+ input: 'hsl(var(--input))',
+ ring: 'hsl(var(--ring))',
+ background: 'hsl(var(--background))',
+ foreground: 'hsl(var(--foreground))',
+ primary: {
+ DEFAULT: 'hsl(var(--primary))',
+ foreground: 'hsl(var(--primary-foreground))',
+ },
+ secondary: {
+ DEFAULT: 'hsl(var(--secondary))',
+ foreground: 'hsl(var(--secondary-foreground))',
+ },
+ destructive: {
+ DEFAULT: 'hsl(var(--destructive))',
+ foreground: 'hsl(var(--destructive-foreground))',
+ },
+ muted: {
+ DEFAULT: 'hsl(var(--muted))',
+ foreground: 'hsl(var(--muted-foreground))',
+ },
+ accent: {
+ DEFAULT: 'hsl(var(--accent))',
+ foreground: 'hsl(var(--accent-foreground))',
+ },
+ popover: {
+ DEFAULT: 'hsl(var(--popover))',
+ foreground: 'hsl(var(--popover-foreground))',
+ },
+ card: {
+ DEFAULT: 'hsl(var(--card))',
+ foreground: 'hsl(var(--card-foreground))',
+ },
+ sidebar: {
+ DEFAULT: 'hsl(var(--sidebar-background))',
+ foreground: 'hsl(var(--sidebar-foreground))',
+ primary: 'hsl(var(--sidebar-primary))',
+ 'primary-foreground': 'hsl(var(--sidebar-primary-foreground))',
+ accent: 'hsl(var(--sidebar-accent))',
+ 'accent-foreground': 'hsl(var(--sidebar-accent-foreground))',
+ border: 'hsl(var(--sidebar-border))',
+ ring: 'hsl(var(--sidebar-ring))',
+ },
+ },
+ borderRadius: {
+ lg: 'var(--radius)',
+ md: 'calc(var(--radius) - 2px)',
+ sm: 'calc(var(--radius) - 4px)',
+ },
+ },
+ },
+ plugins: [],
+};
+
+export default config;
diff --git a/examples/demo/tsconfig.json b/examples/demo/tsconfig.json
new file mode 100644
index 0000000..4c13859
--- /dev/null
+++ b/examples/demo/tsconfig.json
@@ -0,0 +1,25 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "jsx": "react-jsx",
+ "strict": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "allowImportingTsExtensions": false,
+ "baseUrl": ".",
+ "paths": {
+ "@overlock-studio/composer": ["../../src/index.ts"],
+ "@overlock-studio/composer/styles/editor.css": [
+ "../../src/styles/editor.css"
+ ],
+ "@/*": ["../../src/*"]
+ }
+ },
+ "include": ["src", "vite.config.ts"]
+}
diff --git a/examples/demo/vite.config.ts b/examples/demo/vite.config.ts
new file mode 100644
index 0000000..5af653a
--- /dev/null
+++ b/examples/demo/vite.config.ts
@@ -0,0 +1,64 @@
+import { defineConfig, type Plugin } from 'vite';
+import react from '@vitejs/plugin-react';
+import path from 'node:path';
+
+const composerSrc = path.resolve(__dirname, '../../src');
+
+// Server-side OCI fetch endpoint. The library's fetchBlockTypes uses Node
+// modules (zlib, tar-stream), so it can't run in the browser. We expose it
+// here as /api/blocktypes?url=... so the demo's adapter can hit it.
+function blocksApi(): Plugin {
+ return {
+ name: 'composer-demo-blocks-api',
+ configureServer(server) {
+ server.middlewares.use('/api/blocktypes', async (req, res) => {
+ const url = new URL(req.url ?? '', 'http://localhost');
+ const image = url.searchParams.get('url');
+ if (!image) {
+ res.statusCode = 400;
+ res.end(JSON.stringify({ error: 'missing url query param' }));
+ return;
+ }
+ try {
+ const { fetchBlockTypes } = await server.ssrLoadModule(
+ path.join(composerSrc, 'oci/client.ts'),
+ );
+ const blockTypes = await fetchBlockTypes(image);
+ res.setHeader('content-type', 'application/json');
+ res.end(JSON.stringify(blockTypes));
+ } catch (err) {
+ console.error('[composer-demo] /api/blocktypes failed', err);
+ res.statusCode = 500;
+ res.end(
+ JSON.stringify({
+ error: err instanceof Error ? err.message : String(err),
+ }),
+ );
+ }
+ });
+ },
+ };
+}
+
+export default defineConfig({
+ plugins: [blocksApi(), react()],
+ resolve: {
+ alias: {
+ '@overlock-studio/composer/styles/editor.css': path.join(
+ composerSrc,
+ 'styles/editor.css',
+ ),
+ '@overlock-studio/composer/lib/parser': path.join(
+ composerSrc,
+ 'lib/parser.ts',
+ ),
+ '@overlock-studio/composer': path.join(composerSrc, 'index.ts'),
+ '@': composerSrc,
+ },
+ dedupe: ['react', 'react-dom', '@xyflow/react'],
+ },
+ server: {
+ port: 5173,
+ open: true,
+ },
+});
diff --git a/package.json b/package.json
index da76812..97220bf 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,9 @@
"dist",
"src"
],
+ "workspaces": [
+ "examples/*"
+ ],
"sideEffects": [
"*.css"
],
@@ -43,7 +46,9 @@
"clean": "rm -rf dist",
"typecheck": "tsc --noEmit",
"lint": "eslint .",
- "lint:fix": "eslint . --fix"
+ "lint:fix": "eslint . --fix",
+ "demo": "yarn workspace @overlock-studio/composer-demo dev",
+ "demo:build": "yarn workspace @overlock-studio/composer-demo build"
},
"peerDependencies": {
"@xyflow/react": "^12.10.0",
diff --git a/src/components/Editor/ComposerEditor/ComposerEditor.tsx b/src/components/Editor/ComposerEditor/ComposerEditor.tsx
index 94a1339..7162447 100644
--- a/src/components/Editor/ComposerEditor/ComposerEditor.tsx
+++ b/src/components/Editor/ComposerEditor/ComposerEditor.tsx
@@ -253,7 +253,7 @@ function ComposerEditorBody({
return (
-
+
{
+ const [mode, setMode] = useState<'light' | 'dark'>(() =>
+ typeof document !== 'undefined' &&
+ document.documentElement.classList.contains('dark')
+ ? 'dark'
+ : 'light',
+ );
+ useEffect(() => {
+ if (typeof document === 'undefined') return;
+ const root = document.documentElement;
+ const update = (): void =>
+ setMode(root.classList.contains('dark') ? 'dark' : 'light');
+ update();
+ const observer = new MutationObserver(update);
+ observer.observe(root, { attributes: true, attributeFilter: ['class'] });
+ return () => observer.disconnect();
+ }, []);
+ return mode;
+};
+
const sanitizeBaseName = (s: string): string =>
s.replace(/[^a-z0-9-]/gi, '').toLowerCase() || 'block';
@@ -44,6 +64,7 @@ const nextUniqueNodeName = (
export const EditorArea = () => {
const reactFlowRef = useRef(null);
+ const colorMode = useDocumentColorMode();
const {
selectedBlockType,
nodes,
@@ -355,7 +376,7 @@ export const EditorArea = () => {
<>
{!blocksLoading ? (
":
+"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin":
version: 2.3.3
resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1"
dependencies:
@@ -2891,6 +3820,13 @@ __metadata:
languageName: node
linkType: hard
+"gensync@npm:^1.0.0-beta.2":
+ version: 1.0.0-beta.2
+ resolution: "gensync@npm:1.0.0-beta.2"
+ checksum: 10c0/782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8
+ languageName: node
+ linkType: hard
+
"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0":
version: 1.3.1
resolution: "get-intrinsic@npm:1.3.1"
@@ -3411,6 +4347,15 @@ __metadata:
languageName: node
linkType: hard
+"jiti@npm:^1.21.7":
+ version: 1.21.7
+ resolution: "jiti@npm:1.21.7"
+ bin:
+ jiti: bin/jiti.js
+ checksum: 10c0/77b61989c758ff32407cdae8ddc77f85e18e1a13fc4977110dbd2e05fc761842f5f71bce684d9a01316e1c4263971315a111385759951080bbfe17cbb5de8f7a
+ languageName: node
+ linkType: hard
+
"js-cookie@npm:^2.2.1":
version: 2.2.1
resolution: "js-cookie@npm:2.2.1"
@@ -3418,7 +4363,7 @@ __metadata:
languageName: node
linkType: hard
-"js-tokens@npm:^3.0.0 || ^4.0.0":
+"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0":
version: 4.0.0
resolution: "js-tokens@npm:4.0.0"
checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed
@@ -3447,6 +4392,15 @@ __metadata:
languageName: node
linkType: hard
+"jsesc@npm:^3.0.2":
+ version: 3.1.0
+ resolution: "jsesc@npm:3.1.0"
+ bin:
+ jsesc: bin/jsesc
+ checksum: 10c0/531779df5ec94f47e462da26b4cbf05eb88a83d9f08aac2ba04206508fc598527a153d08bd462bae82fc78b3eaa1a908e1a4a79f886e9238641c4cdefaf118b1
+ languageName: node
+ linkType: hard
+
"json-buffer@npm:3.0.1":
version: 3.0.1
resolution: "json-buffer@npm:3.0.1"
@@ -3468,6 +4422,15 @@ __metadata:
languageName: node
linkType: hard
+"json5@npm:^2.2.3":
+ version: 2.2.3
+ resolution: "json5@npm:2.2.3"
+ bin:
+ json5: lib/cli.js
+ checksum: 10c0/5a04eed94810fa55c5ea138b2f7a5c12b97c3750bc63d11e511dcecbfef758003861522a070c2272764ee0f4e3e323862f386945aeb5b85b87ee43f084ba586c
+ languageName: node
+ linkType: hard
+
"jsx-ast-utils@npm:^2.4.1 || ^3.0.0":
version: 3.3.5
resolution: "jsx-ast-utils@npm:3.3.5"
@@ -3499,6 +4462,20 @@ __metadata:
languageName: node
linkType: hard
+"lilconfig@npm:^3.1.1, lilconfig@npm:^3.1.3":
+ version: 3.1.3
+ resolution: "lilconfig@npm:3.1.3"
+ checksum: 10c0/f5604e7240c5c275743561442fbc5abf2a84ad94da0f5adc71d25e31fa8483048de3dcedcb7a44112a942fed305fd75841cdf6c9681c7f640c63f1049e9a5dcc
+ languageName: node
+ linkType: hard
+
+"lines-and-columns@npm:^1.1.6":
+ version: 1.2.4
+ resolution: "lines-and-columns@npm:1.2.4"
+ checksum: 10c0/3da6ee62d4cd9f03f5dc90b4df2540fb85b352081bee77fe4bbcd12c9000ead7f35e0a38b8d09a9bb99b13223446dd8689ff3c4959807620726d788701a83d2d
+ languageName: node
+ linkType: hard
+
"locate-path@npm:^6.0.0":
version: 6.0.0
resolution: "locate-path@npm:6.0.0"
@@ -3526,6 +4503,15 @@ __metadata:
languageName: node
linkType: hard
+"lru-cache@npm:^5.1.1":
+ version: 5.1.1
+ resolution: "lru-cache@npm:5.1.1"
+ dependencies:
+ yallist: "npm:^3.0.2"
+ checksum: 10c0/89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482
+ languageName: node
+ linkType: hard
+
"lucide-react@npm:^0.468.0":
version: 0.468.0
resolution: "lucide-react@npm:0.468.0"
@@ -3614,6 +4600,17 @@ __metadata:
languageName: node
linkType: hard
+"mz@npm:^2.7.0":
+ version: 2.7.0
+ resolution: "mz@npm:2.7.0"
+ dependencies:
+ any-promise: "npm:^1.0.0"
+ object-assign: "npm:^4.0.1"
+ thenify-all: "npm:^1.0.0"
+ checksum: 10c0/103114e93f87362f0b56ab5b2e7245051ad0276b646e3902c98397d18bb8f4a77f2ea4a2c9d3ad516034ea3a56553b60d3f5f78220001ca4c404bd711bd0af39
+ languageName: node
+ linkType: hard
+
"nano-css@npm:^5.6.2":
version: 5.6.2
resolution: "nano-css@npm:5.6.2"
@@ -3633,6 +4630,15 @@ __metadata:
languageName: node
linkType: hard
+"nanoid@npm:^3.3.11":
+ version: 3.3.12
+ resolution: "nanoid@npm:3.3.12"
+ bin:
+ nanoid: bin/nanoid.cjs
+ checksum: 10c0/ba142b7b39e11e80c16dd74b0365d407880c87c1cf7e1480956981ae940ee36060fa5b6f092cd1e315184dd19244c657bd017d03327bd3c62247d691c5e8edfb
+ languageName: node
+ linkType: hard
+
"natural-compare@npm:^1.4.0":
version: 1.4.0
resolution: "natural-compare@npm:1.4.0"
@@ -3672,6 +4678,13 @@ __metadata:
languageName: node
linkType: hard
+"node-releases@npm:^2.0.36":
+ version: 2.0.44
+ resolution: "node-releases@npm:2.0.44"
+ checksum: 10c0/004337ee9c0c455e81fdfc85cc8a585e89932d28338cd35a4ddba21ef2b68ff20cf06097544e7859c1868579d8529ed230802b127be5357c153e267079e8d851
+ languageName: node
+ linkType: hard
+
"nopt@npm:^9.0.0":
version: 9.0.0
resolution: "nopt@npm:9.0.0"
@@ -3690,13 +4703,20 @@ __metadata:
languageName: node
linkType: hard
-"object-assign@npm:^4.1.1":
+"object-assign@npm:^4.0.1, object-assign@npm:^4.1.1":
version: 4.1.1
resolution: "object-assign@npm:4.1.1"
checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414
languageName: node
linkType: hard
+"object-hash@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "object-hash@npm:3.0.0"
+ checksum: 10c0/a06844537107b960c1c8b96cd2ac8592a265186bfa0f6ccafe0d34eabdb526f6fa81da1f37c43df7ed13b12a4ae3457a16071603bcd39d8beddb5f08c37b0f47
+ languageName: node
+ linkType: hard
+
"object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4":
version: 1.13.4
resolution: "object-inspect@npm:1.13.4"
@@ -3848,6 +4868,13 @@ __metadata:
languageName: node
linkType: hard
+"picocolors@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "picocolors@npm:1.1.1"
+ checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58
+ languageName: node
+ linkType: hard
+
"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.3.1":
version: 2.3.2
resolution: "picomatch@npm:2.3.2"
@@ -3855,13 +4882,20 @@ __metadata:
languageName: node
linkType: hard
-"picomatch@npm:^4.0.4":
+"picomatch@npm:^4.0.2, picomatch@npm:^4.0.4":
version: 4.0.4
resolution: "picomatch@npm:4.0.4"
checksum: 10c0/e2c6023372cc7b5764719a5ffb9da0f8e781212fa7ca4bd0562db929df8e117460f00dff3cb7509dacfc06b86de924b247f504d0ce1806a37fac4633081466b0
languageName: node
linkType: hard
+"pify@npm:^2.3.0":
+ version: 2.3.0
+ resolution: "pify@npm:2.3.0"
+ checksum: 10c0/551ff8ab830b1052633f59cb8adc9ae8407a436e06b4a9718bcb27dc5844b83d535c3a8512b388b6062af65a98c49bdc0dd523d8b2617b188f7c8fee457158dc
+ languageName: node
+ linkType: hard
+
"pino-abstract-transport@npm:^2.0.0":
version: 2.0.0
resolution: "pino-abstract-transport@npm:2.0.0"
@@ -3899,6 +4933,13 @@ __metadata:
languageName: node
linkType: hard
+"pirates@npm:^4.0.1":
+ version: 4.0.7
+ resolution: "pirates@npm:4.0.7"
+ checksum: 10c0/a51f108dd811beb779d58a76864bbd49e239fa40c7984cd11596c75a121a8cc789f1c8971d8bb15f0dbf9d48b76c05bb62fcbce840f89b688c0fa64b37e8478a
+ languageName: node
+ linkType: hard
+
"plimit-lit@npm:^1.2.6":
version: 1.6.1
resolution: "plimit-lit@npm:1.6.1"
@@ -3915,6 +4956,92 @@ __metadata:
languageName: node
linkType: hard
+"postcss-import@npm:^15.1.0":
+ version: 15.1.0
+ resolution: "postcss-import@npm:15.1.0"
+ dependencies:
+ postcss-value-parser: "npm:^4.0.0"
+ read-cache: "npm:^1.0.0"
+ resolve: "npm:^1.1.7"
+ peerDependencies:
+ postcss: ^8.0.0
+ checksum: 10c0/518aee5c83ea6940e890b0be675a2588db68b2582319f48c3b4e06535a50ea6ee45f7e63e4309f8754473245c47a0372632378d1d73d901310f295a92f26f17b
+ languageName: node
+ linkType: hard
+
+"postcss-js@npm:^4.0.1":
+ version: 4.1.0
+ resolution: "postcss-js@npm:4.1.0"
+ dependencies:
+ camelcase-css: "npm:^2.0.1"
+ peerDependencies:
+ postcss: ^8.4.21
+ checksum: 10c0/a3cf6e725f3e9ecd7209732f8844a0063a1380b718ccbcf93832b6ec2cd7e63ff70dd2fed49eb2483c7482296860a0f7badd3115b5d0fa05ea648eb6d9dfc9c6
+ languageName: node
+ linkType: hard
+
+"postcss-load-config@npm:^4.0.2 || ^5.0 || ^6.0":
+ version: 6.0.1
+ resolution: "postcss-load-config@npm:6.0.1"
+ dependencies:
+ lilconfig: "npm:^3.1.1"
+ peerDependencies:
+ jiti: ">=1.21.0"
+ postcss: ">=8.0.9"
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+ postcss:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+ checksum: 10c0/74173a58816dac84e44853f7afbd283f4ef13ca0b6baeba27701214beec33f9e309b128f8102e2b173e8d45ecba45d279a9be94b46bf48d219626aa9b5730848
+ languageName: node
+ linkType: hard
+
+"postcss-nested@npm:^6.2.0":
+ version: 6.2.0
+ resolution: "postcss-nested@npm:6.2.0"
+ dependencies:
+ postcss-selector-parser: "npm:^6.1.1"
+ peerDependencies:
+ postcss: ^8.2.14
+ checksum: 10c0/7f9c3f2d764191a39364cbdcec350f26a312431a569c9ef17408021424726b0d67995ff5288405e3724bb7152a4c92f73c027e580ec91e798800ed3c52e2bc6e
+ languageName: node
+ linkType: hard
+
+"postcss-selector-parser@npm:^6.1.1, postcss-selector-parser@npm:^6.1.2":
+ version: 6.1.2
+ resolution: "postcss-selector-parser@npm:6.1.2"
+ dependencies:
+ cssesc: "npm:^3.0.0"
+ util-deprecate: "npm:^1.0.2"
+ checksum: 10c0/523196a6bd8cf660bdf537ad95abd79e546d54180f9afb165a4ab3e651ac705d0f8b8ce6b3164fb9e3279ce482c5f751a69eb2d3a1e8eb0fd5e82294fb3ef13e
+ languageName: node
+ linkType: hard
+
+"postcss-value-parser@npm:^4.0.0, postcss-value-parser@npm:^4.2.0":
+ version: 4.2.0
+ resolution: "postcss-value-parser@npm:4.2.0"
+ checksum: 10c0/f4142a4f56565f77c1831168e04e3effd9ffcc5aebaf0f538eee4b2d465adfd4b85a44257bb48418202a63806a7da7fe9f56c330aebb3cac898e46b4cbf49161
+ languageName: node
+ linkType: hard
+
+"postcss@npm:^8.4.47, postcss@npm:^8.4.49, postcss@npm:^8.5.3":
+ version: 8.5.14
+ resolution: "postcss@npm:8.5.14"
+ dependencies:
+ nanoid: "npm:^3.3.11"
+ picocolors: "npm:^1.1.1"
+ source-map-js: "npm:^1.2.1"
+ checksum: 10c0/48138207cf5ef5581be1bfe2cb65ccfe0ac75e43888ba045afc8ed6043d7b56aeb3b9a9fe5b353ff554be943cd0cc15d826ccb991525159175971e5ee8ab0237
+ languageName: node
+ linkType: hard
+
"prelude-ls@npm:^1.2.1":
version: 1.2.1
resolution: "prelude-ls@npm:1.2.1"
@@ -3986,6 +5113,17 @@ __metadata:
languageName: node
linkType: hard
+"react-dom@npm:^19.0.0":
+ version: 19.2.6
+ resolution: "react-dom@npm:19.2.6"
+ dependencies:
+ scheduler: "npm:^0.27.0"
+ peerDependencies:
+ react: ^19.2.6
+ checksum: 10c0/dbf2aef67857c03a612bc9316a4562e5066f43fa04bf28f7f0734963fc1350da2c9f8eb973930655453281079f30cc8222bab383dbec4b5097084e2c081e3334
+ languageName: node
+ linkType: hard
+
"react-hook-form@npm:^7.54.2":
version: 7.75.0
resolution: "react-hook-form@npm:7.75.0"
@@ -4002,6 +5140,13 @@ __metadata:
languageName: node
linkType: hard
+"react-refresh@npm:^0.17.0":
+ version: 0.17.0
+ resolution: "react-refresh@npm:0.17.0"
+ checksum: 10c0/002cba940384c9930008c0bce26cac97a9d5682bc623112c2268ba0c155127d9c178a9a5cc2212d560088d60dfd503edd808669a25f9b377f316a32361d0b23c
+ languageName: node
+ linkType: hard
+
"react-remove-scroll-bar@npm:^2.3.7":
version: 2.3.8
resolution: "react-remove-scroll-bar@npm:2.3.8"
@@ -4095,6 +5240,22 @@ __metadata:
languageName: node
linkType: hard
+"react@npm:^19.0.0":
+ version: 19.2.6
+ resolution: "react@npm:19.2.6"
+ checksum: 10c0/66afde33b9a9ee87b1e1cae39d8e7e040d1262e719524fd70660c4d4ce79929c532ac19fc3df5a911edaf02768fdf2c49de4ede1ba99bc6aad72796e0e26e798
+ languageName: node
+ linkType: hard
+
+"read-cache@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "read-cache@npm:1.0.0"
+ dependencies:
+ pify: "npm:^2.3.0"
+ checksum: 10c0/90cb2750213c7dd7c80cb420654344a311fdec12944e81eb912cd82f1bc92aea21885fa6ce442e3336d9fccd663b8a7a19c46d9698e6ca55620848ab932da814
+ languageName: node
+ linkType: hard
+
"readdirp@npm:~3.6.0":
version: 3.6.0
resolution: "readdirp@npm:3.6.0"
@@ -4162,6 +5323,20 @@ __metadata:
languageName: node
linkType: hard
+"resolve@npm:^1.1.7, resolve@npm:^1.22.8":
+ version: 1.22.12
+ resolution: "resolve@npm:1.22.12"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ is-core-module: "npm:^2.16.1"
+ path-parse: "npm:^1.0.7"
+ supports-preserve-symlinks-flag: "npm:^1.0.0"
+ bin:
+ resolve: bin/resolve
+ checksum: 10c0/b16dc9b537c02e8c3388f7d3dcff9741d3071625f9a97ac1c885f2b0ca51e78df22328fb6d6ef214dd9101fb7cfc19aa2836fe3410402a94f3f7b8639c7149bf
+ languageName: node
+ linkType: hard
+
"resolve@npm:^2.0.0-next.5":
version: 2.0.0-next.6
resolution: "resolve@npm:2.0.0-next.6"
@@ -4178,6 +5353,20 @@ __metadata:
languageName: node
linkType: hard
+"resolve@patch:resolve@npm%3A^1.1.7#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin":
+ version: 1.22.12
+ resolution: "resolve@patch:resolve@npm%3A1.22.12#optional!builtin::version=1.22.12&hash=c3c19d"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ is-core-module: "npm:^2.16.1"
+ path-parse: "npm:^1.0.7"
+ supports-preserve-symlinks-flag: "npm:^1.0.0"
+ bin:
+ resolve: bin/resolve
+ checksum: 10c0/fc6519984ae1f894d877c0060ba8b1f5ba3bc0e85a02f74e141929c118c23d74d9735619a9cc2965397387e514884245c65d72a40731dcb6cfc84c7bcdc8321e
+ languageName: node
+ linkType: hard
+
"resolve@patch:resolve@npm%3A^2.0.0-next.5#optional!builtin":
version: 2.0.0-next.6
resolution: "resolve@patch:resolve@npm%3A2.0.0-next.6#optional!builtin::version=2.0.0-next.6&hash=c3c19d"
@@ -4201,6 +5390,96 @@ __metadata:
languageName: node
linkType: hard
+"rollup@npm:^4.34.9":
+ version: 4.60.4
+ resolution: "rollup@npm:4.60.4"
+ dependencies:
+ "@rollup/rollup-android-arm-eabi": "npm:4.60.4"
+ "@rollup/rollup-android-arm64": "npm:4.60.4"
+ "@rollup/rollup-darwin-arm64": "npm:4.60.4"
+ "@rollup/rollup-darwin-x64": "npm:4.60.4"
+ "@rollup/rollup-freebsd-arm64": "npm:4.60.4"
+ "@rollup/rollup-freebsd-x64": "npm:4.60.4"
+ "@rollup/rollup-linux-arm-gnueabihf": "npm:4.60.4"
+ "@rollup/rollup-linux-arm-musleabihf": "npm:4.60.4"
+ "@rollup/rollup-linux-arm64-gnu": "npm:4.60.4"
+ "@rollup/rollup-linux-arm64-musl": "npm:4.60.4"
+ "@rollup/rollup-linux-loong64-gnu": "npm:4.60.4"
+ "@rollup/rollup-linux-loong64-musl": "npm:4.60.4"
+ "@rollup/rollup-linux-ppc64-gnu": "npm:4.60.4"
+ "@rollup/rollup-linux-ppc64-musl": "npm:4.60.4"
+ "@rollup/rollup-linux-riscv64-gnu": "npm:4.60.4"
+ "@rollup/rollup-linux-riscv64-musl": "npm:4.60.4"
+ "@rollup/rollup-linux-s390x-gnu": "npm:4.60.4"
+ "@rollup/rollup-linux-x64-gnu": "npm:4.60.4"
+ "@rollup/rollup-linux-x64-musl": "npm:4.60.4"
+ "@rollup/rollup-openbsd-x64": "npm:4.60.4"
+ "@rollup/rollup-openharmony-arm64": "npm:4.60.4"
+ "@rollup/rollup-win32-arm64-msvc": "npm:4.60.4"
+ "@rollup/rollup-win32-ia32-msvc": "npm:4.60.4"
+ "@rollup/rollup-win32-x64-gnu": "npm:4.60.4"
+ "@rollup/rollup-win32-x64-msvc": "npm:4.60.4"
+ "@types/estree": "npm:1.0.8"
+ fsevents: "npm:~2.3.2"
+ dependenciesMeta:
+ "@rollup/rollup-android-arm-eabi":
+ optional: true
+ "@rollup/rollup-android-arm64":
+ optional: true
+ "@rollup/rollup-darwin-arm64":
+ optional: true
+ "@rollup/rollup-darwin-x64":
+ optional: true
+ "@rollup/rollup-freebsd-arm64":
+ optional: true
+ "@rollup/rollup-freebsd-x64":
+ optional: true
+ "@rollup/rollup-linux-arm-gnueabihf":
+ optional: true
+ "@rollup/rollup-linux-arm-musleabihf":
+ optional: true
+ "@rollup/rollup-linux-arm64-gnu":
+ optional: true
+ "@rollup/rollup-linux-arm64-musl":
+ optional: true
+ "@rollup/rollup-linux-loong64-gnu":
+ optional: true
+ "@rollup/rollup-linux-loong64-musl":
+ optional: true
+ "@rollup/rollup-linux-ppc64-gnu":
+ optional: true
+ "@rollup/rollup-linux-ppc64-musl":
+ optional: true
+ "@rollup/rollup-linux-riscv64-gnu":
+ optional: true
+ "@rollup/rollup-linux-riscv64-musl":
+ optional: true
+ "@rollup/rollup-linux-s390x-gnu":
+ optional: true
+ "@rollup/rollup-linux-x64-gnu":
+ optional: true
+ "@rollup/rollup-linux-x64-musl":
+ optional: true
+ "@rollup/rollup-openbsd-x64":
+ optional: true
+ "@rollup/rollup-openharmony-arm64":
+ optional: true
+ "@rollup/rollup-win32-arm64-msvc":
+ optional: true
+ "@rollup/rollup-win32-ia32-msvc":
+ optional: true
+ "@rollup/rollup-win32-x64-gnu":
+ optional: true
+ "@rollup/rollup-win32-x64-msvc":
+ optional: true
+ fsevents:
+ optional: true
+ bin:
+ rollup: dist/bin/rollup
+ checksum: 10c0/2734511579da220408eefb877b51281767d790652cee25da8fcd4936c947e3db14882b5edb1d0d5d5bf60f2a71a58ae7d5f7f46c11e3fdf33182538953886243
+ languageName: node
+ linkType: hard
+
"rtl-css-js@npm:^1.16.1":
version: 1.16.1
resolution: "rtl-css-js@npm:1.16.1"
@@ -4267,6 +5546,13 @@ __metadata:
languageName: node
linkType: hard
+"scheduler@npm:^0.27.0":
+ version: 0.27.0
+ resolution: "scheduler@npm:0.27.0"
+ checksum: 10c0/4f03048cb05a3c8fddc45813052251eca00688f413a3cee236d984a161da28db28ba71bd11e7a3dd02f7af84ab28d39fb311431d3b3772fed557945beb00c452
+ languageName: node
+ linkType: hard
+
"screenfull@npm:^5.1.0":
version: 5.2.0
resolution: "screenfull@npm:5.2.0"
@@ -4416,6 +5702,13 @@ __metadata:
languageName: node
linkType: hard
+"source-map-js@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "source-map-js@npm:1.2.1"
+ checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf
+ languageName: node
+ linkType: hard
+
"source-map@npm:0.5.6":
version: 0.5.6
resolution: "source-map@npm:0.5.6"
@@ -4578,6 +5871,24 @@ __metadata:
languageName: node
linkType: hard
+"sucrase@npm:^3.35.0":
+ version: 3.35.1
+ resolution: "sucrase@npm:3.35.1"
+ dependencies:
+ "@jridgewell/gen-mapping": "npm:^0.3.2"
+ commander: "npm:^4.0.0"
+ lines-and-columns: "npm:^1.1.6"
+ mz: "npm:^2.7.0"
+ pirates: "npm:^4.0.1"
+ tinyglobby: "npm:^0.2.11"
+ ts-interface-checker: "npm:^0.1.9"
+ bin:
+ sucrase: bin/sucrase
+ sucrase-node: bin/sucrase-node
+ checksum: 10c0/6fa22329c261371feb9560630d961ad0d0b9c87dce21ea74557c5f3ffbe5c1ee970ea8bcce9962ae9c90c3c47165ffa7dd41865c7414f5d8ea7a40755d612c5c
+ languageName: node
+ linkType: hard
+
"supports-color@npm:^7.1.0":
version: 7.2.0
resolution: "supports-color@npm:7.2.0"
@@ -4601,6 +5912,39 @@ __metadata:
languageName: node
linkType: hard
+"tailwindcss@npm:^3.4.17":
+ version: 3.4.19
+ resolution: "tailwindcss@npm:3.4.19"
+ dependencies:
+ "@alloc/quick-lru": "npm:^5.2.0"
+ arg: "npm:^5.0.2"
+ chokidar: "npm:^3.6.0"
+ didyoumean: "npm:^1.2.2"
+ dlv: "npm:^1.1.3"
+ fast-glob: "npm:^3.3.2"
+ glob-parent: "npm:^6.0.2"
+ is-glob: "npm:^4.0.3"
+ jiti: "npm:^1.21.7"
+ lilconfig: "npm:^3.1.3"
+ micromatch: "npm:^4.0.8"
+ normalize-path: "npm:^3.0.0"
+ object-hash: "npm:^3.0.0"
+ picocolors: "npm:^1.1.1"
+ postcss: "npm:^8.4.47"
+ postcss-import: "npm:^15.1.0"
+ postcss-js: "npm:^4.0.1"
+ postcss-load-config: "npm:^4.0.2 || ^5.0 || ^6.0"
+ postcss-nested: "npm:^6.2.0"
+ postcss-selector-parser: "npm:^6.1.2"
+ resolve: "npm:^1.22.8"
+ sucrase: "npm:^3.35.0"
+ bin:
+ tailwind: lib/cli.js
+ tailwindcss: lib/cli.js
+ checksum: 10c0/e1063daccb9e5a508b357ec73b0011354204b2366b56496d6f0cc822733a55a0551502cb85856a2257ef9b676d0026616daaaa176d391f3216df57fbd693c581
+ languageName: node
+ linkType: hard
+
"tar-stream@npm:^3.1.7":
version: 3.2.0
resolution: "tar-stream@npm:3.2.0"
@@ -4644,6 +5988,24 @@ __metadata:
languageName: node
linkType: hard
+"thenify-all@npm:^1.0.0":
+ version: 1.6.0
+ resolution: "thenify-all@npm:1.6.0"
+ dependencies:
+ thenify: "npm:>= 3.1.0 < 4"
+ checksum: 10c0/9b896a22735e8122754fe70f1d65f7ee691c1d70b1f116fda04fea103d0f9b356e3676cb789506e3909ae0486a79a476e4914b0f92472c2e093d206aed4b7d6b
+ languageName: node
+ linkType: hard
+
+"thenify@npm:>= 3.1.0 < 4":
+ version: 3.3.1
+ resolution: "thenify@npm:3.3.1"
+ dependencies:
+ any-promise: "npm:^1.0.0"
+ checksum: 10c0/f375aeb2b05c100a456a30bc3ed07ef03a39cbdefe02e0403fb714b8c7e57eeaad1a2f5c4ecfb9ce554ce3db9c2b024eba144843cd9e344566d9fcee73b04767
+ languageName: node
+ linkType: hard
+
"thread-stream@npm:^3.0.0":
version: 3.1.0
resolution: "thread-stream@npm:3.1.0"
@@ -4660,7 +6022,7 @@ __metadata:
languageName: node
linkType: hard
-"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.15":
+"tinyglobby@npm:^0.2.11, tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.13, tinyglobby@npm:^0.2.15":
version: 0.2.16
resolution: "tinyglobby@npm:0.2.16"
dependencies:
@@ -4702,6 +6064,13 @@ __metadata:
languageName: node
linkType: hard
+"ts-interface-checker@npm:^0.1.9":
+ version: 0.1.13
+ resolution: "ts-interface-checker@npm:0.1.13"
+ checksum: 10c0/232509f1b84192d07b81d1e9b9677088e590ac1303436da1e92b296e9be8e31ea042e3e1fd3d29b1742ad2c959e95afe30f63117b8f1bc3a3850070a5142fea7
+ languageName: node
+ linkType: hard
+
"tsc-alias@npm:^1.8.10":
version: 1.8.17
resolution: "tsc-alias@npm:1.8.17"
@@ -4813,6 +6182,16 @@ __metadata:
languageName: node
linkType: hard
+"typescript@npm:^5.6.3":
+ version: 5.9.3
+ resolution: "typescript@npm:5.9.3"
+ bin:
+ tsc: bin/tsc
+ tsserver: bin/tsserver
+ checksum: 10c0/6bd7552ce39f97e711db5aa048f6f9995b53f1c52f7d8667c1abdc1700c68a76a308f579cd309ce6b53646deb4e9a1be7c813a93baaf0a28ccd536a30270e1c5
+ languageName: node
+ linkType: hard
+
"typescript@patch:typescript@npm%3A5.6.3#optional!builtin":
version: 5.6.3
resolution: "typescript@patch:typescript@npm%3A5.6.3#optional!builtin::version=5.6.3&hash=8c6c40"
@@ -4823,6 +6202,16 @@ __metadata:
languageName: node
linkType: hard
+"typescript@patch:typescript@npm%3A^5.6.3#optional!builtin":
+ version: 5.9.3
+ resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin::version=5.9.3&hash=8c6c40"
+ bin:
+ tsc: bin/tsc
+ tsserver: bin/tsserver
+ checksum: 10c0/6f7e53bf0d9702350deeb6f35e08b69cbc8b958c33e0ec77bdc0ad6a6c8e280f3959dcbfde6f5b0848bece57810696489deaaa53d75de3578ff255d168c1efbd
+ languageName: node
+ linkType: hard
+
"unbox-primitive@npm:^1.1.0":
version: 1.1.0
resolution: "unbox-primitive@npm:1.1.0"
@@ -4856,6 +6245,20 @@ __metadata:
languageName: node
linkType: hard
+"update-browserslist-db@npm:^1.2.3":
+ version: 1.2.3
+ resolution: "update-browserslist-db@npm:1.2.3"
+ dependencies:
+ escalade: "npm:^3.2.0"
+ picocolors: "npm:^1.1.1"
+ peerDependencies:
+ browserslist: ">= 4.21.0"
+ bin:
+ update-browserslist-db: cli.js
+ checksum: 10c0/13a00355ea822388f68af57410ce3255941d5fb9b7c49342c4709a07c9f230bbef7f7499ae0ca7e0de532e79a82cc0c4edbd125f1a323a1845bf914efddf8bec
+ languageName: node
+ linkType: hard
+
"uri-js@npm:^4.2.2":
version: 4.4.1
resolution: "uri-js@npm:4.4.1"
@@ -4905,6 +6308,68 @@ __metadata:
languageName: node
linkType: hard
+"util-deprecate@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "util-deprecate@npm:1.0.2"
+ checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942
+ languageName: node
+ linkType: hard
+
+"vite@npm:^6.0.7":
+ version: 6.4.2
+ resolution: "vite@npm:6.4.2"
+ dependencies:
+ esbuild: "npm:^0.25.0"
+ fdir: "npm:^6.4.4"
+ fsevents: "npm:~2.3.3"
+ picomatch: "npm:^4.0.2"
+ postcss: "npm:^8.5.3"
+ rollup: "npm:^4.34.9"
+ tinyglobby: "npm:^0.2.13"
+ peerDependencies:
+ "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0
+ jiti: ">=1.21.0"
+ less: "*"
+ lightningcss: ^1.21.0
+ sass: "*"
+ sass-embedded: "*"
+ stylus: "*"
+ sugarss: "*"
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ dependenciesMeta:
+ fsevents:
+ optional: true
+ peerDependenciesMeta:
+ "@types/node":
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+ bin:
+ vite: bin/vite.js
+ checksum: 10c0/9a62bb4259b4b11b9084c8dc5c25a21c9340d87d83de163d3643f15629d8ac3c2a3a4cda565f1a61e98afc9d78e9cb78eb25d1ae3c302e95d42d13ab61537267
+ languageName: node
+ linkType: hard
+
"which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1":
version: 1.1.1
resolution: "which-boxed-primitive@npm:1.1.1"
@@ -4995,6 +6460,13 @@ __metadata:
languageName: node
linkType: hard
+"yallist@npm:^3.0.2":
+ version: 3.1.1
+ resolution: "yallist@npm:3.1.1"
+ checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1
+ languageName: node
+ linkType: hard
+
"yallist@npm:^5.0.0":
version: 5.0.0
resolution: "yallist@npm:5.0.0"