@baranowski/dynamit
v0.1.0
Published
A block-based article builder for Vue 3.
Readme
Dynamit Article Builder
A block-based article editor for Vue 3, with rich text, headings, quotes, images, dividers, and drag-and-drop ordering.
Install locally
Requires Vue ^3.5.32 in the consuming application. The package is ESM and is intended for a Vue application built with Vite or another compatible bundler.
In this repository:
npm ci
npm packnpm pack automatically builds the library and declarations, then creates dynamit-0.0.0.tgz. Install that file in your application:
npm install /absolute/path/to/dynamit/dynamit-0.0.0.tgzAfter changing Dynamit, run npm pack again and reinstall the new tarball in the consuming project. This project has not been published to the npm registry.
Use the component
Import the package CSS once, typically in your application's entry file:
import 'dynamit/style.css'Then use the component in a Vue single-file component:
<script setup lang="ts">
import { ref } from 'vue'
import { Builder } from 'dynamit'
import type { BlockData } from 'dynamit'
const articleBlocks = ref<BlockData[]>([
{
id: 'intro',
type: 'heading',
data: { level: 'h2', content: 'My first article' },
order: 0,
},
])
</script>
<template>
<Builder v-model="articleBlocks" />
</template>The component updates articleBlocks as you edit. Load previously saved blocks into this array and save the array to your own backend. Dynamit provides the editor; storage and rendering published articles belong to your application.
You can also listen for a formatted JSON string:
<Builder v-model="articleBlocks" @update:json="handleJson" />handleJson receives a string whenever an editor change updates the model.
Register globally
Instead of importing Builder in individual components, install the default Vue plugin:
import { createApp } from 'vue'
import Dynamit from 'dynamit'
import 'dynamit/style.css'
import App from './App.vue'
createApp(App).use(Dynamit).mount('#app')Use <DynamitBuilder v-model="articleBlocks" /> in your templates.
Block data and TypeScript
Every block has id, type, data, and order. The array is kept in display order; order is updated when blocks move or are deleted.
| Type | Data fields |
| --- | --- |
| text | content: HTML string |
| heading | level: h2, h3, or h4; content: plain text |
| quote | quote, author, position: plain text |
| image | url, caption, alt: strings |
| divider | Empty object |
Data fields are optional because newly added blocks start with an empty data object. IDs can be strings or numbers and must be unique within the article.
The package exports BlockData, BlockType, BlockId, BlockDataMap, the individual block data types, and ImageUploader. BlockData is a discriminated union, so TypeScript checks each block's fields against its type.
Image uploads
Provide an uploader from a parent component or with app.provide. It accepts a browser File and returns a permanent image URL, synchronously or through a promise:
import { provide } from 'vue'
import type { ImageUploader } from 'dynamit'
const uploadImage: ImageUploader = async (file) => {
const body = new FormData()
body.append('image', file)
// Replace this endpoint with your application's upload service.
const response = await fetch('/api/images', { method: 'POST', body })
if (!response.ok) throw new Error('Image upload failed')
const result: { url: string } = await response.json()
return result.url
}
provide('dynamitImageUploader', uploadImage)Without an uploader, the editor uses a temporary local object URL for preview. These URLs are not suitable for saved articles.
Typography and dark mode
The editor uses Instrument Sans throughout, loaded through Google Fonts with system sans-serif fallbacks. Google Fonts must be allowed by your host application's network and content-security policy, or you can supply the font yourself.
Dark mode follows Tailwind's dark class on html, any ancestor, or the builder itself. No Tailwind dependency or theme prop is required:
<div :class="{ dark: isDark }">
<Builder v-model="articleBlocks" />
</div>Removing the class restores the light theme. The playground includes a theme toggle. Builder styles are scoped under .dynamit-builder and do not include the playground's page layout or global resets.
Development and builds
For development tooling, use Node.js 20.19+ in the Node 20 series, or 22.12+.
npm ci
npm run dev| Command | Result |
| --- | --- |
| npm run dev | Playground with hot reload |
| npm run typecheck | Check source and configuration types |
| npm run build | Library JS, CSS, and declarations in dist/ |
| npm run build:playground | Playground website in dist-playground/ |
| npm run preview | Preview the built playground |
| npm pack | Rebuild and create the installable tarball |
Only the library files in dist/, package metadata, and this README are included in the tarball. Vue is a peer dependency and is not bundled. Tiptap and vuedraggable are installed as runtime dependencies.
The package is currently marked UNLICENSED; no open-source license is granted.
