Components
ChamevoJS provides a set of StencilJS web components that work with any framework (React, Vue, Angular, Svelte) or vanilla HTML.
Available Components
Main Components
| Component | Tag | Description |
|---|---|---|
| CvCustomizer | <cv-customizer> | Root wrapper - orchestrates canvas, events, keyboard |
| CvCanvas | <cv-canvas> | Canvas container with resize observer |
| CvSizeTooltip | <cv-size-tooltip> | Displays W × H dimensions above selected image elements |
| CvActionButton | <cv-action-button> | Standalone action button for use outside the customizer |
Shared Components
| Component | Tag | Description |
|---|---|---|
| CvButton | <cv-button> | Button with variant, size, disabled |
| CvTabs | <cv-tabs> | Tab navigation with panels |
| CvModal | <cv-modal> | Modal dialog with backdrop |
| CvTooltip | <cv-tooltip> | Tooltip positioned around a trigger |
Registration
Register all components once in your entry point:
import { defineCustomElements } from '@chamevo/customizer';
// Register all cv-* custom elements
defineCustomElements();
Or from the components package directly:
import { defineCustomElements } from '@chamevo/components/loader';
defineCustomElements();
cv-customizer
The root component that creates a ChamevoCanvas and ChamevoJS orchestrator, wires events to Stencil Store, and sets up keyboard controls.
Properties
| Property | Type | Default | Description |
|---|---|---|---|
options | string | Partial<ChamevoOptions> | '{}' | Customizer configuration (JSON string or object) |
proxyFileServer | string | '' | Proxy URL for images and fonts |
Events
| Event | Detail | Description |
|---|---|---|
cvReady | { chamevo: ChamevoJS, canvas: ChamevoCanvas } | Customizer initialized |
cvProductCreate | { product: CVProduct } | Product loaded |
cvViewSelect | { view: CVView, index: number } | Active view changed |
cvElementSelect | { element: unknown } | Element selected/deselected |
cvPriceChange | { price: number, singleProductPrice: number } | Price updated |
Methods
| Method | Returns | Description |
|---|---|---|
loadProduct(product) | Promise<void> | Load a product (CVProduct or flat CVView[]) |
selectView(index) | Promise<void> | Switch active view |
getProduct() | Promise<CVProduct> | Get serialized product |
getOrder() | Promise<unknown> | Get full order data |
getElements(viewIndex?, type?) | Promise<unknown[]> | Get serialized elements |
undo() | Promise<void> | Undo last action |
redo() | Promise<void> | Redo last undone action |
reset() | Promise<void> | Clear all views |
Slots
cv-customizer uses named slots for layout customization:
<cv-customizer options='{"stageWidth": 900, "stageHeight": 600}'>
<div slot="toolbar-top">Custom top toolbar</div>
<div slot="sidebar">Custom sidebar</div>
<div slot="panel">Custom right panel</div>
<div slot="toolbar-bottom">Custom bottom toolbar</div>
</cv-customizer>
| Slot | Position |
|---|---|
toolbar-top | Above the canvas area |
sidebar | Left of the canvas |
panel | Right of the canvas |
toolbar-bottom | Below the canvas area |
Keyboard Controls
When an element is selected on the canvas, cv-customizer handles:
| Key | Action |
|---|---|
| Arrow keys | Move element by 1px |
| Shift+Arrow | Move element by 10px |
| Delete | Remove selected element |
| Backspace | Remove selected element |
Keyboard input is ignored when focus is inside <input>, <textarea>, or contentEditable elements.
Usage Example
import { defineCustomElements } from '@chamevo/customizer';
defineCustomElements();
const customizer = document.querySelector('cv-customizer');
customizer.addEventListener('cvReady', async (e) => {
const { chamevo, canvas } = e.detail;
await customizer.loadProduct({
title: 'T-Shirt',
views: [
{
title: 'Front',
elements: [
{
type: 'image',
source: '/images/tshirt.png',
title: 'T-Shirt',
parameters: { left: 450, top: 300, draggable: false },
},
],
},
],
});
});
cv-canvas
Container component that provides the <canvas> element and monitors container resize.
Events
| Event | Detail | Description |
|---|---|---|
cvCanvasResize | { width: number, height: number } | Container resized |
Methods
| Method | Returns | Description |
|---|---|---|
getCanvasElement() | Promise<HTMLCanvasElement> | Returns the internal canvas element |
cv-button
Reusable button component with variants and sizes.
Properties
| Property | Type | Default | Description |
|---|---|---|---|
variant | 'primary' | 'secondary' | 'ghost' | 'primary' | Visual style |
size | 'sm' | 'md' | 'lg' | 'md' | Button size |
disabled | boolean | false | Disabled state |
<cv-button variant="primary" size="md">Click me</cv-button>
<cv-button variant="ghost" size="sm">Cancel</cv-button>
CSS Theming
All components use CSS custom properties (--cv-*) for theming. Variables are defined on :root and cascade through shadow DOM boundaries.
Global Tokens
:root {
/* Primary palette */
--cv-primary: #2185d0;
--cv-secondary: #6c757d;
--cv-success: #21ba45;
--cv-error: #db2828;
--cv-warning: #fbbd08;
/* Surfaces */
--cv-bg: #ffffff;
--cv-bg-secondary: #f8f9fa;
/* Text */
--cv-text: #212529;
--cv-text-secondary: #6c757d;
/* Borders */
--cv-border: #dee2e6;
/* Border radius */
--cv-radius: 0.375rem;
--cv-radius-sm: 0.25rem;
--cv-radius-lg: 0.5rem;
/* Layout */
--cv-toolbar-height: 48px;
--cv-sidebar-width: 280px;
--cv-panel-width: 260px;
}
Customizing
Override variables on the cv-customizer element or any ancestor:
cv-customizer {
--cv-primary: #e11d48;
--cv-radius: 0.5rem;
--cv-sidebar-width: 300px;
}
Dark Mode
Add the cv-dark class to <cv-customizer> or any ancestor:
<cv-customizer class="cv-dark" options='{"stageWidth": 900}'>
</cv-customizer>
Dark mode overrides color tokens while keeping layout, radius, and transitions unchanged:
.cv-dark {
--cv-primary: #3b9eed;
--cv-bg: #0f172a;
--cv-bg-secondary: #1e293b;
--cv-text: #f1f5f9;
--cv-text-secondary: #94a3b8;
--cv-border: #334155;
}