@pixeasy/customizer-stage
v0.0.1
Published
Framework-agnostic SDK to embed the Pixeasy customizer in Angular, React, Vue, or any ESM app.
Readme
Pixeasy Customizer SDK
Framework-agnostic SDK to embed the Pixeasy customizer in Angular, React, Vue, or any ESM app.
Installation
npm install @pixeasy/customizerQuick Start
import { createPixeasyBuilder } from '@pixeasy/customizer';
import '@pixeasy/customizer/styles.css';
const builder = createPixeasyBuilder();
builder.open({
container: 'pixeasyBuilder',
apiKey: 'dk_xxx_yyy',
productId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
});Note: container can be a CSS selector string (element id) or an HTMLElement reference.
API Reference
createPixeasyBuilder()
Creates and returns a new PixeasyBuilder instance. You can create multiple builder instances if needed.
const builder = createPixeasyBuilder();PixeasyBuilder.open(options)
Opens the customizer with the specified configuration.
Options
type PixeasyOpenOptions = {
// Required
container: string | HTMLElement; // CSS selector or DOM element to mount the customizer
apiKey: string; // Your API key (format: dk_xxx_yyy)
productId: string; // Product ID (UUID format)
// Optional
predesignId?: string; // Load a pre-designed template
submissionNumber?: string; // Load an existing submission for editing
locale?: string; // Language/locale code (e.g., 'en', 'fr', 'de')
theme?: string; // Theme name or color scheme
readonly?: boolean; // Set to true to disable editing (view-only mode)
};Option Details
| Option | Type | Required | Description |
| ------------------ | ----------------------- | -------- | ------------------------------------------------------------------------------------- |
| container | string \| HTMLElement | Yes | Target container to mount the customizer. If string, treated as element ID. |
| apiKey | string | Yes | Your Pixeasy API key for authentication. |
| productId | string | Yes | UUID of the product to customize. |
| predesignId | string | No | Load a pre-designed template/predesign. Useful for template-based workflows. |
| submissionNumber | string | No | Load an existing submission for editing or review. Use with readonly for view-only. |
| locale | string | No | Set the UI language. Examples: 'en', 'fr', 'de', 'es'. |
| theme | string | No | Apply a theme or color scheme to the customizer UI. |
| readonly | boolean | No | Enable view-only mode. Prevents editing and submission. Perfect for order review. |
Events
All events can be subscribed using builder.on(eventName, handler).
| Event | When it fires | Payload |
| -------------------- | -------------------------------------------------------------------------------------------- | ------------------------------ |
| manifest-loaded | After the product manifest loads successfully. | ManifestLoadedEventDetail |
| sdk-ready | After the customizer initializes and is ready for interaction. | SdkReadyEventDetail |
| submission:success | After a successful submission. | SubmissionSuccessEventDetail |
| submission:failed | When submission fails (API error, network issue, or validation error). | SubmissionFailedEventDetail |
| error | When a runtime error occurs (invalid config, manifest load failed, asset load failed, etc.). | ErrorEventDetail |
| closed | When the customizer is closed via builder.close(). | undefined |
Event Payload Types
// Fires after manifest is loaded
interface ManifestLoadedEventDetail {
productId: string;
manifestMeta?: {
version?: string;
} | null;
}
// Fires when SDK is ready for use
interface SdkReadyEventDetail {
productId: string;
}
// Fires on successful submission
interface SubmissionSuccessEventDetail {
productId?: string;
views?: string[]; // Generated views/angles
submissionNumber: string; // Unique submission identifier
}
// Fires when submission fails
interface SubmissionFailedEventDetail {
productId?: string;
views?: string[];
message: string; // Error message
errors?: string[]; // Detailed error list
}
// Fires on SDK errors
interface ErrorEventDetail {
code: 'INVALID_CONFIG' | 'MANIFEST_LOAD_FAILED' | 'ASSET_LOAD_FAILED' | 'RUNTIME_ERROR';
message: string;
}Event Subscription Example
import { SDK_EVENTS } from '@pixeasy/customizer';
const builder = createPixeasyBuilder();
builder.open({
container: 'pixeasyBuilder',
apiKey: 'dk_xxx_yyy',
productId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
});
// Subscribe to events
builder
.on(SDK_EVENTS.MANIFEST_LOADED, (event) => {
console.log('Manifest loaded for product:', event.productId);
})
.on(SDK_EVENTS.SDK_READY, (event) => {
console.log('Customizer is ready!', event.productId);
})
.on(SDK_EVENTS.SUBMISSION_SUCCESS, (event) => {
console.log('Submission successful:', event.submissionNumber);
console.log('Generated views:', event.views);
})
.on(SDK_EVENTS.SUBMISSION_FAILED, (event) => {
console.error('Submission failed:', event.message);
if (event.errors) {
console.error('Errors:', event.errors);
}
})
.on(SDK_EVENTS.ERROR, (event) => {
console.error(`Error [${event.code}]:`, event.message);
})
.on(SDK_EVENTS.CLOSED, () => {
console.log('Customizer closed');
});Unsubscribing from Events
const handleSuccess = (event) => console.log('Success:', event.submissionNumber);
builder.on(SDK_EVENTS.SUBMISSION_SUCCESS, handleSuccess);
// Later, remove the listener
builder.off(SDK_EVENTS.SUBMISSION_SUCCESS, handleSuccess);Framework Examples
React
Basic Usage
import { useEffect } from 'react';
import { createPixeasyBuilder } from '@pixeasy/customizer';
import '@pixeasy/customizer/styles.css';
export function CustomizerHost() {
useEffect(() => {
const builder = createPixeasyBuilder();
builder.open({
container: 'pixeasyBuilder',
apiKey: 'dk_xxx_yyy',
productId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
});
return () => builder.close();
}, []);
return <div id="pixeasyBuilder" />;
}Advanced Usage with Events
import { useEffect } from 'react';
import { createPixeasyBuilder, SDK_EVENTS } from '@pixeasy/customizer';
import '@pixeasy/customizer/styles.css';
export function CustomizerWithEvents() {
useEffect(() => {
const builder = createPixeasyBuilder();
builder
.on(SDK_EVENTS.SDK_READY, () => {
console.log('Customizer ready');
})
.on(SDK_EVENTS.SUBMISSION_SUCCESS, (event) => {
console.log('Submission successful:', event.submissionNumber);
// Handle success - e.g., show confirmation, redirect, etc.
})
.on(SDK_EVENTS.ERROR, (event) => {
console.error('Error occurred:', event.message);
})
.open({
container: 'pixeasyBuilder',
apiKey: 'dk_xxx_yyy',
productId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
locale: 'en',
theme: 'dark',
});
return () => builder.close();
}, []);
return <div id="pixeasyBuilder" style={{ width: '100%', height: '100vh' }} />;
}Load Existing Submission
import { useEffect } from 'react';
import { createPixeasyBuilder, SDK_EVENTS } from '@pixeasy/customizer';
import '@pixeasy/customizer/styles.css';
export function EditSubmission({ submissionNumber }: { submissionNumber: string }) {
useEffect(() => {
const builder = createPixeasyBuilder();
builder
.on(SDK_EVENTS.SUBMISSION_SUCCESS, (event) => {
console.log('Updated submission:', event.submissionNumber);
})
.open({
container: 'pixeasyBuilder',
apiKey: 'dk_xxx_yyy',
productId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
submissionNumber: submissionNumber, // Load for editing
});
return () => builder.close();
}, [submissionNumber]);
return <div id="pixeasyBuilder" />;
}View-Only Mode
import { useEffect } from 'react';
import { createPixeasyBuilder } from '@pixeasy/customizer';
import '@pixeasy/customizer/styles.css';
export function ViewSubmission({ submissionNumber }: { submissionNumber: string }) {
useEffect(() => {
const builder = createPixeasyBuilder();
builder.open({
container: 'pixeasyBuilder',
apiKey: 'dk_xxx_yyy',
productId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
submissionNumber: submissionNumber,
readonly: true, // Enable view-only mode
});
return () => builder.close();
}, [submissionNumber]);
return <div id="pixeasyBuilder" />;
}Vue
Basic Usage
import { onMounted, onBeforeUnmount } from 'vue';
import { createPixeasyBuilder } from '@pixeasy/customizer';
import '@pixeasy/customizer/styles.css';
export default {
setup() {
const builder = createPixeasyBuilder();
onMounted(() => {
builder.open({
container: 'pixeasyBuilder',
apiKey: 'dk_xxx_yyy',
productId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
});
});
onBeforeUnmount(() => builder.close());
return {};
},
};With Events and Options
import { onMounted, onBeforeUnmount } from 'vue';
import { createPixeasyBuilder, SDK_EVENTS } from '@pixeasy/customizer';
import '@pixeasy/customizer/styles.css';
export default {
props: {
submissionNumber: [String, null],
},
setup(props) {
const builder = createPixeasyBuilder();
onMounted(() => {
builder
.on(SDK_EVENTS.SDK_READY, () => {
console.log('Customizer initialized');
})
.on(SDK_EVENTS.SUBMISSION_SUCCESS, (event) => {
console.log('Saved:', event.submissionNumber);
})
.open({
container: 'pixeasyBuilder',
apiKey: 'dk_xxx_yyy',
productId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
submissionNumber: props.submissionNumber || undefined,
locale: 'en',
});
});
onBeforeUnmount(() => builder.close());
return {};
},
};Exports
The package exports the following:
Classes & Functions
createPixeasyBuilder()- Factory function to create a newPixeasyBuilderinstancePixeasyBuilder- Main class for managing the customizer lifecycledefinePixeasyCustomizerElement()- Registers the<pixeasy-customizer>custom element (auto-called internally)generateThumbnails()- Utility function to generate product thumbnails from SVG and 3D models
Types
PixeasyOpenOptions- Configuration object forbuilder.open()SdkElementConfig- Base configuration interfaceManifestLoadedEventDetail- Payload for manifest-loaded eventSdkReadyEventDetail- Payload for sdk-ready eventSubmissionSuccessEventDetail- Payload for submission:success eventSubmissionFailedEventDetail- Payload for submission:failed eventErrorEventDetail- Payload for error eventSDK_EVENTS- Enum of all available event namesBuilderEventName- Type-safe event name typeThumbnailView- View types for thumbnail generation ('front' | 'right' | 'back' | 'left')GeneratedThumbnail- Thumbnail generation result
Stylesheets
@pixeasy/customizer/styles.css- Required stylesheet (import once in your app)
Common Use Cases
Create a New Design from Scratch
builder.open({
container: 'pixeasyBuilder',
apiKey: 'dk_xxx_yyy',
productId: 'product-uuid',
});Use a Template/Predesign
builder.open({
container: 'pixeasyBuilder',
apiKey: 'dk_xxx_yyy',
productId: 'product-uuid',
predesignId: 'predesign-uuid', // Start with a pre-designed template
});Edit an Existing Submission
builder.open({
container: 'pixeasyBuilder',
apiKey: 'dk_xxx_yyy',
productId: 'product-uuid',
submissionNumber: 'SUB-12345', // Load existing submission
});Review Order (Read-Only)
builder.open({
container: 'pixeasyBuilder',
apiKey: 'dk_xxx_yyy',
productId: 'product-uuid',
submissionNumber: 'SUB-12345',
readonly: true, // Disable editing
});Multi-Language Support
builder.open({
container: 'pixeasyBuilder',
apiKey: 'dk_xxx_yyy',
productId: 'product-uuid',
locale: 'de', // German, or 'fr', 'es', etc.
});Best Practices
Always import styles - Include the CSS stylesheet once in your app:
import '@pixeasy/customizer/styles.css';Handle errors gracefully - Always subscribe to the
errorevent:builder.on(SDK_EVENTS.ERROR, (event) => { console.error(`Error [${event.code}]: ${event.message}`); // Show user-friendly error message });Validate API key and Product ID - These are required for the customizer to function:
if (!apiKey || !productId) { throw new Error('Missing required configuration'); }Clean up on unmount - Always call
builder.close()when the component unmounts to prevent memory leaksUse events for flow control - Subscribe to
submission:successto handle post-submission actionsHandle locale properly - Set the locale to match user preferences before opening
Use readonly mode for reviews - Enable
readonly: truewhen showing past submissions or previews
