Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
name: Bug report
about: Something does not work as expected
labels: bug
---

**Version**: `@boxraiser/visual-editor` x.y.z, browser and OS

**What happens**


**What you expected**


**How to reproduce** (a minimal component declaration and value help a lot)

11 changes: 11 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
name: Feature request
about: Suggest an improvement
labels: enhancement
---

**The problem**


**The solution you would like**

8 changes: 8 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
**What and why**


**Checks**

- [ ] `pnpm check`, `pnpm build` and `pnpm test` pass in `visual-editor/`
- [ ] No change to the public API or to the stored JSON format (or it is described above)
- [ ] Documentation and changelog updated when needed
3 changes: 1 addition & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ name: Publish
on:
push:
tags:
- '0.*'
- '1.*'
- '[0-9]+.[0-9]+.[0-9]+*'
workflow_dispatch:

permissions:
Expand Down
26 changes: 26 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Contributing

Thanks for helping! Issues and pull requests are welcome, in English or French.

## Setup

Requirements: Node 24, pnpm 10 (`corepack enable` picks the version from `package.json`) and PHP (the end to end tests use `php -S`).

```bash
pnpm install
cd visual-editor
pnpm dev # Vite playground + PHP preview server on :8000
pnpm check # TypeScript
pnpm build # dist/, what is published on npm
pnpm test # vitest, then Cypress (needs a build)
pnpm format # Prettier
```

To run Cypress against another port: start `php -S localhost:8765` in `visual-editor/` and run `CYPRESS_BASE_URL=http://localhost:8765 npx cypress run`.

## Pull requests

- One topic per pull request, with a short description of the behaviour change.
- Commit messages follow the existing style: `feat:`, `fix:`, `chore:`, `docs:`, `test:`...
- Keep the public API and the stored JSON format stable. `cypress/e2e/compat.cy.js` replays how an existing host uses the library: if it fails, the change breaks existing users and must be discussed first.
- Add or update the documentation in `docs/docs/` and an entry in `docs/docs/changelog.mdx`.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2021-2026 Ciklik and contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
29 changes: 29 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Releasing

Releases are published to npm by GitHub Actions on every `X.Y.Z` tag (`.github/workflows/publish.yml`) with npm trusted publishing (OIDC): no npm token is stored in the repository, and the package gets a provenance attestation.

## One time setup

On npmjs.com, in the settings of `@boxraiser/visual-editor`, add a trusted publisher:

- Provider: GitHub Actions
- Organization or user: `ciklik`
- Repository: `visual-editor`
- Workflow filename: `publish.yml`
- Environment: leave empty

Fallback, only if trusted publishing is not available: create a granular npm access token with publish rights on the package and store it as the `NPM_TOKEN` repository secret. The workflow uses it when OIDC is not possible.

## Release a version

1. Update `version` in `visual-editor/package.json` and add the entry in `docs/docs/changelog.mdx`, then merge to `main`.
2. Tag the merged commit with the bare version and push the tag:

```bash
git tag 0.2.1
git push origin 0.2.1
```

3. The `Publish` workflow builds `visual-editor/dist` and publishes it. It fails if the tag does not match the package version.

If a run fails after the tag is pushed, fix the cause and run the `Publish` workflow again from the Actions tab with "Use workflow from" set to the tag (manual runs are only allowed on tags).
41 changes: 38 additions & 3 deletions docs/docs/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,52 @@ sidebar_position: 10

# Changelog

## 0.2 - 2024/02/01

## 0.2.1 - 2026/10/09

