@jungherz-de/notionkit-elements 1.20.0 → 1.21.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 +61 -0
- package/README.md +6 -5
- package/SKILL.md +37 -34
- package/dist/components/base.js +2 -2
- package/dist/components/nk-table-view.js +46 -0
- package/dist/components/nk-tooltip.js +61 -5
- package/dist/notionkit-elements.esm.js +111 -9
- package/dist/notionkit-elements.esm.min.js +1 -1
- package/dist/notionkit-elements.esm.min.js.map +1 -1
- package/dist/notionkit-elements.js +111 -9
- package/dist/notionkit-elements.min.js +1 -1
- package/package.json +3 -3
- package/src/components/data/nk-table-view.js +46 -0
- package/src/components/overlays/nk-tooltip.js +61 -5
- package/src/util/strings.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,65 @@ All notable changes to NotionKit Elements are documented here. The format follow
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
|
|
5
5
|
[Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [1.21.0] – 2026-10-18
|
|
8
|
+
|
|
9
|
+
Built against NotionKit CSS 1.21.0 (peer `>= 1.21.0`).
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **Select all from the header of a checkbox column (#4).** A `checkbox`
|
|
13
|
+
column with `selectAll: true` is a selection column: its header holds the
|
|
14
|
+
cells' own checkbox instead of a name – empty when no row is chosen, a dash
|
|
15
|
+
for some, a check for all (`th.select-all`, NotionKit 1.21.0) – and sorts
|
|
16
|
+
nothing. A click or Space sets the column for every row the view has – a
|
|
17
|
+
dash selects all, as in Notion –, renders the cells again and fires **one**
|
|
18
|
+
`nk-change { key, value, all: true, rows }`, so an app that keeps its own
|
|
19
|
+
selection follows with one update instead of one per row; Space leaves the
|
|
20
|
+
focus on the header box. A row's own box keeps the header in step without
|
|
21
|
+
losing its focus. Without rows the header box is disabled. What "all" means
|
|
22
|
+
beyond the view's rows – more pages, a filter on the server – stays with
|
|
23
|
+
the app. Its accessible name is the new built-in text `selectAll`
|
|
24
|
+
("Select all" / "Alle auswählen"). Requested by Mailverse for its
|
|
25
|
+
quarantine list.
|
|
26
|
+
- `<nk-check indeterminate>` finally shows its mixed state – a dash in the
|
|
27
|
+
accent box (NotionKit 1.21.0); it looked empty before. The docs show it
|
|
28
|
+
next to the table's selection column.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
- Through NotionKit 1.21.0: a table row with a checkbox cell was 39.5px
|
|
32
|
+
instead of 36px; a selection column would have grown every row.
|
|
33
|
+
|
|
34
|
+
### Tests
|
|
35
|
+
- The parity test runs a script in the class markup too, for what only a
|
|
36
|
+
script sets – an `indeterminate` checkbox – as the docs page does.
|
|
37
|
+
|
|
38
|
+
## [1.20.1] – 2026-10-14
|
|
39
|
+
|
|
40
|
+
Elements only; NotionKit CSS stays at 1.20.0 (peer `>= 1.20.0`).
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
- **`<nk-tooltip>` follows the pointer and the focus inside a shadow root
|
|
44
|
+
(#3).** Moving from one `[data-tooltip]` to the next in the same shadow
|
|
45
|
+
root never updated the tooltip – the first one stayed, or none appeared –
|
|
46
|
+
for the pointer and for Tab alike; `<nk-copy-field icons secret>` kept
|
|
47
|
+
saying "Show" over Copy, an app's toolbar or chart bars in one root did
|
|
48
|
+
the same. `pointerover`, `focusin` and `focusout` carry a `relatedTarget`,
|
|
49
|
+
and when target and `relatedTarget` share a shadow tree the DOM standard
|
|
50
|
+
ends the event path at its host, so the listeners on the document never
|
|
51
|
+
heard of the move. The tooltip now also reads `pointermove` (no
|
|
52
|
+
`relatedTarget`, it always reaches the document) and acts only when the
|
|
53
|
+
element under the pointer changes, so a hand resting on the page leaves a
|
|
54
|
+
tooltip the keyboard or `show(rect)` opened alone; and it catches a key
|
|
55
|
+
that moved the focus – Tab, Option+Tab in Safari, the arrow keys of a
|
|
56
|
+
roving tab stop that moves the focus in its own `keydown` – on `keyup`,
|
|
57
|
+
against the focus recorded before the key went down. Nested shadow roots
|
|
58
|
+
are followed too. A focus move by script alone inside one shadow root
|
|
59
|
+
stays unseen. Reported by Mailverse.
|
|
60
|
+
- **Leaving the window** over a `[data-tooltip]` left its tooltip standing,
|
|
61
|
+
and one still waiting appeared after the pointer had gone. It now goes
|
|
62
|
+
with the pointer (`pointerout` without a `relatedTarget`); a tooltip the
|
|
63
|
+
keyboard or `show(rect)` opened is not the pointer's and stays. Found
|
|
64
|
+
while testing #3.
|
|
65
|
+
|
|
7
66
|
## [1.20.0] – 2026-10-12
|
|
8
67
|
|
|
9
68
|
Built against NotionKit CSS 1.20.0 (peer `>= 1.20.0`).
|
|
@@ -778,6 +837,8 @@ built and tested against NotionKit CSS 1.1.1 (peer range `>= 1.0.0`).
|
|
|
778
837
|
import, never in the core bundle – shadow-less, adding `nk-block-host` to
|
|
779
838
|
itself so the foundation's editor adapter rules apply.
|
|
780
839
|
|
|
840
|
+
[1.21.0]: https://github.com/JUNGHERZ/NotionKit-Elements/releases/tag/v1.21.0
|
|
841
|
+
[1.20.1]: https://github.com/JUNGHERZ/NotionKit-Elements/releases/tag/v1.20.1
|
|
781
842
|
[1.20.0]: https://github.com/JUNGHERZ/NotionKit-Elements/releases/tag/v1.20.0
|
|
782
843
|
[1.19.0]: https://github.com/JUNGHERZ/NotionKit-Elements/releases/tag/v1.19.0
|
|
783
844
|
[1.18.0]: https://github.com/JUNGHERZ/NotionKit-Elements/releases/tag/v1.18.0
|
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<h1 align="center">🧩 NotionKit Elements</h1>
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
<a href="https://www.npmjs.com/package/@jungherz-de/notionkit-elements"><img src="https://img.shields.io/badge/version-1.
|
|
4
|
+
<a href="https://www.npmjs.com/package/@jungherz-de/notionkit-elements"><img src="https://img.shields.io/badge/version-1.21.0-2383e2?style=flat-square" alt="Version"></a>
|
|
5
5
|
<a href="#"><img src="https://img.shields.io/badge/vanilla_JS-no_dependencies-448361?style=flat-square" alt="Vanilla JS"></a>
|
|
6
6
|
<a href="#"><img src="https://img.shields.io/badge/elements-88-529cca?style=flat-square" alt="88 Elements"></a>
|
|
7
7
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-9065b0?style=flat-square" alt="MIT License"></a>
|
|
8
|
-
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/changelog-v1.
|
|
8
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/changelog-v1.21.0-lightgrey?style=flat-square" alt="Changelog"></a>
|
|
9
9
|
<a href="https://www.npmjs.com/package/@jungherz-de/notionkit-elements"><img src="https://img.shields.io/badge/npm-%40jungherz--de%2Fnotionkit--elements-cb3837?style=flat-square&logo=npm" alt="npm"></a>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
@@ -71,8 +71,8 @@ It is the **app layer** of the NotionKit family – three layers, one design lan
|
|
|
71
71
|
<!DOCTYPE html>
|
|
72
72
|
<html lang="en" data-theme="light">
|
|
73
73
|
<head>
|
|
74
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.
|
|
75
|
-
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.
|
|
74
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.21.0/notionkit.min.css">
|
|
75
|
+
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.21.0/dist/notionkit-elements.min.js"></script>
|
|
76
76
|
</head>
|
|
77
77
|
<body class="nk-body">
|
|
78
78
|
<nk-field label="Display name" desc="Shown next to your comments">
|
|
@@ -104,7 +104,7 @@ Without a build step, an import map can point at the minified module instead: `"
|
|
|
104
104
|
|
|
105
105
|
Do not mix the full bundle with the per-component files: each brings its own `NkElement`. With the bundle, take `componentsSheet` and `NkElement` from the bundle (`NotionKitElements.componentsSheet` from the `<script>` build).
|
|
106
106
|
|
|
107
|
-
Two prerequisites, always: `notionkit.css` on the document (the peer dependency, `>= 1.
|
|
107
|
+
Two prerequisites, always: `notionkit.css` on the document (the peer dependency, `>= 1.21.0`; 1.21.0 brings the select-all header of a table and the dash of an indeterminate checkbox and keeps a row with a checkbox at 36px, 1.20.0 brings the appearance glyph of a three-state theme toggle, 1.19.1 keeps a toast with an × at its height, 1.19.0 brings the toast with an action, 1.18.0 brings a bar and its label in one row, stacked properties that keep to their card on a phone and icons in the copy field, 1.17.0 brings a step's label and a gallery card as links, 1.16.0 brings `--nk-block-space` and `flush` for blocks in a column, keeps a wide progress bar and a stretched button's label in shape and lays floating menus above dialogs, 1.15.0 brings table text with a tone and a second line, 1.14.0 brings the gallery view and a banner action that stands at the right edge again, 1.13.0 keeps fields inside narrow panels, leaves a page without icon its padding under the cover and makes cover heights tokens, 1.12.0 brings a tag or button beside a panel's title, lists and grids without outer margin, text values, steps with states in any order and in a row, scrolling tabs, a cap for full pages and buttons per table row, 1.11.0 keeps a floating menu inside an open modal or dialog in place and inside the window and brings the banner's action as a button, fields that share a row and tooltips of several lines, 1.10.1 lets a disabled button show its tooltip, 1.10.0 brings the collapsing sidebar, the resizable side peek, the dialog and the tooltip, 1.9.0 the date picker and the calendar view, 1.8.0 the side peek, the bookmark, the copy field and pictures on the profile row, 1.7.0 the sheet, menus that float in and become sheets on a phone, the sidebar drawer, the database toolbar with filter pills and the steps, 1.7.1 minified files that carry all of it, 1.6.0 page properties, page options, list view, panels, prose and the avatar, 1.5.1 the safe areas, 1.5.0 the Notion-2025 tokens, the nine tag colours and the filled inputs; from 1.5.0 on, Elements and the foundation share one version number – the elements are built and tested against the same release) and `class="nk-body"` on `<body>`. The elements ship no visual CSS of their own – every rule comes from the foundation. The bundle injects the design tokens once as `@layer notionkit-defaults`, so any plain `:root { --nk-accent: … }` of yours re-brands every element in both themes.
|
|
108
108
|
|
|
109
109
|
## Elements
|
|
110
110
|
|
|
@@ -161,6 +161,7 @@ The elements on the page take new texts at once, after `setStrings()` and when `
|
|
|
161
161
|
| `commandPlaceholder` | `nk-cmdk` | `placeholder` | Search or type a command … | Suchen oder Befehl eingeben … |
|
|
162
162
|
| `emojiPlaceholder` | `nk-emoji-picker` | `placeholder` | Search… | Suchen … |
|
|
163
163
|
| `toggleTheme` | `nk-theme-toggle` | `title` | Toggle light / dark | Hell / Dunkel |
|
|
164
|
+
| `selectAll` | `nk-table-view` (a `checkbox` column with `selectAll`) | – | Select all | Alle auswählen |
|
|
164
165
|
| `appearance` | `nk-theme-toggle` (`modes` with `auto`) | `title` | Appearance: {mode} – click: {next} | Darstellung: {mode} – Klick: {next} |
|
|
165
166
|
| `themeAuto` | `nk-theme-toggle` (`modes` with `auto`) | – | automatic (follows the system) | automatisch (wie das System) |
|
|
166
167
|
| `themeLight` | `nk-theme-toggle` (`modes` with `auto`) | – | light | hell |
|
package/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: notionkit-elements
|
|
3
|
-
description: NotionKit Elements is a vanilla-JS Web Components library (v1.
|
|
3
|
+
description: NotionKit Elements is a vanilla-JS Web Components library (v1.21.0) wrapping NotionKit CSS v1.21.0 – the calm, document-centric design system in the Notion idiom. 88 custom elements with the `nk-` prefix, Shadow DOM, automatic light/dark sync via data-theme on <html>, and form-associated controls. Use this reference whenever generating HTML that uses <nk-*> tags to get attributes, slots, events and composition right.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# NotionKit Elements – AI Component Reference
|
|
@@ -21,8 +21,8 @@ description: NotionKit Elements is a vanilla-JS Web Components library (v1.20.0)
|
|
|
21
21
|
<head>
|
|
22
22
|
<meta charset="UTF-8">
|
|
23
23
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
24
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.
|
|
25
|
-
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.
|
|
24
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.21.0/notionkit.min.css">
|
|
25
|
+
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.21.0/dist/notionkit-elements.min.js"></script>
|
|
26
26
|
</head>
|
|
27
27
|
<body class="nk-body">
|
|
28
28
|
<nk-btn variant="primary">Save</nk-btn>
|
|
@@ -412,9 +412,10 @@ Renders `button.nk-switch[role=switch]`; the stylesheet keys the knob on `aria-c
|
|
|
412
412
|
|
|
413
413
|
### 3.9 `<nk-check>` – Checkbox
|
|
414
414
|
|
|
415
|
-
A `label.nk-check` with a custom-drawn checkbox; the label text is slotted, so clicking it toggles the box.
|
|
415
|
+
A `label.nk-check` with a custom-drawn checkbox; the label text is slotted, so clicking it toggles the box. `indeterminate` shows a dash (NotionKit 1.21.0) – for a box over a group partly chosen.
|
|
416
416
|
|
|
417
417
|
```html
|
|
418
|
+
<nk-check indeterminate>All</nk-check>
|
|
418
419
|
<nk-check name="digest" value="weekly" checked>Weekly digest</nk-check>
|
|
419
420
|
<nk-check name="digest" value="mentions">Mentions only</nk-check>
|
|
420
421
|
```
|
|
@@ -437,6 +438,7 @@ A `label.nk-check` with a custom-drawn checkbox; the label text is slotted, so c
|
|
|
437
438
|
|
|
438
439
|
```html
|
|
439
440
|
<!-- equivalent class markup -->
|
|
441
|
+
<label class="nk-check"><input type="checkbox">All</label><script>document.currentScript.previousElementSibling.querySelector('input').indeterminate = true</script>
|
|
440
442
|
<label class="nk-check"><input type="checkbox" name="digest" value="weekly" checked>Weekly digest</label>
|
|
441
443
|
<label class="nk-check"><input type="checkbox" name="digest" value="mentions">Mentions only</label>
|
|
442
444
|
```
|
|
@@ -2562,7 +2564,7 @@ One inverted pill at the bottom centre, above every overlay; over a tab bar at t
|
|
|
2562
2564
|
|
|
2563
2565
|
### 3.76 `<nk-tooltip>` – Tooltip
|
|
2564
2566
|
|
|
2565
|
-
Notion’s hover hint in the toast’s colours, a shortcut muted beside it. One `<nk-tooltip>` without `for` serves every element with `data-tooltip` (and `data-tooltip-key`) on the page, inside shadow roots too – a whole toolbar in one element; with `for` it belongs to one element and shows its own content and `shortcut`. It appears after `delay` ms (400) under the pointer and at once on keyboard focus, never on touch; leaving
|
|
2567
|
+
Notion’s hover hint in the toast’s colours, a shortcut muted beside it. One `<nk-tooltip>` without `for` serves every element with `data-tooltip` (and `data-tooltip-key`) on the page, inside shadow roots too – a whole toolbar in one element, and it follows pointer and keyboard from one such element to the next within the same shadow root; with `for` it belongs to one element and shows its own content and `shortcut`. It appears after `delay` ms (400) under the pointer and at once on keyboard focus, never on touch; leaving – the window too –, a press, blur, scrolling and Escape hide it. It sits 6px below its target and centred, above it where the window ends, 8px inside the window – `placeNear` in `util/floating.js`. `show(target, text, shortcut)` takes an element or a rect, for what has no element of its own: the bars of a chart. The target’s `aria-describedby` names it while it shows. Hover the buttons. A tooltip shown with `show(rect, …)` stays until `hide()`, the pointer on another `[data-tooltip]`, a press or Escape; the wheel hides it too, also inside a shadow root. A line break in the text is kept.
|
|
2566
2568
|
|
|
2567
2569
|
```html
|
|
2568
2570
|
<div style="display:flex;gap:16px;align-items:center;padding:4px 0 44px">
|
|
@@ -2659,13 +2661,14 @@ The view switcher with Notion’s toolbar: child views (`nk-table-view`, `nk-boa
|
|
|
2659
2661
|
|
|
2660
2662
|
### 3.78 `<nk-table-view>` – Table view
|
|
2661
2663
|
|
|
2662
|
-
Renders `columns` × `rows` as the NotionKit table. Cells are polymorphic (`text`, `select`, `multi-select`, `date`, `person`, `checkbox`, `url`, `number`, `progress`) and rendered as plain markup by the exported `renderPropertyCell()` – every cell rule starts with `.nk-table`, so a cell element of its own would never be styled. Header clicks sort with `sortable`. A `number` column stands right-aligned in figures of equal width, formatted by its `locale` and `format` (Intl.NumberFormat options); a person’s `color` takes one of the nine names. A column of type `actions` (NotionKit 1.12.0) sets buttons in each row from `column.actions` – `[{ action, label, icon, danger, disabled, tooltip }]` –, and a row’s value – a list of action names – picks which of them it shows; a click fires `nk-action { action, row, id, anchor }` instead of selecting the row. A `url` value may be `{ href, label, target }`: a link of your own, to another page of the app, with its own text. A text value may be `{ text, desc, color, tooltip }` (NotionKit 1.15.0): a quiet second line, one of Notion’s nine text colours – `orange` for an error –, the whole text in a tooltip. Sorting goes by the value, not the text shown: dates by their time, selects by the order of their options, empty cells last; `sortKey` on a column sorts by another field of the row, a `sort` in a cell’s object by that value. A `date` column with `format` – `'short'`, `'relative'` or the options of Intl.DateTimeFormat – shows ISO dates and date-times formatted in its `locale`.
|
|
2664
|
+
Renders `columns` × `rows` as the NotionKit table. Cells are polymorphic (`text`, `select`, `multi-select`, `date`, `person`, `checkbox`, `url`, `number`, `progress`) and rendered as plain markup by the exported `renderPropertyCell()` – every cell rule starts with `.nk-table`, so a cell element of its own would never be styled. Header clicks sort with `sortable`. A `number` column stands right-aligned in figures of equal width, formatted by its `locale` and `format` (Intl.NumberFormat options); a person’s `color` takes one of the nine names. A column of type `actions` (NotionKit 1.12.0) sets buttons in each row from `column.actions` – `[{ action, label, icon, danger, disabled, tooltip }]` –, and a row’s value – a list of action names – picks which of them it shows; a click fires `nk-action { action, row, id, anchor }` instead of selecting the row. A `url` value may be `{ href, label, target }`: a link of your own, to another page of the app, with its own text. A text value may be `{ text, desc, color, tooltip }` (NotionKit 1.15.0): a quiet second line, one of Notion’s nine text colours – `orange` for an error –, the whole text in a tooltip. Sorting goes by the value, not the text shown: dates by their time, selects by the order of their options, empty cells last; `sortKey` on a column sorts by another field of the row, a `sort` in a cell’s object by that value. A `date` column with `format` – `'short'`, `'relative'` or the options of Intl.DateTimeFormat – shows ISO dates and date-times formatted in its `locale`. A `checkbox` column with `selectAll: true` (1.21.0) is a selection column: its header is a checkbox – empty, a dash for some rows, a check for all – that sorts nothing; a click or Space sets the column for every row the view has (a dash selects all, as in Notion) and fires one `nk-change { key, value, all: true, rows }`. What “all” means beyond these rows – more pages, a filter on the server – stays with the app. Its name comes from the texts (`selectAll`).
|
|
2663
2665
|
|
|
2664
2666
|
```html
|
|
2665
2667
|
<nk-table-view new-row sortable></nk-table-view>
|
|
2666
2668
|
<script>{
|
|
2667
2669
|
const db = document.currentScript.previousElementSibling;
|
|
2668
2670
|
db.columns = [
|
|
2671
|
+
{ key: 'selected', type: 'checkbox', selectAll: true },
|
|
2669
2672
|
{ key: 'name', label: 'Name', type: 'text', icon: '📄', title: true },
|
|
2670
2673
|
{ key: 'status', label: 'Status', type: 'select', icon: '◉', options: [
|
|
2671
2674
|
{ value: 'planned', label: 'Planned', color: 'orange' }, { value: 'progress', label: 'In progress', color: 'blue' }, { value: 'done', label: 'Done', color: 'green' } ] },
|
|
@@ -2676,9 +2679,9 @@ Renders `columns` × `rows` as the NotionKit table. Cells are polymorphic (`text
|
|
|
2676
2679
|
{ key: 'actions', type: 'actions', actions: [{ action: 'open', label: 'Open' }, { action: 'archive', label: 'Archive', danger: true }] },
|
|
2677
2680
|
];
|
|
2678
2681
|
db.rows = [
|
|
2679
|
-
{ id: 1, icon: '🧭', name: { text: 'App shell & sidebar', desc: 'Three open questions' }, status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '08.05.2026', progress: 100, effort: 6, cover: '/covers/aurora.svg' },
|
|
2682
|
+
{ id: 1, icon: '🧭', name: { text: 'App shell & sidebar', desc: 'Three open questions' }, status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '08.05.2026', progress: 100, effort: 6, cover: '/covers/aurora.svg', selected: true },
|
|
2680
2683
|
{ id: 2, icon: '📄', name: 'Page shell & typography', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '10.05.2026', progress: 100, effort: 4.5, cover: '/covers/dunes.svg' },
|
|
2681
|
-
{ id: 3, icon: '🗃️', name: 'Database table view', status: 'progress', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '20.05.2026', progress: 65, effort: 12.5, cover: '/covers/meadow.svg' },
|
|
2684
|
+
{ id: 3, icon: '🗃️', name: 'Database table view', status: 'progress', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '20.05.2026', progress: 65, effort: 12.5, cover: '/covers/meadow.svg', selected: true },
|
|
2682
2685
|
{ id: 4, icon: '▤', name: 'Board view & drag-and-drop', status: 'planned', due: '02.06.2026', progress: 0, effort: 8, actions: ['open'], cover: '/covers/tide.svg' },
|
|
2683
2686
|
];
|
|
2684
2687
|
}</script>
|
|
@@ -2697,23 +2700,23 @@ Renders `columns` × `rows` as the NotionKit table. Cells are polymorphic (`text
|
|
|
2697
2700
|
| `sort-dir` | asc | desc | – | Direction. |
|
|
2698
2701
|
| `wrap` | boolean | – | Cell text may break (Notion's "wrap column"). |
|
|
2699
2702
|
|
|
2700
|
-
**Events:** `nk-select` `{ row, id, key, cell }` – Row clicked. · `nk-change` `{ row, key, value }` – Checkbox cell toggled (row updated in place). · `nk-action` `{ action: 'sort' | 'new-row' | an actions column's action, key?, value?, row?, id?, anchor? }` – Header, add row or a row’s button clicked.
|
|
2703
|
+
**Events:** `nk-select` `{ row, id, key, cell }` – Row clicked. · `nk-change` `{ row, key, value } · selectAll: { key, value, all: true, rows }` – Checkbox cell toggled (row updated in place); from a selectAll header once for every row. · `nk-action` `{ action: 'sort' | 'new-row' | an actions column's action, key?, value?, row?, id?, anchor? }` – Header, add row or a row’s button clicked.
|
|
2701
2704
|
|
|
2702
2705
|
**Properties:** `columns`, `rows`, `data` · **Methods:** `refresh()`
|
|
2703
2706
|
|
|
2704
|
-
**Replaces:** `.nk-table-wrap`, `.nk-table`, `.wrap`, `.th-icon`, `.row-title`, `.date-cell`, `.person-cell`, `.nk-avatar`, `.num`, `.row-actions`, `.actions`, `.td-text`, `.td-desc`, `.nk-new-row`
|
|
2707
|
+
**Replaces:** `.nk-table-wrap`, `.nk-table`, `.wrap`, `.th-icon`, `.row-title`, `.date-cell`, `.person-cell`, `.nk-avatar`, `.num`, `.row-actions`, `.actions`, `.select-all`, `.nk-check`, `.td-text`, `.td-desc`, `.nk-new-row`
|
|
2705
2708
|
|
|
2706
2709
|
```html
|
|
2707
2710
|
<!-- equivalent class markup -->
|
|
2708
2711
|
<div class="nk-table-wrap"><table class="nk-table">
|
|
2709
|
-
<thead><tr><th><span class="th-icon">📄</span>Name</th><th><span class="th-icon">◉</span>Status</th><th><span class="th-icon">👤</span>Owner</th><th><span class="th-icon">📅</span>Due</th><th><span class="th-icon">▰</span>Progress</th><th><span class="th-icon">#</span>Effort (h)</th><th class="actions"></th></tr></thead>
|
|
2712
|
+
<thead><tr><th class="select-all"><label class="nk-check"><input type="checkbox" aria-label="Select all"></label></th><th><span class="th-icon">📄</span>Name</th><th><span class="th-icon">◉</span>Status</th><th><span class="th-icon">👤</span>Owner</th><th><span class="th-icon">📅</span>Due</th><th><span class="th-icon">▰</span>Progress</th><th><span class="th-icon">#</span>Effort (h)</th><th class="actions"></th></tr></thead>
|
|
2710
2713
|
<tbody>
|
|
2711
|
-
<tr><td><span class="row-title">🧭 App shell & sidebar</span><span class="td-desc">Three open questions</span></td><td><span class="nk-tag green">Done</span></td><td><span class="person-cell"><span class="nk-avatar small purple">MK</span> Marcel</span></td><td><span class="date-cell">08.05.2026</span></td><td><span class="nk-progress"><i style="width:100%"></i></span><span class="nk-progress-label">100%</span></td><td class="num"><span>6.0</span></td><td><span class="row-actions"><button class="nk-btn secondary small">Open</button><button class="nk-btn danger small">Archive</button></span></td></tr>
|
|
2712
|
-
<tr><td><span class="row-title">📄 Page shell & typography</span></td><td><span class="nk-tag green">Done</span></td><td><span class="person-cell"><span class="nk-avatar small purple">MK</span> Marcel</span></td><td><span class="date-cell">10.05.2026</span></td><td><span class="nk-progress"><i style="width:100%"></i></span><span class="nk-progress-label">100%</span></td><td class="num"><span>4.5</span></td><td><span class="row-actions"><button class="nk-btn secondary small">Open</button><button class="nk-btn danger small">Archive</button></span></td></tr>
|
|
2713
|
-
<tr><td><span class="row-title">🗃️ Database table view</span></td><td><span class="nk-tag blue">In progress</span></td><td><span class="person-cell"><span class="nk-avatar small purple">MK</span> Marcel</span></td><td><span class="date-cell">20.05.2026</span></td><td><span class="nk-progress"><i style="width:65%"></i></span><span class="nk-progress-label">65%</span></td><td class="num"><span>12.5</span></td><td><span class="row-actions"><button class="nk-btn secondary small">Open</button><button class="nk-btn danger small">Archive</button></span></td></tr>
|
|
2714
|
-
<tr><td><span class="row-title">▤ Board view & drag-and-drop</span></td><td><span class="nk-tag orange">Planned</span></td><td><span class="person-cell">—</span></td><td><span class="date-cell">02.06.2026</span></td><td><span class="nk-progress"><i style="width:0%"></i></span><span class="nk-progress-label">0%</span></td><td class="num"><span>8.0</span></td><td><span class="row-actions"><button class="nk-btn secondary small">Open</button></span></td></tr>
|
|
2714
|
+
<tr><td><label class="nk-check"><input type="checkbox" checked></label></td><td><span class="row-title">🧭 App shell & sidebar</span><span class="td-desc">Three open questions</span></td><td><span class="nk-tag green">Done</span></td><td><span class="person-cell"><span class="nk-avatar small purple">MK</span> Marcel</span></td><td><span class="date-cell">08.05.2026</span></td><td><span class="nk-progress"><i style="width:100%"></i></span><span class="nk-progress-label">100%</span></td><td class="num"><span>6.0</span></td><td><span class="row-actions"><button class="nk-btn secondary small">Open</button><button class="nk-btn danger small">Archive</button></span></td></tr>
|
|
2715
|
+
<tr><td><label class="nk-check"><input type="checkbox"></label></td><td><span class="row-title">📄 Page shell & typography</span></td><td><span class="nk-tag green">Done</span></td><td><span class="person-cell"><span class="nk-avatar small purple">MK</span> Marcel</span></td><td><span class="date-cell">10.05.2026</span></td><td><span class="nk-progress"><i style="width:100%"></i></span><span class="nk-progress-label">100%</span></td><td class="num"><span>4.5</span></td><td><span class="row-actions"><button class="nk-btn secondary small">Open</button><button class="nk-btn danger small">Archive</button></span></td></tr>
|
|
2716
|
+
<tr><td><label class="nk-check"><input type="checkbox" checked></label></td><td><span class="row-title">🗃️ Database table view</span></td><td><span class="nk-tag blue">In progress</span></td><td><span class="person-cell"><span class="nk-avatar small purple">MK</span> Marcel</span></td><td><span class="date-cell">20.05.2026</span></td><td><span class="nk-progress"><i style="width:65%"></i></span><span class="nk-progress-label">65%</span></td><td class="num"><span>12.5</span></td><td><span class="row-actions"><button class="nk-btn secondary small">Open</button><button class="nk-btn danger small">Archive</button></span></td></tr>
|
|
2717
|
+
<tr><td><label class="nk-check"><input type="checkbox"></label></td><td><span class="row-title">▤ Board view & drag-and-drop</span></td><td><span class="nk-tag orange">Planned</span></td><td><span class="person-cell">—</span></td><td><span class="date-cell">02.06.2026</span></td><td><span class="nk-progress"><i style="width:0%"></i></span><span class="nk-progress-label">0%</span></td><td class="num"><span>8.0</span></td><td><span class="row-actions"><button class="nk-btn secondary small">Open</button></span></td></tr>
|
|
2715
2718
|
</tbody>
|
|
2716
|
-
</table><div class="nk-new-row">+ New page</div></div>
|
|
2719
|
+
</table><div class="nk-new-row">+ New page</div></div><script>document.currentScript.previousElementSibling.querySelector('th.select-all input').indeterminate = true</script>
|
|
2717
2720
|
```
|
|
2718
2721
|
|
|
2719
2722
|
**Small screens:** Scrolls horizontally inside `.nk-table-wrap`.
|
|
@@ -3152,8 +3155,8 @@ Eight skeletons, one per app shape, mirroring the NotionKit CSS SKILL.md. Copy o
|
|
|
3152
3155
|
<html lang="en" data-theme="light">
|
|
3153
3156
|
<head>
|
|
3154
3157
|
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
3155
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.
|
|
3156
|
-
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.
|
|
3158
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.21.0/notionkit.min.css">
|
|
3159
|
+
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.21.0/dist/notionkit-elements.min.js"></script>
|
|
3157
3160
|
</head>
|
|
3158
3161
|
<body class="nk-body">
|
|
3159
3162
|
<nk-app>
|
|
@@ -3234,8 +3237,8 @@ Rules of the shell: `nk-sidebar`, `nk-topbar` and `nk-page` are `display: conten
|
|
|
3234
3237
|
<html lang="en" data-theme="light">
|
|
3235
3238
|
<head>
|
|
3236
3239
|
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
3237
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.
|
|
3238
|
-
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.
|
|
3240
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.21.0/notionkit.min.css">
|
|
3241
|
+
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.21.0/dist/notionkit-elements.min.js"></script>
|
|
3239
3242
|
</head>
|
|
3240
3243
|
<body class="nk-body">
|
|
3241
3244
|
<nk-app>
|
|
@@ -3342,8 +3345,8 @@ Data contract: `columns` describe the properties (`type`: text | select | multi-
|
|
|
3342
3345
|
<html lang="en" data-theme="light">
|
|
3343
3346
|
<head>
|
|
3344
3347
|
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
3345
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.
|
|
3346
|
-
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.
|
|
3348
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.21.0/notionkit.min.css">
|
|
3349
|
+
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.21.0/dist/notionkit-elements.min.js"></script>
|
|
3347
3350
|
</head>
|
|
3348
3351
|
<body class="nk-body">
|
|
3349
3352
|
<nk-app>
|
|
@@ -3402,8 +3405,8 @@ Data contract: `columns` describe the properties (`type`: text | select | multi-
|
|
|
3402
3405
|
<html lang="en" data-theme="light">
|
|
3403
3406
|
<head>
|
|
3404
3407
|
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
3405
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.
|
|
3406
|
-
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.
|
|
3408
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.21.0/notionkit.min.css">
|
|
3409
|
+
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.21.0/dist/notionkit-elements.min.js"></script>
|
|
3407
3410
|
</head>
|
|
3408
3411
|
<body class="nk-body">
|
|
3409
3412
|
<!-- your app -->
|
|
@@ -3480,8 +3483,8 @@ The open/close contract is one attribute: `settings.open = true`, `settings.show
|
|
|
3480
3483
|
<html lang="en" data-theme="light">
|
|
3481
3484
|
<head>
|
|
3482
3485
|
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
3483
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.
|
|
3484
|
-
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.
|
|
3486
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.21.0/notionkit.min.css">
|
|
3487
|
+
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.21.0/dist/notionkit-elements.min.js"></script>
|
|
3485
3488
|
</head>
|
|
3486
3489
|
<body class="nk-body">
|
|
3487
3490
|
<div class="nk-page" style="padding-top:48px">
|
|
@@ -3527,8 +3530,8 @@ The open/close contract is one attribute: `settings.open = true`, `settings.show
|
|
|
3527
3530
|
<html lang="en" data-theme="light">
|
|
3528
3531
|
<head>
|
|
3529
3532
|
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
3530
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.
|
|
3531
|
-
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.
|
|
3533
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.21.0/notionkit.min.css">
|
|
3534
|
+
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.21.0/dist/notionkit-elements.min.js"></script>
|
|
3532
3535
|
</head>
|
|
3533
3536
|
<body class="nk-body">
|
|
3534
3537
|
<nk-page narrow icon="📘" cover>
|
|
@@ -3572,8 +3575,8 @@ Note `narrow`: the page is the document, so there is no inner scroll wrapper –
|
|
|
3572
3575
|
<html lang="en" data-theme="light">
|
|
3573
3576
|
<head>
|
|
3574
3577
|
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
3575
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.
|
|
3576
|
-
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.
|
|
3578
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.21.0/notionkit.min.css">
|
|
3579
|
+
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.21.0/dist/notionkit-elements.min.js"></script>
|
|
3577
3580
|
</head>
|
|
3578
3581
|
<body class="nk-body">
|
|
3579
3582
|
<nk-app>
|
|
@@ -3627,8 +3630,8 @@ Note `narrow`: the page is the document, so there is no inner scroll wrapper –
|
|
|
3627
3630
|
<html lang="en" data-theme="light">
|
|
3628
3631
|
<head>
|
|
3629
3632
|
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
3630
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.
|
|
3631
|
-
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.
|
|
3633
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.21.0/notionkit.min.css">
|
|
3634
|
+
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.21.0/dist/notionkit-elements.min.js"></script>
|
|
3632
3635
|
</head>
|
|
3633
3636
|
<body class="nk-body">
|
|
3634
3637
|
<!-- A narrow column, centred: layout is yours, so it is inline. -->
|
|
@@ -3839,10 +3842,10 @@ Form controls additionally re-dispatch a native, bubbling `change` event, so `fo
|
|
|
3839
3842
|
| Texts | `src/util/strings.js` – the English and German dictionary and `setStrings()`; `NkElement#str(key)` reads it in the element's language, `onStringsChanged()` runs after `setStrings()` and when `<html lang>` changes |
|
|
3840
3843
|
| Components | `src/components/{forms,content,shell,page,overlays,data}/nk-*.js`, one tag per file, `customElements.define` at the bottom |
|
|
3841
3844
|
| Build | Rollup: IIFE, minified IIFE, ESM, and per-component ESM entries on a stable `dist/components/base.js` that import NotionKit's sheet (`@jungherz-de/notionkit/notionkit-styles.js`) instead of inlining it; the full bundles inline it and export `componentsSheet` |
|
|
3842
|
-
| Peer | `@jungherz-de/notionkit >= 1.
|
|
3845
|
+
| Peer | `@jungherz-de/notionkit >= 1.21.0` – from 1.5.0 on the elements and the foundation share one version number; the bundle embeds that release's stylesheet, so keep them in step |
|
|
3843
3846
|
|
|
3844
3847
|
Lifecycle: construct (attach shadow, adopt sheets) → first connect (wrapper + `render()`) → every connect (`setupEvents()`, theme registration, light-DOM observer) → `attributeChangedCallback` → `onAttributeChanged` → disconnect (`teardownEvents()`, unregister).
|
|
3845
3848
|
|
|
3846
3849
|
|
|
3847
3850
|
---
|
|
3848
|
-
*NotionKit Elements v1.
|
|
3851
|
+
*NotionKit Elements v1.21.0 · wrapping NotionKit CSS v1.21.0 · MIT · Jungherz GmbH*
|
package/dist/components/base.js
CHANGED
|
@@ -21,7 +21,7 @@ const BUILT_IN = {
|
|
|
21
21
|
appearance: 'Appearance: {mode} – click: {next}', themeAuto: 'automatic (follows the system)', themeLight: 'light', themeDark: 'dark',
|
|
22
22
|
message: 'Message', breadcrumb: 'Breadcrumb', commandPalette: 'Command palette', comment: 'Comment',
|
|
23
23
|
searchEmoji: 'Search emoji', settings: 'Settings', title: 'Title', changeIcon: 'Change icon',
|
|
24
|
-
add: 'Add', more: 'More',
|
|
24
|
+
add: 'Add', more: 'More', selectAll: 'Select all',
|
|
25
25
|
},
|
|
26
26
|
de: {
|
|
27
27
|
copy: 'Kopieren', copied: 'Kopiert', show: 'Zeigen', hide: 'Verbergen',
|
|
@@ -36,7 +36,7 @@ const BUILT_IN = {
|
|
|
36
36
|
appearance: 'Darstellung: {mode} – Klick: {next}', themeAuto: 'automatisch (wie das System)', themeLight: 'hell', themeDark: 'dunkel',
|
|
37
37
|
message: 'Nachricht', breadcrumb: 'Pfad', commandPalette: 'Befehlspalette', comment: 'Kommentar',
|
|
38
38
|
searchEmoji: 'Emoji suchen', settings: 'Einstellungen', title: 'Titel', changeIcon: 'Symbol ändern',
|
|
39
|
-
add: 'Hinzufügen', more: 'Mehr',
|
|
39
|
+
add: 'Hinzufügen', more: 'Mehr', selectAll: 'Alle auswählen',
|
|
40
40
|
},
|
|
41
41
|
};
|
|
42
42
|
const custom = {};
|
|
@@ -16,6 +16,15 @@ import './shared/dates-a32DcW1l.js';
|
|
|
16
16
|
// type 'actions' (NotionKit 1.12.0) sets buttons in each row; a click on one
|
|
17
17
|
// fires nk-action { action, row, id, anchor } instead of selecting the row,
|
|
18
18
|
// and its header sorts nothing.
|
|
19
|
+
//
|
|
20
|
+
// A checkbox column with `selectAll: true` (1.21.0) is a selection column:
|
|
21
|
+
// its header holds a checkbox instead of a name – empty, a dash for some
|
|
22
|
+
// rows, a check for all – and sorts nothing (th.select-all, NotionKit
|
|
23
|
+
// 1.21.0). A click or Space sets the column for every row the view has –
|
|
24
|
+
// a dash selects all, as Notion does –, renders again and fires one
|
|
25
|
+
// nk-change { key, value, all: true, rows }, so an app that keeps its own
|
|
26
|
+
// selection follows with one update. What "all" means beyond these rows –
|
|
27
|
+
// more pages, a filter on the server – stays with the app.
|
|
19
28
|
class NkTableView extends NkElement {
|
|
20
29
|
static get observedAttributes() { return ['name', 'label', 'badge', 'count', 'new-row', 'new-row-label', 'sortable', 'sort-key', 'sort-dir', 'wrap']; }
|
|
21
30
|
|
|
@@ -45,6 +54,7 @@ class NkTableView extends NkElement {
|
|
|
45
54
|
this._table.classList.toggle('wrap', this.getBoolAttr('wrap'));
|
|
46
55
|
const tr = document.createElement('tr');
|
|
47
56
|
for (const col of this._columns) {
|
|
57
|
+
if (col.type === 'checkbox' && col.selectAll) { tr.appendChild(this._selectAllHeader(col)); continue; }
|
|
48
58
|
const actions = col.type === 'actions';
|
|
49
59
|
const th = this.createElement('th', actions ? ['actions'] : [], actions ? { scope: 'col' } : { 'data-key': col.key, scope: 'col' });
|
|
50
60
|
if (col.icon) { const i = this.createElement('span', ['th-icon']); i.textContent = col.icon; th.appendChild(i); }
|
|
@@ -68,6 +78,40 @@ class NkTableView extends NkElement {
|
|
|
68
78
|
}
|
|
69
79
|
this._newRow.textContent = this.getAttribute('new-row-label') || this.str('newPage');
|
|
70
80
|
this._newRow.style.display = this.getBoolAttr('new-row') ? '' : 'none';
|
|
81
|
+
this._syncSelectAll();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** The header of a selection column: the cells' own checkbox, named "Select all". */
|
|
85
|
+
_selectAllHeader(col) {
|
|
86
|
+
const th = this.createElement('th', ['select-all'], { scope: 'col' });
|
|
87
|
+
const label = this.createElement('label', ['nk-check']);
|
|
88
|
+
label.appendChild(this.createElement('input', [], { type: 'checkbox', 'aria-label': this.str('selectAll'), 'data-select-all': col.key }));
|
|
89
|
+
th.appendChild(label);
|
|
90
|
+
if (col.width) th.style.width = col.width;
|
|
91
|
+
return th;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Every header box shows its column: checked for all rows, a dash for some, empty for none – and nothing to choose without rows. */
|
|
95
|
+
_syncSelectAll() {
|
|
96
|
+
for (const input of this._thead?.querySelectorAll('input[data-select-all]') ?? []) {
|
|
97
|
+
const key = input.dataset.selectAll, on = this._rows.filter(r => r[key]).length;
|
|
98
|
+
input.checked = on > 0 && on === this._rows.length;
|
|
99
|
+
input.indeterminate = on > 0 && on < this._rows.length;
|
|
100
|
+
input.disabled = !this._rows.length;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** A click or Space on a header box: the column for every row, one event. */
|
|
105
|
+
_selectAll(input) {
|
|
106
|
+
const key = input.dataset.selectAll;
|
|
107
|
+
// A dash selects all, as Notion does; only a full column clears.
|
|
108
|
+
const value = !(this._rows.length && this._rows.every(r => r[key]));
|
|
109
|
+
for (const row of this._rows) row[key] = value;
|
|
110
|
+
const focused = this._shadow.activeElement === input;
|
|
111
|
+
this._render();
|
|
112
|
+
// Space should leave the focus where it was – on the new header box.
|
|
113
|
+
if (focused) [...this._thead.querySelectorAll('input[data-select-all]')].find(i => i.dataset.selectAll === key)?.focus();
|
|
114
|
+
this.emit('nk-change', { key, value, all: true, rows: this._rows });
|
|
71
115
|
}
|
|
72
116
|
|
|
73
117
|
setupEvents() {
|
|
@@ -98,8 +142,10 @@ class NkTableView extends NkElement {
|
|
|
98
142
|
this._onChange = (e) => {
|
|
99
143
|
const input = e.target;
|
|
100
144
|
if (input.type !== 'checkbox') return;
|
|
145
|
+
if (input.dataset.selectAll != null) { this._selectAll(input); return; }
|
|
101
146
|
const row = this._rowById(input.dataset.rowId);
|
|
102
147
|
if (row) row[input.dataset.key] = input.checked;
|
|
148
|
+
this._syncSelectAll();
|
|
103
149
|
this.emit('nk-change', { row, key: input.dataset.key, value: input.checked });
|
|
104
150
|
};
|
|
105
151
|
this._onKey = (e) => { if ((e.key === 'Enter' || e.key === ' ') && e.target === this._newRow) { e.preventDefault(); this.emit('nk-action', { action: 'new-row' }); } };
|
|
@@ -24,6 +24,17 @@ import '@jungherz-de/notionkit/notionkit-styles.js';
|
|
|
24
24
|
// [data-tooltip], a press or Escape. A line break in the text is kept.
|
|
25
25
|
// While it shows, the target's aria-describedby names it (in the same
|
|
26
26
|
// document or shadow root).
|
|
27
|
+
//
|
|
28
|
+
// Following the pointer and the focus inside a shadow root (1.20.1):
|
|
29
|
+
// pointerover, focusin and focusout carry a relatedTarget, and when target
|
|
30
|
+
// and relatedTarget share a shadow tree the DOM standard ends the event path
|
|
31
|
+
// at its host – the document never hears of a move from one [data-tooltip]
|
|
32
|
+
// to the next in the same root. So the pointer is also read from
|
|
33
|
+
// pointermove, which has no relatedTarget, and acted on only when the
|
|
34
|
+
// element under it changes; and a key that moved the focus – Tab, the arrow
|
|
35
|
+
// keys of a group – is caught on keyup, comparing the focused element with
|
|
36
|
+
// the one before the key went down. A move by script alone inside one
|
|
37
|
+
// shadow root stays unseen.
|
|
27
38
|
const hostSheet = new CSSStyleSheet();
|
|
28
39
|
hostSheet.replaceSync(`:host { display: block; position: fixed; top: 0; left: 0; z-index: 130; pointer-events: none; }`);
|
|
29
40
|
let count = 0;
|
|
@@ -101,14 +112,50 @@ class NkTooltip extends NkElement {
|
|
|
101
112
|
this.show(el, own ? null : el.getAttribute('data-tooltip'), own ? this.getAttribute('shortcut') : el.getAttribute('data-tooltip-key'));
|
|
102
113
|
}
|
|
103
114
|
|
|
115
|
+
/**
|
|
116
|
+
* The pointer is over `el` now (null: no [data-tooltip]). pointerover acts
|
|
117
|
+
* on every boundary it crosses, as it always has; pointermove – the only
|
|
118
|
+
* one that reaches the document from inside a shadow root – only when the
|
|
119
|
+
* element under the pointer changed, so a hand resting on the page leaves
|
|
120
|
+
* a tooltip the keyboard or show(rect) opened alone.
|
|
121
|
+
*/
|
|
122
|
+
_pointer(e, move) {
|
|
123
|
+
const el = e.pointerType === 'touch' ? null : this._targetOf(e);
|
|
124
|
+
if (move && el === this._hover) return;
|
|
125
|
+
this._hover = el;
|
|
126
|
+
if (el === this._target) return;
|
|
127
|
+
this.hide();
|
|
128
|
+
if (!el) return;
|
|
129
|
+
this._target = el;
|
|
130
|
+
this._timer = setTimeout(() => this._showFor(el), this._delay);
|
|
131
|
+
}
|
|
132
|
+
|
|
104
133
|
setupEvents() {
|
|
105
|
-
this._onOver = (e) =>
|
|
106
|
-
|
|
107
|
-
|
|
134
|
+
this._onOver = (e) => this._pointer(e, false);
|
|
135
|
+
this._onMove = (e) => this._pointer(e, true);
|
|
136
|
+
// The pointer left the window (no relatedTarget): a tooltip – shown or
|
|
137
|
+
// still waiting – for what it was on goes with it. One the keyboard or
|
|
138
|
+
// show(rect) opened is not the pointer's and stays.
|
|
139
|
+
this._onOut = (e) => {
|
|
140
|
+
if (e.relatedTarget || e.pointerType === 'touch') return;
|
|
141
|
+
if (this._target && this._target === this._hover) this.hide();
|
|
142
|
+
this._hover = null;
|
|
143
|
+
};
|
|
144
|
+
// Capture, before an element's own keydown moves the focus (a roving tab
|
|
145
|
+
// stop does); not for a held key's repeats, so keyup compares with where
|
|
146
|
+
// the focus was before the key went down.
|
|
147
|
+
this._onKeyDown = (e) => { if (!e.repeat) this._focusBefore = deepActiveElement(); };
|
|
148
|
+
this._onKeyUp = (e) => {
|
|
149
|
+
const active = deepActiveElement();
|
|
150
|
+
if (active === this._focusBefore) return;
|
|
151
|
+
this._focusBefore = active;
|
|
152
|
+
// keyup goes to the focused element, so its path is the focus's path.
|
|
153
|
+
const el = this._targetOf(e);
|
|
154
|
+
if (el && el === this._target) return; // focusin got there first
|
|
108
155
|
this.hide();
|
|
109
|
-
if (!el) return;
|
|
156
|
+
if (!el || !active?.matches(':focus-visible')) return;
|
|
110
157
|
this._target = el;
|
|
111
|
-
this.
|
|
158
|
+
this._showFor(el);
|
|
112
159
|
};
|
|
113
160
|
this._onFocus = (e) => {
|
|
114
161
|
const el = this._targetOf(e);
|
|
@@ -120,7 +167,11 @@ class NkTooltip extends NkElement {
|
|
|
120
167
|
this._onHide = () => this.hide();
|
|
121
168
|
this._onKey = (e) => { if (e.key === 'Escape' && this.open) this.hide(); };
|
|
122
169
|
document.addEventListener('pointerover', this._onOver);
|
|
170
|
+
document.addEventListener('pointermove', this._onMove, { capture: true, passive: true });
|
|
171
|
+
document.addEventListener('pointerout', this._onOut);
|
|
123
172
|
document.addEventListener('focusin', this._onFocus);
|
|
173
|
+
document.addEventListener('keydown', this._onKeyDown, true);
|
|
174
|
+
document.addEventListener('keyup', this._onKeyUp, true);
|
|
124
175
|
document.addEventListener('focusout', this._onHide);
|
|
125
176
|
document.addEventListener('pointerdown', this._onHide, true);
|
|
126
177
|
document.addEventListener('scroll', this._onHide, true);
|
|
@@ -131,13 +182,18 @@ class NkTooltip extends NkElement {
|
|
|
131
182
|
|
|
132
183
|
teardownEvents() {
|
|
133
184
|
document.removeEventListener('pointerover', this._onOver);
|
|
185
|
+
document.removeEventListener('pointermove', this._onMove, { capture: true });
|
|
186
|
+
document.removeEventListener('pointerout', this._onOut);
|
|
134
187
|
document.removeEventListener('focusin', this._onFocus);
|
|
188
|
+
document.removeEventListener('keydown', this._onKeyDown, true);
|
|
189
|
+
document.removeEventListener('keyup', this._onKeyUp, true);
|
|
135
190
|
document.removeEventListener('focusout', this._onHide);
|
|
136
191
|
document.removeEventListener('pointerdown', this._onHide, true);
|
|
137
192
|
document.removeEventListener('scroll', this._onHide, true);
|
|
138
193
|
document.removeEventListener('wheel', this._onHide, { capture: true });
|
|
139
194
|
document.removeEventListener('keydown', this._onKey);
|
|
140
195
|
this.hide();
|
|
196
|
+
this._hover = this._focusBefore = null;
|
|
141
197
|
}
|
|
142
198
|
|
|
143
199
|
onAttributeChanged(name) { if (name === 'shortcut' && !this._text.data) this._fill(null); if (name === 'for') this.hide(); }
|