board.ui - UI Controls
Control component appearance, size, and user notifications.
Overview
board.ui provides methods to:
- Update component preview (static mode)
- Resize component
- Show toast notifications
- Request/release focus (Interaction Mode)
- Access clipboard
Preview Updates
updatePreview() - Set Static Preview
Update the component's preview shown when not in Interaction Mode:
typescript
// From SVG string
const svg = '<svg>...</svg>';
await board.ui.updatePreview(svg);
// From canvas element
const canvas = document.querySelector('canvas');
await board.ui.updatePreview(canvas);
// From any DOM element (screenshot)
await board.ui.updatePreviewFromElement(document.body);The SDK automatically generates previews on blur, but you can manually update for custom previews.
When to Use Manual Preview
typescript
board.on('beforeFreeze', async () => {
// Generate custom preview before blur
const specialView = renderSpecialView();
await board.ui.updatePreview(specialView);
});Resize
resize() - Change Component Size
typescript
// Set size
await board.ui.resize({ width: 400, height: 300 });
// Get current size
const size = board.ui.getSize();
console.log(size); // { width: 400, height: 300 }Focus Management
requestFocus() - Enter Interaction Mode
typescript
// Ask platform to focus component
board.ui.requestFocus();Use case: Component wants to grab attention (e.g., timer finished).
releaseFocus() - Exit Interaction Mode
typescript
// Exit Interaction Mode (like pressing ESC)
board.ui.releaseFocus();Use case: Close modal, finish interaction.
Notifications
showToast() - Show Toast Message
typescript
// Success message
board.ui.showToast('Saved!', { type: 'success', duration: 3000 });
// Error message
board.ui.showToast('Failed to save', { type: 'error' });
// Info message (default)
board.ui.showToast('Processing...', { type: 'info', duration: 2000 });
// Warning message
board.ui.showToast('Low battery', { type: 'warning' });Toast options:
typescript
interface ToastOptions {
type?: 'success' | 'error' | 'info' | 'warning';
duration?: number; // milliseconds (default: 3000)
}Clipboard
clipboard - Read/Write Clipboard
typescript
// Copy to clipboard
await board.ui.clipboard.write('Hello, World!');
board.ui.showToast('Copied to clipboard', { type: 'success' });
// Read from clipboard
const text = await board.ui.clipboard.read();
console.log('Pasted:', text);Examples
Auto-Resize Based on Content
typescript
import { BoardAPI } from '@boardapi/sdk';
const board = new BoardAPI();
async function fitContent() {
const content = document.querySelector('#content');
const rect = content.getBoundingClientRect();
await board.ui.resize({
width: Math.ceil(rect.width) + 40, // Add padding
height: Math.ceil(rect.height) + 40
});
}
board.on('ready', fitContent);
// Re-fit when content changes
board.storage.subscribe('items', fitContent);Custom Preview for Chart
typescript
const board = new BoardAPI();
const chart = initChart();
board.on('beforeFreeze', async () => {
// Generate high-quality chart preview
const canvas = chart.toCanvas({ scale: 2 });
await board.ui.updatePreview(canvas);
});Copy/Paste Data
typescript
const board = new BoardAPI();
// Copy button
document.querySelector('#copy-btn').addEventListener('click', async () => {
const data = board.storage.getAll();
const text = JSON.stringify(data, null, 2);
await board.ui.clipboard.write(text);
board.ui.showToast('Copied to clipboard', { type: 'success' });
});
// Paste button
document.querySelector('#paste-btn').addEventListener('click', async () => {
try {
const text = await board.ui.clipboard.read();
const data = JSON.parse(text);
await board.storage.set('importedData', data);
board.ui.showToast('Pasted successfully', { type: 'success' });
} catch (err) {
board.ui.showToast('Invalid data', { type: 'error' });
}
});Timer Notification
typescript
const board = new BoardAPI();
board.storage.subscribe('remaining', async (seconds) => {
if (seconds === 0) {
// Timer finished
board.ui.showToast('Time is up!', { type: 'warning', duration: 5000 });
// Request focus to grab attention
board.ui.requestFocus();
// Play sound
const audio = new Audio('/alert.mp3');
await audio.play();
}
});Form Validation
typescript
const board = new BoardAPI();
document.querySelector('#submit-btn').addEventListener('click', async () => {
const name = document.querySelector<HTMLInputElement>('#name').value;
const email = document.querySelector<HTMLInputElement>('#email').value;
// Validate
if (!name.trim()) {
board.ui.showToast('Name is required', { type: 'error' });
return;
}
if (!email.includes('@')) {
board.ui.showToast('Invalid email', { type: 'error' });
return;
}
// Save
await board.storage.set('formData', { name, email });
board.ui.showToast('Saved successfully', { type: 'success' });
// Exit Interaction Mode
board.ui.releaseFocus();
});Export as Image
typescript
const board = new BoardAPI();
document.querySelector('#export-btn').addEventListener('click', async () => {
board.ui.showToast('Generating image...', { type: 'info' });
// Generate canvas from current view
const canvas = await html2canvas(document.body);
// Convert to blob
canvas.toBlob(async (blob) => {
// Copy image to clipboard
await navigator.clipboard.write([
new ClipboardItem({ 'image/png': blob })
]);
board.ui.showToast('Image copied to clipboard', { type: 'success' });
});
});Responsive Sizing
typescript
const board = new BoardAPI();
function updateSize() {
const items = board.storage.get('items', []);
const itemsPerRow = 3;
const itemWidth = 100;
const itemHeight = 80;
const padding = 20;
const rows = Math.ceil(items.length / itemsPerRow);
board.ui.resize({
width: (itemsPerRow * itemWidth) + (padding * 2),
height: (rows * itemHeight) + (padding * 2)
});
}
board.on('ready', updateSize);
board.storage.subscribe('items', updateSize);Progress Indicator
typescript
const board = new BoardAPI();
async function processItems(items: any[]) {
const total = items.length;
for (let i = 0; i < total; i++) {
await processItem(items[i]);
// Show progress
const percent = Math.round(((i + 1) / total) * 100);
board.ui.showToast(`Processing... ${percent}%`, {
type: 'info',
duration: 500
});
}
board.ui.showToast('All done!', { type: 'success' });
}Toast Best Practices
- Use appropriate types - Success for confirmations, error for failures
- Keep messages short - 2-5 words is ideal
- Don't spam - Debounce frequent operations
- Set duration wisely - Errors can stay longer (5s), success shorter (2s)
- Actionable messages - "Saved" is better than "Operation completed"
Preview Best Practices
- Let SDK auto-generate - Only customize when needed
- Use SVG when possible - Better quality, smaller size
- Optimize canvas - Scale down for preview
- Update on blur - Use
beforeFreezeevent - Include key data - Preview should show component state
What's Next?
- Lifecycle Events - Handle focus/blur events
- Storage API - Manage component state
- Offline Support - Handle network issues