Appearance
Canvas Manipulation
This guide explains how to interact with canvases in the Canvas UI system, including retrieving canvases, working with sections, understanding context, and updating canvases.
Getting Canvases
Current Canvas
To get the currently active canvas in your application:
typescript
// Using the useOpenedCanvas composable (Vue)
import useOpenedCanvas from '@composables/useOpenedCanvas'
const { openedCanvas } = useOpenedCanvas()
// openedCanvas.value contains the current canvas data
In a Canvas Builder component, the active canvas is typically available through props or composables:
typescript
// In a component that receives activeCanvas as a prop
const { activeCanvas } = defineProps<{
activeCanvas: CanvasRetrieve
}>()
// Using reactive properties in canvas builder components
const activeCanvas = computed(() => props.activeCanvas)
Any Canvas
To fetch a specific canvas by ID:
typescript
// Using the ClientApi in impact apps
import { ClientApi } from '@api/client'
// Fetch by ID
const canvas = await ClientApi.getCanvas({ id: 'canvas-id' })
// Using the API in admin apps
import { getCanvas } from '@shared/api/canvas/canvas.api'
const canvas = await getCanvas('canvas-id')
Getting Canvas Sections
Canvas sections are available through the canvas object structure:
typescript
// Access sections from canvas object
const sections = canvas.sections
// In the Canvas Builder, filtered sections are often computed:
const activeCanvasSections = computed(() => {
const visibleKey = getVisibleKey() // Based on current view mode
return (props.data.sections ?? []).reduce(
(sections, section, nodeIdx) => {
const foundSection = storeActiveCanvasSections.value?.[section.id]
if (foundSection) {
// Process section visibility and content
sections.push({
section: {
...section,
content: {
...(section.content ?? {}),
data: filteredContent
},
},
index: nodeIdx,
})
}
return sections
},
[] as { section: CanvasRetrieve['sections'][number]; index: number }[]
)
})
Understanding Context
Context is a key-value object attached to a canvas that stores state information used by canvas components. It enables components to persist data and communicate with each other.
typescript
// Canvas context structure
interface CanvasContext {
[key: string]: any // Flexible key-value storage
pitcher?: {
// System context
completion_wizard?: {
completed?: boolean
}
}
// App-specific context
myAppName?: {
myState: string
myData: any[]
}
// Section-specific context overrides
ctx_overwrite_sectionId_index?: {
// Section-specific overrides to merge with base context
}
}
Context can be used to:
- Store component state that persists between sessions
- Share data between different components
- Implement conditional logic based on context values
- Override context values for specific sections
typescript
// Accessing context in a component
// 1. Direct access via composables
import { useCanvas } from '@canvas-builder/composables/useCanvas'
// Access context directly from activeCanvas
const { activeCanvas } = useCanvas()
const myAppData = computed(() => activeCanvas.value?.context?.myAppName?.myData)
// In standard apps, using useOpenedCanvas
import { useOpenedCanvas } from '@composables/useOpenedCanvas'
const { openedCanvas } = useOpenedCanvas()
const context = computed(() => openedCanvas.value?.context)
// 2. With section-specific context overrides
function getMergeContext() {
const sectionInfo = sectionListSectionInfo.value
if (!activeCanvas.value?.context) {
return {}
}
// If there's no section info, return the base context
if (!sectionInfo) {
return activeCanvas.value.context
}
// Check for section-specific overrides
const sectionOverrideKey = `ctx_overwrite_${sectionInfo.sectionListId}_${sectionInfo.sectionIdx}`
const hasOverrides = activeCanvas.value.context[sectionOverrideKey]
if (hasOverrides) {
// Merge base context with section-specific overrides
return merge(activeCanvas.value.context, activeCanvas.value.context[sectionOverrideKey])
}
return activeCanvas.value.context
}
// 3. In embedded apps via UI_APP_SET_DATA message
window.addEventListener('message', (event) => {
if (event.data.type === 'UI_APP_SET_DATA') {
// Access canvas context from the payload
const canvasContext = event.data.body.canvas.context
// Access app-specific context using your app's namespace
const myAppContext = canvasContext.myAppName
}
})
Updating Canvas
You can update a canvas by using one of these methods:
Using UI API
typescript
import { useUi } from '@pitcher/canvas-ui'
// Update current canvas
await useUi().updateCanvas({
context: {
myApp: {
someState: 'updated value'
}
}
})
Using Client API
typescript
import { ClientApi } from '@api/client'
// Update canvas by ID with specific fields
await ClientApi.updateCanvas({
id: 'canvas-id',
name: 'Updated Canvas Name',
fields: 'id,name' // Specify fields to return after update
})
In Admin Applications
typescript
import { updateCanvas } from '@shared/api/canvas/canvas.api'
// Update canvas with mutation
const updateCanvasMutation = useUpdateCanvas()
updateCanvasMutation.mutate({
id: 'canvas-id',
context: { /* updated context */ },
fields: 'id,name,context'
})
Updating From Embedded Apps
When updating from embedded applications, you can use the event system:
typescript
// Update via event
ClientApi.broadcast({
type: PitcherEventName.CANVAS_UPDATED,
body: {
id: 'canvas-id',
context: {
myApp: {
stateToUpdate: 'new value'
}
}
}
})
The system automatically derives what fields have changed and updates only those fields on the server.