@kubex/zinc 1.0.4 → 1.0.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/dist/custom-elements.json +1034 -111
- package/dist/vscode.html-custom-data.json +85 -15
- package/dist/web-types.json +215 -24
- package/dist/zn.d.ts +1234 -888
- package/dist/zn.min.css +1 -1
- package/dist/zn.min.js +1979 -940
- package/docs/_includes/default.njk +1 -0
- package/docs/assets/scripts/docs.js +4 -5
- package/docs/assets/scripts/search.js +0 -9
- package/docs/assets/styles/docs.css +3 -3
- package/docs/data/data-table.json +79 -0
- package/docs/data/products-table.json +36 -0
- package/docs/eleventy.config.cjs +3 -0
- package/docs/pages/components/data-select.md +10 -0
- package/docs/pages/components/data-table.md +84 -45
- package/docs/pages/components/dialog.md +1 -1
- package/docs/pages/components/editor.md +1 -3
- package/docs/pages/components/filter-wrapper.md +20 -0
- package/docs/pages/components/icon.md +2 -0
- package/docs/pages/components/item.md +2 -2
- package/docs/pages/components/menu-item.md +12 -3
- package/docs/pages/components/panel.md +17 -0
- package/docs/pages/components/progress-tile.md +17 -1
- package/docs/pages/components/settings-container.md +137 -0
- package/docs/pages/components/textarea.md +1 -1
- package/package.json +3 -1
- package/scss/_root.scss +26 -0
- package/scss/boot.scss +27 -1
- package/scss/mixins/index.scss +30 -1
- package/scss/shared/_base.scss +1 -1
- package/scss/shared/_button.scss +1 -1
- package/scss/shared/layout.scss +7 -0
- package/scss/themes/_dark.scss +5 -5
- package/scss/themes/_light.scss +6 -5
- package/scss/variables/index.scss +9 -0
- package/src/components/alert/alert.component.ts +1 -1
- package/src/components/alert/alert.scss +18 -4
- package/src/components/button/button.component.ts +6 -2
- package/src/components/button/button.scss +16 -1
- package/src/components/button-menu/button-menu.component.ts +23 -15
- package/src/components/button-menu/button-menu.scss +4 -4
- package/src/components/checkbox/checkbox.component.ts +5 -1
- package/src/components/checkbox/checkbox.scss +1 -1
- package/src/components/chip/chip.component.ts +7 -3
- package/src/components/chip/chip.scss +9 -1
- package/src/components/collapsible/collapsible.component.ts +48 -2
- package/src/components/confirm/confirm.component.ts +1 -2
- package/src/components/content-block/content-block.component.ts +25 -1
- package/src/components/content-block/content-block.scss +8 -0
- package/src/components/data-select/data-select.component.ts +1 -1
- package/src/components/data-table/data-table.component.ts +361 -422
- package/src/components/data-table/data-table.scss +6 -1
- package/src/components/datepicker/datepicker.scss +1 -1
- package/src/components/dialog/dialog.component.ts +52 -33
- package/src/components/dialog/dialog.scss +15 -1
- package/src/components/dropdown/dropdown.component.ts +1 -1
- package/src/components/editor/editor.component.ts +196 -158
- package/src/components/editor/editor.scss +25 -5
- package/src/components/editor/modules/ai/index.ts +281 -0
- package/src/components/editor/modules/ai/panel/ai-panel.component.ts +102 -0
- package/src/components/editor/modules/ai/panel/ai-panel.scss +83 -0
- package/src/components/editor/modules/ai/tooltip/ai-tooltip.component.ts +30 -0
- package/src/components/editor/modules/ai/tooltip/ai-tooltip.scss +28 -0
- package/src/components/editor/modules/{attachment-module.ts → attachment/attachment.ts} +7 -7
- package/src/components/editor/modules/context-menu/context-menu-component.ts +115 -0
- package/src/components/editor/modules/context-menu/context-menu.scss +49 -0
- package/src/components/editor/modules/context-menu/context-menu.ts +296 -0
- package/src/components/editor/modules/context-menu/quick-action/index.ts +12 -0
- package/src/components/editor/modules/context-menu/quick-action/quick-action.component.ts +18 -0
- package/src/components/editor/modules/date-picker/date-picker.ts +77 -0
- package/src/components/editor/modules/dialog/dialog.component.ts +115 -0
- package/src/components/editor/modules/dialog/dialog.scss +43 -0
- package/src/components/editor/modules/dialog/dialog.ts +46 -0
- package/src/components/editor/modules/{drag-drop-module.ts → drag-drop/drag-drop.ts} +6 -6
- package/src/components/editor/modules/emoji/emoji.ts +106 -0
- package/src/components/editor/modules/emoji/headless/headless-emoji.component.ts +122 -0
- package/src/components/editor/modules/emoji/headless/headless-emoji.scss +52 -0
- package/src/components/editor/modules/emoji/headless/headless-emoji.ts +223 -0
- package/src/components/editor/modules/{image-resize-module/image-resize-module.ts → image-resize/image-resize.ts} +5 -5
- package/src/components/editor/modules/{time-tracking-module.ts → time-tracking/time-tracking.ts} +5 -5
- package/src/components/editor/modules/toolbar/tool/index.ts +12 -0
- package/src/components/editor/modules/toolbar/tool/tool.component.ts +30 -0
- package/src/components/editor/modules/toolbar/tool/tool.scss +5 -0
- package/src/components/editor/modules/toolbar/toolbar.component.ts +738 -0
- package/src/components/editor/modules/toolbar/toolbar.scss +98 -0
- package/src/components/editor/modules/toolbar/toolbar.ts +328 -0
- package/src/components/expanding-action/expanding-action.component.ts +2 -2
- package/src/components/expanding-action/expanding-action.scss +2 -2
- package/src/components/filter-wrapper/filter-wrapper.component.ts +91 -0
- package/src/components/filter-wrapper/filter-wrapper.scss +11 -0
- package/src/components/filter-wrapper/filter-wrapper.test.ts +10 -0
- package/src/components/filter-wrapper/index.ts +12 -0
- package/src/components/header/header.component.ts +1 -1
- package/src/components/header/header.scss +8 -1
- package/src/components/hover-container/hover-container.scss +39 -36
- package/src/components/icon/icon.component.ts +11 -5
- package/src/components/icon/icon.scss +15 -2
- package/src/components/inline-edit/inline-edit.component.ts +28 -3
- package/src/components/inline-edit/inline-edit.scss +4 -1
- package/src/components/input/input.scss +1 -1
- package/src/components/item/item.component.ts +30 -19
- package/src/components/item/item.scss +56 -14
- package/src/components/linked-select/linked-select.component.ts +5 -1
- package/src/components/menu/menu.component.ts +1 -0
- package/src/components/menu/menu.scss +1 -1
- package/src/components/menu-item/menu-item.component.ts +22 -4
- package/src/components/menu-item/menu-item.scss +54 -7
- package/src/components/navbar/navbar.component.ts +7 -1
- package/src/components/navbar/navbar.scss +26 -16
- package/src/components/option/option.component.ts +4 -1
- package/src/components/option/option.scss +9 -0
- package/src/components/page-nav/page-nav.component.ts +2 -2
- package/src/components/page-nav/page-nav.scss +4 -4
- package/src/components/panel/panel.component.ts +20 -9
- package/src/components/panel/panel.scss +5 -1
- package/src/components/popup/popup.component.ts +16 -2
- package/src/components/progress-tile/progress-tile.component.ts +10 -4
- package/src/components/progress-tile/progress-tile.scss +7 -4
- package/src/components/query-builder/query-builder.component.ts +1 -1
- package/src/components/radio/radio.scss +1 -1
- package/src/components/scroll-container/scroll-container.component.ts +56 -9
- package/src/components/scroll-container/scroll-container.scss +37 -2
- package/src/components/select/select.component.ts +3 -0
- package/src/components/select/select.scss +1 -1
- package/src/components/settings-container/index.ts +12 -0
- package/src/components/settings-container/settings-container.component.ts +226 -0
- package/src/components/settings-container/settings-container.scss +92 -0
- package/src/components/settings-container/settings-container.test.ts +10 -0
- package/src/components/skeleton/skeleton.scss +5 -4
- package/src/components/sp/sp.component.ts +2 -0
- package/src/components/sp/sp.scss +2 -0
- package/src/components/split-button/split-button.component.ts +24 -18
- package/src/components/split-pane/split-pane.component.ts +5 -5
- package/src/components/stat/stat.component.ts +5 -1
- package/src/components/stat/stat.scss +24 -1
- package/src/components/style/style.component.ts +18 -0
- package/src/components/tabs/tabs.component.ts +12 -1
- package/src/components/textarea/textarea.component.ts +3 -1
- package/src/components/textarea/textarea.scss +21 -2
- package/src/components/vertical-stepper/vertical-stepper.scss +1 -1
- package/src/internal/form.ts +3 -1
- package/src/internal/slot.ts +29 -3
- package/src/utilities/on.ts +7 -8
- package/src/utilities/query.ts +5 -1
- package/src/wc.scss +7 -0
- package/src/zinc.ts +5 -0
- package/src/components/editor/modules/dialog-module/dialog-module.component.ts +0 -289
- package/src/components/editor/modules/dialog-module/dialog-module.scss +0 -115
- package/src/components/editor/modules/dialog-module/dialog-module.ts +0 -99
- package/src/components/editor/modules/events/zn-show-canned-response-dialog.ts +0 -15
- package/src/components/editor/modules/menu-module/menu-module.component.ts +0 -149
- package/src/components/editor/modules/menu-module/menu-module.scss +0 -17
- package/src/components/editor/modules/menu-module/menu-module.ts +0 -203
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import './dialog-module.component';
|
|
2
|
-
import {Delta} from 'quill';
|
|
3
|
-
import {html} from "lit";
|
|
4
|
-
import {litToHTML} from "../../../../utilities/lit-to-html";
|
|
5
|
-
import type {CannedResponse} from "../../editor.component";
|
|
6
|
-
import type {ZnCommandSelectEvent} from "../events/zn-command-select";
|
|
7
|
-
import type Quill from 'quill';
|
|
8
|
-
import type ZnDialogModule from './dialog-module.component';
|
|
9
|
-
|
|
10
|
-
class DialogModule {
|
|
11
|
-
private _quill: Quill;
|
|
12
|
-
private _dialog: ZnDialogModule;
|
|
13
|
-
private _commands: CannedResponse[] = [];
|
|
14
|
-
|
|
15
|
-
constructor(quill: Quill) {
|
|
16
|
-
this._quill = quill;
|
|
17
|
-
this.initDialog();
|
|
18
|
-
|
|
19
|
-
document.addEventListener('zn-show-canned-response-dialog', () => {
|
|
20
|
-
this._open();
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public setCommands(commands: CannedResponse[]) {
|
|
25
|
-
this._commands = commands;
|
|
26
|
-
this.addCommands();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
private _open() {
|
|
30
|
-
this._dialog.dialogEl.showModal();
|
|
31
|
-
this.attachEvents();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
private _close() {
|
|
35
|
-
this._dialog.dialogEl.close();
|
|
36
|
-
this.detachEvents();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
private initDialog() {
|
|
40
|
-
this._dialog = this.createDialog()!;
|
|
41
|
-
this._quill.container.ownerDocument.body.appendChild(this._dialog);
|
|
42
|
-
this.addCommands();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
private attachEvents() {
|
|
46
|
-
document.addEventListener('zn-command-select', this.onCommandSelect);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
private detachEvents() {
|
|
50
|
-
document.removeEventListener('zn-command-select', this.onCommandSelect);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
private onCommandSelect = (e: ZnCommandSelectEvent) => {
|
|
54
|
-
const item = e.detail.item;
|
|
55
|
-
const command = item.getAttribute('data-command');
|
|
56
|
-
if (command) {
|
|
57
|
-
this.triggerCommand(this._commands.find((c) => c.title === command)!);
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
private createDialog() {
|
|
62
|
-
const dialog = html`
|
|
63
|
-
<zn-dialog-module anchor=${this._quill.container}></zn-dialog-module>`
|
|
64
|
-
|
|
65
|
-
return litToHTML<ZnDialogModule>(dialog);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
private addCommands() {
|
|
69
|
-
this._dialog.setAttribute('commands', JSON.stringify(this._commands));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
private triggerCommand(command: CannedResponse) {
|
|
73
|
-
this._close();
|
|
74
|
-
this._quill.focus();
|
|
75
|
-
|
|
76
|
-
const range = this._quill.getSelection();
|
|
77
|
-
if (range) {
|
|
78
|
-
let insertIndex = range.index - 1;
|
|
79
|
-
this._quill.deleteText(insertIndex, 1, 'user');
|
|
80
|
-
|
|
81
|
-
const prevChar = this._quill.getText(insertIndex - 1, 1);
|
|
82
|
-
if (prevChar !== ' ' && insertIndex > 0) {
|
|
83
|
-
this._quill.insertText(insertIndex, ' ', 'user');
|
|
84
|
-
insertIndex += 1;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const contentDelta = this._quill.clipboard.convert({html: command?.content});
|
|
88
|
-
this._quill.updateContents(
|
|
89
|
-
new Delta().retain(insertIndex).concat(contentDelta),
|
|
90
|
-
'user'
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
setTimeout(() => this._quill.setSelection(insertIndex + contentDelta.length(), 0, 'silent'), 0);
|
|
94
|
-
this._quill.focus();
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export default DialogModule;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export type ZnShowCannedResponseDialogEvent = CustomEvent<{
|
|
2
|
-
commands: {
|
|
3
|
-
title: string;
|
|
4
|
-
content: string;
|
|
5
|
-
command: string;
|
|
6
|
-
count: string;
|
|
7
|
-
labels?: string[];
|
|
8
|
-
}[];
|
|
9
|
-
}>;
|
|
10
|
-
|
|
11
|
-
declare global {
|
|
12
|
-
interface GlobalEventHandlersEventMap {
|
|
13
|
-
'zn-show-canned-response-dialog': ZnShowCannedResponseDialogEvent;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import {classMap} from "lit/directives/class-map.js";
|
|
2
|
-
import {type CSSResultGroup, html, type TemplateResult, unsafeCSS} from "lit";
|
|
3
|
-
import {property, query, state} from "lit/decorators.js";
|
|
4
|
-
import {watch} from "../../../../internal/watch";
|
|
5
|
-
import ZincElement from "../../../../internal/zinc-element";
|
|
6
|
-
import type {CannedResponse} from "../../editor.component";
|
|
7
|
-
import type ZnMenu from "../../../menu";
|
|
8
|
-
|
|
9
|
-
import styles from './menu-module.scss';
|
|
10
|
-
|
|
11
|
-
export default class MenuModuleComponent extends ZincElement {
|
|
12
|
-
static styles: CSSResultGroup = unsafeCSS(styles);
|
|
13
|
-
|
|
14
|
-
@state() private hasFocus = false;
|
|
15
|
-
|
|
16
|
-
@query('zn-menu') menuEl!: ZnMenu;
|
|
17
|
-
|
|
18
|
-
@query('.menu-module__content') commandList!: HTMLElement;
|
|
19
|
-
|
|
20
|
-
@query('.menu-module') menuModule!: HTMLElement;
|
|
21
|
-
|
|
22
|
-
@property({type: Array}) commands: CannedResponse[] = [];
|
|
23
|
-
@property({type: Boolean, reflect: true}) open = false;
|
|
24
|
-
|
|
25
|
-
private closeWatcher: CloseWatcher | null;
|
|
26
|
-
|
|
27
|
-
connectedCallback() {
|
|
28
|
-
super.connectedCallback();
|
|
29
|
-
this.addEventListener('zn-menu-ready', this.focus);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
disconnectedCallback() {
|
|
33
|
-
super.disconnectedCallback();
|
|
34
|
-
this.removeEventListener('zn-menu-ready', this.focus);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
focus() {
|
|
38
|
-
// Focus the first menu item if available, otherwise fallback to menuEl
|
|
39
|
-
const firstItem = this.menuEl?.getAllItems?.()[0];
|
|
40
|
-
if (firstItem) {
|
|
41
|
-
firstItem.focus();
|
|
42
|
-
} else {
|
|
43
|
-
this.menuEl?.focus();
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
show() {
|
|
48
|
-
this.open = true;
|
|
49
|
-
this.emit('zn-show');
|
|
50
|
-
this.focus();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
hide() {
|
|
54
|
-
this.open = false;
|
|
55
|
-
this.emit('zn-close');
|
|
56
|
-
this.blur();
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@watch('open', {waitUntilFirstUpdate: true})
|
|
60
|
-
handleOpenChange() {
|
|
61
|
-
if (this.open) {
|
|
62
|
-
this.addOpenListeners();
|
|
63
|
-
this.menuEl.style.display = 'block';
|
|
64
|
-
setTimeout(() => this.focus(), 0);
|
|
65
|
-
} else {
|
|
66
|
-
this.menuEl.style.display = 'none';
|
|
67
|
-
this.removeOpenListeners();
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
private addOpenListeners() {
|
|
72
|
-
if ('CloseWatcher' in window) {
|
|
73
|
-
this.closeWatcher?.destroy();
|
|
74
|
-
this.closeWatcher = new CloseWatcher();
|
|
75
|
-
this.closeWatcher.onclose = () => this.requestClose('keyboard');
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
private removeOpenListeners() {
|
|
80
|
-
this.closeWatcher?.destroy();
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
private requestClose(source: 'close-button' | 'keyboard' | 'overlay') {
|
|
84
|
-
const znRequestClose = this.emit('zn-request-close', {
|
|
85
|
-
cancelable: true,
|
|
86
|
-
detail: {source}
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
if (znRequestClose.defaultPrevented) {
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
this.hide();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
private showDialog = () => {
|
|
97
|
-
this.hide();
|
|
98
|
-
this.emit('zn-show-canned-response-dialog', {detail: {commands: this.commands}});
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
private handleClick = (event: MouseEvent) => {
|
|
102
|
-
const target = event.target as HTMLElement | null;
|
|
103
|
-
|
|
104
|
-
if (!target) return;
|
|
105
|
-
|
|
106
|
-
const item = target.hasAttribute('data-command')
|
|
107
|
-
? target
|
|
108
|
-
: target.closest('[data-command]') as HTMLElement | null;
|
|
109
|
-
|
|
110
|
-
if (item) {
|
|
111
|
-
this.emit('zn-command-select', {detail: {item}});
|
|
112
|
-
this.emit('zn-editor-update');
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
private _createCommand(command: CannedResponse): TemplateResult {
|
|
117
|
-
return html`
|
|
118
|
-
<zn-menu-item data-command="${command.title}" @click="${this.handleClick}">
|
|
119
|
-
<div class="command__wrapper">
|
|
120
|
-
<div class="command__command">
|
|
121
|
-
${'/' + (command.command ? command.command :
|
|
122
|
-
command.title.toLowerCase().replace(' ', '-'))}
|
|
123
|
-
</div>
|
|
124
|
-
<div class="command__title">
|
|
125
|
-
${command.title}
|
|
126
|
-
</div>
|
|
127
|
-
</div>
|
|
128
|
-
</zn-menu-item>`
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
render() {
|
|
132
|
-
return html`
|
|
133
|
-
<zn-menu class="${classMap({
|
|
134
|
-
'menu-module': true,
|
|
135
|
-
'menu-module--has-focus': this.hasFocus,
|
|
136
|
-
'menu-module--has-results': this.commands.length > 0,
|
|
137
|
-
'menu-module--open': this.open,
|
|
138
|
-
})}">
|
|
139
|
-
${this.commands.sort((a, b) => parseInt(b.count) - parseInt(a.count))
|
|
140
|
-
.slice(0, 3)
|
|
141
|
-
.map(command => this._createCommand(command))}
|
|
142
|
-
<zn-menu-item @click="${this.showDialog}">View All</zn-menu-item>
|
|
143
|
-
</zn-menu>
|
|
144
|
-
`;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
MenuModuleComponent.define('zn-menu-module');
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
.menu-module {
|
|
2
|
-
display: none;
|
|
3
|
-
|
|
4
|
-
&--open {
|
|
5
|
-
display: block;
|
|
6
|
-
z-index: var(--zn-z-index-dialog);
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.command {
|
|
11
|
-
&__wrapper {
|
|
12
|
-
display: flex;
|
|
13
|
-
flex-direction: column;
|
|
14
|
-
align-items: start;
|
|
15
|
-
gap: var(--zn-spacing-2x-small);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import './menu-module.component';
|
|
2
|
-
import {html} from "lit";
|
|
3
|
-
import {litToHTML} from "../../../../utilities/lit-to-html";
|
|
4
|
-
import {type ZnCommandSelectEvent} from "../events/zn-command-select";
|
|
5
|
-
import Quill, {Delta} from 'quill';
|
|
6
|
-
import type {CannedResponse} from "../../editor.component";
|
|
7
|
-
import type ZnMenuModule from './menu-module.component';
|
|
8
|
-
|
|
9
|
-
interface MenuModuleOptions {
|
|
10
|
-
cannedResponses: CannedResponse[];
|
|
11
|
-
cannedResponsesUri: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export let menuOpen: boolean = false;
|
|
15
|
-
|
|
16
|
-
class MenuModule {
|
|
17
|
-
private _quill: Quill;
|
|
18
|
-
private _menu: ZnMenuModule;
|
|
19
|
-
private readonly _cannedResponsesUri: string = '';
|
|
20
|
-
private _commands: CannedResponse[] = [];
|
|
21
|
-
|
|
22
|
-
constructor(quill: Quill, options: MenuModuleOptions) {
|
|
23
|
-
this._quill = quill;
|
|
24
|
-
this._cannedResponsesUri = options.cannedResponsesUri?.trim() || '';
|
|
25
|
-
this._commands = options.cannedResponses || [];
|
|
26
|
-
|
|
27
|
-
if (this._commands.length > 0 || this._cannedResponsesUri) {
|
|
28
|
-
this.initMenu();
|
|
29
|
-
this.attachEvents();
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
private initMenu() {
|
|
34
|
-
this._menu = this.createMenu()!;
|
|
35
|
-
this._quill.container.ownerDocument.body.appendChild(this._menu);
|
|
36
|
-
this.updateMenuPosition();
|
|
37
|
-
this.addCommands();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
private attachEvents() {
|
|
41
|
-
this._quill.on(Quill.events.TEXT_CHANGE, this.onTextChange);
|
|
42
|
-
document.addEventListener('zn-command-select', this.onCommandSelect);
|
|
43
|
-
document.addEventListener('click', this.onDocumentClick);
|
|
44
|
-
this._menu.addEventListener('zn-show', () => setTimeout(() => this.updateMenuPosition(), 1));
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
private detachEvents() {
|
|
48
|
-
document.removeEventListener('zn-command-select', this.onCommandSelect);
|
|
49
|
-
document.removeEventListener('click', this.onDocumentClick);
|
|
50
|
-
this._menu.removeEventListener('zn-show', () => setTimeout(() => this.updateMenuPosition(), 1));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
private onTextChange = async (_: Delta, _oldDelta: Delta, source: string) => {
|
|
54
|
-
if (source === Quill.sources.USER) {
|
|
55
|
-
// if the user has typed a forward slash, we will show the menu until they type
|
|
56
|
-
// a space or a new line. The menu will contain a list of commands that the user
|
|
57
|
-
// can select from.
|
|
58
|
-
const text = this._quill.getText();
|
|
59
|
-
const index = this._quill.getSelection()?.index ?? 0;
|
|
60
|
-
const char = index === 0 ? text.charAt(0) : text.charAt(index - 1); // Last input char
|
|
61
|
-
const openCharacter = '/';
|
|
62
|
-
|
|
63
|
-
// If the openCharacter is the first character in the editor, and menu isn't open, open it.
|
|
64
|
-
if (index === 0 && char === openCharacter && !menuOpen) {
|
|
65
|
-
await this._openMenu();
|
|
66
|
-
} else if (char === openCharacter && text.charAt(index - 2) === ' ' && !menuOpen) {
|
|
67
|
-
await this._openMenu();
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// if the user has typed a space or a new line, we will close the menu if the menu
|
|
71
|
-
// is open
|
|
72
|
-
if (menuOpen && (char === ' ' || char === '\n')) {
|
|
73
|
-
this._closeMenu();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (menuOpen) {
|
|
77
|
-
this.updateMenuPosition();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// if the user clicks away from the menu, we will close the menu
|
|
81
|
-
document.addEventListener('click', (e) => {
|
|
82
|
-
if (menuOpen && e.target !== this._menu) {
|
|
83
|
-
this._closeMenu();
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
private onCommandSelect = (e: Event) => {
|
|
90
|
-
const event = e as ZnCommandSelectEvent;
|
|
91
|
-
const commandTitle = event.detail.item.getAttribute('data-command');
|
|
92
|
-
if (!commandTitle) return;
|
|
93
|
-
const command = this._commands.find(cmd => cmd.title === commandTitle);
|
|
94
|
-
if (command) {
|
|
95
|
-
this.triggerCommand(command);
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
private onDocumentClick = (e: MouseEvent) => {
|
|
100
|
-
if (menuOpen && e.target !== this._menu) {
|
|
101
|
-
this._closeMenu();
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
private updateMenuPosition(menu: ZnMenuModule = this._menu) {
|
|
106
|
-
const editorBounds = this._quill.container.getBoundingClientRect();
|
|
107
|
-
|
|
108
|
-
// Get the current cursor position
|
|
109
|
-
const range = this._quill.getSelection();
|
|
110
|
-
if (range) {
|
|
111
|
-
const cursorBounds = this._quill.getBounds(range.index);
|
|
112
|
-
|
|
113
|
-
if (cursorBounds) {
|
|
114
|
-
// Position the menu to the right of the cursor
|
|
115
|
-
const maxHeight = 275;
|
|
116
|
-
const top = editorBounds.top + cursorBounds.top;
|
|
117
|
-
const left = editorBounds.left + cursorBounds.right + 10; // Add offset to the right
|
|
118
|
-
const windowHeight = window.innerHeight;
|
|
119
|
-
const hasRoom = windowHeight - top > maxHeight; // Check if there's enough room for the menu
|
|
120
|
-
|
|
121
|
-
if (hasRoom) {
|
|
122
|
-
menu.style.top = `${top}px`;
|
|
123
|
-
} else {
|
|
124
|
-
menu.style.top = `${top - maxHeight}px`;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
menu.style.position = 'absolute';
|
|
128
|
-
menu.style.left = `${left}px`;
|
|
129
|
-
menu.style.maxHeight = `${maxHeight}px`;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
private async _openMenu() {
|
|
135
|
-
menuOpen = true;
|
|
136
|
-
this.attachEvents();
|
|
137
|
-
if (this._cannedResponsesUri) {
|
|
138
|
-
await this.fetchCannedResponses();
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (this._commands.length > 0) {
|
|
142
|
-
this._menu.show();
|
|
143
|
-
this._menu.focus();
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
private _closeMenu() {
|
|
148
|
-
menuOpen = false;
|
|
149
|
-
this.detachEvents();
|
|
150
|
-
this._menu.hide();
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
private createMenu() {
|
|
154
|
-
const menu = html`
|
|
155
|
-
<zn-menu-module anchor=${this._quill.container}></zn-menu-module>`
|
|
156
|
-
|
|
157
|
-
return litToHTML<ZnMenuModule>(menu);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
private addCommands() {
|
|
161
|
-
this._menu.setAttribute('commands', JSON.stringify(this._commands));
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
private triggerCommand(command: CannedResponse) {
|
|
165
|
-
this._closeMenu();
|
|
166
|
-
this._quill.focus();
|
|
167
|
-
|
|
168
|
-
const range = this._quill.getSelection();
|
|
169
|
-
if (range) {
|
|
170
|
-
let insertIndex = range.index - 1;
|
|
171
|
-
this._quill.deleteText(insertIndex, 1, 'user');
|
|
172
|
-
|
|
173
|
-
const prevChar = this._quill.getText(insertIndex - 1, 1);
|
|
174
|
-
if (prevChar !== ' ' && insertIndex > 0) {
|
|
175
|
-
this._quill.insertText(insertIndex, ' ', 'user');
|
|
176
|
-
insertIndex += 1;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const contentDelta = this._quill.clipboard.convert({html: command?.content});
|
|
180
|
-
this._quill.updateContents(
|
|
181
|
-
new Delta().retain(insertIndex).concat(contentDelta),
|
|
182
|
-
'user'
|
|
183
|
-
);
|
|
184
|
-
|
|
185
|
-
setTimeout(() => this._quill.setSelection(insertIndex + contentDelta.length(), 0, 'silent'), 0);
|
|
186
|
-
this._quill.focus();
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
private async fetchCannedResponses() {
|
|
191
|
-
try {
|
|
192
|
-
const response = await fetch(this._cannedResponsesUri);
|
|
193
|
-
this._commands = await response.json() as CannedResponse[];
|
|
194
|
-
if (this._menu) {
|
|
195
|
-
this.addCommands();
|
|
196
|
-
}
|
|
197
|
-
} catch (error) {
|
|
198
|
-
console.error('Error fetching canned responses', error);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export default MenuModule;
|