@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,81 @@
|
|
|
1
|
+
import { NkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// <nk-workspace-switcher slot="workspace" name="Acme" avatar="A">
|
|
4
|
+
// <nk-menu slot="menu">…</nk-menu>
|
|
5
|
+
// </nk-workspace-switcher>
|
|
6
|
+
// → <div class="nk-workspace"><div class="avatar">A</div><span>Acme</span><span class="chev">⌄</span></div>
|
|
7
|
+
// A click toggles `open` and shows whatever sits in the menu slot below the
|
|
8
|
+
// row; clicking outside or pressing Escape closes it.
|
|
9
|
+
const menuSheet = new CSSStyleSheet();
|
|
10
|
+
menuSheet.replaceSync(`
|
|
11
|
+
.nk-ws-anchor { position: relative; }
|
|
12
|
+
.nk-ws-menu { display: none; position: absolute; left: 8px; top: calc(100% - 2px); z-index: 50; }
|
|
13
|
+
:host([open]) .nk-ws-menu { display: block; }
|
|
14
|
+
`);
|
|
15
|
+
|
|
16
|
+
class NkWorkspaceSwitcher extends NkElement {
|
|
17
|
+
static get hostStyles() { return menuSheet; }
|
|
18
|
+
static get observedAttributes() { return ['name', 'avatar', 'open']; }
|
|
19
|
+
|
|
20
|
+
render() {
|
|
21
|
+
this._row = this.createElement('div', ['nk-workspace'], { role: 'button', tabindex: '0', 'aria-haspopup': 'menu' });
|
|
22
|
+
this._avatar = this.createElement('div', ['avatar']);
|
|
23
|
+
const avatarSlot = this.createElement('slot', [], { name: 'avatar' });
|
|
24
|
+
avatarSlot.appendChild(this._avatar);
|
|
25
|
+
this._name = document.createElement('span');
|
|
26
|
+
const chev = this.createElement('span', ['chev']);
|
|
27
|
+
chev.textContent = '⌄';
|
|
28
|
+
this._row.append(avatarSlot, this._name, chev);
|
|
29
|
+
this._menu = this.createElement('div', ['nk-ws-menu']);
|
|
30
|
+
this._menu.appendChild(this.createElement('slot', [], { name: 'menu' }));
|
|
31
|
+
const anchor = this.createElement('div', ['nk-ws-anchor']);
|
|
32
|
+
anchor.append(this._row, this._menu);
|
|
33
|
+
this._wrapper.appendChild(anchor);
|
|
34
|
+
this._sync();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
_sync() {
|
|
38
|
+
const name = this.getAttribute('name') || '';
|
|
39
|
+
this._name.textContent = name;
|
|
40
|
+
this._avatar.textContent = this.getAttribute('avatar') || name.trim().charAt(0).toUpperCase();
|
|
41
|
+
this._row.setAttribute('aria-expanded', this.getBoolAttr('open') ? 'true' : 'false');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
setupEvents() {
|
|
45
|
+
this._onClick = () => this.toggle();
|
|
46
|
+
this._onKey = (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); this.toggle(); } };
|
|
47
|
+
this._onDocClick = (e) => { if (this.getBoolAttr('open') && !e.composedPath().includes(this)) this.close(); };
|
|
48
|
+
this._onDocKey = (e) => { if (e.key === 'Escape' && this.getBoolAttr('open')) this.close(); };
|
|
49
|
+
this._onMenuSelect = () => this.close();
|
|
50
|
+
this._row.addEventListener('click', this._onClick);
|
|
51
|
+
this._row.addEventListener('keydown', this._onKey);
|
|
52
|
+
this._menu.addEventListener('nk-select', this._onMenuSelect);
|
|
53
|
+
document.addEventListener('click', this._onDocClick);
|
|
54
|
+
document.addEventListener('keydown', this._onDocKey);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
teardownEvents() {
|
|
58
|
+
this._row?.removeEventListener('click', this._onClick);
|
|
59
|
+
this._row?.removeEventListener('keydown', this._onKey);
|
|
60
|
+
this._menu?.removeEventListener('nk-select', this._onMenuSelect);
|
|
61
|
+
document.removeEventListener('click', this._onDocClick);
|
|
62
|
+
document.removeEventListener('keydown', this._onDocKey);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
onAttributeChanged(name) {
|
|
66
|
+
this._sync();
|
|
67
|
+
if (name === 'open') this.emit('nk-toggle', { open: this.getBoolAttr('open') });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
show() { this.setBoolAttr('open', true); }
|
|
71
|
+
close() { this.setBoolAttr('open', false); }
|
|
72
|
+
toggle() { this.setBoolAttr('open', !this.getBoolAttr('open')); }
|
|
73
|
+
|
|
74
|
+
get name() { return this.getAttribute('name'); }
|
|
75
|
+
set name(v) { this.setAttribute('name', v); }
|
|
76
|
+
get open() { return this.getBoolAttr('open'); }
|
|
77
|
+
set open(v) { this.setBoolAttr('open', v); }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
customElements.define('nk-workspace-switcher', NkWorkspaceSwitcher);
|
|
81
|
+
export { NkWorkspaceSwitcher };
|
package/src/index.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// NotionKit Elements — Web Components for the NotionKit CSS foundation
|
|
2
|
+
// https://github.com/JUNGHERZ/NotionKit-Elements
|
|
3
|
+
//
|
|
4
|
+
// Importing a component file registers its tag as a side effect; this barrel
|
|
5
|
+
// therefore both registers every element and exposes its class.
|
|
6
|
+
|
|
7
|
+
export { NkElement, NkFormElement } from './base.js';
|
|
8
|
+
|
|
9
|
+
// Wave 1 – forms
|
|
10
|
+
export { NkBtn } from './components/forms/nk-btn.js';
|
|
11
|
+
export { NkInput } from './components/forms/nk-input.js';
|
|
12
|
+
export { NkTextarea } from './components/forms/nk-textarea.js';
|
|
13
|
+
export { NkSelect } from './components/forms/nk-select.js';
|
|
14
|
+
export { NkSwitch } from './components/forms/nk-switch.js';
|
|
15
|
+
export { NkCheck } from './components/forms/nk-check.js';
|
|
16
|
+
export { NkRadio } from './components/forms/nk-radio.js';
|
|
17
|
+
export { NkSlider } from './components/forms/nk-slider.js';
|
|
18
|
+
export { NkField } from './components/forms/nk-field.js';
|
|
19
|
+
|
|
20
|
+
// Wave 1 – content
|
|
21
|
+
export { NkTag } from './components/content/nk-tag.js';
|
|
22
|
+
export { NkProgress } from './components/content/nk-progress.js';
|
|
23
|
+
export { NkCallout } from './components/content/nk-callout.js';
|
|
24
|
+
export { NkDivider } from './components/content/nk-divider.js';
|
|
25
|
+
export { NkHeading } from './components/content/nk-heading.js';
|
|
26
|
+
export { NkToggle } from './components/content/nk-toggle.js';
|
|
27
|
+
export { NkTodo } from './components/content/nk-todo.js';
|
|
28
|
+
export { NkKbd } from './components/content/nk-kbd.js';
|
|
29
|
+
export { NkCode } from './components/content/nk-code.js';
|
|
30
|
+
export { NkQuote } from './components/content/nk-quote.js';
|
|
31
|
+
|
|
32
|
+
// Wave 2 – app shell & navigation
|
|
33
|
+
export { NkApp } from './components/shell/nk-app.js';
|
|
34
|
+
export { NkSidebar } from './components/shell/nk-sidebar.js';
|
|
35
|
+
export { NkWorkspaceSwitcher } from './components/shell/nk-workspace-switcher.js';
|
|
36
|
+
export { NkSectionLabel } from './components/shell/nk-section-label.js';
|
|
37
|
+
export { NkTree } from './components/shell/nk-tree.js';
|
|
38
|
+
export { NkTreeItem } from './components/shell/nk-tree-item.js';
|
|
39
|
+
export { NkTopbar } from './components/shell/nk-topbar.js';
|
|
40
|
+
export { NkBreadcrumb } from './components/shell/nk-breadcrumb.js';
|
|
41
|
+
export { NkThemeToggle } from './components/shell/nk-theme-toggle.js';
|
|
42
|
+
|
|
43
|
+
// Wave 3 – page shell & blocks
|
|
44
|
+
export { NkPage } from './components/page/nk-page.js';
|
|
45
|
+
export { NkPageCover } from './components/page/nk-page-cover.js';
|
|
46
|
+
export { NkPageTitle } from './components/page/nk-page-title.js';
|
|
47
|
+
export { NkPageActions } from './components/page/nk-page-actions.js';
|
|
48
|
+
export { NkBlockHost } from './components/page/nk-block-host.js';
|
|
49
|
+
export { NkBanner } from './components/page/nk-banner.js';
|
|
50
|
+
export { NkEmpty } from './components/page/nk-empty.js';
|
|
51
|
+
export { NkSkeleton } from './components/page/nk-skeleton.js';
|
|
52
|
+
export { NkSynced } from './components/page/nk-synced.js';
|
|
53
|
+
export { NkTabs } from './components/page/nk-tabs.js';
|
|
54
|
+
export { NkTab } from './components/page/nk-tab.js';
|
|
55
|
+
export { NkSegmented } from './components/page/nk-segmented.js';
|
|
56
|
+
export { NkStats } from './components/page/nk-stats.js';
|
|
57
|
+
export { NkStat } from './components/page/nk-stat.js';
|
|
58
|
+
export { NkAvatarGroup } from './components/page/nk-avatar-group.js';
|
|
59
|
+
export { NkMention } from './components/page/nk-mention.js';
|
|
60
|
+
export { NkTemplateBtn } from './components/page/nk-template-btn.js';
|
|
61
|
+
export { NkModelCard } from './components/page/nk-model-card.js';
|
|
62
|
+
export { NkProfileRow } from './components/page/nk-profile-row.js';
|
|
63
|
+
export { NkDangerZone } from './components/page/nk-danger-zone.js';
|
|
64
|
+
export { NkMemberList } from './components/page/nk-member-list.js';
|
|
65
|
+
export { NkMemberRow } from './components/page/nk-member-row.js';
|
|
66
|
+
|
|
67
|
+
// Wave 4 – overlays
|
|
68
|
+
export { NkModal } from './components/overlays/nk-modal.js';
|
|
69
|
+
export { NkSettingsPane } from './components/overlays/nk-settings-pane.js';
|
|
70
|
+
export { NkSettingsUser } from './components/overlays/nk-settings-user.js';
|
|
71
|
+
export { NkCmdk } from './components/overlays/nk-cmdk.js';
|
|
72
|
+
export { NkMenu } from './components/overlays/nk-menu.js';
|
|
73
|
+
export { NkMenuItem } from './components/overlays/nk-menu-item.js';
|
|
74
|
+
export { NkPop } from './components/overlays/nk-pop.js';
|
|
75
|
+
export { NkEmojiPicker } from './components/overlays/nk-emoji-picker.js';
|
|
76
|
+
export { NkToast } from './components/overlays/nk-toast.js';
|
|
77
|
+
|
|
78
|
+
// Wave 5 – data & collaboration
|
|
79
|
+
export { NkDatabase } from './components/data/nk-database.js';
|
|
80
|
+
export { NkTableView } from './components/data/nk-table-view.js';
|
|
81
|
+
export { NkBoardView } from './components/data/nk-board-view.js';
|
|
82
|
+
export { NkFilterBar } from './components/data/nk-filter-bar.js';
|
|
83
|
+
export { NkComments } from './components/data/nk-comments.js';
|
|
84
|
+
export { NkComment } from './components/data/nk-comment.js';
|
|
85
|
+
export { NkAiThread } from './components/data/nk-ai-thread.js';
|
|
86
|
+
export { NkAiMsg } from './components/data/nk-ai-msg.js';
|
|
87
|
+
export { NkAiInputRow } from './components/data/nk-ai-input-row.js';
|
|
88
|
+
export { renderPropertyCell, tagFor, compareBy } from './util/property-cell.js';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Built-in emoji set for <nk-emoji-picker>: eight categories, names for
|
|
2
|
+
// search. Override with `picker.emojis = [{ char, name, cat }]`.
|
|
3
|
+
const C = (cat, icon, list) => list.map(([char, name]) => ({ char, name, cat, icon }));
|
|
4
|
+
export const EMOJI_CATEGORIES = [
|
|
5
|
+
{ id: 'smileys', icon: '😀' }, { id: 'people', icon: '👋' }, { id: 'nature', icon: '🌿' }, { id: 'food', icon: '☕' },
|
|
6
|
+
{ id: 'activity', icon: '🎯' }, { id: 'travel', icon: '🚀' }, { id: 'objects', icon: '💡' }, { id: 'symbols', icon: '✅' },
|
|
7
|
+
];
|
|
8
|
+
export const EMOJI = [
|
|
9
|
+
...C('smileys', '😀', [['😀', 'grinning'], ['😊', 'smile blush'], ['😂', 'joy laugh'], ['🙂', 'slight smile'], ['😉', 'wink'], ['😍', 'heart eyes love'], ['🤔', 'thinking'], ['😎', 'cool sunglasses'], ['🥳', 'party'], ['😴', 'sleep'], ['🤯', 'mind blown'], ['😅', 'sweat smile'], ['🙃', 'upside down'], ['😇', 'angel halo'], ['🤗', 'hug'], ['😢', 'cry sad']]),
|
|
10
|
+
...C('people', '👋', [['👋', 'wave hello'], ['👍', 'thumbs up'], ['👎', 'thumbs down'], ['🙏', 'pray thanks'], ['👏', 'clap'], ['🤝', 'handshake deal'], ['💪', 'strong'], ['👀', 'eyes look'], ['🧠', 'brain knowledge'], ['❤️', 'heart love'], ['👤', 'person user'], ['👥', 'people team members'], ['🧑💻', 'developer'], ['🙋', 'raise hand'], ['✍️', 'writing'], ['🫶', 'heart hands']]),
|
|
11
|
+
...C('nature', '🌿', [['🌿', 'leaf herb'], ['🌱', 'seedling'], ['🌳', 'tree'], ['🌸', 'blossom flower'], ['🌞', 'sun'], ['🌙', 'moon night'], ['⭐', 'star'], ['🔥', 'fire hot'], ['🌈', 'rainbow'], ['🌊', 'wave water'], ['🍀', 'clover luck'], ['🐝', 'bee'], ['🦋', 'butterfly'], ['🐢', 'turtle'], ['🌍', 'earth globe'], ['❄️', 'snow']]),
|
|
12
|
+
...C('food', '☕', [['☕', 'coffee'], ['🍵', 'tea'], ['🍎', 'apple'], ['🍕', 'pizza'], ['🍰', 'cake'], ['🍪', 'cookie'], ['🥐', 'croissant'], ['🍔', 'burger'], ['🍜', 'noodles'], ['🍺', 'beer'], ['🍷', 'wine'], ['🥗', 'salad'], ['🍫', 'chocolate'], ['🍓', 'strawberry'], ['🥑', 'avocado'], ['🍩', 'donut']]),
|
|
13
|
+
...C('activity', '🎯', [['🎯', 'target goal'], ['🏆', 'trophy win'], ['🎉', 'tada celebration'], ['🎨', 'art palette design'], ['🎙️', 'microphone podcast voice'], ['🎬', 'clapper movie'], ['🎮', 'game'], ['⚽', 'football'], ['🏃', 'run'], ['🧘', 'yoga calm'], ['🎵', 'music'], ['🎲', 'dice'], ['🏁', 'finish flag'], ['🎓', 'graduation learn'], ['🧩', 'puzzle piece'], ['🔁', 'repeat retro']]),
|
|
14
|
+
...C('travel', '🚀', [['🚀', 'rocket launch'], ['✈️', 'plane travel'], ['🚗', 'car'], ['🚲', 'bike'], ['🏠', 'house home'], ['🏢', 'office building'], ['🗺️', 'map'], ['🧭', 'compass'], ['⛰️', 'mountain'], ['🏖️', 'beach'], ['🚉', 'station'], ['🛰️', 'satellite'], ['🌆', 'city'], ['🏕️', 'camping'], ['⛵', 'sailboat'], ['🛫', 'departure']]),
|
|
15
|
+
...C('objects', '💡', [['💡', 'idea bulb'], ['📊', 'chart bar'], ['📈', 'chart up'], ['📅', 'calendar date'], ['📄', 'page document'], ['📁', 'folder'], ['🗃️', 'card box database'], ['📌', 'pin'], ['🔍', 'search'], ['🛠️', 'tools'], ['⚙️', 'gear settings'], ['🔔', 'bell notification'], ['💎', 'gem diamond'], ['📝', 'memo notes'], ['📎', 'paperclip files'], ['🔒', 'lock secure'], ['💬', 'speech comment'], ['📤', 'export outbox'], ['📥', 'inbox'], ['🗑️', 'trash bin'], ['🖥️', 'desktop'], ['📱', 'phone'], ['💻', 'laptop'], ['🧾', 'receipt']]),
|
|
16
|
+
...C('symbols', '✅', [['✅', 'check done'], ['✨', 'sparkles ai magic'], ['❌', 'cross no'], ['⚠️', 'warning'], ['ℹ️', 'info'], ['❓', 'question'], ['➕', 'plus add'], ['➡️', 'arrow right'], ['🔴', 'red circle'], ['🟢', 'green circle'], ['🟡', 'yellow circle'], ['🔵', 'blue circle'], ['⏳', 'hourglass wait'], ['♻️', 'recycle'], ['🆕', 'new'], ['💯', 'hundred']]),
|
|
17
|
+
];
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Overlay plumbing shared by nk-modal and nk-cmdk: body scroll lock with a
|
|
2
|
+
// refcount, and `inert` on everything outside the overlay so focus and
|
|
3
|
+
// assistive technology stay inside – nested shadow roots included.
|
|
4
|
+
let locks = 0, previousOverflow = '';
|
|
5
|
+
|
|
6
|
+
export function lockScroll() {
|
|
7
|
+
if (locks++ === 0) {
|
|
8
|
+
previousOverflow = document.documentElement.style.overflow;
|
|
9
|
+
document.documentElement.style.overflow = 'hidden';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function unlockScroll() {
|
|
14
|
+
if (locks > 0 && --locks === 0) document.documentElement.style.overflow = previousOverflow;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Makes every sibling along `el`'s ancestor chain inert (shadow hosts included); returns the undo. */
|
|
18
|
+
export function inertOutside(el) {
|
|
19
|
+
const made = [];
|
|
20
|
+
let node = el;
|
|
21
|
+
while (node && node !== document.body) {
|
|
22
|
+
const parent = node.parentNode instanceof ShadowRoot ? node.parentNode : node.parentNode;
|
|
23
|
+
if (!parent) break;
|
|
24
|
+
for (const sib of parent.children) {
|
|
25
|
+
if (sib === node || sib.inert || /^(SCRIPT|STYLE|LINK|TEMPLATE)$/.test(sib.tagName)) continue;
|
|
26
|
+
sib.inert = true;
|
|
27
|
+
made.push(sib);
|
|
28
|
+
}
|
|
29
|
+
node = parent instanceof ShadowRoot ? parent.host : parent;
|
|
30
|
+
}
|
|
31
|
+
return () => { for (const c of made) c.inert = false; };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The first tabbable element inside a light-DOM subtree, looking into shadow roots. */
|
|
35
|
+
export function firstFocusable(root) {
|
|
36
|
+
const SEL = 'a[href], button:not([disabled]), input:not([disabled]):not([type=hidden]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"]), [contenteditable="true"], [contenteditable="plaintext-only"]';
|
|
37
|
+
const walk = (node) => {
|
|
38
|
+
for (const el of node.querySelectorAll('*')) {
|
|
39
|
+
if (el.matches(SEL) && el.getClientRects().length) return el;
|
|
40
|
+
if (el.shadowRoot) { const inner = walk(el.shadowRoot); if (inner) return inner; }
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
};
|
|
44
|
+
return walk(root);
|
|
45
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Subsequence scoring for the command palette: every query character must
|
|
2
|
+
// appear in order; consecutive hits, word starts and an early first hit score
|
|
3
|
+
// higher. Returns 0 when the query does not match.
|
|
4
|
+
export function fuzzyScore(query, text) {
|
|
5
|
+
const q = query.trim().toLowerCase();
|
|
6
|
+
if (!q) return 1;
|
|
7
|
+
const t = text.toLowerCase();
|
|
8
|
+
let ti = 0, score = 0, streak = 0;
|
|
9
|
+
for (let qi = 0; qi < q.length; qi++) {
|
|
10
|
+
const idx = t.indexOf(q[qi], ti);
|
|
11
|
+
if (idx < 0) return 0;
|
|
12
|
+
const wordStart = idx === 0 || /[\s\-_/.]/.test(t[idx - 1]);
|
|
13
|
+
streak = idx === ti ? streak + 1 : 0;
|
|
14
|
+
score += 1 + streak * 2 + (wordStart ? 3 : 0) - Math.min(3, (idx - ti) * 0.25);
|
|
15
|
+
ti = idx + 1;
|
|
16
|
+
}
|
|
17
|
+
if (t.startsWith(q)) score += 10;
|
|
18
|
+
return Math.max(0.01, score / (1 + t.length / 40));
|
|
19
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Minimal HTML highlighter emitting the .tag / .attr hooks .nk-code styles.
|
|
2
|
+
// Mirrors tools/highlight.mjs in the NotionKit foundation – no third-party
|
|
3
|
+
// highlighter, no other languages. Anything that is not HTML is escaped only.
|
|
4
|
+
export function escapeHtml(s) {
|
|
5
|
+
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function highlightHtml(source) {
|
|
9
|
+
return escapeHtml(source).replace(/<(\/?)([a-zA-Z][\w-]*)([^&]*?)(\/?)>/g, (m, close, tag, attrs, self) => {
|
|
10
|
+
const attrHtml = attrs.replace(/([\w-]+)(=)("[^"]*"|'[^']*')?/g,
|
|
11
|
+
(a, name, eq, val) => `<span class="attr">${name}</span>${eq}${val ?? ''}`);
|
|
12
|
+
return `<${close}<span class="tag">${tag}</span>${attrHtml}${self}>`;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Polymorphic property renderer for database views. Returns plain DOM built
|
|
2
|
+
// from NotionKit classes – deliberately not a custom element: every cell rule
|
|
3
|
+
// starts with `.nk-table`, so a cell inside its own shadow root would never
|
|
4
|
+
// be styled. Exported for consumers who render tables themselves.
|
|
5
|
+
//
|
|
6
|
+
// column: { key, label, type, icon, options: [{ value, label, color }], title }
|
|
7
|
+
// types: text | select | multi-select | date | person | checkbox | url | number | progress
|
|
8
|
+
const el = (tag, cls, text) => { const n = document.createElement(tag); if (cls) n.className = cls; if (text != null) n.textContent = text; return n; };
|
|
9
|
+
const COLORS = ['blue', 'green', 'orange', 'purple'];
|
|
10
|
+
|
|
11
|
+
export function optionFor(column, value) {
|
|
12
|
+
const opts = column.options || [];
|
|
13
|
+
return opts.find(o => o.value === value) || opts.find(o => o.label === value) || null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function tagFor(column, value) {
|
|
17
|
+
const opt = optionFor(column, value);
|
|
18
|
+
const color = opt?.color && COLORS.includes(opt.color) ? opt.color : 'blue';
|
|
19
|
+
return el('span', `nk-tag ${color}`, opt?.label ?? String(value));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function renderPropertyCell(column, value, row = {}) {
|
|
23
|
+
const type = column.type || 'text';
|
|
24
|
+
if (value === undefined || value === null || value === '') {
|
|
25
|
+
if (type === 'checkbox') return checkbox(column, false, row);
|
|
26
|
+
if (type === 'progress') return progress(0);
|
|
27
|
+
return el('span', type === 'person' ? 'person-cell' : null, type === 'text' && column.title ? '' : '—');
|
|
28
|
+
}
|
|
29
|
+
switch (type) {
|
|
30
|
+
case 'select': return tagFor(column, value);
|
|
31
|
+
case 'multi-select': {
|
|
32
|
+
const wrap = el('span');
|
|
33
|
+
wrap.style.display = 'inline-flex'; wrap.style.gap = '4px'; wrap.style.flexWrap = 'wrap';
|
|
34
|
+
for (const v of Array.isArray(value) ? value : String(value).split(',').map(s => s.trim()).filter(Boolean)) wrap.appendChild(tagFor(column, v));
|
|
35
|
+
return wrap;
|
|
36
|
+
}
|
|
37
|
+
case 'date': return el('span', 'date-cell', String(value));
|
|
38
|
+
case 'person': {
|
|
39
|
+
const cell = el('span', 'person-cell');
|
|
40
|
+
const p = typeof value === 'string' ? { name: value } : value;
|
|
41
|
+
const avatar = el('span', 'mini-avatar', p.initials || p.avatar || (p.name || '').split(/\s+/).map(w => w[0]).join('').slice(0, 2).toUpperCase());
|
|
42
|
+
avatar.style.background = p.color || 'var(--nk-text-tertiary)';
|
|
43
|
+
cell.append(avatar, document.createTextNode(' ' + (p.name || '')));
|
|
44
|
+
return cell;
|
|
45
|
+
}
|
|
46
|
+
case 'checkbox': return checkbox(column, !!value, row);
|
|
47
|
+
case 'url': { const a = el('a', null, String(value).replace(/^https?:\/\//, '')); a.href = String(value); a.target = '_blank'; a.rel = 'noopener'; return a; }
|
|
48
|
+
case 'number': return el('span', null, typeof value === 'number' ? value.toLocaleString() : String(value));
|
|
49
|
+
case 'progress': return progress(Number(value) || 0);
|
|
50
|
+
default: {
|
|
51
|
+
if (column.title) {
|
|
52
|
+
const t = el('span', 'row-title');
|
|
53
|
+
if (row.icon) t.append(document.createTextNode(row.icon + ' '));
|
|
54
|
+
t.append(document.createTextNode(String(value)));
|
|
55
|
+
return t;
|
|
56
|
+
}
|
|
57
|
+
return el('span', null, String(value));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function checkbox(column, checked, row) {
|
|
63
|
+
const label = el('label', 'nk-check');
|
|
64
|
+
const input = el('input');
|
|
65
|
+
input.type = 'checkbox'; input.checked = checked;
|
|
66
|
+
input.dataset.key = column.key;
|
|
67
|
+
if (row.id != null) input.dataset.rowId = row.id;
|
|
68
|
+
label.appendChild(input);
|
|
69
|
+
return label;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function progress(value) {
|
|
73
|
+
const frag = document.createDocumentFragment();
|
|
74
|
+
const bar = el('span', 'nk-progress');
|
|
75
|
+
const fill = el('i'); fill.style.width = `${Math.max(0, Math.min(100, value))}%`;
|
|
76
|
+
bar.appendChild(fill);
|
|
77
|
+
frag.append(bar, el('span', 'nk-progress-label', `${Math.round(value)}%`));
|
|
78
|
+
return frag;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Sort comparator for a column type. */
|
|
82
|
+
export function compareBy(column, dir = 1) {
|
|
83
|
+
const type = column.type || 'text';
|
|
84
|
+
return (a, b) => {
|
|
85
|
+
let x = a[column.key], y = b[column.key];
|
|
86
|
+
if (type === 'person') { x = x?.name ?? x ?? ''; y = y?.name ?? y ?? ''; }
|
|
87
|
+
if (type === 'number' || type === 'progress' || type === 'checkbox') return ((Number(x) || 0) - (Number(y) || 0)) * dir;
|
|
88
|
+
return String(x ?? '').localeCompare(String(y ?? ''), undefined, { numeric: true }) * dir;
|
|
89
|
+
};
|
|
90
|
+
}
|