@jungherz-de/notionkit-elements 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +90 -0
- package/dist/components/nk-ai-input-row.js +57 -0
- package/dist/components/nk-ai-msg.js +67 -0
- package/dist/components/nk-ai-thread.js +14 -0
- package/dist/components/nk-app.js +23 -0
- package/dist/components/nk-avatar-group.js +35 -0
- package/dist/components/nk-banner.js +30 -0
- package/dist/components/nk-block-host.js +35 -0
- package/dist/components/nk-board-view.js +129 -0
- package/dist/components/nk-breadcrumb.js +78 -0
- package/dist/components/nk-btn.js +107 -0
- package/dist/components/nk-callout.js +36 -0
- package/dist/components/nk-check.js +77 -0
- package/dist/components/nk-cmdk.js +221 -0
- package/dist/components/nk-code.js +66 -0
- package/dist/components/nk-comment.js +41 -0
- package/dist/components/nk-comments.js +57 -0
- package/dist/components/nk-danger-zone.js +27 -0
- package/dist/components/nk-database.js +100 -0
- package/dist/components/nk-divider.js +12 -0
- package/dist/components/nk-emoji-picker.js +112 -0
- package/dist/components/nk-empty.js +36 -0
- package/dist/components/nk-field.js +50 -0
- package/dist/components/nk-filter-bar.js +78 -0
- package/dist/components/nk-heading.js +29 -0
- package/dist/components/nk-input.js +108 -0
- package/dist/components/nk-kbd.js +15 -0
- package/dist/components/nk-member-list.js +30 -0
- package/dist/components/nk-member-row.js +46 -0
- package/dist/components/nk-mention.js +31 -0
- package/dist/components/nk-menu-item.js +68 -0
- package/dist/components/nk-menu.js +45 -0
- package/dist/components/nk-modal.js +166 -0
- package/dist/components/nk-model-card.js +89 -0
- package/dist/components/nk-page-actions.js +15 -0
- package/dist/components/nk-page-cover.js +35 -0
- package/dist/components/nk-page-title.js +71 -0
- package/dist/components/nk-page.js +71 -0
- package/dist/components/nk-pop.js +90 -0
- package/dist/components/nk-profile-row.js +25 -0
- package/dist/components/nk-progress.js +43 -0
- package/dist/components/nk-quote.js +32 -0
- package/dist/components/nk-radio.js +160 -0
- package/dist/components/nk-section-label.js +42 -0
- package/dist/components/nk-segmented.js +99 -0
- package/dist/components/nk-select.js +127 -0
- package/dist/components/nk-settings-pane.js +40 -0
- package/dist/components/nk-settings-user.js +36 -0
- package/dist/components/nk-sidebar.js +81 -0
- package/dist/components/nk-skeleton.js +31 -0
- package/dist/components/nk-slider.js +85 -0
- package/dist/components/nk-stat.js +40 -0
- package/dist/components/nk-stats.js +14 -0
- package/dist/components/nk-switch.js +69 -0
- package/dist/components/nk-synced.js +26 -0
- package/dist/components/nk-tab.js +54 -0
- package/dist/components/nk-table-view.js +109 -0
- package/dist/components/nk-tabs.js +82 -0
- package/dist/components/nk-tag.js +32 -0
- package/dist/components/nk-template-btn.js +43 -0
- package/dist/components/nk-textarea.js +95 -0
- package/dist/components/nk-theme-toggle.js +67 -0
- package/dist/components/nk-toast.js +51 -0
- package/dist/components/nk-todo.js +73 -0
- package/dist/components/nk-toggle.js +56 -0
- package/dist/components/nk-topbar.js +24 -0
- package/dist/components/nk-tree-item.js +155 -0
- package/dist/components/nk-tree.js +123 -0
- package/dist/components/nk-workspace-switcher.js +82 -0
- package/dist/components/shared/base-6gEcoatG.js +317 -0
- package/dist/components/shared/focus-DXrK9oLe.js +47 -0
- package/dist/components/shared/property-cell-Dn91uFkf.js +92 -0
- package/dist/notionkit-elements.esm.js +4639 -0
- package/dist/notionkit-elements.js +4718 -0
- package/dist/notionkit-elements.min.js +1 -0
- package/package.json +72 -0
- package/src/base.js +296 -0
- package/src/components/content/nk-callout.js +35 -0
- package/src/components/content/nk-code.js +51 -0
- package/src/components/content/nk-divider.js +11 -0
- package/src/components/content/nk-heading.js +28 -0
- package/src/components/content/nk-kbd.js +14 -0
- package/src/components/content/nk-progress.js +42 -0
- package/src/components/content/nk-quote.js +31 -0
- package/src/components/content/nk-tag.js +31 -0
- package/src/components/content/nk-todo.js +72 -0
- package/src/components/content/nk-toggle.js +55 -0
- package/src/components/data/nk-ai-input-row.js +56 -0
- package/src/components/data/nk-ai-msg.js +66 -0
- package/src/components/data/nk-ai-thread.js +13 -0
- package/src/components/data/nk-board-view.js +128 -0
- package/src/components/data/nk-comment.js +40 -0
- package/src/components/data/nk-comments.js +56 -0
- package/src/components/data/nk-database.js +99 -0
- package/src/components/data/nk-filter-bar.js +77 -0
- package/src/components/data/nk-table-view.js +108 -0
- package/src/components/forms/nk-btn.js +106 -0
- package/src/components/forms/nk-check.js +76 -0
- package/src/components/forms/nk-field.js +49 -0
- package/src/components/forms/nk-input.js +107 -0
- package/src/components/forms/nk-radio.js +159 -0
- package/src/components/forms/nk-select.js +126 -0
- package/src/components/forms/nk-slider.js +84 -0
- package/src/components/forms/nk-switch.js +68 -0
- package/src/components/forms/nk-textarea.js +94 -0
- package/src/components/overlays/nk-cmdk.js +201 -0
- package/src/components/overlays/nk-emoji-picker.js +94 -0
- package/src/components/overlays/nk-menu-item.js +67 -0
- package/src/components/overlays/nk-menu.js +44 -0
- package/src/components/overlays/nk-modal.js +165 -0
- package/src/components/overlays/nk-pop.js +89 -0
- package/src/components/overlays/nk-settings-pane.js +39 -0
- package/src/components/overlays/nk-settings-user.js +35 -0
- package/src/components/overlays/nk-toast.js +50 -0
- package/src/components/page/nk-avatar-group.js +34 -0
- package/src/components/page/nk-banner.js +29 -0
- package/src/components/page/nk-block-host.js +34 -0
- package/src/components/page/nk-danger-zone.js +26 -0
- package/src/components/page/nk-empty.js +35 -0
- package/src/components/page/nk-member-list.js +29 -0
- package/src/components/page/nk-member-row.js +45 -0
- package/src/components/page/nk-mention.js +30 -0
- package/src/components/page/nk-model-card.js +88 -0
- package/src/components/page/nk-page-actions.js +14 -0
- package/src/components/page/nk-page-cover.js +34 -0
- package/src/components/page/nk-page-title.js +70 -0
- package/src/components/page/nk-page.js +70 -0
- package/src/components/page/nk-profile-row.js +24 -0
- package/src/components/page/nk-segmented.js +98 -0
- package/src/components/page/nk-skeleton.js +30 -0
- package/src/components/page/nk-stat.js +39 -0
- package/src/components/page/nk-stats.js +13 -0
- package/src/components/page/nk-synced.js +25 -0
- package/src/components/page/nk-tab.js +53 -0
- package/src/components/page/nk-tabs.js +81 -0
- package/src/components/page/nk-template-btn.js +42 -0
- package/src/components/shell/nk-app.js +22 -0
- package/src/components/shell/nk-breadcrumb.js +77 -0
- package/src/components/shell/nk-section-label.js +41 -0
- package/src/components/shell/nk-sidebar.js +80 -0
- package/src/components/shell/nk-theme-toggle.js +66 -0
- package/src/components/shell/nk-topbar.js +23 -0
- package/src/components/shell/nk-tree-item.js +154 -0
- package/src/components/shell/nk-tree.js +122 -0
- package/src/components/shell/nk-workspace-switcher.js +81 -0
- package/src/index.js +88 -0
- package/src/util/emoji.js +17 -0
- package/src/util/focus.js +45 -0
- package/src/util/fuzzy.js +19 -0
- package/src/util/highlight.js +14 -0
- package/src/util/property-cell.js +90 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { NkElement } from '../../base.js';
|
|
2
|
+
import { lockScroll, unlockScroll, inertOutside, firstFocusable } from '../../util/focus.js';
|
|
3
|
+
|
|
4
|
+
// <nk-modal id="settings">
|
|
5
|
+
// <nk-settings-user slot="user" name="…" mail="…"></nk-settings-user>
|
|
6
|
+
// <nk-settings-pane name="profile" group="Account" icon="👤" label="My profile" title="My profile" active>…</nk-settings-pane>
|
|
7
|
+
// <nk-settings-pane name="members" group="Workspace" icon="👥" label="Members" title="Members">…</nk-settings-pane>
|
|
8
|
+
// </nk-modal>
|
|
9
|
+
// → <div class="nk-modal-backdrop open"><div class="nk-modal" role="dialog">
|
|
10
|
+
// <nav class="nk-settings-nav">…user… section labels + tree rows…</nav>
|
|
11
|
+
// <div class="nk-settings-content">…panes…</div></div></div>
|
|
12
|
+
//
|
|
13
|
+
// The modal renders the nav rows itself from the panes' label/icon/group, so
|
|
14
|
+
// `.nk-settings-nav .nk-tree-item` and the 860px icon-rail rules match with
|
|
15
|
+
// no JS breakpoint. Escape and the backdrop close it; focus moves in and
|
|
16
|
+
// back out; the page behind is scroll-locked and inert. Put the element
|
|
17
|
+
// directly under <body>: a transformed ancestor would trap the fixed backdrop.
|
|
18
|
+
class NkModal extends NkElement {
|
|
19
|
+
static get observedAttributes() { return ['open', 'pane']; }
|
|
20
|
+
|
|
21
|
+
render() {
|
|
22
|
+
this._backdrop = this.createElement('div', ['nk-modal-backdrop']);
|
|
23
|
+
this._backdrop.inert = true;
|
|
24
|
+
this._box = this.createElement('div', ['nk-modal'], { role: 'dialog', 'aria-modal': 'true', tabindex: '-1' });
|
|
25
|
+
this._nav = this.createElement('nav', ['nk-settings-nav'], { 'aria-label': 'Settings' });
|
|
26
|
+
this._nav.appendChild(this.createElement('slot', [], { name: 'user' }));
|
|
27
|
+
this._rows = document.createElement('div');
|
|
28
|
+
this._nav.appendChild(this._rows);
|
|
29
|
+
this._nav.appendChild(this.createElement('slot', [], { name: 'nav' }));
|
|
30
|
+
this._content = this.createElement('div', ['nk-settings-content']);
|
|
31
|
+
this._slot = document.createElement('slot');
|
|
32
|
+
this._content.appendChild(this._slot);
|
|
33
|
+
this._box.append(this._nav, this._content);
|
|
34
|
+
this._backdrop.appendChild(this._box);
|
|
35
|
+
this._wrapper.appendChild(this._backdrop);
|
|
36
|
+
this._syncOpen();
|
|
37
|
+
this.requestNav();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get panes() { return [...this.querySelectorAll(':scope > nk-settings-pane')]; }
|
|
41
|
+
|
|
42
|
+
/** Rebuilds the nav from the panes (debounced – panes upgrade after the modal). */
|
|
43
|
+
requestNav() {
|
|
44
|
+
if (this._navQueued) return;
|
|
45
|
+
this._navQueued = true;
|
|
46
|
+
queueMicrotask(() => { this._navQueued = false; this._buildNav(); });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
_buildNav() {
|
|
50
|
+
if (!this._rows) return;
|
|
51
|
+
const panes = this.panes;
|
|
52
|
+
const labelled = panes.filter(p => p.getAttribute('label'));
|
|
53
|
+
this._rows.replaceChildren();
|
|
54
|
+
this._nav.style.display = (labelled.length || this.querySelector(':scope > [slot="nav"], :scope > [slot="user"]')) ? '' : 'none';
|
|
55
|
+
let lastGroup = null;
|
|
56
|
+
for (const pane of labelled) {
|
|
57
|
+
const group = pane.getAttribute('group');
|
|
58
|
+
if (group && group !== lastGroup) {
|
|
59
|
+
const label = this.createElement('div', ['nk-section-label']);
|
|
60
|
+
label.textContent = group;
|
|
61
|
+
this._rows.appendChild(label);
|
|
62
|
+
lastGroup = group;
|
|
63
|
+
}
|
|
64
|
+
const row = this.createElement('div', ['nk-tree-item'], { role: 'tab', tabindex: '0', 'data-pane': pane.name });
|
|
65
|
+
const icon = this.createElement('span', ['icon']);
|
|
66
|
+
icon.textContent = pane.getAttribute('icon') || '';
|
|
67
|
+
const text = this.createElement('span', ['label']);
|
|
68
|
+
text.textContent = pane.getAttribute('label');
|
|
69
|
+
row.append(icon, text);
|
|
70
|
+
this._rows.appendChild(row);
|
|
71
|
+
}
|
|
72
|
+
this._syncActive();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Marks the active pane and its nav row without rebuilding the rows (keeps focus). */
|
|
76
|
+
_syncActive() {
|
|
77
|
+
const panes = this.panes;
|
|
78
|
+
let current = this.getAttribute('pane');
|
|
79
|
+
if (!panes.some(p => p.name === current)) current = (panes.find(p => p.hasAttribute('active')) || panes[0])?.name ?? null;
|
|
80
|
+
for (const row of this._rows.querySelectorAll('[data-pane]')) {
|
|
81
|
+
const on = row.dataset.pane === current;
|
|
82
|
+
row.classList.toggle('active', on);
|
|
83
|
+
row.setAttribute('aria-selected', on ? 'true' : 'false');
|
|
84
|
+
}
|
|
85
|
+
for (const pane of panes) pane.active = pane.name === current;
|
|
86
|
+
this._current = current;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
_syncOpen() {
|
|
90
|
+
const open = this.getBoolAttr('open');
|
|
91
|
+
this._backdrop.classList.toggle('open', open);
|
|
92
|
+
this._backdrop.inert = !open;
|
|
93
|
+
if (open === this._wasOpen) return;
|
|
94
|
+
this._wasOpen = open;
|
|
95
|
+
if (open) {
|
|
96
|
+
this._returnFocus = document.activeElement;
|
|
97
|
+
lockScroll();
|
|
98
|
+
this._undoInert = inertOutside(this);
|
|
99
|
+
requestAnimationFrame(() => {
|
|
100
|
+
const target = this._rows.querySelector('.nk-tree-item.active') || firstFocusable(this) || this._box;
|
|
101
|
+
target.focus({ preventScroll: true });
|
|
102
|
+
});
|
|
103
|
+
} else {
|
|
104
|
+
unlockScroll();
|
|
105
|
+
this._undoInert?.(); this._undoInert = null;
|
|
106
|
+
const back = this._returnFocus;
|
|
107
|
+
if (back && typeof back.focus === 'function' && back.isConnected) back.focus({ preventScroll: true });
|
|
108
|
+
this._returnFocus = null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
setupEvents() {
|
|
113
|
+
this._onBackdrop = (e) => { if (e.target === this._backdrop) this.close(); };
|
|
114
|
+
this._onKey = (e) => { if (e.key === 'Escape' && this.getBoolAttr('open')) { e.stopPropagation(); this.close(); } };
|
|
115
|
+
this._onNavClick = (e) => { const row = e.target.closest('[data-pane]'); if (row) { row.focus(); this.pane = row.dataset.pane; } };
|
|
116
|
+
this._onNavKey = (e) => {
|
|
117
|
+
const row = e.target.closest?.('[data-pane]');
|
|
118
|
+
if (!row) return;
|
|
119
|
+
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); this.pane = row.dataset.pane; return; }
|
|
120
|
+
const dir = { ArrowDown: 1, ArrowUp: -1 }[e.key];
|
|
121
|
+
if (!dir) return;
|
|
122
|
+
const rows = [...this._rows.querySelectorAll('[data-pane]')];
|
|
123
|
+
const next = rows[(rows.indexOf(row) + dir + rows.length) % rows.length];
|
|
124
|
+
e.preventDefault(); next.focus(); this.pane = next.dataset.pane;
|
|
125
|
+
};
|
|
126
|
+
this._onSlot = () => this.requestNav();
|
|
127
|
+
this._backdrop.addEventListener('click', this._onBackdrop);
|
|
128
|
+
document.addEventListener('keydown', this._onKey);
|
|
129
|
+
this._rows.addEventListener('click', this._onNavClick);
|
|
130
|
+
this._rows.addEventListener('keydown', this._onNavKey);
|
|
131
|
+
this._slot.addEventListener('slotchange', this._onSlot);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
teardownEvents() {
|
|
135
|
+
this._backdrop?.removeEventListener('click', this._onBackdrop);
|
|
136
|
+
document.removeEventListener('keydown', this._onKey);
|
|
137
|
+
this._rows?.removeEventListener('click', this._onNavClick);
|
|
138
|
+
this._rows?.removeEventListener('keydown', this._onNavKey);
|
|
139
|
+
this._slot?.removeEventListener('slotchange', this._onSlot);
|
|
140
|
+
if (this._wasOpen) { unlockScroll(); this._undoInert?.(); this._undoInert = null; this._wasOpen = false; }
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
onAttributeChanged(name) {
|
|
144
|
+
if (name === 'open') {
|
|
145
|
+
this._syncOpen();
|
|
146
|
+
this.emit('nk-toggle', { open: this.getBoolAttr('open') });
|
|
147
|
+
} else if (name === 'pane') {
|
|
148
|
+
const before = this._current;
|
|
149
|
+
this._syncActive();
|
|
150
|
+
if (this._current !== before) this.emit('nk-select', { value: this._current, label: this.panes.find(p => p.name === this._current)?.getAttribute('label') ?? this._current });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
show(pane) { if (pane) this.setAttribute('pane', pane); this.setBoolAttr('open', true); }
|
|
155
|
+
close() { this.setBoolAttr('open', false); }
|
|
156
|
+
toggle() { this.setBoolAttr('open', !this.getBoolAttr('open')); }
|
|
157
|
+
|
|
158
|
+
get open() { return this.getBoolAttr('open'); }
|
|
159
|
+
set open(v) { this.setBoolAttr('open', v); }
|
|
160
|
+
get pane() { return this._current ?? this.getAttribute('pane'); }
|
|
161
|
+
set pane(v) { this.setAttribute('pane', v); }
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
customElements.define('nk-modal', NkModal);
|
|
165
|
+
export { NkModal };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { NkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// <nk-pop placement="bottom-start">
|
|
4
|
+
// <nk-btn slot="trigger" variant="secondary">Options</nk-btn>
|
|
5
|
+
// <nk-menu>…</nk-menu>
|
|
6
|
+
// </nk-pop>
|
|
7
|
+
// The trigger stays in the light DOM; a click on it toggles `open`, outside
|
|
8
|
+
// clicks and Escape close. Content is wrapped in `.nk-pop` unless it brings
|
|
9
|
+
// its own surface (nk-menu, nk-emoji-picker) or `bare` is set. The only
|
|
10
|
+
// styling here is positioning – the surface look is the stylesheet's.
|
|
11
|
+
const popSheet = new CSSStyleSheet();
|
|
12
|
+
popSheet.replaceSync(`
|
|
13
|
+
.nk-pop-anchor { position: relative; display: inline-block; }
|
|
14
|
+
.nk-pop-float { display: none; position: absolute; z-index: 50; top: 100%; left: 0; margin-top: 4px; }
|
|
15
|
+
:host([open]) .nk-pop-float { display: block; }
|
|
16
|
+
:host([placement="bottom-end"]) .nk-pop-float { left: auto; right: 0; }
|
|
17
|
+
:host([placement="top-start"]) .nk-pop-float { top: auto; bottom: 100%; margin: 0 0 4px; }
|
|
18
|
+
:host([placement="top-end"]) .nk-pop-float { top: auto; bottom: 100%; left: auto; right: 0; margin: 0 0 4px; }
|
|
19
|
+
`);
|
|
20
|
+
const OWN_SURFACE = new Set(['nk-menu', 'nk-emoji-picker']);
|
|
21
|
+
|
|
22
|
+
class NkPop extends NkElement {
|
|
23
|
+
static get hostStyles() { return popSheet; }
|
|
24
|
+
static get observedAttributes() { return ['open', 'placement', 'bare']; }
|
|
25
|
+
|
|
26
|
+
render() {
|
|
27
|
+
const anchor = this.createElement('div', ['nk-pop-anchor']);
|
|
28
|
+
this._triggerSlot = this.createElement('slot', [], { name: 'trigger' });
|
|
29
|
+
this._float = this.createElement('div', ['nk-pop-float']);
|
|
30
|
+
this._surface = this.createElement('div', ['nk-pop']);
|
|
31
|
+
this._slot = document.createElement('slot');
|
|
32
|
+
this._surface.appendChild(this._slot);
|
|
33
|
+
this._float.appendChild(this._surface);
|
|
34
|
+
anchor.append(this._triggerSlot, this._float);
|
|
35
|
+
this._wrapper.appendChild(anchor);
|
|
36
|
+
this._syncSurface();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
_syncSurface() {
|
|
40
|
+
const bare = this.getBoolAttr('bare') || this._slot.assignedElements().some(el => OWN_SURFACE.has(el.localName));
|
|
41
|
+
this._surface.className = bare ? '' : 'nk-pop';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
setupEvents() {
|
|
45
|
+
this._onTrigger = (e) => {
|
|
46
|
+
if (!e.composedPath().some(n => n instanceof Element && n.getAttribute?.('slot') === 'trigger')) return;
|
|
47
|
+
e.stopPropagation();
|
|
48
|
+
this.toggle();
|
|
49
|
+
};
|
|
50
|
+
this._onDocClick = (e) => { if (this.getBoolAttr('open') && !e.composedPath().includes(this)) this.close(); };
|
|
51
|
+
this._onKey = (e) => { if (e.key === 'Escape' && this.getBoolAttr('open')) this.close(); };
|
|
52
|
+
this._onSelect = (e) => { if (e.target !== this) this.close(); };
|
|
53
|
+
this._onSlot = () => this._syncSurface();
|
|
54
|
+
this.addEventListener('click', this._onTrigger);
|
|
55
|
+
document.addEventListener('click', this._onDocClick);
|
|
56
|
+
document.addEventListener('keydown', this._onKey);
|
|
57
|
+
this._float.addEventListener('nk-select', this._onSelect);
|
|
58
|
+
this._slot.addEventListener('slotchange', this._onSlot);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
teardownEvents() {
|
|
62
|
+
this.removeEventListener('click', this._onTrigger);
|
|
63
|
+
document.removeEventListener('click', this._onDocClick);
|
|
64
|
+
document.removeEventListener('keydown', this._onKey);
|
|
65
|
+
this._float?.removeEventListener('nk-select', this._onSelect);
|
|
66
|
+
this._slot?.removeEventListener('slotchange', this._onSlot);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
onAttributeChanged(name) {
|
|
70
|
+
if (name === 'bare') this._syncSurface();
|
|
71
|
+
if (name === 'open') {
|
|
72
|
+
const open = this.getBoolAttr('open');
|
|
73
|
+
for (const el of this._triggerSlot.assignedElements()) el.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
74
|
+
this.emit('nk-toggle', { open });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
show() { this.setBoolAttr('open', true); }
|
|
79
|
+
close() { this.setBoolAttr('open', false); }
|
|
80
|
+
toggle() { this.setBoolAttr('open', !this.getBoolAttr('open')); }
|
|
81
|
+
|
|
82
|
+
get open() { return this.getBoolAttr('open'); }
|
|
83
|
+
set open(v) { this.setBoolAttr('open', v); }
|
|
84
|
+
get placement() { return this.getAttribute('placement') || 'bottom-start'; }
|
|
85
|
+
set placement(v) { this.setAttribute('placement', v); }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
customElements.define('nk-pop', NkPop);
|
|
89
|
+
export { NkPop };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { NkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// <nk-settings-pane name="profile" label="My profile" icon="👤" group="Account" title="My profile" active>…</nk-settings-pane>
|
|
4
|
+
// → <section class="nk-settings-pane active"><h2>My profile</h2>…</section>
|
|
5
|
+
// `label`, `icon` and `group` feed the nav that <nk-modal> renders; `title`
|
|
6
|
+
// renders the pane heading (child-combinator rule, so it lives here). Slotted
|
|
7
|
+
// <h2>/<h3> are styled by their twins.
|
|
8
|
+
class NkSettingsPane extends NkElement {
|
|
9
|
+
static get observedAttributes() { return ['name', 'label', 'icon', 'group', 'title', 'active']; }
|
|
10
|
+
|
|
11
|
+
render() {
|
|
12
|
+
this._section = this.createElement('section', ['nk-settings-pane'], { role: 'tabpanel' });
|
|
13
|
+
this._h2 = document.createElement('h2');
|
|
14
|
+
this._section.appendChild(this._h2);
|
|
15
|
+
this._section.appendChild(document.createElement('slot'));
|
|
16
|
+
this._wrapper.appendChild(this._section);
|
|
17
|
+
this._sync();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_sync() {
|
|
21
|
+
const title = this.getAttribute('title');
|
|
22
|
+
this._h2.textContent = title || '';
|
|
23
|
+
this._h2.style.display = title ? '' : 'none';
|
|
24
|
+
this._section.classList.toggle('active', this.getBoolAttr('active'));
|
|
25
|
+
this._section.setAttribute('aria-label', this.getAttribute('label') || title || this.getAttribute('name') || '');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
onAttributeChanged(name) {
|
|
29
|
+
this._sync();
|
|
30
|
+
if (['label', 'icon', 'group', 'name'].includes(name)) this.closest('nk-modal')?.requestNav?.();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get name() { return this.getAttribute('name') ?? this.getAttribute('label') ?? ''; }
|
|
34
|
+
get active() { return this.getBoolAttr('active'); }
|
|
35
|
+
set active(v) { this.setBoolAttr('active', v); }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
customElements.define('nk-settings-pane', NkSettingsPane);
|
|
39
|
+
export { NkSettingsPane };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { NkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// <nk-settings-user slot="user" name="Marcel Karas" mail="marcel@…" avatar="MK"></nk-settings-user>
|
|
4
|
+
// → <div class="nk-settings-user"><div class="avatar">MK</div><div class="u-text"><div class="name">…</div><div class="mail">…</div></div></div>
|
|
5
|
+
class NkSettingsUser extends NkElement {
|
|
6
|
+
static get observedAttributes() { return ['name', 'mail', 'avatar']; }
|
|
7
|
+
|
|
8
|
+
render() {
|
|
9
|
+
const box = this.createElement('div', ['nk-settings-user']);
|
|
10
|
+
this._avatar = this.createElement('div', ['avatar']);
|
|
11
|
+
const s = this.createElement('slot', [], { name: 'avatar' });
|
|
12
|
+
s.appendChild(this._avatar);
|
|
13
|
+
const text = this.createElement('div', ['u-text']);
|
|
14
|
+
this._name = this.createElement('div', ['name']);
|
|
15
|
+
this._mail = this.createElement('div', ['mail']);
|
|
16
|
+
text.append(this._name, this._mail);
|
|
17
|
+
box.append(s, text);
|
|
18
|
+
this._wrapper.appendChild(box);
|
|
19
|
+
this._sync();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
_sync() {
|
|
23
|
+
const name = this.getAttribute('name') || '';
|
|
24
|
+
this._name.textContent = name;
|
|
25
|
+
const mail = this.getAttribute('mail');
|
|
26
|
+
this._mail.textContent = mail || '';
|
|
27
|
+
this._mail.style.display = mail ? '' : 'none';
|
|
28
|
+
this._avatar.textContent = this.getAttribute('avatar') || name.split(/\s+/).map(w => w[0]).join('').slice(0, 2).toUpperCase();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
onAttributeChanged() { this._sync(); }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
customElements.define('nk-settings-user', NkSettingsUser);
|
|
35
|
+
export { NkSettingsUser };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { NkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// <nk-toast id="toast"></nk-toast> … toast.show('Saved');
|
|
4
|
+
// → <div class="nk-toast show">✓ Saved</div>
|
|
5
|
+
// One node, bottom-centred, auto-hides after `duration` ms (default 2200).
|
|
6
|
+
class NkToast extends NkElement {
|
|
7
|
+
static get observedAttributes() { return ['open', 'duration', 'icon']; }
|
|
8
|
+
|
|
9
|
+
render() {
|
|
10
|
+
this._box = this.createElement('div', ['nk-toast'], { role: 'status', 'aria-live': 'polite' });
|
|
11
|
+
this._icon = document.createElement('span');
|
|
12
|
+
this._msg = document.createElement('span');
|
|
13
|
+
this._box.append(this._icon, this._msg, document.createElement('slot'));
|
|
14
|
+
this._wrapper.appendChild(this._box);
|
|
15
|
+
this._sync();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
_sync() {
|
|
19
|
+
this._box.classList.toggle('show', this.getBoolAttr('open'));
|
|
20
|
+
const icon = this.getAttribute('icon') ?? '✓';
|
|
21
|
+
this._icon.textContent = icon;
|
|
22
|
+
this._icon.style.display = icon ? '' : 'none';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Shows `message` (or the slotted content when omitted) and hides it again after `duration`. */
|
|
26
|
+
show(message, { duration } = {}) {
|
|
27
|
+
if (message !== undefined) this._msg.textContent = message;
|
|
28
|
+
clearTimeout(this._timer);
|
|
29
|
+
this.setBoolAttr('open', true);
|
|
30
|
+
const ms = duration ?? Number(this.getAttribute('duration')) ?? 2200;
|
|
31
|
+
if (ms > 0) this._timer = setTimeout(() => this.close(), ms || 2200);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
close() { clearTimeout(this._timer); this.setBoolAttr('open', false); }
|
|
35
|
+
|
|
36
|
+
onAttributeChanged(name) {
|
|
37
|
+
this._sync();
|
|
38
|
+
if (name === 'open') this.emit('nk-toggle', { open: this.getBoolAttr('open') });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
disconnectedCallback() { super.disconnectedCallback(); clearTimeout(this._timer); }
|
|
42
|
+
|
|
43
|
+
get open() { return this.getBoolAttr('open'); }
|
|
44
|
+
set open(v) { this.setBoolAttr('open', v); }
|
|
45
|
+
get message() { return this._msg?.textContent ?? ''; }
|
|
46
|
+
set message(v) { if (this._msg) this._msg.textContent = v; }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
customElements.define('nk-toast', NkToast);
|
|
50
|
+
export { NkToast };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { NkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// <nk-avatar-group more="+2">
|
|
4
|
+
// <span class="mini-avatar" style="background:#448361">SL</span>…
|
|
5
|
+
// </nk-avatar-group>
|
|
6
|
+
// → <div class="nk-avatar-group">…<span class="mini-avatar more">+2</span></div>
|
|
7
|
+
// The avatars stay in the light DOM (::slotted twins size and overlap them);
|
|
8
|
+
// the "more" bubble is rendered here from the attribute.
|
|
9
|
+
class NkAvatarGroup extends NkElement {
|
|
10
|
+
static get observedAttributes() { return ['more']; }
|
|
11
|
+
|
|
12
|
+
render() {
|
|
13
|
+
const box = this.createElement('div', ['nk-avatar-group']);
|
|
14
|
+
box.appendChild(document.createElement('slot'));
|
|
15
|
+
this._more = this.createElement('span', ['mini-avatar', 'more']);
|
|
16
|
+
box.appendChild(this._more);
|
|
17
|
+
this._wrapper.appendChild(box);
|
|
18
|
+
this._sync();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
_sync() {
|
|
22
|
+
const more = this.getAttribute('more');
|
|
23
|
+
this._more.textContent = more || '';
|
|
24
|
+
this._more.style.display = more ? '' : 'none';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
onAttributeChanged() { this._sync(); }
|
|
28
|
+
|
|
29
|
+
get more() { return this.getAttribute('more'); }
|
|
30
|
+
set more(v) { v == null ? this.removeAttribute('more') : this.setAttribute('more', v); }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
customElements.define('nk-avatar-group', NkAvatarGroup);
|
|
34
|
+
export { NkAvatarGroup };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { NkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// <nk-banner variant="info">ℹ️ <span>Text</span><span slot="action">Open</span></nk-banner>
|
|
4
|
+
// → <div class="nk-banner info">…<span class="b-action">Open</span></div>
|
|
5
|
+
const VARIANTS = ['info', 'success', 'warning'];
|
|
6
|
+
|
|
7
|
+
class NkBanner extends NkElement {
|
|
8
|
+
static get observedAttributes() { return ['variant']; }
|
|
9
|
+
|
|
10
|
+
render() {
|
|
11
|
+
this._box = this.createElement('div', this._classes(), { role: 'status' });
|
|
12
|
+
this._box.appendChild(document.createElement('slot'));
|
|
13
|
+
this._box.appendChild(this.createElement('slot', [], { name: 'action' }));
|
|
14
|
+
this._wrapper.appendChild(this._box);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
_classes() {
|
|
18
|
+
const v = this.getAttribute('variant');
|
|
19
|
+
return ['nk-banner', ...(VARIANTS.includes(v) ? [v] : [])];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
onAttributeChanged() { if (this._box) this._box.className = this._classes().join(' '); }
|
|
23
|
+
|
|
24
|
+
get variant() { return this.getAttribute('variant'); }
|
|
25
|
+
set variant(v) { v ? this.setAttribute('variant', v) : this.removeAttribute('variant'); }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
customElements.define('nk-banner', NkBanner);
|
|
29
|
+
export { NkBanner };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { NkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// <nk-block-host handle><p>Editable content lives here.</p></nk-block-host>
|
|
4
|
+
// → <div class="nk-block-host"><span class="nk-block-handle">⠿</span>…</div>
|
|
5
|
+
// The optical shell for editor content (hover wash, focus ring, drop target).
|
|
6
|
+
// Mount an editor into the light DOM; <nk-editor> (v1.1) does that for TipTap.
|
|
7
|
+
class NkBlockHost extends NkElement {
|
|
8
|
+
static get observedAttributes() { return ['handle', 'drop-target']; }
|
|
9
|
+
|
|
10
|
+
render() {
|
|
11
|
+
this._box = this.createElement('div', ['nk-block-host']);
|
|
12
|
+
this._handle = this.createElement('span', ['nk-block-handle'], { 'aria-hidden': 'true' });
|
|
13
|
+
this._handle.textContent = '⠿';
|
|
14
|
+
this._box.appendChild(this._handle);
|
|
15
|
+
this._box.appendChild(document.createElement('slot'));
|
|
16
|
+
this._wrapper.appendChild(this._box);
|
|
17
|
+
this._sync();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_sync() {
|
|
21
|
+
this._handle.style.display = this.getBoolAttr('handle') ? '' : 'none';
|
|
22
|
+
this._box.classList.toggle('nk-drop-target', this.getBoolAttr('drop-target'));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
onAttributeChanged() { this._sync(); }
|
|
26
|
+
|
|
27
|
+
get handle() { return this.getBoolAttr('handle'); }
|
|
28
|
+
set handle(v) { this.setBoolAttr('handle', v); }
|
|
29
|
+
get dropTarget() { return this.getBoolAttr('drop-target'); }
|
|
30
|
+
set dropTarget(v) { this.setBoolAttr('drop-target', v); }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
customElements.define('nk-block-host', NkBlockHost);
|
|
34
|
+
export { NkBlockHost };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// <nk-danger-zone title="Danger zone">…</nk-danger-zone>
|
|
4
|
+
// → <div class="nk-danger-zone"><div class="dz-title">Danger zone</div>…</div>
|
|
5
|
+
class NkDangerZone extends NkElement {
|
|
6
|
+
static get observedAttributes() { return ['title']; }
|
|
7
|
+
|
|
8
|
+
render() {
|
|
9
|
+
const box = this.createElement('div', ['nk-danger-zone']);
|
|
10
|
+
this._title = this.createElement('div', ['dz-title']);
|
|
11
|
+
box.appendChild(this._title);
|
|
12
|
+
box.appendChild(document.createElement('slot'));
|
|
13
|
+
this._wrapper.appendChild(box);
|
|
14
|
+
this._sync();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
_sync() {
|
|
18
|
+
const t = this.getAttribute('title');
|
|
19
|
+
this._title.textContent = t || '';
|
|
20
|
+
this._title.style.display = t ? '' : 'none';
|
|
21
|
+
}
|
|
22
|
+
onAttributeChanged() { this._sync(); }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
customElements.define('nk-danger-zone', NkDangerZone);
|
|
26
|
+
export { NkDangerZone };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { NkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// <nk-empty icon="🗂️" title="No entries yet" desc="Create the first one."><nk-btn variant="primary" small>+ New</nk-btn></nk-empty>
|
|
4
|
+
// → <div class="nk-empty"><div class="e-icon">🗂️</div><div class="e-title">…</div><div class="e-desc">…</div>…</div>
|
|
5
|
+
class NkEmpty extends NkElement {
|
|
6
|
+
static get observedAttributes() { return ['icon', 'title', 'desc']; }
|
|
7
|
+
|
|
8
|
+
render() {
|
|
9
|
+
const box = this.createElement('div', ['nk-empty']);
|
|
10
|
+
this._parts = {};
|
|
11
|
+
for (const [slot, cls] of [['icon', 'e-icon'], ['title', 'e-title'], ['desc', 'e-desc']]) {
|
|
12
|
+
const el = this.createElement('div', [cls]);
|
|
13
|
+
const s = this.createElement('slot', [], { name: slot });
|
|
14
|
+
s.appendChild(el);
|
|
15
|
+
box.appendChild(s);
|
|
16
|
+
this._parts[slot] = el;
|
|
17
|
+
}
|
|
18
|
+
box.appendChild(document.createElement('slot'));
|
|
19
|
+
this._wrapper.appendChild(box);
|
|
20
|
+
this._sync();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
_sync() {
|
|
24
|
+
for (const [slot, el] of Object.entries(this._parts)) {
|
|
25
|
+
const v = this.getAttribute(slot);
|
|
26
|
+
el.textContent = v || '';
|
|
27
|
+
el.style.display = v ? '' : 'none';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
onAttributeChanged() { this._sync(); }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
customElements.define('nk-empty', NkEmpty);
|
|
35
|
+
export { NkEmpty };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { NkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// <nk-member-list><nk-member-row …></nk-member-row>…</nk-member-list>
|
|
4
|
+
// → <div class="nk-member-list">…</div>; the last row gets `last` (no border).
|
|
5
|
+
class NkMemberList extends NkElement {
|
|
6
|
+
render() {
|
|
7
|
+
const box = this.createElement('div', ['nk-member-list']);
|
|
8
|
+
this._slot = document.createElement('slot');
|
|
9
|
+
box.appendChild(this._slot);
|
|
10
|
+
this._wrapper.appendChild(box);
|
|
11
|
+
this._mark();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
_mark() {
|
|
15
|
+
const rows = this._slot.assignedElements().filter(el => el.localName === 'nk-member-row');
|
|
16
|
+
rows.forEach((row, i) => { if (i === rows.length - 1) row.setAttribute('last', ''); else row.removeAttribute('last'); });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
setupEvents() {
|
|
20
|
+
this._onSlot = () => this._mark();
|
|
21
|
+
this._slot.addEventListener('slotchange', this._onSlot);
|
|
22
|
+
this._mark();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
teardownEvents() { this._slot?.removeEventListener('slotchange', this._onSlot); }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
customElements.define('nk-member-list', NkMemberList);
|
|
29
|
+
export { NkMemberList };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { NkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// <nk-member-row name="Sara Lindt" mail="sara@…" avatar="SL" color="#448361">
|
|
4
|
+
// <nk-select slot="role" compact>…</nk-select>
|
|
5
|
+
// </nk-member-row>
|
|
6
|
+
// → <div class="nk-member-row"><span class="mini-avatar">SL</span><div>Sara Lindt<div class="m-mail">…</div></div><select …></div>
|
|
7
|
+
class NkMemberRow extends NkElement {
|
|
8
|
+
static get observedAttributes() { return ['name', 'mail', 'avatar', 'color', 'last']; }
|
|
9
|
+
|
|
10
|
+
render() {
|
|
11
|
+
this._row = this.createElement('div', ['nk-member-row']);
|
|
12
|
+
this._avatar = this.createElement('span', ['mini-avatar']);
|
|
13
|
+
const avatarSlot = this.createElement('slot', [], { name: 'avatar' });
|
|
14
|
+
avatarSlot.appendChild(this._avatar);
|
|
15
|
+
const text = document.createElement('div');
|
|
16
|
+
this._name = document.createTextNode('');
|
|
17
|
+
this._mail = this.createElement('div', ['m-mail']);
|
|
18
|
+
text.append(this._name, this._mail);
|
|
19
|
+
// `.nk-member-row .nk-select { margin-left: auto }` cannot reach a select
|
|
20
|
+
// inside another shadow root, and a display:contents host takes no margin –
|
|
21
|
+
// so the role slot sits in a box that carries that rule.
|
|
22
|
+
const role = document.createElement('div');
|
|
23
|
+
role.style.marginLeft = 'auto';
|
|
24
|
+
role.appendChild(this.createElement('slot', [], { name: 'role' }));
|
|
25
|
+
this._row.append(avatarSlot, text, role, document.createElement('slot'));
|
|
26
|
+
this._wrapper.appendChild(this._row);
|
|
27
|
+
this._sync();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
_sync() {
|
|
31
|
+
this._name.data = this.getAttribute('name') || '';
|
|
32
|
+
const mail = this.getAttribute('mail');
|
|
33
|
+
this._mail.textContent = mail || '';
|
|
34
|
+
this._mail.style.display = mail ? '' : 'none';
|
|
35
|
+
const avatar = this.getAttribute('avatar');
|
|
36
|
+
this._avatar.textContent = avatar || (this.getAttribute('name') || '').split(/\s+/).map(w => w[0]).join('').slice(0, 2).toUpperCase();
|
|
37
|
+
this._avatar.style.background = this.getAttribute('color') || 'var(--nk-text-tertiary)';
|
|
38
|
+
this._row.classList.toggle('last', this.getBoolAttr('last'));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
onAttributeChanged() { this._sync(); }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
customElements.define('nk-member-row', NkMemberRow);
|
|
45
|
+
export { NkMemberRow };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { NkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// <nk-mention type="person"><span slot="avatar" class="mini-avatar" style="background:#448361">SL</span>Sara Lindt</nk-mention>
|
|
4
|
+
// <nk-mention type="page">📄 Onboarding</nk-mention> <nk-mention type="date">📅 May 20</nk-mention>
|
|
5
|
+
// → <span class="nk-mention person">…</span>
|
|
6
|
+
const TYPES = ['person', 'page', 'date'];
|
|
7
|
+
|
|
8
|
+
class NkMention extends NkElement {
|
|
9
|
+
static get observedAttributes() { return ['type']; }
|
|
10
|
+
|
|
11
|
+
render() {
|
|
12
|
+
this._box = this.createElement('span', this._classes());
|
|
13
|
+
this._box.appendChild(this.createElement('slot', [], { name: 'avatar' }));
|
|
14
|
+
this._box.appendChild(document.createElement('slot'));
|
|
15
|
+
this._wrapper.appendChild(this._box);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
_classes() {
|
|
19
|
+
const t = this.getAttribute('type');
|
|
20
|
+
return ['nk-mention', ...(TYPES.includes(t) ? [t] : [])];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
onAttributeChanged() { if (this._box) this._box.className = this._classes().join(' '); }
|
|
24
|
+
|
|
25
|
+
get type() { return this.getAttribute('type'); }
|
|
26
|
+
set type(v) { v ? this.setAttribute('type', v) : this.removeAttribute('type'); }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
customElements.define('nk-mention', NkMention);
|
|
30
|
+
export { NkMention };
|