flowbite-mcp 1.1.3 → 1.1.5
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 +49 -74
- package/build/index.js +20 -36
- package/data/components/accordion.md +39 -53
- package/data/components/alerts.md +27 -44
- package/data/components/avatar.md +20 -33
- package/data/components/badge.md +34 -47
- package/data/components/banner.md +10 -29
- package/data/components/bottom-navigation.md +16 -29
- package/data/components/breadcrumb.md +12 -25
- package/data/components/button-group.md +26 -39
- package/data/components/buttons.md +41 -67
- package/data/components/card.md +34 -47
- package/data/components/carousel.md +25 -39
- package/data/components/chat-bubble.md +36 -50
- package/data/components/clipboard.md +256 -252
- package/data/components/datepicker.md +56 -70
- package/data/components/device-mockups.md +16 -29
- package/data/components/drawer.md +42 -56
- package/data/components/dropdowns.md +66 -80
- package/data/components/footer.md +16 -29
- package/data/components/forms.md +32 -50
- package/data/components/gallery.md +16 -33
- package/data/components/indicators.md +18 -31
- package/data/components/jumbotron.md +12 -25
- package/data/components/kbd.md +14 -27
- package/data/components/list-group.md +14 -27
- package/data/components/mega-menu.md +10 -24
- package/data/components/modal.md +37 -51
- package/data/components/navbar.md +41 -55
- package/data/components/pagination.md +22 -35
- package/data/components/popover.md +36 -51
- package/data/components/progress.md +10 -23
- package/data/components/qr-code.md +41 -133
- package/data/components/rating.md +16 -29
- package/data/components/sidebar.md +15 -30
- package/data/components/skeleton.md +16 -29
- package/data/components/speed-dial.md +40 -55
- package/data/components/spinner.md +14 -27
- package/data/components/stepper.md +14 -27
- package/data/components/tables.md +45 -64
- package/data/components/tabs.md +30 -45
- package/data/components/timeline.md +10 -23
- package/data/components/toast.md +25 -39
- package/data/components/tooltips.md +24 -39
- package/data/components/typography.md +22 -35
- package/data/components/video.md +14 -27
- package/data/forms/checkbox.md +27 -43
- package/data/forms/file-input.md +12 -26
- package/data/forms/floating-label.md +12 -25
- package/data/forms/input-field.md +17 -32
- package/data/forms/number-input.md +83 -93
- package/data/forms/phone-input.md +42 -54
- package/data/forms/radio.md +23 -39
- package/data/forms/range.md +12 -26
- package/data/forms/search-input.md +14 -31
- package/data/forms/select.md +15 -30
- package/data/forms/textarea.md +8 -21
- package/data/forms/timepicker.md +30 -42
- package/data/forms/toggle.md +18 -31
- package/data/plugins/charts.md +542 -526
- package/data/plugins/datatables.md +285 -286
- package/data/plugins/wysiwyg.md +658 -650
- package/data/quickstart.md +24 -24
- package/data/typography/blockquote.md +24 -37
- package/data/typography/headings.md +30 -43
- package/data/typography/hr.md +10 -23
- package/data/typography/images.md +32 -45
- package/data/typography/links.md +16 -29
- package/data/typography/lists.md +22 -35
- package/data/typography/paragraphs.md +30 -43
- package/data/typography/text.md +42 -55
- package/package.json +1 -1
package/data/plugins/wysiwyg.md
CHANGED
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
title: Tailwind CSS WYSIWYG Text Editor - Flowbite
|
|
4
|
-
description: Use the wysiwyg text editor component from Flowbite to create and modify content by manipulating paragraphs, headings, images and styling them using all available options
|
|
5
|
-
group: plugins
|
|
6
|
-
toc: true
|
|
7
|
-
requires_js: true
|
|
8
|
-
|
|
9
|
-
previous: Datatables
|
|
10
|
-
previousLink: plugins/datatables/
|
|
11
|
-
---
|
|
12
|
-
|
|
13
1
|
The WYSIWYG text editor from Flowbite is open-source under the MIT license based on the [Tip Tap library](https://github.com/ueberdosis/tiptap) and allows you to easily edit complex text data with typography styles, links, images, videos, and more.
|
|
14
2
|
|
|
15
3
|
The markup and styles provided by Flowbite are all built with the utility classes from Tailwind CSS and the styles for the content inside the WYSIWYG text editor are based on the [Flowbite Typography](https://flowbite.com/docs/components/typography/) plugin.
|
|
@@ -24,19 +12,19 @@ Before continuing make sure that you have Tailwind CSS, Flowbite, and Tip Tap in
|
|
|
24
12
|
|
|
25
13
|
2. Install the [Flowbite Typography](https://flowbite.com/docs/components/typography/) plugin to format the content of text inside the WYSYIWYG editor preview:
|
|
26
14
|
|
|
27
|
-
|
|
15
|
+
```bash
|
|
28
16
|
npm i flowbite-typography
|
|
29
|
-
|
|
17
|
+
```
|
|
30
18
|
|
|
31
19
|
3. Import the `flowbite-typography` plugin inside your main Tailwind CSS file:
|
|
32
20
|
|
|
33
|
-
|
|
21
|
+
```javascript
|
|
34
22
|
@plugin "flowbite-typography";
|
|
35
|
-
|
|
23
|
+
```
|
|
36
24
|
|
|
37
25
|
Alternatively you can do the same but in your `tailwind.config.js` file:
|
|
38
26
|
|
|
39
|
-
|
|
27
|
+
```javascript
|
|
40
28
|
// import the tailwind.config.js file in your main CSS file if using Tailwind CSS v4
|
|
41
29
|
module.exports = {
|
|
42
30
|
theme: {
|
|
@@ -47,13 +35,13 @@ module.exports = {
|
|
|
47
35
|
// ...
|
|
48
36
|
],
|
|
49
37
|
}
|
|
50
|
-
|
|
38
|
+
```
|
|
51
39
|
|
|
52
40
|
4. Finally, install Tip Tap either via NPM or skip this step if you're using CDN:
|
|
53
41
|
|
|
54
|
-
|
|
42
|
+
```bash
|
|
55
43
|
npm install @tiptap/core @tiptap/pm @tiptap/starter-kit
|
|
56
|
-
|
|
44
|
+
```
|
|
57
45
|
|
|
58
46
|
Now you're ready to use the examples below by copying the HTML markup and the JavaScript code.
|
|
59
47
|
|
|
@@ -61,228 +49,7 @@ Now you're ready to use the examples below by copying the HTML markup and the Ja
|
|
|
61
49
|
|
|
62
50
|
Use this example of a WYSIWYG text editor to enable basic typography styling and formatting, adding lists, links, images, videos, code blocks, aligning text, blockquotes, setting headers and paragraphs and more.
|
|
63
51
|
|
|
64
|
-
|
|
65
|
-
import { Editor } from 'https://esm.sh/@tiptap/core@2.6.6';
|
|
66
|
-
import StarterKit from 'https://esm.sh/@tiptap/starter-kit@2.6.6';
|
|
67
|
-
import Highlight from 'https://esm.sh/@tiptap/extension-highlight@2.6.6';
|
|
68
|
-
import Underline from 'https://esm.sh/@tiptap/extension-underline@2.6.6';
|
|
69
|
-
import Link from 'https://esm.sh/@tiptap/extension-link@2.6.6';
|
|
70
|
-
import TextAlign from 'https://esm.sh/@tiptap/extension-text-align@2.6.6';
|
|
71
|
-
import Image from 'https://esm.sh/@tiptap/extension-image@2.6.6';
|
|
72
|
-
import YouTube from 'https://esm.sh/@tiptap/extension-youtube@2.6.6';
|
|
73
|
-
import TextStyle from 'https://esm.sh/@tiptap/extension-text-style@2.6.6';
|
|
74
|
-
import FontFamily from 'https://esm.sh/@tiptap/extension-font-family@2.6.6';
|
|
75
|
-
import { Color } from 'https://esm.sh/@tiptap/extension-color@2.6.6';
|
|
76
|
-
import Bold from 'https://esm.sh/@tiptap/extension-bold@2.6.6'; // Import the Bold extension
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
window.addEventListener('load', function() {
|
|
80
|
-
if (document.getElementById("wysiwyg-example")) {
|
|
81
|
-
|
|
82
|
-
const FontSizeTextStyle = TextStyle.extend({
|
|
83
|
-
addAttributes() {
|
|
84
|
-
return {
|
|
85
|
-
fontSize: {
|
|
86
|
-
default: null,
|
|
87
|
-
parseHTML: element => element.style.fontSize,
|
|
88
|
-
renderHTML: attributes => {
|
|
89
|
-
if (!attributes.fontSize) {
|
|
90
|
-
return {};
|
|
91
|
-
}
|
|
92
|
-
return { style: 'font-size: ' + attributes.fontSize };
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
},
|
|
97
|
-
});
|
|
98
|
-
const CustomBold = Bold.extend({
|
|
99
|
-
// Override the renderHTML method
|
|
100
|
-
renderHTML({ mark, HTMLAttributes }) {
|
|
101
|
-
const { style, ...rest } = HTMLAttributes;
|
|
102
|
-
|
|
103
|
-
// Merge existing styles with font-weight
|
|
104
|
-
const newStyle = 'font-weight: bold;' + (style ? ' ' + style : '');
|
|
105
|
-
|
|
106
|
-
return ['span', { ...rest, style: newStyle.trim() }, 0];
|
|
107
|
-
},
|
|
108
|
-
// Ensure it doesn't exclude other marks
|
|
109
|
-
addOptions() {
|
|
110
|
-
return {
|
|
111
|
-
...this.parent?.(),
|
|
112
|
-
HTMLAttributes: {},
|
|
113
|
-
};
|
|
114
|
-
},
|
|
115
|
-
});
|
|
116
|
-
// tip tap editor setup
|
|
117
|
-
const editor = new Editor({
|
|
118
|
-
element: document.querySelector('#wysiwyg-example'),
|
|
119
|
-
extensions: [
|
|
120
|
-
StarterKit.configure({
|
|
121
|
-
textStyle: false,
|
|
122
|
-
bold: false,
|
|
123
|
-
marks: {
|
|
124
|
-
bold: false,
|
|
125
|
-
},
|
|
126
|
-
}),
|
|
127
|
-
// Include the custom Bold extension
|
|
128
|
-
CustomBold,
|
|
129
|
-
TextStyle,
|
|
130
|
-
Color,
|
|
131
|
-
FontSizeTextStyle,
|
|
132
|
-
FontFamily,
|
|
133
|
-
Highlight,
|
|
134
|
-
Underline,
|
|
135
|
-
Link.configure({
|
|
136
|
-
openOnClick: false,
|
|
137
|
-
autolink: true,
|
|
138
|
-
defaultProtocol: 'https',
|
|
139
|
-
}),
|
|
140
|
-
TextAlign.configure({
|
|
141
|
-
types: ['heading', 'paragraph'],
|
|
142
|
-
}),
|
|
143
|
-
Image,
|
|
144
|
-
YouTube,
|
|
145
|
-
],
|
|
146
|
-
content: '<p>Flowbite is an <strong>open-source library of UI components</strong> based on the utility-first Tailwind CSS framework featuring dark mode support, a Figma design system, and more.</p><p>It includes all of the commonly used components that a website requires, such as buttons, dropdowns, navigation bars, modals, datepickers, advanced charts and the list goes on.</p><p>Here is an example of a button component:</p><code><button type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-base text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Default</button></code><p>Learn more about all components from the <a href="https://flowbite.com/docs/getting-started/introduction/">Flowbite Docs</a>.</p>',
|
|
147
|
-
editorProps: {
|
|
148
|
-
attributes: {
|
|
149
|
-
class: 'format lg:format-lg dark:format-invert focus:outline-none format-blue max-w-none',
|
|
150
|
-
},
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// set up custom event listeners for the buttons
|
|
155
|
-
document.getElementById('toggleBoldButton').addEventListener('click', () => editor.chain().focus().toggleBold().run());
|
|
156
|
-
document.getElementById('toggleItalicButton').addEventListener('click', () => editor.chain().focus().toggleItalic().run());
|
|
157
|
-
document.getElementById('toggleUnderlineButton').addEventListener('click', () => editor.chain().focus().toggleUnderline().run());
|
|
158
|
-
document.getElementById('toggleStrikeButton').addEventListener('click', () => editor.chain().focus().toggleStrike().run());
|
|
159
|
-
document.getElementById('toggleHighlightButton').addEventListener('click', () => {
|
|
160
|
-
const isHighlighted = editor.isActive('highlight');
|
|
161
|
-
// when using toggleHighlight(), judge if is is already highlighted.
|
|
162
|
-
editor.chain().focus().toggleHighlight({
|
|
163
|
-
color: isHighlighted ? undefined : '#ffc078' // if is already highlighted,unset the highlight color
|
|
164
|
-
}).run();
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
document.getElementById('toggleLinkButton').addEventListener('click', () => {
|
|
168
|
-
const url = window.prompt('Enter image URL:', 'https://flowbite.com');
|
|
169
|
-
editor.chain().focus().toggleLink({ href: url }).run();
|
|
170
|
-
});
|
|
171
|
-
document.getElementById('removeLinkButton').addEventListener('click', () => {
|
|
172
|
-
editor.chain().focus().unsetLink().run()
|
|
173
|
-
});
|
|
174
|
-
document.getElementById('toggleCodeButton').addEventListener('click', () => {
|
|
175
|
-
editor.chain().focus().toggleCode().run();
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
document.getElementById('toggleLeftAlignButton').addEventListener('click', () => {
|
|
179
|
-
editor.chain().focus().setTextAlign('left').run();
|
|
180
|
-
});
|
|
181
|
-
document.getElementById('toggleCenterAlignButton').addEventListener('click', () => {
|
|
182
|
-
editor.chain().focus().setTextAlign('center').run();
|
|
183
|
-
});
|
|
184
|
-
document.getElementById('toggleRightAlignButton').addEventListener('click', () => {
|
|
185
|
-
editor.chain().focus().setTextAlign('right').run();
|
|
186
|
-
});
|
|
187
|
-
document.getElementById('toggleListButton').addEventListener('click', () => {
|
|
188
|
-
editor.chain().focus().toggleBulletList().run();
|
|
189
|
-
});
|
|
190
|
-
document.getElementById('toggleOrderedListButton').addEventListener('click', () => {
|
|
191
|
-
editor.chain().focus().toggleOrderedList().run();
|
|
192
|
-
});
|
|
193
|
-
document.getElementById('toggleBlockquoteButton').addEventListener('click', () => {
|
|
194
|
-
editor.chain().focus().toggleBlockquote().run();
|
|
195
|
-
});
|
|
196
|
-
document.getElementById('toggleHRButton').addEventListener('click', () => {
|
|
197
|
-
editor.chain().focus().setHorizontalRule().run();
|
|
198
|
-
});
|
|
199
|
-
document.getElementById('addImageButton').addEventListener('click', () => {
|
|
200
|
-
const url = window.prompt('Enter image URL:', 'https://placehold.co/600x400');
|
|
201
|
-
if (url) {
|
|
202
|
-
editor.chain().focus().setImage({ src: url }).run();
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
document.getElementById('addVideoButton').addEventListener('click', () => {
|
|
206
|
-
const url = window.prompt('Enter YouTube URL:', 'https://www.youtube.com/watch?v=KaLxCiilHns');
|
|
207
|
-
if (url) {
|
|
208
|
-
editor.commands.setYoutubeVideo({
|
|
209
|
-
src: url,
|
|
210
|
-
width: 640,
|
|
211
|
-
height: 480,
|
|
212
|
-
})
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
// typography dropdown
|
|
217
|
-
const typographyDropdown = FlowbiteInstances.getInstance('Dropdown', 'typographyDropdown');
|
|
218
|
-
|
|
219
|
-
document.getElementById('toggleParagraphButton').addEventListener('click', () => {
|
|
220
|
-
editor.chain().focus().setParagraph().run();
|
|
221
|
-
typographyDropdown.hide();
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
document.querySelectorAll('[data-heading-level]').forEach((button) => {
|
|
225
|
-
button.addEventListener('click', () => {
|
|
226
|
-
const level = button.getAttribute('data-heading-level');
|
|
227
|
-
editor.chain().focus().toggleHeading({ level: parseInt(level) }).run()
|
|
228
|
-
typographyDropdown.hide();
|
|
229
|
-
});
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
const textSizeDropdown = FlowbiteInstances.getInstance('Dropdown', 'textSizeDropdown');
|
|
233
|
-
|
|
234
|
-
// Loop through all elements with the data-text-size attribute
|
|
235
|
-
document.querySelectorAll('[data-text-size]').forEach((button) => {
|
|
236
|
-
button.addEventListener('click', () => {
|
|
237
|
-
const fontSize = button.getAttribute('data-text-size');
|
|
238
|
-
|
|
239
|
-
// Apply the selected font size via pixels using the TipTap editor chain
|
|
240
|
-
editor.chain().focus().setMark('textStyle', { fontSize }).run();
|
|
241
|
-
|
|
242
|
-
// Hide the dropdown after selection
|
|
243
|
-
textSizeDropdown.hide();
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
// Listen for color picker changes
|
|
248
|
-
const colorPicker = document.getElementById('color');
|
|
249
|
-
colorPicker.addEventListener('input', (event) => {
|
|
250
|
-
const selectedColor = event.target.value;
|
|
251
|
-
|
|
252
|
-
// Apply the selected color to the selected text
|
|
253
|
-
editor.chain().focus().setColor(selectedColor).run();
|
|
254
|
-
})
|
|
255
|
-
|
|
256
|
-
document.querySelectorAll('[data-hex-color]').forEach((button) => {
|
|
257
|
-
button.addEventListener('click', () => {
|
|
258
|
-
const selectedColor = button.getAttribute('data-hex-color');
|
|
259
|
-
|
|
260
|
-
// Apply the selected color to the selected text
|
|
261
|
-
editor.chain().focus().setColor(selectedColor).run();
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
document.getElementById('reset-color').addEventListener('click', () => {
|
|
266
|
-
editor.commands.unsetColor();
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
const fontFamilyDropdown = FlowbiteInstances.getInstance('Dropdown', 'fontFamilyDropdown');
|
|
270
|
-
|
|
271
|
-
// Loop through all elements with the data-font-family attribute
|
|
272
|
-
document.querySelectorAll('[data-font-family]').forEach((button) => {
|
|
273
|
-
button.addEventListener('click', () => {
|
|
274
|
-
const fontFamily = button.getAttribute('data-font-family');
|
|
275
|
-
|
|
276
|
-
// Apply the selected font size via pixels using the TipTap editor chain
|
|
277
|
-
editor.chain().focus().setFontFamily(fontFamily).run();
|
|
278
|
-
|
|
279
|
-
// Hide the dropdown after selection
|
|
280
|
-
fontFamilyDropdown.hide();
|
|
281
|
-
});
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
})
|
|
285
|
-
` >}}
|
|
52
|
+
```html
|
|
286
53
|
<div class="w-full bg-neutral-secondary-medium border border-default-medium rounded-base">
|
|
287
54
|
<div class="p-2 border-b border-default-medium">
|
|
288
55
|
<div class="flex flex-wrap items-center">
|
|
@@ -649,55 +416,25 @@ window.addEventListener('load', function() {
|
|
|
649
416
|
<div id="wysiwyg-example"class="block w-full px-0 text-sm text-body bg-neutral-primary border-0 focus:ring-0"></div>
|
|
650
417
|
</div>
|
|
651
418
|
</div>
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
Notice: there is a <a href="https://github.com/ueberdosis/tiptap/issues/577" target="_blank" rel="nofollow noreferrer">known issue from TipTap</a> when splitting blocks (ie. using enter to create break lines) and using the bullet list item. A quickfix for `v2.6.6` when using CDN is to match the import statements:
|
|
655
|
-
|
|
656
|
-
{{< code lang="html" file="wysiwyg.html" icon="file" >}}
|
|
657
|
-
<script type="importmap">
|
|
658
|
-
{
|
|
659
|
-
"imports": {
|
|
660
|
-
"https://esm.sh/v135/prosemirror-model@1.22.3/es2022/prosemirror-model.mjs": "https://esm.sh/v135/prosemirror-model@1.19.3/es2022/prosemirror-model.mjs",
|
|
661
|
-
"https://esm.sh/v135/prosemirror-model@1.22.1/es2022/prosemirror-model.mjs": "https://esm.sh/v135/prosemirror-model@1.19.3/es2022/prosemirror-model.mjs"
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
</script>
|
|
665
|
-
{{< /code >}}
|
|
666
|
-
|
|
667
|
-
If you're importing the package with Yarn or NPM then you need to add this in your `package.json` file:
|
|
668
|
-
|
|
669
|
-
{{< code lang="javascript" file="wysiwyg.js" icon="file" >}}
|
|
670
|
-
// when using Yarn
|
|
671
|
-
"resolutions": {
|
|
672
|
-
"prosemirror-model": "1.19.3"
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
// when using NPM
|
|
676
|
-
"overrides": {
|
|
677
|
-
"prosemirror-model": "1.19.3"
|
|
678
|
-
}
|
|
679
|
-
{{< /code >}}
|
|
680
|
-
|
|
681
|
-
We recommend later checking the Tip Tap library for a proper update to prevent this quickfix in the future.
|
|
682
|
-
|
|
683
|
-
## Text formatting
|
|
419
|
+
```
|
|
684
420
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
{{< example class="flex justify-center bg-neutral-primary" github="plugins/wysiwyg.md" show_dark=true wysiwyg=true script_module=true disable_init_js=true javascript=`
|
|
421
|
+
```javascript
|
|
688
422
|
import { Editor } from 'https://esm.sh/@tiptap/core@2.6.6';
|
|
689
423
|
import StarterKit from 'https://esm.sh/@tiptap/starter-kit@2.6.6';
|
|
690
424
|
import Highlight from 'https://esm.sh/@tiptap/extension-highlight@2.6.6';
|
|
691
425
|
import Underline from 'https://esm.sh/@tiptap/extension-underline@2.6.6';
|
|
692
|
-
import
|
|
693
|
-
import
|
|
426
|
+
import Link from 'https://esm.sh/@tiptap/extension-link@2.6.6';
|
|
427
|
+
import TextAlign from 'https://esm.sh/@tiptap/extension-text-align@2.6.6';
|
|
428
|
+
import Image from 'https://esm.sh/@tiptap/extension-image@2.6.6';
|
|
429
|
+
import YouTube from 'https://esm.sh/@tiptap/extension-youtube@2.6.6';
|
|
694
430
|
import TextStyle from 'https://esm.sh/@tiptap/extension-text-style@2.6.6';
|
|
695
431
|
import FontFamily from 'https://esm.sh/@tiptap/extension-font-family@2.6.6';
|
|
696
432
|
import { Color } from 'https://esm.sh/@tiptap/extension-color@2.6.6';
|
|
697
|
-
import Bold from 'https://esm.sh/@tiptap/extension-bold@2.6.6';
|
|
433
|
+
import Bold from 'https://esm.sh/@tiptap/extension-bold@2.6.6'; // Import the Bold extension
|
|
434
|
+
|
|
698
435
|
|
|
699
436
|
window.addEventListener('load', function() {
|
|
700
|
-
if (document.getElementById("wysiwyg-
|
|
437
|
+
if (document.getElementById("wysiwyg-example")) {
|
|
701
438
|
|
|
702
439
|
const FontSizeTextStyle = TextStyle.extend({
|
|
703
440
|
addAttributes() {
|
|
@@ -716,18 +453,27 @@ window.addEventListener('load', function() {
|
|
|
716
453
|
},
|
|
717
454
|
});
|
|
718
455
|
const CustomBold = Bold.extend({
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
});
|
|
456
|
+
// Override the renderHTML method
|
|
457
|
+
renderHTML({ mark, HTMLAttributes }) {
|
|
458
|
+
const { style, ...rest } = HTMLAttributes;
|
|
459
|
+
|
|
460
|
+
// Merge existing styles with font-weight
|
|
461
|
+
const newStyle = 'font-weight: bold;' + (style ? ' ' + style : '');
|
|
726
462
|
|
|
463
|
+
return ['span', { ...rest, style: newStyle.trim() }, 0];
|
|
464
|
+
},
|
|
465
|
+
// Ensure it doesn't exclude other marks
|
|
466
|
+
addOptions() {
|
|
467
|
+
return {
|
|
468
|
+
...this.parent?.(),
|
|
469
|
+
HTMLAttributes: {},
|
|
470
|
+
};
|
|
471
|
+
},
|
|
472
|
+
});
|
|
727
473
|
// tip tap editor setup
|
|
728
474
|
const editor = new Editor({
|
|
729
|
-
element: document.querySelector('#wysiwyg-
|
|
730
|
-
|
|
475
|
+
element: document.querySelector('#wysiwyg-example'),
|
|
476
|
+
extensions: [
|
|
731
477
|
StarterKit.configure({
|
|
732
478
|
textStyle: false,
|
|
733
479
|
bold: false,
|
|
@@ -737,16 +483,24 @@ window.addEventListener('load', function() {
|
|
|
737
483
|
}),
|
|
738
484
|
// Include the custom Bold extension
|
|
739
485
|
CustomBold,
|
|
740
|
-
Highlight,
|
|
741
|
-
Underline,
|
|
742
|
-
Subscript,
|
|
743
|
-
Superscript,
|
|
744
486
|
TextStyle,
|
|
745
|
-
FontSizeTextStyle,
|
|
746
487
|
Color,
|
|
747
|
-
|
|
488
|
+
FontSizeTextStyle,
|
|
489
|
+
FontFamily,
|
|
490
|
+
Highlight,
|
|
491
|
+
Underline,
|
|
492
|
+
Link.configure({
|
|
493
|
+
openOnClick: false,
|
|
494
|
+
autolink: true,
|
|
495
|
+
defaultProtocol: 'https',
|
|
496
|
+
}),
|
|
497
|
+
TextAlign.configure({
|
|
498
|
+
types: ['heading', 'paragraph'],
|
|
499
|
+
}),
|
|
500
|
+
Image,
|
|
501
|
+
YouTube,
|
|
748
502
|
],
|
|
749
|
-
content: '<p>Flowbite
|
|
503
|
+
content: '<p>Flowbite is an <strong>open-source library of UI components</strong> based on the utility-first Tailwind CSS framework featuring dark mode support, a Figma design system, and more.</p><p>It includes all of the commonly used components that a website requires, such as buttons, dropdowns, navigation bars, modals, datepickers, advanced charts and the list goes on.</p><p>Here is an example of a button component:</p><code><button type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-base text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Default</button></code><p>Learn more about all components from the <a href="https://flowbite.com/docs/getting-started/introduction/">Flowbite Docs</a>.</p>',
|
|
750
504
|
editorProps: {
|
|
751
505
|
attributes: {
|
|
752
506
|
class: 'format lg:format-lg dark:format-invert focus:outline-none format-blue max-w-none',
|
|
@@ -759,8 +513,6 @@ window.addEventListener('load', function() {
|
|
|
759
513
|
document.getElementById('toggleItalicButton').addEventListener('click', () => editor.chain().focus().toggleItalic().run());
|
|
760
514
|
document.getElementById('toggleUnderlineButton').addEventListener('click', () => editor.chain().focus().toggleUnderline().run());
|
|
761
515
|
document.getElementById('toggleStrikeButton').addEventListener('click', () => editor.chain().focus().toggleStrike().run());
|
|
762
|
-
document.getElementById('toggleSubscriptButton').addEventListener('click', () => editor.chain().focus().toggleSubscript().run());
|
|
763
|
-
document.getElementById('toggleSuperscriptButton').addEventListener('click', () => editor.chain().focus().toggleSuperscript().run());
|
|
764
516
|
document.getElementById('toggleHighlightButton').addEventListener('click', () => {
|
|
765
517
|
const isHighlighted = editor.isActive('highlight');
|
|
766
518
|
// when using toggleHighlight(), judge if is is already highlighted.
|
|
@@ -769,8 +521,69 @@ window.addEventListener('load', function() {
|
|
|
769
521
|
}).run();
|
|
770
522
|
});
|
|
771
523
|
|
|
524
|
+
document.getElementById('toggleLinkButton').addEventListener('click', () => {
|
|
525
|
+
const url = window.prompt('Enter image URL:', 'https://flowbite.com');
|
|
526
|
+
editor.chain().focus().toggleLink({ href: url }).run();
|
|
527
|
+
});
|
|
528
|
+
document.getElementById('removeLinkButton').addEventListener('click', () => {
|
|
529
|
+
editor.chain().focus().unsetLink().run()
|
|
530
|
+
});
|
|
772
531
|
document.getElementById('toggleCodeButton').addEventListener('click', () => {
|
|
773
532
|
editor.chain().focus().toggleCode().run();
|
|
533
|
+
})
|
|
534
|
+
|
|
535
|
+
document.getElementById('toggleLeftAlignButton').addEventListener('click', () => {
|
|
536
|
+
editor.chain().focus().setTextAlign('left').run();
|
|
537
|
+
});
|
|
538
|
+
document.getElementById('toggleCenterAlignButton').addEventListener('click', () => {
|
|
539
|
+
editor.chain().focus().setTextAlign('center').run();
|
|
540
|
+
});
|
|
541
|
+
document.getElementById('toggleRightAlignButton').addEventListener('click', () => {
|
|
542
|
+
editor.chain().focus().setTextAlign('right').run();
|
|
543
|
+
});
|
|
544
|
+
document.getElementById('toggleListButton').addEventListener('click', () => {
|
|
545
|
+
editor.chain().focus().toggleBulletList().run();
|
|
546
|
+
});
|
|
547
|
+
document.getElementById('toggleOrderedListButton').addEventListener('click', () => {
|
|
548
|
+
editor.chain().focus().toggleOrderedList().run();
|
|
549
|
+
});
|
|
550
|
+
document.getElementById('toggleBlockquoteButton').addEventListener('click', () => {
|
|
551
|
+
editor.chain().focus().toggleBlockquote().run();
|
|
552
|
+
});
|
|
553
|
+
document.getElementById('toggleHRButton').addEventListener('click', () => {
|
|
554
|
+
editor.chain().focus().setHorizontalRule().run();
|
|
555
|
+
});
|
|
556
|
+
document.getElementById('addImageButton').addEventListener('click', () => {
|
|
557
|
+
const url = window.prompt('Enter image URL:', 'https://placehold.co/600x400');
|
|
558
|
+
if (url) {
|
|
559
|
+
editor.chain().focus().setImage({ src: url }).run();
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
document.getElementById('addVideoButton').addEventListener('click', () => {
|
|
563
|
+
const url = window.prompt('Enter YouTube URL:', 'https://www.youtube.com/watch?v=KaLxCiilHns');
|
|
564
|
+
if (url) {
|
|
565
|
+
editor.commands.setYoutubeVideo({
|
|
566
|
+
src: url,
|
|
567
|
+
width: 640,
|
|
568
|
+
height: 480,
|
|
569
|
+
})
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// typography dropdown
|
|
574
|
+
const typographyDropdown = FlowbiteInstances.getInstance('Dropdown', 'typographyDropdown');
|
|
575
|
+
|
|
576
|
+
document.getElementById('toggleParagraphButton').addEventListener('click', () => {
|
|
577
|
+
editor.chain().focus().setParagraph().run();
|
|
578
|
+
typographyDropdown.hide();
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
document.querySelectorAll('[data-heading-level]').forEach((button) => {
|
|
582
|
+
button.addEventListener('click', () => {
|
|
583
|
+
const level = button.getAttribute('data-heading-level');
|
|
584
|
+
editor.chain().focus().toggleHeading({ level: parseInt(level) }).run()
|
|
585
|
+
typographyDropdown.hide();
|
|
586
|
+
});
|
|
774
587
|
});
|
|
775
588
|
|
|
776
589
|
const textSizeDropdown = FlowbiteInstances.getInstance('Dropdown', 'textSizeDropdown');
|
|
@@ -824,10 +637,44 @@ window.addEventListener('load', function() {
|
|
|
824
637
|
fontFamilyDropdown.hide();
|
|
825
638
|
});
|
|
826
639
|
});
|
|
640
|
+
}
|
|
641
|
+
})
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
Notice: there is a <a href="https://github.com/ueberdosis/tiptap/issues/577" target="_blank" rel="nofollow noreferrer">known issue from TipTap</a> when splitting blocks (ie. using enter to create break lines) and using the bullet list item. A quickfix for `v2.6.6` when using CDN is to match the import statements:
|
|
827
645
|
|
|
646
|
+
```html
|
|
647
|
+
<script type="importmap">
|
|
648
|
+
{
|
|
649
|
+
"imports": {
|
|
650
|
+
"https://esm.sh/v135/prosemirror-model@1.22.3/es2022/prosemirror-model.mjs": "https://esm.sh/v135/prosemirror-model@1.19.3/es2022/prosemirror-model.mjs",
|
|
651
|
+
"https://esm.sh/v135/prosemirror-model@1.22.1/es2022/prosemirror-model.mjs": "https://esm.sh/v135/prosemirror-model@1.19.3/es2022/prosemirror-model.mjs"
|
|
652
|
+
}
|
|
828
653
|
}
|
|
829
|
-
|
|
830
|
-
|
|
654
|
+
</script>
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
If you're importing the package with Yarn or NPM then you need to add this in your `package.json` file:
|
|
658
|
+
|
|
659
|
+
```javascript
|
|
660
|
+
// when using Yarn
|
|
661
|
+
"resolutions": {
|
|
662
|
+
"prosemirror-model": "1.19.3"
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// when using NPM
|
|
666
|
+
"overrides": {
|
|
667
|
+
"prosemirror-model": "1.19.3"
|
|
668
|
+
}
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
We recommend later checking the Tip Tap library for a proper update to prevent this quickfix in the future.
|
|
672
|
+
|
|
673
|
+
## Text formatting
|
|
674
|
+
|
|
675
|
+
Use this example of a WYSIWYG text editor to enable typography styling, formatting and marking such as underline, bold, italic, strikethrough, code, highlight and also selecting text size, color, font family and more using the utility classes from Tailwind CSS.
|
|
676
|
+
|
|
677
|
+
```html
|
|
831
678
|
<div class="w-full bg-neutral-secondary-medium border border-default-medium rounded-base">
|
|
832
679
|
<div class="p-2 border-b border-default-medium">
|
|
833
680
|
<div class="flex flex-wrap items-center">
|
|
@@ -1042,44 +889,71 @@ window.addEventListener('load', function() {
|
|
|
1042
889
|
<div id="wysiwyg-text-example" class="block w-full px-0 text-sm text-body bg-neutral-primary border-0 focus:ring-0"></div>
|
|
1043
890
|
</div>
|
|
1044
891
|
</div>
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
## Text alignment
|
|
1048
|
-
|
|
1049
|
-
Enable text alignment to the left, center, right, and justify for the content inside of the WYSIWYG component.
|
|
892
|
+
```
|
|
1050
893
|
|
|
1051
|
-
|
|
894
|
+
```javascript
|
|
1052
895
|
import { Editor } from 'https://esm.sh/@tiptap/core@2.6.6';
|
|
1053
896
|
import StarterKit from 'https://esm.sh/@tiptap/starter-kit@2.6.6';
|
|
1054
897
|
import Highlight from 'https://esm.sh/@tiptap/extension-highlight@2.6.6';
|
|
1055
898
|
import Underline from 'https://esm.sh/@tiptap/extension-underline@2.6.6';
|
|
1056
|
-
import
|
|
1057
|
-
import
|
|
1058
|
-
import
|
|
1059
|
-
import
|
|
899
|
+
import Subscript from 'https://esm.sh/@tiptap/extension-subscript@2.6.6';
|
|
900
|
+
import Superscript from 'https://esm.sh/@tiptap/extension-superscript@2.6.6';
|
|
901
|
+
import TextStyle from 'https://esm.sh/@tiptap/extension-text-style@2.6.6';
|
|
902
|
+
import FontFamily from 'https://esm.sh/@tiptap/extension-font-family@2.6.6';
|
|
903
|
+
import { Color } from 'https://esm.sh/@tiptap/extension-color@2.6.6';
|
|
904
|
+
import Bold from 'https://esm.sh/@tiptap/extension-bold@2.6.6';
|
|
1060
905
|
|
|
1061
906
|
window.addEventListener('load', function() {
|
|
1062
|
-
if (document.getElementById("wysiwyg-
|
|
907
|
+
if (document.getElementById("wysiwyg-text-example")) {
|
|
908
|
+
|
|
909
|
+
const FontSizeTextStyle = TextStyle.extend({
|
|
910
|
+
addAttributes() {
|
|
911
|
+
return {
|
|
912
|
+
fontSize: {
|
|
913
|
+
default: null,
|
|
914
|
+
parseHTML: element => element.style.fontSize,
|
|
915
|
+
renderHTML: attributes => {
|
|
916
|
+
if (!attributes.fontSize) {
|
|
917
|
+
return {};
|
|
918
|
+
}
|
|
919
|
+
return { style: 'font-size: ' + attributes.fontSize };
|
|
920
|
+
},
|
|
921
|
+
},
|
|
922
|
+
};
|
|
923
|
+
},
|
|
924
|
+
});
|
|
925
|
+
const CustomBold = Bold.extend({
|
|
926
|
+
// Override the renderHTML method
|
|
927
|
+
renderHTML({ HTMLAttributes }) {
|
|
928
|
+
return ['span', { ...HTMLAttributes, style: 'font-weight: bold;' }, 0];
|
|
929
|
+
},
|
|
930
|
+
// Ensure it doesn't exclude other marks
|
|
931
|
+
excludes: '',
|
|
932
|
+
});
|
|
1063
933
|
|
|
1064
934
|
// tip tap editor setup
|
|
1065
935
|
const editor = new Editor({
|
|
1066
|
-
element: document.querySelector('#wysiwyg-
|
|
1067
|
-
|
|
1068
|
-
StarterKit
|
|
936
|
+
element: document.querySelector('#wysiwyg-text-example'),
|
|
937
|
+
extensions: [
|
|
938
|
+
StarterKit.configure({
|
|
939
|
+
textStyle: false,
|
|
940
|
+
bold: false,
|
|
941
|
+
marks: {
|
|
942
|
+
bold: false,
|
|
943
|
+
},
|
|
944
|
+
}),
|
|
945
|
+
// Include the custom Bold extension
|
|
946
|
+
CustomBold,
|
|
1069
947
|
Highlight,
|
|
1070
948
|
Underline,
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
types: ['heading', 'paragraph'],
|
|
1078
|
-
}),
|
|
1079
|
-
Image,
|
|
1080
|
-
YouTube
|
|
949
|
+
Subscript,
|
|
950
|
+
Superscript,
|
|
951
|
+
TextStyle,
|
|
952
|
+
FontSizeTextStyle,
|
|
953
|
+
Color,
|
|
954
|
+
FontFamily
|
|
1081
955
|
],
|
|
1082
|
-
content: '<p>Flowbite is an <strong>open-source library of UI components</strong>
|
|
956
|
+
content: '<p>Flowbite React is an <strong>open-source library of UI components</strong> built using React and Tailwind CSS. It supports dark mode, a Figma design system, and more.</p><p>It includes essential components for web apps like buttons, dropdowns, navigation bars, modals, datepickers, and charts, all optimized for React.</p><p>Example button component in Flowbite React:</p><code>import { Button } from 'flowbite-react'; <Button color="blue">Default</Button></code><p>These components can also be easily customized using the theme props from the Flowbite Docs and allows you to add your own Tailwind CSS utility classes to override the default styles.</p><p>Explore more components and props values in the Flowbite Docs.</p>',
|
|
1083
957
|
editorProps: {
|
|
1084
958
|
attributes: {
|
|
1085
959
|
class: 'format lg:format-lg dark:format-invert focus:outline-none format-blue max-w-none',
|
|
@@ -1088,21 +962,85 @@ window.addEventListener('load', function() {
|
|
|
1088
962
|
});
|
|
1089
963
|
|
|
1090
964
|
// set up custom event listeners for the buttons
|
|
1091
|
-
document.getElementById('
|
|
1092
|
-
|
|
965
|
+
document.getElementById('toggleBoldButton').addEventListener('click', () => editor.chain().focus().toggleBold().run());
|
|
966
|
+
document.getElementById('toggleItalicButton').addEventListener('click', () => editor.chain().focus().toggleItalic().run());
|
|
967
|
+
document.getElementById('toggleUnderlineButton').addEventListener('click', () => editor.chain().focus().toggleUnderline().run());
|
|
968
|
+
document.getElementById('toggleStrikeButton').addEventListener('click', () => editor.chain().focus().toggleStrike().run());
|
|
969
|
+
document.getElementById('toggleSubscriptButton').addEventListener('click', () => editor.chain().focus().toggleSubscript().run());
|
|
970
|
+
document.getElementById('toggleSuperscriptButton').addEventListener('click', () => editor.chain().focus().toggleSuperscript().run());
|
|
971
|
+
document.getElementById('toggleHighlightButton').addEventListener('click', () => {
|
|
972
|
+
const isHighlighted = editor.isActive('highlight');
|
|
973
|
+
// when using toggleHighlight(), judge if is is already highlighted.
|
|
974
|
+
editor.chain().focus().toggleHighlight({
|
|
975
|
+
color: isHighlighted ? undefined : '#ffc078' // if is already highlighted,unset the highlight color
|
|
976
|
+
}).run();
|
|
1093
977
|
});
|
|
1094
|
-
|
|
1095
|
-
|
|
978
|
+
|
|
979
|
+
document.getElementById('toggleCodeButton').addEventListener('click', () => {
|
|
980
|
+
editor.chain().focus().toggleCode().run();
|
|
1096
981
|
});
|
|
1097
|
-
|
|
1098
|
-
|
|
982
|
+
|
|
983
|
+
const textSizeDropdown = FlowbiteInstances.getInstance('Dropdown', 'textSizeDropdown');
|
|
984
|
+
|
|
985
|
+
// Loop through all elements with the data-text-size attribute
|
|
986
|
+
document.querySelectorAll('[data-text-size]').forEach((button) => {
|
|
987
|
+
button.addEventListener('click', () => {
|
|
988
|
+
const fontSize = button.getAttribute('data-text-size');
|
|
989
|
+
|
|
990
|
+
// Apply the selected font size via pixels using the TipTap editor chain
|
|
991
|
+
editor.chain().focus().setMark('textStyle', { fontSize }).run();
|
|
992
|
+
|
|
993
|
+
// Hide the dropdown after selection
|
|
994
|
+
textSizeDropdown.hide();
|
|
995
|
+
});
|
|
1099
996
|
});
|
|
1100
|
-
|
|
1101
|
-
|
|
997
|
+
|
|
998
|
+
// Listen for color picker changes
|
|
999
|
+
const colorPicker = document.getElementById('color');
|
|
1000
|
+
colorPicker.addEventListener('input', (event) => {
|
|
1001
|
+
const selectedColor = event.target.value;
|
|
1002
|
+
|
|
1003
|
+
// Apply the selected color to the selected text
|
|
1004
|
+
editor.chain().focus().setColor(selectedColor).run();
|
|
1005
|
+
})
|
|
1006
|
+
|
|
1007
|
+
document.querySelectorAll('[data-hex-color]').forEach((button) => {
|
|
1008
|
+
button.addEventListener('click', () => {
|
|
1009
|
+
const selectedColor = button.getAttribute('data-hex-color');
|
|
1010
|
+
|
|
1011
|
+
// Apply the selected color to the selected text
|
|
1012
|
+
editor.chain().focus().setColor(selectedColor).run();
|
|
1013
|
+
});
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
document.getElementById('reset-color').addEventListener('click', () => {
|
|
1017
|
+
editor.commands.unsetColor();
|
|
1018
|
+
})
|
|
1019
|
+
|
|
1020
|
+
const fontFamilyDropdown = FlowbiteInstances.getInstance('Dropdown', 'fontFamilyDropdown');
|
|
1021
|
+
|
|
1022
|
+
// Loop through all elements with the data-font-family attribute
|
|
1023
|
+
document.querySelectorAll('[data-font-family]').forEach((button) => {
|
|
1024
|
+
button.addEventListener('click', () => {
|
|
1025
|
+
const fontFamily = button.getAttribute('data-font-family');
|
|
1026
|
+
|
|
1027
|
+
// Apply the selected font size via pixels using the TipTap editor chain
|
|
1028
|
+
editor.chain().focus().setFontFamily(fontFamily).run();
|
|
1029
|
+
|
|
1030
|
+
// Hide the dropdown after selection
|
|
1031
|
+
fontFamilyDropdown.hide();
|
|
1032
|
+
});
|
|
1102
1033
|
});
|
|
1034
|
+
|
|
1103
1035
|
}
|
|
1104
1036
|
})
|
|
1105
|
-
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
## Text alignment
|
|
1040
|
+
|
|
1041
|
+
Enable text alignment to the left, center, right, and justify for the content inside of the WYSIWYG component.
|
|
1042
|
+
|
|
1043
|
+
```html
|
|
1106
1044
|
<div class="w-full bg-neutral-secondary-medium border border-default-medium rounded-base">
|
|
1107
1045
|
<div class="p-2 border-b border-default-medium">
|
|
1108
1046
|
<div class="flex flex-wrap items-center">
|
|
@@ -1151,26 +1089,40 @@ window.addEventListener('load', function() {
|
|
|
1151
1089
|
<div id="wysiwyg-alignment-example"class="block w-full px-0 text-sm text-body bg-neutral-primary border-0 focus:ring-0"></div>
|
|
1152
1090
|
</div>
|
|
1153
1091
|
</div>
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
## Typography elements
|
|
1092
|
+
```
|
|
1157
1093
|
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
{{< example class="flex justify-center bg-neutral-primary" github="plugins/wysiwyg.md" show_dark=true wysiwyg=true script_module=true disable_init_js=true javascript=`
|
|
1094
|
+
```javascript
|
|
1161
1095
|
import { Editor } from 'https://esm.sh/@tiptap/core@2.6.6';
|
|
1162
1096
|
import StarterKit from 'https://esm.sh/@tiptap/starter-kit@2.6.6';
|
|
1097
|
+
import Highlight from 'https://esm.sh/@tiptap/extension-highlight@2.6.6';
|
|
1098
|
+
import Underline from 'https://esm.sh/@tiptap/extension-underline@2.6.6';
|
|
1099
|
+
import Link from 'https://esm.sh/@tiptap/extension-link@2.6.6';
|
|
1100
|
+
import TextAlign from 'https://esm.sh/@tiptap/extension-text-align@2.6.6';
|
|
1101
|
+
import Image from 'https://esm.sh/@tiptap/extension-image@2.6.6';
|
|
1102
|
+
import YouTube from 'https://esm.sh/@tiptap/extension-youtube@2.6.6';
|
|
1163
1103
|
|
|
1164
1104
|
window.addEventListener('load', function() {
|
|
1165
|
-
if (document.getElementById("wysiwyg-
|
|
1105
|
+
if (document.getElementById("wysiwyg-alignment-example")) {
|
|
1166
1106
|
|
|
1167
1107
|
// tip tap editor setup
|
|
1168
1108
|
const editor = new Editor({
|
|
1169
|
-
element: document.querySelector('#wysiwyg-
|
|
1109
|
+
element: document.querySelector('#wysiwyg-alignment-example'),
|
|
1170
1110
|
extensions: [
|
|
1171
|
-
StarterKit
|
|
1111
|
+
StarterKit,
|
|
1112
|
+
Highlight,
|
|
1113
|
+
Underline,
|
|
1114
|
+
Link.configure({
|
|
1115
|
+
openOnClick: false,
|
|
1116
|
+
autolink: true,
|
|
1117
|
+
defaultProtocol: 'https',
|
|
1118
|
+
}),
|
|
1119
|
+
TextAlign.configure({
|
|
1120
|
+
types: ['heading', 'paragraph'],
|
|
1121
|
+
}),
|
|
1122
|
+
Image,
|
|
1123
|
+
YouTube
|
|
1172
1124
|
],
|
|
1173
|
-
content: '<p>Flowbite is an <strong>open-source library of UI components</strong> based on the utility-first Tailwind CSS framework featuring dark mode support, a Figma design system, and more.</p><p>It includes all of the commonly used components that a website requires, such as buttons, dropdowns, navigation bars, modals, datepickers, advanced charts and the list goes on.</p><
|
|
1125
|
+
content: '<p>Flowbite is an <strong>open-source library of UI components</strong> based on the utility-first Tailwind CSS framework featuring dark mode support, a Figma design system, and more.</p><p>It includes all of the commonly used components that a website requires, such as buttons, dropdowns, navigation bars, modals, datepickers, advanced charts and the list goes on.</p><p>Here is an example of a button component:</p><code><button type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-base text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Default</button></code><p>Learn more about all components from the <a href="https://flowbite.com/docs/getting-started/introduction/">Flowbite Docs</a>.</p>',
|
|
1174
1126
|
editorProps: {
|
|
1175
1127
|
attributes: {
|
|
1176
1128
|
class: 'format lg:format-lg dark:format-invert focus:outline-none format-blue max-w-none',
|
|
@@ -1179,40 +1131,27 @@ window.addEventListener('load', function() {
|
|
|
1179
1131
|
});
|
|
1180
1132
|
|
|
1181
1133
|
// set up custom event listeners for the buttons
|
|
1182
|
-
document.getElementById('
|
|
1183
|
-
|
|
1184
|
-
});
|
|
1185
|
-
document.getElementById('toggleOrderedListButton').addEventListener('click', () => {
|
|
1186
|
-
editor.chain().focus().toggleOrderedList().run();
|
|
1134
|
+
document.getElementById('toggleLeftAlignButton').addEventListener('click', () => {
|
|
1135
|
+
editor.chain().focus().setTextAlign('left').run();
|
|
1187
1136
|
});
|
|
1188
|
-
document.getElementById('
|
|
1189
|
-
editor.chain().focus().
|
|
1137
|
+
document.getElementById('toggleCenterAlignButton').addEventListener('click', () => {
|
|
1138
|
+
editor.chain().focus().setTextAlign('center').run();
|
|
1190
1139
|
});
|
|
1191
|
-
document.getElementById('
|
|
1192
|
-
editor.chain().focus().
|
|
1140
|
+
document.getElementById('toggleRightAlignButton').addEventListener('click', () => {
|
|
1141
|
+
editor.chain().focus().setTextAlign('right').run();
|
|
1193
1142
|
});
|
|
1194
|
-
document.getElementById('
|
|
1195
|
-
editor.chain().focus().
|
|
1143
|
+
document.getElementById('toggleJustifyButton').addEventListener('click', () => {
|
|
1144
|
+
editor.chain().focus().setTextAlign('justify').run();
|
|
1196
1145
|
});
|
|
1146
|
+
}
|
|
1147
|
+
})
|
|
1148
|
+
```
|
|
1197
1149
|
|
|
1198
|
-
|
|
1199
|
-
const typographyDropdown = FlowbiteInstances.getInstance('Dropdown', 'typographyDropdown');
|
|
1150
|
+
## Typography elements
|
|
1200
1151
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
});
|
|
1205
|
-
|
|
1206
|
-
document.querySelectorAll('[data-heading-level]').forEach((button) => {
|
|
1207
|
-
button.addEventListener('click', () => {
|
|
1208
|
-
const level = button.getAttribute('data-heading-level');
|
|
1209
|
-
editor.chain().focus().toggleHeading({ level: parseInt(level) }).run()
|
|
1210
|
-
typographyDropdown.hide();
|
|
1211
|
-
});
|
|
1212
|
-
});
|
|
1213
|
-
}
|
|
1214
|
-
})
|
|
1215
|
-
` >}}
|
|
1152
|
+
Use this example to create typography elements like bullet lists, ordered lists, blockquotes, horizontal rules, paragraphs, headings, code blocks based on Tailwind CSS utility classees and the Flowbite API.
|
|
1153
|
+
|
|
1154
|
+
```html
|
|
1216
1155
|
<div class="w-full bg-neutral-secondary-medium border border-default-medium rounded-base">
|
|
1217
1156
|
<div class="p-2 border-b border-default-medium">
|
|
1218
1157
|
<div class="flex items-center gap-2">
|
|
@@ -1351,32 +1290,22 @@ window.addEventListener('load', function() {
|
|
|
1351
1290
|
<div id="wysiwyg-typography-example"class="block w-full px-0 text-sm text-body bg-neutral-primary border-0 focus:ring-0"></div>
|
|
1352
1291
|
</div>
|
|
1353
1292
|
</div>
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
## Configuring links
|
|
1293
|
+
```
|
|
1357
1294
|
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
{{< example class="flex justify-center bg-neutral-primary" github="plugins/wysiwyg.md" show_dark=true wysiwyg=true script_module=true disable_init_js=true javascript=`
|
|
1295
|
+
```javascript
|
|
1361
1296
|
import { Editor } from 'https://esm.sh/@tiptap/core@2.6.6';
|
|
1362
1297
|
import StarterKit from 'https://esm.sh/@tiptap/starter-kit@2.6.6';
|
|
1363
|
-
import Link from 'https://esm.sh/@tiptap/extension-link@2.6.6';
|
|
1364
1298
|
|
|
1365
1299
|
window.addEventListener('load', function() {
|
|
1366
|
-
if (document.getElementById("wysiwyg-
|
|
1300
|
+
if (document.getElementById("wysiwyg-typography-example")) {
|
|
1367
1301
|
|
|
1368
1302
|
// tip tap editor setup
|
|
1369
1303
|
const editor = new Editor({
|
|
1370
|
-
element: document.querySelector('#wysiwyg-
|
|
1304
|
+
element: document.querySelector('#wysiwyg-typography-example'),
|
|
1371
1305
|
extensions: [
|
|
1372
|
-
StarterKit
|
|
1373
|
-
Link.configure({
|
|
1374
|
-
openOnClick: false,
|
|
1375
|
-
autolink: true,
|
|
1376
|
-
defaultProtocol: 'https',
|
|
1377
|
-
})
|
|
1306
|
+
StarterKit
|
|
1378
1307
|
],
|
|
1379
|
-
content: '<p>Flowbite is an <strong>open-source library of UI components</strong> based on the utility-first Tailwind CSS framework featuring dark mode support, a Figma design system, and more.</p><p>It includes all of the commonly used components that a website requires, such as buttons, dropdowns, navigation bars, modals, datepickers, advanced charts and the list goes on.</p><p>Here is an example of a button component:</p><code><button type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-base text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Default</button></code><p>Learn more about all components from the <a href="https://flowbite.com/docs/getting-started/introduction/">Flowbite Docs</a>.</p>',
|
|
1308
|
+
content: '<p>Flowbite is an <strong>open-source library of UI components</strong> based on the utility-first Tailwind CSS framework featuring dark mode support, a Figma design system, and more.</p><p>It includes all of the commonly used components that a website requires, such as buttons, dropdowns, navigation bars, modals, datepickers, advanced charts and the list goes on.</p><ul><li>Over 600+ open-source UI components</li><li>Supports dark mode and RTL</li><li>Available in React, Vue, Svelte frameworks</li></ul><p>Here is an example of a button component:</p><pre><code><button type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-base text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Default</button></code></pre><p>Learn more about all components from the <a href="https://flowbite.com/docs/getting-started/introduction/">Flowbite Docs</a>.</p>',
|
|
1380
1309
|
editorProps: {
|
|
1381
1310
|
attributes: {
|
|
1382
1311
|
class: 'format lg:format-lg dark:format-invert focus:outline-none format-blue max-w-none',
|
|
@@ -1385,16 +1314,46 @@ window.addEventListener('load', function() {
|
|
|
1385
1314
|
});
|
|
1386
1315
|
|
|
1387
1316
|
// set up custom event listeners for the buttons
|
|
1388
|
-
document.getElementById('
|
|
1389
|
-
|
|
1390
|
-
editor.chain().focus().toggleLink({ href: url }).run();
|
|
1317
|
+
document.getElementById('toggleListButton').addEventListener('click', () => {
|
|
1318
|
+
editor.chain().focus().toggleBulletList().run();
|
|
1391
1319
|
});
|
|
1392
|
-
document.getElementById('
|
|
1393
|
-
editor.chain().focus().
|
|
1320
|
+
document.getElementById('toggleOrderedListButton').addEventListener('click', () => {
|
|
1321
|
+
editor.chain().focus().toggleOrderedList().run();
|
|
1322
|
+
});
|
|
1323
|
+
document.getElementById('toggleBlockquoteButton').addEventListener('click', () => {
|
|
1324
|
+
editor.chain().focus().toggleBlockquote().run();
|
|
1325
|
+
});
|
|
1326
|
+
document.getElementById('toggleHRButton').addEventListener('click', () => {
|
|
1327
|
+
editor.chain().focus().setHorizontalRule().run();
|
|
1328
|
+
});
|
|
1329
|
+
document.getElementById('toggleCodeBlockButton').addEventListener('click', () => {
|
|
1330
|
+
editor.chain().focus().toggleCodeBlock().run();
|
|
1331
|
+
});
|
|
1332
|
+
|
|
1333
|
+
// typography dropdown
|
|
1334
|
+
const typographyDropdown = FlowbiteInstances.getInstance('Dropdown', 'typographyDropdown');
|
|
1335
|
+
|
|
1336
|
+
document.getElementById('toggleParagraphButton').addEventListener('click', () => {
|
|
1337
|
+
editor.chain().focus().setParagraph().run();
|
|
1338
|
+
typographyDropdown.hide();
|
|
1339
|
+
});
|
|
1340
|
+
|
|
1341
|
+
document.querySelectorAll('[data-heading-level]').forEach((button) => {
|
|
1342
|
+
button.addEventListener('click', () => {
|
|
1343
|
+
const level = button.getAttribute('data-heading-level');
|
|
1344
|
+
editor.chain().focus().toggleHeading({ level: parseInt(level) }).run()
|
|
1345
|
+
typographyDropdown.hide();
|
|
1346
|
+
});
|
|
1394
1347
|
});
|
|
1395
1348
|
}
|
|
1396
1349
|
})
|
|
1397
|
-
|
|
1350
|
+
```
|
|
1351
|
+
|
|
1352
|
+
## Configuring links
|
|
1353
|
+
|
|
1354
|
+
Use this example to add and remove anchor links for the content inside of the WYSIWYG text editor.
|
|
1355
|
+
|
|
1356
|
+
```html
|
|
1398
1357
|
<div class="w-full bg-neutral-secondary-medium border border-default-medium rounded-base">
|
|
1399
1358
|
<div class="p-2 border-b border-default-medium">
|
|
1400
1359
|
<div class="flex flex-wrap items-center">
|
|
@@ -1427,28 +1386,28 @@ window.addEventListener('load', function() {
|
|
|
1427
1386
|
<div id="wysiwyg-links-example"class="block w-full px-0 text-sm text-body bg-neutral-primary border-0 focus:ring-0"></div>
|
|
1428
1387
|
</div>
|
|
1429
1388
|
</div>
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
## Using images
|
|
1433
|
-
|
|
1434
|
-
Use this example to learn how to add images inside of the WYSIWYG text editor and configure settings such as the image URL, image alt attribute which is important for SEO and accessibility and the image title.
|
|
1389
|
+
```
|
|
1435
1390
|
|
|
1436
|
-
|
|
1391
|
+
```javascript
|
|
1437
1392
|
import { Editor } from 'https://esm.sh/@tiptap/core@2.6.6';
|
|
1438
1393
|
import StarterKit from 'https://esm.sh/@tiptap/starter-kit@2.6.6';
|
|
1439
|
-
import
|
|
1394
|
+
import Link from 'https://esm.sh/@tiptap/extension-link@2.6.6';
|
|
1440
1395
|
|
|
1441
1396
|
window.addEventListener('load', function() {
|
|
1442
|
-
if (document.getElementById("wysiwyg-
|
|
1397
|
+
if (document.getElementById("wysiwyg-links-example")) {
|
|
1443
1398
|
|
|
1444
1399
|
// tip tap editor setup
|
|
1445
1400
|
const editor = new Editor({
|
|
1446
|
-
element: document.querySelector('#wysiwyg-
|
|
1401
|
+
element: document.querySelector('#wysiwyg-links-example'),
|
|
1447
1402
|
extensions: [
|
|
1448
1403
|
StarterKit,
|
|
1449
|
-
|
|
1404
|
+
Link.configure({
|
|
1405
|
+
openOnClick: false,
|
|
1406
|
+
autolink: true,
|
|
1407
|
+
defaultProtocol: 'https',
|
|
1408
|
+
})
|
|
1450
1409
|
],
|
|
1451
|
-
content: '<p>Flowbite is an <strong>open-source library of UI components</strong> based on the utility-first Tailwind CSS framework featuring dark mode support, a Figma design system, and more.</p><
|
|
1410
|
+
content: '<p>Flowbite is an <strong>open-source library of UI components</strong> based on the utility-first Tailwind CSS framework featuring dark mode support, a Figma design system, and more.</p><p>It includes all of the commonly used components that a website requires, such as buttons, dropdowns, navigation bars, modals, datepickers, advanced charts and the list goes on.</p><p>Here is an example of a button component:</p><code><button type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-base text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Default</button></code><p>Learn more about all components from the <a href="https://flowbite.com/docs/getting-started/introduction/">Flowbite Docs</a>.</p>',
|
|
1452
1411
|
editorProps: {
|
|
1453
1412
|
attributes: {
|
|
1454
1413
|
class: 'format lg:format-lg dark:format-invert focus:outline-none format-blue max-w-none',
|
|
@@ -1457,33 +1416,22 @@ window.addEventListener('load', function() {
|
|
|
1457
1416
|
});
|
|
1458
1417
|
|
|
1459
1418
|
// set up custom event listeners for the buttons
|
|
1460
|
-
document.getElementById('
|
|
1461
|
-
const url = window.prompt('Enter image URL:', 'https://
|
|
1462
|
-
|
|
1463
|
-
editor.chain().focus().setImage({ src: url }).run();
|
|
1464
|
-
}
|
|
1419
|
+
document.getElementById('toggleLinkButton').addEventListener('click', () => {
|
|
1420
|
+
const url = window.prompt('Enter image URL:', 'https://flowbite.com');
|
|
1421
|
+
editor.chain().focus().toggleLink({ href: url }).run();
|
|
1465
1422
|
});
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
document.getElementById('advancedImageForm').addEventListener('submit', (e) => {
|
|
1470
|
-
|
|
1471
|
-
e.preventDefault();
|
|
1472
|
-
|
|
1473
|
-
const imageUrl = document.getElementById('URL').value;
|
|
1474
|
-
const imageAlt = document.getElementById('alt').value;
|
|
1475
|
-
const imageTitle = document.getElementById('title').value;
|
|
1476
|
-
|
|
1477
|
-
if (imageUrl) {
|
|
1478
|
-
editor.chain().focus().setImage({ src: imageUrl, alt: imageAlt ? imageAlt : '', title: imageTitle ? imageTitle: '' }).run();
|
|
1479
|
-
document.getElementById('advancedImageForm').reset();
|
|
1480
|
-
advancedImageModal.hide();
|
|
1481
|
-
}
|
|
1423
|
+
document.getElementById('removeLinkButton').addEventListener('click', () => {
|
|
1424
|
+
editor.chain().focus().unsetLink().run()
|
|
1482
1425
|
});
|
|
1483
|
-
|
|
1484
1426
|
}
|
|
1485
1427
|
})
|
|
1486
|
-
|
|
1428
|
+
```
|
|
1429
|
+
|
|
1430
|
+
## Using images
|
|
1431
|
+
|
|
1432
|
+
Use this example to learn how to add images inside of the WYSIWYG text editor and configure settings such as the image URL, image alt attribute which is important for SEO and accessibility and the image title.
|
|
1433
|
+
|
|
1434
|
+
```html
|
|
1487
1435
|
<div class="w-full bg-neutral-secondary-medium border border-default-medium rounded-base">
|
|
1488
1436
|
<div class="p-2 border-b border-default-medium">
|
|
1489
1437
|
<div class="flex items-center gap-2">
|
|
@@ -1557,26 +1505,22 @@ window.addEventListener('load', function() {
|
|
|
1557
1505
|
</div>
|
|
1558
1506
|
</div>
|
|
1559
1507
|
</div>
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
## Adding videos
|
|
1508
|
+
```
|
|
1563
1509
|
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
{{< example class="flex justify-center bg-neutral-primary" github="plugins/wysiwyg.md" show_dark=true wysiwyg=true script_module=true disable_init_js=true javascript=`
|
|
1510
|
+
```javascript
|
|
1567
1511
|
import { Editor } from 'https://esm.sh/@tiptap/core@2.6.6';
|
|
1568
1512
|
import StarterKit from 'https://esm.sh/@tiptap/starter-kit@2.6.6';
|
|
1569
|
-
import
|
|
1513
|
+
import Image from 'https://esm.sh/@tiptap/extension-image@2.6.6';
|
|
1570
1514
|
|
|
1571
1515
|
window.addEventListener('load', function() {
|
|
1572
|
-
if (document.getElementById("wysiwyg-
|
|
1516
|
+
if (document.getElementById("wysiwyg-images-example")) {
|
|
1573
1517
|
|
|
1574
1518
|
// tip tap editor setup
|
|
1575
1519
|
const editor = new Editor({
|
|
1576
|
-
element: document.querySelector('#wysiwyg-
|
|
1520
|
+
element: document.querySelector('#wysiwyg-images-example'),
|
|
1577
1521
|
extensions: [
|
|
1578
1522
|
StarterKit,
|
|
1579
|
-
|
|
1523
|
+
Image
|
|
1580
1524
|
],
|
|
1581
1525
|
content: '<p>Flowbite is an <strong>open-source library of UI components</strong> based on the utility-first Tailwind CSS framework featuring dark mode support, a Figma design system, and more.</p><img src="https://placehold.co/600x400" contenteditable="false" draggable="true"><p>It includes all of the commonly used components that a website requires, such as buttons, dropdowns, navigation bars, modals, datepickers, advanced charts and the list goes on.</p><p>Here is an example of a button component:</p><code><button type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-base text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Default</button></code><p>Learn more about all components from the <a href="https://flowbite.com/docs/getting-started/introduction/">Flowbite Docs</a>.</p>',
|
|
1582
1526
|
editorProps: {
|
|
@@ -1587,37 +1531,39 @@ window.addEventListener('load', function() {
|
|
|
1587
1531
|
});
|
|
1588
1532
|
|
|
1589
1533
|
// set up custom event listeners for the buttons
|
|
1590
|
-
document.getElementById('
|
|
1591
|
-
const url = window.prompt('Enter
|
|
1534
|
+
document.getElementById('addImageButton').addEventListener('click', () => {
|
|
1535
|
+
const url = window.prompt('Enter image URL:', 'https://placehold.co/600x400');
|
|
1592
1536
|
if (url) {
|
|
1593
|
-
editor.
|
|
1594
|
-
src: url,
|
|
1595
|
-
width: 640,
|
|
1596
|
-
height: 480,
|
|
1597
|
-
})
|
|
1537
|
+
editor.chain().focus().setImage({ src: url }).run();
|
|
1598
1538
|
}
|
|
1599
1539
|
});
|
|
1600
1540
|
|
|
1601
|
-
const
|
|
1541
|
+
const advancedImageModal = FlowbiteInstances.getInstance('Modal', 'advanced-image-modal');
|
|
1602
1542
|
|
|
1603
|
-
document.getElementById('
|
|
1543
|
+
document.getElementById('advancedImageForm').addEventListener('submit', (e) => {
|
|
1604
1544
|
|
|
1605
1545
|
e.preventDefault();
|
|
1606
1546
|
|
|
1607
|
-
const
|
|
1608
|
-
const
|
|
1609
|
-
const
|
|
1547
|
+
const imageUrl = document.getElementById('URL').value;
|
|
1548
|
+
const imageAlt = document.getElementById('alt').value;
|
|
1549
|
+
const imageTitle = document.getElementById('title').value;
|
|
1610
1550
|
|
|
1611
|
-
if (
|
|
1612
|
-
editor.
|
|
1613
|
-
document.getElementById('
|
|
1614
|
-
|
|
1551
|
+
if (imageUrl) {
|
|
1552
|
+
editor.chain().focus().setImage({ src: imageUrl, alt: imageAlt ? imageAlt : '', title: imageTitle ? imageTitle: '' }).run();
|
|
1553
|
+
document.getElementById('advancedImageForm').reset();
|
|
1554
|
+
advancedImageModal.hide();
|
|
1615
1555
|
}
|
|
1616
1556
|
});
|
|
1617
1557
|
|
|
1618
1558
|
}
|
|
1619
1559
|
})
|
|
1620
|
-
|
|
1560
|
+
```
|
|
1561
|
+
|
|
1562
|
+
## Adding videos
|
|
1563
|
+
|
|
1564
|
+
Use this example to embed videos inside the WYSIWYG text editor based on a YouTube URL source and set the width and height of the video by using the Flowbite modal component API.
|
|
1565
|
+
|
|
1566
|
+
```html
|
|
1621
1567
|
<div class="w-full bg-neutral-secondary-medium border border-default-medium rounded-base">
|
|
1622
1568
|
<div class="p-2 border-b border-default-medium">
|
|
1623
1569
|
<div class="flex items-center gap-2">
|
|
@@ -1686,60 +1632,24 @@ window.addEventListener('load', function() {
|
|
|
1686
1632
|
</div>
|
|
1687
1633
|
</div>
|
|
1688
1634
|
</div>
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
## Editing tables
|
|
1635
|
+
```
|
|
1692
1636
|
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
{{< example class="flex justify-center bg-neutral-primary" github="plugins/wysiwyg.md" show_dark=true wysiwyg=true script_module=true disable_init_js=true javascript=`
|
|
1637
|
+
```javascript
|
|
1696
1638
|
import { Editor } from 'https://esm.sh/@tiptap/core@2.6.6';
|
|
1697
1639
|
import StarterKit from 'https://esm.sh/@tiptap/starter-kit@2.6.6';
|
|
1698
|
-
import
|
|
1699
|
-
import TableCell from 'https://esm.sh/@tiptap/extension-table-cell@2.6.6';
|
|
1700
|
-
import TableHeader from 'https://esm.sh/@tiptap/extension-table-header@2.6.6';
|
|
1701
|
-
import TableRow from 'https://esm.sh/@tiptap/extension-table-row@2.6.6';
|
|
1702
|
-
|
|
1703
|
-
const TipTapExtensionTableCell = TableCell.extend({
|
|
1704
|
-
addAttributes() {
|
|
1705
|
-
return {
|
|
1706
|
-
...this.parent?.(),
|
|
1707
|
-
backgroundColor: {
|
|
1708
|
-
default: null,
|
|
1709
|
-
renderHTML: (attributes) => {
|
|
1710
|
-
if (!attributes.backgroundColor) {
|
|
1711
|
-
return {}
|
|
1712
|
-
}
|
|
1713
|
-
|
|
1714
|
-
return {
|
|
1715
|
-
style: 'background-color: ' + attributes.backgroundColor,
|
|
1716
|
-
}
|
|
1717
|
-
},
|
|
1718
|
-
parseHTML: (element) => {
|
|
1719
|
-
return element.style.backgroundColor.replace(/['"]+/g, '')
|
|
1720
|
-
},
|
|
1721
|
-
},
|
|
1722
|
-
}
|
|
1723
|
-
},
|
|
1724
|
-
});
|
|
1640
|
+
import YouTube from 'https://esm.sh/@tiptap/extension-youtube@2.6.6';
|
|
1725
1641
|
|
|
1726
1642
|
window.addEventListener('load', function() {
|
|
1727
|
-
if (document.getElementById("wysiwyg-
|
|
1643
|
+
if (document.getElementById("wysiwyg-video-example")) {
|
|
1728
1644
|
|
|
1729
1645
|
// tip tap editor setup
|
|
1730
1646
|
const editor = new Editor({
|
|
1731
|
-
element: document.querySelector('#wysiwyg-
|
|
1647
|
+
element: document.querySelector('#wysiwyg-video-example'),
|
|
1732
1648
|
extensions: [
|
|
1733
1649
|
StarterKit,
|
|
1734
|
-
|
|
1735
|
-
resizable: true,
|
|
1736
|
-
}),
|
|
1737
|
-
TableRow,
|
|
1738
|
-
TableHeader,
|
|
1739
|
-
TableCell,
|
|
1740
|
-
TipTapExtensionTableCell
|
|
1650
|
+
YouTube
|
|
1741
1651
|
],
|
|
1742
|
-
content: '<p>
|
|
1652
|
+
content: '<p>Flowbite is an <strong>open-source library of UI components</strong> based on the utility-first Tailwind CSS framework featuring dark mode support, a Figma design system, and more.</p><img src="https://placehold.co/600x400" contenteditable="false" draggable="true"><p>It includes all of the commonly used components that a website requires, such as buttons, dropdowns, navigation bars, modals, datepickers, advanced charts and the list goes on.</p><p>Here is an example of a button component:</p><code><button type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-base text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Default</button></code><p>Learn more about all components from the <a href="https://flowbite.com/docs/getting-started/introduction/">Flowbite Docs</a>.</p>',
|
|
1743
1653
|
editorProps: {
|
|
1744
1654
|
attributes: {
|
|
1745
1655
|
class: 'format lg:format-lg dark:format-invert focus:outline-none format-blue max-w-none',
|
|
@@ -1748,108 +1658,43 @@ window.addEventListener('load', function() {
|
|
|
1748
1658
|
});
|
|
1749
1659
|
|
|
1750
1660
|
// set up custom event listeners for the buttons
|
|
1751
|
-
document.getElementById('
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
// add column after
|
|
1761
|
-
document.getElementById('addColumnAfterButton').addEventListener('click', () => {
|
|
1762
|
-
editor.chain().focus().addColumnAfter().run();
|
|
1763
|
-
});
|
|
1764
|
-
|
|
1765
|
-
// remove column
|
|
1766
|
-
document.getElementById('removeColumnButton').addEventListener('click', () => {
|
|
1767
|
-
editor.chain().focus().deleteColumn().run();
|
|
1768
|
-
});
|
|
1769
|
-
|
|
1770
|
-
// add row before
|
|
1771
|
-
document.getElementById('addRowBeforeButton').addEventListener('click', () => {
|
|
1772
|
-
editor.chain().focus().addRowBefore().run();
|
|
1773
|
-
});
|
|
1774
|
-
|
|
1775
|
-
// add row after
|
|
1776
|
-
document.getElementById('addRowAfterButton').addEventListener('click', () => {
|
|
1777
|
-
editor.chain().focus().addRowAfter().run();
|
|
1778
|
-
});
|
|
1779
|
-
|
|
1780
|
-
// remove row
|
|
1781
|
-
document.getElementById('removeRowButton').addEventListener('click', () => {
|
|
1782
|
-
editor.chain().focus().deleteRow().run();
|
|
1783
|
-
});
|
|
1784
|
-
|
|
1785
|
-
// delete table
|
|
1786
|
-
document.getElementById('deleteTableButton').addEventListener('click', () => {
|
|
1787
|
-
editor.chain().focus().deleteTable().run();
|
|
1788
|
-
});
|
|
1789
|
-
|
|
1790
|
-
// merge cells
|
|
1791
|
-
document.getElementById('mergeCellsButton').addEventListener('click', () => {
|
|
1792
|
-
editor.chain().focus().mergeCells().run();
|
|
1793
|
-
});
|
|
1794
|
-
|
|
1795
|
-
// split cells
|
|
1796
|
-
document.getElementById('splitCellsButton').addEventListener('click', () => {
|
|
1797
|
-
editor.chain().focus().splitCell().run();
|
|
1798
|
-
});
|
|
1799
|
-
|
|
1800
|
-
// merge or split
|
|
1801
|
-
document.getElementById('mergeOrSplitButton').addEventListener('click', () => {
|
|
1802
|
-
editor.chain().focus().mergeOrSplit().run();
|
|
1803
|
-
});
|
|
1804
|
-
|
|
1805
|
-
// toggle header column
|
|
1806
|
-
document.getElementById('toggleHeaderColumnButton').addEventListener('click', () => {
|
|
1807
|
-
editor.chain().focus().toggleHeaderColumn().run();
|
|
1808
|
-
});
|
|
1809
|
-
|
|
1810
|
-
// toggle header row
|
|
1811
|
-
document.getElementById('toggleHeaderRowButton').addEventListener('click', () => {
|
|
1812
|
-
editor.chain().focus().toggleHeaderRow().run();
|
|
1813
|
-
});
|
|
1814
|
-
|
|
1815
|
-
// toggle header cell
|
|
1816
|
-
document.getElementById('toggleHeaderCellButton').addEventListener('click', () => {
|
|
1817
|
-
editor.chain().focus().toggleHeaderCell().run();
|
|
1661
|
+
document.getElementById('addVideoButton').addEventListener('click', () => {
|
|
1662
|
+
const url = window.prompt('Enter YouTube URL:', 'https://www.youtube.com/watch?v=KaLxCiilHns');
|
|
1663
|
+
if (url) {
|
|
1664
|
+
editor.commands.setYoutubeVideo({
|
|
1665
|
+
src: url,
|
|
1666
|
+
width: 640,
|
|
1667
|
+
height: 480,
|
|
1668
|
+
})
|
|
1669
|
+
}
|
|
1818
1670
|
});
|
|
1819
1671
|
|
|
1820
|
-
const
|
|
1672
|
+
const advancedVideoModal = FlowbiteInstances.getInstance('Modal', 'advanced-video-modal');
|
|
1821
1673
|
|
|
1822
|
-
document.getElementById('
|
|
1674
|
+
document.getElementById('advancedVideoForm').addEventListener('submit', (e) => {
|
|
1823
1675
|
|
|
1824
1676
|
e.preventDefault();
|
|
1825
1677
|
|
|
1826
|
-
const
|
|
1827
|
-
const
|
|
1828
|
-
|
|
1829
|
-
if (attributeName && attributeValue) {
|
|
1830
|
-
const result = editor.commands.setCellAttribute(attributeName ? attributeName : '', attributeValue ? attributeValue : '');
|
|
1831
|
-
document.getElementById('addCellAttributeForm').reset();
|
|
1832
|
-
cellAttributeModal.hide();
|
|
1833
|
-
}
|
|
1834
|
-
});
|
|
1835
|
-
|
|
1836
|
-
// fix tables
|
|
1837
|
-
document.getElementById('fixTablesButton').addEventListener('click', () => {
|
|
1838
|
-
editor.commands.fixTables();
|
|
1839
|
-
});
|
|
1840
|
-
|
|
1841
|
-
// go to previous cell
|
|
1842
|
-
document.getElementById('previousCellButton').addEventListener('click', () => {
|
|
1843
|
-
editor.chain().focus().goToPreviousCell().run();
|
|
1844
|
-
});
|
|
1678
|
+
const videoUrl = document.getElementById('URL').value;
|
|
1679
|
+
const videoWidth = document.getElementById('width').value;
|
|
1680
|
+
const videoHeight = document.getElementById('height').value;
|
|
1845
1681
|
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1682
|
+
if (videoUrl) {
|
|
1683
|
+
editor.commands.setYoutubeVideo({ src: videoUrl, width: videoWidth ? videoWidth : 640, height: videoHeight ? videoHeight: 480 });
|
|
1684
|
+
document.getElementById('advancedVideoForm').reset();
|
|
1685
|
+
advancedVideoModal.hide();
|
|
1686
|
+
}
|
|
1849
1687
|
});
|
|
1688
|
+
|
|
1850
1689
|
}
|
|
1851
1690
|
})
|
|
1852
|
-
|
|
1691
|
+
```
|
|
1692
|
+
|
|
1693
|
+
## Editing tables
|
|
1694
|
+
|
|
1695
|
+
Use this example to edit table data inside the WYSIWYG text editor by adding and removing table column, rows, and cells and use other features to navigate through the table data for a convenient editing process.
|
|
1696
|
+
|
|
1697
|
+
```html
|
|
1853
1698
|
<div class="w-full bg-neutral-secondary-medium border border-default-medium rounded-base">
|
|
1854
1699
|
<div class="p-2 border-b border-default-medium">
|
|
1855
1700
|
<div class="flex items-center gap-2">
|
|
@@ -2092,26 +1937,56 @@ window.addEventListener('load', function() {
|
|
|
2092
1937
|
</div>
|
|
2093
1938
|
</div>
|
|
2094
1939
|
</div>
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
## Undo and redo
|
|
2098
|
-
|
|
2099
|
-
Use the history functionality from the WYSIWYG text editor component to integrate undo and redo actions.
|
|
1940
|
+
```
|
|
2100
1941
|
|
|
2101
|
-
|
|
1942
|
+
```javascript
|
|
2102
1943
|
import { Editor } from 'https://esm.sh/@tiptap/core@2.6.6';
|
|
2103
1944
|
import StarterKit from 'https://esm.sh/@tiptap/starter-kit@2.6.6';
|
|
1945
|
+
import Table from 'https://esm.sh/@tiptap/extension-table@2.6.6';
|
|
1946
|
+
import TableCell from 'https://esm.sh/@tiptap/extension-table-cell@2.6.6';
|
|
1947
|
+
import TableHeader from 'https://esm.sh/@tiptap/extension-table-header@2.6.6';
|
|
1948
|
+
import TableRow from 'https://esm.sh/@tiptap/extension-table-row@2.6.6';
|
|
1949
|
+
|
|
1950
|
+
const TipTapExtensionTableCell = TableCell.extend({
|
|
1951
|
+
addAttributes() {
|
|
1952
|
+
return {
|
|
1953
|
+
...this.parent?.(),
|
|
1954
|
+
backgroundColor: {
|
|
1955
|
+
default: null,
|
|
1956
|
+
renderHTML: (attributes) => {
|
|
1957
|
+
if (!attributes.backgroundColor) {
|
|
1958
|
+
return {}
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
return {
|
|
1962
|
+
style: 'background-color: ' + attributes.backgroundColor,
|
|
1963
|
+
}
|
|
1964
|
+
},
|
|
1965
|
+
parseHTML: (element) => {
|
|
1966
|
+
return element.style.backgroundColor.replace(/['"]+/g, '')
|
|
1967
|
+
},
|
|
1968
|
+
},
|
|
1969
|
+
}
|
|
1970
|
+
},
|
|
1971
|
+
});
|
|
2104
1972
|
|
|
2105
1973
|
window.addEventListener('load', function() {
|
|
2106
|
-
if (document.getElementById("wysiwyg-
|
|
1974
|
+
if (document.getElementById("wysiwyg-tables-example")) {
|
|
2107
1975
|
|
|
2108
1976
|
// tip tap editor setup
|
|
2109
1977
|
const editor = new Editor({
|
|
2110
|
-
element: document.querySelector('#wysiwyg-
|
|
1978
|
+
element: document.querySelector('#wysiwyg-tables-example'),
|
|
2111
1979
|
extensions: [
|
|
2112
|
-
StarterKit
|
|
1980
|
+
StarterKit,
|
|
1981
|
+
Table.configure({
|
|
1982
|
+
resizable: true,
|
|
1983
|
+
}),
|
|
1984
|
+
TableRow,
|
|
1985
|
+
TableHeader,
|
|
1986
|
+
TableCell,
|
|
1987
|
+
TipTapExtensionTableCell
|
|
2113
1988
|
],
|
|
2114
|
-
content: '<p>
|
|
1989
|
+
content: '<p>Understanding global <strong>population growth trends</strong> is essential for analyzing the development and future of nations. Population growth rates provide insights into economic prospects, resource allocation, and potential challenges for countries worldwide.</p><p>Here is an example of population data:</p><div class=tableWrapper><table style=min-width:75px><col><col><col><tr><th colspan=1 rowspan=1><p>Country<th colspan=1 rowspan=1><p>Population<th colspan=1 rowspan=1><p>Growth rate<tr><td colspan=1 rowspan=1><p>United States<td colspan=1 rowspan=1><p>333 million<td colspan=1 rowspan=1><p>0.4%<tr><td colspan=1 rowspan=1><p>China<td colspan=1 rowspan=1><p>1.41 billion<td colspan=1 rowspan=1><p>0%<tr><td colspan=1 rowspan=1><p>Germany<td colspan=1 rowspan=1><p>83.8 million<td colspan=1 rowspan=1><p>0.7%<tr><td colspan=1 rowspan=1><p>India<td colspan=1 rowspan=1><p>1.42 billion<td colspan=1 rowspan=1><p>1.0%<tr><td colspan=1 rowspan=1><p>Brazil<td colspan=1 rowspan=1><p>214 million<td colspan=1 rowspan=1><p>0.6%<tr><td colspan=1 rowspan=1><p>Indonesia<td colspan=1 rowspan=1><p>273 million<td colspan=1 rowspan=1><p>1.1%<tr><td colspan=1 rowspan=1><p>Pakistan<td colspan=1 rowspan=1><p>231 million<td colspan=1 rowspan=1><p>2.0%<tr><td colspan=1 rowspan=1><p>Nigeria<td colspan=1 rowspan=1><p>223 million<td colspan=1 rowspan=1><p>2.5%</table></div><p>Learn more about global population trends from reliable sources like the <a href=https://www.worldpopulationreview.com>World Population Review</a>.</p>',
|
|
2115
1990
|
editorProps: {
|
|
2116
1991
|
attributes: {
|
|
2117
1992
|
class: 'format lg:format-lg dark:format-invert focus:outline-none format-blue max-w-none',
|
|
@@ -2120,16 +1995,114 @@ window.addEventListener('load', function() {
|
|
|
2120
1995
|
});
|
|
2121
1996
|
|
|
2122
1997
|
// set up custom event listeners for the buttons
|
|
2123
|
-
document.getElementById('
|
|
2124
|
-
editor.chain().focus().
|
|
1998
|
+
document.getElementById('addTableButton').addEventListener('click', () => {
|
|
1999
|
+
editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run();
|
|
2125
2000
|
});
|
|
2126
|
-
|
|
2127
|
-
|
|
2001
|
+
|
|
2002
|
+
// add column before
|
|
2003
|
+
document.getElementById('addColumnBeforeButton').addEventListener('click', () => {
|
|
2004
|
+
editor.chain().focus().addColumnBefore().run();
|
|
2005
|
+
});
|
|
2006
|
+
|
|
2007
|
+
// add column after
|
|
2008
|
+
document.getElementById('addColumnAfterButton').addEventListener('click', () => {
|
|
2009
|
+
editor.chain().focus().addColumnAfter().run();
|
|
2010
|
+
});
|
|
2011
|
+
|
|
2012
|
+
// remove column
|
|
2013
|
+
document.getElementById('removeColumnButton').addEventListener('click', () => {
|
|
2014
|
+
editor.chain().focus().deleteColumn().run();
|
|
2015
|
+
});
|
|
2016
|
+
|
|
2017
|
+
// add row before
|
|
2018
|
+
document.getElementById('addRowBeforeButton').addEventListener('click', () => {
|
|
2019
|
+
editor.chain().focus().addRowBefore().run();
|
|
2020
|
+
});
|
|
2021
|
+
|
|
2022
|
+
// add row after
|
|
2023
|
+
document.getElementById('addRowAfterButton').addEventListener('click', () => {
|
|
2024
|
+
editor.chain().focus().addRowAfter().run();
|
|
2025
|
+
});
|
|
2026
|
+
|
|
2027
|
+
// remove row
|
|
2028
|
+
document.getElementById('removeRowButton').addEventListener('click', () => {
|
|
2029
|
+
editor.chain().focus().deleteRow().run();
|
|
2030
|
+
});
|
|
2031
|
+
|
|
2032
|
+
// delete table
|
|
2033
|
+
document.getElementById('deleteTableButton').addEventListener('click', () => {
|
|
2034
|
+
editor.chain().focus().deleteTable().run();
|
|
2035
|
+
});
|
|
2036
|
+
|
|
2037
|
+
// merge cells
|
|
2038
|
+
document.getElementById('mergeCellsButton').addEventListener('click', () => {
|
|
2039
|
+
editor.chain().focus().mergeCells().run();
|
|
2040
|
+
});
|
|
2041
|
+
|
|
2042
|
+
// split cells
|
|
2043
|
+
document.getElementById('splitCellsButton').addEventListener('click', () => {
|
|
2044
|
+
editor.chain().focus().splitCell().run();
|
|
2045
|
+
});
|
|
2046
|
+
|
|
2047
|
+
// merge or split
|
|
2048
|
+
document.getElementById('mergeOrSplitButton').addEventListener('click', () => {
|
|
2049
|
+
editor.chain().focus().mergeOrSplit().run();
|
|
2050
|
+
});
|
|
2051
|
+
|
|
2052
|
+
// toggle header column
|
|
2053
|
+
document.getElementById('toggleHeaderColumnButton').addEventListener('click', () => {
|
|
2054
|
+
editor.chain().focus().toggleHeaderColumn().run();
|
|
2055
|
+
});
|
|
2056
|
+
|
|
2057
|
+
// toggle header row
|
|
2058
|
+
document.getElementById('toggleHeaderRowButton').addEventListener('click', () => {
|
|
2059
|
+
editor.chain().focus().toggleHeaderRow().run();
|
|
2128
2060
|
});
|
|
2129
2061
|
|
|
2062
|
+
// toggle header cell
|
|
2063
|
+
document.getElementById('toggleHeaderCellButton').addEventListener('click', () => {
|
|
2064
|
+
editor.chain().focus().toggleHeaderCell().run();
|
|
2065
|
+
});
|
|
2066
|
+
|
|
2067
|
+
const cellAttributeModal = FlowbiteInstances.getInstance('Modal', 'cell-attribute-modal');
|
|
2068
|
+
|
|
2069
|
+
document.getElementById('addCellAttributeForm').addEventListener('submit', (e) => {
|
|
2070
|
+
|
|
2071
|
+
e.preventDefault();
|
|
2072
|
+
|
|
2073
|
+
const attributeName = document.getElementById('attribute-name').value;
|
|
2074
|
+
const attributeValue = document.getElementById('attribute-value').value;
|
|
2075
|
+
|
|
2076
|
+
if (attributeName && attributeValue) {
|
|
2077
|
+
const result = editor.commands.setCellAttribute(attributeName ? attributeName : '', attributeValue ? attributeValue : '');
|
|
2078
|
+
document.getElementById('addCellAttributeForm').reset();
|
|
2079
|
+
cellAttributeModal.hide();
|
|
2080
|
+
}
|
|
2081
|
+
});
|
|
2082
|
+
|
|
2083
|
+
// fix tables
|
|
2084
|
+
document.getElementById('fixTablesButton').addEventListener('click', () => {
|
|
2085
|
+
editor.commands.fixTables();
|
|
2086
|
+
});
|
|
2087
|
+
|
|
2088
|
+
// go to previous cell
|
|
2089
|
+
document.getElementById('previousCellButton').addEventListener('click', () => {
|
|
2090
|
+
editor.chain().focus().goToPreviousCell().run();
|
|
2091
|
+
});
|
|
2092
|
+
|
|
2093
|
+
// go to the next cell
|
|
2094
|
+
document.getElementById('nextCellButton').addEventListener('click', () => {
|
|
2095
|
+
editor.chain().focus().goToNextCell().run();
|
|
2096
|
+
});
|
|
2130
2097
|
}
|
|
2131
2098
|
})
|
|
2132
|
-
|
|
2099
|
+
```
|
|
2100
|
+
|
|
2101
|
+
## Undo and redo
|
|
2102
|
+
|
|
2103
|
+
Use the history functionality from the WYSIWYG text editor component to integrate undo and redo actions.
|
|
2104
|
+
|
|
2105
|
+
```html
|
|
2133
2106
|
<div class="w-full bg-neutral-secondary-medium border border-default-medium rounded-base">
|
|
2134
2107
|
<div class="p-2 border-b border-default-medium">
|
|
2135
2108
|
<div class="flex flex-wrap items-center">
|
|
@@ -2162,22 +2135,18 @@ window.addEventListener('load', function() {
|
|
|
2162
2135
|
<div id="wysiwyg-history-example"class="block w-full px-0 text-sm text-body bg-neutral-primary border-0 focus:ring-0"></div>
|
|
2163
2136
|
</div>
|
|
2164
2137
|
</div>
|
|
2165
|
-
|
|
2138
|
+
```
|
|
2166
2139
|
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
Use the `editor.getJSON()` and the `editor.getHTML()` functions to export the text content inside of the WYSIWYG text editor in JSON or raw HTML format to persist into your database or API structure.
|
|
2170
|
-
|
|
2171
|
-
{{< example class="flex justify-center bg-neutral-primary" github="plugins/wysiwyg.md" show_dark=true wysiwyg=true script_module=true disable_init_js=true javascript=`
|
|
2140
|
+
```javascript
|
|
2172
2141
|
import { Editor } from 'https://esm.sh/@tiptap/core@2.6.6';
|
|
2173
2142
|
import StarterKit from 'https://esm.sh/@tiptap/starter-kit@2.6.6';
|
|
2174
2143
|
|
|
2175
2144
|
window.addEventListener('load', function() {
|
|
2176
|
-
if (document.getElementById("wysiwyg-
|
|
2145
|
+
if (document.getElementById("wysiwyg-history-example")) {
|
|
2177
2146
|
|
|
2178
2147
|
// tip tap editor setup
|
|
2179
2148
|
const editor = new Editor({
|
|
2180
|
-
element: document.querySelector('#wysiwyg-
|
|
2149
|
+
element: document.querySelector('#wysiwyg-history-example'),
|
|
2181
2150
|
extensions: [
|
|
2182
2151
|
StarterKit
|
|
2183
2152
|
],
|
|
@@ -2189,34 +2158,23 @@ window.addEventListener('load', function() {
|
|
|
2189
2158
|
}
|
|
2190
2159
|
});
|
|
2191
2160
|
|
|
2192
|
-
const sourceCodeModal = FlowbiteInstances.getInstance('Modal', 'source-code-modal');
|
|
2193
|
-
const sourceCodeWrapper = document.getElementById('sourceCode');
|
|
2194
|
-
|
|
2195
2161
|
// set up custom event listeners for the buttons
|
|
2196
|
-
document.getElementById('
|
|
2197
|
-
|
|
2198
|
-
// basically just use editor.getHTML(); to get the raw html
|
|
2199
|
-
|
|
2200
|
-
sourceCodeWrapper.innerHTML = editor.getHTML()
|
|
2201
|
-
.replace(/&/g, "&") // Escape & character
|
|
2202
|
-
.replace(/</g, "<") // Escape < character
|
|
2203
|
-
.replace(/>/g, ">") // Escape > character
|
|
2204
|
-
.replace(/"/g, """) // Escape " character
|
|
2205
|
-
.replace(/'/g, "'"); // Escape ' character
|
|
2162
|
+
document.getElementById('toggleUndoButton').addEventListener('click', () => {
|
|
2163
|
+
editor.chain().focus().undo().run();
|
|
2206
2164
|
});
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
// basically just use editor.getJSON(); to get the raw json
|
|
2211
|
-
|
|
2212
|
-
sourceCode.innerHTML = JSON.stringify(editor.getJSON(), null, 2)
|
|
2213
|
-
.replace(/&/g, "&")
|
|
2214
|
-
.replace(/</g, "<")
|
|
2215
|
-
.replace(/>/g, ">");
|
|
2165
|
+
document.getElementById('toggleRedoButton').addEventListener('click', () => {
|
|
2166
|
+
editor.chain().focus().redo().run()
|
|
2216
2167
|
});
|
|
2168
|
+
|
|
2217
2169
|
}
|
|
2218
2170
|
})
|
|
2219
|
-
|
|
2171
|
+
```
|
|
2172
|
+
|
|
2173
|
+
## Exporting data
|
|
2174
|
+
|
|
2175
|
+
Use the `editor.getJSON()` and the `editor.getHTML()` functions to export the text content inside of the WYSIWYG text editor in JSON or raw HTML format to persist into your database or API structure.
|
|
2176
|
+
|
|
2177
|
+
```html
|
|
2220
2178
|
<div class="w-full bg-neutral-secondary-medium border border-default-medium rounded-base">
|
|
2221
2179
|
<div class="p-2 border-b border-default-medium">
|
|
2222
2180
|
<div class="flex flex-wrap items-center">
|
|
@@ -2273,7 +2231,57 @@ window.addEventListener('load', function() {
|
|
|
2273
2231
|
</div>
|
|
2274
2232
|
</div>
|
|
2275
2233
|
</div>
|
|
2276
|
-
|
|
2234
|
+
```
|
|
2235
|
+
|
|
2236
|
+
```javascript
|
|
2237
|
+
import { Editor } from 'https://esm.sh/@tiptap/core@2.6.6';
|
|
2238
|
+
import StarterKit from 'https://esm.sh/@tiptap/starter-kit@2.6.6';
|
|
2239
|
+
|
|
2240
|
+
window.addEventListener('load', function() {
|
|
2241
|
+
if (document.getElementById("wysiwyg-export-example")) {
|
|
2242
|
+
|
|
2243
|
+
// tip tap editor setup
|
|
2244
|
+
const editor = new Editor({
|
|
2245
|
+
element: document.querySelector('#wysiwyg-export-example'),
|
|
2246
|
+
extensions: [
|
|
2247
|
+
StarterKit
|
|
2248
|
+
],
|
|
2249
|
+
content: '<p>Flowbite is an <strong>open-source library of UI components</strong> based on the utility-first Tailwind CSS framework featuring dark mode support, a Figma design system, and more.</p><p>It includes all of the commonly used components that a website requires, such as buttons, dropdowns, navigation bars, modals, datepickers, advanced charts and the list goes on.</p><p>Here is an example of a button component:</p><code><button type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-base text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Default</button></code><p>Learn more about all components from the <a href="https://flowbite.com/docs/getting-started/introduction/">Flowbite Docs</a>.</p>',
|
|
2250
|
+
editorProps: {
|
|
2251
|
+
attributes: {
|
|
2252
|
+
class: 'format lg:format-lg dark:format-invert focus:outline-none format-blue max-w-none',
|
|
2253
|
+
},
|
|
2254
|
+
}
|
|
2255
|
+
});
|
|
2256
|
+
|
|
2257
|
+
const sourceCodeModal = FlowbiteInstances.getInstance('Modal', 'source-code-modal');
|
|
2258
|
+
const sourceCodeWrapper = document.getElementById('sourceCode');
|
|
2259
|
+
|
|
2260
|
+
// set up custom event listeners for the buttons
|
|
2261
|
+
document.getElementById('toggleHTMLButton').addEventListener('click', () => {
|
|
2262
|
+
|
|
2263
|
+
// basically just use editor.getHTML(); to get the raw html
|
|
2264
|
+
|
|
2265
|
+
sourceCodeWrapper.innerHTML = editor.getHTML()
|
|
2266
|
+
.replace(/&/g, "&") // Escape & character
|
|
2267
|
+
.replace(/</g, "<") // Escape < character
|
|
2268
|
+
.replace(/>/g, ">") // Escape > character
|
|
2269
|
+
.replace(/"/g, """) // Escape " character
|
|
2270
|
+
.replace(/'/g, "'"); // Escape ' character
|
|
2271
|
+
});
|
|
2272
|
+
|
|
2273
|
+
document.getElementById('toggleJSONButton').addEventListener('click', () => {
|
|
2274
|
+
|
|
2275
|
+
// basically just use editor.getJSON(); to get the raw json
|
|
2276
|
+
|
|
2277
|
+
sourceCode.innerHTML = JSON.stringify(editor.getJSON(), null, 2)
|
|
2278
|
+
.replace(/&/g, "&")
|
|
2279
|
+
.replace(/</g, "<")
|
|
2280
|
+
.replace(/>/g, ">");
|
|
2281
|
+
});
|
|
2282
|
+
}
|
|
2283
|
+
})
|
|
2284
|
+
```
|
|
2277
2285
|
|
|
2278
2286
|
## Javascript behaviour
|
|
2279
2287
|
|
|
@@ -2281,7 +2289,7 @@ Learn more about how you can programmatically use the WYSIWYG editor using Javas
|
|
|
2281
2289
|
|
|
2282
2290
|
After you have installed Tip Tap via NPM or CDN you can create a new `Editor` object:
|
|
2283
2291
|
|
|
2284
|
-
|
|
2292
|
+
```javascript
|
|
2285
2293
|
import { Editor } from '@tiptap/core';
|
|
2286
2294
|
import StarterKit from '@tiptap/starter-kit';
|
|
2287
2295
|
|
|
@@ -2290,13 +2298,13 @@ new Editor({
|
|
|
2290
2298
|
extensions: [StarterKit],
|
|
2291
2299
|
content: '<p>Welcome to Flowbite!</p>',
|
|
2292
2300
|
})
|
|
2293
|
-
|
|
2301
|
+
```
|
|
2294
2302
|
|
|
2295
2303
|
Make sure that you also have an empty `div` element with the appropiate ID:
|
|
2296
2304
|
|
|
2297
|
-
|
|
2305
|
+
```html
|
|
2298
2306
|
<div id="wysiwyg"></div>
|
|
2299
|
-
|
|
2307
|
+
```
|
|
2300
2308
|
|
|
2301
2309
|
This code will automatically set up the markup needed inside of the WYSIWYG component. Please note the fact that the Tip Tap library is headless so you need to style the elements yourself, but you can copy-paste the examples from Flowbite on this page.
|
|
2302
2310
|
|
|
@@ -2304,7 +2312,7 @@ This code will automatically set up the markup needed inside of the WYSIWYG comp
|
|
|
2304
2312
|
|
|
2305
2313
|
We also recommend adding custom typography classes from the [Flowbite Typography](https://flowbite.com/docs/components/typography/) package so that the content inside of the text editor will be correctly styled:
|
|
2306
2314
|
|
|
2307
|
-
|
|
2315
|
+
```javascript
|
|
2308
2316
|
new Editor({
|
|
2309
2317
|
element: document.getElementById('wysiwyg'),
|
|
2310
2318
|
extensions: [StarterKit],
|
|
@@ -2315,7 +2323,7 @@ new Editor({
|
|
|
2315
2323
|
},
|
|
2316
2324
|
}
|
|
2317
2325
|
})
|
|
2318
|
-
|
|
2326
|
+
```
|
|
2319
2327
|
|
|
2320
2328
|
### Extensions
|
|
2321
2329
|
|
|
@@ -2323,7 +2331,7 @@ Tip Tap is a modular library meaning that if you want to introduce images, video
|
|
|
2323
2331
|
|
|
2324
2332
|
Here is one example where we add the link extension:
|
|
2325
2333
|
|
|
2326
|
-
|
|
2334
|
+
```javascript
|
|
2327
2335
|
import { Editor } from '@tiptap/core';
|
|
2328
2336
|
import StarterKit from '@tiptap/starter-kit';
|
|
2329
2337
|
import Link from '@tiptap/extension-link';
|
|
@@ -2345,7 +2353,7 @@ const editor = new Editor({
|
|
|
2345
2353
|
},
|
|
2346
2354
|
}
|
|
2347
2355
|
});
|
|
2348
|
-
|
|
2356
|
+
```
|
|
2349
2357
|
|
|
2350
2358
|
Links will now be available inside the WYSIWYG component. Learn more about all of the <a href="https://tiptap.dev/docs/editor/extensions/overview" target="_blank" rel="nofollow">extensions API</a>.
|
|
2351
2359
|
|
|
@@ -2353,22 +2361,22 @@ Links will now be available inside the WYSIWYG component. Learn more about all o
|
|
|
2353
2361
|
|
|
2354
2362
|
You can easily call the methods from the `Editor` object to set text styles, links, images, and more. Here is one example where based upon a click event on a button you will be prompted with the URL of the link and it will add it to the currently selected text:
|
|
2355
2363
|
|
|
2356
|
-
|
|
2364
|
+
```javascript
|
|
2357
2365
|
// set up custom event listeners for the buttons
|
|
2358
2366
|
document.getElementById('toggleLinkButton').addEventListener('click', () => {
|
|
2359
2367
|
const url = window.prompt('Enter image URL:', 'https://flowbite.com');
|
|
2360
2368
|
editor.chain().focus().toggleLink({ href: url }).run();
|
|
2361
2369
|
});
|
|
2362
|
-
|
|
2370
|
+
```
|
|
2363
2371
|
|
|
2364
2372
|
And here's another example where you can unset a link:
|
|
2365
2373
|
|
|
2366
|
-
|
|
2374
|
+
```javascript
|
|
2367
2375
|
// unset the links based on a button click
|
|
2368
2376
|
document.getElementById('removeLinkButton').addEventListener('click', () => {
|
|
2369
2377
|
editor.chain().focus().unsetLink().run()
|
|
2370
2378
|
});
|
|
2371
|
-
|
|
2379
|
+
```
|
|
2372
2380
|
|
|
2373
2381
|
Examples from this page have functional elements so you can check the JavaScript tab for the source code.
|
|
2374
2382
|
|