mirror of
https://github.com/ueberdosis/tiptap.git
synced 2024-11-23 19:19:03 +08:00
Merge branch 'develop' into feature/once
This commit is contained in:
commit
b873b36f11
8
.changeset/README.md
Normal file
8
.changeset/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Changesets
|
||||
|
||||
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
||||
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
||||
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
||||
|
||||
We have a quick list of common questions to get you started engaging with this project in
|
||||
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
5
.changeset/chatty-monkeys-hear.md
Normal file
5
.changeset/chatty-monkeys-hear.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tiptap/extension-list-keymap": patch
|
||||
---
|
||||
|
||||
Fix backspace behavior when selection is not collapsed
|
5
.changeset/chatty-pianos-learn.md
Normal file
5
.changeset/chatty-pianos-learn.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tiptap/core": patch
|
||||
---
|
||||
|
||||
preserve existing node attributes when running setNode
|
14
.changeset/config.json
Normal file
14
.changeset/config.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": "https://unpkg.com/@changesets/config@3.0.1/schema.json",
|
||||
"changelog": "@changesets/cli/changelog",
|
||||
"commit": false,
|
||||
"fixed": [["@tiptap/*"]],
|
||||
"linked": [],
|
||||
"access": "public",
|
||||
"baseBranch": "main",
|
||||
"updateInternalDependencies": "patch",
|
||||
"ignore": [],
|
||||
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
|
||||
"onlyUpdatePeerDependentsWhenOutOfRange": true
|
||||
}
|
||||
}
|
5
.changeset/five-flowers-eat.md
Normal file
5
.changeset/five-flowers-eat.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tiptap/vue-3": patch
|
||||
---
|
||||
|
||||
Fix editor destruction before transition end if editor is nested
|
5
.changeset/five-mice-turn.md
Normal file
5
.changeset/five-mice-turn.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tiptap/extension-bubble-menu": patch
|
||||
---
|
||||
|
||||
Add `element: HTMLElement` to `shouldShow` options within the BubbleMenu options.
|
5
.changeset/fresh-coats-relate.md
Normal file
5
.changeset/fresh-coats-relate.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tiptap/core": minor
|
||||
---
|
||||
|
||||
Previously, only a json representation of the node could be inserted into the editor. This change allows for the insertion of Prosemirror `Node`s and `Fragment`s directly into the editor through the `insertContentAt`, `setContent` and `insertContent` commands.
|
5
.changeset/funny-otters-protect.md
Normal file
5
.changeset/funny-otters-protect.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tiptap/core": patch
|
||||
---
|
||||
|
||||
Addresses a bug with `insertContentAt`'s `simulatedPasteRules` option where it could only accept text and not Prosemirror `Node` and `Content`
|
5
.changeset/happy-vans-smash.md
Normal file
5
.changeset/happy-vans-smash.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tiptap/core": patch
|
||||
---
|
||||
|
||||
Updates the types of `addOptions` and `addStorage` to have the parent be possibly undefined which is the most accurate typing
|
5
.changeset/mean-moose-bow.md
Normal file
5
.changeset/mean-moose-bow.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tiptap/vue-2": patch
|
||||
---
|
||||
|
||||
Pin vue-ts-types to a working version for vue-2
|
5
.changeset/polite-buttons-wash.md
Normal file
5
.changeset/polite-buttons-wash.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tiptap/react": patch
|
||||
---
|
||||
|
||||
React 19 is now allowed as a peer dep, we did not have to make any changes for React 19
|
5
.changeset/serious-coins-fail.md
Normal file
5
.changeset/serious-coins-fail.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tiptap/extension-mention": patch
|
||||
---
|
||||
|
||||
add zero-width space to resolve cursor selection issue
|
5
.changeset/swift-keys-collect.md
Normal file
5
.changeset/swift-keys-collect.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tiptap/core": patch
|
||||
---
|
||||
|
||||
Improve handling of selections with `updateAttributes`. Should no longer modify parent nodes of the same type.
|
5
.changeset/two-rats-watch.md
Normal file
5
.changeset/two-rats-watch.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tiptap/extension-table": patch
|
||||
---
|
||||
|
||||
enforce cellMinWidth even on column not resized by the user, fixes #5435
|
6
.changeset/witty-olives-protect.md
Normal file
6
.changeset/witty-olives-protect.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@tiptap/extension-link": patch
|
||||
"tiptap-demos": patch
|
||||
---
|
||||
|
||||
The link extension's `validate` option now applies to both auto-linking and XSS mitigation. While, the new `shouldAutoLink` option is used to disable auto linking on an otherwise valid url.
|
@ -8,6 +8,15 @@ module.exports = {
|
||||
node: true,
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
'./**/*.ts',
|
||||
'./**/*.tsx',
|
||||
'./**/*.js',
|
||||
'./**/*.jsx',
|
||||
],
|
||||
extends: ['plugin:react-hooks/recommended'],
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'./**/*.ts',
|
||||
|
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
@ -1,9 +1,6 @@
|
||||
# Global
|
||||
* @bdbch @svenadlung
|
||||
|
||||
# docs
|
||||
/docs/ @svenadlung
|
||||
|
||||
# demos
|
||||
/demos/ @bdbch
|
||||
|
||||
|
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@ -14,7 +14,7 @@
|
||||
<!-- Add any other notes or screenshots about the PR here. -->
|
||||
|
||||
## Checklist
|
||||
- [ ] I have renamed my PR according to the naming conventions. (e.g. `feat: Implement new feature` or `chore(deps): Update dependencies`)
|
||||
- [ ] I have created a [changeset](https://github.com/changesets/changesets) for this PR if necessary.
|
||||
- [ ] My changes do not break the library.
|
||||
- [ ] I have added tests where applicable.
|
||||
- [ ] I have followed the project guidelines.
|
||||
|
25
.github/workflows/build.yml
vendored
25
.github/workflows/build.yml
vendored
@ -3,16 +3,22 @@
|
||||
|
||||
name: build
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
- next
|
||||
- release/*
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
- next
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
@ -20,7 +26,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16]
|
||||
node-version: [20]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.4
|
||||
@ -31,11 +37,12 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Load cached dependencies
|
||||
uses: actions/cache@v4.0.2
|
||||
uses: actions/cache@v4.1.2
|
||||
id: cache
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
**/.turbo
|
||||
/home/runner/.cache/Cypress
|
||||
key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
|
||||
|
||||
@ -64,7 +71,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16]
|
||||
node-version: [20]
|
||||
test-spec:
|
||||
- { name: "Integration", spec: "./tests/cypress/integration/**/*.spec.{js,ts}" }
|
||||
#- { name: "Demos/Commands", spec: "./demos/src/Commands/**/*.spec.{js,ts}" }
|
||||
@ -96,10 +103,10 @@ jobs:
|
||||
|
||||
- name: Test ${{ matrix.test-spec.name }}
|
||||
id: cypress
|
||||
uses: cypress-io/github-action@v6.6.0
|
||||
uses: cypress-io/github-action@v6.7.6
|
||||
with:
|
||||
cache-key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
|
||||
start: npm run start
|
||||
start: npm run serve
|
||||
wait-on: 'http://localhost:3000'
|
||||
spec: ${{ matrix.test-spec.spec }}
|
||||
project: ./tests
|
||||
@ -107,7 +114,7 @@ jobs:
|
||||
quiet: true
|
||||
|
||||
- name: Export screenshots (on failure only)
|
||||
uses: actions/upload-artifact@v4.3.3
|
||||
uses: actions/upload-artifact@v4.4.3
|
||||
if: failure()
|
||||
with:
|
||||
name: cypress-screenshots
|
||||
@ -115,7 +122,7 @@ jobs:
|
||||
retention-days: 7
|
||||
|
||||
- name: Export screen recordings (on failure only)
|
||||
uses: actions/upload-artifact@v4.3.3
|
||||
uses: actions/upload-artifact@v4.4.3
|
||||
if: failure()
|
||||
with:
|
||||
name: cypress-videos
|
||||
@ -129,7 +136,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16]
|
||||
node-version: [20]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.4
|
||||
@ -140,7 +147,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Load cached dependencies
|
||||
uses: actions/cache@v4.0.2
|
||||
uses: actions/cache@v4.1.2
|
||||
id: cache
|
||||
with:
|
||||
path: |
|
||||
|
21
.github/workflows/deploy.yml
vendored
21
.github/workflows/deploy.yml
vendored
@ -1,21 +0,0 @@
|
||||
# Automate, customize, and execute your software development workflows right in your repository with GitHub Actions.
|
||||
# Documentation: https://docs.github.com/en/actions
|
||||
|
||||
name: deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
if: github.ref == 'refs/heads/main'
|
||||
|
||||
steps:
|
||||
|
||||
- name: Update the documentation
|
||||
run: curl ${{ secrets.TRIGGER_DEPLOYMENT }}
|
27
.github/workflows/docsearch.yml
vendored
27
.github/workflows/docsearch.yml
vendored
@ -1,27 +0,0 @@
|
||||
# Automate, customize, and execute your software development workflows right in your repository with GitHub Actions.
|
||||
# Documentation: https://docs.github.com/en/actions
|
||||
|
||||
name: docsearch
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '5 0 * * *'
|
||||
|
||||
jobs:
|
||||
|
||||
docsearch:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.4
|
||||
|
||||
- name: Run DocSearch Scraper
|
||||
shell: bash
|
||||
run: |
|
||||
docker run \
|
||||
-e TYPESENSE_API_KEY=${{ secrets.TYPESENSE_API_KEY }} \
|
||||
-e TYPESENSE_HOST="${{ secrets.TYPESENSE_HOST }}" \
|
||||
-e TYPESENSE_PORT="${{ secrets.TYPESENSE_PORT }}" \
|
||||
-e TYPESENSE_PROTOCOL="${{ secrets.TYPESENSE_PROTOCOL }}" \
|
||||
-e CONFIG="$(cat docsearch.config.json | jq -r tostring)" \
|
||||
typesense/docsearch-scraper
|
88
.github/workflows/publish.yml
vendored
Normal file
88
.github/workflows/publish.yml
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
name: Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
# manual trigger for other branches
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [20]
|
||||
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: 'https://registry.npmjs.org/'
|
||||
|
||||
- name: Load cached dependencies
|
||||
uses: actions/cache@v4.1.2
|
||||
id: cache
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
**/.turbo
|
||||
/home/runner/.cache/Cypress
|
||||
key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Create Release PR or publish stable version to npm
|
||||
id: changesets
|
||||
uses: changesets/action@v1
|
||||
with:
|
||||
createGithubReleases: false
|
||||
publish: npm run publish
|
||||
version: npm run version
|
||||
title: ${{ github.ref_name == 'main' && 'Publish a new stable version' || 'Publish a new pre-release version' }}
|
||||
commit: >-
|
||||
${{ github.ref_name == 'main' && 'chore(release): publish a new release version' || 'chore(release): publish a new pre-release version' }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
|
||||
- name: Send release notification
|
||||
if: steps.changesets.outputs.published == 'true'
|
||||
id: slack
|
||||
uses: slackapi/slack-github-action@v1.27.0
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"message": "[Tiptap Editor Release]: New Tiptap Editor version has been released to NPM."
|
||||
}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
|
||||
- name: Send failure notification
|
||||
if: failure()
|
||||
id: slack_failure
|
||||
uses: slackapi/slack-github-action@v1.27.0
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"message": "[Tiptap Editor Release]: There was an issue publishing a new version. You can find the logs here: https://github.com/ueberdosis/tiptap/actions/runs/${{ github.run_id }}"
|
||||
}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
31
.github/workflows/release.yml
vendored
31
.github/workflows/release.yml
vendored
@ -1,31 +0,0 @@
|
||||
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
|
||||
|
||||
name: Release new version
|
||||
|
||||
# on github release published or workflow_dispatch
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
publish-npm:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.4
|
||||
- uses: actions/setup-node@v4.0.0
|
||||
with:
|
||||
node-version: 16
|
||||
registry-url: https://registry.npmjs.org/
|
||||
- run: npm ci
|
||||
- run: npm run publish
|
||||
name: "Publish release (current) to NPM"
|
||||
if: "!github.event.release.prerelease"
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
- run: npm run publish:pre
|
||||
name: "Publish release (next) to NPM"
|
||||
if: "github.event.release.prerelease"
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -17,6 +17,9 @@ yarn-error.log*
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# Turbo cache
|
||||
.turbo
|
||||
|
||||
.rpt2_cache
|
||||
.rts2_cache
|
||||
.rts2_cache_cjs
|
||||
|
@ -1,2 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
npx --no -- commitlint --edit "$1"
|
@ -1,5 +1,11 @@
|
||||
# Change Log
|
||||
|
||||
> **Important information**
|
||||
>
|
||||
> As of version 2.4.1 Tiptap uses **Changesets** which don't allow the generation of one generic CHANGELOG file.
|
||||
> If you want to check changes of a specific package version, check the **CHANGELOG.md** file in the specific package
|
||||
> directory or out [Github Releases](https://github.com/ueberdosis/tiptap/releases)
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
|
@ -36,10 +36,10 @@ Before submitting a pull request:
|
||||
- Check the codebase to ensure that your feature doesn't already exist.
|
||||
- Check the pull requests to ensure that another person hasn't already submitted the feature or fix.
|
||||
|
||||
Before commiting:
|
||||
Before committing:
|
||||
|
||||
- Make sure to run the tests and linter before committing your changes.
|
||||
- Write [conventional commit messages](https://www.conventionalcommits.org/en). You can use `npm run cz` for that.
|
||||
- If you are making changes to one of the packages, make sure to **always** include a [changeset](https://github.com/changesets/changesets) in your PR describing **what changed** with a **description** of the change. Those are responsible for changelog creation
|
||||
|
||||
## Requirements
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023, Tiptap GmbH
|
||||
Copyright (c) 2024, Tiptap GmbH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -86,6 +86,12 @@ For help, discussion about best practices, or any other conversation that would
|
||||
<strong>Basewell</strong>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" width="100">
|
||||
<a href="https://poggio.io">
|
||||
<img src="https://unavatar.io/github/poggiolabs" width="25"><br>
|
||||
<strong>Poggio</strong>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@ -93,7 +99,7 @@ For help, discussion about best practices, or any other conversation that would
|
||||
|
||||
</table>
|
||||
|
||||
[iFixit](https://www.ifixit.com/), [ApostropheCMS](https://apostrophecms.com/), [Novadiscovery](http://www.novadiscovery.com/), [Omics Data Automation](https://www.omicsautomation.com), [Flow Mobile](https://www.flowmobile.app/), [DocIQ](https://www.dociq.io/) and [hundreds of awesome inviduals](https://github.com/sponsors/ueberdosis).
|
||||
[iFixit](https://www.ifixit.com/), [ApostropheCMS](https://apostrophecms.com/), [Novadiscovery](http://www.novadiscovery.com/), [Omics Data Automation](https://www.omicsautomation.com), [Flow Mobile](https://www.flowmobile.app/), [DocIQ](https://www.dociq.io/) and [hundreds of awesome individuals](https://github.com/sponsors/ueberdosis).
|
||||
|
||||
### Contributing
|
||||
Feel like adding some magic of your own to Tiptap Editor Core? We welcome contributions! Please see our [CONTRIBUTING](CONTRIBUTING.md) guidelines for how to get started.
|
||||
|
@ -1,5 +1,31 @@
|
||||
# Change Log
|
||||
|
||||
## 2.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 6834a7f: Bundling of packages no longer includes tiptap dependency type definitions
|
||||
|
||||
## 2.4.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d6e56c4: declare lowlight to be a peer dep of extension-code-block-lowlight, update usage to v3
|
||||
|
||||
## 2.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 85d21ca: Updated demos and reverted vue specific performance enhancements until we know they work
|
||||
|
||||
> in commit ff04353b3ee0e6fc63733a673e2b27d2272a3355 revert: "fix(vue-3): faster component rendering (#5206)"
|
||||
> This reverts commit 31f37464912b7b21f3a565ca63222b9f5b6cce00.
|
||||
|
||||
and
|
||||
|
||||
> in commit dbab8e42eac893a0237566fb30c14b4ed0f3674a revert: "fix(vue-3): fix editor.state updating too late during a transaction due to reactiveState fixes #4870 (#5252)"
|
||||
> This reverts commit 509676ed4a63b84b904a98c1e34d18449d25c2a7.
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
@ -7,868 +33,480 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.3.2](https://github.com/ueberdosis/tiptap/compare/v2.3.1...v2.3.2) (2024-05-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* NodePos querySelectorAll function ([#5094](https://github.com/ueberdosis/tiptap/issues/5094)) ([4900a27](https://github.com/ueberdosis/tiptap/commit/4900a27c5389d9a2d0d69f407ca3db0155304315))
|
||||
|
||||
|
||||
|
||||
|
||||
- NodePos querySelectorAll function ([#5094](https://github.com/ueberdosis/tiptap/issues/5094)) ([4900a27](https://github.com/ueberdosis/tiptap/commit/4900a27c5389d9a2d0d69f407ca3db0155304315))
|
||||
|
||||
## [2.3.1](https://github.com/ueberdosis/tiptap/compare/v2.3.0...v2.3.1) (2024-04-30)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.3.0](https://github.com/ueberdosis/tiptap/compare/v2.2.6...v2.3.0) (2024-04-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** fix nodepos child lookup ([#5038](https://github.com/ueberdosis/tiptap/issues/5038)) ([22ced31](https://github.com/ueberdosis/tiptap/commit/22ced318723003365fbfd8f59b8dac79c7563017))
|
||||
|
||||
- **core:** fix nodepos child lookup ([#5038](https://github.com/ueberdosis/tiptap/issues/5038)) ([22ced31](https://github.com/ueberdosis/tiptap/commit/22ced318723003365fbfd8f59b8dac79c7563017))
|
||||
|
||||
### Features
|
||||
|
||||
* **core:** apply input and paste rules when using insertContent methods ([#5046](https://github.com/ueberdosis/tiptap/issues/5046)) ([96b6abc](https://github.com/ueberdosis/tiptap/commit/96b6abcf6edbc6cac03a391130d9feebb6de3a04))
|
||||
|
||||
|
||||
|
||||
|
||||
- **core:** apply input and paste rules when using insertContent methods ([#5046](https://github.com/ueberdosis/tiptap/issues/5046)) ([96b6abc](https://github.com/ueberdosis/tiptap/commit/96b6abcf6edbc6cac03a391130d9feebb6de3a04))
|
||||
|
||||
## [2.2.6](https://github.com/ueberdosis/tiptap/compare/v2.2.5...v2.2.6) (2024-04-06)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.2.5](https://github.com/ueberdosis/tiptap/compare/v2.2.4...v2.2.5) (2024-04-05)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.2.4](https://github.com/ueberdosis/tiptap/compare/v2.2.3...v2.2.4) (2024-02-23)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.2.3](https://github.com/ueberdosis/tiptap/compare/v2.2.2...v2.2.3) (2024-02-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix test path ([21aa96d](https://github.com/ueberdosis/tiptap/commit/21aa96dee8deab1f439b7f655b8ed266a516a4cd))
|
||||
|
||||
|
||||
|
||||
|
||||
- fix test path ([21aa96d](https://github.com/ueberdosis/tiptap/commit/21aa96dee8deab1f439b7f655b8ed266a516a4cd))
|
||||
|
||||
## [2.2.2](https://github.com/ueberdosis/tiptap/compare/v2.2.1...v2.2.2) (2024-02-07)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.2.1](https://github.com/ueberdosis/tiptap/compare/v2.2.0...v2.2.1) (2024-01-31)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.2.0](https://github.com/ueberdosis/tiptap/compare/v2.1.16...v2.2.0) (2024-01-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** fix new lines being added via elementFromString ([#4767](https://github.com/ueberdosis/tiptap/issues/4767)) ([b7a2504](https://github.com/ueberdosis/tiptap/commit/b7a2504f16f46563537c890930cb2c332c256175))
|
||||
* fix imports, fix demos, unpin y-prosemirror ([681aa57](https://github.com/ueberdosis/tiptap/commit/681aa577bff500015c3f925e300c55a71c73efaf))
|
||||
* fix newline stripping via insertContent ([8954007](https://github.com/ueberdosis/tiptap/commit/8954007b2b92b040d69b26a0866ae58fabf5e512))
|
||||
|
||||
|
||||
- **core:** fix new lines being added via elementFromString ([#4767](https://github.com/ueberdosis/tiptap/issues/4767)) ([b7a2504](https://github.com/ueberdosis/tiptap/commit/b7a2504f16f46563537c890930cb2c332c256175))
|
||||
- fix imports, fix demos, unpin y-prosemirror ([681aa57](https://github.com/ueberdosis/tiptap/commit/681aa577bff500015c3f925e300c55a71c73efaf))
|
||||
- fix newline stripping via insertContent ([8954007](https://github.com/ueberdosis/tiptap/commit/8954007b2b92b040d69b26a0866ae58fabf5e512))
|
||||
|
||||
# [2.2.0-rc.8](https://github.com/ueberdosis/tiptap/compare/v2.1.14...v2.2.0-rc.8) (2024-01-08)
|
||||
|
||||
|
||||
|
||||
# [2.2.0-rc.7](https://github.com/ueberdosis/tiptap/compare/v2.2.0-rc.6...v2.2.0-rc.7) (2023-11-27)
|
||||
|
||||
|
||||
|
||||
# [2.2.0-rc.6](https://github.com/ueberdosis/tiptap/compare/v2.2.0-rc.5...v2.2.0-rc.6) (2023-11-23)
|
||||
|
||||
|
||||
|
||||
# [2.2.0-rc.4](https://github.com/ueberdosis/tiptap/compare/v2.1.11...v2.2.0-rc.4) (2023-10-10)
|
||||
|
||||
|
||||
|
||||
# [2.2.0-rc.3](https://github.com/ueberdosis/tiptap/compare/v2.2.0-rc.2...v2.2.0-rc.3) (2023-08-18)
|
||||
|
||||
|
||||
|
||||
# [2.2.0-rc.1](https://github.com/ueberdosis/tiptap/compare/v2.2.0-rc.0...v2.2.0-rc.1) (2023-08-18)
|
||||
|
||||
|
||||
|
||||
# [2.2.0-rc.0](https://github.com/ueberdosis/tiptap/compare/v2.1.5...v2.2.0-rc.0) (2023-08-18)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **placeholder:** allow editor-is-empty class on any node ([#4335](https://github.com/ueberdosis/tiptap/issues/4335)) ([ff929b1](https://github.com/ueberdosis/tiptap/commit/ff929b179de930619005a773bb4186ae2aa2ec58))
|
||||
|
||||
|
||||
|
||||
|
||||
- **placeholder:** allow editor-is-empty class on any node ([#4335](https://github.com/ueberdosis/tiptap/issues/4335)) ([ff929b1](https://github.com/ueberdosis/tiptap/commit/ff929b179de930619005a773bb4186ae2aa2ec58))
|
||||
|
||||
## [2.1.16](https://github.com/ueberdosis/tiptap/compare/v2.1.15...v2.1.16) (2024-01-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** fix new lines being added via elementFromString ([#4767](https://github.com/ueberdosis/tiptap/issues/4767)) ([2235908](https://github.com/ueberdosis/tiptap/commit/2235908c28f388eda041d1d5d017554d513fe909))
|
||||
|
||||
|
||||
|
||||
|
||||
- **core:** fix new lines being added via elementFromString ([#4767](https://github.com/ueberdosis/tiptap/issues/4767)) ([2235908](https://github.com/ueberdosis/tiptap/commit/2235908c28f388eda041d1d5d017554d513fe909))
|
||||
|
||||
## [2.1.15](https://github.com/ueberdosis/tiptap/compare/v2.1.14...v2.1.15) (2024-01-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** fix insertContentAt keeping new lines in html content ([#4465](https://github.com/ueberdosis/tiptap/issues/4465)) ([135a12f](https://github.com/ueberdosis/tiptap/commit/135a12f7aa2df839a0b619704110a360b980c738))
|
||||
* **link:** fix tests ([d495d92](https://github.com/ueberdosis/tiptap/commit/d495d92a1f7b1c51e09ac8f4934e15a2d1cf070d))
|
||||
|
||||
|
||||
|
||||
|
||||
- **core:** fix insertContentAt keeping new lines in html content ([#4465](https://github.com/ueberdosis/tiptap/issues/4465)) ([135a12f](https://github.com/ueberdosis/tiptap/commit/135a12f7aa2df839a0b619704110a360b980c738))
|
||||
- **link:** fix tests ([d495d92](https://github.com/ueberdosis/tiptap/commit/d495d92a1f7b1c51e09ac8f4934e15a2d1cf070d))
|
||||
|
||||
## [2.1.14](https://github.com/ueberdosis/tiptap/compare/v2.1.13...v2.1.14) (2024-01-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **typography:** require spaces after divisions to not break date formats ([#4696](https://github.com/ueberdosis/tiptap/issues/4696)) ([f6d7e00](https://github.com/ueberdosis/tiptap/commit/f6d7e00a746a67fa440a3fa0f5362295959873d2))
|
||||
|
||||
|
||||
|
||||
|
||||
- **typography:** require spaces after divisions to not break date formats ([#4696](https://github.com/ueberdosis/tiptap/issues/4696)) ([f6d7e00](https://github.com/ueberdosis/tiptap/commit/f6d7e00a746a67fa440a3fa0f5362295959873d2))
|
||||
|
||||
## [2.1.13](https://github.com/ueberdosis/tiptap/compare/v2.1.12...v2.1.13) (2023-11-30)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.12](https://github.com/ueberdosis/tiptap/compare/v2.1.11...v2.1.12) (2023-10-11)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.11](https://github.com/ueberdosis/tiptap/compare/v2.1.10...v2.1.11) (2023-09-20)
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "v2.2.11" ([6aa755a](https://github.com/ueberdosis/tiptap/commit/6aa755a04b9955fc175c7ab33dee527d0d5deef0))
|
||||
|
||||
|
||||
|
||||
|
||||
- Revert "v2.2.11" ([6aa755a](https://github.com/ueberdosis/tiptap/commit/6aa755a04b9955fc175c7ab33dee527d0d5deef0))
|
||||
|
||||
## [2.1.10](https://github.com/ueberdosis/tiptap/compare/v2.1.9...v2.1.10) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.9](https://github.com/ueberdosis/tiptap/compare/v2.1.8...v2.1.9) (2023-09-14)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.8](https://github.com/ueberdosis/tiptap-workspace/compare/v2.1.7...v2.1.8) (2023-09-04)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.7](https://github.com/ueberdosis/tiptap-workspace/compare/v2.1.6...v2.1.7) (2023-09-04)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.6](https://github.com/ueberdosis/tiptap/compare/v2.1.5...v2.1.6) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.2.0-rc.2](https://github.com/ueberdosis/tiptap/compare/v2.1.6...v2.2.0-rc.2) (2023-08-18)
|
||||
|
||||
|
||||
|
||||
# [2.2.0-rc.1](https://github.com/ueberdosis/tiptap/compare/v2.2.0-rc.0...v2.2.0-rc.1) (2023-08-18)
|
||||
|
||||
|
||||
|
||||
# [2.2.0-rc.0](https://github.com/ueberdosis/tiptap/compare/v2.1.5...v2.2.0-rc.0) (2023-08-18)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **placeholder:** allow editor-is-empty class on any node ([#4335](https://github.com/ueberdosis/tiptap/issues/4335)) ([ff929b1](https://github.com/ueberdosis/tiptap/commit/ff929b179de930619005a773bb4186ae2aa2ec58))
|
||||
|
||||
|
||||
|
||||
|
||||
- **placeholder:** allow editor-is-empty class on any node ([#4335](https://github.com/ueberdosis/tiptap/issues/4335)) ([ff929b1](https://github.com/ueberdosis/tiptap/commit/ff929b179de930619005a773bb4186ae2aa2ec58))
|
||||
|
||||
# [2.2.0-rc.1](https://github.com/ueberdosis/tiptap/compare/v2.2.0-rc.0...v2.2.0-rc.1) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
# [2.2.0-rc.0](https://github.com/ueberdosis/tiptap/compare/v2.1.5...v2.2.0-rc.0) (2023-08-18)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **placeholder:** allow editor-is-empty class on any node ([#4335](https://github.com/ueberdosis/tiptap/issues/4335)) ([ff929b1](https://github.com/ueberdosis/tiptap/commit/ff929b179de930619005a773bb4186ae2aa2ec58))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- **placeholder:** allow editor-is-empty class on any node ([#4335](https://github.com/ueberdosis/tiptap/issues/4335)) ([ff929b1](https://github.com/ueberdosis/tiptap/commit/ff929b179de930619005a773bb4186ae2aa2ec58))
|
||||
|
||||
## [2.1.6](https://github.com/ueberdosis/tiptap/compare/v2.1.5...v2.1.6) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.5](https://github.com/ueberdosis/tiptap/compare/v2.1.4...v2.1.5) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.4](https://github.com/ueberdosis/tiptap/compare/v2.1.3...v2.1.4) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.3](https://github.com/ueberdosis/tiptap/compare/v2.1.2...v2.1.3) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.2](https://github.com/ueberdosis/tiptap/compare/v2.1.1...v2.1.2) (2023-08-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** fix error when merging class attributes ([#4340](https://github.com/ueberdosis/tiptap/issues/4340)) ([a251946](https://github.com/ueberdosis/tiptap/commit/a2519468589e2baa44901a66a3a06b24dc8626d6))
|
||||
|
||||
|
||||
|
||||
|
||||
- **core:** fix error when merging class attributes ([#4340](https://github.com/ueberdosis/tiptap/issues/4340)) ([a251946](https://github.com/ueberdosis/tiptap/commit/a2519468589e2baa44901a66a3a06b24dc8626d6))
|
||||
|
||||
## [2.1.1](https://github.com/ueberdosis/tiptap/compare/v2.1.0...v2.1.1) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.1.0](https://github.com/ueberdosis/tiptap-workspace/compare/v2.1.0-rc.14...v2.1.0) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.1.0-rc.14](https://github.com/ueberdosis/tiptap-workspace/compare/v2.1.0-rc.13...v2.1.0-rc.14) (2023-08-11)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.1.0-rc.13](https://github.com/ueberdosis/tiptap-workspace/compare/v2.0.4...v2.1.0-rc.13) (2023-08-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **demos:** add missing extensions ([6383fd5](https://github.com/ueberdosis/tiptap-workspace/commit/6383fd54080b2ad555286cd0e7c4ad880200200f))
|
||||
* **demos:** update deps ([05a2edf](https://github.com/ueberdosis/tiptap-workspace/commit/05a2edfc16e297effa86d1583fb1680be0320f25))
|
||||
* **strikethrough:** update strikethrough shortcut ([#4288](https://github.com/ueberdosis/tiptap-workspace/issues/4288)) ([fd35db4](https://github.com/ueberdosis/tiptap-workspace/commit/fd35db4d090d9fdfef1196fb1f6f858f13cf53d1))
|
||||
|
||||
|
||||
- **demos:** add missing extensions ([6383fd5](https://github.com/ueberdosis/tiptap-workspace/commit/6383fd54080b2ad555286cd0e7c4ad880200200f))
|
||||
- **demos:** update deps ([05a2edf](https://github.com/ueberdosis/tiptap-workspace/commit/05a2edfc16e297effa86d1583fb1680be0320f25))
|
||||
- **strikethrough:** update strikethrough shortcut ([#4288](https://github.com/ueberdosis/tiptap-workspace/issues/4288)) ([fd35db4](https://github.com/ueberdosis/tiptap-workspace/commit/fd35db4d090d9fdfef1196fb1f6f858f13cf53d1))
|
||||
|
||||
# [2.1.0-rc.12](https://github.com/ueberdosis/tiptap-workspace/compare/v2.1.0-rc.11...v2.1.0-rc.12) (2023-07-14)
|
||||
|
||||
|
||||
|
||||
# [2.1.0-rc.11](https://github.com/ueberdosis/tiptap-workspace/compare/v2.1.0-rc.10...v2.1.0-rc.11) (2023-07-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **tests:** fix link rel tests ([c1d1854](https://github.com/ueberdosis/tiptap-workspace/commit/c1d18543b03b1fb6b99a2f3546aa5da10c919920))
|
||||
|
||||
|
||||
- **tests:** fix link rel tests ([c1d1854](https://github.com/ueberdosis/tiptap-workspace/commit/c1d18543b03b1fb6b99a2f3546aa5da10c919920))
|
||||
|
||||
# [2.1.0-rc.10](https://github.com/ueberdosis/tiptap-workspace/compare/v2.1.0-rc.9...v2.1.0-rc.10) (2023-07-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **react:** check props.clientRect before creating ReactRenderer ([#4138](https://github.com/ueberdosis/tiptap-workspace/issues/4138)) ([d710846](https://github.com/ueberdosis/tiptap-workspace/commit/d710846ecb6a3059dfbc21300b9a4b887a8defa3))
|
||||
|
||||
|
||||
- **react:** check props.clientRect before creating ReactRenderer ([#4138](https://github.com/ueberdosis/tiptap-workspace/issues/4138)) ([d710846](https://github.com/ueberdosis/tiptap-workspace/commit/d710846ecb6a3059dfbc21300b9a4b887a8defa3))
|
||||
|
||||
# [2.1.0-rc.9](https://github.com/ueberdosis/tiptap-workspace/compare/v2.1.0-rc.8...v2.1.0-rc.9) (2023-06-15)
|
||||
|
||||
|
||||
|
||||
# [2.1.0-rc.8](https://github.com/ueberdosis/tiptap-workspace/compare/v2.1.0-rc.7...v2.1.0-rc.8) (2023-05-25)
|
||||
|
||||
|
||||
|
||||
# [2.1.0-rc.5](https://github.com/ueberdosis/tiptap-workspace/compare/v2.1.0-rc.4...v2.1.0-rc.5) (2023-05-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add tiptap class ([614fc80](https://github.com/ueberdosis/tiptap-workspace/commit/614fc8082c376bf3c40a05c23ceda6b4a6fbf8d0))
|
||||
|
||||
|
||||
- add tiptap class ([614fc80](https://github.com/ueberdosis/tiptap-workspace/commit/614fc8082c376bf3c40a05c23ceda6b4a6fbf8d0))
|
||||
|
||||
# [2.1.0-rc.4](https://github.com/ueberdosis/tiptap-workspace/compare/v2.1.0-rc.3...v2.1.0-rc.4) (2023-04-27)
|
||||
|
||||
|
||||
|
||||
# [2.1.0-rc.3](https://github.com/ueberdosis/tiptap-workspace/compare/v2.1.0-rc.2...v2.1.0-rc.3) (2023-04-26)
|
||||
|
||||
|
||||
|
||||
# [2.1.0-rc.2](https://github.com/ueberdosis/tiptap-workspace/compare/v2.0.3...v2.1.0-rc.2) (2023-04-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **extension-link:** fix link not being kept when pasting url with link ([#3975](https://github.com/ueberdosis/tiptap-workspace/issues/3975)) ([e7d7d49](https://github.com/ueberdosis/tiptap-workspace/commit/e7d7d496376c8c11e24c342e20bd179a6ea7dcee))
|
||||
|
||||
|
||||
- **extension-link:** fix link not being kept when pasting url with link ([#3975](https://github.com/ueberdosis/tiptap-workspace/issues/3975)) ([e7d7d49](https://github.com/ueberdosis/tiptap-workspace/commit/e7d7d496376c8c11e24c342e20bd179a6ea7dcee))
|
||||
|
||||
# [2.1.0-rc.1](https://github.com/ueberdosis/tiptap-workspace/compare/v2.1.0-rc.0...v2.1.0-rc.1) (2023-04-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bubble-menu:** fix debounce not working with collab/collaboration cursor ([#3956](https://github.com/ueberdosis/tiptap-workspace/issues/3956)) ([e8cef04](https://github.com/ueberdosis/tiptap-workspace/commit/e8cef0404b5039ec2657536976b8b31931afd337))
|
||||
|
||||
|
||||
- **bubble-menu:** fix debounce not working with collab/collaboration cursor ([#3956](https://github.com/ueberdosis/tiptap-workspace/issues/3956)) ([e8cef04](https://github.com/ueberdosis/tiptap-workspace/commit/e8cef0404b5039ec2657536976b8b31931afd337))
|
||||
|
||||
# [2.1.0-rc.0](https://github.com/ueberdosis/tiptap-workspace/compare/v2.0.2...v2.1.0-rc.0) (2023-04-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* clear nodes when cursor at start of empty isolating parent ([#3943](https://github.com/ueberdosis/tiptap-workspace/issues/3943)) ([7278ee2](https://github.com/ueberdosis/tiptap-workspace/commit/7278ee2b05de2f96efddf3b1dc3bfd3d52262cbb))
|
||||
* Update peerDependencies to fix lerna version tasks ([#3914](https://github.com/ueberdosis/tiptap-workspace/issues/3914)) ([0c1bba3](https://github.com/ueberdosis/tiptap-workspace/commit/0c1bba3137b535776bcef95ff3c55e13f5a2db46))
|
||||
|
||||
|
||||
|
||||
|
||||
- clear nodes when cursor at start of empty isolating parent ([#3943](https://github.com/ueberdosis/tiptap-workspace/issues/3943)) ([7278ee2](https://github.com/ueberdosis/tiptap-workspace/commit/7278ee2b05de2f96efddf3b1dc3bfd3d52262cbb))
|
||||
- Update peerDependencies to fix lerna version tasks ([#3914](https://github.com/ueberdosis/tiptap-workspace/issues/3914)) ([0c1bba3](https://github.com/ueberdosis/tiptap-workspace/commit/0c1bba3137b535776bcef95ff3c55e13f5a2db46))
|
||||
|
||||
# [2.1.0-rc.12](https://github.com/ueberdosis/tiptap-workspace/compare/v2.1.0-rc.11...v2.1.0-rc.12) (2023-07-14)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.1.0-rc.11](https://github.com/ueberdosis/tiptap/compare/v2.1.0-rc.10...v2.1.0-rc.11) (2023-07-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **tests:** fix link rel tests ([c1d1854](https://github.com/ueberdosis/tiptap/commit/c1d18543b03b1fb6b99a2f3546aa5da10c919920))
|
||||
|
||||
|
||||
|
||||
|
||||
- **tests:** fix link rel tests ([c1d1854](https://github.com/ueberdosis/tiptap/commit/c1d18543b03b1fb6b99a2f3546aa5da10c919920))
|
||||
|
||||
# [2.1.0-rc.10](https://github.com/ueberdosis/tiptap/compare/v2.1.0-rc.9...v2.1.0-rc.10) (2023-07-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **react:** check props.clientRect before creating ReactRenderer ([#4138](https://github.com/ueberdosis/tiptap/issues/4138)) ([d710846](https://github.com/ueberdosis/tiptap/commit/d710846ecb6a3059dfbc21300b9a4b887a8defa3))
|
||||
|
||||
|
||||
|
||||
|
||||
- **react:** check props.clientRect before creating ReactRenderer ([#4138](https://github.com/ueberdosis/tiptap/issues/4138)) ([d710846](https://github.com/ueberdosis/tiptap/commit/d710846ecb6a3059dfbc21300b9a4b887a8defa3))
|
||||
|
||||
# [2.1.0-rc.9](https://github.com/ueberdosis/tiptap/compare/v2.1.0-rc.8...v2.1.0-rc.9) (2023-06-15)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.1.0-rc.8](https://github.com/ueberdosis/tiptap/compare/v2.1.0-rc.7...v2.1.0-rc.8) (2023-05-25)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.1.0-rc.7](https://github.com/ueberdosis/tiptap/compare/v2.1.0-rc.6...v2.1.0-rc.7) (2023-05-25)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.1.0-rc.6](https://github.com/ueberdosis/tiptap/compare/v2.1.0-rc.5...v2.1.0-rc.6) (2023-05-25)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.1.0-rc.5](https://github.com/ueberdosis/tiptap/compare/v2.1.0-rc.4...v2.1.0-rc.5) (2023-05-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add tiptap class ([614fc80](https://github.com/ueberdosis/tiptap/commit/614fc8082c376bf3c40a05c23ceda6b4a6fbf8d0))
|
||||
|
||||
|
||||
|
||||
|
||||
- add tiptap class ([614fc80](https://github.com/ueberdosis/tiptap/commit/614fc8082c376bf3c40a05c23ceda6b4a6fbf8d0))
|
||||
|
||||
# [2.1.0-rc.4](https://github.com/ueberdosis/tiptap/compare/v2.1.0-rc.3...v2.1.0-rc.4) (2023-04-27)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.1.0-rc.3](https://github.com/ueberdosis/tiptap/compare/v2.1.0-rc.2...v2.1.0-rc.3) (2023-04-26)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.1.0-rc.2](https://github.com/ueberdosis/tiptap/compare/v2.0.3...v2.1.0-rc.2) (2023-04-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **extension-link:** fix link not being kept when pasting url with link ([#3975](https://github.com/ueberdosis/tiptap/issues/3975)) ([e7d7d49](https://github.com/ueberdosis/tiptap/commit/e7d7d496376c8c11e24c342e20bd179a6ea7dcee))
|
||||
|
||||
|
||||
- **extension-link:** fix link not being kept when pasting url with link ([#3975](https://github.com/ueberdosis/tiptap/issues/3975)) ([e7d7d49](https://github.com/ueberdosis/tiptap/commit/e7d7d496376c8c11e24c342e20bd179a6ea7dcee))
|
||||
|
||||
# [2.1.0-rc.1](https://github.com/ueberdosis/tiptap/compare/v2.1.0-rc.0...v2.1.0-rc.1) (2023-04-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bubble-menu:** fix debounce not working with collab/collaboration cursor ([#3956](https://github.com/ueberdosis/tiptap/issues/3956)) ([e8cef04](https://github.com/ueberdosis/tiptap/commit/e8cef0404b5039ec2657536976b8b31931afd337))
|
||||
|
||||
|
||||
- **bubble-menu:** fix debounce not working with collab/collaboration cursor ([#3956](https://github.com/ueberdosis/tiptap/issues/3956)) ([e8cef04](https://github.com/ueberdosis/tiptap/commit/e8cef0404b5039ec2657536976b8b31931afd337))
|
||||
|
||||
# [2.1.0-rc.0](https://github.com/ueberdosis/tiptap/compare/v2.0.2...v2.1.0-rc.0) (2023-04-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* clear nodes when cursor at start of empty isolating parent ([#3943](https://github.com/ueberdosis/tiptap/issues/3943)) ([7278ee2](https://github.com/ueberdosis/tiptap/commit/7278ee2b05de2f96efddf3b1dc3bfd3d52262cbb))
|
||||
* Update peerDependencies to fix lerna version tasks ([#3914](https://github.com/ueberdosis/tiptap/issues/3914)) ([0c1bba3](https://github.com/ueberdosis/tiptap/commit/0c1bba3137b535776bcef95ff3c55e13f5a2db46))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- clear nodes when cursor at start of empty isolating parent ([#3943](https://github.com/ueberdosis/tiptap/issues/3943)) ([7278ee2](https://github.com/ueberdosis/tiptap/commit/7278ee2b05de2f96efddf3b1dc3bfd3d52262cbb))
|
||||
- Update peerDependencies to fix lerna version tasks ([#3914](https://github.com/ueberdosis/tiptap/issues/3914)) ([0c1bba3](https://github.com/ueberdosis/tiptap/commit/0c1bba3137b535776bcef95ff3c55e13f5a2db46))
|
||||
|
||||
# [2.1.0-rc.0](https://github.com/ueberdosis/tiptap/compare/v2.0.2...v2.1.0-rc.0) (2023-04-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* clear nodes when cursor at start of empty isolating parent ([#3943](https://github.com/ueberdosis/tiptap/issues/3943)) ([7278ee2](https://github.com/ueberdosis/tiptap/commit/7278ee2b05de2f96efddf3b1dc3bfd3d52262cbb))
|
||||
* **bubble-menu:** fix debounce not working with collab/collaboration cursor ([#3956](https://github.com/ueberdosis/tiptap/issues/3956)) ([a78f8cd](https://github.com/ueberdosis/tiptap/commit/a78f8cd9646008e4db938fa3c22b0714c8bb5849))
|
||||
|
||||
|
||||
|
||||
- clear nodes when cursor at start of empty isolating parent ([#3943](https://github.com/ueberdosis/tiptap/issues/3943)) ([7278ee2](https://github.com/ueberdosis/tiptap/commit/7278ee2b05de2f96efddf3b1dc3bfd3d52262cbb))
|
||||
- **bubble-menu:** fix debounce not working with collab/collaboration cursor ([#3956](https://github.com/ueberdosis/tiptap/issues/3956)) ([a78f8cd](https://github.com/ueberdosis/tiptap/commit/a78f8cd9646008e4db938fa3c22b0714c8bb5849))
|
||||
|
||||
## [2.0.3](https://github.com/ueberdosis/tiptap/compare/v2.0.2...v2.0.3) (2023-04-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bubble-menu:** fix debounce not working with collab/collaboration cursor ([#3956](https://github.com/ueberdosis/tiptap/issues/3956)) ([e8cef04](https://github.com/ueberdosis/tiptap/commit/e8cef0404b5039ec2657536976b8b31931afd337))
|
||||
|
||||
|
||||
|
||||
|
||||
- **bubble-menu:** fix debounce not working with collab/collaboration cursor ([#3956](https://github.com/ueberdosis/tiptap/issues/3956)) ([e8cef04](https://github.com/ueberdosis/tiptap/commit/e8cef0404b5039ec2657536976b8b31931afd337))
|
||||
|
||||
## [2.0.2](https://github.com/ueberdosis/tiptap/compare/v2.0.1...v2.0.2) (2023-04-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add box-shadow to collab demo ([c5496c1](https://github.com/ueberdosis/tiptap/commit/c5496c1b27783150dafb5ebdf6bda43648a46316))
|
||||
* landingpage demo ([#3925](https://github.com/ueberdosis/tiptap/issues/3925)) ([958925f](https://github.com/ueberdosis/tiptap/commit/958925f2560ca786cd0cf52b83b7ae51deb7dd77))
|
||||
* Tiptap collab demo styling ([87840b0](https://github.com/ueberdosis/tiptap/commit/87840b0f0821ca65d9f104d9c90512021aa70113))
|
||||
|
||||
|
||||
|
||||
|
||||
- add box-shadow to collab demo ([c5496c1](https://github.com/ueberdosis/tiptap/commit/c5496c1b27783150dafb5ebdf6bda43648a46316))
|
||||
- landingpage demo ([#3925](https://github.com/ueberdosis/tiptap/issues/3925)) ([958925f](https://github.com/ueberdosis/tiptap/commit/958925f2560ca786cd0cf52b83b7ae51deb7dd77))
|
||||
- Tiptap collab demo styling ([87840b0](https://github.com/ueberdosis/tiptap/commit/87840b0f0821ca65d9f104d9c90512021aa70113))
|
||||
|
||||
## [2.0.1](https://github.com/ueberdosis/tiptap/compare/v2.0.0...v2.0.1) (2023-03-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Update peerDependencies to fix lerna version tasks ([#3914](https://github.com/ueberdosis/tiptap/issues/3914)) ([0534f76](https://github.com/ueberdosis/tiptap/commit/0534f76401bf5399c01ca7f39d87f7221d91b4f7))
|
||||
|
||||
|
||||
|
||||
|
||||
- Update peerDependencies to fix lerna version tasks ([#3914](https://github.com/ueberdosis/tiptap/issues/3914)) ([0534f76](https://github.com/ueberdosis/tiptap/commit/0534f76401bf5399c01ca7f39d87f7221d91b4f7))
|
||||
|
||||
# [2.0.0-beta.220](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.219...v2.0.0-beta.220) (2023-02-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** fix destroyed view causing errors on dispatchTransaction ([#3799](https://github.com/ueberdosis/tiptap/issues/3799)) ([3c07ca0](https://github.com/ueberdosis/tiptap/commit/3c07ca0b9c48cef60d56acdd44812e20e05fc928))
|
||||
* **tests:** fix tests for lists ([02eec8a](https://github.com/ueberdosis/tiptap/commit/02eec8aaefc2709dc20f91c3c8f9eca84cddc12d))
|
||||
|
||||
|
||||
|
||||
|
||||
- **core:** fix destroyed view causing errors on dispatchTransaction ([#3799](https://github.com/ueberdosis/tiptap/issues/3799)) ([3c07ca0](https://github.com/ueberdosis/tiptap/commit/3c07ca0b9c48cef60d56acdd44812e20e05fc928))
|
||||
- **tests:** fix tests for lists ([02eec8a](https://github.com/ueberdosis/tiptap/commit/02eec8aaefc2709dc20f91c3c8f9eca84cddc12d))
|
||||
|
||||
# [2.0.0-beta.219](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.218...v2.0.0-beta.219) (2023-02-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** allow insertContentAt and insertContent text node arrays ([#3790](https://github.com/ueberdosis/tiptap/issues/3790)) ([0300630](https://github.com/ueberdosis/tiptap/commit/0300630a5b04b61d4eef8155f24ca0ef2d683966))
|
||||
|
||||
- **core:** allow insertContentAt and insertContent text node arrays ([#3790](https://github.com/ueberdosis/tiptap/issues/3790)) ([0300630](https://github.com/ueberdosis/tiptap/commit/0300630a5b04b61d4eef8155f24ca0ef2d683966))
|
||||
|
||||
### Features
|
||||
|
||||
* [#3540](https://github.com/ueberdosis/tiptap/issues/3540) Ability to preserve marks on lists ([#3541](https://github.com/ueberdosis/tiptap/issues/3541)) ([36bb1e1](https://github.com/ueberdosis/tiptap/commit/36bb1e1041f91da6437272e7196702df868eae0f))
|
||||
|
||||
|
||||
|
||||
|
||||
- [#3540](https://github.com/ueberdosis/tiptap/issues/3540) Ability to preserve marks on lists ([#3541](https://github.com/ueberdosis/tiptap/issues/3541)) ([36bb1e1](https://github.com/ueberdosis/tiptap/commit/36bb1e1041f91da6437272e7196702df868eae0f))
|
||||
|
||||
# [2.0.0-beta.218](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.217...v2.0.0-beta.218) (2023-02-18)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.217](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.216...v2.0.0-beta.217) (2023-02-09)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.216](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.215...v2.0.0-beta.216) (2023-02-08)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.215](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.214...v2.0.0-beta.215) (2023-02-08)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.214](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.213...v2.0.0-beta.214) (2023-02-08)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.213](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.212...v2.0.0-beta.213) (2023-02-07)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.212](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.211...v2.0.0-beta.212) (2023-02-03)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.211](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.210...v2.0.0-beta.211) (2023-02-02)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.210](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.209...v2.0.0-beta.210) (2023-02-02)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **pm:** new prosemirror package for dependency resolving ([f387ad3](https://github.com/ueberdosis/tiptap/commit/f387ad3dd4c2b30eaea33fb0ba0b42e0cd39263b))
|
||||
|
||||
|
||||
|
||||
|
||||
- **pm:** new prosemirror package for dependency resolving ([f387ad3](https://github.com/ueberdosis/tiptap/commit/f387ad3dd4c2b30eaea33fb0ba0b42e0cd39263b))
|
||||
|
||||
# [2.0.0-beta.209](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.208...v2.0.0-beta.209) (2022-12-16)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.208](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.207...v2.0.0-beta.208) (2022-12-16)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.207](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.206...v2.0.0-beta.207) (2022-12-08)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.206](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.205...v2.0.0-beta.206) (2022-12-08)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.205](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.204...v2.0.0-beta.205) (2022-12-05)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.204](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.203...v2.0.0-beta.204) (2022-11-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **tests:** fix autolink validation test ([5150095](https://github.com/ueberdosis/tiptap/commit/5150095c6b510c080f4aa35f54d2387543f86da8))
|
||||
|
||||
|
||||
|
||||
|
||||
- **tests:** fix autolink validation test ([5150095](https://github.com/ueberdosis/tiptap/commit/5150095c6b510c080f4aa35f54d2387543f86da8))
|
||||
|
||||
# [2.0.0-beta.203](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.202...v2.0.0-beta.203) (2022-11-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **extension/table:** move dependency from @_ueberdosis to [@tiptap](https://github.com/tiptap) ([#3448](https://github.com/ueberdosis/tiptap/issues/3448)) ([31c3a9a](https://github.com/ueberdosis/tiptap/commit/31c3a9aad9eb37f445eadcd27135611291178ca6))
|
||||
|
||||
|
||||
|
||||
|
||||
- **extension/table:** move dependency from @\_ueberdosis to [@tiptap](https://github.com/tiptap) ([#3448](https://github.com/ueberdosis/tiptap/issues/3448)) ([31c3a9a](https://github.com/ueberdosis/tiptap/commit/31c3a9aad9eb37f445eadcd27135611291178ca6))
|
||||
|
||||
# [2.0.0-beta.202](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.201...v2.0.0-beta.202) (2022-11-04)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.201](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.200...v2.0.0-beta.201) (2022-11-04)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.200](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.199...v2.0.0-beta.200) (2022-11-04)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.199](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.198...v2.0.0-beta.199) (2022-09-30)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.198](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.197...v2.0.0-beta.198) (2022-09-29)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.197](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.196...v2.0.0-beta.197) (2022-09-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** Can() does not work for setting marks ([#3223](https://github.com/ueberdosis/tiptap/issues/3223)) ([17a41da](https://github.com/ueberdosis/tiptap/commit/17a41da5a7a14879cf490c81914084791c4c494c))
|
||||
|
||||
|
||||
|
||||
|
||||
- **core:** Can() does not work for setting marks ([#3223](https://github.com/ueberdosis/tiptap/issues/3223)) ([17a41da](https://github.com/ueberdosis/tiptap/commit/17a41da5a7a14879cf490c81914084791c4c494c))
|
||||
|
||||
# [2.0.0-beta.196](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.195...v2.0.0-beta.196) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.195](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.194...v2.0.0-beta.195) (2022-09-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **extension/bubble-menu:** :bug: fix bubble menu and floating menu being available when editor not editable ([#3195](https://github.com/ueberdosis/tiptap/issues/3195)) ([fa96749](https://github.com/ueberdosis/tiptap/commit/fa96749ce22ec67125da491cfeeb38623b9f0d6e))
|
||||
|
||||
|
||||
|
||||
|
||||
- **extension/bubble-menu:** :bug: fix bubble menu and floating menu being available when editor not editable ([#3195](https://github.com/ueberdosis/tiptap/issues/3195)) ([fa96749](https://github.com/ueberdosis/tiptap/commit/fa96749ce22ec67125da491cfeeb38623b9f0d6e))
|
||||
|
||||
# [2.0.0-beta.194](https://github.com/ueberdosis/tiptap/compare/v2.0.0-beta.193...v2.0.0-beta.194) (2022-09-11)
|
||||
|
||||
**Note:** Version bump only for package tiptap-demos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.193](https://github.com/ueberdosis/tiptap/compare/v0.1.2...v2.0.0-beta.193) (2022-09-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bump documents ([43611ea](https://github.com/ueberdosis/tiptap/commit/43611ea2e70d3dc66ff907ba7ca377bf74814543))
|
||||
* disable broken tests for experiements with further todo message ([b8ae9e2](https://github.com/ueberdosis/tiptap/commit/b8ae9e27622857093c6ca539901956da5cc291e5))
|
||||
* don’t check for active node in wrapIn command, fix [#1059](https://github.com/ueberdosis/tiptap/issues/1059) ([170ec4b](https://github.com/ueberdosis/tiptap/commit/170ec4be5b3c8362890ca3100a223b505f788381))
|
||||
* **extension/collaboration:** :ambulance: pin y-prosemirror version to 1.0.20 to fix broken functionality with vue ([5989f3b](https://github.com/ueberdosis/tiptap/commit/5989f3b780bb64b2884d81dcd41a95d98a0714b2))
|
||||
* fix RangeError bug when selecting all text, fix [#2490](https://github.com/ueberdosis/tiptap/issues/2490) ([70422dd](https://github.com/ueberdosis/tiptap/commit/70422dd107ed1ecdd8dfe41a8a93297124d2f1e0))
|
||||
* **maintainment:** fix cjs issues with prosemirror-tables ([eb92597](https://github.com/ueberdosis/tiptap/commit/eb925976038fbf59f6ba333ccc57ea84113da00e))
|
||||
* remove some magic strings ([6c34dec](https://github.com/ueberdosis/tiptap/commit/6c34dec33ac39c9f037a0a72e4525f3fc6d422bf))
|
||||
* **suggestion:** :bug: make clientrect prop optional as it can potentially be undefined ([#2813](https://github.com/ueberdosis/tiptap/issues/2813)) ([f019f70](https://github.com/ueberdosis/tiptap/commit/f019f70a19c34715e2d5c3921d348e11c7ac51a3)), closes [#2795](https://github.com/ueberdosis/tiptap/issues/2795)
|
||||
* temp fix collaboration demo ([4528756](https://github.com/ueberdosis/tiptap/commit/45287563f3cfb389095a2794cb2001d65e56d633))
|
||||
|
||||
- bump documents ([43611ea](https://github.com/ueberdosis/tiptap/commit/43611ea2e70d3dc66ff907ba7ca377bf74814543))
|
||||
- disable broken tests for experiements with further todo message ([b8ae9e2](https://github.com/ueberdosis/tiptap/commit/b8ae9e27622857093c6ca539901956da5cc291e5))
|
||||
- don’t check for active node in wrapIn command, fix [#1059](https://github.com/ueberdosis/tiptap/issues/1059) ([170ec4b](https://github.com/ueberdosis/tiptap/commit/170ec4be5b3c8362890ca3100a223b505f788381))
|
||||
- **extension/collaboration:** :ambulance: pin y-prosemirror version to 1.0.20 to fix broken functionality with vue ([5989f3b](https://github.com/ueberdosis/tiptap/commit/5989f3b780bb64b2884d81dcd41a95d98a0714b2))
|
||||
- fix RangeError bug when selecting all text, fix [#2490](https://github.com/ueberdosis/tiptap/issues/2490) ([70422dd](https://github.com/ueberdosis/tiptap/commit/70422dd107ed1ecdd8dfe41a8a93297124d2f1e0))
|
||||
- **maintainment:** fix cjs issues with prosemirror-tables ([eb92597](https://github.com/ueberdosis/tiptap/commit/eb925976038fbf59f6ba333ccc57ea84113da00e))
|
||||
- remove some magic strings ([6c34dec](https://github.com/ueberdosis/tiptap/commit/6c34dec33ac39c9f037a0a72e4525f3fc6d422bf))
|
||||
- **suggestion:** :bug: make clientrect prop optional as it can potentially be undefined ([#2813](https://github.com/ueberdosis/tiptap/issues/2813)) ([f019f70](https://github.com/ueberdosis/tiptap/commit/f019f70a19c34715e2d5c3921d348e11c7ac51a3)), closes [#2795](https://github.com/ueberdosis/tiptap/issues/2795)
|
||||
- temp fix collaboration demo ([4528756](https://github.com/ueberdosis/tiptap/commit/45287563f3cfb389095a2794cb2001d65e56d633))
|
||||
|
||||
### Features
|
||||
|
||||
* Add extension storage ([#2069](https://github.com/ueberdosis/tiptap/issues/2069)) ([7ffabf2](https://github.com/ueberdosis/tiptap/commit/7ffabf251c408a652eec1931cc78a8bd43cccb67))
|
||||
* add getText() and generateText() methods (fix [#1428](https://github.com/ueberdosis/tiptap/issues/1428)) ([#1875](https://github.com/ueberdosis/tiptap/issues/1875)) ([fe6a3e7](https://github.com/ueberdosis/tiptap/commit/fe6a3e7491f6a42123d3d8a92ab588f2a40d7799))
|
||||
* add some improvements to `CharacterCount` extension ([#2256](https://github.com/ueberdosis/tiptap/issues/2256)), fix [#1049](https://github.com/ueberdosis/tiptap/issues/1049), fix [#1550](https://github.com/ueberdosis/tiptap/issues/1550), fix [#1839](https://github.com/ueberdosis/tiptap/issues/1839), fix [#2245](https://github.com/ueberdosis/tiptap/issues/2245) ([5daa870](https://github.com/ueberdosis/tiptap/commit/5daa870b0906f0387fe07041681bc6f5b3774617))
|
||||
* Add support for autolink ([#2226](https://github.com/ueberdosis/tiptap/issues/2226)) ([3d68981](https://github.com/ueberdosis/tiptap/commit/3d68981b47d087fff40549d2143eb952fc9e0a50))
|
||||
* **extension-link:** :sparkles: add validate option to link extension ([23e67ad](https://github.com/ueberdosis/tiptap/commit/23e67adfa730df7364bc31220d0ed0e8ea522593)), closes [#2779](https://github.com/ueberdosis/tiptap/issues/2779)
|
||||
* **extension/youtube:** :sparkles: new youtube embed extension ([#2814](https://github.com/ueberdosis/tiptap/issues/2814)) ([1c0554b](https://github.com/ueberdosis/tiptap/commit/1c0554b7c06d80145274353e58d56608b097fbe4))
|
||||
* Integrate input rules and paste rules into the core ([#1997](https://github.com/ueberdosis/tiptap/issues/1997)) ([723b955](https://github.com/ueberdosis/tiptap/commit/723b955cecc5c92c8aad897ce16c60fb62976571))
|
||||
* parseHTML for attributes should return the value instead of an object now, fix [#1863](https://github.com/ueberdosis/tiptap/issues/1863) ([8a3b47a](https://github.com/ueberdosis/tiptap/commit/8a3b47a529d28b28b50d634c6ff69b8e5aad3080))
|
||||
- Add extension storage ([#2069](https://github.com/ueberdosis/tiptap/issues/2069)) ([7ffabf2](https://github.com/ueberdosis/tiptap/commit/7ffabf251c408a652eec1931cc78a8bd43cccb67))
|
||||
- add getText() and generateText() methods (fix [#1428](https://github.com/ueberdosis/tiptap/issues/1428)) ([#1875](https://github.com/ueberdosis/tiptap/issues/1875)) ([fe6a3e7](https://github.com/ueberdosis/tiptap/commit/fe6a3e7491f6a42123d3d8a92ab588f2a40d7799))
|
||||
- add some improvements to `CharacterCount` extension ([#2256](https://github.com/ueberdosis/tiptap/issues/2256)), fix [#1049](https://github.com/ueberdosis/tiptap/issues/1049), fix [#1550](https://github.com/ueberdosis/tiptap/issues/1550), fix [#1839](https://github.com/ueberdosis/tiptap/issues/1839), fix [#2245](https://github.com/ueberdosis/tiptap/issues/2245) ([5daa870](https://github.com/ueberdosis/tiptap/commit/5daa870b0906f0387fe07041681bc6f5b3774617))
|
||||
- Add support for autolink ([#2226](https://github.com/ueberdosis/tiptap/issues/2226)) ([3d68981](https://github.com/ueberdosis/tiptap/commit/3d68981b47d087fff40549d2143eb952fc9e0a50))
|
||||
- **extension-link:** :sparkles: add validate option to link extension ([23e67ad](https://github.com/ueberdosis/tiptap/commit/23e67adfa730df7364bc31220d0ed0e8ea522593)), closes [#2779](https://github.com/ueberdosis/tiptap/issues/2779)
|
||||
- **extension/youtube:** :sparkles: new youtube embed extension ([#2814](https://github.com/ueberdosis/tiptap/issues/2814)) ([1c0554b](https://github.com/ueberdosis/tiptap/commit/1c0554b7c06d80145274353e58d56608b097fbe4))
|
||||
- Integrate input rules and paste rules into the core ([#1997](https://github.com/ueberdosis/tiptap/issues/1997)) ([723b955](https://github.com/ueberdosis/tiptap/commit/723b955cecc5c92c8aad897ce16c60fb62976571))
|
||||
- parseHTML for attributes should return the value instead of an object now, fix [#1863](https://github.com/ueberdosis/tiptap/issues/1863) ([8a3b47a](https://github.com/ueberdosis/tiptap/commit/8a3b47a529d28b28b50d634c6ff69b8e5aad3080))
|
||||
|
@ -1,7 +1,11 @@
|
||||
d3
|
||||
highlight.js/lib/languages/css
|
||||
highlight.js/lib/languages/javascript
|
||||
highlight.js/lib/languages/typescript
|
||||
highlight.js/lib/languages/xml
|
||||
highlight.js/lib/core
|
||||
linkifyjs
|
||||
lowlight
|
||||
lowlight/lib/core
|
||||
prosemirror-commands
|
||||
prosemirror-dropcursor
|
||||
prosemirror-gapcursor
|
||||
@ -16,9 +20,13 @@ prosemirror-view
|
||||
react
|
||||
react-dom
|
||||
react-dom/client
|
||||
use-sync-external-store/shim
|
||||
use-sync-external-store/shim/with-selector
|
||||
shiki
|
||||
simplify-js
|
||||
tippy.js
|
||||
uuid
|
||||
y-webrtc
|
||||
yjs
|
||||
@hocuspocus/provider
|
||||
@lifeomic/attempt
|
||||
|
7330
demos/package-lock.json
generated
7330
demos/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "tiptap-demos",
|
||||
"version": "2.4.0",
|
||||
"version": "2.5.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "vite --host",
|
||||
"build:demos": "npm run ts && vite build",
|
||||
@ -9,26 +10,28 @@
|
||||
"ts": "tsc --project tsconfig.base.json --noEmit && tsc --project tsconfig.react.json --noEmit && tsc --project tsconfig.vue-2.json --noEmit && tsc --project tsconfig.vue-3.json --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hocuspocus/provider": "^2.9.0",
|
||||
"@hocuspocus/provider": "2.13.5",
|
||||
"@lexical/react": "^0.11.1",
|
||||
"@shikijs/core": "1.10.3",
|
||||
"d3": "^7.3.0",
|
||||
"fast-glob": "^3.2.11",
|
||||
"highlight.js": "^11.6.0",
|
||||
"highlight.js": "^11.10.0",
|
||||
"lexical": "^0.11.1",
|
||||
"lowlight": "^2.7.0",
|
||||
"lowlight": "^3.1.0",
|
||||
"remixicon": "^2.5.0",
|
||||
"shiki": "^0.10.0",
|
||||
"shiki": "^1.10.3",
|
||||
"simplify-js": "^1.2.4",
|
||||
"y-prosemirror": "^1.2.5",
|
||||
"y-prosemirror": "1.2.11",
|
||||
"y-webrtc": "^10.3.0",
|
||||
"yjs": "^13.6.11"
|
||||
"yjs": "13.6.18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.49",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@vitejs/plugin-react": "^1.3.1",
|
||||
"@vitejs/plugin-vue": "^1.10.2",
|
||||
"@vitejs/plugin-react": "^1.3.2",
|
||||
"@vitejs/plugin-vue": "^5.0.0",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"esbuild": "0.21.5",
|
||||
"iframe-resizer": "^4.3.2",
|
||||
"postcss": "^8.4.31",
|
||||
"postcss-import": "^15.1.0",
|
||||
@ -36,13 +39,13 @@
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"sass": "^1.49.7",
|
||||
"svelte": "^3.49.0",
|
||||
"svelte": "^4.2.19",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"typescript": "4.7.4",
|
||||
"typescript": "^5.4.5",
|
||||
"uuid": "^8.3.2",
|
||||
"vite": "^2.9.18",
|
||||
"vite-plugin-checker": "^0.3.4",
|
||||
"vue": "^3.0.5",
|
||||
"vite": "^5.4.6",
|
||||
"vite-plugin-checker": "^0.6.4",
|
||||
"vue": "^3.0.0",
|
||||
"vue-router": "^4.0.11"
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
<div class="overflow-hidden">
|
||||
<div
|
||||
class="bg-white"
|
||||
:class="[hidePreview ? 'hidden' : '']"
|
||||
>
|
||||
<demo-frame
|
||||
:src="currentIframeUrl"
|
||||
@ -140,6 +141,10 @@ export default {
|
||||
return this.query.hideSource || false
|
||||
},
|
||||
|
||||
hidePreview() {
|
||||
return this.query.hidePreview || false
|
||||
},
|
||||
|
||||
githubUrl() {
|
||||
return `https://github.com/ueberdosis/tiptap/tree/main/demos/src/${this.name}`
|
||||
},
|
||||
|
@ -1,32 +1,90 @@
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
// @ts-nocheck
|
||||
const showDemoList = process.env.NODE_ENV === 'development'
|
||||
|
||||
const searchValue = ref('')
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul v-if="$route.path === '/'">
|
||||
<li
|
||||
class="p-5 border-b-2 border-black"
|
||||
v-for="route in $router.options.routes"
|
||||
:key="route.path"
|
||||
<template v-if="$route.path === '/'">
|
||||
<input
|
||||
class="w-full p-3 my-3 focus:outline-none border-b"
|
||||
type="search"
|
||||
placeholder="Search for a demo..."
|
||||
autofocus
|
||||
v-model="searchValue"
|
||||
>
|
||||
<router-link
|
||||
class="block mb-2 font-medium"
|
||||
:to="route.path"
|
||||
<ul v-if="showDemoList || listing">
|
||||
<li
|
||||
class="p-5 border-b-2 border-black"
|
||||
v-for="route in $router.options.routes.filter(route => searchValue === ''? true : route.props.name.toLowerCase().includes(searchValue.toLowerCase()))"
|
||||
:key="route.path"
|
||||
>
|
||||
{{ route.props.name }}
|
||||
</router-link>
|
||||
|
||||
<div class="flex">
|
||||
<a
|
||||
class="mr-4 text-sm text-gray-300 font-medium"
|
||||
v-for="(tab, index) in route.props.tabs"
|
||||
:key="index"
|
||||
:href="`/src/${route.props.name}/${tab.name}/`"
|
||||
<router-link
|
||||
class="block mb-2 font-medium"
|
||||
:to="route.path"
|
||||
>
|
||||
{{ tab.name }}
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
{{ route.props.name }}
|
||||
</router-link>
|
||||
|
||||
<div class="flex">
|
||||
<a
|
||||
class="mr-4 text-sm text-gray-300 font-medium"
|
||||
v-for="(tab, index) in route.props.tabs"
|
||||
:key="index"
|
||||
:href="`/src/${route.props.name}/${tab.name}/`"
|
||||
>
|
||||
{{ tab.name }}
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-else>Nothing to see here :-)</div>
|
||||
</template>
|
||||
<router-view v-else />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
fromString(value) {
|
||||
if (value === null) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (value.match(/^\d*(\.\d+)?$/)) {
|
||||
return Number(value)
|
||||
}
|
||||
|
||||
if (value === 'true') {
|
||||
return true
|
||||
}
|
||||
|
||||
if (value === 'false') {
|
||||
return false
|
||||
}
|
||||
|
||||
if (value === 'null') {
|
||||
return null
|
||||
}
|
||||
|
||||
return value
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
query() {
|
||||
return Object.fromEntries(Object
|
||||
.entries(this.$route.query)
|
||||
.map(([key, value]) => [key, this.fromString(value)]))
|
||||
},
|
||||
|
||||
listing() {
|
||||
return this.query.listing || false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
@ -1,15 +1,4 @@
|
||||
import * as shiki from 'shiki'
|
||||
import onigasm from 'shiki/dist/onig.wasm?url'
|
||||
import langCSS from 'shiki/languages/css.tmLanguage.json'
|
||||
import langHTML from 'shiki/languages/html.tmLanguage.json'
|
||||
import langJS from 'shiki/languages/javascript.tmLanguage.json'
|
||||
import langJSX from 'shiki/languages/jsx.tmLanguage.json'
|
||||
import langSCSS from 'shiki/languages/scss.tmLanguage.json'
|
||||
import langTSX from 'shiki/languages/tsx.tmLanguage.json'
|
||||
import langTS from 'shiki/languages/typescript.tmLanguage.json'
|
||||
import langVue from 'shiki/languages/vue.tmLanguage.json'
|
||||
import langVueHTML from 'shiki/languages/vue-html.tmLanguage.json'
|
||||
import theme from 'shiki/themes/material-darker.json'
|
||||
|
||||
let highlighter = null
|
||||
|
||||
@ -18,64 +7,18 @@ async function init() {
|
||||
return highlighter
|
||||
}
|
||||
|
||||
const arrayBuffer = await fetch(onigasm).then(response => response.arrayBuffer())
|
||||
|
||||
shiki.setOnigasmWASM(arrayBuffer)
|
||||
|
||||
highlighter = await shiki.getHighlighter({
|
||||
theme,
|
||||
highlighter = await shiki.createHighlighter({
|
||||
themes: ['material-theme-darker'],
|
||||
langs: [
|
||||
{
|
||||
id: 'html',
|
||||
scopeName: langHTML.scopeName,
|
||||
grammar: langHTML,
|
||||
embeddedLangs: ['javascript', 'css'],
|
||||
},
|
||||
{
|
||||
id: 'javascript',
|
||||
scopeName: langJS.scopeName,
|
||||
grammar: langJS,
|
||||
aliases: ['js'],
|
||||
},
|
||||
{
|
||||
id: 'jsx',
|
||||
scopeName: langJSX.scopeName,
|
||||
grammar: langJSX,
|
||||
},
|
||||
{
|
||||
id: 'typescript',
|
||||
scopeName: langTS.scopeName,
|
||||
grammar: langTS,
|
||||
aliases: ['ts'],
|
||||
},
|
||||
{
|
||||
id: 'tsx',
|
||||
scopeName: langTSX.scopeName,
|
||||
grammar: langTSX,
|
||||
},
|
||||
{
|
||||
id: 'vue-html',
|
||||
scopeName: langVueHTML.scopeName,
|
||||
grammar: langVueHTML,
|
||||
embeddedLangs: ['vue', 'javascript'],
|
||||
},
|
||||
{
|
||||
id: 'vue',
|
||||
scopeName: langVue.scopeName,
|
||||
grammar: langVue,
|
||||
embeddedLangs: ['json', 'markdown', 'pug', 'haml', 'vue-html', 'sass', 'scss', 'less', 'stylus', 'postcss', 'css', 'typescript', 'coffee', 'javascript'],
|
||||
},
|
||||
{
|
||||
id: 'css',
|
||||
scopeName: langCSS.scopeName,
|
||||
grammar: langCSS,
|
||||
},
|
||||
{
|
||||
id: 'scss',
|
||||
scopeName: langSCSS.scopeName,
|
||||
grammar: langSCSS,
|
||||
embeddedLangs: ['css'],
|
||||
},
|
||||
'html',
|
||||
'js',
|
||||
'jsx',
|
||||
'ts',
|
||||
'tsx',
|
||||
'css',
|
||||
'vue-html',
|
||||
'vue',
|
||||
'scss',
|
||||
],
|
||||
})
|
||||
|
||||
@ -84,9 +27,12 @@ async function init() {
|
||||
|
||||
// eslint-disable-next-line
|
||||
self.addEventListener('message', async event => {
|
||||
init().then(() => {
|
||||
init().then(async () => {
|
||||
const { code, language } = event.data
|
||||
const html = highlighter.codeToHtml(code, language)
|
||||
|
||||
await highlighter.loadLanguage(language)
|
||||
|
||||
const html = highlighter.codeToHtml(code, { lang: language, theme: 'material-theme-darker' })
|
||||
|
||||
// eslint-disable-next-line
|
||||
self.postMessage({ code, language, html })
|
||||
|
@ -1,4 +1,24 @@
|
||||
$colorBlack: #000;
|
||||
/* Base HTML and global element styles*/
|
||||
:root {
|
||||
--white: #FFF;
|
||||
--black: #2E2B29;
|
||||
--black-contrast: #110F0E;
|
||||
--gray-1: rgba(61, 37, 20, 0.05);
|
||||
--gray-2: rgba(61, 37, 20, 0.08);
|
||||
--gray-3: rgba(61, 37, 20, 0.12);
|
||||
--gray-4: rgba(53, 38, 28, 0.30);
|
||||
--gray-5: rgba(28, 25, 23, 0.60);
|
||||
--green: #22C55E;
|
||||
--purple: #6A00F5;
|
||||
--purple-contrast: #5800CC;
|
||||
--purple-light: rgba(88, 5, 255, 0.05);
|
||||
--yellow-contrast: #FACC15;
|
||||
--yellow: rgba(250, 204, 21, 0.4);
|
||||
--yellow-light: #FFFAE5;
|
||||
--red: #FF5C33;
|
||||
--red-light: #FFEBE5;
|
||||
--shadow: 0px 12px 33px 0px rgba(0, 0, 0, 0.06), 0px 3.618px 9.949px 0px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
@ -9,32 +29,46 @@ $colorBlack: #000;
|
||||
html {
|
||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
line-height: 1.5;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 1rem;
|
||||
min-height: 10rem;
|
||||
min-height: 25rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.tiptap {
|
||||
caret-color: var(--purple);
|
||||
margin: 1.5rem;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom scrollbar styles */
|
||||
::-webkit-scrollbar {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
border: 4px solid transparent;
|
||||
background-clip: padding-box;
|
||||
border-radius: 8px;
|
||||
background-color: transparent;
|
||||
border: 4px solid transparent;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border: 4px solid rgba(0, 0, 0, 0);
|
||||
background-clip: padding-box;
|
||||
border-radius: 8px;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
border: 4px solid rgba(0, 0, 0, 0);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
:hover::-webkit-scrollbar-thumb {
|
||||
@ -47,37 +81,302 @@ body {
|
||||
|
||||
::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-corner {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* Specific element and component styles */
|
||||
button,
|
||||
input,
|
||||
select {
|
||||
font-size: inherit;
|
||||
select,
|
||||
textarea {
|
||||
background: var(--gray-2);
|
||||
border-radius: 0.5rem;
|
||||
border: none;
|
||||
color: var(--black);
|
||||
font-family: inherit;
|
||||
color: black;
|
||||
margin: 0.1rem;
|
||||
border: 1px solid black;
|
||||
border-radius: 0.3rem;
|
||||
padding: 0.1rem 0.4rem;
|
||||
background: white;
|
||||
accent-color: black;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.15;
|
||||
margin: none;
|
||||
padding: 0.375rem 0.625rem;
|
||||
transition: all 0.2s cubic-bezier(0.65,0.05,0.36,1);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--gray-3);
|
||||
color: var(--black-contrast);
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.3;
|
||||
background: var(--gray-1);
|
||||
color: var(--gray-4);
|
||||
}
|
||||
|
||||
&:checked {
|
||||
accent-color: var(--purple);
|
||||
}
|
||||
|
||||
&.primary {
|
||||
background: var(--black);
|
||||
color: var(--white);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--black-contrast);
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
background: var(--gray-1);
|
||||
color: var(--gray-4);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background: var(--purple);
|
||||
color: var(--white);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--purple-contrast);
|
||||
color: var(--white);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tiptap:focus {
|
||||
outline: none;
|
||||
button:not([disabled]),
|
||||
select:not([disabled]) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.is-active {
|
||||
background: black;
|
||||
color: white;
|
||||
input[type="text"],
|
||||
textarea {
|
||||
background-color: unset;
|
||||
border: 1px solid var(--gray-3);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--black);
|
||||
|
||||
&::placeholder {
|
||||
color: var(--gray-4);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: unset;
|
||||
border-color: var(--gray-4);
|
||||
}
|
||||
|
||||
&:focus-visible, &:focus {
|
||||
border-color: var(--purple);
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
/* reset */
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="Gray" d="M7 10l5 5 5-5z"/></svg>');
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 0.1rem center;
|
||||
background-size: 1.25rem 1.25rem;
|
||||
padding-right: 1.25rem;
|
||||
|
||||
&:focus {
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
form {
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.hint {
|
||||
align-items: center;
|
||||
background-color: var(--yellow-light);
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid var(--gray-2);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-size: 0.75rem;
|
||||
gap: 0.25rem;
|
||||
line-height: 1.15;
|
||||
padding: 0.3rem 0.5rem;
|
||||
|
||||
&.purple-spinner,
|
||||
&.error {
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.badge {
|
||||
background-color: var(--gray-1);
|
||||
border: 1px solid var(--gray-3);
|
||||
border-radius: 2rem;
|
||||
color: var(--gray-5);
|
||||
font-size: 0.625rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
padding: 0.25rem 0.5rem;
|
||||
}
|
||||
|
||||
&.purple-spinner {
|
||||
background-color: var(--purple-light);
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
background-image: url("data:image/svg+xml;utf8,<svg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='28px' height='30px' viewBox='0 0 24 30' style='enable-background:new 0 0 50 50;' xml:space='preserve'><rect x='0' y='10' width='6' height='10' fill='%236A00F5' rx='3' ry='3'><animateTransform attributeType='xml' attributeName='transform' type='translate' values='0 0; 0 5; 0 -5; 0 0' begin='0' dur='0.6s' repeatCount='indefinite'/></rect><rect x='10' y='10' width='6' height='10' fill='%236A00F5' rx='3' ry='3'><animateTransform attributeType='xml' attributeName='transform' type='translate' values='0 0; 0 5; 0 -5; 0 0' begin='0.2s' dur='0.6s' repeatCount='indefinite'/></rect><rect x='20' y='10' width='6' height='10' fill='%236A00F5' rx='3' ry='3'><animateTransform attributeType='xml' attributeName='transform' type='translate' values='0 0; 0 5; 0 -5; 0 0' begin='0.4s' dur='0.6s' repeatCount='indefinite'/></rect></svg>");
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.error {
|
||||
background-color: var(--red-light);
|
||||
}
|
||||
}
|
||||
|
||||
.label,
|
||||
.label-small,
|
||||
.label-large {
|
||||
color: var(--black);
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.label-small {
|
||||
color: var(--gray-5);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.label-large {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--gray-3);
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
kbd {
|
||||
background-color: var(--gray-2);
|
||||
border: 1px solid var(--gray-2);
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.6rem;
|
||||
line-height: 1.15;
|
||||
padding: 0.1rem 0.25rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* Layout and structure */
|
||||
#app,
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.control-group {
|
||||
align-items: flex-start;
|
||||
background-color: var(--white);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding: 1.5rem;
|
||||
|
||||
.sticky {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
[data-node-view-wrapper] > .control-group {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.flex-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.switch-group {
|
||||
align-items: center;
|
||||
background: var(--gray-2);
|
||||
border-radius: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
flex: 0 1 auto;
|
||||
justify-content: flex-start;
|
||||
padding: 0.125rem;
|
||||
|
||||
label {
|
||||
align-items: center;
|
||||
border-radius: 0.375rem;
|
||||
color: var(--gray-5);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
gap: 0.25rem;
|
||||
line-height: 1.15;
|
||||
min-height: 1.5rem;
|
||||
padding: 0 0.375rem;
|
||||
transition: all 0.2s cubic-bezier(0.65,0.05,0.36,1);
|
||||
|
||||
&:has(input:checked) {
|
||||
background-color: var(--white);
|
||||
color: var(--black-contrast);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--black);
|
||||
}
|
||||
|
||||
input {
|
||||
display: none;
|
||||
margin: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.output-group {
|
||||
background-color: var(--gray-1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
font-size: 0.75rem;
|
||||
gap: 1rem;
|
||||
margin-top: 2.5rem;
|
||||
padding: 1.5rem;
|
||||
|
||||
label {
|
||||
color: var(--black);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.15;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,12 @@ export default function init(name: string, source: any) {
|
||||
|
||||
import(`../src/${demoCategory}/${demoName}/${frameworkName}/index.vue`)
|
||||
.then(module => {
|
||||
createApp(module.default).mount('#app')
|
||||
const app = createApp(module.default)
|
||||
|
||||
if (typeof module.configureApp === 'function') {
|
||||
module.configureApp(app)
|
||||
}
|
||||
app.mount('#app')
|
||||
debug()
|
||||
})
|
||||
}
|
||||
|
@ -8,10 +8,6 @@ import StarterKit from '@tiptap/starter-kit'
|
||||
import React, { useCallback } from 'react'
|
||||
|
||||
const MenuBar = ({ editor }) => {
|
||||
if (!editor) {
|
||||
return null
|
||||
}
|
||||
|
||||
const onCutToStart = useCallback(() => {
|
||||
editor.chain().cut({ from: editor.state.selection.$from.pos, to: editor.state.selection.$to.pos }, 1).run()
|
||||
}, [editor])
|
||||
@ -20,11 +16,17 @@ const MenuBar = ({ editor }) => {
|
||||
editor.chain().cut({ from: editor.state.selection.$from.pos, to: editor.state.selection.$to.pos }, editor.state.doc.nodeSize - 2).run()
|
||||
}, [editor])
|
||||
|
||||
if (!editor) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button onClick={onCutToStart}>Cut content to start of document</button>
|
||||
<button onClick={onCutToEnd}>Cut content to end of document</button>
|
||||
</>
|
||||
<div className="control-group">
|
||||
<div className="button-group">
|
||||
<button onClick={onCutToStart}>Cut content to start of document</button>
|
||||
<button onClick={onCutToEnd}>Cut content to end of document</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -49,7 +51,7 @@ export default () => {
|
||||
Hi there,
|
||||
</h2>
|
||||
<p>
|
||||
this is a <em>basic</em> example of <strong>tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
|
||||
this is a <em>basic</em> example of <strong>Tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
@ -77,9 +79,9 @@ export default () => {
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<MenuBar editor={editor} />
|
||||
<EditorContent editor={editor} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -21,41 +21,41 @@ context('/src/Examples/Default/React/', () => {
|
||||
})
|
||||
|
||||
const buttonMarks = [
|
||||
{ label: 'bold', tag: 'strong' },
|
||||
{ label: 'italic', tag: 'em' },
|
||||
{ label: 'strike', tag: 's' },
|
||||
{ label: 'Bold', tag: 'strong' },
|
||||
{ label: 'Italic', tag: 'em' },
|
||||
{ label: 'Strike', tag: 's' },
|
||||
]
|
||||
|
||||
buttonMarks.forEach(m => {
|
||||
it(`should disable ${m.label} when the code tag is enabled for cursor`, () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('code').click()
|
||||
cy.get('button').contains('Code').click()
|
||||
cy.get('button').contains(m.label).should('be.disabled')
|
||||
})
|
||||
|
||||
it(`should enable ${m.label} when the code tag is disabled for cursor`, () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('code').click()
|
||||
cy.get('button').contains('code').click()
|
||||
cy.get('button').contains('Code').click()
|
||||
cy.get('button').contains('Code').click()
|
||||
cy.get('button').contains(m.label).should('not.be.disabled')
|
||||
})
|
||||
|
||||
it(`should disable ${m.label} when the code tag is enabled for selection`, () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world{selectall}')
|
||||
cy.get('button').contains('code').click()
|
||||
cy.get('button').contains('Code').click()
|
||||
cy.get('button').contains(m.label).should('be.disabled')
|
||||
})
|
||||
|
||||
it(`should enable ${m.label} when the code tag is disabled for selection`, () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world{selectall}')
|
||||
cy.get('button').contains('code').click()
|
||||
cy.get('button').contains('code').click()
|
||||
cy.get('button').contains('Code').click()
|
||||
cy.get('button').contains('Code').click()
|
||||
cy.get('button').contains(m.label).should('not.be.disabled')
|
||||
})
|
||||
|
||||
it(`should apply ${m.label} when the button is pressed`, () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('paragraph').click()
|
||||
cy.get('button').contains('Paragraph').click()
|
||||
cy.get('.tiptap').type('{selectall}')
|
||||
cy.get('button').contains(m.label).click()
|
||||
cy.get(`.tiptap ${m.tag}`).should('exist').should('have.text', 'Hello world')
|
||||
@ -64,40 +64,40 @@ context('/src/Examples/Default/React/', () => {
|
||||
|
||||
it('should clear marks when the button is pressed', () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('paragraph').click()
|
||||
cy.get('button').contains('Paragraph').click()
|
||||
cy.get('.tiptap').type('{selectall}')
|
||||
cy.get('button').contains('bold').click()
|
||||
cy.get('button').contains('Bold').click()
|
||||
cy.get('.tiptap strong').should('exist').should('have.text', 'Hello world')
|
||||
cy.get('button').contains('clear marks').click()
|
||||
cy.get('button').contains('Clear marks').click()
|
||||
cy.get('.tiptap strong').should('not.exist')
|
||||
})
|
||||
|
||||
it('should clear nodes when the button is pressed', () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('bullet list').click()
|
||||
cy.get('button').contains('Bullet list').click()
|
||||
cy.get('.tiptap ul').should('exist').should('have.text', 'Hello world')
|
||||
cy.get('.tiptap').type('{enter}A second item{enter}A third item{selectall}')
|
||||
cy.get('button').contains('clear nodes').click()
|
||||
cy.get('button').contains('Clear nodes').click()
|
||||
cy.get('.tiptap ul').should('not.exist')
|
||||
cy.get('.tiptap p').should('have.length', 3)
|
||||
})
|
||||
|
||||
const buttonNodes = [
|
||||
{ label: 'h1', tag: 'h1' },
|
||||
{ label: 'h2', tag: 'h2' },
|
||||
{ label: 'h3', tag: 'h3' },
|
||||
{ label: 'h4', tag: 'h4' },
|
||||
{ label: 'h5', tag: 'h5' },
|
||||
{ label: 'h6', tag: 'h6' },
|
||||
{ label: 'bullet list', tag: 'ul' },
|
||||
{ label: 'ordered list', tag: 'ol' },
|
||||
{ label: 'code block', tag: 'pre code' },
|
||||
{ label: 'blockquote', tag: 'blockquote' },
|
||||
{ label: 'H1', tag: 'h1' },
|
||||
{ label: 'H2', tag: 'h2' },
|
||||
{ label: 'H3', tag: 'h3' },
|
||||
{ label: 'H4', tag: 'h4' },
|
||||
{ label: 'H5', tag: 'h5' },
|
||||
{ label: 'H6', tag: 'h6' },
|
||||
{ label: 'Bullet list', tag: 'ul' },
|
||||
{ label: 'Ordered list', tag: 'ol' },
|
||||
{ label: 'Code block', tag: 'pre code' },
|
||||
{ label: 'Blockquote', tag: 'blockquote' },
|
||||
]
|
||||
|
||||
buttonNodes.forEach(n => {
|
||||
it(`should set ${n.label} when the button is pressed`, () => {
|
||||
cy.get('button').contains('paragraph').click()
|
||||
cy.get('button').contains('Paragraph').click()
|
||||
cy.get('.tiptap').type('{selectall}Hello world{selectall}')
|
||||
|
||||
cy.get('button').contains(n.label).click()
|
||||
@ -109,35 +109,35 @@ context('/src/Examples/Default/React/', () => {
|
||||
|
||||
it('should add a hr when on the same line as a node', () => {
|
||||
cy.get('.tiptap').type('{rightArrow}')
|
||||
cy.get('button').contains('horizontal rule').click()
|
||||
cy.get('button').contains('Horizontal rule').click()
|
||||
cy.get('.tiptap hr').should('exist')
|
||||
cy.get('.tiptap h1').should('exist')
|
||||
})
|
||||
|
||||
it('should add a hr when on a new line', () => {
|
||||
cy.get('.tiptap').type('{rightArrow}{enter}')
|
||||
cy.get('button').contains('horizontal rule').click()
|
||||
cy.get('button').contains('Horizontal rule').click()
|
||||
cy.get('.tiptap hr').should('exist')
|
||||
cy.get('.tiptap h1').should('exist')
|
||||
})
|
||||
|
||||
it('should add a br', () => {
|
||||
cy.get('.tiptap').type('{rightArrow}')
|
||||
cy.get('button').contains('hard break').click()
|
||||
cy.get('button').contains('Hard break').click()
|
||||
cy.get('.tiptap h1 br').should('exist')
|
||||
})
|
||||
|
||||
it('should undo', () => {
|
||||
cy.get('.tiptap').type('{selectall}{backspace}')
|
||||
cy.get('button').contains('undo').click()
|
||||
cy.get('button').contains('Undo').click()
|
||||
cy.get('.tiptap').should('contain', 'Hello world')
|
||||
})
|
||||
|
||||
it('should redo', () => {
|
||||
cy.get('.tiptap').type('{selectall}{backspace}')
|
||||
cy.get('button').contains('undo').click()
|
||||
cy.get('button').contains('Undo').click()
|
||||
cy.get('.tiptap').should('contain', 'Hello world')
|
||||
cy.get('button').contains('redo').click()
|
||||
cy.get('button').contains('Redo').click()
|
||||
cy.get('.tiptap').should('not.contain', 'Hello world')
|
||||
})
|
||||
})
|
||||
|
@ -1,56 +1,91 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: rgba(#616161, 0.1);
|
||||
color: #616161;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
font-size: 0.8rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
border-left: 2px solid rgba(#0D0D0D, 0.1);
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 2px solid rgba(#0D0D0D, 0.1);
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import './styles.scss'
|
||||
|
||||
import { Color } from '@tiptap/extension-color'
|
||||
import Link from '@tiptap/extension-link'
|
||||
import ListItem from '@tiptap/extension-list-item'
|
||||
import TextStyle from '@tiptap/extension-text-style'
|
||||
import { EditorProvider, useCurrentEditor } from '@tiptap/react'
|
||||
@ -29,23 +30,26 @@ const MenuBar = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button data-test-id="html-content" onClick={() => editor.chain().insertContent(htmlContent).focus().run()}>
|
||||
Insert html content
|
||||
</button>
|
||||
<button data-test-id="html-content-spans" onClick={() => editor.chain().insertContent('<p><b>Hello</b> <i>World</i></p>').focus().run()}>
|
||||
Insert html with span tags content
|
||||
</button>
|
||||
<button data-test-id="text-content" onClick={() => editor.chain().insertContent(textContent).focus().run()}>
|
||||
Insert text content
|
||||
</button>
|
||||
</>
|
||||
<div className="control-group">
|
||||
<div className="button-group">
|
||||
<button data-test-id="html-content" onClick={() => editor.chain().insertContent(htmlContent).focus().run()}>
|
||||
Insert HTML content
|
||||
</button>
|
||||
<button data-test-id="html-content-spans" onClick={() => editor.chain().insertContent('<p><b>Hello</b> <i>World</i></p>').focus().run()}>
|
||||
Insert HTML with span tags content
|
||||
</button>
|
||||
<button data-test-id="text-content" onClick={() => editor.chain().insertContent(textContent).focus().run()}>
|
||||
Insert text content
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const extensions = [
|
||||
Color.configure({ types: [TextStyle.name, ListItem.name] }),
|
||||
TextStyle.configure({ types: [ListItem.name] }),
|
||||
Link,
|
||||
StarterKit.configure({
|
||||
bulletList: {
|
||||
keepMarks: true,
|
||||
|
@ -11,7 +11,7 @@ context('/src/Commands/InsertContent/React/', () => {
|
||||
cy.get('button[data-test-id="html-content"]').click()
|
||||
|
||||
// check if the content html is correct
|
||||
cy.get('.tiptap').should('contain.html', '<h1>Tiptap</h1><p><strong>Hello World</strong></p><p>This is a paragraph<br>with a break.</p><p>And this is some additional string content.</p>')
|
||||
cy.get('.tiptap').should('contain.html', '<h1><a target="_blank" rel="noopener noreferrer nofollow" href="https://tiptap.dev/">Tiptap</a></h1><p><strong>Hello World</strong></p><p>This is a paragraph<br>with a break.</p><p>And this is some additional string content.</p>')
|
||||
})
|
||||
|
||||
it('should keep spaces inbetween tags in html content', () => {
|
||||
@ -41,4 +41,78 @@ context('/src/Commands/InsertContent/React/', () => {
|
||||
cy.get('.tiptap').should('contain.html', '<pre><code>foo\nbar</code></pre>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should keep newlines and tabs', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.insertContent('<p>Hello\n\tworld\n\t\thow\n\t\t\tnice.\ntest\tOK</p>')
|
||||
cy.get('.tiptap').should('contain.html', '<p>Hello\n\tworld\n\t\thow\n\t\t\tnice.\ntest\tOK</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should keep newlines and tabs', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.insertContent('<h1>Tiptap</h1>\n<p><strong>Hello World</strong></p>')
|
||||
cy.get('.tiptap').should('contain.html', '<h1>Tiptap</h1><p><strong>Hello World</strong></p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow inserting nothing', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.insertContent('')
|
||||
cy.get('.tiptap').should('contain.html', '')
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow inserting a partial HTML tag', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.insertContent('<p>foo')
|
||||
cy.get('.tiptap').should('contain.html', '<p>foo</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow inserting an incomplete HTML tag', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.insertContent('foo<p')
|
||||
cy.get('.tiptap').should('contain.html', '<p>foo<p</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow inserting a list', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.insertContent('<ul><li>ABC</li><li>123</li></ul>')
|
||||
cy.get('.tiptap').should('contain.html', '<ul><li><p>ABC</p></li><li><p>123</p></li></ul>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should remove newlines and tabs when parseOptions.preserveWhitespace=false', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.insertContent('\n<h1>Tiptap</h1><p><strong>Hello\n World</strong>\n</p>\n', { parseOptions: { preserveWhitespace: false } })
|
||||
cy.get('.tiptap').should('contain.html', '<h1>Tiptap</h1><p><strong>Hello World</strong></p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should respect editor.options.parseOptions if defined to be `false`', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.options.parseOptions = { preserveWhitespace: false }
|
||||
editor.commands.insertContent('\n<h1>Tiptap</h1><p><strong>Hello\n World</strong>\n</p>\n')
|
||||
cy.get('.tiptap').should('contain.html', '<h1>Tiptap</h1><p><strong>Hello World</strong></p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should respect editor.options.parseOptions if defined to be `full`', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.options.parseOptions = { preserveWhitespace: 'full' }
|
||||
editor.commands.insertContent('\n<h1>Tiptap</h1><p><strong>Hello\n World</strong>\n</p>\n')
|
||||
cy.get('.tiptap').should('contain.html', '<h1>Tiptap</h1><p><strong>Hello\n World</strong></p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should respect editor.options.parseOptions if defined to be `true`', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.options.parseOptions = { preserveWhitespace: true }
|
||||
editor.commands.insertContent('<h1>Tiptap</h1><p><strong>Hello\n World</strong>\n</p>')
|
||||
cy.get('.tiptap').should('contain.html', '<h1>Tiptap</h1><p><strong>Hello World</strong></p>')
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
@ -1,56 +1,91 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: rgba(#616161, 0.1);
|
||||
color: #616161;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
font-size: 0.8rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
border-left: 2px solid rgba(#0D0D0D, 0.1);
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 2px solid rgba(#0D0D0D, 0.1);
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
@ -14,154 +14,152 @@ const MenuBar = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="control-group">
|
||||
<div>
|
||||
<button
|
||||
onClick={() => setUseInputRules(prev => !prev)}
|
||||
style={{
|
||||
color: useInputRules ? 'white' : 'inherit',
|
||||
backgroundColor: useInputRules ? 'black' : 'transparent',
|
||||
}}
|
||||
>
|
||||
Apply Input Rules
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setUsePasteRules(prev => !prev)}
|
||||
style={{
|
||||
color: usePasteRules ? 'white' : 'inherit',
|
||||
backgroundColor: usePasteRules ? 'black' : 'transparent',
|
||||
}}
|
||||
>
|
||||
Apply Paste Rules
|
||||
</button>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={useInputRules}
|
||||
onChange={() => setUseInputRules(prev => !prev)}
|
||||
/>
|
||||
Apply input rules
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={usePasteRules}
|
||||
onChange={() => setUsePasteRules(prev => !prev)}
|
||||
/>
|
||||
Apply paste rules
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<div className="button-group">
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent('-', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-1
|
||||
>
|
||||
Insert "-"
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent(' ', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-2
|
||||
>
|
||||
Insert " "
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent('A', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-3
|
||||
>
|
||||
Insert "A"
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent('-', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-1
|
||||
>
|
||||
Insert "-"
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent(' ', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-2
|
||||
>
|
||||
Insert " "
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent('A', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-3
|
||||
>
|
||||
Insert "A"
|
||||
</button>
|
||||
<br />
|
||||
|
||||
<br />
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent('*this is', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-4
|
||||
>
|
||||
Insert "*this is"
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent(' a test*', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-5
|
||||
>
|
||||
Insert " a test*"
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent(' a test*, whooho', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-6
|
||||
>
|
||||
Insert " a test*, whooho."
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent('*this is a test*, whooho.', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-7
|
||||
>
|
||||
Insert "*this is a test*, whooho."
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent('*this is a test*', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-8
|
||||
>
|
||||
Insert "*this is a test*"
|
||||
</button>
|
||||
</>
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent('*this is', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-4
|
||||
>
|
||||
Insert "*this is"
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent(' a test*', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-5
|
||||
>
|
||||
Insert " a test*"
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent(' a test*, whooho', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-6
|
||||
>
|
||||
Insert " a test*, whooho."
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent('*this is a test*, whooho.', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-7
|
||||
>
|
||||
Insert "*this is a test*, whooho."
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
editor
|
||||
.chain()
|
||||
.insertContent('*this is a test*', {
|
||||
applyInputRules: useInputRules,
|
||||
applyPasteRules: usePasteRules,
|
||||
})
|
||||
.focus()
|
||||
.run()
|
||||
}}
|
||||
data-test-8
|
||||
>
|
||||
Insert "*this is a test*"
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,56 +1,91 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: rgba(#616161, 0.1);
|
||||
color: #616161;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
font-size: 0.8rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
border-left: 2px solid rgba(#0D0D0D, 0.1);
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 2px solid rgba(#0D0D0D, 0.1);
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
31
demos/src/Commands/SetContent/React/index.jsx
Normal file
31
demos/src/Commands/SetContent/React/index.jsx
Normal file
@ -0,0 +1,31 @@
|
||||
import './styles.scss'
|
||||
|
||||
import { Color } from '@tiptap/extension-color'
|
||||
import ListItem from '@tiptap/extension-list-item'
|
||||
import Mentions from '@tiptap/extension-mention'
|
||||
import TextStyle from '@tiptap/extension-text-style'
|
||||
import { EditorProvider } from '@tiptap/react'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import React from 'react'
|
||||
|
||||
const extensions = [
|
||||
Color.configure({ types: [TextStyle.name, ListItem.name] }),
|
||||
TextStyle.configure({ types: [ListItem.name] }),
|
||||
StarterKit.configure({
|
||||
bulletList: {
|
||||
keepMarks: true,
|
||||
},
|
||||
orderedList: {
|
||||
keepMarks: true,
|
||||
},
|
||||
}),
|
||||
Mentions,
|
||||
]
|
||||
|
||||
const content = ''
|
||||
|
||||
export default () => {
|
||||
return (
|
||||
<EditorProvider extensions={extensions} content={content}></EditorProvider>
|
||||
)
|
||||
}
|
181
demos/src/Commands/SetContent/React/index.spec.js
Normal file
181
demos/src/Commands/SetContent/React/index.spec.js
Normal file
@ -0,0 +1,181 @@
|
||||
context('/src/Commands/SetContent/React/', () => {
|
||||
before(() => {
|
||||
cy.visit('/src/Commands/SetContent/React/')
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
cy.get('.tiptap').type('{selectall}{backspace}')
|
||||
})
|
||||
|
||||
it('should insert raw text content', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('Hello World.')
|
||||
cy.get('.tiptap').should('contain.html', '<p>Hello World.</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should insert raw JSON content', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent({ type: 'paragraph', content: [{ type: 'text', text: 'Hello World.' }] })
|
||||
cy.get('.tiptap').should('contain.html', '<p>Hello World.</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should insert a Prosemirror Node as content', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent(editor.schema.node('paragraph', null, editor.schema.text('Hello World.')))
|
||||
cy.get('.tiptap').should('contain.html', '<p>Hello World.</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should insert a Prosemirror Fragment as content', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent(editor.schema.node('doc', null, editor.schema.node('paragraph', null, editor.schema.text('Hello World.'))).content)
|
||||
cy.get('.tiptap').should('contain.html', '<p>Hello World.</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should emit updates', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
let updateCount = 0
|
||||
const callback = () => {
|
||||
updateCount += 1
|
||||
}
|
||||
|
||||
editor.on('update', callback)
|
||||
// emit an update
|
||||
editor.commands.setContent('Hello World.', true)
|
||||
expect(updateCount).to.equal(1)
|
||||
|
||||
updateCount = 0
|
||||
// do not emit an update
|
||||
editor.commands.setContent('Hello World again.', false)
|
||||
expect(updateCount).to.equal(0)
|
||||
editor.off('update', callback)
|
||||
})
|
||||
})
|
||||
|
||||
it('should insert more complex html content', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<h1>Welcome to Tiptap</h1><p>This is a paragraph.</p><ul><li><p>List Item A</p></li><li><p>List Item B</p><ul><li><p>Subchild</p></li></ul></li></ul>')
|
||||
cy.get('.tiptap').should('contain.html', '<h1>Welcome to Tiptap</h1><p>This is a paragraph.</p><ul><li><p>List Item A</p></li><li><p>List Item B</p><ul><li><p>Subchild</p></li></ul></li></ul>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should remove newlines and tabs', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<p>Hello\n\tworld\n\t\thow\n\t\t\tnice.</p>')
|
||||
cy.get('.tiptap').should('contain.html', '<p>Hello world how nice.</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should keep newlines and tabs when preserveWhitespace = full', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<p>Hello\n\tworld\n\t\thow\n\t\t\tnice.</p>', false, { preserveWhitespace: 'full' })
|
||||
cy.get('.tiptap').should('contain.html', '<p>Hello\n\tworld\n\t\thow\n\t\t\tnice.</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should overwrite existing content', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<p>Initial Content</p>')
|
||||
cy.get('.tiptap').should('contain.html', '<p>Initial Content</p>')
|
||||
})
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<p>Overwritten Content</p>')
|
||||
cy.get('.tiptap').should('contain.html', '<p>Overwritten Content</p>')
|
||||
})
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('Content without tags')
|
||||
cy.get('.tiptap').should('contain.html', '<p>Content without tags</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should insert mentions', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<p><span data-type="mention" data-id="1" data-label="John Doe">@John Doe</span></p>')
|
||||
cy.get('.tiptap').should('contain.html', '<span data-type="mention" data-id="1" data-label="John Doe" contenteditable="false">@John Doe</span>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should remove newlines and tabs between html fragments', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<h1>Tiptap</h1>\n\t<p><strong>Hello World</strong></p>')
|
||||
cy.get('.tiptap').should('contain.html', '<h1>Tiptap</h1><p><strong>Hello World</strong></p>')
|
||||
})
|
||||
})
|
||||
|
||||
// TODO I'm not certain about this behavior and what it should do...
|
||||
// This exists in insertContentAt as well
|
||||
it('should keep newlines and tabs between html fragments when preserveWhitespace = full', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<h1>Tiptap</h1>\n\t<p><strong>Hello World</strong></p>', false, { preserveWhitespace: 'full' })
|
||||
cy.get('.tiptap').should('contain.html', '<h1>Tiptap</h1><p>\n\t</p><p><strong>Hello World</strong></p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow inserting nothing', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('')
|
||||
cy.get('.tiptap').should('contain.html', '')
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow inserting nothing when preserveWhitespace = full', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('', false, { preserveWhitespace: 'full' })
|
||||
cy.get('.tiptap').should('contain.html', '')
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow inserting a partial HTML tag', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<p>foo')
|
||||
cy.get('.tiptap').should('contain.html', '<p>foo</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow inserting a partial HTML tag when preserveWhitespace = full', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<p>foo', false, { preserveWhitespace: 'full' })
|
||||
cy.get('.tiptap').should('contain.html', '<p>foo</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('will remove an incomplete HTML tag', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('foo<p')
|
||||
cy.get('.tiptap').should('contain.html', '<p>foo</p>')
|
||||
})
|
||||
})
|
||||
|
||||
// TODO I'm not certain about this behavior and what it should do...
|
||||
// This exists in insertContentAt as well
|
||||
it('should allow inserting an incomplete HTML tag when preserveWhitespace = full', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('foo<p', false, { preserveWhitespace: 'full' })
|
||||
cy.get('.tiptap').should('contain.html', '<p>foo<p</p>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow inserting a list', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<ul><li>ABC</li><li>123</li></ul>')
|
||||
cy.get('.tiptap').should('contain.html', '<ul><li><p>ABC</p></li><li><p>123</p></li></ul>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow inserting a list when preserveWhitespace = full', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('<ul><li>ABC</li><li>123</li></ul>', false, { preserveWhitespace: 'full' })
|
||||
cy.get('.tiptap').should('contain.html', '<ul><li><p>ABC</p></li><li><p>123</p></li></ul>')
|
||||
})
|
||||
})
|
||||
|
||||
it('should remove newlines and tabs when parseOptions.preserveWhitespace=false', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
editor.commands.setContent('\n<h1>Tiptap</h1><p><strong>Hello\n World</strong>\n</p>\n', false, { preserveWhitespace: false })
|
||||
cy.get('.tiptap').should('contain.html', '<h1>Tiptap</h1><p><strong>Hello World</strong></p>')
|
||||
})
|
||||
})
|
||||
})
|
56
demos/src/Commands/SetContent/React/styles.scss
Normal file
56
demos/src/Commands/SetContent/React/styles.scss
Normal file
@ -0,0 +1,56 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: rgba(#616161, 0.1);
|
||||
color: #616161;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
padding-left: 1rem;
|
||||
border-left: 2px solid rgba(#0D0D0D, 0.1);
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 2px solid rgba(#0D0D0D, 0.1);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
209
demos/src/Demos/CollaborationSplitPane/React/Editor.jsx
Normal file
209
demos/src/Demos/CollaborationSplitPane/React/Editor.jsx
Normal file
@ -0,0 +1,209 @@
|
||||
import CharacterCount from '@tiptap/extension-character-count'
|
||||
import Collaboration from '@tiptap/extension-collaboration'
|
||||
import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
|
||||
import Highlight from '@tiptap/extension-highlight'
|
||||
import TaskItem from '@tiptap/extension-task-item'
|
||||
import TaskList from '@tiptap/extension-task-list'
|
||||
import { EditorContent, useEditor } from '@tiptap/react'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
const colors = [
|
||||
'#958DF1',
|
||||
'#F98181',
|
||||
'#FBBC88',
|
||||
'#FAF594',
|
||||
'#70CFF8',
|
||||
'#94FADB',
|
||||
'#B9F18D',
|
||||
'#C3E2C2',
|
||||
'#EAECCC',
|
||||
'#AFC8AD',
|
||||
'#EEC759',
|
||||
'#9BB8CD',
|
||||
'#FF90BC',
|
||||
'#FFC0D9',
|
||||
'#DC8686',
|
||||
'#7ED7C1',
|
||||
'#F3EEEA',
|
||||
'#89B9AD',
|
||||
'#D0BFFF',
|
||||
'#FFF8C9',
|
||||
'#CBFFA9',
|
||||
'#9BABB8',
|
||||
'#E3F4F4',
|
||||
]
|
||||
const names = [
|
||||
'Lea Thompson',
|
||||
'Cyndi Lauper',
|
||||
'Tom Cruise',
|
||||
'Madonna',
|
||||
'Jerry Hall',
|
||||
'Joan Collins',
|
||||
'Winona Ryder',
|
||||
'Christina Applegate',
|
||||
'Alyssa Milano',
|
||||
'Molly Ringwald',
|
||||
'Ally Sheedy',
|
||||
'Debbie Harry',
|
||||
'Olivia Newton-John',
|
||||
'Elton John',
|
||||
'Michael J. Fox',
|
||||
'Axl Rose',
|
||||
'Emilio Estevez',
|
||||
'Ralph Macchio',
|
||||
'Rob Lowe',
|
||||
'Jennifer Grey',
|
||||
'Mickey Rourke',
|
||||
'John Cusack',
|
||||
'Matthew Broderick',
|
||||
'Justine Bateman',
|
||||
'Lisa Bonet',
|
||||
]
|
||||
|
||||
const defaultContent = `
|
||||
<p>Hi 👋, this is a collaborative document.</p>
|
||||
<p>Feel free to edit and collaborate in real-time!</p>
|
||||
`
|
||||
|
||||
const getRandomElement = list => list[Math.floor(Math.random() * list.length)]
|
||||
|
||||
const getRandomColor = () => getRandomElement(colors)
|
||||
const getRandomName = () => getRandomElement(names)
|
||||
|
||||
const getInitialUser = () => {
|
||||
return {
|
||||
name: getRandomName(),
|
||||
color: getRandomColor(),
|
||||
}
|
||||
}
|
||||
|
||||
const Editor = ({
|
||||
ydoc, provider, room,
|
||||
}) => {
|
||||
const [status, setStatus] = useState('connecting')
|
||||
const [currentUser, setCurrentUser] = useState(getInitialUser)
|
||||
|
||||
const editor = useEditor({
|
||||
enableContentCheck: true,
|
||||
onContentError: ({ disableCollaboration }) => {
|
||||
disableCollaboration()
|
||||
},
|
||||
onCreate: ({ editor: currentEditor }) => {
|
||||
provider.on('synced', () => {
|
||||
if (currentEditor.isEmpty) {
|
||||
currentEditor.commands.setContent(defaultContent)
|
||||
}
|
||||
})
|
||||
},
|
||||
extensions: [
|
||||
StarterKit.configure({
|
||||
history: false,
|
||||
}),
|
||||
Highlight,
|
||||
TaskList,
|
||||
TaskItem,
|
||||
CharacterCount.extend().configure({
|
||||
limit: 10000,
|
||||
}),
|
||||
Collaboration.extend().configure({
|
||||
document: ydoc,
|
||||
}),
|
||||
CollaborationCursor.extend().configure({
|
||||
provider,
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
// Update status changes
|
||||
const statusHandler = event => {
|
||||
setStatus(event.status)
|
||||
}
|
||||
|
||||
provider.on('status', statusHandler)
|
||||
|
||||
return () => {
|
||||
provider.off('status', statusHandler)
|
||||
}
|
||||
}, [provider])
|
||||
|
||||
// Save current user to localStorage and emit to editor
|
||||
useEffect(() => {
|
||||
if (editor && currentUser) {
|
||||
localStorage.setItem('currentUser', JSON.stringify(currentUser))
|
||||
editor.chain().focus().updateUser(currentUser).run()
|
||||
}
|
||||
}, [editor, currentUser])
|
||||
|
||||
const setName = useCallback(() => {
|
||||
const name = (window.prompt('Name', currentUser.name) || '').trim().substring(0, 32)
|
||||
|
||||
if (name) {
|
||||
return setCurrentUser({ ...currentUser, name })
|
||||
}
|
||||
}, [currentUser])
|
||||
|
||||
if (!editor) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="column-half">
|
||||
<div className="control-group">
|
||||
<div className="button-group">
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBold().run()}
|
||||
className={editor.isActive('bold') ? 'is-active' : ''}
|
||||
>
|
||||
Bold
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleItalic().run()}
|
||||
className={editor.isActive('italic') ? 'is-active' : ''}
|
||||
>
|
||||
Italic
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleStrike().run()}
|
||||
className={editor.isActive('strike') ? 'is-active' : ''}
|
||||
>
|
||||
Strike
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBulletList().run()}
|
||||
className={editor.isActive('bulletList') ? 'is-active' : ''}
|
||||
>
|
||||
Bullet list
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleCode().run()}
|
||||
className={editor.isActive('code') ? 'is-active' : ''}
|
||||
>
|
||||
Code
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<EditorContent editor={editor} className="main-group" />
|
||||
|
||||
<div
|
||||
className="collab-status-group"
|
||||
data-state={status === 'connected' ? 'online' : 'offline'}
|
||||
>
|
||||
<label>
|
||||
{status === 'connected'
|
||||
? `${editor.storage.collaborationCursor.users.length} user${
|
||||
editor.storage.collaborationCursor.users.length === 1 ? '' : 's'
|
||||
} online in ${room}`
|
||||
: 'offline'}
|
||||
</label>
|
||||
<button style={{ '--color': currentUser.color }} onClick={setName}>
|
||||
✎ {currentUser.name}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Editor
|
39
demos/src/Demos/CollaborationSplitPane/React/index.jsx
Normal file
39
demos/src/Demos/CollaborationSplitPane/React/index.jsx
Normal file
@ -0,0 +1,39 @@
|
||||
import './styles.scss'
|
||||
|
||||
import { TiptapCollabProvider } from '@hocuspocus/provider'
|
||||
import * as Y from 'yjs'
|
||||
|
||||
import Editor from './Editor.jsx'
|
||||
|
||||
const appId = '7j9y6m10'
|
||||
const room = `room.${new Date()
|
||||
.getFullYear()
|
||||
.toString()
|
||||
.slice(-2)}${new Date().getMonth() + 1}${new Date().getDate()}-ok`
|
||||
|
||||
// ydoc and provider for Editor A
|
||||
const ydocA = new Y.Doc()
|
||||
const providerA = new TiptapCollabProvider({
|
||||
appId,
|
||||
name: room,
|
||||
document: ydocA,
|
||||
})
|
||||
|
||||
// ydoc and provider for Editor B
|
||||
const ydocB = new Y.Doc()
|
||||
const providerB = new TiptapCollabProvider({
|
||||
appId,
|
||||
name: room,
|
||||
document: ydocB,
|
||||
})
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<div className="col-group">
|
||||
<Editor provider={providerA} ydoc={ydocA} room={room} />
|
||||
<Editor provider={providerB} ydoc={ydocB} room={room} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
24
demos/src/Demos/CollaborationSplitPane/React/index.spec.js
Normal file
24
demos/src/Demos/CollaborationSplitPane/React/index.spec.js
Normal file
@ -0,0 +1,24 @@
|
||||
context('/src/Demos/CollaborationSplitPane/React/', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/src/Demos/CollaborationSplitPane/React/')
|
||||
})
|
||||
|
||||
it('should have a working tiptap instance', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
// eslint-disable-next-line
|
||||
expect(editor).to.not.be.null
|
||||
})
|
||||
})
|
||||
|
||||
it('should have a ydoc', () => {
|
||||
cy.get('.tiptap').then(([{ editor }]) => {
|
||||
/**
|
||||
* @type {import('yjs').Doc}
|
||||
*/
|
||||
const yDoc = editor.extensionManager.extensions.find(a => a.name === 'collaboration').options.document
|
||||
|
||||
// eslint-disable-next-line
|
||||
expect(yDoc).to.not.be.null
|
||||
})
|
||||
})
|
||||
})
|
280
demos/src/Demos/CollaborationSplitPane/React/styles.scss
Normal file
280
demos/src/Demos/CollaborationSplitPane/React/styles.scss
Normal file
@ -0,0 +1,280 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
/* Highlight specific styles */
|
||||
mark {
|
||||
background-color: #FAF594;
|
||||
border-radius: 0.4rem;
|
||||
box-decoration-break: clone;
|
||||
padding: 0.1rem 0.3rem;
|
||||
}
|
||||
|
||||
/* Task list specific styles */
|
||||
ul[data-type="taskList"] {
|
||||
list-style: none;
|
||||
margin-left: 0;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
|
||||
> label {
|
||||
flex: 0 0 auto;
|
||||
margin-right: 0.5rem;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
> div {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
ul[data-type="taskList"] {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* Give a remote user a caret */
|
||||
.collaboration-cursor__caret {
|
||||
border-left: 1px solid #0d0d0d;
|
||||
border-right: 1px solid #0d0d0d;
|
||||
margin-left: -1px;
|
||||
margin-right: -1px;
|
||||
pointer-events: none;
|
||||
position: relative;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
/* Render the username above the caret */
|
||||
.collaboration-cursor__label {
|
||||
border-radius: 3px 3px 3px 0;
|
||||
color: #0d0d0d;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
left: -1px;
|
||||
line-height: normal;
|
||||
padding: 0.1rem 0.3rem;
|
||||
position: absolute;
|
||||
top: -1.4em;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.col-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100vh;
|
||||
|
||||
@media (max-width: 540px) {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
/* Column-half */
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.column-half {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
|
||||
&:last-child {
|
||||
border-left: 1px solid var(--gray-3);
|
||||
|
||||
@media (max-width: 540px) {
|
||||
border-left: none;
|
||||
border-top: 1px solid var(--gray-3);
|
||||
}
|
||||
}
|
||||
|
||||
& > .main-group {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Collaboration status */
|
||||
.collab-status-group {
|
||||
align-items: center;
|
||||
background-color: var(--white);
|
||||
border-top: 1px solid var(--gray-3);
|
||||
bottom: 0;
|
||||
color: var(--gray-5);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 400;
|
||||
gap: 1rem;
|
||||
justify-content: space-between;
|
||||
padding: 0.375rem 0.5rem 0.375rem 1rem;
|
||||
position: sticky;
|
||||
width: 100%;
|
||||
z-index: 100;
|
||||
|
||||
button {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
align-self: stretch;
|
||||
background: none;
|
||||
display: -webkit-box;
|
||||
flex-shrink: 1;
|
||||
font-size: 0.75rem;
|
||||
max-width: 100%;
|
||||
padding: 0.25rem 0.375rem;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
&::before {
|
||||
background-color: var(--color);
|
||||
border-radius: 0.375rem;
|
||||
content: "";
|
||||
height: 100%;
|
||||
left: 0;
|
||||
opacity: 0.5;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
transition: all 0.2s cubic-bezier(0.65,0.05,0.36,1);
|
||||
width: 100%;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
&:hover::before {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-shrink: 0;
|
||||
gap: 0.375rem;
|
||||
line-height: 1.1;
|
||||
|
||||
&::before {
|
||||
border-radius: 50%;
|
||||
content: " ";
|
||||
height: 0.35rem;
|
||||
width: 0.35rem;
|
||||
}
|
||||
}
|
||||
|
||||
&[data-state="online"] {
|
||||
label {
|
||||
&::before {
|
||||
background-color: var(--green);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&[data-state="offline"] {
|
||||
label {
|
||||
&::before {
|
||||
background-color: var(--red);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
context('/src/Examples/CollaborativeEditing/React/', () => {
|
||||
context('/src/Demos/SingleRoomCollab/React/', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/src/Examples/CollaborativeEditing/React/')
|
||||
cy.visit('/src/Demos/SingleRoomCollab/React/')
|
||||
})
|
||||
|
||||
/* it('should show the current room with participants', () => {
|
||||
|
@ -50,22 +50,26 @@ export default () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button
|
||||
onClick={setLink}
|
||||
className={editor.isActive('link') ? 'is-active' : ''}
|
||||
data-testid="setLink"
|
||||
>
|
||||
setLink
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().unsetLink().run()}
|
||||
disabled={!editor.isActive('link')}
|
||||
data-testid="unsetLink"
|
||||
>
|
||||
unsetLink
|
||||
</button>
|
||||
<>
|
||||
<div className="control-group">
|
||||
<div className="button-group">
|
||||
<button
|
||||
onClick={setLink}
|
||||
className={editor.isActive('link') ? 'is-active' : ''}
|
||||
data-testid="setLink"
|
||||
>
|
||||
Set link
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().unsetLink().run()}
|
||||
disabled={!editor.isActive('link')}
|
||||
data-testid="unsetLink"
|
||||
>
|
||||
Unset link
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<EditorContent editor={editor} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -1,54 +1,101 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: rgba(#616161, 0.1);
|
||||
color: #616161;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
font-size: 0.8rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
border-left: 2px solid rgba(#0D0D0D, 0.1);
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
/* Link styles */
|
||||
a {
|
||||
color: var(--purple);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: var(--purple-contrast);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,116 +12,118 @@ const MenuBar = ({ editor }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBold().run()}
|
||||
className={editor.isActive('bold') ? 'is-active' : ''}
|
||||
>
|
||||
bold
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleItalic().run()}
|
||||
className={editor.isActive('italic') ? 'is-active' : ''}
|
||||
>
|
||||
italic
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleStrike().run()}
|
||||
className={editor.isActive('strike') ? 'is-active' : ''}
|
||||
>
|
||||
strike
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleCode().run()}
|
||||
className={editor.isActive('code') ? 'is-active' : ''}
|
||||
>
|
||||
code
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().unsetAllMarks().run()}>
|
||||
clear marks
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().clearNodes().run()}>
|
||||
clear nodes
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().setParagraph().run()}
|
||||
className={editor.isActive('paragraph') ? 'is-active' : ''}
|
||||
>
|
||||
paragraph
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
|
||||
className={editor.isActive('heading', { level: 1 }) ? 'is-active' : ''}
|
||||
>
|
||||
h1
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
|
||||
className={editor.isActive('heading', { level: 2 }) ? 'is-active' : ''}
|
||||
>
|
||||
h2
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
|
||||
className={editor.isActive('heading', { level: 3 }) ? 'is-active' : ''}
|
||||
>
|
||||
h3
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 4 }).run()}
|
||||
className={editor.isActive('heading', { level: 4 }) ? 'is-active' : ''}
|
||||
>
|
||||
h4
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 5 }).run()}
|
||||
className={editor.isActive('heading', { level: 5 }) ? 'is-active' : ''}
|
||||
>
|
||||
h5
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 6 }).run()}
|
||||
className={editor.isActive('heading', { level: 6 }) ? 'is-active' : ''}
|
||||
>
|
||||
h6
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBulletList().run()}
|
||||
className={editor.isActive('bulletList') ? 'is-active' : ''}
|
||||
>
|
||||
bullet list
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleOrderedList().run()}
|
||||
className={editor.isActive('orderedList') ? 'is-active' : ''}
|
||||
>
|
||||
ordered list
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleCodeBlock().run()}
|
||||
className={editor.isActive('codeBlock') ? 'is-active' : ''}
|
||||
>
|
||||
code block
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBlockquote().run()}
|
||||
className={editor.isActive('blockquote') ? 'is-active' : ''}
|
||||
>
|
||||
blockquote
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setHorizontalRule().run()}>
|
||||
horizontal rule
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setHardBreak().run()}>
|
||||
hard break
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().undo().run()}>
|
||||
undo
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().redo().run()}>
|
||||
redo
|
||||
</button>
|
||||
</>
|
||||
<div className="control-group">
|
||||
<div className="button-group">
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBold().run()}
|
||||
className={editor.isActive('bold') ? 'is-active' : ''}
|
||||
>
|
||||
Bold
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleItalic().run()}
|
||||
className={editor.isActive('italic') ? 'is-active' : ''}
|
||||
>
|
||||
Italic
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleStrike().run()}
|
||||
className={editor.isActive('strike') ? 'is-active' : ''}
|
||||
>
|
||||
Strike
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleCode().run()}
|
||||
className={editor.isActive('code') ? 'is-active' : ''}
|
||||
>
|
||||
Code
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().unsetAllMarks().run()}>
|
||||
Clear marks
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().clearNodes().run()}>
|
||||
Clear nodes
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().setParagraph().run()}
|
||||
className={editor.isActive('paragraph') ? 'is-active' : ''}
|
||||
>
|
||||
Paragraph
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
|
||||
className={editor.isActive('heading', { level: 1 }) ? 'is-active' : ''}
|
||||
>
|
||||
H1
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
|
||||
className={editor.isActive('heading', { level: 2 }) ? 'is-active' : ''}
|
||||
>
|
||||
H2
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
|
||||
className={editor.isActive('heading', { level: 3 }) ? 'is-active' : ''}
|
||||
>
|
||||
H3
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 4 }).run()}
|
||||
className={editor.isActive('heading', { level: 4 }) ? 'is-active' : ''}
|
||||
>
|
||||
H4
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 5 }).run()}
|
||||
className={editor.isActive('heading', { level: 5 }) ? 'is-active' : ''}
|
||||
>
|
||||
H5
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 6 }).run()}
|
||||
className={editor.isActive('heading', { level: 6 }) ? 'is-active' : ''}
|
||||
>
|
||||
H6
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBulletList().run()}
|
||||
className={editor.isActive('bulletList') ? 'is-active' : ''}
|
||||
>
|
||||
Bullet list
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleOrderedList().run()}
|
||||
className={editor.isActive('orderedList') ? 'is-active' : ''}
|
||||
>
|
||||
Ordered list
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleCodeBlock().run()}
|
||||
className={editor.isActive('codeBlock') ? 'is-active' : ''}
|
||||
>
|
||||
Code block
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBlockquote().run()}
|
||||
className={editor.isActive('blockquote') ? 'is-active' : ''}
|
||||
>
|
||||
Blockquote
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setHorizontalRule().run()}>
|
||||
Horizontal rule
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setHardBreak().run()}>
|
||||
Hard break
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().undo().run()}>
|
||||
Undo
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().redo().run()}>
|
||||
Redo
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -139,9 +141,9 @@ export default () => {
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<MenuBar editor={editor} />
|
||||
<EditorContent editor={editor} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -1,54 +1,91 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: rgba(#616161, 0.1);
|
||||
color: #616161;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
font-size: 0.8rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
border-left: 2px solid rgba(#0D0D0D, 0.1);
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,70 +1,74 @@
|
||||
<template>
|
||||
<div v-if="editor">
|
||||
<button @click="editor.chain().focus().toggleBold().run()" :class="{ 'is-active': editor.isActive('bold') }">
|
||||
bold
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleItalic().run()" :class="{ 'is-active': editor.isActive('italic') }">
|
||||
italic
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleStrike().run()" :class="{ 'is-active': editor.isActive('strike') }">
|
||||
strike
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleCode().run()" :class="{ 'is-active': editor.isActive('code') }">
|
||||
code
|
||||
</button>
|
||||
<button @click="editor.chain().focus().unsetAllMarks().run()">
|
||||
clear marks
|
||||
</button>
|
||||
<button @click="editor.chain().focus().clearNodes().run()">
|
||||
clear nodes
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setParagraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
|
||||
paragraph
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
|
||||
h1
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
|
||||
h2
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
|
||||
h3
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 4 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 4 }) }">
|
||||
h4
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 5 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 5 }) }">
|
||||
h5
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 6 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 6 }) }">
|
||||
h6
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleBulletList().run()" :class="{ 'is-active': editor.isActive('bulletList') }">
|
||||
bullet list
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleOrderedList().run()" :class="{ 'is-active': editor.isActive('orderedList') }">
|
||||
ordered list
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleCodeBlock().run()" :class="{ 'is-active': editor.isActive('codeBlock') }">
|
||||
code block
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleBlockquote().run()" :class="{ 'is-active': editor.isActive('blockquote') }">
|
||||
blockquote
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setHorizontalRule().run()">
|
||||
horizontal rule
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setHardBreak().run()">
|
||||
hard break
|
||||
</button>
|
||||
<button @click="editor.chain().focus().undo().run()">
|
||||
undo
|
||||
</button>
|
||||
<button @click="editor.chain().focus().redo().run()">
|
||||
redo
|
||||
</button>
|
||||
<div v-if="editor" class="container">
|
||||
<div class="control-group">
|
||||
<div class="button-group">
|
||||
<button @click="editor.chain().focus().toggleBold().run()" :class="{ 'is-active': editor.isActive('bold') }">
|
||||
Bold
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleItalic().run()" :class="{ 'is-active': editor.isActive('italic') }">
|
||||
Italic
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleStrike().run()" :class="{ 'is-active': editor.isActive('strike') }">
|
||||
Strike
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleCode().run()" :class="{ 'is-active': editor.isActive('code') }">
|
||||
Code
|
||||
</button>
|
||||
<button @click="editor.chain().focus().unsetAllMarks().run()">
|
||||
Clear marks
|
||||
</button>
|
||||
<button @click="editor.chain().focus().clearNodes().run()">
|
||||
Clear nodes
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setParagraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
|
||||
Paragraph
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
|
||||
H1
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
|
||||
H2
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
|
||||
H3
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 4 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 4 }) }">
|
||||
H4
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 5 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 5 }) }">
|
||||
H5
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 6 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 6 }) }">
|
||||
H6
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleBulletList().run()" :class="{ 'is-active': editor.isActive('bulletList') }">
|
||||
Bullet list
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleOrderedList().run()" :class="{ 'is-active': editor.isActive('orderedList') }">
|
||||
Ordered list
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleCodeBlock().run()" :class="{ 'is-active': editor.isActive('codeBlock') }">
|
||||
Code block
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleBlockquote().run()" :class="{ 'is-active': editor.isActive('blockquote') }">
|
||||
Blockquote
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setHorizontalRule().run()">
|
||||
Horizontal rule
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setHardBreak().run()">
|
||||
Hard break
|
||||
</button>
|
||||
<button @click="editor.chain().focus().undo().run()">
|
||||
Undo
|
||||
</button>
|
||||
<button @click="editor.chain().focus().redo().run()">
|
||||
Redo
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<editor-content :editor="editor" />
|
||||
</div>
|
||||
<editor-content :editor="editor" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -107,15 +111,23 @@ export default {
|
||||
<style lang="scss">
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
@ -123,40 +135,69 @@ export default {
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: rgba(#616161, 0.1);
|
||||
color: #616161;
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
padding-left: 1rem;
|
||||
border-left: 2px solid rgba(#0D0D0D, 0.1);
|
||||
border: none;
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -17,109 +17,109 @@ const MenuBar = ({ editor }) => {
|
||||
onClick={() => editor.chain().focus().toggleBold().run()}
|
||||
className={editor.isActive('bold') ? 'is-active' : ''}
|
||||
>
|
||||
bold
|
||||
Bold
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleItalic().run()}
|
||||
className={editor.isActive('italic') ? 'is-active' : ''}
|
||||
>
|
||||
italic
|
||||
Italic
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleStrike().run()}
|
||||
className={editor.isActive('strike') ? 'is-active' : ''}
|
||||
>
|
||||
strike
|
||||
Strike
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleCode().run()}
|
||||
className={editor.isActive('code') ? 'is-active' : ''}
|
||||
>
|
||||
code
|
||||
Code
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().unsetAllMarks().run()}>
|
||||
clear marks
|
||||
Clear marks
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().clearNodes().run()}>
|
||||
clear nodes
|
||||
Clear nodes
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().setParagraph().run()}
|
||||
className={editor.isActive('paragraph') ? 'is-active' : ''}
|
||||
>
|
||||
paragraph
|
||||
Paragraph
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
|
||||
className={editor.isActive('heading', { level: 1 }) ? 'is-active' : ''}
|
||||
>
|
||||
h1
|
||||
H1
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
|
||||
className={editor.isActive('heading', { level: 2 }) ? 'is-active' : ''}
|
||||
>
|
||||
h2
|
||||
H2
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
|
||||
className={editor.isActive('heading', { level: 3 }) ? 'is-active' : ''}
|
||||
>
|
||||
h3
|
||||
H3
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 4 }).run()}
|
||||
className={editor.isActive('heading', { level: 4 }) ? 'is-active' : ''}
|
||||
>
|
||||
h4
|
||||
H4
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 5 }).run()}
|
||||
className={editor.isActive('heading', { level: 5 }) ? 'is-active' : ''}
|
||||
>
|
||||
h5
|
||||
H5
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 6 }).run()}
|
||||
className={editor.isActive('heading', { level: 6 }) ? 'is-active' : ''}
|
||||
>
|
||||
h6
|
||||
H6
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBulletList().run()}
|
||||
className={editor.isActive('bulletList') ? 'is-active' : ''}
|
||||
>
|
||||
bullet list
|
||||
Bullet list
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleOrderedList().run()}
|
||||
className={editor.isActive('orderedList') ? 'is-active' : ''}
|
||||
>
|
||||
ordered list
|
||||
Ordered list
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleCodeBlock().run()}
|
||||
className={editor.isActive('codeBlock') ? 'is-active' : ''}
|
||||
>
|
||||
code block
|
||||
Code block
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBlockquote().run()}
|
||||
className={editor.isActive('blockquote') ? 'is-active' : ''}
|
||||
>
|
||||
blockquote
|
||||
Blockquote
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setHorizontalRule().run()}>
|
||||
horizontal rule
|
||||
Horizontal rule
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setHardBreak().run()}>
|
||||
hard break
|
||||
Hard break
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().undo().run()}>
|
||||
undo
|
||||
Undo
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().redo().run()}>
|
||||
redo
|
||||
Redo
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
@ -135,7 +135,7 @@ export default () => {
|
||||
Hi there,
|
||||
</h2>
|
||||
<p>
|
||||
this is a <em>basic</em> example of <strong>tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
|
||||
this is a <em>basic</em> example of <strong>Tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
@ -163,9 +163,9 @@ export default () => {
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<MenuBar editor={editor} />
|
||||
<EditorContent editor={editor} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -1,56 +1,91 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: rgba(#616161, 0.1);
|
||||
color: #616161;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
font-size: 0.8rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
border-left: 2px solid rgba(#0D0D0D, 0.1);
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 2px solid rgba(#0D0D0D, 0.1);
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,67 +1,67 @@
|
||||
<template>
|
||||
<div v-if="editor" class="toolbar" :class="styles.toolbar">
|
||||
<button @click="editor.chain().focus().toggleBold().run()" :class="{ 'is-active': editor.isActive('bold') }">
|
||||
bold
|
||||
Bold
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleItalic().run()" :class="{ 'is-active': editor.isActive('italic') }">
|
||||
italic
|
||||
Italic
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleStrike().run()" :class="{ 'is-active': editor.isActive('strike') }">
|
||||
strike
|
||||
Strike
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleCode().run()" :class="{ 'is-active': editor.isActive('code') }">
|
||||
code
|
||||
Code
|
||||
</button>
|
||||
<button @click="editor.chain().focus().unsetAllMarks().run()">
|
||||
clear marks
|
||||
Clear marks
|
||||
</button>
|
||||
<button @click="editor.chain().focus().clearNodes().run()">
|
||||
clear nodes
|
||||
Clear nodes
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setParagraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
|
||||
paragraph
|
||||
Paragraph
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
|
||||
h1
|
||||
H1
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
|
||||
h2
|
||||
H2
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
|
||||
h3
|
||||
H3
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 4 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 4 }) }">
|
||||
h4
|
||||
H4
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 5 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 5 }) }">
|
||||
h5
|
||||
H5
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 6 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 6 }) }">
|
||||
h6
|
||||
H6
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleBulletList().run()" :class="{ 'is-active': editor.isActive('bulletList') }">
|
||||
bullet list
|
||||
Bullet list
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleOrderedList().run()" :class="{ 'is-active': editor.isActive('orderedList') }">
|
||||
ordered list
|
||||
Ordered list
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleCodeBlock().run()" :class="{ 'is-active': editor.isActive('codeBlock') }">
|
||||
code block
|
||||
Code block
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleBlockquote().run()" :class="{ 'is-active': editor.isActive('blockquote') }">
|
||||
blockquote
|
||||
Blockquote
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setHorizontalRule().run()">
|
||||
horizontal rule
|
||||
Horizontal rule
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setHardBreak().run()">
|
||||
hard break
|
||||
Hard break
|
||||
</button>
|
||||
<button @click="editor.chain().focus().undo().run()">
|
||||
undo
|
||||
Undo
|
||||
</button>
|
||||
<button @click="editor.chain().focus().redo().run()">
|
||||
redo
|
||||
Redo
|
||||
</button>
|
||||
</div>
|
||||
<editor-content :editor="editor" />
|
||||
@ -95,7 +95,7 @@ export default {
|
||||
This is a red headline
|
||||
</h1>
|
||||
<p>
|
||||
this is a <em>basic</em> example of <strong>tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
|
||||
this is a <em>basic</em> example of <strong>Tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
@ -132,15 +132,23 @@ export default {
|
||||
<style lang="scss">
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
@ -148,41 +156,68 @@ export default {
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: rgba(#616161, 0.1);
|
||||
color: #616161;
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
border-left: 2px solid rgba(#0D0D0D, 0.1);
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 2px solid rgba(#0D0D0D, 0.1);
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
.code-block {
|
||||
position: relative;
|
||||
|
||||
select {
|
||||
position: absolute;
|
||||
right: 0.5rem;
|
||||
top: 0.5rem;
|
||||
.tiptap {
|
||||
.code-block {
|
||||
position: relative;
|
||||
|
||||
select {
|
||||
position: absolute;
|
||||
background-color: var(--white);
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="Black" d="M7 10l5 5 5-5z"/></svg>');
|
||||
right: 0.5rem;
|
||||
top: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,3 @@
|
||||
// load specific languages only
|
||||
// import { lowlight } from 'lowlight/lib/core'
|
||||
// import javascript from 'highlight.js/lib/languages/javascript'
|
||||
// lowlight.registerLanguage('javascript', javascript)
|
||||
import './styles.scss'
|
||||
|
||||
import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight'
|
||||
@ -13,16 +9,21 @@ import css from 'highlight.js/lib/languages/css'
|
||||
import js from 'highlight.js/lib/languages/javascript'
|
||||
import ts from 'highlight.js/lib/languages/typescript'
|
||||
import html from 'highlight.js/lib/languages/xml'
|
||||
// load all highlight.js languages
|
||||
import { lowlight } from 'lowlight'
|
||||
// load all languages with "all" or common languages with "common"
|
||||
import { all, createLowlight } from 'lowlight'
|
||||
import React from 'react'
|
||||
|
||||
import CodeBlockComponent from './CodeBlockComponent.jsx'
|
||||
// eslint-disable-next-line
|
||||
import CodeBlockComponent from './CodeBlockComponent'
|
||||
|
||||
lowlight.registerLanguage('html', html)
|
||||
lowlight.registerLanguage('css', css)
|
||||
lowlight.registerLanguage('js', js)
|
||||
lowlight.registerLanguage('ts', ts)
|
||||
// create a lowlight instance
|
||||
const lowlight = createLowlight(all)
|
||||
|
||||
// you can also register individual languages
|
||||
lowlight.register('html', html)
|
||||
lowlight.register('css', css)
|
||||
lowlight.register('js', js)
|
||||
lowlight.register('ts', ts)
|
||||
|
||||
const MenuBar = ({ editor }) => {
|
||||
if (!editor) {
|
||||
@ -30,9 +31,13 @@ const MenuBar = ({ editor }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<button onClick={() => editor.chain().focus().toggleCodeBlock().run()} className={editor.isActive('codeBlock') ? 'is-active' : ''}>
|
||||
code block
|
||||
</button>
|
||||
<div className="control-group">
|
||||
<div className="button-group">
|
||||
<button onClick={() => editor.chain().focus().toggleCodeBlock().run()} className={editor.isActive('codeBlock') ? 'is-active' : ''}>
|
||||
Toggle code block
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -52,7 +57,7 @@ export default () => {
|
||||
],
|
||||
content: `
|
||||
<p>
|
||||
That’s a boring paragraph followed by a fenced code block:
|
||||
That's a boring paragraph followed by a fenced code block:
|
||||
</p>
|
||||
<pre><code class="language-javascript">for (var i=1; i <= 20; i++)
|
||||
{
|
||||
@ -72,9 +77,9 @@ export default () => {
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<MenuBar editor={editor} />
|
||||
<EditorContent editor={editor} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ context('/src/Examples/CodeBlockLanguage/React/', () => {
|
||||
|
||||
expect(initialCount).to.be.greaterThan(0)
|
||||
|
||||
cy.wait(100)
|
||||
cy.get('.tiptap select').select('java')
|
||||
cy.wait(500)
|
||||
|
||||
|
@ -1,23 +1,25 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0d0d0d;
|
||||
color: #fff;
|
||||
font-family: "JetBrainsMono", monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Code styling */
|
||||
.hljs-comment,
|
||||
.hljs-quote {
|
||||
color: #616161;
|
||||
|
@ -46,13 +46,17 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.code-block {
|
||||
position: relative;
|
||||
.tiptap {
|
||||
.code-block {
|
||||
position: relative;
|
||||
|
||||
select {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
select {
|
||||
position: absolute;
|
||||
background-color: var(--white);
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="Black" d="M7 10l5 5 5-5z"/></svg>');
|
||||
right: 0.5rem;
|
||||
top: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -15,6 +15,7 @@ context('/src/Examples/CodeBlockLanguage/Vue/', () => {
|
||||
|
||||
expect(initialCount).to.be.greaterThan(0)
|
||||
|
||||
cy.wait(100)
|
||||
cy.get('.tiptap select').select('java')
|
||||
cy.wait(500)
|
||||
|
||||
|
@ -1,8 +1,12 @@
|
||||
<template>
|
||||
<div v-if="editor">
|
||||
<button @click="editor.chain().focus().toggleCodeBlock().run()" :class="{ 'is-active': editor.isActive('codeBlock') }">
|
||||
code block
|
||||
</button>
|
||||
<div v-if="editor" class="container">
|
||||
<div class="control-group">
|
||||
<div class="button-">
|
||||
<button @click="editor.chain().focus().toggleCodeBlock().run()" :class="{ 'is-active': editor.isActive('codeBlock') }">
|
||||
Toggle code block
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<editor-content :editor="editor" />
|
||||
</template>
|
||||
@ -17,20 +21,19 @@ import css from 'highlight.js/lib/languages/css'
|
||||
import js from 'highlight.js/lib/languages/javascript'
|
||||
import ts from 'highlight.js/lib/languages/typescript'
|
||||
import html from 'highlight.js/lib/languages/xml'
|
||||
// load all highlight.js languages
|
||||
import { lowlight } from 'lowlight'
|
||||
// load all languages with "all" or common languages with "common"
|
||||
import { all, createLowlight } from 'lowlight'
|
||||
|
||||
import CodeBlockComponent from './CodeBlockComponent.vue'
|
||||
|
||||
lowlight.registerLanguage('html', html)
|
||||
lowlight.registerLanguage('css', css)
|
||||
lowlight.registerLanguage('js', js)
|
||||
lowlight.registerLanguage('ts', ts)
|
||||
// create a lowlight instance
|
||||
const lowlight = createLowlight(all)
|
||||
|
||||
// load specific languages only
|
||||
// import { lowlight } from 'lowlight/lib/core'
|
||||
// import javascript from 'highlight.js/lib/languages/javascript'
|
||||
// lowlight.registerLanguage('javascript', javascript)
|
||||
// you can also register languages
|
||||
lowlight.register('html', html)
|
||||
lowlight.register('css', css)
|
||||
lowlight.register('js', js)
|
||||
lowlight.register('ts', ts)
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -59,7 +62,7 @@ export default {
|
||||
],
|
||||
content: `
|
||||
<p>
|
||||
That’s a boring paragraph followed by a fenced code block:
|
||||
That's a boring paragraph followed by a fenced code block:
|
||||
</p>
|
||||
<pre><code class="language-javascript">for (var i=1; i <= 20; i++)
|
||||
{
|
||||
@ -88,24 +91,26 @@ export default {
|
||||
<style lang="scss">
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Code styling */
|
||||
.hljs-comment,
|
||||
.hljs-quote {
|
||||
color: #616161;
|
||||
@ -121,7 +126,7 @@ export default {
|
||||
.hljs-name,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class {
|
||||
color: #F98181;
|
||||
color: #f98181;
|
||||
}
|
||||
|
||||
.hljs-number,
|
||||
@ -131,23 +136,23 @@ export default {
|
||||
.hljs-literal,
|
||||
.hljs-type,
|
||||
.hljs-params {
|
||||
color: #FBBC88;
|
||||
color: #fbbc88;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-symbol,
|
||||
.hljs-bullet {
|
||||
color: #B9F18D;
|
||||
color: #b9f18d;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-section {
|
||||
color: #FAF594;
|
||||
color: #faf594;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag {
|
||||
color: #70CFF8;
|
||||
color: #70cff8;
|
||||
}
|
||||
|
||||
.hljs-emphasis {
|
||||
|
@ -59,25 +59,25 @@ export default ({ editor }) => {
|
||||
},
|
||||
{
|
||||
icon: 'list-unordered',
|
||||
title: 'Bullet List',
|
||||
title: 'Bullet list',
|
||||
action: () => editor.chain().focus().toggleBulletList().run(),
|
||||
isActive: () => editor.isActive('bulletList'),
|
||||
},
|
||||
{
|
||||
icon: 'list-ordered',
|
||||
title: 'Ordered List',
|
||||
title: 'Ordered list',
|
||||
action: () => editor.chain().focus().toggleOrderedList().run(),
|
||||
isActive: () => editor.isActive('orderedList'),
|
||||
},
|
||||
{
|
||||
icon: 'list-check-2',
|
||||
title: 'Task List',
|
||||
title: 'Task list',
|
||||
action: () => editor.chain().focus().toggleTaskList().run(),
|
||||
isActive: () => editor.isActive('taskList'),
|
||||
},
|
||||
{
|
||||
icon: 'code-box-line',
|
||||
title: 'Code Block',
|
||||
title: 'Code block',
|
||||
action: () => editor.chain().focus().toggleCodeBlock().run(),
|
||||
isActive: () => editor.isActive('codeBlock'),
|
||||
},
|
||||
@ -92,7 +92,7 @@ export default ({ editor }) => {
|
||||
},
|
||||
{
|
||||
icon: 'separator',
|
||||
title: 'Horizontal Rule',
|
||||
title: 'Horizontal rule',
|
||||
action: () => editor.chain().focus().setHorizontalRule().run(),
|
||||
},
|
||||
{
|
||||
@ -100,12 +100,12 @@ export default ({ editor }) => {
|
||||
},
|
||||
{
|
||||
icon: 'text-wrap',
|
||||
title: 'Hard Break',
|
||||
title: 'Hard break',
|
||||
action: () => editor.chain().focus().setHardBreak().run(),
|
||||
},
|
||||
{
|
||||
icon: 'format-clear',
|
||||
title: 'Clear Format',
|
||||
title: 'Clear format',
|
||||
action: () => editor.chain().focus().clearNodes().unsetAllMarks()
|
||||
.run(),
|
||||
},
|
||||
|
@ -78,25 +78,25 @@ export default {
|
||||
},
|
||||
{
|
||||
icon: 'list-unordered',
|
||||
title: 'Bullet List',
|
||||
title: 'Bullet list',
|
||||
action: () => this.editor.chain().focus().toggleBulletList().run(),
|
||||
isActive: () => this.editor.isActive('bulletList'),
|
||||
},
|
||||
{
|
||||
icon: 'list-ordered',
|
||||
title: 'Ordered List',
|
||||
title: 'Ordered list',
|
||||
action: () => this.editor.chain().focus().toggleOrderedList().run(),
|
||||
isActive: () => this.editor.isActive('orderedList'),
|
||||
},
|
||||
{
|
||||
icon: 'list-check-2',
|
||||
title: 'Task List',
|
||||
title: 'Task list',
|
||||
action: () => this.editor.chain().focus().toggleTaskList().run(),
|
||||
isActive: () => this.editor.isActive('taskList'),
|
||||
},
|
||||
{
|
||||
icon: 'code-box-line',
|
||||
title: 'Code Block',
|
||||
title: 'Code block',
|
||||
action: () => this.editor.chain().focus().toggleCodeBlock().run(),
|
||||
isActive: () => this.editor.isActive('codeBlock'),
|
||||
},
|
||||
@ -111,7 +111,7 @@ export default {
|
||||
},
|
||||
{
|
||||
icon: 'separator',
|
||||
title: 'Horizontal Rule',
|
||||
title: 'Horizontal rule',
|
||||
action: () => this.editor.chain().focus().setHorizontalRule().run(),
|
||||
},
|
||||
{
|
||||
@ -119,12 +119,12 @@ export default {
|
||||
},
|
||||
{
|
||||
icon: 'text-wrap',
|
||||
title: 'Hard Break',
|
||||
title: 'Hard break',
|
||||
action: () => this.editor.chain().focus().setHardBreak().run(),
|
||||
},
|
||||
{
|
||||
icon: 'format-clear',
|
||||
title: 'Clear Format',
|
||||
title: 'Clear format',
|
||||
action: () => this.editor.chain()
|
||||
.focus()
|
||||
.clearNodes()
|
||||
|
@ -54,11 +54,11 @@ export const MentionList = forwardRef((props, ref) => {
|
||||
}))
|
||||
|
||||
return (
|
||||
<div className="items">
|
||||
<div className="dropdown-menu">
|
||||
{props.items.length
|
||||
? props.items.map((item, index) => (
|
||||
<button
|
||||
className={`item ${index === selectedIndex ? 'is-selected' : ''}`}
|
||||
className={index === selectedIndex ? 'is-selected' : ''}
|
||||
key={index}
|
||||
onClick={() => selectItem(index)}
|
||||
>
|
||||
|
@ -1,28 +1,31 @@
|
||||
.items {
|
||||
padding: 0.2rem;
|
||||
/* Dropdown menu */
|
||||
.dropdown-menu {
|
||||
background: var(--white);
|
||||
border: 1px solid var(--gray-1);
|
||||
border-radius: 0.7rem;
|
||||
box-shadow: var(--shadow);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.1rem;
|
||||
overflow: auto;
|
||||
padding: 0.4rem;
|
||||
position: relative;
|
||||
border-radius: 0.5rem;
|
||||
background: #FFF;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
overflow: hidden;
|
||||
font-size: 0.9rem;
|
||||
box-shadow:
|
||||
0 0 0 1px rgba(0, 0, 0, 0.05),
|
||||
0px 10px 20px rgba(0, 0, 0, 0.1),
|
||||
;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: block;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
background: transparent;
|
||||
border-radius: 0.4rem;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.2rem 0.4rem;
|
||||
button {
|
||||
align-items: center;
|
||||
background-color: transparent;
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
|
||||
&:hover,
|
||||
&:hover.is-selected {
|
||||
background-color: var(--gray-3);
|
||||
}
|
||||
|
||||
&.is-selected {
|
||||
border-color: #000;
|
||||
&.is-selected {
|
||||
background-color: var(--gray-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ export default () => {
|
||||
: 0
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<EditorContent editor={editor} />
|
||||
{editor
|
||||
&& <div className={`character-count ${editor.storage.characterCount.characters() === limit ? 'character-count--warning' : ''}`}>
|
||||
@ -48,7 +48,6 @@ export default () => {
|
||||
height="20"
|
||||
width="20"
|
||||
viewBox="0 0 20 20"
|
||||
className="character-count__graph"
|
||||
>
|
||||
<circle
|
||||
r="10"
|
||||
@ -74,11 +73,9 @@ export default () => {
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<div className="character-count__text">
|
||||
{editor.storage.characterCount.characters()}/{limit} characters
|
||||
</div>
|
||||
{editor.storage.characterCount.characters()} / {limit} characters
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -4,33 +4,33 @@ context('/src/Examples/Community/React/', () => {
|
||||
})
|
||||
|
||||
it('should count the characters correctly', () => {
|
||||
// check if count text is "44/280 characters"
|
||||
cy.get('.character-count__text').should('have.text', '44/280 characters')
|
||||
// check if count text is "44 / 280 characters"
|
||||
cy.get('.character-count').should('contain', '44 / 280 characters')
|
||||
|
||||
// type in .tiptap
|
||||
cy.get('.tiptap').type(' Hello World')
|
||||
cy.get('.character-count__text').should('have.text', '56/280 characters')
|
||||
cy.get('.character-count').should('contain', '56 / 280 characters')
|
||||
|
||||
// remove content from .tiptap and enter text
|
||||
cy.get('.tiptap').type('{selectall}{backspace}Hello World')
|
||||
cy.get('.character-count__text').should('have.text', '11/280 characters')
|
||||
cy.get('.character-count').should('contain', '11 / 280 characters')
|
||||
})
|
||||
|
||||
it('should mention a user', () => {
|
||||
cy.get('.tiptap').type('{selectall}{backspace}@')
|
||||
|
||||
// check if the mention autocomplete is visible
|
||||
cy.get('.tippy-content .items').should('be.visible')
|
||||
cy.get('.tippy-content .dropdown-menu').should('be.visible')
|
||||
|
||||
// select the first user
|
||||
cy.get('.tippy-content .items .item').first().then($el => {
|
||||
cy.get('.tippy-content .dropdown-menu button').first().then($el => {
|
||||
const name = $el.text()
|
||||
|
||||
$el.click()
|
||||
|
||||
// check if the user is mentioned
|
||||
cy.get('.tiptap').should('have.text', `@${name} `)
|
||||
cy.get('.character-count__text').should('have.text', '2/280 characters')
|
||||
cy.get('.character-count').should('contain', '2 / 280 characters')
|
||||
})
|
||||
|
||||
})
|
||||
|
@ -1,41 +1,33 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
|
||||
.mention {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
box-decoration-break: clone;
|
||||
color: var(--purple);
|
||||
padding: 0.1rem 0.3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.mention {
|
||||
border: 1px solid #000;
|
||||
border-radius: 0.4rem;
|
||||
padding: 0.1rem 0.3rem;
|
||||
box-decoration-break: clone;
|
||||
}
|
||||
|
||||
/* Character count */
|
||||
.character-count {
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #68CEF8;
|
||||
color: var(--gray-5);
|
||||
display: flex;
|
||||
font-size: 0.75rem;
|
||||
gap: .5rem;
|
||||
margin: 1.5rem;
|
||||
|
||||
&--warning {
|
||||
color: #FB5151;
|
||||
svg {
|
||||
color: var(--purple);
|
||||
}
|
||||
|
||||
&__graph {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
&__text {
|
||||
color: #868e96;
|
||||
&--warning,
|
||||
&--warning svg {
|
||||
color: var(--red);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
<template>
|
||||
<div class="items">
|
||||
<div class="dropdown-menu">
|
||||
<template v-if="items.length">
|
||||
<button
|
||||
class="item"
|
||||
:class="{ 'is-selected': index === selectedIndex }"
|
||||
v-for="(item, index) in items"
|
||||
:key="index"
|
||||
@ -87,32 +86,35 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.items {
|
||||
padding: 0.2rem;
|
||||
/* Dropdown menu */
|
||||
.dropdown-menu {
|
||||
background: var(--white);
|
||||
border: 1px solid var(--gray-1);
|
||||
border-radius: 0.7rem;
|
||||
box-shadow: var(--shadow);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.1rem;
|
||||
overflow: auto;
|
||||
padding: 0.4rem;
|
||||
position: relative;
|
||||
border-radius: 0.5rem;
|
||||
background: #FFF;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
overflow: hidden;
|
||||
font-size: 0.9rem;
|
||||
box-shadow:
|
||||
0 0 0 1px rgba(0, 0, 0, 0.05),
|
||||
0px 10px 20px rgba(0, 0, 0, 0.1),
|
||||
;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: block;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
background: transparent;
|
||||
border-radius: 0.4rem;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.2rem 0.4rem;
|
||||
button {
|
||||
align-items: center;
|
||||
background-color: transparent;
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
|
||||
&.is-selected {
|
||||
border-color: #000;
|
||||
&:hover,
|
||||
&:hover.is-selected {
|
||||
background-color: var(--gray-3);
|
||||
}
|
||||
|
||||
&.is-selected {
|
||||
background-color: var(--gray-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -4,33 +4,33 @@ context('/src/Examples/Community/Vue/', () => {
|
||||
})
|
||||
|
||||
it('should count the characters correctly', () => {
|
||||
// check if count text is "44/280 characters"
|
||||
cy.get('.character-count__text').should('have.text', '44/280 characters')
|
||||
// check if count text is "44 / 280 characters"
|
||||
cy.get('.character-count').should('contain', '44 / 280 characters')
|
||||
|
||||
// type in .tiptap
|
||||
cy.get('.tiptap').type(' Hello World')
|
||||
cy.get('.character-count__text').should('have.text', '56/280 characters')
|
||||
cy.get('.character-count').should('contain', '56 / 280 characters')
|
||||
|
||||
// remove content from .tiptap and enter text
|
||||
cy.get('.tiptap').type('{selectall}{backspace}Hello World')
|
||||
cy.get('.character-count__text').should('have.text', '11/280 characters')
|
||||
cy.get('.character-count').should('contain', '11 / 280 characters')
|
||||
})
|
||||
|
||||
it('should mention a user', () => {
|
||||
cy.get('.tiptap').type('{selectall}{backspace}@')
|
||||
|
||||
// check if the mention autocomplete is visible
|
||||
cy.get('.tippy-content .items').should('be.visible')
|
||||
cy.get('.tippy-content .dropdown-menu').should('be.visible')
|
||||
|
||||
// select the first user
|
||||
cy.get('.tippy-content .items .item').first().then($el => {
|
||||
cy.get('.tippy-content .dropdown-menu button').first().then($el => {
|
||||
const name = $el.text()
|
||||
|
||||
$el.click()
|
||||
|
||||
// check if the user is mentioned
|
||||
cy.get('.tiptap').should('have.text', `@${name} `)
|
||||
cy.get('.character-count__text').should('have.text', '2/280 characters')
|
||||
cy.get('.character-count').should('contain', '2 / 280 characters')
|
||||
})
|
||||
|
||||
})
|
||||
|
@ -6,7 +6,6 @@
|
||||
height="20"
|
||||
width="20"
|
||||
viewBox="0 0 20 20"
|
||||
class="character-count__graph"
|
||||
>
|
||||
<circle
|
||||
r="10"
|
||||
@ -32,7 +31,7 @@
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<div class="character-count__text">{{ editor.storage.characterCount.characters() }}/{{ limit }} characters</div>
|
||||
{{ editor.storage.characterCount.characters() }} / {{ limit }} characters
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -97,43 +96,35 @@ export default {
|
||||
<style lang="scss">
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
.mention {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
box-decoration-break: clone;
|
||||
color: var(--purple);
|
||||
padding: 0.1rem 0.3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.mention {
|
||||
border: 1px solid #000;
|
||||
border-radius: 0.4rem;
|
||||
padding: 0.1rem 0.3rem;
|
||||
box-decoration-break: clone;
|
||||
}
|
||||
|
||||
/* Character count */
|
||||
.character-count {
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #68CEF8;
|
||||
color: var(--gray-5);
|
||||
display: flex;
|
||||
font-size: 0.75rem;
|
||||
gap: .5rem;
|
||||
margin: 1.5rem;
|
||||
|
||||
&--warning {
|
||||
color: #FB5151;
|
||||
svg {
|
||||
color: var(--purple);
|
||||
}
|
||||
|
||||
&__graph {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
&__text {
|
||||
color: #868e96;
|
||||
&--warning,
|
||||
&--warning svg {
|
||||
color: var(--red);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,24 +1,109 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
/* Placeholder (at the top) */
|
||||
/* p.is-editor-empty:first-child::before {
|
||||
color: var(--gray-4);
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
height: 0;
|
||||
pointer-events: none;
|
||||
}*/
|
||||
|
||||
/* Placeholder (on every new line) */
|
||||
.is-empty::before {
|
||||
color: var(--gray-4);
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
height: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Placeholder (at the top) */
|
||||
/*.tiptap p.is-editor-empty:first-child::before {
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
color: #ced4da;
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
}*/
|
||||
|
||||
/* Placeholder (on every new line) */
|
||||
.tiptap .is-empty::before {
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
color: #ced4da;
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
}
|
||||
|
@ -60,26 +60,111 @@ export default {
|
||||
<style lang="scss">
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
/* Placeholder (at the top) */
|
||||
/* p.is-editor-empty:first-child::before {
|
||||
color: var(--gray-4);
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
height: 0;
|
||||
pointer-events: none;
|
||||
}*/
|
||||
|
||||
/* Placeholder (on every new line) */
|
||||
.is-empty::before {
|
||||
color: var(--gray-4);
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
height: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Placeholder (at the top) */
|
||||
/*.tiptap p.is-editor-empty:first-child::before {
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
color: #ced4da;
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
}*/
|
||||
|
||||
/* Placeholder (on every new line) */
|
||||
.tiptap .is-empty::before {
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
color: #ced4da;
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,24 +1,91 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Placeholder (at the top) */
|
||||
/*.tiptap p.is-editor-empty:first-child::before {
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
color: #ced4da;
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
}*/
|
||||
|
||||
/* Placeholder (on every new line) */
|
||||
.tiptap .is-empty::before {
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
color: #ced4da;
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
}
|
||||
|
@ -15,168 +15,170 @@ const MenuBar = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBold().run()}
|
||||
disabled={
|
||||
!editor.can()
|
||||
.chain()
|
||||
.focus()
|
||||
.toggleBold()
|
||||
.run()
|
||||
}
|
||||
className={editor.isActive('bold') ? 'is-active' : ''}
|
||||
>
|
||||
bold
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleItalic().run()}
|
||||
disabled={
|
||||
!editor.can()
|
||||
.chain()
|
||||
.focus()
|
||||
.toggleItalic()
|
||||
.run()
|
||||
}
|
||||
className={editor.isActive('italic') ? 'is-active' : ''}
|
||||
>
|
||||
italic
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleStrike().run()}
|
||||
disabled={
|
||||
!editor.can()
|
||||
.chain()
|
||||
.focus()
|
||||
.toggleStrike()
|
||||
.run()
|
||||
}
|
||||
className={editor.isActive('strike') ? 'is-active' : ''}
|
||||
>
|
||||
strike
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleCode().run()}
|
||||
disabled={
|
||||
!editor.can()
|
||||
.chain()
|
||||
.focus()
|
||||
.toggleCode()
|
||||
.run()
|
||||
}
|
||||
className={editor.isActive('code') ? 'is-active' : ''}
|
||||
>
|
||||
code
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().unsetAllMarks().run()}>
|
||||
clear marks
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().clearNodes().run()}>
|
||||
clear nodes
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().setParagraph().run()}
|
||||
className={editor.isActive('paragraph') ? 'is-active' : ''}
|
||||
>
|
||||
paragraph
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
|
||||
className={editor.isActive('heading', { level: 1 }) ? 'is-active' : ''}
|
||||
>
|
||||
h1
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
|
||||
className={editor.isActive('heading', { level: 2 }) ? 'is-active' : ''}
|
||||
>
|
||||
h2
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
|
||||
className={editor.isActive('heading', { level: 3 }) ? 'is-active' : ''}
|
||||
>
|
||||
h3
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 4 }).run()}
|
||||
className={editor.isActive('heading', { level: 4 }) ? 'is-active' : ''}
|
||||
>
|
||||
h4
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 5 }).run()}
|
||||
className={editor.isActive('heading', { level: 5 }) ? 'is-active' : ''}
|
||||
>
|
||||
h5
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 6 }).run()}
|
||||
className={editor.isActive('heading', { level: 6 }) ? 'is-active' : ''}
|
||||
>
|
||||
h6
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBulletList().run()}
|
||||
className={editor.isActive('bulletList') ? 'is-active' : ''}
|
||||
>
|
||||
bullet list
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleOrderedList().run()}
|
||||
className={editor.isActive('orderedList') ? 'is-active' : ''}
|
||||
>
|
||||
ordered list
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleCodeBlock().run()}
|
||||
className={editor.isActive('codeBlock') ? 'is-active' : ''}
|
||||
>
|
||||
code block
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBlockquote().run()}
|
||||
className={editor.isActive('blockquote') ? 'is-active' : ''}
|
||||
>
|
||||
blockquote
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setHorizontalRule().run()}>
|
||||
horizontal rule
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setHardBreak().run()}>
|
||||
hard break
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().undo().run()}
|
||||
disabled={
|
||||
!editor.can()
|
||||
.chain()
|
||||
.focus()
|
||||
.undo()
|
||||
.run()
|
||||
}
|
||||
>
|
||||
undo
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().redo().run()}
|
||||
disabled={
|
||||
!editor.can()
|
||||
.chain()
|
||||
.focus()
|
||||
.redo()
|
||||
.run()
|
||||
}
|
||||
>
|
||||
redo
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().setColor('#958DF1').run()}
|
||||
className={editor.isActive('textStyle', { color: '#958DF1' }) ? 'is-active' : ''}
|
||||
>
|
||||
purple
|
||||
</button>
|
||||
</>
|
||||
<div className="control-group">
|
||||
<div className="button-group">
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBold().run()}
|
||||
disabled={
|
||||
!editor.can()
|
||||
.chain()
|
||||
.focus()
|
||||
.toggleBold()
|
||||
.run()
|
||||
}
|
||||
className={editor.isActive('bold') ? 'is-active' : ''}
|
||||
>
|
||||
Bold
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleItalic().run()}
|
||||
disabled={
|
||||
!editor.can()
|
||||
.chain()
|
||||
.focus()
|
||||
.toggleItalic()
|
||||
.run()
|
||||
}
|
||||
className={editor.isActive('italic') ? 'is-active' : ''}
|
||||
>
|
||||
Italic
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleStrike().run()}
|
||||
disabled={
|
||||
!editor.can()
|
||||
.chain()
|
||||
.focus()
|
||||
.toggleStrike()
|
||||
.run()
|
||||
}
|
||||
className={editor.isActive('strike') ? 'is-active' : ''}
|
||||
>
|
||||
Strike
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleCode().run()}
|
||||
disabled={
|
||||
!editor.can()
|
||||
.chain()
|
||||
.focus()
|
||||
.toggleCode()
|
||||
.run()
|
||||
}
|
||||
className={editor.isActive('code') ? 'is-active' : ''}
|
||||
>
|
||||
Code
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().unsetAllMarks().run()}>
|
||||
Clear marks
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().clearNodes().run()}>
|
||||
Clear nodes
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().setParagraph().run()}
|
||||
className={editor.isActive('paragraph') ? 'is-active' : ''}
|
||||
>
|
||||
Paragraph
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
|
||||
className={editor.isActive('heading', { level: 1 }) ? 'is-active' : ''}
|
||||
>
|
||||
H1
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
|
||||
className={editor.isActive('heading', { level: 2 }) ? 'is-active' : ''}
|
||||
>
|
||||
H2
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
|
||||
className={editor.isActive('heading', { level: 3 }) ? 'is-active' : ''}
|
||||
>
|
||||
H3
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 4 }).run()}
|
||||
className={editor.isActive('heading', { level: 4 }) ? 'is-active' : ''}
|
||||
>
|
||||
H4
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 5 }).run()}
|
||||
className={editor.isActive('heading', { level: 5 }) ? 'is-active' : ''}
|
||||
>
|
||||
H5
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 6 }).run()}
|
||||
className={editor.isActive('heading', { level: 6 }) ? 'is-active' : ''}
|
||||
>
|
||||
H6
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBulletList().run()}
|
||||
className={editor.isActive('bulletList') ? 'is-active' : ''}
|
||||
>
|
||||
Bullet list
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleOrderedList().run()}
|
||||
className={editor.isActive('orderedList') ? 'is-active' : ''}
|
||||
>
|
||||
Ordered list
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleCodeBlock().run()}
|
||||
className={editor.isActive('codeBlock') ? 'is-active' : ''}
|
||||
>
|
||||
Code block
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().toggleBlockquote().run()}
|
||||
className={editor.isActive('blockquote') ? 'is-active' : ''}
|
||||
>
|
||||
Blockquote
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setHorizontalRule().run()}>
|
||||
Horizontal rule
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setHardBreak().run()}>
|
||||
Hard break
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().undo().run()}
|
||||
disabled={
|
||||
!editor.can()
|
||||
.chain()
|
||||
.focus()
|
||||
.undo()
|
||||
.run()
|
||||
}
|
||||
>
|
||||
Undo
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().redo().run()}
|
||||
disabled={
|
||||
!editor.can()
|
||||
.chain()
|
||||
.focus()
|
||||
.redo()
|
||||
.run()
|
||||
}
|
||||
>
|
||||
Redo
|
||||
</button>
|
||||
<button
|
||||
onClick={() => editor.chain().focus().setColor('#958DF1').run()}
|
||||
className={editor.isActive('textStyle', { color: '#958DF1' }) ? 'is-active' : ''}
|
||||
>
|
||||
Purple
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -200,7 +202,7 @@ const content = `
|
||||
Hi there,
|
||||
</h2>
|
||||
<p>
|
||||
this is a <em>basic</em> example of <strong>tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
|
||||
this is a <em>basic</em> example of <strong>Tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
@ -214,7 +216,7 @@ const content = `
|
||||
Isn’t that great? And all of that is editable. But wait, there’s more. Let’s try a code block:
|
||||
</p>
|
||||
<pre><code class="language-css">body {
|
||||
display: none;
|
||||
display: none;
|
||||
}</code></pre>
|
||||
<p>
|
||||
I know, I know, this is impressive. It’s only the tip of the iceberg though. Give it a try and click a little bit around. Don’t forget to check the other examples too.
|
||||
|
@ -21,41 +21,41 @@ context('/src/Examples/Default/React/', () => {
|
||||
})
|
||||
|
||||
const buttonMarks = [
|
||||
{ label: 'bold', tag: 'strong' },
|
||||
{ label: 'italic', tag: 'em' },
|
||||
{ label: 'strike', tag: 's' },
|
||||
{ label: 'Bold', tag: 'strong' },
|
||||
{ label: 'Italic', tag: 'em' },
|
||||
{ label: 'Strike', tag: 's' },
|
||||
]
|
||||
|
||||
buttonMarks.forEach(m => {
|
||||
it(`should disable ${m.label} when the code tag is enabled for cursor`, () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('code').click()
|
||||
cy.get('button').contains('Code').click()
|
||||
cy.get('button').contains(m.label).should('be.disabled')
|
||||
})
|
||||
|
||||
it(`should enable ${m.label} when the code tag is disabled for cursor`, () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('code').click()
|
||||
cy.get('button').contains('code').click()
|
||||
cy.get('button').contains('Code').click()
|
||||
cy.get('button').contains('Code').click()
|
||||
cy.get('button').contains(m.label).should('not.be.disabled')
|
||||
})
|
||||
|
||||
it(`should disable ${m.label} when the code tag is enabled for selection`, () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world{selectall}')
|
||||
cy.get('button').contains('code').click()
|
||||
cy.get('button').contains('Code').click()
|
||||
cy.get('button').contains(m.label).should('be.disabled')
|
||||
})
|
||||
|
||||
it(`should enable ${m.label} when the code tag is disabled for selection`, () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world{selectall}')
|
||||
cy.get('button').contains('code').click()
|
||||
cy.get('button').contains('code').click()
|
||||
cy.get('button').contains('Code').click()
|
||||
cy.get('button').contains('Code').click()
|
||||
cy.get('button').contains(m.label).should('not.be.disabled')
|
||||
})
|
||||
|
||||
it(`should apply ${m.label} when the button is pressed`, () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('paragraph').click()
|
||||
cy.get('button').contains('Paragraph').click()
|
||||
cy.get('.tiptap').type('{selectall}')
|
||||
cy.get('button').contains(m.label).click()
|
||||
cy.get(`.tiptap ${m.tag}`).should('exist').should('have.text', 'Hello world')
|
||||
@ -64,40 +64,40 @@ context('/src/Examples/Default/React/', () => {
|
||||
|
||||
it('should clear marks when the button is pressed', () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('paragraph').click()
|
||||
cy.get('button').contains('Paragraph').click()
|
||||
cy.get('.tiptap').type('{selectall}')
|
||||
cy.get('button').contains('bold').click()
|
||||
cy.get('button').contains('Bold').click()
|
||||
cy.get('.tiptap strong').should('exist').should('have.text', 'Hello world')
|
||||
cy.get('button').contains('clear marks').click()
|
||||
cy.get('button').contains('Clear marks').click()
|
||||
cy.get('.tiptap strong').should('not.exist')
|
||||
})
|
||||
|
||||
it('should clear nodes when the button is pressed', () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('bullet list').click()
|
||||
cy.get('button').contains('Bullet list').click()
|
||||
cy.get('.tiptap ul').should('exist').should('have.text', 'Hello world')
|
||||
cy.get('.tiptap').type('{enter}A second item{enter}A third item{selectall}')
|
||||
cy.get('button').contains('clear nodes').click()
|
||||
cy.get('button').contains('Clear nodes').click()
|
||||
cy.get('.tiptap ul').should('not.exist')
|
||||
cy.get('.tiptap p').should('have.length', 3)
|
||||
})
|
||||
|
||||
const buttonNodes = [
|
||||
{ label: 'h1', tag: 'h1' },
|
||||
{ label: 'h2', tag: 'h2' },
|
||||
{ label: 'h3', tag: 'h3' },
|
||||
{ label: 'h4', tag: 'h4' },
|
||||
{ label: 'h5', tag: 'h5' },
|
||||
{ label: 'h6', tag: 'h6' },
|
||||
{ label: 'bullet list', tag: 'ul' },
|
||||
{ label: 'ordered list', tag: 'ol' },
|
||||
{ label: 'code block', tag: 'pre code' },
|
||||
{ label: 'blockquote', tag: 'blockquote' },
|
||||
{ label: 'H1', tag: 'h1' },
|
||||
{ label: 'H2', tag: 'h2' },
|
||||
{ label: 'H3', tag: 'h3' },
|
||||
{ label: 'H4', tag: 'h4' },
|
||||
{ label: 'H5', tag: 'h5' },
|
||||
{ label: 'H6', tag: 'h6' },
|
||||
{ label: 'Bullet list', tag: 'ul' },
|
||||
{ label: 'Ordered list', tag: 'ol' },
|
||||
{ label: 'Code block', tag: 'pre code' },
|
||||
{ label: 'Blockquote', tag: 'blockquote' },
|
||||
]
|
||||
|
||||
buttonNodes.forEach(n => {
|
||||
it(`should set ${n.label} when the button is pressed`, () => {
|
||||
cy.get('button').contains('paragraph').click()
|
||||
cy.get('button').contains('Paragraph').click()
|
||||
cy.get('.tiptap').type('{selectall}Hello world{selectall}')
|
||||
|
||||
cy.get('button').contains(n.label).click()
|
||||
@ -109,35 +109,35 @@ context('/src/Examples/Default/React/', () => {
|
||||
|
||||
it('should add a hr when on the same line as a node', () => {
|
||||
cy.get('.tiptap').type('{rightArrow}')
|
||||
cy.get('button').contains('horizontal rule').click()
|
||||
cy.get('button').contains('Horizontal rule').click()
|
||||
cy.get('.tiptap hr').should('exist')
|
||||
cy.get('.tiptap h1').should('exist')
|
||||
})
|
||||
|
||||
it('should add a hr when on a new line', () => {
|
||||
cy.get('.tiptap').type('{rightArrow}{enter}')
|
||||
cy.get('button').contains('horizontal rule').click()
|
||||
cy.get('button').contains('Horizontal rule').click()
|
||||
cy.get('.tiptap hr').should('exist')
|
||||
cy.get('.tiptap h1').should('exist')
|
||||
})
|
||||
|
||||
it('should add a br', () => {
|
||||
cy.get('.tiptap').type('{rightArrow}')
|
||||
cy.get('button').contains('hard break').click()
|
||||
cy.get('button').contains('Hard break').click()
|
||||
cy.get('.tiptap h1 br').should('exist')
|
||||
})
|
||||
|
||||
it('should undo', () => {
|
||||
cy.get('.tiptap').type('{selectall}{backspace}')
|
||||
cy.get('button').contains('undo').click()
|
||||
cy.get('button').contains('Undo').click()
|
||||
cy.get('.tiptap').should('contain', 'Hello world')
|
||||
})
|
||||
|
||||
it('should redo', () => {
|
||||
cy.get('.tiptap').type('{selectall}{backspace}')
|
||||
cy.get('button').contains('undo').click()
|
||||
cy.get('button').contains('Undo').click()
|
||||
cy.get('.tiptap').should('contain', 'Hello world')
|
||||
cy.get('button').contains('redo').click()
|
||||
cy.get('button').contains('Redo').click()
|
||||
cy.get('.tiptap').should('not.contain', 'Hello world')
|
||||
})
|
||||
})
|
||||
|
@ -1,56 +1,91 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: rgba(#616161, 0.1);
|
||||
color: #616161;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
font-size: 0.8rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
border-left: 2px solid rgba(#0D0D0D, 0.1);
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 2px solid rgba(#0D0D0D, 0.1);
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
@ -21,15 +21,15 @@ context('/src/Examples/Default/React/', () => {
|
||||
})
|
||||
|
||||
const buttonMarks = [
|
||||
{ label: 'bold', tag: 'strong' },
|
||||
{ label: 'italic', tag: 'em' },
|
||||
{ label: 'strike', tag: 's' },
|
||||
{ label: 'Bold', tag: 'strong' },
|
||||
{ label: 'Italic', tag: 'em' },
|
||||
{ label: 'Strike', tag: 's' },
|
||||
]
|
||||
|
||||
buttonMarks.forEach(m => {
|
||||
it(`should apply ${m.label} when the button is pressed`, () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('paragraph').click()
|
||||
cy.get('button').contains('Paragraph').click()
|
||||
cy.get('.tiptap').type('{selectall}')
|
||||
cy.get('button').contains(m.label).click()
|
||||
cy.get(`.tiptap ${m.tag}`).should('exist').should('have.text', 'Hello world')
|
||||
@ -38,40 +38,40 @@ context('/src/Examples/Default/React/', () => {
|
||||
|
||||
it('should clear marks when the button is pressed', () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('paragraph').click()
|
||||
cy.get('button').contains('Paragraph').click()
|
||||
cy.get('.tiptap').type('{selectall}')
|
||||
cy.get('button').contains('bold').click()
|
||||
cy.get('button').contains('Bold').click()
|
||||
cy.get('.tiptap strong').should('exist').should('have.text', 'Hello world')
|
||||
cy.get('button').contains('clear marks').click()
|
||||
cy.get('button').contains('Clear marks').click()
|
||||
cy.get('.tiptap strong').should('not.exist')
|
||||
})
|
||||
|
||||
it('should clear nodes when the button is pressed', () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('bullet list').click()
|
||||
cy.get('button').contains('Bullet list').click()
|
||||
cy.get('.tiptap ul').should('exist').should('have.text', 'Hello world')
|
||||
cy.get('.tiptap').type('{enter}A second item{enter}A third item{selectall}')
|
||||
cy.get('button').contains('clear nodes').click()
|
||||
cy.get('button').contains('Clear nodes').click()
|
||||
cy.get('.tiptap ul').should('not.exist')
|
||||
cy.get('.tiptap p').should('have.length', 3)
|
||||
})
|
||||
|
||||
const buttonNodes = [
|
||||
{ label: 'h1', tag: 'h1' },
|
||||
{ label: 'h2', tag: 'h2' },
|
||||
{ label: 'h3', tag: 'h3' },
|
||||
{ label: 'h4', tag: 'h4' },
|
||||
{ label: 'h5', tag: 'h5' },
|
||||
{ label: 'h6', tag: 'h6' },
|
||||
{ label: 'bullet list', tag: 'ul' },
|
||||
{ label: 'ordered list', tag: 'ol' },
|
||||
{ label: 'code block', tag: 'pre code' },
|
||||
{ label: 'blockquote', tag: 'blockquote' },
|
||||
{ label: 'H1', tag: 'h1' },
|
||||
{ label: 'H2', tag: 'h2' },
|
||||
{ label: 'H3', tag: 'h3' },
|
||||
{ label: 'H4', tag: 'h4' },
|
||||
{ label: 'H5', tag: 'h5' },
|
||||
{ label: 'H6', tag: 'h6' },
|
||||
{ label: 'Bullet list', tag: 'ul' },
|
||||
{ label: 'Ordered list', tag: 'ol' },
|
||||
{ label: 'Code block', tag: 'pre code' },
|
||||
{ label: 'Blockquote', tag: 'blockquote' },
|
||||
]
|
||||
|
||||
buttonNodes.forEach(n => {
|
||||
it(`should set ${n.label} when the button is pressed`, () => {
|
||||
cy.get('button').contains('paragraph').click()
|
||||
cy.get('button').contains('Paragraph').click()
|
||||
cy.get('.tiptap').type('{selectall}Hello world{selectall}')
|
||||
|
||||
cy.get('button').contains(n.label).click()
|
||||
@ -83,35 +83,35 @@ context('/src/Examples/Default/React/', () => {
|
||||
|
||||
it('should add a hr when on the same line as a node', () => {
|
||||
cy.get('.tiptap').type('{rightArrow}')
|
||||
cy.get('button').contains('horizontal rule').click()
|
||||
cy.get('button').contains('Horizontal rule').click()
|
||||
cy.get('.tiptap hr').should('exist')
|
||||
cy.get('.tiptap h1').should('exist')
|
||||
})
|
||||
|
||||
it('should add a hr when on a new line', () => {
|
||||
cy.get('.tiptap').type('{rightArrow}{enter}')
|
||||
cy.get('button').contains('horizontal rule').click()
|
||||
cy.get('button').contains('Horizontal rule').click()
|
||||
cy.get('.tiptap hr').should('exist')
|
||||
cy.get('.tiptap h1').should('exist')
|
||||
})
|
||||
|
||||
it('should add a br', () => {
|
||||
cy.get('.tiptap').type('{rightArrow}')
|
||||
cy.get('button').contains('hard break').click()
|
||||
cy.get('button').contains('Hard break').click()
|
||||
cy.get('.tiptap h1 br').should('exist')
|
||||
})
|
||||
|
||||
it('should undo', () => {
|
||||
cy.get('.tiptap').type('{selectall}{backspace}')
|
||||
cy.get('button').contains('undo').click()
|
||||
cy.get('button').contains('Undo').click()
|
||||
cy.get('.tiptap').should('contain', 'Hello world')
|
||||
})
|
||||
|
||||
it('should redo', () => {
|
||||
cy.get('.tiptap').type('{selectall}{backspace}')
|
||||
cy.get('button').contains('undo').click()
|
||||
cy.get('button').contains('Undo').click()
|
||||
cy.get('.tiptap').should('contain', 'Hello world')
|
||||
cy.get('button').contains('redo').click()
|
||||
cy.get('button').contains('Redo').click()
|
||||
cy.get('.tiptap').should('not.contain', 'Hello world')
|
||||
})
|
||||
})
|
||||
|
@ -1,6 +1,9 @@
|
||||
<script>
|
||||
import "./styles.scss";
|
||||
|
||||
import { Color } from '@tiptap/extension-color'
|
||||
import ListItem from '@tiptap/extension-list-item'
|
||||
import TextStyle from '@tiptap/extension-text-style'
|
||||
import StarterKit from "@tiptap/starter-kit";
|
||||
import { Editor } from "@tiptap/core";
|
||||
import { onMount } from "svelte";
|
||||
@ -11,13 +14,17 @@
|
||||
onMount(() => {
|
||||
editor = new Editor({
|
||||
element: element,
|
||||
extensions: [StarterKit],
|
||||
extensions: [
|
||||
Color.configure({ types: [TextStyle.name, ListItem.name] }),
|
||||
TextStyle.configure({ types: [ListItem.name] }),
|
||||
StarterKit,
|
||||
],
|
||||
content: `
|
||||
<h2>
|
||||
Hi there,
|
||||
</h2>
|
||||
<p>
|
||||
this is a <em>basic</em> example of <strong>tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
|
||||
this is a <em>basic</em> example of <strong>Tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
@ -31,8 +38,8 @@
|
||||
Isn’t that great? And all of that is editable. But wait, there’s more. Let’s try a code block:
|
||||
</p>
|
||||
<pre><code class="language-css">body {
|
||||
display: none;
|
||||
}</code></pre>
|
||||
display: none;
|
||||
}</code></pre>
|
||||
<p>
|
||||
I know, I know, this is impressive. It’s only the tip of the iceberg though. Give it a try and click a little bit around. Don’t forget to check the other examples too.
|
||||
</p>
|
||||
@ -51,119 +58,125 @@
|
||||
</script>
|
||||
|
||||
{#if editor}
|
||||
<div>
|
||||
<div>
|
||||
<div class="control-group">
|
||||
<div class="button-group">
|
||||
<button
|
||||
on:click={() => console.log && editor.chain().focus().toggleBold().run()}
|
||||
disabled={!editor.can().chain().focus().toggleBold().run()}
|
||||
class={editor.isActive("bold") ? "is-active" : ""}
|
||||
>
|
||||
bold
|
||||
Bold
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().toggleItalic().run()}
|
||||
disabled={!editor.can().chain().focus().toggleItalic().run()}
|
||||
class={editor.isActive("italic") ? "is-active" : ""}
|
||||
>
|
||||
italic
|
||||
Italic
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().toggleStrike().run()}
|
||||
disabled={!editor.can().chain().focus().toggleStrike().run()}
|
||||
class={editor.isActive("strike") ? "is-active" : ""}
|
||||
>
|
||||
strike
|
||||
Strike
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().toggleCode().run()}
|
||||
disabled={!editor.can().chain().focus().toggleCode().run()}
|
||||
class={editor.isActive("code") ? "is-active" : ""}
|
||||
>
|
||||
code
|
||||
Code
|
||||
</button>
|
||||
<button on:click={() => editor.chain().focus().unsetAllMarks().run()}> clear marks </button>
|
||||
<button on:click={() => editor.chain().focus().clearNodes().run()}> clear nodes </button>
|
||||
<button on:click={() => editor.chain().focus().unsetAllMarks().run()}>Clear marks</button>
|
||||
<button on:click={() => editor.chain().focus().clearNodes().run()}>Clear nodes</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().setParagraph().run()}
|
||||
class={editor.isActive("paragraph") ? "is-active" : ""}
|
||||
>
|
||||
paragraph
|
||||
Paragraph
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
|
||||
class={editor.isActive("heading", { level: 1 }) ? "is-active" : ""}
|
||||
>
|
||||
h1
|
||||
H1
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
|
||||
class={editor.isActive("heading", { level: 2 }) ? "is-active" : ""}
|
||||
>
|
||||
h2
|
||||
H2
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
|
||||
class={editor.isActive("heading", { level: 3 }) ? "is-active" : ""}
|
||||
>
|
||||
h3
|
||||
H3
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().toggleHeading({ level: 4 }).run()}
|
||||
class={editor.isActive("heading", { level: 4 }) ? "is-active" : ""}
|
||||
>
|
||||
h4
|
||||
H4
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().toggleHeading({ level: 5 }).run()}
|
||||
class={editor.isActive("heading", { level: 5 }) ? "is-active" : ""}
|
||||
>
|
||||
h5
|
||||
H5
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().toggleHeading({ level: 6 }).run()}
|
||||
class={editor.isActive("heading", { level: 6 }) ? "is-active" : ""}
|
||||
>
|
||||
h6
|
||||
H6
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().toggleBulletList().run()}
|
||||
class={editor.isActive("bulletList") ? "is-active" : ""}
|
||||
>
|
||||
bullet list
|
||||
Bullet list
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().toggleOrderedList().run()}
|
||||
class={editor.isActive("orderedList") ? "is-active" : ""}
|
||||
>
|
||||
ordered list
|
||||
Ordered list
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().toggleCodeBlock().run()}
|
||||
class={editor.isActive("codeBlock") ? "is-active" : ""}
|
||||
>
|
||||
code block
|
||||
Code block
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().toggleBlockquote().run()}
|
||||
class={editor.isActive("blockquote") ? "is-active" : ""}
|
||||
>
|
||||
blockquote
|
||||
Blockquote
|
||||
</button>
|
||||
<button on:click={() => editor.chain().focus().setHorizontalRule().run()}>
|
||||
horizontal rule
|
||||
Horizontal rule
|
||||
</button>
|
||||
<button on:click={() => editor.chain().focus().setHardBreak().run()}> hard break </button>
|
||||
<button on:click={() => editor.chain().focus().setHardBreak().run()}>Hard break</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().undo().run()}
|
||||
disabled={!editor.can().chain().focus().undo().run()}
|
||||
>
|
||||
undo
|
||||
Undo
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().redo().run()}
|
||||
disabled={!editor.can().chain().focus().redo().run()}
|
||||
>
|
||||
redo
|
||||
Redo
|
||||
</button>
|
||||
<button
|
||||
on:click={() => editor.chain().focus().setColor('#958DF1').run()}
|
||||
class={editor.isActive('textStyle', { color: '#958DF1' }) ? 'is-active' : ''}
|
||||
>
|
||||
Purple
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,56 +1,91 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: rgba(#616161, 0.1);
|
||||
color: #616161;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
font-size: 0.8rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
border-left: 2px solid rgba(#0D0D0D, 0.1);
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 2px solid rgba(#0D0D0D, 0.1);
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
@ -21,15 +21,15 @@ context('/src/Examples/Default/Vue/', () => {
|
||||
})
|
||||
|
||||
const buttonMarks = [
|
||||
{ label: 'bold', tag: 'strong' },
|
||||
{ label: 'italic', tag: 'em' },
|
||||
{ label: 'strike', tag: 's' },
|
||||
{ label: 'Bold', tag: 'strong' },
|
||||
{ label: 'Italic', tag: 'em' },
|
||||
{ label: 'Strike', tag: 's' },
|
||||
]
|
||||
|
||||
buttonMarks.forEach(m => {
|
||||
it(`should apply ${m.label} when the button is pressed`, () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('paragraph').click()
|
||||
cy.get('button').contains('Paragraph').click()
|
||||
cy.get('.tiptap').type('{selectall}')
|
||||
cy.get('button').contains(m.label).click()
|
||||
cy.get(`.tiptap ${m.tag}`).should('exist').should('have.text', 'Hello world')
|
||||
@ -38,40 +38,40 @@ context('/src/Examples/Default/Vue/', () => {
|
||||
|
||||
it('should clear marks when the button is pressed', () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('paragraph').click()
|
||||
cy.get('button').contains('Paragraph').click()
|
||||
cy.get('.tiptap').type('{selectall}')
|
||||
cy.get('button').contains('bold').click()
|
||||
cy.get('button').contains('Bold').click()
|
||||
cy.get('.tiptap strong').should('exist').should('have.text', 'Hello world')
|
||||
cy.get('button').contains('clear marks').click()
|
||||
cy.get('button').contains('Clear marks').click()
|
||||
cy.get('.tiptap strong').should('not.exist')
|
||||
})
|
||||
|
||||
it('should clear nodes when the button is pressed', () => {
|
||||
cy.get('.tiptap').type('{selectall}Hello world')
|
||||
cy.get('button').contains('bullet list').click()
|
||||
cy.get('button').contains('Bullet list').click()
|
||||
cy.get('.tiptap ul').should('exist').should('have.text', 'Hello world')
|
||||
cy.get('.tiptap').type('{enter}A second item{enter}A third item{selectall}')
|
||||
cy.get('button').contains('clear nodes').click()
|
||||
cy.get('button').contains('Clear nodes').click()
|
||||
cy.get('.tiptap ul').should('not.exist')
|
||||
cy.get('.tiptap p').should('have.length', 3)
|
||||
})
|
||||
|
||||
const buttonNodes = [
|
||||
{ label: 'h1', tag: 'h1' },
|
||||
{ label: 'h2', tag: 'h2' },
|
||||
{ label: 'h3', tag: 'h3' },
|
||||
{ label: 'h4', tag: 'h4' },
|
||||
{ label: 'h5', tag: 'h5' },
|
||||
{ label: 'h6', tag: 'h6' },
|
||||
{ label: 'bullet list', tag: 'ul' },
|
||||
{ label: 'ordered list', tag: 'ol' },
|
||||
{ label: 'code block', tag: 'pre code' },
|
||||
{ label: 'blockquote', tag: 'blockquote' },
|
||||
{ label: 'H1', tag: 'h1' },
|
||||
{ label: 'H2', tag: 'h2' },
|
||||
{ label: 'H3', tag: 'h3' },
|
||||
{ label: 'H4', tag: 'h4' },
|
||||
{ label: 'H5', tag: 'h5' },
|
||||
{ label: 'H6', tag: 'h6' },
|
||||
{ label: 'Bullet list', tag: 'ul' },
|
||||
{ label: 'Ordered list', tag: 'ol' },
|
||||
{ label: 'Code block', tag: 'pre code' },
|
||||
{ label: 'Blockquote', tag: 'blockquote' },
|
||||
]
|
||||
|
||||
buttonNodes.forEach(n => {
|
||||
it(`should set ${n.label} when the button is pressed`, () => {
|
||||
cy.get('button').contains('paragraph').click()
|
||||
cy.get('button').contains('Paragraph').click()
|
||||
cy.get('.tiptap').type('{selectall}Hello world{selectall}')
|
||||
|
||||
cy.get('button').contains(n.label).click()
|
||||
@ -83,35 +83,35 @@ context('/src/Examples/Default/Vue/', () => {
|
||||
|
||||
it('should add a hr when on the same line as a node', () => {
|
||||
cy.get('.tiptap').type('{rightArrow}')
|
||||
cy.get('button').contains('horizontal rule').click()
|
||||
cy.get('button').contains('Horizontal rule').click()
|
||||
cy.get('.tiptap hr').should('exist')
|
||||
cy.get('.tiptap h1').should('exist')
|
||||
})
|
||||
|
||||
it('should add a hr when on a new line', () => {
|
||||
cy.get('.tiptap').type('{rightArrow}{enter}')
|
||||
cy.get('button').contains('horizontal rule').click()
|
||||
cy.get('button').contains('Horizontal rule').click()
|
||||
cy.get('.tiptap hr').should('exist')
|
||||
cy.get('.tiptap h1').should('exist')
|
||||
})
|
||||
|
||||
it('should add a br', () => {
|
||||
cy.get('.tiptap').type('{rightArrow}')
|
||||
cy.get('button').contains('hard break').click()
|
||||
cy.get('button').contains('Hard break').click()
|
||||
cy.get('.tiptap h1 br').should('exist')
|
||||
})
|
||||
|
||||
it('should undo', () => {
|
||||
cy.get('.tiptap').type('{selectall}{backspace}')
|
||||
cy.get('button').contains('undo').click()
|
||||
cy.get('button').contains('Undo').click()
|
||||
cy.get('.tiptap').should('contain', 'Hello world')
|
||||
})
|
||||
|
||||
it('should redo', () => {
|
||||
cy.get('.tiptap').type('{selectall}{backspace}')
|
||||
cy.get('button').contains('undo').click()
|
||||
cy.get('button').contains('Undo').click()
|
||||
cy.get('.tiptap').should('contain', 'Hello world')
|
||||
cy.get('button').contains('redo').click()
|
||||
cy.get('button').contains('Redo').click()
|
||||
cy.get('.tiptap').should('not.contain', 'Hello world')
|
||||
})
|
||||
})
|
||||
|
@ -1,73 +1,83 @@
|
||||
<template>
|
||||
<div v-if="editor">
|
||||
<button @click="editor.chain().focus().toggleBold().run()" :disabled="!editor.can().chain().focus().toggleBold().run()" :class="{ 'is-active': editor.isActive('bold') }">
|
||||
bold
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleItalic().run()" :disabled="!editor.can().chain().focus().toggleItalic().run()" :class="{ 'is-active': editor.isActive('italic') }">
|
||||
italic
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleStrike().run()" :disabled="!editor.can().chain().focus().toggleStrike().run()" :class="{ 'is-active': editor.isActive('strike') }">
|
||||
strike
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleCode().run()" :disabled="!editor.can().chain().focus().toggleCode().run()" :class="{ 'is-active': editor.isActive('code') }">
|
||||
code
|
||||
</button>
|
||||
<button @click="editor.chain().focus().unsetAllMarks().run()">
|
||||
clear marks
|
||||
</button>
|
||||
<button @click="editor.chain().focus().clearNodes().run()">
|
||||
clear nodes
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setParagraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
|
||||
paragraph
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
|
||||
h1
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
|
||||
h2
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
|
||||
h3
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 4 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 4 }) }">
|
||||
h4
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 5 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 5 }) }">
|
||||
h5
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 6 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 6 }) }">
|
||||
h6
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleBulletList().run()" :class="{ 'is-active': editor.isActive('bulletList') }">
|
||||
bullet list
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleOrderedList().run()" :class="{ 'is-active': editor.isActive('orderedList') }">
|
||||
ordered list
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleCodeBlock().run()" :class="{ 'is-active': editor.isActive('codeBlock') }">
|
||||
code block
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleBlockquote().run()" :class="{ 'is-active': editor.isActive('blockquote') }">
|
||||
blockquote
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setHorizontalRule().run()">
|
||||
horizontal rule
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setHardBreak().run()">
|
||||
hard break
|
||||
</button>
|
||||
<button @click="editor.chain().focus().undo().run()" :disabled="!editor.can().chain().focus().undo().run()">
|
||||
undo
|
||||
</button>
|
||||
<button @click="editor.chain().focus().redo().run()" :disabled="!editor.can().chain().focus().redo().run()">
|
||||
redo
|
||||
</button>
|
||||
<div v-if="editor" class="container">
|
||||
<div class="control-group">
|
||||
<div class="button-group">
|
||||
<button @click="editor.chain().focus().toggleBold().run()" :disabled="!editor.can().chain().focus().toggleBold().run()" :class="{ 'is-active': editor.isActive('bold') }">
|
||||
Bold
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleItalic().run()" :disabled="!editor.can().chain().focus().toggleItalic().run()" :class="{ 'is-active': editor.isActive('italic') }">
|
||||
Italic
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleStrike().run()" :disabled="!editor.can().chain().focus().toggleStrike().run()" :class="{ 'is-active': editor.isActive('strike') }">
|
||||
Strike
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleCode().run()" :disabled="!editor.can().chain().focus().toggleCode().run()" :class="{ 'is-active': editor.isActive('code') }">
|
||||
Code
|
||||
</button>
|
||||
<button @click="editor.chain().focus().unsetAllMarks().run()">
|
||||
Clear marks
|
||||
</button>
|
||||
<button @click="editor.chain().focus().clearNodes().run()">
|
||||
Clear nodes
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setParagraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
|
||||
Paragraph
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
|
||||
H1
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
|
||||
H2
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
|
||||
H3
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 4 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 4 }) }">
|
||||
H4
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 5 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 5 }) }">
|
||||
H5
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 6 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 6 }) }">
|
||||
H6
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleBulletList().run()" :class="{ 'is-active': editor.isActive('bulletList') }">
|
||||
Bullet list
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleOrderedList().run()" :class="{ 'is-active': editor.isActive('orderedList') }">
|
||||
Ordered list
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleCodeBlock().run()" :class="{ 'is-active': editor.isActive('codeBlock') }">
|
||||
Code block
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleBlockquote().run()" :class="{ 'is-active': editor.isActive('blockquote') }">
|
||||
Blockquote
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setHorizontalRule().run()">
|
||||
Horizontal rule
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setHardBreak().run()">
|
||||
Hard break
|
||||
</button>
|
||||
<button @click="editor.chain().focus().undo().run()" :disabled="!editor.can().chain().focus().undo().run()">
|
||||
Undo
|
||||
</button>
|
||||
<button @click="editor.chain().focus().redo().run()" :disabled="!editor.can().chain().focus().redo().run()">
|
||||
Redo
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setColor('#958DF1').run()" :class="{ 'is-active': editor.isActive('textStyle', { color: '#958DF1' }) }">
|
||||
Purple
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<editor-content :editor="editor" />
|
||||
</div>
|
||||
<editor-content :editor="editor" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Color } from '@tiptap/extension-color'
|
||||
import ListItem from '@tiptap/extension-list-item'
|
||||
import TextStyle from '@tiptap/extension-text-style'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import { Editor, EditorContent } from '@tiptap/vue-3'
|
||||
|
||||
@ -85,6 +95,8 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Color.configure({ types: [TextStyle.name, ListItem.name] }),
|
||||
TextStyle.configure({ types: [ListItem.name] }),
|
||||
StarterKit,
|
||||
],
|
||||
content: `
|
||||
@ -92,7 +104,7 @@ export default {
|
||||
Hi there,
|
||||
</h2>
|
||||
<p>
|
||||
this is a <em>basic</em> example of <strong>tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
|
||||
this is a <em>basic</em> example of <strong>Tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
@ -129,15 +141,23 @@ export default {
|
||||
<style lang="scss">
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
@ -145,41 +165,68 @@ export default {
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: rgba(#616161, 0.1);
|
||||
color: #616161;
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
border-left: 2px solid rgba(#0D0D0D, 0.1);
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 2px solid rgba(#0D0D0D, 0.1);
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,31 @@
|
||||
<template>
|
||||
<node-view-wrapper class="draw">
|
||||
<input type="color" v-model="color">
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
max="10"
|
||||
v-model="size"
|
||||
>
|
||||
<button @click="clear">
|
||||
clear
|
||||
</button>
|
||||
<svg viewBox="0 0 500 250" ref="canvas">
|
||||
<template v-for="item in node.attrs.lines">
|
||||
<path
|
||||
v-if="item.id !== id"
|
||||
:key="item.id"
|
||||
:d="item.path"
|
||||
:id="`id-${item.id}`"
|
||||
:stroke="item.color"
|
||||
:stroke-width="item.size"
|
||||
/>
|
||||
</template>
|
||||
</svg>
|
||||
<div class="control-group">
|
||||
<div class="button-group">
|
||||
<input type="color" v-model="color">
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
max="10"
|
||||
v-model="size"
|
||||
>
|
||||
<button @click="clear">
|
||||
Clear
|
||||
</button>
|
||||
</div>
|
||||
<svg viewBox="0 0 500 250" ref="canvas">
|
||||
<template v-for="item in node.attrs.lines">
|
||||
<path
|
||||
v-if="item.id !== id"
|
||||
:key="item.id"
|
||||
:d="item.path"
|
||||
:id="`id-${item.id}`"
|
||||
:stroke="item.color"
|
||||
:stroke-width="item.size"
|
||||
/>
|
||||
</template>
|
||||
</svg>
|
||||
</div>
|
||||
</node-view-wrapper>
|
||||
</template>
|
||||
|
||||
|
@ -12,44 +12,46 @@ const MenuBar = ({ editor }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()} className={editor.isActive('heading', { level: 1 }) ? 'is-active' : ''}>
|
||||
h1
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()} className={editor.isActive('heading', { level: 2 }) ? 'is-active' : ''}>
|
||||
h2
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()} className={editor.isActive('heading', { level: 3 }) ? 'is-active' : ''}>
|
||||
h3
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setParagraph().run()} className={editor.isActive('paragraph') ? 'is-active' : ''}>
|
||||
paragraph
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().toggleBold().run()} className={editor.isActive('bold') ? 'is-active' : ''}>
|
||||
bold
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().toggleItalic().run()} className={editor.isActive('italic') ? 'is-active' : ''}>
|
||||
italic
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().toggleStrike().run()} className={editor.isActive('strike') ? 'is-active' : ''}>
|
||||
strike
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().toggleHighlight().run()} className={editor.isActive('highlight') ? 'is-active' : ''}>
|
||||
highlight
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setTextAlign('left').run()} className={editor.isActive({ textAlign: 'left' }) ? 'is-active' : ''}>
|
||||
left
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setTextAlign('center').run()} className={editor.isActive({ textAlign: 'center' }) ? 'is-active' : ''}>
|
||||
center
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setTextAlign('right').run()} className={editor.isActive({ textAlign: 'right' }) ? 'is-active' : ''}>
|
||||
right
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setTextAlign('justify').run()} className={editor.isActive({ textAlign: 'justify' }) ? 'is-active' : ''}>
|
||||
justify
|
||||
</button>
|
||||
</>
|
||||
<div className="control-group">
|
||||
<div className="button-group">
|
||||
<button onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()} className={editor.isActive('heading', { level: 1 }) ? 'is-active' : ''}>
|
||||
H1
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()} className={editor.isActive('heading', { level: 2 }) ? 'is-active' : ''}>
|
||||
H2
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()} className={editor.isActive('heading', { level: 3 }) ? 'is-active' : ''}>
|
||||
H3
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setParagraph().run()} className={editor.isActive('paragraph') ? 'is-active' : ''}>
|
||||
Paragraph
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().toggleBold().run()} className={editor.isActive('bold') ? 'is-active' : ''}>
|
||||
Bold
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().toggleItalic().run()} className={editor.isActive('italic') ? 'is-active' : ''}>
|
||||
Italic
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().toggleStrike().run()} className={editor.isActive('strike') ? 'is-active' : ''}>
|
||||
Strike
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().toggleHighlight().run()} className={editor.isActive('highlight') ? 'is-active' : ''}>
|
||||
Highlight
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setTextAlign('left').run()} className={editor.isActive({ textAlign: 'left' }) ? 'is-active' : ''}>
|
||||
Left
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setTextAlign('center').run()} className={editor.isActive({ textAlign: 'center' }) ? 'is-active' : ''}>
|
||||
Center
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setTextAlign('right').run()} className={editor.isActive({ textAlign: 'right' }) ? 'is-active' : ''}>
|
||||
Right
|
||||
</button>
|
||||
<button onClick={() => editor.chain().focus().setTextAlign('justify').run()} className={editor.isActive({ textAlign: 'justify' }) ? 'is-active' : ''}>
|
||||
Justify
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -91,9 +93,9 @@ export default () => {
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<MenuBar editor={editor} />
|
||||
<EditorContent editor={editor} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ context('/src/Examples/Formatting/React/', () => {
|
||||
})
|
||||
|
||||
const marks = [
|
||||
{ label: 'highlight', mark: 'mark' },
|
||||
{ label: 'Highlight', mark: 'mark' },
|
||||
]
|
||||
|
||||
marks.forEach(m => {
|
||||
@ -20,10 +20,10 @@ context('/src/Examples/Formatting/React/', () => {
|
||||
})
|
||||
|
||||
const alignments = [
|
||||
{ label: 'left', alignment: 'left' },
|
||||
{ label: 'center', alignment: 'center' },
|
||||
{ label: 'right', alignment: 'right' },
|
||||
{ label: 'justify', alignment: 'justify' },
|
||||
{ label: 'Left', alignment: 'left' },
|
||||
{ label: 'Center', alignment: 'center' },
|
||||
{ label: 'Right', alignment: 'right' },
|
||||
{ label: 'Justify', alignment: 'justify' },
|
||||
]
|
||||
|
||||
alignments.forEach(a => {
|
||||
|
@ -1,62 +1,98 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
margin-top: 1rem;
|
||||
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: rgba(#616161, 0.1);
|
||||
color: #616161;
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: #FAF594;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 0.4rem;
|
||||
box-decoration-break: clone;
|
||||
padding: 0.1rem 0.3rem;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
border-left: 2px solid rgba(#0D0D0D, 0.1);
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 2px solid rgba(#0D0D0D, 0.1);
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ context('/src/Examples/Formatting/Vue/', () => {
|
||||
})
|
||||
|
||||
const marks = [
|
||||
{ label: 'highlight', mark: 'mark' },
|
||||
{ label: 'Highlight', mark: 'mark' },
|
||||
]
|
||||
|
||||
marks.forEach(m => {
|
||||
@ -20,10 +20,10 @@ context('/src/Examples/Formatting/Vue/', () => {
|
||||
})
|
||||
|
||||
const alignments = [
|
||||
{ label: 'left', alignment: 'left' },
|
||||
{ label: 'center', alignment: 'center' },
|
||||
{ label: 'right', alignment: 'right' },
|
||||
{ label: 'justify', alignment: 'justify' },
|
||||
{ label: 'Left', alignment: 'left' },
|
||||
{ label: 'Center', alignment: 'center' },
|
||||
{ label: 'Right', alignment: 'right' },
|
||||
{ label: 'Justify', alignment: 'justify' },
|
||||
]
|
||||
|
||||
alignments.forEach(a => {
|
||||
|
@ -1,43 +1,47 @@
|
||||
<template>
|
||||
<div v-if="editor">
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
|
||||
h1
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
|
||||
h2
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
|
||||
h3
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setParagraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
|
||||
paragraph
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleBold().run()" :class="{ 'is-active': editor.isActive('bold') }">
|
||||
bold
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleItalic().run()" :class="{ 'is-active': editor.isActive('italic') }">
|
||||
italic
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleStrike().run()" :class="{ 'is-active': editor.isActive('strike') }">
|
||||
strike
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHighlight().run()" :class="{ 'is-active': editor.isActive('highlight') }">
|
||||
highlight
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setTextAlign('left').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'left' }) }">
|
||||
left
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setTextAlign('center').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'center' }) }">
|
||||
center
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setTextAlign('right').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'right' }) }">
|
||||
right
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setTextAlign('justify').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'justify' }) }">
|
||||
justify
|
||||
</button>
|
||||
<div v-if="editor" class="container">
|
||||
<div class="control-group">
|
||||
<div class="button-group">
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
|
||||
H1
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
|
||||
H2
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHeading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
|
||||
H3
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setParagraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
|
||||
Paragraph
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleBold().run()" :class="{ 'is-active': editor.isActive('bold') }">
|
||||
Bold
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleItalic().run()" :class="{ 'is-active': editor.isActive('italic') }">
|
||||
Italic
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleStrike().run()" :class="{ 'is-active': editor.isActive('strike') }">
|
||||
Strike
|
||||
</button>
|
||||
<button @click="editor.chain().focus().toggleHighlight().run()" :class="{ 'is-active': editor.isActive('highlight') }">
|
||||
Highlight
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setTextAlign('left').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'left' }) }">
|
||||
Left
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setTextAlign('center').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'center' }) }">
|
||||
Center
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setTextAlign('right').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'right' }) }">
|
||||
Right
|
||||
</button>
|
||||
<button @click="editor.chain().focus().setTextAlign('justify').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'justify' }) }">
|
||||
Justify
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<editor-content :editor="editor" />
|
||||
</div>
|
||||
<editor-content :editor="editor" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -104,17 +108,23 @@ export default {
|
||||
<style lang="scss">
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
margin-top: 1rem;
|
||||
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
@ -122,45 +132,75 @@ export default {
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: rgba(#616161, 0.1);
|
||||
color: #616161;
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0D0D0D;
|
||||
color: #FFF;
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
padding: 0.75rem 1rem;
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: #FAF594;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 0.4rem;
|
||||
box-decoration-break: clone;
|
||||
padding: 0.1rem 0.3rem;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
border-left: 2px solid rgba(#0D0D0D, 0.1);
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 2px solid rgba(#0D0D0D, 0.1);
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
@ -37,9 +37,13 @@ export default () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={addImage}>add image from URL</button>
|
||||
<>
|
||||
<div className="control-group">
|
||||
<div className="button-group">
|
||||
<button onClick={addImage}>Add image from URL</button>
|
||||
</div>
|
||||
</div>
|
||||
<EditorContent editor={editor} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user