@jungherz-de/notionkit-elements 1.15.0 → 1.17.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/CHANGELOG.md +36 -0
- package/README.md +67 -7
- package/SKILL.md +67 -59
- package/dist/components/base.js +106 -3
- package/dist/components/nk-ai-input-row.js +6 -3
- package/dist/components/nk-board-view.js +2 -2
- package/dist/components/nk-breadcrumb.js +2 -1
- package/dist/components/nk-calendar-view.js +8 -5
- package/dist/components/nk-calendar.js +12 -9
- package/dist/components/nk-cmdk.js +7 -3
- package/dist/components/nk-comments.js +5 -3
- package/dist/components/nk-copy-field.js +6 -3
- package/dist/components/nk-dialog.js +1 -1
- package/dist/components/nk-emoji-picker.js +6 -2
- package/dist/components/nk-filter-bar.js +10 -8
- package/dist/components/nk-gallery-view.js +29 -7
- package/dist/components/nk-image-picker.js +7 -3
- package/dist/components/nk-list-view.js +3 -2
- package/dist/components/nk-menu.js +2 -2
- package/dist/components/nk-modal.js +4 -2
- package/dist/components/nk-page-title.js +2 -1
- package/dist/components/nk-page.js +3 -1
- package/dist/components/nk-panel.js +4 -1
- package/dist/components/nk-peek.js +7 -4
- package/dist/components/nk-select.js +13 -8
- package/dist/components/nk-sheet.js +1 -1
- package/dist/components/nk-sidebar.js +6 -3
- package/dist/components/nk-steps.js +20 -4
- package/dist/components/nk-synced.js +2 -1
- package/dist/components/nk-table-view.js +3 -2
- package/dist/components/nk-theme-toggle.js +5 -2
- package/dist/components/nk-tooltip.js +1 -1
- package/dist/components/nk-tree-item.js +3 -1
- package/dist/components/shared/{focus-BNAChOXO.js → focus-C4tbSNND.js} +7 -2
- package/dist/components/shared/{property-cell-BSVcETss.js → property-cell-DcsfnUNF.js} +15 -5
- package/dist/notionkit-elements.esm.js +295 -83
- package/dist/notionkit-elements.esm.min.js +2 -0
- package/dist/notionkit-elements.esm.min.js.map +1 -0
- package/dist/notionkit-elements.js +297 -82
- package/dist/notionkit-elements.min.js +1 -1
- package/package.json +4 -3
- package/src/base.js +36 -2
- package/src/components/data/nk-ai-input-row.js +6 -3
- package/src/components/data/nk-board-view.js +2 -2
- package/src/components/data/nk-calendar-view.js +7 -4
- package/src/components/data/nk-comments.js +5 -3
- package/src/components/data/nk-filter-bar.js +10 -8
- package/src/components/data/nk-gallery-view.js +29 -7
- package/src/components/data/nk-list-view.js +2 -1
- package/src/components/data/nk-table-view.js +2 -1
- package/src/components/forms/nk-calendar.js +11 -8
- package/src/components/forms/nk-copy-field.js +6 -3
- package/src/components/forms/nk-image-picker.js +7 -3
- package/src/components/forms/nk-select.js +13 -8
- package/src/components/overlays/nk-cmdk.js +6 -2
- package/src/components/overlays/nk-emoji-picker.js +6 -2
- package/src/components/overlays/nk-menu.js +1 -1
- package/src/components/overlays/nk-modal.js +3 -1
- package/src/components/overlays/nk-peek.js +6 -3
- package/src/components/page/nk-page-title.js +2 -1
- package/src/components/page/nk-page.js +3 -1
- package/src/components/page/nk-panel.js +4 -1
- package/src/components/page/nk-steps.js +20 -4
- package/src/components/page/nk-synced.js +2 -1
- package/src/components/shell/nk-breadcrumb.js +2 -1
- package/src/components/shell/nk-sidebar.js +5 -2
- package/src/components/shell/nk-theme-toggle.js +5 -2
- package/src/components/shell/nk-tree-item.js +3 -1
- package/src/index.js +5 -1
- package/src/util/focus.js +7 -2
- package/src/util/property-cell.js +14 -4
- package/src/util/strings.js +73 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NkElement } from './base.js';
|
|
2
|
-
import { d as deepActiveElement } from './shared/focus-
|
|
2
|
+
import { d as deepActiveElement } from './shared/focus-C4tbSNND.js';
|
|
3
3
|
import { p as placeUnder } from './shared/floating-DOK73b_D.js';
|
|
4
4
|
import '@jungherz-de/notionkit/notionkit-styles.js';
|
|
5
5
|
|
|
@@ -20,7 +20,7 @@ import '@jungherz-de/notionkit/notionkit-styles.js';
|
|
|
20
20
|
// close it too, a switch row does not. Opened from the keyboard, focus moves
|
|
21
21
|
// to the first item; closing returns it to where it was.
|
|
22
22
|
const floatSheet = new CSSStyleSheet();
|
|
23
|
-
floatSheet.replaceSync(`:host([floating]) { display: block; position: fixed; top: 0; left: 0; z-index:
|
|
23
|
+
floatSheet.replaceSync(`:host([floating]) { display: block; position: fixed; top: 0; left: 0; z-index: 106; pointer-events: none; }`);
|
|
24
24
|
|
|
25
25
|
class NkMenu extends NkElement {
|
|
26
26
|
static get hostStyles() { return floatSheet; }
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NkElement } from './base.js';
|
|
2
|
-
import { l as lockScroll, i as inertOutside, f as firstFocusable, u as unlockScroll } from './shared/focus-
|
|
2
|
+
import { l as lockScroll, i as inertOutside, f as firstFocusable, u as unlockScroll } from './shared/focus-C4tbSNND.js';
|
|
3
3
|
import '@jungherz-de/notionkit/notionkit-styles.js';
|
|
4
4
|
|
|
5
5
|
// <nk-modal id="settings">
|
|
@@ -23,7 +23,7 @@ class NkModal extends NkElement {
|
|
|
23
23
|
this._backdrop = this.createElement('div', ['nk-modal-backdrop']);
|
|
24
24
|
this._backdrop.inert = true;
|
|
25
25
|
this._box = this.createElement('div', ['nk-modal'], { role: 'dialog', 'aria-modal': 'true', tabindex: '-1' });
|
|
26
|
-
this._nav = this.createElement('nav', ['nk-settings-nav'], { 'aria-label': '
|
|
26
|
+
this._nav = this.createElement('nav', ['nk-settings-nav'], { 'aria-label': this.str('settings') });
|
|
27
27
|
this._nav.appendChild(this.createElement('slot', [], { name: 'user' }));
|
|
28
28
|
this._rows = document.createElement('div');
|
|
29
29
|
this._nav.appendChild(this._rows);
|
|
@@ -141,6 +141,8 @@ class NkModal extends NkElement {
|
|
|
141
141
|
if (this._wasOpen) { unlockScroll(); this._undoInert?.(); this._undoInert = null; this._wasOpen = false; }
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
onStringsChanged() { this._nav.setAttribute('aria-label', this.str('settings')); }
|
|
145
|
+
|
|
144
146
|
onAttributeChanged(name) {
|
|
145
147
|
if (name === 'open') {
|
|
146
148
|
this._syncOpen();
|
|
@@ -24,7 +24,7 @@ class NkPageTitle extends NkElement {
|
|
|
24
24
|
this._h1.setAttribute('contenteditable', 'plaintext-only');
|
|
25
25
|
this._h1.setAttribute('spellcheck', 'false');
|
|
26
26
|
this._h1.setAttribute('role', 'textbox');
|
|
27
|
-
this._h1.setAttribute('aria-label', '
|
|
27
|
+
this._h1.setAttribute('aria-label', this.str('title'));
|
|
28
28
|
const text = this.getAttribute('value') ?? this.textContent.trim();
|
|
29
29
|
if (this._h1.textContent !== text && document.activeElement !== this) this._h1.textContent = text;
|
|
30
30
|
this._h1.setAttribute('data-placeholder', this.getAttribute('placeholder') || '');
|
|
@@ -59,6 +59,7 @@ class NkPageTitle extends NkElement {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
onAttributeChanged() { this._sync(); }
|
|
62
|
+
onStringsChanged() { if (this._h1.hasAttribute('role')) this._h1.setAttribute('aria-label', this.str('title')); }
|
|
62
63
|
|
|
63
64
|
get value() { return this.getBoolAttr('editable') ? (this._h1?.textContent.trim() ?? '') : (this.getAttribute('value') ?? this.textContent.trim()); }
|
|
64
65
|
set value(v) { this.setAttribute('value', v); }
|
|
@@ -20,7 +20,7 @@ class NkPage extends NkElement {
|
|
|
20
20
|
|
|
21
21
|
render() {
|
|
22
22
|
this._page = this.createElement('div', ['nk-page']);
|
|
23
|
-
this._icon = this.createElement('div', ['nk-page-icon'], { role: 'button', title: '
|
|
23
|
+
this._icon = this.createElement('div', ['nk-page-icon'], { role: 'button', title: this.str('changeIcon') });
|
|
24
24
|
this._iconSlot = this.createElement('slot', [], { name: 'icon' });
|
|
25
25
|
this._iconSlot.appendChild(this._icon);
|
|
26
26
|
this._page.appendChild(this._iconSlot);
|
|
@@ -76,6 +76,8 @@ class NkPage extends NkElement {
|
|
|
76
76
|
this._iconSlot?.removeEventListener('slotchange', this._onCover);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
onStringsChanged() { this._icon.title = this.str('changeIcon'); }
|
|
80
|
+
|
|
79
81
|
onAttributeChanged(name) {
|
|
80
82
|
if (name === 'narrow') this._build();
|
|
81
83
|
else this._sync();
|
|
@@ -43,7 +43,10 @@ class NkPanel extends NkElement {
|
|
|
43
43
|
const href = this.getAttribute('href');
|
|
44
44
|
if (href) { this._box.setAttribute('href', href); this._box.target = this.getAttribute('target') || ''; }
|
|
45
45
|
const cover = this.getAttribute('cover');
|
|
46
|
-
|
|
46
|
+
// The band is in the tree only with `cover`: hidden, it still matched
|
|
47
|
+
// `.nk-cover + .nk-page-icon` and pulled a lone icon over the tile's edge.
|
|
48
|
+
if (cover === null) this._cover.remove();
|
|
49
|
+
else if (!this._cover.isConnected) this._box.prepend(this._cover);
|
|
47
50
|
if (cover) { this._img.src = cover; if (!this._img.isConnected) this._cover.appendChild(this._img); }
|
|
48
51
|
else this._img.remove();
|
|
49
52
|
const icon = this.getAttribute('icon');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NkElement } from './base.js';
|
|
2
|
-
import { d as deepActiveElement, l as lockScroll, i as inertOutside, u as unlockScroll } from './shared/focus-
|
|
2
|
+
import { d as deepActiveElement, l as lockScroll, i as inertOutside, u as unlockScroll } from './shared/focus-C4tbSNND.js';
|
|
3
3
|
import '@jungherz-de/notionkit/notionkit-styles.js';
|
|
4
4
|
|
|
5
5
|
// <nk-peek id="peek" label="Database Table-View">
|
|
@@ -27,7 +27,8 @@ import '@jungherz-de/notionkit/notionkit-styles.js';
|
|
|
27
27
|
// Notion: from `min` (380) to `max` (all but 320px of the window). The width
|
|
28
28
|
// is the token --nk-peek-width, set on :root; `width` (px) sets it too, and
|
|
29
29
|
// nk-resize { width } fires when a drag or a key ends – the moment to keep
|
|
30
|
-
// it. resize-label names the edge (default "Resize"
|
|
30
|
+
// it. resize-label names the edge (default "Resize", in German "Breite
|
|
31
|
+
// ändern").
|
|
31
32
|
// `inset`: while it is open on the desktop, the page's <nk-app> gets
|
|
32
33
|
// `peek-inset` – its main column makes room instead of lying under the peek.
|
|
33
34
|
const CLOSE_ICON = '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="m6 17 5-5-5-5M13 17l5-5-5-5"/></svg>';
|
|
@@ -74,7 +75,7 @@ class NkPeek extends NkElement {
|
|
|
74
75
|
|
|
75
76
|
_syncResize() {
|
|
76
77
|
this._handle.hidden = !this.getBoolAttr('resizable');
|
|
77
|
-
this._handle.setAttribute('aria-label', this.getAttribute('resize-label') || '
|
|
78
|
+
this._handle.setAttribute('aria-label', this.getAttribute('resize-label') || this.str('resize'));
|
|
78
79
|
this._handle.setAttribute('aria-valuemin', this._min);
|
|
79
80
|
this._handle.setAttribute('aria-valuenow', Math.round(this.width));
|
|
80
81
|
}
|
|
@@ -91,7 +92,7 @@ class NkPeek extends NkElement {
|
|
|
91
92
|
_syncLabels() {
|
|
92
93
|
const label = this.getAttribute('label');
|
|
93
94
|
if (label) this._box.setAttribute('aria-label', label); else this._box.removeAttribute('aria-label');
|
|
94
|
-
this._close.setAttribute('aria-label', this.getAttribute('close-label') || '
|
|
95
|
+
this._close.setAttribute('aria-label', this.getAttribute('close-label') || this.str('close'));
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
_syncOpen() {
|
|
@@ -176,6 +177,8 @@ class NkPeek extends NkElement {
|
|
|
176
177
|
this._wasOpen = false;
|
|
177
178
|
}
|
|
178
179
|
|
|
180
|
+
onStringsChanged() { this._syncResize(); this._syncLabels(); }
|
|
181
|
+
|
|
179
182
|
onAttributeChanged(name, _old, value) {
|
|
180
183
|
if (name === 'width') { this._setWidth(Number(value)); return; }
|
|
181
184
|
if (name === 'inset') { this._syncInset(); return; }
|
|
@@ -9,8 +9,10 @@ import '@jungherz-de/notionkit/notionkit-styles.js';
|
|
|
9
9
|
// The light-DOM <option>s are copied into the shadow <select>. A
|
|
10
10
|
// MutationObserver keeps the copy in step when a framework swaps them; the
|
|
11
11
|
// empty string is a valid value; the live selection survives a rebuild. A
|
|
12
|
-
// value
|
|
13
|
-
//
|
|
12
|
+
// value – attribute or property – whose option is not there yet waits and
|
|
13
|
+
// wins over the browser's preselection once the option arrives, unless
|
|
14
|
+
// someone has chosen another option in the meantime; settling on it fires
|
|
15
|
+
// no nk-change.
|
|
14
16
|
class NkSelect extends NkFormElement {
|
|
15
17
|
static get observedAttributes() { return ['value', 'name', 'disabled', 'required', 'compact', 'wide', 'aria-label']; }
|
|
16
18
|
static get observesLightDom() { return true; }
|
|
@@ -20,6 +22,7 @@ class NkSelect extends NkFormElement {
|
|
|
20
22
|
this._forwardAll();
|
|
21
23
|
this._wrapper.appendChild(this._select);
|
|
22
24
|
this._defaultValue = this.getAttribute('value');
|
|
25
|
+
this._pending = this._defaultValue;
|
|
23
26
|
// Children may not be parsed yet when connectedCallback runs.
|
|
24
27
|
this.projectLightDom();
|
|
25
28
|
requestAnimationFrame(() => this.projectLightDom());
|
|
@@ -53,11 +56,11 @@ class NkSelect extends NkFormElement {
|
|
|
53
56
|
this._select.innerHTML = '';
|
|
54
57
|
for (const node of nodes) this._select.appendChild(node.cloneNode(true));
|
|
55
58
|
|
|
56
|
-
// A value that
|
|
57
|
-
//
|
|
58
|
-
// default (first option / `selected`).
|
|
59
|
-
if (this._pending != null
|
|
60
|
-
else
|
|
59
|
+
// A value that waits for its option first – it keeps waiting while the
|
|
60
|
+
// option is missing; else the live selection when it survived; else the
|
|
61
|
+
// browser default (first option / `selected`).
|
|
62
|
+
if (this._pending != null) { if (this._applyValue(this._pending)) this._pending = null; }
|
|
63
|
+
else this._applyValue(previous);
|
|
61
64
|
this._syncFormValue();
|
|
62
65
|
}
|
|
63
66
|
|
|
@@ -86,7 +89,8 @@ class NkSelect extends NkFormElement {
|
|
|
86
89
|
onAttributeChanged(name) {
|
|
87
90
|
if (!this._select) return;
|
|
88
91
|
if (name === 'value') {
|
|
89
|
-
this.
|
|
92
|
+
const value = this.getAttribute('value');
|
|
93
|
+
this._pending = value === null || this._applyValue(value) ? null : value;
|
|
90
94
|
this._syncFormValue();
|
|
91
95
|
return;
|
|
92
96
|
}
|
|
@@ -100,6 +104,7 @@ class NkSelect extends NkFormElement {
|
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
resetValue() {
|
|
107
|
+
this._pending = null;
|
|
103
108
|
if (!this._applyValue(this._defaultValue)) this._select.selectedIndex = 0;
|
|
104
109
|
this._syncFormValue();
|
|
105
110
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NkElement } from './base.js';
|
|
2
|
-
import { d as deepActiveElement, l as lockScroll, i as inertOutside, f as firstFocusable, u as unlockScroll } from './shared/focus-
|
|
2
|
+
import { d as deepActiveElement, l as lockScroll, i as inertOutside, f as firstFocusable, u as unlockScroll } from './shared/focus-C4tbSNND.js';
|
|
3
3
|
import '@jungherz-de/notionkit/notionkit-styles.js';
|
|
4
4
|
|
|
5
5
|
// <nk-sheet id="more" title="More">
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NkElement } from './base.js';
|
|
2
|
-
import { d as deepActiveElement } from './shared/focus-
|
|
2
|
+
import { d as deepActiveElement } from './shared/focus-C4tbSNND.js';
|
|
3
3
|
import '@jungherz-de/notionkit/notionkit-styles.js';
|
|
4
4
|
|
|
5
5
|
// <nk-sidebar slot="sidebar">
|
|
@@ -24,7 +24,8 @@ import '@jungherz-de/notionkit/notionkit-styles.js';
|
|
|
24
24
|
// brings it back; ⌘\ or Ctrl+\ toggles it (on a phone the drawer).
|
|
25
25
|
// `collapsed` is the state, collapse() / expand() / toggleCollapsed() the
|
|
26
26
|
// API, nk-collapse { collapsed } the moment to keep it. collapse-label names
|
|
27
|
-
// the « (default "Close sidebar"
|
|
27
|
+
// the « (default "Close sidebar", in German "Seitenleiste schließen") and is
|
|
28
|
+
// its tooltip for <nk-tooltip>.
|
|
28
29
|
const COLLAPSE_ICON = '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="m18 17-5-5 5-5M11 17l-5-5 5-5"/></svg>';
|
|
29
30
|
const phone = () => matchMedia('(max-width: 860px)').matches;
|
|
30
31
|
|
|
@@ -54,7 +55,7 @@ class NkSidebar extends NkElement {
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
_syncCollapse() {
|
|
57
|
-
const label = this.getAttribute('collapse-label') || '
|
|
58
|
+
const label = this.getAttribute('collapse-label') || this.str('closeSidebar');
|
|
58
59
|
this._collapse.hidden = !this.getBoolAttr('collapsible');
|
|
59
60
|
this._collapse.setAttribute('aria-label', label);
|
|
60
61
|
this._collapse.dataset.tooltip = label;
|
|
@@ -106,6 +107,8 @@ class NkSidebar extends NkElement {
|
|
|
106
107
|
document.removeEventListener('keydown', this._onKey);
|
|
107
108
|
}
|
|
108
109
|
|
|
110
|
+
onStringsChanged() { this._syncCollapse(); }
|
|
111
|
+
|
|
109
112
|
onAttributeChanged(name) {
|
|
110
113
|
if (name === 'open') {
|
|
111
114
|
this._syncOpen();
|
|
@@ -18,6 +18,12 @@ import '@jungherz-de/notionkit/notionkit-styles.js';
|
|
|
18
18
|
// nk-select { index, value, step } – index counts from 1, like `current` –
|
|
19
19
|
// and, unless cancelled, makes that step current. `horizontal` sets the
|
|
20
20
|
// steps in one row above a wizard.
|
|
21
|
+
// A step with `href` (1.17.0) shows its label as a link, <a class="st-label">,
|
|
22
|
+
// with or without `selectable` – to open a chapter in a new tab or copy its
|
|
23
|
+
// address. A plain click, or Enter, fires the same nk-select; cancelling it
|
|
24
|
+
// keeps the browser from following the link, for a router of your own. A
|
|
25
|
+
// middle click or one with Cmd, Ctrl, Shift or Alt fires nothing and does
|
|
26
|
+
// what a link does.
|
|
21
27
|
class NkSteps extends NkElement {
|
|
22
28
|
static get observedAttributes() { return ['steps', 'current', 'label', 'selectable', 'horizontal']; }
|
|
23
29
|
|
|
@@ -45,7 +51,7 @@ class NkSteps extends NkElement {
|
|
|
45
51
|
// Rebuilding drops the focused label; the new one at that place takes it back.
|
|
46
52
|
const focused = this.shadowRoot?.activeElement?.closest?.('li')?.dataset.index;
|
|
47
53
|
this._list.replaceChildren(...this._items().map((_, i) => {
|
|
48
|
-
const n = i + 1, { label: text, desc, state } = this._step(i);
|
|
54
|
+
const n = i + 1, { label: text, desc, state, href } = this._step(i);
|
|
49
55
|
// A state of its own wins; without one, the steps before `current` are done.
|
|
50
56
|
const done = state ? state === 'done' : n < current, skipped = state === 'skipped';
|
|
51
57
|
const li = this.createElement('li', ['nk-step'], { 'data-index': String(n) });
|
|
@@ -55,7 +61,8 @@ class NkSteps extends NkElement {
|
|
|
55
61
|
if (n === current) li.setAttribute('aria-current', 'step');
|
|
56
62
|
const mark = this.createElement('span', ['st-mark'], { 'aria-hidden': 'true' });
|
|
57
63
|
mark.textContent = done ? '✓' : skipped ? '–' : String(n);
|
|
58
|
-
const body =
|
|
64
|
+
const body = href != null && href !== '' ? this.createElement('a', ['st-label'], { href: String(href) })
|
|
65
|
+
: selectable ? this.createElement('button', ['st-label'], { type: 'button' }) : document.createElement('span');
|
|
59
66
|
body.textContent = text ?? '';
|
|
60
67
|
if (desc) { const d = this.createElement('span', ['st-desc']); d.textContent = desc; body.appendChild(d); }
|
|
61
68
|
li.append(mark, body);
|
|
@@ -66,9 +73,18 @@ class NkSteps extends NkElement {
|
|
|
66
73
|
|
|
67
74
|
setupEvents() {
|
|
68
75
|
this._onClick = (e) => {
|
|
69
|
-
if (!this.getBoolAttr('selectable')) return;
|
|
70
76
|
const li = e.target.closest?.('li.nk-step');
|
|
71
|
-
if (li
|
|
77
|
+
if (!li || !this._list.contains(li)) return;
|
|
78
|
+
const link = li.querySelector('a.st-label');
|
|
79
|
+
if (link) {
|
|
80
|
+
// The link contract: a plain left click is a selection, any other
|
|
81
|
+
// one the browser's. The mark beside the link counts as the link.
|
|
82
|
+
if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
83
|
+
if (!link.contains(e.target)) { link.click(); return; }
|
|
84
|
+
if (!this.select(Number(li.dataset.index))) e.preventDefault();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (this.getBoolAttr('selectable')) this.select(Number(li.dataset.index));
|
|
72
88
|
};
|
|
73
89
|
this._list.addEventListener('click', this._onClick);
|
|
74
90
|
}
|
|
@@ -15,8 +15,9 @@ class NkSynced extends NkElement {
|
|
|
15
15
|
this._sync();
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
_sync() { this._badge.textContent = this.getAttribute('badge') ?? '
|
|
18
|
+
_sync() { this._badge.textContent = this.getAttribute('badge') ?? this.str('synced'); }
|
|
19
19
|
onAttributeChanged() { this._sync(); }
|
|
20
|
+
onStringsChanged() { this._sync(); }
|
|
20
21
|
|
|
21
22
|
get badge() { return this.getAttribute('badge'); }
|
|
22
23
|
set badge(v) { this.setAttribute('badge', v); }
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NkElement } from './base.js';
|
|
2
|
-
import { c as compareBy, r as renderPropertyCell } from './shared/property-cell-
|
|
2
|
+
import { c as compareBy, r as renderPropertyCell } from './shared/property-cell-DcsfnUNF.js';
|
|
3
3
|
import '@jungherz-de/notionkit/notionkit-styles.js';
|
|
4
4
|
import './shared/avatar-CzPZN3uP.js';
|
|
5
5
|
import './shared/dates-a32DcW1l.js';
|
|
@@ -66,7 +66,7 @@ class NkTableView extends NkElement {
|
|
|
66
66
|
}
|
|
67
67
|
this._tbody.appendChild(r);
|
|
68
68
|
}
|
|
69
|
-
this._newRow.textContent = this.getAttribute('new-row-label') || '
|
|
69
|
+
this._newRow.textContent = this.getAttribute('new-row-label') || this.str('newPage');
|
|
70
70
|
this._newRow.style.display = this.getBoolAttr('new-row') ? '' : 'none';
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -116,6 +116,7 @@ class NkTableView extends NkElement {
|
|
|
116
116
|
|
|
117
117
|
_rowById(id) { return this._rows.find(r => String(r.id) === String(id)); }
|
|
118
118
|
onAttributeChanged() { this._render(); }
|
|
119
|
+
onStringsChanged() { this._render(); }
|
|
119
120
|
|
|
120
121
|
get name() { return this.getAttribute('name') || 'table'; }
|
|
121
122
|
get columns() { return this._columns; }
|
|
@@ -15,7 +15,7 @@ class NkThemeToggle extends NkElement {
|
|
|
15
15
|
|
|
16
16
|
render() {
|
|
17
17
|
this._btn = this.createElement('button', ['nk-topbar-btn', 'nk-theme-toggle'], { type: 'button' });
|
|
18
|
-
this.
|
|
18
|
+
this._syncTitle();
|
|
19
19
|
this._wrapper.appendChild(this._btn);
|
|
20
20
|
const root = document.documentElement;
|
|
21
21
|
let stored = null;
|
|
@@ -46,8 +46,11 @@ class NkThemeToggle extends NkElement {
|
|
|
46
46
|
window.removeEventListener('message', this._onMessage);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
_syncTitle() { this._btn.title = this.getAttribute('title') || this.str('toggleTheme'); }
|
|
50
|
+
onStringsChanged() { this._syncTitle(); }
|
|
51
|
+
|
|
49
52
|
onAttributeChanged(name) {
|
|
50
|
-
if (name === 'title' && this._btn) this.
|
|
53
|
+
if (name === 'title' && this._btn) this._syncTitle();
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
/** Sets the theme on <html>, persists it and reports it. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NkElement } from './base.js';
|
|
2
2
|
import { a as placeNear } from './shared/floating-DOK73b_D.js';
|
|
3
|
-
import { d as deepActiveElement } from './shared/focus-
|
|
3
|
+
import { d as deepActiveElement } from './shared/focus-C4tbSNND.js';
|
|
4
4
|
import '@jungherz-de/notionkit/notionkit-styles.js';
|
|
5
5
|
|
|
6
6
|
// <nk-tooltip></nk-tooltip> one for the page: every [data-tooltip]
|
|
@@ -34,7 +34,7 @@ class NkTreeItem extends NkElement {
|
|
|
34
34
|
this._labelSlot.appendChild(this._labelText);
|
|
35
35
|
this._label.appendChild(this._labelSlot);
|
|
36
36
|
this._actions = this.createElement('span', ['actions']);
|
|
37
|
-
for (const [action, glyph, title] of [['add', '+', '
|
|
37
|
+
for (const [action, glyph, title] of [['add', '+', this.str('add')], ['more', '⋯', this.str('more')]]) {
|
|
38
38
|
const b = this.createElement('span', [], { 'data-action': action, role: 'button', title });
|
|
39
39
|
b.textContent = glyph;
|
|
40
40
|
this._actions.appendChild(b);
|
|
@@ -120,6 +120,8 @@ class NkTreeItem extends NkElement {
|
|
|
120
120
|
this._row?.removeEventListener('keydown', this._onKey);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
onStringsChanged() { for (const b of this._actions.children) b.title = this.str(b.dataset.action); }
|
|
124
|
+
|
|
123
125
|
onAttributeChanged(name) {
|
|
124
126
|
if (name === 'label') this.assignSlots();
|
|
125
127
|
else this._sync();
|
|
@@ -15,7 +15,12 @@ function unlockScroll() {
|
|
|
15
15
|
if (locks > 0 && --locks === 0) document.documentElement.style.overflow = previousOverflow;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
// Floating layers under <body> that open from inside an overlay – a menu, a
|
|
19
|
+
// date picker – and the tooltip and toast stay usable: made inert, a date
|
|
20
|
+
// picker opened from a dialog showed but took no click.
|
|
21
|
+
const LAYERS = 'nk-menu[floating], nk-calendar[floating], nk-tooltip, nk-toast';
|
|
22
|
+
|
|
23
|
+
/** Makes every sibling along `el`'s ancestor chain inert (shadow hosts included), floating layers aside; returns the undo. */
|
|
19
24
|
function inertOutside(el) {
|
|
20
25
|
const made = [];
|
|
21
26
|
let node = el;
|
|
@@ -23,7 +28,7 @@ function inertOutside(el) {
|
|
|
23
28
|
const parent = node.parentNode instanceof ShadowRoot ? node.parentNode : node.parentNode;
|
|
24
29
|
if (!parent) break;
|
|
25
30
|
for (const sib of parent.children) {
|
|
26
|
-
if (sib === node || sib.inert || /^(SCRIPT|STYLE|LINK|TEMPLATE)$/.test(sib.tagName)) continue;
|
|
31
|
+
if (sib === node || sib.inert || /^(SCRIPT|STYLE|LINK|TEMPLATE)$/.test(sib.tagName) || sib.matches(LAYERS)) continue;
|
|
27
32
|
sib.inert = true;
|
|
28
33
|
made.push(sib);
|
|
29
34
|
}
|
|
@@ -16,6 +16,8 @@ import { r as resolveLocale } from './dates-a32DcW1l.js';
|
|
|
16
16
|
// text: a string, or { text, desc, color, tooltip, sort } – one of Notion's
|
|
17
17
|
// nine text colours for a tone, a quiet second line under it, the whole
|
|
18
18
|
// text in a tooltip (served by <nk-tooltip>), a value to sort by.
|
|
19
|
+
// progress: 0–100, the bar and its percentage as Intl writes it in
|
|
20
|
+
// column.locale, else the page's language ("45 %" in German).
|
|
19
21
|
// date: the value as given, or with column.format ('short', 'relative' or
|
|
20
22
|
// Intl.DateTimeFormat options) and column.locale formatted from an ISO date
|
|
21
23
|
// or date-time, D.M.YYYY, a Date or a timestamp; { start, end } is a range.
|
|
@@ -81,7 +83,7 @@ function renderPropertyCell(column, value, row = {}) {
|
|
|
81
83
|
if (type === 'actions') return actions(column, value);
|
|
82
84
|
if (value === undefined || value === null || value === '') {
|
|
83
85
|
if (type === 'checkbox') return checkbox(column, false, row);
|
|
84
|
-
if (type === 'progress') return progress(0);
|
|
86
|
+
if (type === 'progress') return progress(column, 0);
|
|
85
87
|
return el('span', type === 'person' ? 'person-cell' : null, type === 'text' && column.title ? '' : '—');
|
|
86
88
|
}
|
|
87
89
|
switch (type) {
|
|
@@ -113,7 +115,7 @@ function renderPropertyCell(column, value, row = {}) {
|
|
|
113
115
|
}
|
|
114
116
|
// column.locale / column.format: Intl.NumberFormat locale and options, e.g. { minimumFractionDigits: 1 }.
|
|
115
117
|
case 'number': return el('span', null, typeof value === 'number' ? value.toLocaleString(column.locale, column.format) : String(value));
|
|
116
|
-
case 'progress': return progress(Number(value) || 0);
|
|
118
|
+
case 'progress': return progress(column, Number(value) || 0);
|
|
117
119
|
default: {
|
|
118
120
|
const o = typeof value === 'object' ? value : { text: value };
|
|
119
121
|
let t;
|
|
@@ -159,15 +161,23 @@ function checkbox(column, checked, row) {
|
|
|
159
161
|
return label;
|
|
160
162
|
}
|
|
161
163
|
|
|
162
|
-
function progress(value) {
|
|
164
|
+
function progress(column, value) {
|
|
163
165
|
const frag = document.createDocumentFragment();
|
|
164
166
|
const bar = el('span', 'nk-progress');
|
|
165
167
|
const fill = el('i'); fill.style.width = `${Math.max(0, Math.min(100, value))}%`;
|
|
166
168
|
bar.appendChild(fill);
|
|
167
|
-
frag.append(bar, el('span', 'nk-progress-label',
|
|
169
|
+
frag.append(bar, el('span', 'nk-progress-label', formatPercent(column, value)));
|
|
168
170
|
return frag;
|
|
169
171
|
}
|
|
170
172
|
|
|
173
|
+
/** A progress value of 0–100 as Intl writes a percentage in column.locale, else the page's language: 45 → "45%", in German "45 %". */
|
|
174
|
+
function formatPercent(column, value) {
|
|
175
|
+
const n = Number(value) || 0;
|
|
176
|
+
try {
|
|
177
|
+
return new Intl.NumberFormat(column.locale || resolveLocale(), { style: 'percent', maximumFractionDigits: 0 }).format(n / 100);
|
|
178
|
+
} catch { return `${Math.round(n)}%`; } // a lang Intl does not take
|
|
179
|
+
}
|
|
180
|
+
|
|
171
181
|
/** A select's place among its options: the order Notion sorts by. */
|
|
172
182
|
function rankOf(column, value) {
|
|
173
183
|
const i = (column.options || []).findIndex(o => o.value === value || o.label === value);
|
|
@@ -201,4 +211,4 @@ function compareBy(column, dir = 1) {
|
|
|
201
211
|
};
|
|
202
212
|
}
|
|
203
213
|
|
|
204
|
-
export { textOf as a, compareBy as c,
|
|
214
|
+
export { textOf as a, formatDate as b, compareBy as c, formatPercent as f, renderPropertyCell as r, tagFor as t };
|