A powerful SDK for capturing and reproducing React components with their styles, animations, and interactivity. Maestro enables WYSIWYG editing capabilities for React applications with Supabase backend integration.
npm install maestro-client
# or
yarn add maestro-client
- Component Capture: Capture DOM elements with their styles and structure
- Accurate Style Reproduction: Faithfully reproduce components including CSS animations
- Editable Fields: Mark and edit specific content within components
- Supabase Integration: Store and retrieve captured components from Supabase
- React Context API: Simple integration with React applications
First, create a new Supabase project and set up the required tables:
-- Components table for storing captured components
create table public.components (
id uuid not null default uuid_generate_v4() primary key,
site_id text not null,
name text not null,
html text not null,
css text not null,
props jsonb default '{}'::jsonb,
editable_fields jsonb default '[]'::jsonb,
metadata jsonb default '{}'::jsonb,
created_at timestamp with time zone default now(),
updated_at timestamp with time zone default now()
);
-- Site contents table for dynamic content
create table public.site_contents (
id uuid not null default uuid_generate_v4() primary key,
site_id text not null,
content_type text not null,
content_id text not null,
content jsonb not null default '{}'::jsonb,
created_at timestamp with time zone default now(),
updated_at timestamp with time zone default now(),
unique(site_id, content_id)
);
-- Enable RLS and create policies as needed
alter table public.components enable row level security;
alter table public.site_contents enable row level security;
-- Example policies to allow read access
create policy "Allow read access to components"
on public.components for select
to authenticated, anon
using (true);
create policy "Allow read access to site contents"
on public.site_contents for select
to authenticated, anon
using (true);
Create a .env.local
file in your project with:
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
NEXT_PUBLIC_MAESTRO_SITE_ID=your-site-id
NEXT_PUBLIC_MAESTRO_API_KEY=your-api-key
// In your _app.tsx or similar
import { initMaestro } from 'maestro-client';
import 'maestro-client/dist/styles.css'; // Import Maestro styles
// Initialize Maestro once at application startup
initMaestro({
siteId: process.env.NEXT_PUBLIC_MAESTRO_SITE_ID || '',
apiKey: process.env.NEXT_PUBLIC_MAESTRO_API_KEY || '',
supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL || '',
supabaseKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || '',
environment: process.env.NODE_ENV === 'production' ? 'production' : 'development',
debug: process.env.NODE_ENV !== 'production'
});
function MyApp({ Component, pageProps }) {
return (
<SimpleMaestroProvider>
<Component {...pageProps} />
</SimpleMaestroProvider>
);
}
export default MyApp;
Maestro offers multiple ways to make your content editable:
import { withMaestro } from 'maestro-client';
// Your original component
function ProductCard({ title, description, price }) {
return (
<div className="product-card">
<h2>{title}</h2>
<p>{description}</p>
<span className="price">${price}</span>
</div>
);
}
// Export with Maestro integration
export default withMaestro(ProductCard, {
componentId: "product-card",
componentType: "card",
editableProps: ["title", "description", "price"]
});
import { EditableFieldComponent } from 'maestro-client';
function ProductCard({ title, description, price }) {
return (
<div className="product-card" id="product-1">
<h2>
<EditableFieldComponent name="title" label="Product Title">
{title}
</EditableFieldComponent>
</h2>
<p>
<EditableFieldComponent name="description" type="textarea">
{description}
</EditableFieldComponent>
</p>
<span className="price">${price}</span>
</div>
);
}
import { MaestroContent } from 'maestro-client';
function HomePage() {
return (
<div>
<MaestroContent
contentId="hero-section"
contentType="hero"
defaultContent={{
title: "Welcome to our site",
subtitle: "Discover amazing products",
buttonText: "Shop Now"
}}
renderContent={(content) => (
<div className="hero">
<h1>{content.title}</h1>
<p>{content.subtitle}</p>
<button>{content.buttonText}</button>
</div>
)}
/>
</div>
);
}
import { ComponentPreview } from 'maestro-client';
function PreviewPage() {
return (
<div>
<h1>Component Preview</h1>
<ComponentPreview
componentId="product-1"
editable={true}
showProps={true}
/>
</div>
);
}
- MaestroProvider: Main provider component that initializes the SDK
- SimpleMaestroProvider: Simplified provider that reads from environment variables
- ComponentPreview: Displays a captured component with optional editing capabilities
- EditableFieldComponent: Marks a field as editable within a component
- MaestroContent: Component for dynamic content management
- withMaestro: HOC to make existing components editable
- useMaestro: Hook to access Maestro functionality within components
- initMaestro: Initialize the Maestro SDK
- captureComponent: Captures DOM elements with their styles and structure
MIT