- Fix: the `change` event carries the JSON of the page in `detail` again (removed in 0.2.0), and is emitted for every change made in the editor, including the preview arrows. It is not emitted when the host sets `value`
- Fix: one store per element, the content is kept when the editor is hidden and shown again, and `value` can be read right after the element is inserted
- Fix: the text alignment radios are no longer submitted with the surrounding form (#4)
- Fix: preview messages are only accepted from the preview iframe and from the editor window
- Fix: English and French translations
- Feat: strike, superscript, subscript and inline code in the text toolbar, "New tab" option on links, "No color" in the color palette (#21)
- Change: links created from the toolbar open in the same tab by default (use the "New tab" option)
- Security: Tiptap 3.31 (prosemirror-view XSS on paste, linkifyjs) and dependency updates
- Chore: MIT license, `exports` map in `package.json` (only the entry point, `VisualEditor.js`, `VisualEditor.standalone.js` and `package.json` can be imported), minified standalone build, the playground icons are no longer published
- Chore: publication to npm with trusted publishing (OIDC) and provenance

## 0.2.0 - 2026/02/12

Not published on npm. Upgrading from 0.1.x, mind these behaviour changes:

- **Breaking**: the `change` event had no `detail` anymore (restored in 0.2.1)
- **Breaking**: the text toolbar offers h1 headings, and the alignment button is available in multiline fields too: it writes an inline `style="text-align: ..."` on paragraphs and headings
- **Breaking**: blocks can be moved with up and down arrows in the preview (they emit `change` since 0.2.1)
- Feat: export UI components
- Feat: registerButton() method for adding custom button
- Feat: Add control in the preview
- Feat: New responsive controls
- Feat: Add a new `templates` event (cancelable)
- Feat: Add a new `components` event (cancelable)
- Chore: Remove `detail` in the change event
- Fix: key missing on templates listing

## 0.1.4 - 2025/12/01

- Fix: undefined text alignment in the toolbar

## 0.1.3 - 2025/11/19

- Fix: z-index of the text toolbar

## 0.1.2 - 2025/07/24

- Republication of 0.1.1

## 0.1.1 - 2025/07/24

- Feat: Tiptap 3
- Fix: no default text alignment added by Tiptap
- Fix: SSR compatibility

## 0.1.0 - 2023/03/16

- Feat: Add a new `postMessagePreview` option for VisualEditor
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/events.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ If you need to create custom behaviour you can listen for some events on the edi

| **Event** | **Description** | **Cancellable** | **Methods** |
|-----------|-----------------|-------------|-------------|
| `change` | Fires when the value of the editor is changed by the user | No | |
| `change` | Fires when the value of the editor is changed by the user (not when the value is set by the host) | No | **detail** : `string`, the JSON of the page (same as `element.value`) |
| `templates` | Fires when the user click on the template button | Yes | |
| `components` | Fires when the user click on the add component button | Yes | |
| `removeitem` | Fires when a bloc is removed | Yes | **detail.confirm** : `() => void`, triggers the intended action (usefull if event was prevented) |
52 changes: 38 additions & 14 deletions visual-editor/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
# Visual Editor

[![npm version](https://badge.fury.io/js/@boxraiser%2Fvisual-editor.svg)](https://badge.fury.io/js/@boxraiser%2Fvisual-editor)
[![Tests](https://github.com/boxraiser/visual-editor/actions/workflows/test.yml/badge.svg)](https://github.com/boxraiser/visual-editor/actions/workflows/test.yml)
[![npm version](https://img.shields.io/npm/v/@boxraiser/visual-editor)](https://www.npmjs.com/package/@boxraiser/visual-editor)
[![Tests](https://github.com/ciklik/visual-editor/actions/workflows/test.yml/badge.svg)](https://github.com/ciklik/visual-editor/actions/workflows/test.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ciklik/visual-editor/blob/main/LICENSE)

[Documentation](http://ciklik.github.io/visual-editor/)
[Documentation](https://ciklik.github.io/visual-editor/)

## Installation

```bash
npm install @boxraiser/visual-editor react react-dom
```

React 18 is a peer dependency. A build with every dependency included is also available as `@boxraiser/visual-editor/VisualEditor.standalone.js`.

## Getting started

Expand All @@ -15,15 +24,14 @@ Start by instantiating the editor.

```js
import { VisualEditor } from '@boxraiser/visual-editor'
import '@boxraiser/visual-editor/style.css'

let editor = new VisualEditor()
const editor = new VisualEditor()
```

Then register your page components using the `registerComponent` method that expect 2 parameters

- A unique identifier for the block (string)
- An option object object (see [EditorComponentDefinition](https://github.com/Grafikart/VisualEditor/blob/master/src/types.ts#L24) for more information)
- An option object object (see [EditorComponentDefinition](https://github.com/ciklik/visual-editor/blob/main/visual-editor/src/types.ts) for more information)

```js
import { HTMLText, Repeater, Text, Row, Select } from '@boxraiser/visual-editor'
Expand All @@ -33,16 +41,16 @@ editor.registerComponent('hero', {
title: 'Hero',
category: 'Banner',
fields: [
new Text('title', {multiline: false}),
new HTMLText('content'),
new Repeater('buttons', {
Text('title', {multiline: false}),
HTMLText('content'),
Repeater('buttons', {
title: 'Boutons',
addLabel: 'Add a new button',
fields: [
new Row([
new Text('label', { label: 'Libellé', default: 'Call to action' }),
new Text('url', { label: 'Lien' }),
new Select('type', {
Row([
Text('label', { label: 'Libellé', default: 'Call to action' }),
Text('url', { label: 'Lien' }),
Select('type', {
default: 'primary',
label: 'type',
options: [
Expand Down Expand Up @@ -89,6 +97,18 @@ There are multiple attributes :

The custom element will create a hidden field that will be used to store the data, no need for additional JavaScript you will receive the data when the form is submitted.

### Listening to changes

The element emits a `change` event every time the content is changed by the user. `event.detail` (and `element.value`) contains the JSON of the page.

```js
document.querySelector('visual-editor').addEventListener('change', (e) => {
console.log(JSON.parse(e.detail))
})
```

See the [documentation](https://ciklik.github.io/visual-editor/) for the other events, the fields, the templates and the preview.

### How the data is formatted ?

The data use a simple structure (to be usable with any framework or technology)
Expand Down Expand Up @@ -117,7 +137,7 @@ A real world example
{
"title": "Album example",
"titleAlign": "center",
"content": "<p>Something short and leading about the collection below—its contents, the creator, etc. Make it short and sweet, but not too short so folks don't simply skip over it entirely.</p>",
"content": "<p>Something short and leading about the collection below, its contents, the creator, etc. Make it short and sweet, but not too short so folks don't simply skip over it entirely.</p>",
"buttons": [
{
"label": "Main call to action",
Expand Down Expand Up @@ -226,3 +246,7 @@ A real world example
}
]
```

## License

[MIT](https://github.com/ciklik/visual-editor/blob/main/LICENSE)
27 changes: 25 additions & 2 deletions visual-editor/package.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
{
"name": "@boxraiser/visual-editor",
"version": "0.2.0",
"version": "0.2.1",
"description": "Block based visual editor, as a custom element",
"license": "MIT",
"type": "module",
"main": "VisualEditor.js",
"types": "./VisualEditor.d.ts",
"exports": {
".": {
"types": "./VisualEditor.d.ts",
"default": "./VisualEditor.js"
},
"./VisualEditor.js": "./VisualEditor.js",
"./VisualEditor.standalone.js": "./VisualEditor.standalone.js",
"./package.json": "./package.json"
},
"sideEffects": false,
"files": [
"VisualEditor.js",
"VisualEditor.standalone.js",
"**/*.d.ts",
"LICENSE"
],
"repository": {
"type": "git",
"url": "https://github.com/ciklik/visual-editor"
},
"homepage": "https://ciklik.github.io/visual-editor/",
"bugs": "https://github.com/ciklik/visual-editor/issues",
"scripts": {
"dev": "concurrently \"vite\" \"php -S 0.0.0.0:8000 -ddisplay_errors=1 -t server/\"",
"check": "tsc",
"build": "tsc && vite build && node esbuild.js && npm run declaration && cp package.json dist/package.json && cp README.md dist/README.md",
"build": "tsc && vite build && node esbuild.js && npm run declaration && cp package.json dist/package.json && cp README.md ../LICENSE dist/",
"serve": "vite preview",
"format": "prettier --config .prettierrc 'src/**/*.{ts,tsx}' --write",
"declaration": "tsc --declaration --emitDeclarationOnly --jsx react-jsx --esModuleInterop --target es2020 -p tsconfig.json --noEmit false && tsc-alias",
Expand Down Expand Up @@ -93,5 +113,8 @@
},
"volta": {
"node": "24.21.0"
},
"engines": {
"node": ">=18"
}
}
8 changes: 5 additions & 3 deletions visual-editor/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import react from '@vitejs/plugin-react'
import analyze from 'rollup-plugin-analyzer'

// https://vitejs.dev/config/
export default defineConfig({
export default defineConfig(({ command }) => ({
define: { 'process.env.NODE_ENV': '"production"' },
// The playground icons are not part of the library
publicDir: command === 'build' ? false : 'public',
plugins: [
react({
babel: {
Expand Down Expand Up @@ -33,7 +35,7 @@ export default defineConfig({
},
},
build: {
minify: false,
minify: true,
rollupOptions: {
plugins: [
analyze({
Expand All @@ -50,4 +52,4 @@ export default defineConfig({
fileName: () => 'VisualEditor.standalone.js',
},
},
})
}))
Loading