openpencil/packages/vue
Danila Poyarkov be942783dc
refactor(i18n): migrate app copy to domain namespaces
* refactor(i18n): migrate app copy to domain namespaces

- Replace the monolithic dialogs catalog with 16 flat product-domain catalogs
- Preserve every translated locale value while moving all 356 messages
- Expose narrow domain composables and retain useI18n as a compatibility aggregate
- Document namespace ownership and admission rules

* fix(i18n): complete migrated locale coverage

- Translate exposed MCP automation, code editor, credential, and media placeholders
- Restore missing German, Spanish, French, Italian, Polish, and Russian diacritics
- Preserve technical product terms and interpolation placeholders

* fix(i18n): polish remaining locale wording

- Correct the mixed-language German code source label
- Preserve stock_photo and Pexels semantics in German and Polish
- Improve Italian MCP and code-editor grammar
- Use the standard Russian term for MCP endpoint

* fix(i18n): migrate diagnostics copy after rebase

- Add a diagnostics domain for newly merged usage and telemetry settings
- Keep settings navigation labels in the settings domain
- Preserve translated diagnostics catalogs from current master

* style(app): format rebased settings components

* refactor(i18n): simplify domain message keys

- Remove redundant domain prefixes from settings, diagnostics, automation, and integration catalogs
- Move feature-specific actions out of the common namespace
- Preserve current-master language picker and diagnostics copy across every locale
- Update consumers to concise semantic keys

* fix(app): preserve font and updater contracts

- Restore browser and abort-aware font loading from current master
- Remove the unused parameter helper from common messages
- Update updater tests for semantic domain keys

* fix(i18n): finish semantic diagnostics access

* refactor(i18n): derive active MCP status message

* fix(i18n): preserve rendering settings after rebase

- Add a rendering domain for tiled canvas preferences
- Preserve the current-master language and rendering settings UI
- Move every translated renderer preference out of the retired dialogs catalog

* fix(i18n): polish reviewed locale semantics

* test(i18n): enforce translation completeness baseline

- Fail on interpolation placeholder drift and suspicious mixed-script values
- Reject new source-identical translations while tracking existing debt explicitly
- Report translated-message coverage for every supported locale
- Require baseline cleanup when existing placeholders are translated

* refactor(i18n): baseline reviewed mixed-script messages

- Replace brittle product-vocabulary exceptions with Unicode script detection
- Track reviewed mixed-script messages by stable locale and message identity
- Reject new entries and stale baseline debt without hardcoded terminology

