@kubex/zinc 1.0.25 → 1.0.99
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/.claude/project.md +556 -0
- package/.github/workflows/js_build_and_deploy.yaml +9 -10
- package/dist/custom-elements.json +13575 -8856
- package/dist/vscode.html-custom-data.json +583 -48
- package/dist/web-types.json +1441 -181
- package/dist/zn.d.ts +1645 -660
- package/dist/zn.min.css +1 -1
- package/dist/zn.min.js +1412 -893
- package/docs/_utilities/code-previews.cjs +10 -1
- package/docs/assets/scripts/docs.js +42 -18
- package/docs/data/data-table.json +229 -66
- package/docs/data/empty.json +6 -0
- package/docs/data/products-table.json +41 -193
- package/docs/pages/components/action-bar.md +121 -6
- package/docs/pages/components/alert.md +118 -15
- package/docs/pages/components/animated-button.md +299 -0
- package/docs/pages/components/audio-select.md +534 -0
- package/docs/pages/components/bulk-actions.md +79 -5
- package/docs/pages/components/button-group.md +235 -27
- package/docs/pages/components/button.md +139 -1
- package/docs/pages/components/chart.md +365 -9
- package/docs/pages/components/checkbox.md +387 -58
- package/docs/pages/components/chip.md +253 -33
- package/docs/pages/components/collapsible.md +393 -46
- package/docs/pages/components/cols.md +152 -30
- package/docs/pages/components/confirm.md +182 -16
- package/docs/pages/components/copy-button.md +169 -6
- package/docs/pages/components/data-select.md +194 -15
- package/docs/pages/components/data-table-filter.md +96 -5
- package/docs/pages/components/data-table-search.md +451 -0
- package/docs/pages/components/data-table-sort.md +66 -5
- package/docs/pages/components/data-table.md +727 -66
- package/docs/pages/components/datepicker.md +402 -7
- package/docs/pages/components/defined-label.md +120 -5
- package/docs/pages/components/dialog.md +339 -59
- package/docs/pages/components/dropdown.md +366 -11
- package/docs/pages/components/editor.md +604 -7
- package/docs/pages/components/empty-state.md +315 -16
- package/docs/pages/components/expanding-action.md +212 -28
- package/docs/pages/components/file.md +421 -12
- package/docs/pages/components/filter-container.md +158 -5
- package/docs/pages/components/filter-wrapper.md +167 -6
- package/docs/pages/components/form-group.md +383 -6
- package/docs/pages/components/hover-container.md +237 -6
- package/docs/pages/components/icon-picker.md +121 -0
- package/docs/pages/components/icon.md +454 -48
- package/docs/pages/components/inline-edit.md +787 -19
- package/docs/pages/components/input-group.md +207 -13
- package/docs/pages/components/input.md +194 -0
- package/docs/pages/components/item.md +18 -0
- package/docs/pages/components/key-container.md +115 -0
- package/docs/pages/components/key.md +101 -0
- package/docs/pages/components/menu.md +512 -6
- package/docs/pages/components/note.md +239 -36
- package/docs/pages/components/opt-group.md +107 -0
- package/docs/pages/components/pagination.md +332 -6
- package/docs/pages/components/pane.md +222 -6
- package/docs/pages/components/panel.md +213 -26
- package/docs/pages/components/popup.md +1354 -6
- package/docs/pages/components/priority-list.md +233 -0
- package/docs/pages/components/progress-bar.md +387 -6
- package/docs/pages/components/radio-group.md +242 -5
- package/docs/pages/components/radio.md +474 -6
- package/docs/pages/components/rating.md +331 -7
- package/docs/pages/components/reveal.md +524 -6
- package/docs/pages/components/scroll-container.md +552 -6
- package/docs/pages/components/select.md +762 -160
- package/docs/pages/components/skeleton.md +473 -30
- package/docs/pages/components/slideout.md +261 -5
- package/docs/pages/components/sp.md +99 -41
- package/docs/pages/components/split-button.md +347 -9
- package/docs/pages/components/split-pane.md +445 -6
- package/docs/pages/components/stat.md +549 -9
- package/docs/pages/components/status-indicator.md +230 -1
- package/docs/pages/components/stepper.md +563 -6
- package/docs/pages/components/tabs.md +439 -13
- package/docs/pages/components/textarea.md +415 -17
- package/docs/pages/components/tile.md +385 -26
- package/docs/pages/components/toggle.md +424 -6
- package/docs/pages/components/tooltip.md +367 -0
- package/docs/pages/components/translation-group.md +210 -0
- package/docs/pages/components/translations.md +319 -19
- package/docs/pages/components/vertical-stepper.md +401 -8
- package/docs/pages/components/well.md +300 -3
- package/docs/pages/getting-started/form-controls.md +162 -0
- package/docs/pages/index.md +116 -15
- package/package.json +5 -6
- package/scss/_global-spacing.scss +4 -0
- package/scss/_root.scss +2 -2
- package/scss/boot.scss +19 -0
- package/scss/shared/layout.scss +5 -0
- package/scss/themes/_light.scss +3 -3
- package/src/components/alert/alert.scss +1 -0
- package/src/components/animated-button/README.md +306 -0
- package/src/components/animated-button/animated-button.component.ts +229 -0
- package/src/components/animated-button/animated-button.scss +228 -0
- package/src/components/animated-button/animated-button.test.ts +143 -0
- package/src/components/animated-button/index.ts +12 -0
- package/src/components/button/button.component.ts +5 -0
- package/src/components/button-group/button-group.component.ts +25 -13
- package/src/components/button-group/button-group.scss +6 -0
- package/src/components/checkbox/checkbox.component.ts +4 -0
- package/src/components/checkbox/checkbox.scss +7 -4
- package/src/components/checkbox-group/checkbox-group.scss +7 -0
- package/src/components/chip/chip.component.ts +7 -2
- package/src/components/chip/chip.scss +16 -2
- package/src/components/collapsible/collapsible.component.ts +27 -20
- package/src/components/cols/cols.component.ts +14 -2
- package/src/components/cols/cols.scss +6 -12
- package/src/components/confirm/confirm.component.ts +7 -0
- package/src/components/copy-button/copy-button.component.ts +12 -11
- package/src/components/data-select/data-select.component.ts +215 -44
- package/src/components/data-select/data-select.scss +66 -6
- package/src/components/data-select/providers/currency-data-provider.ts +20 -6
- package/src/components/data-select/providers/provider.ts +1 -0
- package/src/components/data-select/providers/us-state-data-provider.ts +68 -0
- package/src/components/data-table/data-table.component.ts +81 -22
- package/src/components/data-table-search/data-table-search.component.ts +184 -0
- package/src/components/data-table-search/data-table-search.scss +17 -0
- package/src/components/data-table-search/data-table-search.test.ts +11 -0
- package/src/components/data-table-search/index.ts +12 -0
- package/src/components/datepicker/datepicker.component.ts +347 -13
- package/src/components/dialog/dialog.component.ts +1 -1
- package/src/components/empty-state/empty-state.scss +6 -1
- package/src/components/header/header.scss +3 -3
- package/src/components/icon/icon.component.ts +23 -1
- package/src/components/icon/icon.scss +23 -0
- package/src/components/icon-picker/brand-icons.ts +24 -0
- package/src/components/icon-picker/icon-picker.component.ts +407 -0
- package/src/components/icon-picker/icon-picker.scss +205 -0
- package/src/components/icon-picker/index.ts +12 -0
- package/src/components/icon-picker/line-icons.ts +612 -0
- package/src/components/icon-picker/material-icons.ts +14543 -0
- package/src/components/inline-edit/inline-edit.component.ts +190 -46
- package/src/components/inline-edit/inline-edit.scss +29 -0
- package/src/components/inline-edit/inline-edit.test.ts +314 -1
- package/src/components/input/input.component.ts +324 -5
- package/src/components/input/input.scss +87 -0
- package/src/components/input-group/input-group.component.ts +28 -7
- package/src/components/input-group/input-group.scss +48 -10
- package/src/components/item/item.component.ts +24 -3
- package/src/components/item/item.scss +18 -0
- package/src/components/key/index.ts +12 -0
- package/src/components/key/key.component.ts +47 -0
- package/src/components/key/key.scss +38 -0
- package/src/components/key-container/index.ts +12 -0
- package/src/components/key-container/key-container.component.ts +142 -0
- package/src/components/key-container/key-container.scss +33 -0
- package/src/components/menu-item/menu-item.component.ts +20 -0
- package/src/components/menu-item/menu-item.scss +69 -2
- package/src/components/navbar/navbar.component.ts +103 -11
- package/src/components/navbar/navbar.scss +6 -1
- package/src/components/opt-group/index.ts +12 -0
- package/src/components/opt-group/opt-group.component.ts +74 -0
- package/src/components/opt-group/opt-group.scss +37 -0
- package/src/components/opt-group/opt-group.test.ts +27 -0
- package/src/components/option/option.component.ts +1 -16
- package/src/components/option/option.scss +4 -0
- package/src/components/panel/panel.component.ts +10 -8
- package/src/components/panel/panel.scss +20 -0
- package/src/components/priority-list/index.ts +12 -0
- package/src/components/priority-list/priority-list.component.ts +611 -0
- package/src/components/priority-list/priority-list.scss +185 -0
- package/src/components/priority-list/priority-list.test.ts +139 -0
- package/src/components/progress-bar/progress-bar.component.ts +22 -16
- package/src/components/radio/radio.scss +10 -3
- package/src/components/select/select.component.ts +812 -72
- package/src/components/select/select.scss +108 -2
- package/src/components/select/select.test.ts +147 -2
- package/src/components/settings-container/settings-container.component.ts +44 -19
- package/src/components/settings-container/settings-container.scss +1 -1
- package/src/components/skeleton/skeleton.component.ts +6 -1
- package/src/components/slideout/slideout.scss +8 -3
- package/src/components/sp/sp.component.ts +3 -1
- package/src/components/sp/sp.scss +19 -0
- package/src/components/stepper/stepper.component.ts +16 -10
- package/src/components/textarea/textarea.scss +0 -4
- package/src/components/tile/tile.component.ts +12 -3
- package/src/components/tile/tile.scss +1 -1
- package/src/components/timer/timer.component.ts +15 -2
- package/src/components/toggle/toggle.component.ts +29 -26
- package/src/components/toggle/toggle.scss +13 -1
- package/src/components/translation-group/index.ts +12 -0
- package/src/components/translation-group/translation-group.component.ts +207 -0
- package/src/components/translation-group/translation-group.scss +8 -0
- package/src/components/translations/translations.component.ts +90 -44
- package/src/components/translations/translations.scss +4 -0
- package/src/components/vertical-stepper/vertical-stepper.component.ts +14 -9
- package/src/events/events.ts +12 -7
- package/src/events/zn-language-change.ts +7 -0
- package/src/events/zn-purchase.ts +11 -0
- package/src/events/zn-redirect.ts +7 -0
- package/src/events/zn-reorder.ts +7 -0
- package/src/events/zn-search-change.ts +11 -0
- package/src/events/zn-submit.ts +1 -1
- package/src/form-control.scss +4 -0
- package/src/internal/form-navigation.ts +510 -0
- package/src/internal/form.ts +6 -0
- package/src/zinc.ts +91 -83
|
@@ -1,24 +1,621 @@
|
|
|
1
1
|
---
|
|
2
2
|
meta:
|
|
3
3
|
title: Editor
|
|
4
|
-
description:
|
|
4
|
+
description: A rich text editor component powered by Quill for composing formatted content with support for text formatting, lists, images, attachments, emojis, dates, and more.
|
|
5
5
|
layout: component
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
The Editor is a powerful rich text editing component built on top of Quill. It provides a customizable toolbar with formatting options, supports file attachments and uploads, includes emoji and date pickers, and offers AI-assisted writing capabilities.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
```html:preview
|
|
11
|
+
<zn-editor
|
|
12
|
+
name="content"
|
|
13
|
+
value=""
|
|
14
|
+
code-blocks
|
|
15
|
+
dividers
|
|
16
|
+
links
|
|
17
|
+
images
|
|
18
|
+
emojis
|
|
19
|
+
style="height: 400px">
|
|
11
20
|
</zn-editor>
|
|
12
21
|
```
|
|
13
22
|
|
|
23
|
+
:::tip
|
|
24
|
+
This component works with standard `<form>` elements. Please refer to the section on [form controls](/getting-started/form-controls) to learn more about form submission and client-side validation.
|
|
25
|
+
:::
|
|
26
|
+
|
|
14
27
|
## Examples
|
|
15
28
|
|
|
16
|
-
###
|
|
29
|
+
### Basic Editor
|
|
30
|
+
|
|
31
|
+
A basic editor with default formatting options (headings, bold, italic, underline, colors, lists, etc.).
|
|
32
|
+
|
|
33
|
+
```html:preview
|
|
34
|
+
<zn-editor
|
|
35
|
+
name="description"
|
|
36
|
+
style="height: 300px">
|
|
37
|
+
</zn-editor>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Editor with Initial Value
|
|
41
|
+
|
|
42
|
+
Set initial HTML content using the `value` attribute.
|
|
43
|
+
|
|
44
|
+
```html:preview
|
|
45
|
+
<zn-editor
|
|
46
|
+
name="content"
|
|
47
|
+
value="<h2>Welcome</h2><p>This editor has <strong>initial content</strong> with formatting.</p>"
|
|
48
|
+
style="height: 300px">
|
|
49
|
+
</zn-editor>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Interaction Types
|
|
53
|
+
|
|
54
|
+
The editor supports two interaction types: `chat` and `ticket`. In chat mode, pressing Enter submits the form if there is content. In ticket mode (default), Enter creates a new line.
|
|
55
|
+
|
|
56
|
+
#### Chat Mode
|
|
57
|
+
|
|
58
|
+
In chat mode, pressing Enter will submit the form automatically if the editor has content.
|
|
59
|
+
|
|
60
|
+
```html:preview
|
|
61
|
+
<form class="chat-form">
|
|
62
|
+
<zn-editor
|
|
63
|
+
name="message"
|
|
64
|
+
interaction-type="chat"
|
|
65
|
+
style="height: 200px">
|
|
66
|
+
</zn-editor>
|
|
67
|
+
<div style="margin-top: 1rem; padding: 1rem; background: var(--zn-color-neutral-100); border-radius: 4px; font-size: 0.875rem;">
|
|
68
|
+
<strong>Messages:</strong>
|
|
69
|
+
<div id="chat-messages"></div>
|
|
70
|
+
</div>
|
|
71
|
+
</form>
|
|
72
|
+
|
|
73
|
+
<script type="module">
|
|
74
|
+
const form = document.querySelector('.chat-form');
|
|
75
|
+
const messagesDiv = document.getElementById('chat-messages');
|
|
76
|
+
|
|
77
|
+
await customElements.whenDefined('zn-editor');
|
|
78
|
+
|
|
79
|
+
form.addEventListener('submit', (e) => {
|
|
80
|
+
e.preventDefault();
|
|
81
|
+
const formData = new FormData(form);
|
|
82
|
+
const message = formData.get('message');
|
|
83
|
+
if (message) {
|
|
84
|
+
const time = new Date().toLocaleTimeString();
|
|
85
|
+
messagesDiv.innerHTML += `<div style="margin-top: 0.5rem;">[${time}] ${message}</div>`;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
</script>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### Ticket Mode
|
|
92
|
+
|
|
93
|
+
In ticket mode (default), Enter creates new lines. Forms must be submitted using a submit button.
|
|
94
|
+
|
|
95
|
+
```html:preview
|
|
96
|
+
<form class="ticket-form">
|
|
97
|
+
<zn-editor
|
|
98
|
+
name="ticket-content"
|
|
99
|
+
interaction-type="ticket"
|
|
100
|
+
style="height: 250px">
|
|
101
|
+
</zn-editor>
|
|
102
|
+
<br />
|
|
103
|
+
<zn-button type="submit" color="success">Submit Ticket</zn-button>
|
|
104
|
+
</form>
|
|
105
|
+
|
|
106
|
+
<script type="module">
|
|
107
|
+
const form = document.querySelector('.ticket-form');
|
|
108
|
+
|
|
109
|
+
await Promise.all([
|
|
110
|
+
customElements.whenDefined('zn-editor'),
|
|
111
|
+
customElements.whenDefined('zn-button')
|
|
112
|
+
]);
|
|
113
|
+
|
|
114
|
+
form.addEventListener('submit', (e) => {
|
|
115
|
+
e.preventDefault();
|
|
116
|
+
const formData = new FormData(form);
|
|
117
|
+
alert('Ticket submitted!\n\n' + formData.get('ticket-content'));
|
|
118
|
+
});
|
|
119
|
+
</script>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Enabling Features
|
|
123
|
+
|
|
124
|
+
The editor has many optional features that can be enabled with boolean attributes.
|
|
125
|
+
|
|
126
|
+
#### Code Blocks
|
|
127
|
+
|
|
128
|
+
Enable code block insertion with the `code-blocks` attribute.
|
|
129
|
+
|
|
130
|
+
```html:preview
|
|
131
|
+
<zn-editor
|
|
132
|
+
name="content"
|
|
133
|
+
code-blocks
|
|
134
|
+
style="height: 300px">
|
|
135
|
+
</zn-editor>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### Inline Code
|
|
139
|
+
|
|
140
|
+
Enable inline code formatting with the `code` attribute.
|
|
141
|
+
|
|
142
|
+
```html:preview
|
|
143
|
+
<zn-editor
|
|
144
|
+
name="content"
|
|
145
|
+
code
|
|
146
|
+
value="<p>Use inline code for commands like <code>npm install</code></p>"
|
|
147
|
+
style="height: 300px">
|
|
148
|
+
</zn-editor>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### Dividers
|
|
152
|
+
|
|
153
|
+
Enable horizontal rule insertion with the `dividers` attribute.
|
|
154
|
+
|
|
155
|
+
```html:preview
|
|
156
|
+
<zn-editor
|
|
157
|
+
name="content"
|
|
158
|
+
dividers
|
|
159
|
+
value="<p>Section 1</p><hr class='ql-hr'><p>Section 2</p>"
|
|
160
|
+
style="height: 300px">
|
|
161
|
+
</zn-editor>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### Links
|
|
165
|
+
|
|
166
|
+
Enable link insertion and editing with the `links` attribute.
|
|
167
|
+
|
|
168
|
+
```html:preview
|
|
169
|
+
<zn-editor
|
|
170
|
+
name="content"
|
|
171
|
+
links
|
|
172
|
+
value="<p>Visit <a href='https://zinc.style'>our website</a> for more info.</p>"
|
|
173
|
+
style="height: 300px">
|
|
174
|
+
</zn-editor>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### Images
|
|
178
|
+
|
|
179
|
+
Enable image insertion with the `images` attribute.
|
|
180
|
+
|
|
181
|
+
```html:preview
|
|
182
|
+
<zn-editor
|
|
183
|
+
name="content"
|
|
184
|
+
images
|
|
185
|
+
style="height: 300px">
|
|
186
|
+
</zn-editor>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### Videos
|
|
190
|
+
|
|
191
|
+
Enable video embedding with the `videos` attribute.
|
|
192
|
+
|
|
193
|
+
```html:preview
|
|
194
|
+
<zn-editor
|
|
195
|
+
name="content"
|
|
196
|
+
videos
|
|
197
|
+
style="height: 300px">
|
|
198
|
+
</zn-editor>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
#### Emojis
|
|
202
|
+
|
|
203
|
+
Enable emoji picker with the `emojis` attribute. Users can type `:` to trigger autocomplete or use the emoji picker from the toolbar.
|
|
204
|
+
|
|
205
|
+
```html:preview
|
|
206
|
+
<zn-editor
|
|
207
|
+
name="content"
|
|
208
|
+
emojis
|
|
209
|
+
value="<p>Express yourself! 😀 🎉 ❤️</p>"
|
|
210
|
+
style="height: 300px">
|
|
211
|
+
</zn-editor>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### Dates
|
|
215
|
+
|
|
216
|
+
Enable date picker with the `dates` attribute.
|
|
217
|
+
|
|
218
|
+
```html:preview
|
|
219
|
+
<zn-editor
|
|
220
|
+
name="content"
|
|
221
|
+
dates
|
|
222
|
+
style="height: 300px">
|
|
223
|
+
</zn-editor>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
#### All Features Combined
|
|
227
|
+
|
|
228
|
+
Enable all features together for a fully-featured editor.
|
|
229
|
+
|
|
230
|
+
```html:preview
|
|
231
|
+
<zn-editor
|
|
232
|
+
name="content"
|
|
233
|
+
code-blocks
|
|
234
|
+
code
|
|
235
|
+
dividers
|
|
236
|
+
links
|
|
237
|
+
images
|
|
238
|
+
videos
|
|
239
|
+
dates
|
|
240
|
+
emojis
|
|
241
|
+
style="height: 400px">
|
|
242
|
+
</zn-editor>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### File Attachments
|
|
246
|
+
|
|
247
|
+
Enable file attachments with the `attachments` attribute. You must also provide an `attachment-url` for uploading files.
|
|
248
|
+
|
|
249
|
+
```html:preview
|
|
250
|
+
<form class="attachment-form">
|
|
251
|
+
<zn-editor
|
|
252
|
+
name="message"
|
|
253
|
+
attachments
|
|
254
|
+
attachment-url="/api/upload"
|
|
255
|
+
style="height: 300px">
|
|
256
|
+
</zn-editor>
|
|
257
|
+
<input type="hidden" name="attachments" />
|
|
258
|
+
<br />
|
|
259
|
+
<zn-button type="submit" color="success">Submit</zn-button>
|
|
260
|
+
</form>
|
|
261
|
+
|
|
262
|
+
<script type="module">
|
|
263
|
+
const form = document.querySelector('.attachment-form');
|
|
264
|
+
|
|
265
|
+
await Promise.all([
|
|
266
|
+
customElements.whenDefined('zn-editor'),
|
|
267
|
+
customElements.whenDefined('zn-button')
|
|
268
|
+
]);
|
|
17
269
|
|
|
18
|
-
|
|
270
|
+
form.addEventListener('submit', (e) => {
|
|
271
|
+
e.preventDefault();
|
|
272
|
+
alert('Form submitted! In a real application, attachments would be uploaded to the server.');
|
|
273
|
+
});
|
|
274
|
+
</script>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
:::warning
|
|
278
|
+
**Note:** The attachment feature requires a server endpoint that accepts POST requests with file data and returns JSON with `uploadPath`, `uploadUrl`, and `originalFilename` properties.
|
|
279
|
+
:::
|
|
280
|
+
|
|
281
|
+
### Custom Toolbar Tools
|
|
282
|
+
|
|
283
|
+
Add custom tools to the editor toolbar using the `zn-editor-tool` component in the `tools` slot.
|
|
284
|
+
|
|
285
|
+
```html:preview
|
|
286
|
+
<zn-editor
|
|
287
|
+
name="content"
|
|
288
|
+
style="height: 300px">
|
|
289
|
+
<zn-editor-tool
|
|
290
|
+
slot="tools"
|
|
291
|
+
icon="lightbulb"
|
|
292
|
+
label="Insert Tip"
|
|
293
|
+
handler="dialog"
|
|
294
|
+
uri="/custom/tip"
|
|
295
|
+
key="tip">
|
|
296
|
+
</zn-editor-tool>
|
|
297
|
+
</zn-editor>
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Context Menu Quick Actions
|
|
301
|
+
|
|
302
|
+
Add custom quick actions to the context menu using the `zn-editor-quick-action` component in the `context-items` slot.
|
|
303
|
+
|
|
304
|
+
```html:preview
|
|
305
|
+
<zn-editor
|
|
306
|
+
name="content"
|
|
307
|
+
value="<p>Select this text to see custom quick actions in the context menu</p>"
|
|
308
|
+
style="height: 300px">
|
|
309
|
+
<zn-editor-quick-action
|
|
310
|
+
slot="context-items"
|
|
311
|
+
icon="translate"
|
|
312
|
+
label="Translate"
|
|
313
|
+
uri="/api/translate"
|
|
314
|
+
key="translate"
|
|
315
|
+
order="1">
|
|
316
|
+
</zn-editor-quick-action>
|
|
317
|
+
<zn-editor-quick-action
|
|
318
|
+
slot="context-items"
|
|
319
|
+
icon="auto_fix_high"
|
|
320
|
+
label="Improve"
|
|
321
|
+
uri="/api/improve"
|
|
322
|
+
key="improve"
|
|
323
|
+
order="2">
|
|
324
|
+
</zn-editor-quick-action>
|
|
325
|
+
</zn-editor>
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### AI-Assisted Editing
|
|
329
|
+
|
|
330
|
+
Enable AI features with the `ai` attribute and provide an `ai-path` for the AI service endpoint.
|
|
331
|
+
|
|
332
|
+
```html:preview
|
|
333
|
+
<zn-editor
|
|
334
|
+
name="content"
|
|
335
|
+
ai
|
|
336
|
+
ai-path="/api/ai"
|
|
337
|
+
style="height: 350px">
|
|
338
|
+
</zn-editor>
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
:::warning
|
|
342
|
+
**Note:** The AI feature requires a server endpoint that accepts POST requests and returns AI-generated content. The AI module is experimental.
|
|
343
|
+
:::
|
|
344
|
+
|
|
345
|
+
### Custom Actions Slot
|
|
346
|
+
|
|
347
|
+
Add custom action buttons below the editor using the `actions` slot.
|
|
348
|
+
|
|
349
|
+
```html:preview
|
|
350
|
+
<zn-editor
|
|
351
|
+
name="content"
|
|
352
|
+
style="height: 300px">
|
|
353
|
+
<div slot="actions" style="display: flex; gap: 0.5rem;">
|
|
354
|
+
<zn-button color="success" type="button" id="save-draft">Save Draft</zn-button>
|
|
355
|
+
<zn-button color="primary" type="submit">Publish</zn-button>
|
|
356
|
+
</div>
|
|
357
|
+
</zn-editor>
|
|
358
|
+
|
|
359
|
+
<script type="module">
|
|
360
|
+
await customElements.whenDefined('zn-button');
|
|
361
|
+
|
|
362
|
+
document.getElementById('save-draft').addEventListener('click', () => {
|
|
363
|
+
alert('Draft saved!');
|
|
364
|
+
});
|
|
365
|
+
</script>
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Programmatic Content Insertion
|
|
369
|
+
|
|
370
|
+
You can programmatically insert or replace content in the editor using special data attributes on clickable elements.
|
|
371
|
+
|
|
372
|
+
#### Insert Mode
|
|
373
|
+
|
|
374
|
+
Insert text at the current cursor position using `editor-mode="insert"`.
|
|
375
|
+
|
|
376
|
+
```html:preview
|
|
377
|
+
<div style="margin-bottom: 1rem;">
|
|
378
|
+
<zn-button
|
|
379
|
+
editor-id="demo-editor"
|
|
380
|
+
editor-mode="insert"
|
|
381
|
+
editor-content-id="insert-content">
|
|
382
|
+
Insert Template
|
|
383
|
+
</zn-button>
|
|
384
|
+
<input type="hidden" id="insert-content" value="[Inserted template text]">
|
|
385
|
+
</div>
|
|
386
|
+
|
|
387
|
+
<zn-editor
|
|
388
|
+
id="demo-editor"
|
|
389
|
+
name="content"
|
|
390
|
+
value="<p>Click the button to insert text at cursor position.</p>"
|
|
391
|
+
style="height: 250px">
|
|
392
|
+
</zn-editor>
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
#### Replace Mode
|
|
396
|
+
|
|
397
|
+
Replace selected text or entire content using `editor-mode="replace"`.
|
|
398
|
+
|
|
399
|
+
```html:preview
|
|
400
|
+
<div style="margin-bottom: 1rem;">
|
|
401
|
+
<zn-button
|
|
402
|
+
editor-id="replace-editor"
|
|
403
|
+
editor-mode="replace"
|
|
404
|
+
editor-content-id="replace-content">
|
|
405
|
+
Replace with Template
|
|
406
|
+
</zn-button>
|
|
407
|
+
<input type="hidden" id="replace-content" value="This is replacement text">
|
|
408
|
+
</div>
|
|
409
|
+
|
|
410
|
+
<zn-editor
|
|
411
|
+
id="replace-editor"
|
|
412
|
+
name="content"
|
|
413
|
+
value="<p>Select some text and click the button, or click with no selection to replace all.</p>"
|
|
414
|
+
style="height: 250px">
|
|
415
|
+
</zn-editor>
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### Events
|
|
419
|
+
|
|
420
|
+
Listen to editor events to respond to user interactions.
|
|
19
421
|
|
|
20
|
-
|
|
422
|
+
```html:preview
|
|
423
|
+
<zn-editor
|
|
424
|
+
id="event-demo"
|
|
425
|
+
name="content"
|
|
426
|
+
interaction-type="chat"
|
|
427
|
+
style="height: 200px">
|
|
428
|
+
</zn-editor>
|
|
429
|
+
|
|
430
|
+
<div id="event-log" style="margin-top: 1rem; padding: 1rem; background: var(--zn-color-neutral-100); border-radius: 4px; font-family: monospace; font-size: 0.875rem; max-height: 200px; overflow-y: auto;">
|
|
431
|
+
Events will appear here...
|
|
432
|
+
</div>
|
|
433
|
+
|
|
434
|
+
<script type="module">
|
|
435
|
+
const editor = document.getElementById('event-demo');
|
|
436
|
+
const eventLog = document.getElementById('event-log');
|
|
437
|
+
|
|
438
|
+
await customElements.whenDefined('zn-editor');
|
|
439
|
+
|
|
440
|
+
function logEvent(eventName, detail = '') {
|
|
441
|
+
const time = new Date().toLocaleTimeString();
|
|
442
|
+
const message = `[${time}] ${eventName}${detail ? ': ' + JSON.stringify(detail).substring(0, 50) : ''}`;
|
|
443
|
+
eventLog.innerHTML = message + '<br>' + eventLog.innerHTML;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
editor.addEventListener('zn-change', (e) => {
|
|
447
|
+
logEvent('zn-change', 'content updated');
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
editor.addEventListener('zn-submit', (e) => {
|
|
451
|
+
logEvent('zn-submit', {value: e.detail.value.substring(0, 30) + '...'});
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
editor.addEventListener('zn-element-added', (e) => {
|
|
455
|
+
logEvent('zn-element-added', 'editor initialized');
|
|
456
|
+
});
|
|
457
|
+
</script>
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### Form Validation
|
|
461
|
+
|
|
462
|
+
The editor integrates with HTML5 form validation.
|
|
463
|
+
|
|
464
|
+
```html:preview
|
|
465
|
+
<form class="editor-validation-form">
|
|
466
|
+
<zn-editor
|
|
467
|
+
id="validation-editor"
|
|
468
|
+
name="description"
|
|
469
|
+
style="height: 250px">
|
|
470
|
+
</zn-editor>
|
|
471
|
+
<br />
|
|
472
|
+
<zn-button type="submit" color="success">Submit</zn-button>
|
|
473
|
+
</form>
|
|
474
|
+
|
|
475
|
+
<script type="module">
|
|
476
|
+
const form = document.querySelector('.editor-validation-form');
|
|
477
|
+
const editor = document.getElementById('validation-editor');
|
|
478
|
+
|
|
479
|
+
await Promise.all([
|
|
480
|
+
customElements.whenDefined('zn-editor'),
|
|
481
|
+
customElements.whenDefined('zn-button')
|
|
482
|
+
]);
|
|
483
|
+
|
|
484
|
+
// Custom validation: require at least 10 characters
|
|
485
|
+
editor.addEventListener('zn-change', () => {
|
|
486
|
+
const text = editor.value.replace(/<[^>]*>/g, '').trim();
|
|
487
|
+
if (text.length < 10 && text.length > 0) {
|
|
488
|
+
editor.setCustomValidity('Content must be at least 10 characters long');
|
|
489
|
+
} else if (text.length === 0) {
|
|
490
|
+
editor.setCustomValidity('Content is required');
|
|
491
|
+
} else {
|
|
492
|
+
editor.setCustomValidity('');
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
form.addEventListener('submit', (e) => {
|
|
497
|
+
e.preventDefault();
|
|
498
|
+
if (form.checkValidity()) {
|
|
499
|
+
alert('Form submitted successfully!');
|
|
500
|
+
} else {
|
|
501
|
+
editor.reportValidity();
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
</script>
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Responsive Toolbar
|
|
508
|
+
|
|
509
|
+
The toolbar automatically adapts to available space, moving tools into an overflow menu on smaller screens.
|
|
510
|
+
|
|
511
|
+
```html:preview
|
|
512
|
+
<div style="resize: horizontal; overflow: auto; border: 2px dashed var(--zn-color-neutral-300); padding: 1rem; min-width: 300px; max-width: 100%;">
|
|
513
|
+
<p style="font-size: 0.875rem; color: var(--zn-color-neutral-600); margin-bottom: 0.5rem;">Resize this container to see the toolbar adapt</p>
|
|
514
|
+
<zn-editor
|
|
515
|
+
name="content"
|
|
516
|
+
code-blocks
|
|
517
|
+
dividers
|
|
518
|
+
links
|
|
519
|
+
images
|
|
520
|
+
emojis
|
|
521
|
+
dates
|
|
522
|
+
style="height: 300px">
|
|
523
|
+
</zn-editor>
|
|
524
|
+
</div>
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### Time Tracking Integration
|
|
528
|
+
|
|
529
|
+
The editor can integrate with hidden time tracking inputs in the form for tracking editing time.
|
|
530
|
+
|
|
531
|
+
```html:preview
|
|
532
|
+
<form class="time-tracking-form">
|
|
533
|
+
<input type="hidden" name="startTime" id="startTime" />
|
|
534
|
+
<input type="hidden" name="openTime" id="openTime" />
|
|
535
|
+
|
|
536
|
+
<zn-editor
|
|
537
|
+
name="content"
|
|
538
|
+
style="height: 250px">
|
|
539
|
+
</zn-editor>
|
|
540
|
+
<br />
|
|
541
|
+
<zn-button type="submit" color="success">Submit</zn-button>
|
|
542
|
+
|
|
543
|
+
<div style="margin-top: 1rem; font-size: 0.875rem; color: var(--zn-color-neutral-600);">
|
|
544
|
+
Time tracking is active. Check form data on submit.
|
|
545
|
+
</div>
|
|
546
|
+
</form>
|
|
547
|
+
|
|
548
|
+
<script type="module">
|
|
549
|
+
const form = document.querySelector('.time-tracking-form');
|
|
550
|
+
|
|
551
|
+
await Promise.all([
|
|
552
|
+
customElements.whenDefined('zn-editor'),
|
|
553
|
+
customElements.whenDefined('zn-button')
|
|
554
|
+
]);
|
|
555
|
+
|
|
556
|
+
form.addEventListener('submit', (e) => {
|
|
557
|
+
e.preventDefault();
|
|
558
|
+
const formData = new FormData(form);
|
|
559
|
+
const data = Object.fromEntries(formData);
|
|
560
|
+
alert('Form with time tracking:\n\n' + JSON.stringify(data, null, 2));
|
|
561
|
+
});
|
|
562
|
+
</script>
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
### Advanced: Accessing Quill Instance
|
|
566
|
+
|
|
567
|
+
For advanced use cases, you can access the underlying Quill instance after the editor is initialized.
|
|
568
|
+
|
|
569
|
+
```html:preview
|
|
570
|
+
<zn-editor
|
|
571
|
+
id="quill-access"
|
|
572
|
+
name="content"
|
|
573
|
+
value="<p>This editor demonstrates direct Quill API access.</p>"
|
|
574
|
+
style="height: 250px">
|
|
575
|
+
</zn-editor>
|
|
576
|
+
|
|
577
|
+
<div style="margin-top: 1rem; display: flex; gap: 0.5rem;">
|
|
578
|
+
<zn-button id="get-length">Get Text Length</zn-button>
|
|
579
|
+
<zn-button id="insert-text">Insert Text</zn-button>
|
|
580
|
+
<zn-button id="format-bold">Toggle Bold</zn-button>
|
|
581
|
+
</div>
|
|
582
|
+
|
|
583
|
+
<script type="module">
|
|
584
|
+
const editor = document.getElementById('quill-access');
|
|
585
|
+
|
|
586
|
+
await Promise.all([
|
|
587
|
+
customElements.whenDefined('zn-editor'),
|
|
588
|
+
customElements.whenDefined('zn-button')
|
|
589
|
+
]);
|
|
590
|
+
|
|
591
|
+
// Wait for editor to be fully initialized
|
|
592
|
+
editor.addEventListener('zn-element-added', () => {
|
|
593
|
+
const quill = editor.quillElement;
|
|
594
|
+
|
|
595
|
+
document.getElementById('get-length').addEventListener('click', () => {
|
|
596
|
+
const length = quill.getLength();
|
|
597
|
+
alert(`Text length: ${length} characters`);
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
document.getElementById('insert-text').addEventListener('click', () => {
|
|
601
|
+
const range = quill.getSelection();
|
|
602
|
+
const index = range ? range.index : 0;
|
|
603
|
+
quill.insertText(index, ' [Inserted via API] ');
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
document.getElementById('format-bold').addEventListener('click', () => {
|
|
607
|
+
const range = quill.getSelection();
|
|
608
|
+
if (range) {
|
|
609
|
+
const format = quill.getFormat(range);
|
|
610
|
+
quill.format('bold', !format.bold);
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
</script>
|
|
615
|
+
```
|
|
21
616
|
|
|
22
|
-
|
|
617
|
+
:::warning
|
|
618
|
+
**Note:** Direct access to the Quill instance should be used with caution. Always prefer using the editor's public API when possible. The `quillElement` property is available but not officially documented and may change in future versions.
|
|
619
|
+
:::
|
|
23
620
|
|
|
24
621
|
|