@eventuras/scribo 0.4.2 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/README.md +103 -8
- package/RELEASE.md +102 -0
- package/package.json +52 -28
- package/src/MarkdownEditor.css +50 -2
- package/src/MarkdownEditor.tsx +14 -13
- package/src/MarkdownInput.tsx +79 -0
- package/src/index.tsx +1 -0
- package/src/main.tsx +6 -4
- package/src/nodes/EditorNodes.ts +2 -1
- package/src/plugins/FloatingLinkEditorPlugin.tsx +14 -3
- package/src/plugins/HistoryPlugin.tsx +6 -1
- package/src/themes/EditorTheme.css +61 -6
- package/src/ui/ContentEditable.tsx +21 -19
- package/vite.config.site.ts +19 -0
- package/vite.config.ts +33 -32
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# @eventuras/scribo
|
|
2
|
+
|
|
3
|
+
## 0.8.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- chore: update dependencies across frontend packages
|
|
8
|
+
|
|
9
|
+
## 0.8.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
### 🧱 Features
|
|
14
|
+
|
|
15
|
+
- feat(scribo): auto heigh expanding (6ca2322) [@eventuras/scribo]
|
|
16
|
+
|
|
17
|
+
### 🐞 Bug Fixes
|
|
18
|
+
|
|
19
|
+
- fix(scribo): import MarkdownEditor.css for styling (d1eec7a) [@eventuras/scribo]
|
|
20
|
+
- fix(scribo): disable swc in scribo (ebce6db) [@eventuras/scribo]
|
|
21
|
+
|
|
22
|
+
### ♻️ Refactoring
|
|
23
|
+
|
|
24
|
+
- refactor(scribo): merge markdowninput into scribo with flexible styling (373587e) [@eventuras/scribo]
|
|
25
|
+
|
|
26
|
+
### 🧹 Maintenance
|
|
27
|
+
|
|
28
|
+
- chore(scribo): externalize Lexical packages in build configuration (7c7caaf) [@eventuras/scribo]
|
|
29
|
+
- chore(convertoapi,docsite,web,markdown,scribo,sdk): upgrade deps (b2de638) [@eventuras/scribo]
|
|
30
|
+
|
|
31
|
+
### ⚙️ CI/CD
|
|
32
|
+
|
|
33
|
+
- ci(scribo): implement automated release workflow for Scribo (36d6ba1) [@eventuras/scribo]
|
|
34
|
+
|
|
35
|
+
## 0.7.1
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- - chore(convertoapi,docsite,web,markdown,scribo,sdk): upgrade deps (51e931b) [@eventuras/scribo]
|
|
40
|
+
|
|
41
|
+
## 0.7.0
|
|
42
|
+
|
|
43
|
+
### Minor Changes
|
|
44
|
+
|
|
45
|
+
- ## Initial history (pre-Changesets)
|
|
46
|
+
- chore(scribo): upgrade lexical (f78dfa1)
|
|
47
|
+
- chore(scribo): update packages (3475e0f)
|
|
48
|
+
- feat(scribo): use readme as default content of editor page (428fc2b)
|
|
49
|
+
- fix(scribo): add dependency (101954b)
|
|
50
|
+
- feat(scribo): cache npm files for scribo build (a065b61)
|
|
51
|
+
- feat(scribo): add undo/redo to markdown editor (b2482cc)
|
|
52
|
+
- feat(scribo): adds links and link editing to editor (afe159d)
|
|
53
|
+
- feat(scribo): set up scribo demo site (a467bc2)
|
package/README.md
CHANGED
|
@@ -1,26 +1,121 @@
|
|
|
1
1
|
# Scribo markdown editor
|
|
2
2
|
|
|
3
|
-
Markdown editor built on [Lexical framework](https://lexical.dev/). Intended to be used as part of eventuras, but also packed as a standalone component. Scribo is a WYSIWYG
|
|
3
|
+
Markdown editor built on [Lexical framework](https://lexical.dev/). Intended to be used as part of eventuras, but also packed as a standalone component. Scribo is a WYSIWYG editor with markdown export.
|
|
4
4
|
|
|
5
5
|
The editor should provide simple and intuitive editing of markdown text, with a focus on the most common use cases.
|
|
6
6
|
|
|
7
|
+
Test the [scribo editor online demo](https://scribo.losol.no/).
|
|
8
|
+
|
|
9
|
+
> **Lexical version**: we are keeping the lexical version in sync with the [lexical version used in Payload CMS](https://github.com/payloadcms/payload/blob/main/packages/richtext-lexical/package.json), to prevent multiple versions making trouble.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm add @eventuras/scribo
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
**Important**: You must import the CSS file for Scribo to display correctly:
|
|
20
|
+
|
|
21
|
+
### MarkdownEditor (WYSIWYG Editor)
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import "@eventuras/scribo/style.css";
|
|
25
|
+
import { MarkdownEditor } from "@eventuras/scribo";
|
|
26
|
+
|
|
27
|
+
function MyComponent() {
|
|
28
|
+
return <MarkdownEditor defaultValue="# Hello World" />;
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### MarkdownInput (Form-ready Input)
|
|
33
|
+
|
|
34
|
+
For use with native HTML forms (FormData API):
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import "@eventuras/scribo/style.css";
|
|
38
|
+
import { MarkdownInput } from "@eventuras/scribo";
|
|
39
|
+
|
|
40
|
+
function MyForm() {
|
|
41
|
+
return (
|
|
42
|
+
<form>
|
|
43
|
+
<MarkdownInput
|
|
44
|
+
name="description"
|
|
45
|
+
label="Description"
|
|
46
|
+
placeholder="Enter markdown..."
|
|
47
|
+
defaultValue="# Hello"
|
|
48
|
+
maxLength={500}
|
|
49
|
+
className="mb-4"
|
|
50
|
+
labelClassName="font-bold"
|
|
51
|
+
editorClassName="border rounded"
|
|
52
|
+
errorClassName="text-red-500"
|
|
53
|
+
/>
|
|
54
|
+
<button type="submit">Submit</button>
|
|
55
|
+
</form>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The `MarkdownInput` component is framework-agnostic and provides:
|
|
61
|
+
|
|
62
|
+
- Hidden input for FormData submission
|
|
63
|
+
- Optional label and validation
|
|
64
|
+
- Flexible styling via className props
|
|
65
|
+
- Character limit validation
|
|
66
|
+
|
|
67
|
+
### Peer Dependencies
|
|
68
|
+
|
|
69
|
+
Scribo requires the following peer dependencies:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pnpm add react react-dom lexical @lexical/code @lexical/hashtag @lexical/link @lexical/list @lexical/mark @lexical/markdown @lexical/overflow @lexical/react @lexical/rich-text @lexical/selection @lexical/table @lexical/utils prismjs
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Prism.js for syntax highlighting:**
|
|
76
|
+
Scribo uses Prism.js for code syntax highlighting but does not bundle it. You need to install `prismjs` and import the language grammars you need in your application.
|
|
77
|
+
|
|
78
|
+
Example:
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import "prismjs";
|
|
82
|
+
import "prismjs/components/prism-javascript";
|
|
83
|
+
import "prismjs/components/prism-typescript";
|
|
84
|
+
import "prismjs/components/prism-css";
|
|
85
|
+
// Import other languages as needed
|
|
86
|
+
```
|
|
87
|
+
|
|
7
88
|
## Develop
|
|
8
89
|
|
|
9
90
|
To start developing Scribo, run the following commands:
|
|
10
91
|
|
|
11
92
|
```bash
|
|
12
|
-
|
|
93
|
+
pnpm install
|
|
13
94
|
vite dev
|
|
14
95
|
```
|
|
15
96
|
|
|
16
|
-
##
|
|
97
|
+
## Release
|
|
98
|
+
|
|
99
|
+
Quick release process:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# 1. Create changeset (choose one)
|
|
103
|
+
pnpm changeset # Manual (recommended)
|
|
104
|
+
pnpm changeset:suggest # Auto-generate from commits
|
|
105
|
+
|
|
106
|
+
# 2. Version package
|
|
107
|
+
pnpm changeset:version
|
|
17
108
|
|
|
18
|
-
|
|
109
|
+
# 3. Commit and push (create PR to main)
|
|
110
|
+
git checkout -b release/scribo-v0.x.x
|
|
111
|
+
git add .
|
|
112
|
+
git commit -m "chore(scribo): release v0.x.x"
|
|
113
|
+
git push origin release/scribo-v0.x.x
|
|
114
|
+
|
|
115
|
+
# 4. Merge PR to main, then automated workflow will publish to npm and create GitHub release
|
|
116
|
+
```
|
|
19
117
|
|
|
20
|
-
|
|
21
|
-
1. `npm run build`
|
|
22
|
-
1. `npm login --scope @eventuras --auth-type web`
|
|
23
|
-
1. `npm publish --access public`
|
|
118
|
+
For detailed release instructions, including setup and troubleshooting, see [RELEASE.md](./RELEASE.md).
|
|
24
119
|
|
|
25
120
|
## Credits
|
|
26
121
|
|
package/RELEASE.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Release Instructions for @eventuras/scribo
|
|
2
|
+
|
|
3
|
+
This document explains how to configure the automated release workflow for `@eventuras/scribo`.
|
|
4
|
+
|
|
5
|
+
## Release Process
|
|
6
|
+
|
|
7
|
+
### Standard Release
|
|
8
|
+
|
|
9
|
+
1. **Create changesets** for your changes:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Option A: Manual (recommended for better changelog messages)
|
|
13
|
+
pnpm changeset
|
|
14
|
+
|
|
15
|
+
# Option B: Auto-generate from commits (review and edit after)
|
|
16
|
+
pnpm changeset:suggest
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
> **Tip**: `changeset:suggest` analyzes your git commits since the last release and automatically generates changeset files. Review the generated changesets and edit them for clarity if needed.
|
|
20
|
+
|
|
21
|
+
2. **Version the package** when ready:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pnpm changeset:version
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
3. **Commit and push** the version bump:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
git add .
|
|
31
|
+
git commit -m "chore(scribo): release v0.x.x"
|
|
32
|
+
git push origin main
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
4. **Automated workflow** will:
|
|
36
|
+
- ✅ Build the package
|
|
37
|
+
- ✅ Publish to npm with provenance
|
|
38
|
+
- ✅ Create Git tag `@eventuras/scribo@x.x.x`
|
|
39
|
+
- ✅ Create GitHub Release with changelog
|
|
40
|
+
|
|
41
|
+
### Manual Release
|
|
42
|
+
|
|
43
|
+
If the automated workflow fails or you need to publish manually:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
cd libs/scribo
|
|
47
|
+
pnpm build
|
|
48
|
+
npm login --scope @eventuras --auth-type web
|
|
49
|
+
npm publish --access public
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Release Setup
|
|
53
|
+
|
|
54
|
+
### NPM Trusted Publishing Setup (Recommended)
|
|
55
|
+
|
|
56
|
+
Scribo uses **npm trusted publishing with OIDC** for secure, token-free publishing.
|
|
57
|
+
|
|
58
|
+
#### Configure Trusted Publisher on npmjs.com
|
|
59
|
+
|
|
60
|
+
1. Log in to [npmjs.com](https://www.npmjs.com)
|
|
61
|
+
2. Navigate to `@eventuras/scribo` package settings
|
|
62
|
+
3. Find **Trusted Publisher** section
|
|
63
|
+
4. Click **GitHub Actions**
|
|
64
|
+
5. Configure:
|
|
65
|
+
- **Organization or user**: `losol`
|
|
66
|
+
- **Repository**: `eventuras`
|
|
67
|
+
- **Workflow filename**: `scribo-release.yml` (include `.yml` extension)
|
|
68
|
+
- **Environment name**: `scribo-npm`
|
|
69
|
+
6. Click **Add trusted publisher**
|
|
70
|
+
|
|
71
|
+
#### Set Up GitHub Environment
|
|
72
|
+
|
|
73
|
+
The workflow uses a GitHub environment for deployment protection (optional but recommended):
|
|
74
|
+
|
|
75
|
+
1. Go to your GitHub repository
|
|
76
|
+
2. Navigate to **Settings** → **Environments**
|
|
77
|
+
3. Click **New environment**
|
|
78
|
+
4. Name: `scribo-npm`
|
|
79
|
+
5. (Optional) Add protection rules:
|
|
80
|
+
- Required reviewers if you want manual approval
|
|
81
|
+
- Deployment branches: Select "Selected branches" and add `main`
|
|
82
|
+
6. Click **Create environment**
|
|
83
|
+
|
|
84
|
+
> **Note**: With trusted publishing, you don't need to add any secrets to this environment. The workflow uses OIDC authentication automatically.
|
|
85
|
+
|
|
86
|
+
### Legacy: Token-Based Publishing (Not Recommended)
|
|
87
|
+
|
|
88
|
+
If you cannot use trusted publishing, you can fall back to traditional npm tokens:
|
|
89
|
+
|
|
90
|
+
1. Create a granular access token on npmjs.com with write access to `@eventuras/scribo`
|
|
91
|
+
2. Add it as `NODE_AUTH_TOKEN` secret in the `scribo-npm` environment
|
|
92
|
+
3. Update the workflow to include `NODE_AUTH_TOKEN` environment variable in the publish step
|
|
93
|
+
|
|
94
|
+
However, trusted publishing is strongly recommended for better security.
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
## Workflow Trigger
|
|
98
|
+
|
|
99
|
+
The release workflow (`.github/workflows/scribo-release.yml`) triggers automatically when:
|
|
100
|
+
|
|
101
|
+
- Changes are pushed to the `main` branch
|
|
102
|
+
- The file `libs/scribo/package.json` is modified
|
package/package.json
CHANGED
|
@@ -1,41 +1,65 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eventuras/scribo",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
3
|
+
"version": "0.8.1",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://github.com/losol/eventuras.git",
|
|
7
|
+
"directory": "libs/scribo"
|
|
8
|
+
},
|
|
5
9
|
"type": "module",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/main.d.ts",
|
|
13
|
+
"import": "./dist/main.js"
|
|
14
|
+
},
|
|
15
|
+
"./style.css": "./dist/scribo.css"
|
|
16
|
+
},
|
|
17
|
+
"main": "src/main.tsx",
|
|
6
18
|
"scripts": {
|
|
7
19
|
"build": "vite build",
|
|
8
|
-
"build:site": "
|
|
20
|
+
"build:site": "vite build --config vite.config.site.ts",
|
|
9
21
|
"dev": "vite"
|
|
10
22
|
},
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"@lexical/link": "0.28.0",
|
|
13
|
-
"@lexical/markdown": "^0.28.0",
|
|
14
|
-
"@lexical/react": "^0.28.0",
|
|
15
|
-
"lexical": "^0.28.0"
|
|
16
|
-
},
|
|
17
|
-
"peerDependencies": {
|
|
18
|
-
"react": "^19.1.0",
|
|
19
|
-
"react-dom": "^19.1.0"
|
|
20
|
-
},
|
|
21
|
-
"devDependencies": {
|
|
22
|
-
"@eventuras/eslint-config": "*",
|
|
23
|
-
"@eventuras/typescript-config": "*",
|
|
24
|
-
"@swc/core": "^1.13.3",
|
|
25
|
-
"@testing-library/react": "^16.3.0",
|
|
26
|
-
"@types/react": "^19.1.9",
|
|
27
|
-
"@types/react-dom": "^19.1.7",
|
|
28
|
-
"@vitejs/plugin-react-swc": "^4.0.0",
|
|
29
|
-
"lightningcss": "^1.30.1",
|
|
30
|
-
"react": "19.1.1",
|
|
31
|
-
"react-dom": "19.1.1",
|
|
32
|
-
"typescript": "^5.9.2",
|
|
33
|
-
"vite": "^7.1.1",
|
|
34
|
-
"vitest": "^3.2.4"
|
|
35
|
-
},
|
|
36
23
|
"overrides": {
|
|
37
24
|
"vite": {
|
|
38
25
|
"rollup": "npm:@rollup/wasm-node"
|
|
39
26
|
}
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@lexical/code": "0.35.0",
|
|
30
|
+
"@lexical/hashtag": "0.35.0",
|
|
31
|
+
"@lexical/link": "0.35.0",
|
|
32
|
+
"@lexical/list": "0.35.0",
|
|
33
|
+
"@lexical/mark": "0.35.0",
|
|
34
|
+
"@lexical/markdown": "0.35.0",
|
|
35
|
+
"@lexical/overflow": "0.35.0",
|
|
36
|
+
"@lexical/react": "^0.35.0",
|
|
37
|
+
"@lexical/rich-text": "0.35.0",
|
|
38
|
+
"@lexical/selection": "0.35.0",
|
|
39
|
+
"@lexical/table": "0.35.0",
|
|
40
|
+
"@lexical/utils": "0.35.0",
|
|
41
|
+
"lexical": "0.35.0",
|
|
42
|
+
"prismjs": "^1.30.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@eventuras/eslint-config": "workspace:*",
|
|
46
|
+
"@eventuras/typescript-config": "workspace:*",
|
|
47
|
+
"@eventuras/vite-config": "workspace:*",
|
|
48
|
+
"@testing-library/react": "^16.3.1",
|
|
49
|
+
"@types/react": "^19.2.7",
|
|
50
|
+
"@types/react-dom": "^19.2.3",
|
|
51
|
+
"@vitejs/plugin-react": "^5.1.2",
|
|
52
|
+
"lightningcss": "^1.30.2",
|
|
53
|
+
"typescript": "^5.9.3",
|
|
54
|
+
"vite": "^7.3.0",
|
|
55
|
+
"vitest": "^4.0.16"
|
|
56
|
+
},
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"react": "^19.2.3",
|
|
59
|
+
"react-dom": "^19.2.3"
|
|
60
|
+
},
|
|
61
|
+
"packageManager": "pnpm@10.26.0",
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": ">=22.0.0 <25.0.0"
|
|
40
64
|
}
|
|
41
65
|
}
|
package/src/MarkdownEditor.css
CHANGED
|
@@ -43,16 +43,64 @@
|
|
|
43
43
|
z-index: 0;
|
|
44
44
|
overflow: auto;
|
|
45
45
|
resize: vertical;
|
|
46
|
-
height: 80vh;
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
.editor {
|
|
50
49
|
flex: auto;
|
|
51
50
|
position: relative;
|
|
52
|
-
resize: vertical;
|
|
53
51
|
z-index: -1;
|
|
54
52
|
}
|
|
55
53
|
|
|
54
|
+
.editor p {
|
|
55
|
+
margin: 0 0 1em 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.editor h1,
|
|
59
|
+
.editor h2,
|
|
60
|
+
.editor h3,
|
|
61
|
+
.editor h4,
|
|
62
|
+
.editor h5,
|
|
63
|
+
.editor h6 {
|
|
64
|
+
margin: 1em 0 0.5em 0;
|
|
65
|
+
line-height: 1.3;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.editor h1 {
|
|
69
|
+
font-size: 1.75em;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.editor h2 {
|
|
73
|
+
font-size: 1.5em;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.editor h3 {
|
|
77
|
+
font-size: 1.25em;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.editor h4 {
|
|
81
|
+
font-size: 1.1em;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.editor h5,
|
|
85
|
+
.editor h6 {
|
|
86
|
+
font-size: 1em;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.editor h1:first-child,
|
|
90
|
+
.editor h2:first-child,
|
|
91
|
+
.editor h3:first-child,
|
|
92
|
+
.editor h4:first-child,
|
|
93
|
+
.editor h5:first-child,
|
|
94
|
+
.editor h6:first-child {
|
|
95
|
+
margin-top: 0;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.editor blockquote {
|
|
99
|
+
margin: 1em 0;
|
|
100
|
+
padding-left: 1em;
|
|
101
|
+
border-left: 3px solid #ddd;
|
|
102
|
+
}
|
|
103
|
+
|
|
56
104
|
ul {
|
|
57
105
|
list-style-type: disc;
|
|
58
106
|
padding: 10px 0 !important;
|
package/src/MarkdownEditor.tsx
CHANGED
|
@@ -18,26 +18,27 @@ import ToolbarPlugin from "./plugins/ToolbarPlugin";
|
|
|
18
18
|
import EditorTheme from "./themes/EditorTheme";
|
|
19
19
|
import ContentEditable from "./ui/ContentEditable";
|
|
20
20
|
import Placeholder from "./ui/Placeholder";
|
|
21
|
-
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
|
|
22
|
-
import "./MarkdownEditor.css";
|
|
21
|
+
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
|
|
23
22
|
import LinkPlugin from "./plugins/LinkPlugin";
|
|
24
23
|
import FloatingLinkEditorPlugin from "./plugins/FloatingLinkEditorPlugin";
|
|
25
24
|
import AutoLinkPlugin from "./plugins/AutoLinkPlugin";
|
|
26
|
-
import {useSharedHistoryContext} from './context/SharedHistoryContext';
|
|
25
|
+
import { useSharedHistoryContext } from './context/SharedHistoryContext';
|
|
27
26
|
|
|
28
27
|
export type onChangeMisc = {
|
|
29
|
-
plainText: string
|
|
30
|
-
}
|
|
28
|
+
plainText: string;
|
|
29
|
+
};
|
|
31
30
|
export interface MarkdownEditorProps {
|
|
32
31
|
initialMarkdown?: string;
|
|
33
32
|
className?: string;
|
|
34
33
|
onChange?: (markdown: string, misc: onChangeMisc) => void;
|
|
35
34
|
onBlur?: () => void;
|
|
36
35
|
placeholder?: string;
|
|
36
|
+
'data-testid'?: string;
|
|
37
|
+
id?: string;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
const MarkdownEditor: React.FC<MarkdownEditorProps> = (props) => {
|
|
40
|
-
const {historyState} = useSharedHistoryContext();
|
|
41
|
+
const { historyState } = useSharedHistoryContext();
|
|
41
42
|
const [isLinkEditMode, setIsLinkEditMode] = useState<boolean>(false);
|
|
42
43
|
|
|
43
44
|
const [floatingAnchorElem, setFloatingAnchorElem] =
|
|
@@ -52,7 +53,7 @@ const MarkdownEditor: React.FC<MarkdownEditorProps> = (props) => {
|
|
|
52
53
|
const internalOnChange = (editorState: EditorState) => {
|
|
53
54
|
editorState.read(() => {
|
|
54
55
|
const markdown = $convertToMarkdownString(TRANSFORMERS);
|
|
55
|
-
const plainText = $getRoot().getTextContent()
|
|
56
|
+
const plainText = $getRoot().getTextContent();
|
|
56
57
|
props.onChange && props.onChange(markdown, { plainText });
|
|
57
58
|
});
|
|
58
59
|
};
|
|
@@ -72,21 +73,21 @@ const MarkdownEditor: React.FC<MarkdownEditorProps> = (props) => {
|
|
|
72
73
|
return (
|
|
73
74
|
<div className={props.className}>
|
|
74
75
|
<LexicalComposer initialConfig={initialConfig}>
|
|
75
|
-
<div className="editor-shell" onBlur={props.onBlur}>
|
|
76
|
+
<div className="editor-shell" onBlur={props.onBlur} data-testid={props['data-testid']} id={props.id}>
|
|
76
77
|
<ToolbarPlugin setIsLinkEditMode={setIsLinkEditMode} />
|
|
77
78
|
<div className="editor-container rich-text">
|
|
78
79
|
<HistoryPlugin externalHistoryState={historyState} />
|
|
79
80
|
<AutoLinkPlugin />
|
|
80
81
|
<LinkPlugin />
|
|
81
82
|
<FloatingLinkEditorPlugin
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
anchorElem={floatingAnchorElem}
|
|
84
|
+
isLinkEditMode={isLinkEditMode}
|
|
85
|
+
setIsLinkEditMode={setIsLinkEditMode}
|
|
86
|
+
/>
|
|
86
87
|
<RichTextPlugin
|
|
87
88
|
contentEditable={
|
|
88
89
|
<div className="editor-scroller">
|
|
89
|
-
<div className="editor" ref={onRef}>
|
|
90
|
+
<div className="editor" ref={onRef} id={props.id ? `${props.id}-editable` : undefined}>
|
|
90
91
|
<ContentEditable />
|
|
91
92
|
</div>
|
|
92
93
|
</div>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import MarkdownEditor from './MarkdownEditor';
|
|
3
|
+
import { useRef, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
export type MarkdownInputProps = {
|
|
6
|
+
id?: string;
|
|
7
|
+
name: string;
|
|
8
|
+
maxLength?: number;
|
|
9
|
+
label?: string;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
defaultValue?: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
labelClassName?: string;
|
|
14
|
+
editorClassName?: string;
|
|
15
|
+
errorClassName?: string;
|
|
16
|
+
onChange?: (value: string) => void;
|
|
17
|
+
'data-testid'?: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* MarkdownInput component that works standalone or with parent form handling
|
|
22
|
+
* Uses onChange callback to notify parent of value changes
|
|
23
|
+
* Framework-agnostic with flexible className props for custom styling
|
|
24
|
+
*/
|
|
25
|
+
const MarkdownInput = (props: MarkdownInputProps) => {
|
|
26
|
+
const [error, setError] = useState<string | null>(null);
|
|
27
|
+
const [value, setValue] = useState(props.defaultValue ?? '');
|
|
28
|
+
const plainTextRef = useRef('');
|
|
29
|
+
const id = props.id ?? props.name;
|
|
30
|
+
|
|
31
|
+
const handleChange = (markdown: string, { plainText }: { plainText: string; }) => {
|
|
32
|
+
plainTextRef.current = plainText;
|
|
33
|
+
setValue(markdown);
|
|
34
|
+
|
|
35
|
+
// Notify parent component of the change
|
|
36
|
+
if (props.onChange) {
|
|
37
|
+
props.onChange(markdown);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Validate maxLength if provided
|
|
41
|
+
if (props.maxLength && plainText.length >= props.maxLength) {
|
|
42
|
+
setError(`Maximum ${props.maxLength} characters allowed`);
|
|
43
|
+
} else {
|
|
44
|
+
setError(null);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div className={props.className}>
|
|
50
|
+
{props.label && (
|
|
51
|
+
<label htmlFor={id} className={props.labelClassName}>
|
|
52
|
+
{props.label}
|
|
53
|
+
</label>
|
|
54
|
+
)}
|
|
55
|
+
{/* Hidden input to store value - controlled by React state */}
|
|
56
|
+
<input
|
|
57
|
+
type="hidden"
|
|
58
|
+
name={props.name}
|
|
59
|
+
value={value}
|
|
60
|
+
/>
|
|
61
|
+
<MarkdownEditor
|
|
62
|
+
onChange={handleChange}
|
|
63
|
+
className={props.editorClassName}
|
|
64
|
+
initialMarkdown={props.defaultValue}
|
|
65
|
+
placeholder={props.placeholder}
|
|
66
|
+
data-testid={props['data-testid']}
|
|
67
|
+
id={id}
|
|
68
|
+
/>
|
|
69
|
+
{error && (
|
|
70
|
+
<span role="alert" className={props.errorClassName}>
|
|
71
|
+
{error}
|
|
72
|
+
</span>
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
MarkdownInput.displayName = 'MarkdownInput';
|
|
79
|
+
export default MarkdownInput;
|
package/src/index.tsx
CHANGED
package/src/main.tsx
CHANGED
package/src/nodes/EditorNodes.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { HeadingNode, QuoteNode } from "@lexical/rich-text";
|
|
|
18
18
|
import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
|
|
19
19
|
import type { Klass, LexicalNode } from "lexical";
|
|
20
20
|
|
|
21
|
+
// Using 'as any' to work around Lexical version conflicts between workspace installs
|
|
21
22
|
const EditorNodes: Array<Klass<LexicalNode>> = [
|
|
22
23
|
HeadingNode,
|
|
23
24
|
ListNode,
|
|
@@ -34,6 +35,6 @@ const EditorNodes: Array<Klass<LexicalNode>> = [
|
|
|
34
35
|
OverflowNode,
|
|
35
36
|
HorizontalRuleNode,
|
|
36
37
|
MarkNode,
|
|
37
|
-
];
|
|
38
|
+
] as any;
|
|
38
39
|
|
|
39
40
|
export default EditorNodes;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// https://github.com/facebook/lexical/blob/main/packages/lexical-playground/src/plugins/FloatingLinkEditorPlugin/index.tsx
|
|
1
3
|
/**
|
|
2
4
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
5
|
*
|
|
@@ -5,7 +7,6 @@
|
|
|
5
7
|
* LICENSE file in the root directory of this source tree.
|
|
6
8
|
*
|
|
7
9
|
*/
|
|
8
|
-
// https://github.com/facebook/lexical/blob/main/packages/lexical-playground/src/plugins/FloatingLinkEditorPlugin/index.tsx
|
|
9
10
|
import type {JSX} from 'react';
|
|
10
11
|
|
|
11
12
|
import './FloatingLinkEditorPlugin.css';
|
|
@@ -451,7 +452,7 @@ function useFloatingLinkEditorToolbar(
|
|
|
451
452
|
}
|
|
452
453
|
|
|
453
454
|
export default function FloatingLinkEditorPlugin({
|
|
454
|
-
anchorElem
|
|
455
|
+
anchorElem,
|
|
455
456
|
isLinkEditMode,
|
|
456
457
|
setIsLinkEditMode,
|
|
457
458
|
}: {
|
|
@@ -460,9 +461,19 @@ export default function FloatingLinkEditorPlugin({
|
|
|
460
461
|
setIsLinkEditMode: Dispatch<boolean>;
|
|
461
462
|
}): JSX.Element | null {
|
|
462
463
|
const [editor] = useLexicalComposerContext();
|
|
464
|
+
|
|
465
|
+
// Use document.body as default, but only in browser environment
|
|
466
|
+
const defaultAnchorElem = typeof document !== 'undefined' ? document.body : null;
|
|
467
|
+
const effectiveAnchorElem = anchorElem ?? defaultAnchorElem;
|
|
468
|
+
|
|
469
|
+
// Don't render if we don't have a valid anchor element
|
|
470
|
+
if (!effectiveAnchorElem) {
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
|
|
463
474
|
return useFloatingLinkEditorToolbar(
|
|
464
475
|
editor,
|
|
465
|
-
|
|
476
|
+
effectiveAnchorElem,
|
|
466
477
|
isLinkEditMode,
|
|
467
478
|
setIsLinkEditMode,
|
|
468
479
|
);
|
|
@@ -140,7 +140,11 @@ function getChangeType(
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
const nextDirtyNode = dirtyNodes[0];
|
|
143
|
-
|
|
143
|
+
|
|
144
|
+
if (!nextDirtyNode) {
|
|
145
|
+
return OTHER;
|
|
146
|
+
}
|
|
147
|
+
|
|
144
148
|
const prevDirtyNode = prevEditorState._nodeMap.get(nextDirtyNode.__key);
|
|
145
149
|
|
|
146
150
|
if (
|
|
@@ -299,6 +303,7 @@ function createMergeActionGetter(
|
|
|
299
303
|
if (dirtyLeaves.size === 1) {
|
|
300
304
|
const dirtyLeafKey = Array.from(dirtyLeaves)[0];
|
|
301
305
|
if (
|
|
306
|
+
dirtyLeafKey &&
|
|
302
307
|
isTextNodeUnchanged(dirtyLeafKey, prevEditorState, nextEditorState)
|
|
303
308
|
) {
|
|
304
309
|
return HISTORY_MERGE;
|
|
@@ -9,13 +9,16 @@
|
|
|
9
9
|
.PlaygroundEditorTheme__ltr {
|
|
10
10
|
text-align: left;
|
|
11
11
|
}
|
|
12
|
+
|
|
12
13
|
.PlaygroundEditorTheme__rtl {
|
|
13
14
|
text-align: right;
|
|
14
15
|
}
|
|
16
|
+
|
|
15
17
|
.PlaygroundEditorTheme__paragraph {
|
|
16
18
|
margin: 0;
|
|
17
19
|
position: relative;
|
|
18
20
|
}
|
|
21
|
+
|
|
19
22
|
.PlaygroundEditorTheme__quote {
|
|
20
23
|
margin: 0;
|
|
21
24
|
margin-left: 20px;
|
|
@@ -27,6 +30,7 @@
|
|
|
27
30
|
border-left-style: solid;
|
|
28
31
|
padding-left: 16px;
|
|
29
32
|
}
|
|
33
|
+
|
|
30
34
|
.PlaygroundEditorTheme__h1 {
|
|
31
35
|
font-size: 32px;
|
|
32
36
|
line-height: 1.3;
|
|
@@ -36,74 +40,90 @@
|
|
|
36
40
|
font-weight: 700;
|
|
37
41
|
margin: 0;
|
|
38
42
|
}
|
|
43
|
+
|
|
39
44
|
.PlaygroundEditorTheme__h2 {
|
|
40
|
-
font-size:
|
|
45
|
+
font-size: 24px;
|
|
41
46
|
color: #406280;
|
|
42
47
|
padding-top: 2rem;
|
|
43
|
-
|
|
48
|
+
padding-bottom: 0.5rem;
|
|
44
49
|
font-weight: 700;
|
|
45
50
|
margin: 0;
|
|
46
51
|
}
|
|
52
|
+
|
|
47
53
|
.PlaygroundEditorTheme__h3 {
|
|
48
54
|
font-size: 24px;
|
|
49
55
|
color: #406280;
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
padding-top: 2rem;
|
|
57
|
+
padding-bottom: 0.5rem;
|
|
52
58
|
font-weight: 700;
|
|
53
59
|
margin: 0;
|
|
54
60
|
}
|
|
61
|
+
|
|
55
62
|
.PlaygroundEditorTheme__h4 {
|
|
56
63
|
font-size: 16px;
|
|
57
64
|
color: #406280;
|
|
58
|
-
|
|
59
|
-
|
|
65
|
+
padding-top: 1.5rem;
|
|
66
|
+
padding-bottom: 0rem;
|
|
60
67
|
font-weight: 700;
|
|
61
68
|
margin: 0;
|
|
62
69
|
}
|
|
70
|
+
|
|
63
71
|
.PlaygroundEditorTheme__indent {
|
|
64
72
|
--lexical-indent-base-value: 40px;
|
|
65
73
|
}
|
|
74
|
+
|
|
66
75
|
.PlaygroundEditorTheme__textBold {
|
|
67
76
|
font-weight: bold;
|
|
68
77
|
}
|
|
78
|
+
|
|
69
79
|
.PlaygroundEditorTheme__textItalic {
|
|
70
80
|
font-style: italic;
|
|
71
81
|
}
|
|
82
|
+
|
|
72
83
|
.PlaygroundEditorTheme__textUnderline {
|
|
73
84
|
text-decoration: underline;
|
|
74
85
|
}
|
|
86
|
+
|
|
75
87
|
.PlaygroundEditorTheme__textStrikethrough {
|
|
76
88
|
text-decoration: line-through;
|
|
77
89
|
}
|
|
90
|
+
|
|
78
91
|
.PlaygroundEditorTheme__textUnderlineStrikethrough {
|
|
79
92
|
text-decoration: underline line-through;
|
|
80
93
|
}
|
|
94
|
+
|
|
81
95
|
.PlaygroundEditorTheme__textSubscript {
|
|
82
96
|
font-size: 0.8em;
|
|
83
97
|
vertical-align: sub !important;
|
|
84
98
|
}
|
|
99
|
+
|
|
85
100
|
.PlaygroundEditorTheme__textSuperscript {
|
|
86
101
|
font-size: 0.8em;
|
|
87
102
|
vertical-align: super;
|
|
88
103
|
}
|
|
104
|
+
|
|
89
105
|
.PlaygroundEditorTheme__textCode {
|
|
90
106
|
background-color: rgb(240, 242, 245);
|
|
91
107
|
padding: 1px 0.25rem;
|
|
92
108
|
font-family: Menlo, Consolas, Monaco, monospace;
|
|
93
109
|
font-size: 94%;
|
|
94
110
|
}
|
|
111
|
+
|
|
95
112
|
.PlaygroundEditorTheme__hashtag {
|
|
96
113
|
background-color: rgba(88, 144, 255, 0.15);
|
|
97
114
|
border-bottom: 1px solid rgba(88, 144, 255, 0.3);
|
|
98
115
|
}
|
|
116
|
+
|
|
99
117
|
.PlaygroundEditorTheme__link {
|
|
100
118
|
color: rgb(33, 111, 219);
|
|
101
119
|
text-decoration: none;
|
|
102
120
|
}
|
|
121
|
+
|
|
103
122
|
.PlaygroundEditorTheme__link:hover {
|
|
104
123
|
text-decoration: underline;
|
|
105
124
|
cursor: pointer;
|
|
106
125
|
}
|
|
126
|
+
|
|
107
127
|
.PlaygroundEditorTheme__code {
|
|
108
128
|
background-color: rgb(240, 242, 245);
|
|
109
129
|
font-family: Menlo, Consolas, Monaco, monospace;
|
|
@@ -118,6 +138,7 @@
|
|
|
118
138
|
position: relative;
|
|
119
139
|
tab-size: 2;
|
|
120
140
|
}
|
|
141
|
+
|
|
121
142
|
.PlaygroundEditorTheme__code:before {
|
|
122
143
|
content: attr(data-gutter);
|
|
123
144
|
position: absolute;
|
|
@@ -131,47 +152,56 @@
|
|
|
131
152
|
text-align: right;
|
|
132
153
|
min-width: 25px;
|
|
133
154
|
}
|
|
155
|
+
|
|
134
156
|
.PlaygroundEditorTheme__characterLimit {
|
|
135
157
|
display: inline;
|
|
136
158
|
background-color: #ffbbbb !important;
|
|
137
159
|
}
|
|
160
|
+
|
|
138
161
|
.PlaygroundEditorTheme__ol1 {
|
|
139
162
|
padding: 0;
|
|
140
163
|
margin: 0;
|
|
141
164
|
list-style-position: inside;
|
|
142
165
|
}
|
|
166
|
+
|
|
143
167
|
.PlaygroundEditorTheme__ol2 {
|
|
144
168
|
padding: 0;
|
|
145
169
|
margin: 0;
|
|
146
170
|
list-style-type: upper-alpha;
|
|
147
171
|
list-style-position: inside;
|
|
148
172
|
}
|
|
173
|
+
|
|
149
174
|
.PlaygroundEditorTheme__ol3 {
|
|
150
175
|
padding: 0;
|
|
151
176
|
margin: 0;
|
|
152
177
|
list-style-type: lower-alpha;
|
|
153
178
|
list-style-position: inside;
|
|
154
179
|
}
|
|
180
|
+
|
|
155
181
|
.PlaygroundEditorTheme__ol4 {
|
|
156
182
|
padding: 0;
|
|
157
183
|
margin: 0;
|
|
158
184
|
list-style-type: upper-roman;
|
|
159
185
|
list-style-position: inside;
|
|
160
186
|
}
|
|
187
|
+
|
|
161
188
|
.PlaygroundEditorTheme__ol5 {
|
|
162
189
|
padding: 0;
|
|
163
190
|
margin: 0;
|
|
164
191
|
list-style-type: lower-roman;
|
|
165
192
|
list-style-position: inside;
|
|
166
193
|
}
|
|
194
|
+
|
|
167
195
|
.PlaygroundEditorTheme__ul {
|
|
168
196
|
padding: 0;
|
|
169
197
|
margin: 0;
|
|
170
198
|
list-style-position: inside;
|
|
171
199
|
}
|
|
200
|
+
|
|
172
201
|
.PlaygroundEditorTheme__listItem {
|
|
173
202
|
margin: 0 32px;
|
|
174
203
|
}
|
|
204
|
+
|
|
175
205
|
.PlaygroundEditorTheme__listItemChecked,
|
|
176
206
|
.PlaygroundEditorTheme__listItemUnchecked {
|
|
177
207
|
position: relative;
|
|
@@ -182,9 +212,11 @@
|
|
|
182
212
|
list-style-type: none;
|
|
183
213
|
outline: none;
|
|
184
214
|
}
|
|
215
|
+
|
|
185
216
|
.PlaygroundEditorTheme__listItemChecked {
|
|
186
217
|
text-decoration: line-through;
|
|
187
218
|
}
|
|
219
|
+
|
|
188
220
|
.PlaygroundEditorTheme__listItemUnchecked:before,
|
|
189
221
|
.PlaygroundEditorTheme__listItemChecked:before {
|
|
190
222
|
content: "";
|
|
@@ -197,26 +229,31 @@
|
|
|
197
229
|
background-size: cover;
|
|
198
230
|
position: absolute;
|
|
199
231
|
}
|
|
232
|
+
|
|
200
233
|
.PlaygroundEditorTheme__listItemUnchecked[dir="rtl"]:before,
|
|
201
234
|
.PlaygroundEditorTheme__listItemChecked[dir="rtl"]:before {
|
|
202
235
|
left: auto;
|
|
203
236
|
right: 0;
|
|
204
237
|
}
|
|
238
|
+
|
|
205
239
|
.PlaygroundEditorTheme__listItemUnchecked:focus:before,
|
|
206
240
|
.PlaygroundEditorTheme__listItemChecked:focus:before {
|
|
207
241
|
box-shadow: 0 0 0 2px #a6cdfe;
|
|
208
242
|
border-radius: 2px;
|
|
209
243
|
}
|
|
244
|
+
|
|
210
245
|
.PlaygroundEditorTheme__listItemUnchecked:before {
|
|
211
246
|
border: 1px solid #999;
|
|
212
247
|
border-radius: 2px;
|
|
213
248
|
}
|
|
249
|
+
|
|
214
250
|
.PlaygroundEditorTheme__listItemChecked:before {
|
|
215
251
|
border: 1px solid rgb(61, 135, 245);
|
|
216
252
|
border-radius: 2px;
|
|
217
253
|
background-color: #3d87f5;
|
|
218
254
|
background-repeat: no-repeat;
|
|
219
255
|
}
|
|
256
|
+
|
|
220
257
|
.PlaygroundEditorTheme__listItemChecked:after {
|
|
221
258
|
content: "";
|
|
222
259
|
cursor: pointer;
|
|
@@ -232,65 +269,83 @@
|
|
|
232
269
|
transform: rotate(45deg);
|
|
233
270
|
border-width: 0 2px 2px 0;
|
|
234
271
|
}
|
|
272
|
+
|
|
235
273
|
.PlaygroundEditorTheme__nestedListItem {
|
|
236
274
|
list-style-type: none;
|
|
237
275
|
}
|
|
276
|
+
|
|
238
277
|
.PlaygroundEditorTheme__nestedListItem:before,
|
|
239
278
|
.PlaygroundEditorTheme__nestedListItem:after {
|
|
240
279
|
display: none;
|
|
241
280
|
}
|
|
281
|
+
|
|
242
282
|
.PlaygroundEditorTheme__tokenComment {
|
|
243
283
|
color: slategray;
|
|
244
284
|
}
|
|
285
|
+
|
|
245
286
|
.PlaygroundEditorTheme__tokenPunctuation {
|
|
246
287
|
color: #999;
|
|
247
288
|
}
|
|
289
|
+
|
|
248
290
|
.PlaygroundEditorTheme__tokenProperty {
|
|
249
291
|
color: #905;
|
|
250
292
|
}
|
|
293
|
+
|
|
251
294
|
.PlaygroundEditorTheme__tokenSelector {
|
|
252
295
|
color: #690;
|
|
253
296
|
}
|
|
297
|
+
|
|
254
298
|
.PlaygroundEditorTheme__tokenOperator {
|
|
255
299
|
color: #9a6e3a;
|
|
256
300
|
}
|
|
301
|
+
|
|
257
302
|
.PlaygroundEditorTheme__tokenAttr {
|
|
258
303
|
color: #07a;
|
|
259
304
|
}
|
|
305
|
+
|
|
260
306
|
.PlaygroundEditorTheme__tokenVariable {
|
|
261
307
|
color: #e90;
|
|
262
308
|
}
|
|
309
|
+
|
|
263
310
|
.PlaygroundEditorTheme__tokenFunction {
|
|
264
311
|
color: #dd4a68;
|
|
265
312
|
}
|
|
313
|
+
|
|
266
314
|
.PlaygroundEditorTheme__mark {
|
|
267
315
|
background: rgba(255, 212, 0, 0.14);
|
|
268
316
|
border-bottom: 2px solid rgba(255, 212, 0, 0.3);
|
|
269
317
|
padding-bottom: 2px;
|
|
270
318
|
}
|
|
319
|
+
|
|
271
320
|
.PlaygroundEditorTheme__markOverlap {
|
|
272
321
|
background: rgba(255, 212, 0, 0.3);
|
|
273
322
|
border-bottom: 2px solid rgba(255, 212, 0, 0.7);
|
|
274
323
|
}
|
|
324
|
+
|
|
275
325
|
.PlaygroundEditorTheme__mark.selected {
|
|
276
326
|
background: rgba(255, 212, 0, 0.5);
|
|
277
327
|
border-bottom: 2px solid rgba(255, 212, 0, 1);
|
|
278
328
|
}
|
|
329
|
+
|
|
279
330
|
.PlaygroundEditorTheme__markOverlap.selected {
|
|
280
331
|
background: rgba(255, 212, 0, 0.7);
|
|
281
332
|
border-bottom: 2px solid rgba(255, 212, 0, 0.7);
|
|
282
333
|
}
|
|
334
|
+
|
|
283
335
|
.PlaygroundEditorTheme__embedBlock {
|
|
284
336
|
user-select: none;
|
|
285
337
|
}
|
|
338
|
+
|
|
286
339
|
.PlaygroundEditorTheme__embedBlockFocus {
|
|
287
340
|
outline: 2px solid rgb(60, 132, 244);
|
|
288
341
|
}
|
|
342
|
+
|
|
289
343
|
.PlaygroundEditorTheme__layoutContaner {
|
|
290
344
|
display: grid;
|
|
291
345
|
gap: 10px;
|
|
292
346
|
margin: 10px 0;
|
|
293
347
|
}
|
|
348
|
+
|
|
294
349
|
.PlaygroundEditorTheme__layoutItem {
|
|
295
350
|
border: 1px dashed #ddd;
|
|
296
351
|
padding: 8px 16px;
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the MIT license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
import type {JSX} from 'react';
|
|
9
|
-
import "./ContentEditable.css";
|
|
10
|
-
|
|
11
|
-
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
12
|
-
|
|
13
|
-
export default function LexicalContentEditable({
|
|
14
|
-
className,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import type { JSX } from 'react';
|
|
9
|
+
import "./ContentEditable.css";
|
|
10
|
+
|
|
11
|
+
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
12
|
+
|
|
13
|
+
export default function LexicalContentEditable({
|
|
14
|
+
className,
|
|
15
|
+
id,
|
|
16
|
+
}: {
|
|
17
|
+
className?: string;
|
|
18
|
+
id?: string;
|
|
19
|
+
}): JSX.Element {
|
|
20
|
+
return <ContentEditable className={className || "ContentEditable__root"} id={id} />;
|
|
21
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Vite configuration for building the demo site.
|
|
7
|
+
* Used explicitly via: vite build --config vite.config.site.ts
|
|
8
|
+
*/
|
|
9
|
+
export default defineConfig({
|
|
10
|
+
plugins: [react()],
|
|
11
|
+
build: {
|
|
12
|
+
outDir: 'dist/site',
|
|
13
|
+
rollupOptions: {
|
|
14
|
+
input: {
|
|
15
|
+
main: resolve(__dirname, 'index.html'),
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
package/vite.config.ts
CHANGED
|
@@ -1,32 +1,33 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
});
|
|
1
|
+
import { defineReactLibConfig } from '@eventuras/vite-config/react-lib';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Vite configuration for building the Scribo library.
|
|
5
|
+
* For the demo site, see vite.config.site.ts
|
|
6
|
+
*/
|
|
7
|
+
export default defineReactLibConfig({
|
|
8
|
+
entry: 'src/main.tsx',
|
|
9
|
+
useSWC: false,
|
|
10
|
+
external: [
|
|
11
|
+
// Externalize all Lexical packages to avoid bundling them
|
|
12
|
+
'lexical',
|
|
13
|
+
'@lexical/code',
|
|
14
|
+
'@lexical/hashtag',
|
|
15
|
+
'@lexical/history',
|
|
16
|
+
'@lexical/link',
|
|
17
|
+
'@lexical/list',
|
|
18
|
+
'@lexical/markdown',
|
|
19
|
+
'@lexical/mark',
|
|
20
|
+
'@lexical/overflow',
|
|
21
|
+
'@lexical/react',
|
|
22
|
+
'@lexical/rich-text',
|
|
23
|
+
'@lexical/selection',
|
|
24
|
+
'@lexical/text',
|
|
25
|
+
'@lexical/utils',
|
|
26
|
+
// Also externalize any sub-exports from @lexical/react
|
|
27
|
+
/^@lexical\//,
|
|
28
|
+
// Externalize Prism.js to avoid bundling all language grammars
|
|
29
|
+
'prismjs',
|
|
30
|
+
/^prismjs\//,
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
|