* fix(fig): resolve relocated stroke test helper
2026-08-31 23:54:14 +03:00
..
example
src refactor(i18n): migrate app copy to domain namespaces 2026-08-31 23:54:14 +03:00
ARCHITECTURE.md feat(vue): finalize NumberField API and docs 2026-07-13 10:19:24 +03:00
package.json refactor(canvas): adopt immutable CanvasKit paths (#554) 2026-08-18 23:09:45 +03:00
README.md feat(editor): add component property controls 2026-07-17 21:59:49 +03:00
tsconfig.json
tsdown.config.ts fix(vue): make package types ATTW-safe 2026-07-01 13:30:46 +03:00

@open-pencil/vue

Headless Vue 3 SDK for building OpenPencil-powered editors.

@open-pencil/vue sits on top of @open-pencil/core and provides:

  • Vue editor injection via provideEditor() / useEditor()
  • canvas integration via useCanvas(), useCanvasInput(), and useTextEdit()
  • selection, command, panel, variables, and i18n composables
  • headless structural primitives like CanvasRoot, LayerTreeRoot, PageListRoot, and ToolbarRoot

The SDK is headless by design: it provides logic and structure, while your app owns styling and product-specific UI.

Install

bun add @open-pencil/vue @open-pencil/core canvaskit-wasm

Quick start

<script setup lang="ts">
import { createEditor } from '@open-pencil/core/editor'
import { provideEditor } from '@open-pencil/vue'

const editor = createEditor({
  width: 1200,
  height: 800,
})

editor.createShape('RECTANGLE', 100, 100, 200, 150)
editor.zoomToFit()

provideEditor(editor)
</script>

<template>
  <div class="h-screen">
    <CanvasRoot v-slot="{ canvasRef }">
      <canvas ref="canvasRef" class="size-full" />
    </CanvasRoot>
  </div>
</template>

Core concepts

Editor context

Use provideEditor(editor) once near the top of your subtree.

import { provideEditor } from '@open-pencil/vue'

provideEditor(editor)

Read it anywhere below with useEditor().

import { useEditor } from '@open-pencil/vue'

const editor = useEditor()

Canvas wiring

At the composable level, the main canvas APIs are:

  • useCanvas()
  • useCanvasInput()
  • useTextEdit()

If you want SDK-provided structure, use headless primitives like CanvasRoot and CanvasSurface.

Headless primitives

Main structural primitives include:

  • CanvasRoot
  • LayerTreeRoot
  • PageListRoot
  • PropertyListRoot
  • PropertySectionRoot
  • SegmentedControlRoot
  • ToolbarRoot
  • ColorPickerRoot
  • FontPickerRoot
  • NumberFieldRoot / NumberFieldInput / NumberFieldValue
  • BindableValueRoot / BindableValueTrigger / BindableValuePicker
  • LayoutControlsRoot
  • ConstraintsControlRoot

These components coordinate structure and state, but do not impose app styling. NumberField adds pointer scrubbing, Arrow-key stepping, mixed/bound state attributes, and safe arithmetic expressions such as +10, *2, 50%, and 12*8+4. BindableValue composes fields with a generic BindingProvider and supports detach-on-edit, read-only, and edit-variable policies. Focusing a bound NumberField is non-destructive; the configured policy begins only on the first value mutation. LayoutControlsRoot exposes axis-oriented sizing actions; editing a Hug or Fill dimension can switch that axis to Fixed inside the same provider transaction. ConstraintsControlRoot exposes eligible frame-child constraints, mixed axis values, pin actions, and undo-batched multi-selection updates. AppearanceControlsRoot exposes selection-derived independent-corner presentation state so consumers do not need parallel expansion heuristics. PropertyListRoot is controlled and editor-agnostic; OpenPencil panels connect it to selection and undo through useEditorPropertyList(). useColorModel() provides precise scene-color/Reka bridges, reactive RGB/HSL/HSB/OkHCL channels, extensible format state, and shared slider presentation data. FillRoot and FillSwatch separate fill behavior and binding-aware previews from popover composition; ChannelSlider provides accessible scalar OkHCL controls until Reka supports them.

Public API tiers

Core API

These are the main APIs most SDK consumers should start with.

Context and canvas

  • provideEditor()
  • useEditor()
  • useCanvas()
  • useCanvasInput()
  • useTextEdit()

Selection and commands

  • useSelectionState()
  • useSelectionCapabilities()
  • useEditorCommands()
  • useMenuModel()

Property panels

  • usePosition()
  • useLayout()
  • useConstraints()
  • useComponentProperties()
  • useAppearance()
  • useSharedStyleBinding()
  • useColorModel()
  • useMask()
  • useTypography()
  • useExport()
  • useFillControls()
  • useStrokeControls()
  • useEffectsControls()

Variables, navigation, and localization

  • useVariablesEditor()
  • usePageList()
  • useI18n()

Headless primitives

  • CanvasRoot
  • LayerTreeRoot
  • PageListRoot
  • PropertyListRoot
  • PropertyListItem
  • PropertyListAdd / PropertyListRemove / PropertyListVisibility
  • PropertySectionRoot / PropertySectionHeader / PropertySectionTitle
  • PropertySectionActions / PropertySectionContent / PropertySectionEmptyAction
  • SegmentedControlRoot / SegmentedControlItem
  • ToolbarRoot
  • NumberFieldRoot
  • NumberFieldInput
  • NumberFieldValue
  • NumberFieldLeading
  • NumberFieldUnit
  • NumberFieldTrailing
  • NumberFieldMenu
  • BindableValueRoot
  • BindableValueTrigger
  • BindableValuePicker
  • FillRoot / FillSwatch
  • ChannelSliderRoot / ChannelSliderTrack / ChannelSliderThumb

Advanced API

These exports are intentionally public, but they are lower-level or more specialized.

  • useNodeProps()
  • useEditorPropertyList()
  • useSceneComputed()
  • useColorBindingProvider()
  • useColorVariableBinding()
  • provideBindingProvider()
  • useBindingProvider()
  • useNumberBindingProvider()
  • useFill()
  • useGradientStops()
  • useFontPicker()
  • useOkHCL()
  • useVariables()
  • useVariablesDialogState()
  • useVariablesTable()
  • usePropScrub()
  • useLayerDrag()
  • useInlineRename()
  • useToolbarState()
  • useNodeFontStatus()
  • useCanvasDrop()
  • extractImageFilesFromClipboard()
  • useViewportKind()
  • toolCursor()

Primitive context helpers and low-level stores

These are mostly useful when extending SDK primitives rather than building from top-level composables.

  • useCanvasContext()
  • useLayerTree()
  • useToolbar()
  • usePropertyList()
  • useNumberField()
  • locale
  • localeSetting
  • setLocale()
  • AVAILABLE_LOCALES
  • LOCALE_LABELS

Example patterns

Minimal provider component

<script setup lang="ts">
import { provideEditor } from '@open-pencil/vue'

import type { Editor } from '@open-pencil/core/editor'

const props = defineProps<{
  editor: Editor
}>()

provideEditor(props.editor)
</script>

<template>
  <slot />
</template>

Read selection state

import { useSelectionState } from '@open-pencil/vue'

const { hasSelection, selectedCount, selectedNode } = useSelectionState()

Build a menu

import { useMenuModel } from '@open-pencil/vue'

const { appMenu, canvasMenu } = useMenuModel()

Build a page list

<PageListRoot v-slot="{ pages, currentPageId, switchPage }">
  <ul>
    <li v-for="page in pages" :key="page.id">
      <button :data-active="page.id === currentPageId" @click="switchPage(page.id)">
        {{ page.name }}
      </button>
    </li>
  </ul>
</PageListRoot>

Documentation

For fuller guides and API docs, see the documentation site:

  • packages/docs/programmable/sdk/

Example app

Run the included example:

cd packages/vue/example
bun install
bun run dev