lit-tip-tap 0.0.0
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/README.md +90 -0
- package/dist/lit-tip-tap-toolbar-DlicURCM.js +234 -0
- package/dist/lit-tip-tap.js +5 -0
- package/dist/lit-tip-tap.registered.js +7 -0
- package/dist/src/basic.styles.d.ts +2 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.registered.d.ts +4 -0
- package/dist/src/lit-tip-tap-toolbar.d.ts +9 -0
- package/dist/src/lit-tip-tap-toolbar.register.d.ts +6 -0
- package/dist/src/lit-tip-tap.d.ts +20 -0
- package/dist/src/lit-tip-tap.register.d.ts +6 -0
- package/dist/tests/lit-tip-tap-toolbar.test.d.ts +2 -0
- package/dist/tests/lit-tip-tap.test.d.ts +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# lit-tip-tap
|
|
2
|
+
|
|
3
|
+
Add a rich text editor easily with this component.
|
|
4
|
+
|
|
5
|
+
Lit web component wrapping [TipTap 3](https://tiptap.dev).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add lit-tip-tap lit @tiptap/core @tiptap/pm @tiptap/starter-kit
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## `<lit-tip-tap>`
|
|
14
|
+
|
|
15
|
+
### Properties
|
|
16
|
+
|
|
17
|
+
- `extensions` (`AnyExtension[]`, default `[]`) — TipTap extensions. Falls back to `StarterKit` when empty. Setting this re-initializes the editor, preserving content.
|
|
18
|
+
- `initialString` (`string`, default `''`) — HTML string used as initial editor content.
|
|
19
|
+
- `tiptap` (`Editor`) — The underlying TipTap `Editor` instance (read-only, available after connect).
|
|
20
|
+
|
|
21
|
+
### Initial Content
|
|
22
|
+
|
|
23
|
+
Set content via the `initialString` property, or provide a `<template>` child:
|
|
24
|
+
|
|
25
|
+
```html
|
|
26
|
+
<lit-tip-tap initial-string="Starting content here."></lit-tip-tap>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<lit-tip-tap>
|
|
31
|
+
<template>
|
|
32
|
+
<p>Starting content here.</p>
|
|
33
|
+
</template>
|
|
34
|
+
</lit-tip-tap>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
A `<template>` child takes precedence over `initialString`.
|
|
38
|
+
|
|
39
|
+
### Getters
|
|
40
|
+
|
|
41
|
+
- `html` — Current content as HTML.
|
|
42
|
+
- `json` — Current content as TipTap JSON.
|
|
43
|
+
- `value` — Alias for `html`.
|
|
44
|
+
- `textContent` — Plain text content.
|
|
45
|
+
|
|
46
|
+
### Events
|
|
47
|
+
|
|
48
|
+
- `change` — Fires on every content update.
|
|
49
|
+
|
|
50
|
+
### Slots
|
|
51
|
+
|
|
52
|
+
- `toolbar` — Slot for a toolbar component. Slotted elements receive the `tiptap` editor instance automatically.
|
|
53
|
+
|
|
54
|
+
## `<lit-tip-tap-toolbar>`
|
|
55
|
+
|
|
56
|
+
A batteries-included toolbar. Slot it into `<lit-tip-tap>` and it auto-wires to the editor.
|
|
57
|
+
|
|
58
|
+
Buttons: heading select, bold, italic, strikethrough, code, bullet list, numbered list, indent left/right, blockquote, horizontal rule, clear formatting.
|
|
59
|
+
|
|
60
|
+
All buttons expose a `part` attribute for styling with `::part()`.
|
|
61
|
+
|
|
62
|
+
## Code example
|
|
63
|
+
|
|
64
|
+
```html
|
|
65
|
+
<script type="module">
|
|
66
|
+
import 'lit-tip-tap/registered';
|
|
67
|
+
import Underline from '@tiptap/extension-underline';
|
|
68
|
+
|
|
69
|
+
const editor = document.querySelector('lit-tip-tap');
|
|
70
|
+
|
|
71
|
+
// Add an extension reactively
|
|
72
|
+
editor.extensions = [...editor.extensions, Underline];
|
|
73
|
+
|
|
74
|
+
// Listen for changes
|
|
75
|
+
editor.addEventListener('change', () => {
|
|
76
|
+
console.log('HTML:', editor.html);
|
|
77
|
+
console.log('HTML (value):', editor.value);
|
|
78
|
+
console.log('JSON:', editor.json);
|
|
79
|
+
console.log('Text:', editor.textContent);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Programmatic access to TipTap
|
|
83
|
+
editor.tiptap.commands.focus();
|
|
84
|
+
editor.tiptap.commands.toggleBold();
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<lit-tip-tap initial-string="<p>Hello <strong>world</strong></p>">
|
|
88
|
+
<lit-tip-tap-toolbar slot="toolbar"></lit-tip-tap-toolbar>
|
|
89
|
+
</lit-tip-tap>
|
|
90
|
+
```
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
var S = (i) => {
|
|
2
|
+
throw TypeError(i);
|
|
3
|
+
};
|
|
4
|
+
var g = (i, e, t) => e.has(i) || S("Cannot " + t);
|
|
5
|
+
var h = (i, e, t) => (g(i, e, "read from private field"), t ? t.call(i) : e.get(i)), d = (i, e, t) => e.has(i) ? S("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(i) : e.set(i, t), C = (i, e, t, s) => (g(i, e, "write to private field"), s ? s.call(i, t) : e.set(i, t), t), p = (i, e, t) => (g(i, e, "access private method"), t);
|
|
6
|
+
import { css as x, LitElement as y, html as L } from "lit";
|
|
7
|
+
import { property as k } from "lit/decorators.js";
|
|
8
|
+
import { Extension as A, Editor as H } from "@tiptap/core";
|
|
9
|
+
import q from "@tiptap/starter-kit";
|
|
10
|
+
import { createRef as I, ref as w } from "lit/directives/ref.js";
|
|
11
|
+
import { classMap as r } from "lit/directives/class-map.js";
|
|
12
|
+
const B = x`
|
|
13
|
+
code {
|
|
14
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
15
|
+
border-radius: 0.25em;
|
|
16
|
+
padding: 0.15em 0.3em;
|
|
17
|
+
font-size: 0.9em;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
pre code {
|
|
21
|
+
display: block;
|
|
22
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
23
|
+
border-radius: 0.375em;
|
|
24
|
+
padding: 0.75em 1em;
|
|
25
|
+
font-size: 0.9em;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
blockquote {
|
|
29
|
+
border-left: 3px solid rgba(0, 0, 0, 0.2);
|
|
30
|
+
margin-left: 0.5rem;
|
|
31
|
+
padding-left: 0.5rem;
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
34
|
+
var P = Object.defineProperty, _ = (i, e, t, s) => {
|
|
35
|
+
for (var n = void 0, a = i.length - 1, l; a >= 0; a--)
|
|
36
|
+
(l = i[a]) && (n = l(e, t, n) || n);
|
|
37
|
+
return n && P(e, t, n), n;
|
|
38
|
+
}, c, o, f, m;
|
|
39
|
+
const $ = class $ extends y {
|
|
40
|
+
constructor() {
|
|
41
|
+
super(...arguments);
|
|
42
|
+
d(this, o);
|
|
43
|
+
d(this, c);
|
|
44
|
+
C(this, c, A.create({
|
|
45
|
+
onUpdate: () => {
|
|
46
|
+
this.dispatchEvent(new Event("change"));
|
|
47
|
+
}
|
|
48
|
+
})), this.extensions = [], this._tipTapEl = I(), this.initialString = "";
|
|
49
|
+
}
|
|
50
|
+
addExtension(...t) {
|
|
51
|
+
const s = this.tiptap.getJSON(), n = this._tipTapEl.value;
|
|
52
|
+
this.tiptap.destroy(), this.extensions = [...this.extensions, ...t], this.tiptap = p(this, o, f).call(this, this.extensions), n && (this.tiptap.mount(n), this.tiptap.commands.setContent(s)), p(this, o, m).call(this);
|
|
53
|
+
}
|
|
54
|
+
get initialContents() {
|
|
55
|
+
const t = this.querySelector("template");
|
|
56
|
+
return t ? (this.initialString = t.innerHTML.trim(), this.initialString) : this.initialString;
|
|
57
|
+
}
|
|
58
|
+
connectedCallback() {
|
|
59
|
+
super.connectedCallback(), this.tiptap = p(this, o, f).call(this, this.extensions), p(this, o, m).call(this);
|
|
60
|
+
}
|
|
61
|
+
firstUpdated() {
|
|
62
|
+
if (!this._tipTapEl.value)
|
|
63
|
+
throw new Error("Lit tip tap mounting div not present!");
|
|
64
|
+
this.tiptap.mount(this._tipTapEl.value), this.tiptap.commands.setContent(this.initialContents);
|
|
65
|
+
}
|
|
66
|
+
disconnectedCallback() {
|
|
67
|
+
super.disconnectedCallback(), this.tiptap?.destroy();
|
|
68
|
+
}
|
|
69
|
+
get html() {
|
|
70
|
+
return this.tiptap?.getHTML() ?? "";
|
|
71
|
+
}
|
|
72
|
+
get json() {
|
|
73
|
+
return this.tiptap?.getJSON();
|
|
74
|
+
}
|
|
75
|
+
get value() {
|
|
76
|
+
return this.html;
|
|
77
|
+
}
|
|
78
|
+
get textContent() {
|
|
79
|
+
return this.tiptap?.getText() ?? "";
|
|
80
|
+
}
|
|
81
|
+
render() {
|
|
82
|
+
return L`<div>
|
|
83
|
+
<slot name="toolbar"></slot>
|
|
84
|
+
<div ${w(this._tipTapEl)}></div>
|
|
85
|
+
</div>`;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
c = new WeakMap(), o = new WeakSet(), f = function(t) {
|
|
89
|
+
const s = [
|
|
90
|
+
...t.length > 0 ? t : [q],
|
|
91
|
+
h(this, c)
|
|
92
|
+
];
|
|
93
|
+
return new H({ extensions: s, injectCSS: !0 });
|
|
94
|
+
}, m = function() {
|
|
95
|
+
this.querySelectorAll("[slot]").forEach((s) => {
|
|
96
|
+
s.tiptap = this.tiptap;
|
|
97
|
+
});
|
|
98
|
+
}, $.styles = B;
|
|
99
|
+
let b = $;
|
|
100
|
+
_([
|
|
101
|
+
k({ attribute: !1 })
|
|
102
|
+
], b.prototype, "extensions");
|
|
103
|
+
_([
|
|
104
|
+
k()
|
|
105
|
+
], b.prototype, "initialString");
|
|
106
|
+
var z = Object.defineProperty, M = (i, e, t, s) => {
|
|
107
|
+
for (var n = void 0, a = i.length - 1, l; a >= 0; a--)
|
|
108
|
+
(l = i[a]) && (n = l(e, t, n) || n);
|
|
109
|
+
return n && z(e, t, n), n;
|
|
110
|
+
}, u;
|
|
111
|
+
const E = class E extends y {
|
|
112
|
+
constructor() {
|
|
113
|
+
super(...arguments);
|
|
114
|
+
d(this, u, () => {
|
|
115
|
+
this.requestUpdate();
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
willUpdate(t) {
|
|
119
|
+
t.has("tiptap") && (t.get("tiptap")?.off(
|
|
120
|
+
"transaction",
|
|
121
|
+
h(this, u)
|
|
122
|
+
), this.tiptap?.on("transaction", h(this, u)));
|
|
123
|
+
}
|
|
124
|
+
render() {
|
|
125
|
+
return L`<div part="toolbar">
|
|
126
|
+
<select
|
|
127
|
+
part="heading-select"
|
|
128
|
+
@change=${(t) => {
|
|
129
|
+
if (t.target instanceof HTMLSelectElement) {
|
|
130
|
+
const { value: s } = t.target;
|
|
131
|
+
if (s === "paragraph")
|
|
132
|
+
this.tiptap?.chain().focus().setParagraph().run();
|
|
133
|
+
else {
|
|
134
|
+
const n = Number(s);
|
|
135
|
+
this.tiptap?.chain().focus().toggleHeading({ level: n }).run();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}}
|
|
139
|
+
>
|
|
140
|
+
<option value="paragraph">Paragraph</option>
|
|
141
|
+
<option value="1">Heading 1</option>
|
|
142
|
+
<option value="2">Heading 2</option>
|
|
143
|
+
<option value="3">Heading 3</option>
|
|
144
|
+
</select>
|
|
145
|
+
<button
|
|
146
|
+
part="button bold-button"
|
|
147
|
+
class=${r({ "is-active": this.tiptap?.isActive("bold") ?? !1 })}
|
|
148
|
+
@click=${() => this.tiptap?.chain().focus().toggleBold().run()}
|
|
149
|
+
>
|
|
150
|
+
Bold
|
|
151
|
+
</button>
|
|
152
|
+
<button
|
|
153
|
+
part="button italic-button"
|
|
154
|
+
class=${r({ "is-active": this.tiptap?.isActive("italic") ?? !1 })}
|
|
155
|
+
@click=${() => this.tiptap?.chain().focus().toggleItalic().run()}
|
|
156
|
+
>
|
|
157
|
+
Italic
|
|
158
|
+
</button>
|
|
159
|
+
<button
|
|
160
|
+
part="button strike-button"
|
|
161
|
+
class=${r({ "is-active": this.tiptap?.isActive("strike") ?? !1 })}
|
|
162
|
+
@click=${() => this.tiptap?.chain().focus().toggleStrike().run()}
|
|
163
|
+
>
|
|
164
|
+
Strikethrough
|
|
165
|
+
</button>
|
|
166
|
+
<button
|
|
167
|
+
part="button code-button"
|
|
168
|
+
class=${r({ "is-active": this.tiptap?.isActive("code") ?? !1 })}
|
|
169
|
+
@click=${() => this.tiptap?.chain().focus().toggleCode().run()}
|
|
170
|
+
>
|
|
171
|
+
Code
|
|
172
|
+
</button>
|
|
173
|
+
<button
|
|
174
|
+
part="button bullet-list-button"
|
|
175
|
+
class=${r({ "is-active": this.tiptap?.isActive("bulletList") ?? !1 })}
|
|
176
|
+
@click=${() => this.tiptap?.chain().focus().toggleBulletList().run()}
|
|
177
|
+
>
|
|
178
|
+
Bullet List
|
|
179
|
+
</button>
|
|
180
|
+
<button
|
|
181
|
+
part="button ordered-list-button"
|
|
182
|
+
class=${r({ "is-active": this.tiptap?.isActive("orderedList") ?? !1 })}
|
|
183
|
+
@click=${() => this.tiptap?.chain().focus().toggleOrderedList().run()}
|
|
184
|
+
>
|
|
185
|
+
Numbered List
|
|
186
|
+
</button>
|
|
187
|
+
<button
|
|
188
|
+
part="button indent-left-button"
|
|
189
|
+
@click=${() => this.tiptap?.chain().focus().liftListItem("listItem").run()}
|
|
190
|
+
>
|
|
191
|
+
Indent Left
|
|
192
|
+
</button>
|
|
193
|
+
<button
|
|
194
|
+
part="button indent-right-button"
|
|
195
|
+
@click=${() => this.tiptap?.chain().focus().sinkListItem("listItem").run()}
|
|
196
|
+
>
|
|
197
|
+
Indent Right
|
|
198
|
+
</button>
|
|
199
|
+
<button
|
|
200
|
+
part="button blockquote-button"
|
|
201
|
+
class=${r({ "is-active": this.tiptap?.isActive("blockquote") ?? !1 })}
|
|
202
|
+
@click=${() => this.tiptap?.chain().focus().toggleBlockquote().run()}
|
|
203
|
+
>
|
|
204
|
+
Blockquote
|
|
205
|
+
</button>
|
|
206
|
+
<button
|
|
207
|
+
part="button horizontal-rule-button"
|
|
208
|
+
@click=${() => this.tiptap?.chain().focus().setHorizontalRule().run()}
|
|
209
|
+
>
|
|
210
|
+
Horizontal Rule
|
|
211
|
+
</button>
|
|
212
|
+
<button
|
|
213
|
+
part="button clear-formatting-button"
|
|
214
|
+
@click=${() => this.tiptap?.chain().focus().unsetAllMarks().run()}
|
|
215
|
+
>
|
|
216
|
+
Clear Formatting
|
|
217
|
+
</button>
|
|
218
|
+
</div>`;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
u = new WeakMap(), E.styles = x`
|
|
222
|
+
button.is-active {
|
|
223
|
+
background-color: rgba(0, 0, 0, 0.1);
|
|
224
|
+
font-weight: bold;
|
|
225
|
+
}
|
|
226
|
+
`;
|
|
227
|
+
let v = E;
|
|
228
|
+
M([
|
|
229
|
+
k({ attribute: !1 })
|
|
230
|
+
], v.prototype, "tiptap");
|
|
231
|
+
export {
|
|
232
|
+
b as L,
|
|
233
|
+
v as a
|
|
234
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Editor } from '@tiptap/core';
|
|
2
|
+
import { LitElement } from 'lit';
|
|
3
|
+
export declare class LitTipTapToolbar extends LitElement {
|
|
4
|
+
#private;
|
|
5
|
+
static styles: import("lit").CSSResult;
|
|
6
|
+
tiptap?: Editor;
|
|
7
|
+
willUpdate(changed: Map<PropertyKey, unknown>): void;
|
|
8
|
+
render(): import("lit").TemplateResult<1>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
import { Editor, type AnyExtension } from '@tiptap/core';
|
|
3
|
+
export declare class LitTipTap extends LitElement {
|
|
4
|
+
#private;
|
|
5
|
+
static styles: import("lit").CSSResult;
|
|
6
|
+
tiptap: Editor;
|
|
7
|
+
extensions: AnyExtension[];
|
|
8
|
+
addExtension(...newExtensions: AnyExtension[]): void;
|
|
9
|
+
_tipTapEl: import("lit/directives/ref.js").Ref<HTMLDivElement>;
|
|
10
|
+
initialString: string;
|
|
11
|
+
get initialContents(): string;
|
|
12
|
+
connectedCallback(): void;
|
|
13
|
+
firstUpdated(): void;
|
|
14
|
+
disconnectedCallback(): void;
|
|
15
|
+
get html(): string;
|
|
16
|
+
get json(): import("@tiptap/core").DocumentType<Record<string, any> | undefined, import("@tiptap/core").NodeType<string, Record<string, any> | undefined, any, (import("@tiptap/core").NodeType<any, any, any, any> | import("@tiptap/core").TextType<import("@tiptap/core").MarkType<any, any>>)[]>[]>;
|
|
17
|
+
get value(): string;
|
|
18
|
+
get textContent(): string;
|
|
19
|
+
render(): import("lit").TemplateResult<1>;
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '../src/lit-tip-tap.register.js';
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lit-tip-tap",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/lit-tip-tap.js",
|
|
6
|
+
"module": "./dist/lit-tip-tap.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/lit-tip-tap.js"
|
|
12
|
+
},
|
|
13
|
+
"./registered": {
|
|
14
|
+
"types": "./dist/index.registered.d.ts",
|
|
15
|
+
"import": "./dist/lit-tip-tap.registered.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@tiptap/core": "^3.19.0",
|
|
23
|
+
"@tiptap/pm": "^3.19.0",
|
|
24
|
+
"@tiptap/starter-kit": "^3.19.0",
|
|
25
|
+
"lit": "^3.3.1"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@tiptap/core": "^3.19.0",
|
|
29
|
+
"@tiptap/pm": "^3.19.0",
|
|
30
|
+
"@tiptap/starter-kit": "^3.19.0",
|
|
31
|
+
"@vitest/browser-playwright": "^4.0.18",
|
|
32
|
+
"eslint": "^9.39.2",
|
|
33
|
+
"eslint-config-prettier": "^10.1.8",
|
|
34
|
+
"eslint-plugin-lit": "^2.2.1",
|
|
35
|
+
"lit": "^3.3.1",
|
|
36
|
+
"prettier": "^3.8.1",
|
|
37
|
+
"typescript": "~5.9.3",
|
|
38
|
+
"typescript-eslint": "^8.55.0",
|
|
39
|
+
"vite": "^7.3.1",
|
|
40
|
+
"vitest": "^4.0.18"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"dev": "vite",
|
|
44
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json && vite build",
|
|
45
|
+
"preview": "vite preview",
|
|
46
|
+
"lint": "eslint src",
|
|
47
|
+
"lint:fix": "eslint src --fix",
|
|
48
|
+
"format": "prettier --write src",
|
|
49
|
+
"format:check": "prettier --check src",
|
|
50
|
+
"test": "vitest",
|
|
51
|
+
"test:run": "vitest run"
|
|
52
|
+
}
|
|
53
|
+
}
|