diff --git a/.github/workflows/demo.yml b/.github/workflows/demo.yml new file mode 100644 index 000000000..6f01b8b1c --- /dev/null +++ b/.github/workflows/demo.yml @@ -0,0 +1,54 @@ +name: Demo and documentation + +on: + push: + branches: [master] + paths: + - 'demo/**' + - 'docs/**' + - 'src/**' + - 'README.md' + - 'package.json' + - 'package-lock.json' + - 'tsconfig.json' + - 'tsup.config.ts' + - '.nvmrc' + - '.github/workflows/ci.yml' + - '.github/workflows/demo.yml' + pull_request: + paths: + - 'demo/**' + - 'docs/**' + - 'src/**' + - 'README.md' + - 'package.json' + - 'package-lock.json' + - 'tsconfig.json' + - 'tsup.config.ts' + - '.nvmrc' + - '.github/workflows/ci.yml' + - '.github/workflows/demo.yml' + +jobs: + demo: + name: Demo and docs (Node ${{ matrix.node }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node: [22, 25] + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-node@v7 + with: + node-version: ${{ matrix.node }} + cache: npm + cache-dependency-path: | + package-lock.json + demo/package-lock.json + # The root prepare script builds the wrapper during installation. + - run: npm ci + - run: npm --prefix demo ci + - run: npm --prefix demo run build + - run: npm --prefix demo test + - run: npm --prefix demo run test:docs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index de2bbe201..1113dca77 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,15 +1,31 @@ ## Prerequisites -[Node.js](http://nodejs.org/) >= v10 must be installed. +[Node.js](https://nodejs.org/) 22, matching `.nvmrc`, must be installed. ## Installation -- Running `npm install` in the components's root directory will install everything you need for development. -- Running `npm install` in the `demo` directory will install everything you need to run a demo app locally. +From the repository root: + +```bash +npm install +npm --prefix demo install +``` + +The root install builds the wrapper through its `prepare` script. ## Demo Development Server -- `npm start` from `demo` directory will run the component's demo app at [http://localhost:3000](http://localhost:3000) with hot module reloading. +The demo consumes the built wrapper through `file:..`. Run these commands in two terminals, both from the repository root: + +```bash +npm start +``` + +```bash +npm --prefix demo run dev +``` + +`npm start` runs `tsup --watch` to rebuild wrapper changes. The demo server reloads those builds at [http://localhost:3000](http://localhost:3000); running only the demo server will not pick up wrapper source edits. ## Running Tests diff --git a/README.md b/README.md index 6f292acc7..245ed5380 100644 --- a/README.md +++ b/README.md @@ -53,41 +53,44 @@ See the [CHANGELOG](CHANGELOG.md) for the full list. Require the EmailEditor component and render it with JSX: + + ```tsx -import React, { useRef } from 'react'; +import { useRef, useState } from 'react'; import { createRoot } from 'react-dom/client'; +import EmailEditor, { + type EditorRef, + type EmailEditorProps, +} from 'react-email-editor'; -import EmailEditor, { EditorRef, EmailEditorProps } from 'react-email-editor'; - -const App = (props) => { +const App = () => { const emailEditorRef = useRef(null); + const [ready, setReady] = useState(false); + const [html, setHtml] = useState(''); const exportHtml = () => { - const unlayer = emailEditorRef.current?.editor; - - unlayer?.exportHtml((data) => { - const { design, html } = data; - console.log('exportHtml', html); + if (!ready) return; + emailEditorRef.current?.editor?.exportHtml((data) => { + setHtml(data.html); + // Persist data.design to reopen it later with editor.loadDesign(data.design). }); }; - const onReady: EmailEditorProps['onReady'] = (unlayer) => { - // editor is ready - // you can load your template here; - // the design json can be obtained by calling - // unlayer.loadDesign(callback) or unlayer.exportHtml(callback) - // or generated from React code with @unlayer/react-elements (renderToJson) - // const templateJson = { DESIGN JSON GOES HERE }; - // unlayer.loadDesign(templateJson); + const onReady: EmailEditorProps['onReady'] = (editor) => { + setReady(true); + // editor is now ready for calls such as saveDesign and loadDesign. + // Load an existing design here: editor.loadDesign(savedDesign). + // Obtain design JSON from editor.saveDesign(callback), editor.exportHtml(callback), + // or @unlayer/react-elements' renderToJson(). loadDesign accepts JSON, not a callback. }; return (
-
- -
- + + {html &&