@livenetworks/ashlar 1.4.1 → 1.6.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/README.md +189 -177
- package/js/COMPONENTS.md +55 -49
- package/js/index.js +22 -5
- package/js/ln-accordion/README.md +186 -137
- package/js/ln-accordion/ln-accordion.js +1 -1
- package/js/ln-ajax/README.md +73 -4
- package/js/ln-ajax/ln-ajax.js +1 -1
- package/js/ln-ajax/src/ln-ajax.js +13 -13
- package/js/ln-api-connector/README.md +261 -150
- package/js/ln-api-connector/ln-api-connector.js +1 -1
- package/js/ln-api-connector/src/ln-api-connector.js +368 -265
- package/js/ln-api-queue/README.md +219 -0
- package/js/ln-api-queue/ln-api-queue.js +1 -0
- package/js/ln-api-queue/src/ln-api-queue.js +320 -0
- package/js/ln-api-queue/src/queue-storage.js +455 -0
- package/js/ln-autoresize/README.md +47 -0
- package/js/ln-autoresize/ln-autoresize.js +1 -1
- package/js/ln-autosave/README.md +33 -1
- package/js/ln-autosave/ln-autosave.js +1 -1
- package/js/ln-autosave/src/ln-autosave.js +4 -4
- package/js/ln-circular-progress/README.md +27 -13
- package/js/ln-circular-progress/ln-circular-progress.js +1 -1
- package/js/ln-circular-progress/src/ln-circular-progress.js +18 -5
- package/js/ln-confirm/README.md +162 -86
- package/js/ln-confirm/_ln-confirm.scss +11 -0
- package/js/ln-confirm/ln-confirm.js +1 -1
- package/js/ln-confirm/src/ln-confirm.js +77 -41
- package/js/ln-core/README.md +896 -0
- package/js/ln-core/hash.js +92 -0
- package/js/ln-core/helpers.js +337 -8
- package/js/ln-core/index.js +4 -2
- package/js/ln-core/persist.js +29 -3
- package/js/ln-core/positioning.js +1 -35
- package/js/ln-core/window-cache.js +213 -0
- package/js/ln-couchdb-connector/README.md +177 -156
- package/js/ln-couchdb-connector/ln-couchdb-connector.js +1 -1
- package/js/ln-couchdb-connector/src/ln-couchdb-connector.js +398 -348
- package/js/ln-data-coordinator/README.md +536 -165
- package/js/ln-data-coordinator/ln-data-coordinator.js +1 -1
- package/js/ln-data-coordinator/src/data-read-policy.js +18 -0
- package/js/ln-data-coordinator/src/ln-data-coordinator.js +1042 -249
- package/js/ln-data-coordinator/src/mutation-receipts.js +46 -0
- package/js/ln-data-store/README.md +241 -94
- package/js/ln-data-store/ln-data-store.js +1 -1
- package/js/ln-data-store/src/ln-data-store.js +694 -699
- package/js/ln-date/README.md +39 -1
- package/js/ln-date/ln-date-dev.scss +14 -0
- package/js/ln-date/ln-date.js +1 -1
- package/js/ln-date/src/ln-date.js +236 -178
- package/js/ln-debug/README.md +58 -0
- package/js/ln-debug/ln-debug.js +1 -0
- package/js/ln-debug/src/ln-debug.js +19 -0
- package/js/ln-dropdown/README.md +31 -8
- package/js/ln-dropdown/ln-dropdown.js +1 -1
- package/js/ln-dropdown/src/ln-dropdown.js +30 -13
- package/js/ln-editor/README.md +274 -0
- package/js/ln-editor/ln-editor.js +1 -0
- package/js/ln-editor/ln-editor.scss +43 -0
- package/js/ln-editor/src/ln-editor.js +619 -0
- package/js/ln-external-links/README.md +44 -5
- package/js/ln-external-links/ln-external-links.js +1 -1
- package/js/ln-fill/README.md +199 -0
- package/js/ln-fill/ln-fill.js +1 -0
- package/js/ln-fill/src/ln-fill.js +87 -0
- package/js/ln-filter/README.md +189 -99
- package/js/ln-filter/ln-filter-dev.scss +8 -0
- package/js/ln-filter/ln-filter.js +1 -1
- package/js/ln-filter/src/ln-filter.js +22 -7
- package/js/ln-form/README.md +212 -49
- package/js/ln-form/ln-form.js +1 -1
- package/js/ln-form/src/ln-form.js +99 -199
- package/js/ln-http/README.md +125 -89
- package/js/ln-http/ln-http.js +1 -1
- package/js/ln-http/src/ln-http.js +32 -13
- package/js/ln-icon/README.md +130 -0
- package/js/ln-icon/ln-icon.js +1 -0
- package/js/{ln-icons/src/ln-icons.js → ln-icon/src/ln-icon.js} +20 -15
- package/js/ln-link/README.md +47 -9
- package/js/ln-link/ln-link.js +1 -1
- package/js/ln-link/src/ln-link.js +22 -6
- package/js/ln-list/README.md +129 -0
- package/js/ln-list/ln-list.js +1 -0
- package/js/ln-list/ln-list.scss +28 -0
- package/js/ln-list/src/ln-list.js +1216 -0
- package/js/ln-modal/README.md +185 -154
- package/js/ln-modal/ln-modal-dev.scss +13 -0
- package/js/ln-modal/ln-modal.js +1 -1
- package/js/ln-modal/ln-modal.scss +28 -4
- package/js/ln-modal/src/ln-modal.js +137 -201
- package/js/ln-modal-coordinator/README.md +99 -0
- package/js/ln-modal-coordinator/ln-modal-coordinator-dev.scss +8 -0
- package/js/ln-modal-coordinator/ln-modal-coordinator.js +1 -0
- package/js/ln-modal-coordinator/src/ln-modal-coordinator.js +345 -0
- package/js/ln-nav/README.md +46 -3
- package/js/ln-nav/ln-nav.js +1 -1
- package/js/ln-nav/src/ln-nav.js +92 -127
- package/js/ln-number/README.md +28 -1
- package/js/ln-number/ln-number-dev.scss +13 -0
- package/js/ln-number/ln-number.js +1 -1
- package/js/ln-number/src/ln-number.js +443 -350
- package/js/ln-options/README.md +66 -0
- package/js/ln-options/ln-options.js +1 -0
- package/js/ln-options/src/ln-options.js +74 -0
- package/js/ln-popover/README.md +40 -5
- package/js/ln-popover/ln-popover.js +1 -1
- package/js/ln-popover/src/ln-popover.js +38 -11
- package/js/ln-progress/README.md +413 -442
- package/js/ln-progress/ln-progress.js +1 -1
- package/js/ln-progress/src/ln-progress.js +98 -150
- package/js/ln-router/README.md +432 -0
- package/js/ln-router/ln-router.js +1 -0
- package/js/ln-router/src/ln-router.js +539 -0
- package/js/ln-search/README.md +158 -83
- package/js/ln-search/ln-search-dev.scss +8 -0
- package/js/ln-search/ln-search.js +1 -1
- package/js/ln-search/src/ln-search.js +12 -9
- package/js/ln-slug/README.md +110 -0
- package/js/ln-slug/ln-slug.js +1 -0
- package/js/ln-slug/src/ln-slug.js +74 -0
- package/js/ln-sort/README.md +170 -0
- package/js/ln-sort/ln-sort-dev.scss +8 -0
- package/js/ln-sort/ln-sort.js +1 -0
- package/js/ln-sort/src/ln-sort.js +178 -0
- package/js/ln-sortable/README.md +133 -95
- package/js/ln-sortable/ln-sortable.js +1 -1
- package/js/ln-stat/README.md +55 -0
- package/js/ln-stat/ln-stat.js +1 -0
- package/js/ln-stat/src/ln-stat.js +55 -0
- package/js/ln-table/README.md +285 -101
- package/js/ln-table/ln-table-dev.scss +17 -0
- package/js/ln-table/ln-table.js +1 -1
- package/js/ln-table/ln-table.scss +1 -1
- package/js/ln-table/src/ln-table.js +1493 -473
- package/js/ln-table-coordinator/README.md +73 -0
- package/js/ln-table-coordinator/ln-table-coordinator.js +1 -0
- package/js/ln-table-coordinator/src/ln-table-coordinator.js +160 -0
- package/js/ln-tabs/README.md +221 -137
- package/js/ln-tabs/ln-tabs-dev.scss +18 -0
- package/js/ln-tabs/ln-tabs.js +1 -1
- package/js/ln-tabs/src/ln-tabs.js +41 -24
- package/js/ln-time/README.md +14 -0
- package/js/ln-time/ln-time.js +1 -1
- package/js/ln-time/src/ln-time.js +223 -192
- package/js/ln-toast/README.md +178 -122
- package/js/ln-toast/ln-toast.js +1 -15
- package/js/ln-toast/src/ln-toast.js +232 -210
- package/js/ln-toast/template.html +16 -12
- package/js/ln-toggle/README.md +61 -2
- package/js/ln-toggle/ln-toggle-dev.scss +13 -0
- package/js/ln-toggle/ln-toggle.js +1 -1
- package/js/ln-toggle/src/ln-toggle.js +56 -43
- package/js/ln-tooltip/README.md +95 -58
- package/js/ln-tooltip/ln-tooltip-dev.scss +9 -0
- package/js/ln-tooltip/ln-tooltip.js +1 -1
- package/js/ln-tooltip/src/ln-tooltip.js +45 -6
- package/js/ln-translations/README.md +118 -96
- package/js/ln-translations/ln-translations.js +1 -1
- package/js/ln-translations/src/ln-translations.js +10 -5
- package/js/ln-upload/README.md +85 -10
- package/js/ln-upload/ln-upload.js +1 -1
- package/js/ln-upload/src/ln-upload.js +26 -10
- package/js/ln-validate/README.md +72 -0
- package/js/ln-validate/ln-validate-dev.scss +15 -0
- package/js/ln-validate/ln-validate.js +1 -1
- package/js/ln-validate/src/ln-validate.js +64 -0
- package/package.json +61 -55
- package/scss/base/_global.scss +2 -2
- package/scss/base/_typography.scss +1 -2
- package/scss/components/_date.scss +1 -0
- package/scss/components/_dropdown.scss +0 -5
- package/scss/components/_editor.scss +5 -0
- package/scss/components/_filter.scss +26 -0
- package/scss/components/_form.scss +7 -0
- package/scss/components/_ln-table.scss +14 -5
- package/scss/components/_sort.scss +10 -0
- package/scss/components/_table.scss +68 -1
- package/scss/components/_toast.scss +68 -41
- package/scss/components/_toggle.scss +16 -0
- package/scss/config/_density.scss +205 -117
- package/scss/config/_icons.scss +10 -9
- package/scss/config/_tokens.scss +69 -47
- package/scss/config/mixins/_accordion.scss +2 -7
- package/scss/config/mixins/_alert.scss +4 -4
- package/scss/config/mixins/_breadcrumbs.scss +2 -2
- package/scss/config/mixins/_btn.scss +1 -1
- package/scss/config/mixins/_card.scss +89 -14
- package/scss/config/mixins/_collapsible.scss +3 -0
- package/scss/config/mixins/_colors.scss +1 -1
- package/scss/config/mixins/_diagnostics.scss +48 -0
- package/scss/config/mixins/_display.scss +1 -0
- package/scss/config/mixins/_dropdown.scss +3 -5
- package/scss/config/mixins/_editor.scss +124 -0
- package/scss/config/mixins/_empty-state.scss +7 -0
- package/scss/config/mixins/_filter.scss +47 -0
- package/scss/config/mixins/_footer.scss +1 -2
- package/scss/config/mixins/_form.scss +207 -21
- package/scss/config/mixins/_index.scss +4 -1
- package/scss/config/mixins/_ln-table.scss +51 -93
- package/scss/config/mixins/_modal.scss +149 -66
- package/scss/config/mixins/_nav.scss +3 -4
- package/scss/config/mixins/_popover.scss +39 -0
- package/scss/config/mixins/_sidebar.scss +1 -1
- package/scss/config/mixins/_sort.scss +42 -0
- package/scss/config/mixins/_table.scss +232 -38
- package/scss/config/mixins/_toast.scss +179 -152
- package/scss/config/mixins/_tooltip.scss +17 -7
- package/scss/config/mixins/_typography.scss +4 -2
- package/scss/ln-ashlar-dev.scss +39 -0
- package/scss/ln-ashlar.scss +8 -2
- package/js/ln-data-table/README.md +0 -110
- package/js/ln-data-table/ln-data-table.js +0 -1
- package/js/ln-data-table/ln-data-table.scss +0 -10
- package/js/ln-data-table/src/ln-data-table.js +0 -1103
- package/js/ln-icons/README.md +0 -88
- package/js/ln-icons/ln-icons.js +0 -1
- package/js/ln-table/ln-table-sort.js +0 -1
- package/js/ln-table/src/ln-table-sort.js +0 -168
- package/scss/components/_data-table.scss +0 -83
- package/scss/config/mixins/_data-table.scss +0 -346
|
@@ -6,14 +6,21 @@
|
|
|
6
6
|
@use 'motion' as *;
|
|
7
7
|
|
|
8
8
|
// Shared dark-bubble chrome for ::after pseudo-tooltips (tooltip, confirm)
|
|
9
|
-
// and JS-portal tooltip-element.
|
|
10
|
-
//
|
|
9
|
+
// and JS-portal tooltip-element. Reads the theme-root token pair
|
|
10
|
+
// (--fg-default / --bg-base) NOT the rebindable --color-fg / --color-bg:
|
|
11
|
+
// the ::after inherits custom properties from its trigger, and many
|
|
12
|
+
// components locally rebind --color-fg/--color-bg (btn, accordion,
|
|
13
|
+
// avatar, app-shell, …). Reading those would make the bubble's text
|
|
14
|
+
// inherit a context-specific value — e.g. dark-on-dark = invisible.
|
|
15
|
+
// --fg-default / --bg-base are only ever set at :root (and flipped at
|
|
16
|
+
// the dark-theme :root), so the dark-mode inversion still works while
|
|
17
|
+
// the bubble stays immune to component-scope rebinds.
|
|
11
18
|
@mixin tooltip-bubble {
|
|
12
19
|
--padding-y: var(--size-xs);
|
|
13
20
|
--padding-x: var(--size-sm);
|
|
14
21
|
padding: var(--padding-y) var(--padding-x);
|
|
15
|
-
background: var(--
|
|
16
|
-
color: var(--
|
|
22
|
+
background: var(--fg-default);
|
|
23
|
+
color: var(--bg-base);
|
|
17
24
|
@include typography(caption);
|
|
18
25
|
--radius: var(--radius-sm);
|
|
19
26
|
border-radius: var(--radius);
|
|
@@ -89,15 +96,18 @@
|
|
|
89
96
|
}
|
|
90
97
|
|
|
91
98
|
// ─── JS Portal (real DOM tooltip) ──────────────────────
|
|
92
|
-
// When JS enhance is active, tooltips render as positioned
|
|
93
|
-
//
|
|
99
|
+
// When JS enhance is active, tooltips render as positioned DOM elements
|
|
100
|
+
// inside #ln-tooltip-portal, a shared popover="manual" container promoted
|
|
101
|
+
// to the browser's top layer (showPopover()/hidePopover() in ln-tooltip.js)
|
|
102
|
+
// instead of ::after.
|
|
94
103
|
|
|
95
104
|
@mixin tooltip-portal {
|
|
96
105
|
position: fixed;
|
|
106
|
+
inset: auto;
|
|
107
|
+
margin: 0;
|
|
97
108
|
top: 0;
|
|
98
109
|
left: 0;
|
|
99
110
|
pointer-events: none;
|
|
100
|
-
z-index: var(--z-toast);
|
|
101
111
|
}
|
|
102
112
|
|
|
103
113
|
@mixin tooltip-element {
|
|
@@ -49,8 +49,10 @@
|
|
|
49
49
|
@error "typography(): unknown role '#{$role}'. Valid roles: #{$valid-roles}";
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
font-size: var(--text-#{$role});
|
|
53
|
-
|
|
52
|
+
--font-size: var(--text-#{$role});
|
|
53
|
+
font-size: var(--font-size);
|
|
54
|
+
--line-height: var(--lh-#{$role});
|
|
55
|
+
line-height: var(--line-height);
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
@mixin tracking-tight { letter-spacing: var(--tracking-tight); }
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// Dev & Validation Diagnostics — ln-ashlar
|
|
3
|
+
// ==========================================================================
|
|
4
|
+
// This stylesheet contains diagnostic CSS tools to validate correct HTML
|
|
5
|
+
// structure, missing integration attributes, and accessibility warnings during
|
|
6
|
+
// development. Do not compile or deploy this file to production.
|
|
7
|
+
// ==========================================================================
|
|
8
|
+
|
|
9
|
+
@use 'config/mixins' as *;
|
|
10
|
+
|
|
11
|
+
// --- Modular Component Diagnostics ---
|
|
12
|
+
@use '../js/ln-toggle/ln-toggle-dev';
|
|
13
|
+
@use '../js/ln-table/ln-table-dev';
|
|
14
|
+
@use '../js/ln-modal/ln-modal-dev';
|
|
15
|
+
@use '../js/ln-modal-coordinator/ln-modal-coordinator-dev';
|
|
16
|
+
@use '../js/ln-validate/ln-validate-dev';
|
|
17
|
+
@use '../js/ln-date/ln-date-dev';
|
|
18
|
+
@use '../js/ln-number/ln-number-dev';
|
|
19
|
+
@use '../js/ln-tabs/ln-tabs-dev';
|
|
20
|
+
@use '../js/ln-search/ln-search-dev';
|
|
21
|
+
@use '../js/ln-filter/ln-filter-dev';
|
|
22
|
+
@use '../js/ln-sort/ln-sort-dev';
|
|
23
|
+
@use '../js/ln-tooltip/ln-tooltip-dev';
|
|
24
|
+
|
|
25
|
+
// --- General HTML/Accessibility Diagnostics ---
|
|
26
|
+
[data-ln-debug] {
|
|
27
|
+
// 1. Image Missing Alt: accessibility warning
|
|
28
|
+
// Flags an <img> with NO alt attribute (empty alt="" is the valid decorative pattern and is intentionally NOT flagged)
|
|
29
|
+
img:not([alt]) {
|
|
30
|
+
@include dev-replaced-error;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 2. Abbr Missing Title: accessibility warning
|
|
34
|
+
// Flags an <abbr> with no title — the abbreviation has no expansion and is meaningless to readers
|
|
35
|
+
abbr:not([title]) {
|
|
36
|
+
@include dev-inline-error("abbr is missing a title attribute");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
package/scss/ln-ashlar.scss
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
@use 'components/date';
|
|
14
14
|
@use 'components/layout';
|
|
15
15
|
@use 'components/table';
|
|
16
|
+
@use 'components/sort';
|
|
16
17
|
@use 'components/tabs';
|
|
17
18
|
@use 'components/toggle';
|
|
18
19
|
@use 'components/accordion';
|
|
@@ -31,9 +32,11 @@
|
|
|
31
32
|
@use 'components/timeline';
|
|
32
33
|
@use 'components/stat-card';
|
|
33
34
|
@use 'components/prose';
|
|
35
|
+
@use 'components/editor';
|
|
34
36
|
@use 'components/scrollbar';
|
|
35
37
|
@use 'components/tooltip';
|
|
36
38
|
@use 'components/popover';
|
|
39
|
+
@use 'components/filter';
|
|
37
40
|
@use 'components/chip';
|
|
38
41
|
@use 'components/loader';
|
|
39
42
|
@use 'components/progress';
|
|
@@ -45,7 +48,6 @@
|
|
|
45
48
|
@use 'components/toast';
|
|
46
49
|
@use 'components/upload';
|
|
47
50
|
@use 'components/translations';
|
|
48
|
-
@use 'components/data-table';
|
|
49
51
|
@use 'components/ln-table';
|
|
50
52
|
@use 'components/ajax';
|
|
51
53
|
|
|
@@ -60,4 +62,8 @@
|
|
|
60
62
|
@use '../js/ln-filter/ln-filter';
|
|
61
63
|
@use '../js/ln-search/ln-search';
|
|
62
64
|
@use '../js/ln-table/ln-table' as ln-table-state;
|
|
63
|
-
@use '../js/ln-
|
|
65
|
+
@use '../js/ln-list/ln-list';
|
|
66
|
+
@use '../js/ln-editor/ln-editor';
|
|
67
|
+
@use '../js/ln-confirm/ln-confirm';
|
|
68
|
+
|
|
69
|
+
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
# ln-data-table
|
|
2
|
-
|
|
3
|
-
A zero-dependency, event-driven **Data Presentation Shell** that manages row template rendering, interactive sorting, column filtering, search states, multi-row selections, virtual scrolling (10,000+ items), and keyboard layouts.
|
|
4
|
-
|
|
5
|
-
It decouples data presentation from data fetching: announcing query intents via request events and awaiting rendered datasets asynchronously.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## 🧭 Philosophy & Architecture
|
|
10
|
-
|
|
11
|
-
1. **Presenter Separation:** The component possesses no fetching capabilities. It translates column and search interactions into unified query events and delegates execution to a coordinator (such as `ln-store` or direct server fetchers).
|
|
12
|
-
2. **Dynamic Template Scoping:** Row designs are written cleanly inside standard HTML `<template>` slots. Values are safely bound using double-curly brackets (`{{ field }}`) using browser-native `textContent` for robust XSS protection.
|
|
13
|
-
3. **Flicker-Free Virtual Rendering:** Massive tables auto-activate high-performance virtual scrolling. Only the visible portion of rows plus a buffer are mounted, keeping the DOM extremely small.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## 📦 Minimal Blueprint
|
|
18
|
-
|
|
19
|
-
```html
|
|
20
|
-
<section data-ln-data-table="documents" data-ln-data-table-selectable id="documents-table">
|
|
21
|
-
<header class="ln-table__toolbar">
|
|
22
|
-
<h3>Documents</h3>
|
|
23
|
-
<input type="search" placeholder="Search..." data-ln-data-table-search>
|
|
24
|
-
</header>
|
|
25
|
-
|
|
26
|
-
<table>
|
|
27
|
-
<thead>
|
|
28
|
-
<tr>
|
|
29
|
-
<th data-ln-col-select></th>
|
|
30
|
-
<th data-ln-col="title">
|
|
31
|
-
Title
|
|
32
|
-
<button data-ln-col-sort aria-label="Sort">
|
|
33
|
-
<svg class="ln-icon" data-ln-sort-icon="none"><use href="#ln-arrows-sort"></use></svg>
|
|
34
|
-
<svg class="ln-icon" data-ln-sort-icon="asc"><use href="#ln-arrow-up"></use></svg>
|
|
35
|
-
<svg class="ln-icon" data-ln-sort-icon="desc"><use href="#ln-arrow-down"></use></svg>
|
|
36
|
-
</button>
|
|
37
|
-
</th>
|
|
38
|
-
</tr>
|
|
39
|
-
</thead>
|
|
40
|
-
<tbody data-ln-data-table-body></tbody>
|
|
41
|
-
</table>
|
|
42
|
-
|
|
43
|
-
<!-- Row Template -->
|
|
44
|
-
<template data-ln-template="documents-row">
|
|
45
|
-
<tr data-ln-row>
|
|
46
|
-
<td><input type="checkbox" data-ln-row-select></td>
|
|
47
|
-
<td>{{ title }}</td>
|
|
48
|
-
</tr>
|
|
49
|
-
</template>
|
|
50
|
-
</section>
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
> [!IMPORTANT]
|
|
54
|
-
> Directly nested `<table>` elements must not be wrapped in scroll-trapping `overflow-y: auto` containers. The sticky header and virtual scroll calculations automatically bind to the nearest scrollable page-level container.
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## 🛠️ Declarative API Contract
|
|
59
|
-
|
|
60
|
-
### HTML Attributes
|
|
61
|
-
|
|
62
|
-
| Attribute | Elements | Description |
|
|
63
|
-
| :--- | :--- | :--- |
|
|
64
|
-
| `data-ln-data-table` | `<section>` | Component root and namespace. |
|
|
65
|
-
| `data-ln-data-table-selectable` | `<section>` | Opt-in. Activates checkbox columns and selection tracking. |
|
|
66
|
-
| `data-ln-col="field"` | `<th>` | Binds column interactions (sort, filter) to a data property. |
|
|
67
|
-
| `data-ln-data-table-search` | `<input>` | Binds keystroke entries to instant search events. |
|
|
68
|
-
|
|
69
|
-
### JS API
|
|
70
|
-
|
|
71
|
-
Access the presentation state directly via the `lnDataTable` property on the section container:
|
|
72
|
-
|
|
73
|
-
```javascript
|
|
74
|
-
const table = document.getElementById('documents-table');
|
|
75
|
-
|
|
76
|
-
// 1. Inspect state
|
|
77
|
-
const selection = table.lnDataTable.selectedIds; // Set of active string IDs
|
|
78
|
-
const sortedBy = table.lnDataTable.currentSort; // { field, direction }
|
|
79
|
-
|
|
80
|
-
// 2. Tear down listeners
|
|
81
|
-
table.lnDataTable.destroy();
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## ⚡ DOM Events
|
|
87
|
-
|
|
88
|
-
### Emitted (Telemetry & Intent)
|
|
89
|
-
|
|
90
|
-
| Event | Payload | Description |
|
|
91
|
-
| :--- | :--- | :--- |
|
|
92
|
-
| `ln-data-table:request-data` | `{ table, sort, filters, search }` | Intent event. Fired whenever query states change. |
|
|
93
|
-
| `ln-data-table:row-click` | `{ table, id, record }` | Fired when clicking a row (ignored on inputs/links). |
|
|
94
|
-
| `ln-data-table:row-action` | `{ table, id, action, record }` | Fired on clicking `[data-ln-row-action="action"]` slots. |
|
|
95
|
-
| `ln-data-table:select` | `{ table, selectedIds, count }` | Fired on selecting row checkboxes. |
|
|
96
|
-
|
|
97
|
-
### Received (State Synchronization)
|
|
98
|
-
|
|
99
|
-
| Event | Payload | Description |
|
|
100
|
-
| :--- | :--- | :--- |
|
|
101
|
-
| `ln-data-table:set-data` | `{ data: Array, total, filtered }` | Populates table, rebuilds filters, formats counts. |
|
|
102
|
-
| `ln-data-table:set-loading` | `{ loading: Boolean }` | Toggles dim loading state (pointer-events disabled). |
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
## ⚠️ Common Pitfalls
|
|
107
|
-
|
|
108
|
-
- **Bypassing the Template Slot:** Putting static row markup directly inside `<tbody>` will result in it being immediately purged on the first data render event. Always build row cells within `<template>`.
|
|
109
|
-
- **Horizontal Overflow Traps:** Attempting to wrap tables in scroll layers breaks sticky header positioning. Let layout views manage full viewport boundaries instead.
|
|
110
|
-
- **Direct JS string injections:** Attempting to render raw HTML inside templates bypasses the safe `textContent` parser, opening XSS risks. Use custom action dispatchers for complex fields.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(function(){"use strict";const x={};function F(o,r){x[o]||(x[o]=document.querySelector('[data-ln-template="'+o+'"]'));const _=x[o];return _?_.content.cloneNode(!0):(console.warn("["+r+'] Template "'+o+'" not found'),null)}function m(o,r,_){o.dispatchEvent(new CustomEvent(r,{bubbles:!0,detail:_||{}}))}function D(o,r){if(!o||!r)return o;const _=o.querySelectorAll("[data-ln-field]");for(let u=0;u<_.length;u++){const a=_[u],g=a.getAttribute("data-ln-field");r[g]!=null&&(a.textContent=r[g])}const y=o.querySelectorAll("[data-ln-attr]");for(let u=0;u<y.length;u++){const a=y[u],g=a.getAttribute("data-ln-attr").split(",");for(let e=0;e<g.length;e++){const t=g[e].trim().split(":");if(t.length!==2)continue;const n=t[0].trim(),l=t[1].trim();r[l]!=null&&a.setAttribute(n,r[l])}}const C=o.querySelectorAll("[data-ln-show]");for(let u=0;u<C.length;u++){const a=C[u],g=a.getAttribute("data-ln-show");g in r&&a.classList.toggle("hidden",!r[g])}const S=o.querySelectorAll("[data-ln-class]");for(let u=0;u<S.length;u++){const a=S[u],g=a.getAttribute("data-ln-class").split(",");for(let e=0;e<g.length;e++){const t=g[e].trim().split(":");if(t.length!==2)continue;const n=t[0].trim(),l=t[1].trim();l in r&&a.classList.toggle(n,!!r[l])}}return o}function T(o,r){if(!o||!r)return o;const _=document.createTreeWalker(o,NodeFilter.SHOW_TEXT);for(;_.nextNode();){const y=_.currentNode;y.textContent.indexOf("{{")!==-1&&(y.textContent=y.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(C,S){return r[S]!==void 0?r[S]:""}))}return o}function R(o,r){if(!document.body){document.addEventListener("DOMContentLoaded",function(){R(o,r)}),console.warn("["+r+'] Script loaded before <body> — add "defer" to your <script> tag');return}o()}function E(o,r,_){if(o){const y=o.querySelector('[data-ln-template="'+r+'"]');if(y)return y.content.cloneNode(!0)}return F(r,_)}function I(o,r,_,y){if(o.nodeType!==1)return;const S=r.indexOf("[")!==-1||r.indexOf(".")!==-1||r.indexOf("#")!==-1?r:"["+r+"]",u=Array.from(o.querySelectorAll(S));o.matches&&o.matches(S)&&u.push(o);for(const a of u)a[_]||(a[_]=new y(a))}function O(o,r,_,y,C={}){const S=C.extraAttributes||[],u=C.onAttributeChange||null,a=C.onInit||null;function g(e){const t=e||document.body;I(t,o,r,_),a&&a(t)}return R(function(){const e=new MutationObserver(function(n){for(let l=0;l<n.length;l++){const i=n[l];if(i.type==="childList"){for(let s=0;s<i.addedNodes.length;s++){const c=i.addedNodes[s];c.nodeType===1&&(I(c,o,r,_),a&&a(c))}for(let s=0;s<i.removedNodes.length;s++){const c=i.removedNodes[s];if(c.nodeType===1){const f=o.indexOf("[")!==-1||o.indexOf(".")!==-1||o.indexOf("#")!==-1?o:"["+o+"]",p=Array.from(c.querySelectorAll(f));c.matches&&c.matches(f)&&p.push(c);for(let A=0;A<p.length;A++){const v=p[A];if(!document.contains(v)){const w=v[r];w&&typeof w.destroy=="function"&&w.destroy()}}}}}else i.type==="attributes"&&(u&&i.target[r]?u(i.target,i.attributeName):(I(i.target,o,r,_),a&&a(i.target)))}});let t=[];if(o.indexOf("[")!==-1){const n=/\[([\w-]+)/g;let l;for(;(l=n.exec(o))!==null;)t.push(l[1])}else t.push(o);e.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:t.concat(S)})},y),window[r]=g,document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){g(document.body)}):g(document.body),g}const q={};function H(o,r){q[o]=r}function N(o){return q[o]||{ingress:r=>r,egress:r=>r}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=H,window.lnCore.getDataMapper=N),(function(){const o="data-ln-data-table",r="lnDataTable";if(window[r]!==void 0)return;const C=typeof Intl<"u"?new Intl.NumberFormat(document.documentElement.lang||void 0):null;function S(e){return C?C.format(e):String(e)}function u(e){let t=e.parentElement;for(;t&&t!==document.body&&t!==document.documentElement;){const l=getComputedStyle(t).overflowY;if(l==="auto"||l==="scroll")return t;t=t.parentElement}return null}function a(e){this.dom=e,this.name=e.getAttribute(o)||"",this.table=e.querySelector("table"),this.tbody=e.querySelector("[data-ln-data-table-body]")||e.querySelector("tbody"),this.thead=e.querySelector("thead"),this.ths=this.thead?Array.from(this.thead.querySelectorAll("th")):[],this.isLoaded=!1,this.totalCount=0,this.visibleCount=0,this.currentSort=null,this.currentFilters={},this.currentSearch="",this.selectedIds=new Set,this._data=[],this._lastTotal=0,this._lastFiltered=0,this._filterOptions={},this._filterableFields=this.ths.filter(function(n){return n.getAttribute("data-ln-col")&&n.querySelector("[data-ln-col-filter]")}).map(function(n){return n.getAttribute("data-ln-col")}),this._virtual=!1,this._rowHeight=0,this._vStart=-1,this._vEnd=-1,this._rafId=null,this._scrollHandler=null,this._scrollContainer=null,this._totalSpan=e.querySelector("[data-ln-data-table-total]"),this._filteredSpan=e.querySelector("[data-ln-data-table-filtered]"),this._filteredSpan&&(this._filteredWrap=this._filteredSpan.parentElement!==e?this._filteredSpan.closest("[data-ln-data-table-filtered-wrap]")||this._filteredSpan.parentNode:null),this._selectedSpan=e.querySelector("[data-ln-data-table-selected]"),this._selectedSpan&&(this._selectedWrap=this._selectedSpan.parentElement!==e?this._selectedSpan.closest("[data-ln-data-table-selected-wrap]")||this._selectedSpan.parentNode:null);const t=this;return this._onSetData=function(n){const l=n.detail||{};t._data=l.data||[],t._lastTotal=l.total!=null?l.total:t._data.length,t._lastFiltered=l.filtered!=null?l.filtered:t._data.length,t.totalCount=t._lastTotal,t.visibleCount=t._lastFiltered,t.isLoaded=!0,t._updateFilterOptions(l.filterOptions),t._vStart=-1,t._vEnd=-1,t._renderRows(),t._updateFooter(),m(e,"ln-data-table:rendered",{table:t.name,total:t.totalCount,visible:t.visibleCount})},e.addEventListener("ln-data-table:set-data",this._onSetData),this._onSetLoading=function(n){const l=n.detail&&n.detail.loading;e.classList.toggle("ln-data-table--loading",!!l),l&&(t.isLoaded=!1)},e.addEventListener("ln-data-table:set-loading",this._onSetLoading),this._sortButtons=Array.from(e.querySelectorAll("[data-ln-col-sort]")),this._onSortClick=function(n){const l=n.target.closest("[data-ln-col-sort]");if(!l)return;const i=l.closest("th");if(!i)return;const s=i.getAttribute("data-ln-col");s&&t._handleSort(s,i)},this.thead&&this.thead.addEventListener("click",this._onSortClick),this._activeDropdown=null,this._onFilterClick=function(n){const l=n.target.closest("[data-ln-col-filter]");if(!l)return;n.stopPropagation();const i=l.closest("th");if(!i)return;const s=i.getAttribute("data-ln-col");if(s){if(t._activeDropdown&&t._activeDropdown.field===s){t._closeFilterDropdown();return}t._openFilterDropdown(s,i,l)}},this.thead&&this.thead.addEventListener("click",this._onFilterClick),this._onDocClick=function(){t._activeDropdown&&t._closeFilterDropdown()},document.addEventListener("click",this._onDocClick),this._onClearAll=function(n){n.target.closest("[data-ln-data-table-clear-all]")&&(t.currentFilters={},t._updateFilterIndicators(),m(e,"ln-data-table:clear-filters",{table:t.name}),t._requestData())},e.addEventListener("click",this._onClearAll),this._selectable=e.hasAttribute("data-ln-data-table-selectable"),this._selectableActive=!1,this._selectable&&this._enableSelection(),this._onRowClick=function(n){if(n.target.closest("[data-ln-row-select]")||n.target.closest("[data-ln-row-action]")||n.target.closest("a")||n.target.closest("button")||n.ctrlKey||n.metaKey||n.button===1)return;const l=n.target.closest("[data-ln-row]");if(!l)return;const i=l.getAttribute("data-ln-row-id"),s=l._lnRecord||{};m(e,"ln-data-table:row-click",{table:t.name,id:i,record:s})},this.tbody&&this.tbody.addEventListener("click",this._onRowClick),this._onRowAction=function(n){const l=n.target.closest("[data-ln-row-action]");if(!l)return;n.stopPropagation();const i=l.closest("[data-ln-row]");if(!i)return;const s=l.getAttribute("data-ln-row-action"),c=i.getAttribute("data-ln-row-id"),d=i._lnRecord||{};m(e,"ln-data-table:row-action",{table:t.name,id:c,action:s,record:d})},this.tbody&&this.tbody.addEventListener("click",this._onRowAction),this._searchInput=e.querySelector("[data-ln-data-table-search]"),this._searchInput&&(this._onSearchInput=function(){t.currentSearch=t._searchInput.value,m(e,"ln-data-table:search",{table:t.name,query:t.currentSearch}),t._requestData()},this._searchInput.addEventListener("input",this._onSearchInput)),this._focusedRowIndex=-1,this._onKeydown=function(n){if(!e.contains(document.activeElement)&&document.activeElement!==document.body||document.activeElement&&(document.activeElement.tagName==="INPUT"||document.activeElement.tagName==="TEXTAREA"))return;if(n.key==="/"){t._searchInput&&(n.preventDefault(),t._searchInput.focus());return}const l=t.tbody?Array.from(t.tbody.querySelectorAll("[data-ln-row]")):[];if(l.length)switch(n.key){case"ArrowDown":n.preventDefault(),t._focusedRowIndex=Math.min(t._focusedRowIndex+1,l.length-1),t._focusRow(l);break;case"ArrowUp":n.preventDefault(),t._focusedRowIndex=Math.max(t._focusedRowIndex-1,0),t._focusRow(l);break;case"Home":n.preventDefault(),t._focusedRowIndex=0,t._focusRow(l);break;case"End":n.preventDefault(),t._focusedRowIndex=l.length-1,t._focusRow(l);break;case"Enter":if(t._focusedRowIndex>=0&&t._focusedRowIndex<l.length){n.preventDefault();const i=l[t._focusedRowIndex];m(e,"ln-data-table:row-click",{table:t.name,id:i.getAttribute("data-ln-row-id"),record:i._lnRecord||{}})}break;case" ":if(t._selectable&&t._focusedRowIndex>=0&&t._focusedRowIndex<l.length){n.preventDefault();const i=l[t._focusedRowIndex].querySelector("[data-ln-row-select]");i&&(i.checked=!i.checked,i.dispatchEvent(new Event("change",{bubbles:!0})))}break;case"Escape":t._activeDropdown&&t._closeFilterDropdown();break}},document.addEventListener("keydown",this._onKeydown),m(e,"ln-data-table:request-data",{table:this.name,sort:this.currentSort,filters:this.currentFilters,search:this.currentSearch}),this}a.prototype._handleSort=function(e,t){let n;!this.currentSort||this.currentSort.field!==e?n="asc":this.currentSort.direction==="asc"?n="desc":n=null;for(let l=0;l<this.ths.length;l++)this.ths[l].classList.remove("ln-sort-asc","ln-sort-desc");n?(this.currentSort={field:e,direction:n},t.classList.add(n==="asc"?"ln-sort-asc":"ln-sort-desc")):this.currentSort=null,m(this.dom,"ln-data-table:sort",{table:this.name,field:e,direction:n}),this._requestData()},a.prototype._requestData=function(){m(this.dom,"ln-data-table:request-data",{table:this.name,sort:this.currentSort,filters:this.currentFilters,search:this.currentSearch})},a.prototype._updateSelectAll=function(){if(!this._selectAllCheckbox||!this.tbody)return;const e=this.tbody.querySelectorAll("[data-ln-row]");let t=e.length>0;for(let n=0;n<e.length;n++){const l=e[n].getAttribute("data-ln-row-id");if(l!=null&&!this.selectedIds.has(l)){t=!1;break}}this._selectAllCheckbox.checked=t},Object.defineProperty(a.prototype,"selectedCount",{get:function(){return this.selectedIds.size},set:function(){}}),a.prototype._enableSelection=function(){if(this._selectableActive)return;this._selectableActive=!0;const e=this;if(this._onSelectionChange=function(t){const n=t.target.closest("[data-ln-row-select]");if(!n)return;const l=n.closest("[data-ln-row]");if(!l)return;const i=l.getAttribute("data-ln-row-id");i!=null&&(n.checked?(e.selectedIds.add(i),l.classList.add("ln-row-selected")):(e.selectedIds.delete(i),l.classList.remove("ln-row-selected")),e.selectedCount=e.selectedIds.size,e._updateSelectAll(),e._updateFooter(),m(e.dom,"ln-data-table:select",{table:e.name,selectedIds:e.selectedIds,count:e.selectedCount}))},this.tbody&&this.tbody.addEventListener("change",this._onSelectionChange),this._selectAllCheckbox=this.dom.querySelector('[data-ln-col-select] input[type="checkbox"]')||this.dom.querySelector("[data-ln-col-select]"),this._selectAllCheckbox&&this._selectAllCheckbox.tagName==="TH"){const t=document.createElement("input");t.type="checkbox",t.setAttribute("aria-label","Select all"),this._selectAllCheckbox.appendChild(t),this._selectAllCheckbox=t}if(this._selectAllCheckbox&&(this._onSelectAll=function(){const t=e._selectAllCheckbox.checked,n=e.tbody?e.tbody.querySelectorAll("[data-ln-row]"):[];for(let l=0;l<n.length;l++){const i=n[l].getAttribute("data-ln-row-id"),s=n[l].querySelector("[data-ln-row-select]");i!=null&&(t?(e.selectedIds.add(i),n[l].classList.add("ln-row-selected")):(e.selectedIds.delete(i),n[l].classList.remove("ln-row-selected")),s&&(s.checked=t))}e.selectedCount=e.selectedIds.size,m(e.dom,"ln-data-table:select-all",{table:e.name,selected:t}),m(e.dom,"ln-data-table:select",{table:e.name,selectedIds:e.selectedIds,count:e.selectedCount}),e._updateFooter()},this._selectAllCheckbox.addEventListener("change",this._onSelectAll)),this.tbody){const t=this.tbody.querySelectorAll("[data-ln-row]");for(let n=0;n<t.length;n++){const l=t[n].querySelector("[data-ln-row-select]"),i=t[n].getAttribute("data-ln-row-id");l&&l.checked&&i!=null&&(this.selectedIds.add(i),t[n].classList.add("ln-row-selected"))}this.selectedCount=this.selectedIds.size,this.selectedCount>0&&this._updateSelectAll()}},a.prototype._disableSelection=function(){if(!this._selectableActive)return;this._selectableActive=!1,this.tbody&&this._onSelectionChange&&this.tbody.removeEventListener("change",this._onSelectionChange),this._selectAllCheckbox&&this._onSelectAll&&this._selectAllCheckbox.removeEventListener("change",this._onSelectAll);const e=this.dom.querySelector("[data-ln-col-select]");if(e){const t=e.querySelector('input[type="checkbox"]');t&&t.remove()}if(this._selectAllCheckbox=null,this.selectedIds.clear(),this.selectedCount=0,this.tbody){const t=this.tbody.querySelectorAll("[data-ln-row]");for(let n=0;n<t.length;n++){t[n].classList.remove("ln-row-selected");const l=t[n].querySelector("[data-ln-row-select]");l&&(l.checked=!1)}}this._updateFooter()},a.prototype._focusRow=function(e){for(let t=0;t<e.length;t++)e[t].classList.remove("ln-row-focused"),e[t].removeAttribute("tabindex");if(this._focusedRowIndex>=0&&this._focusedRowIndex<e.length){const t=e[this._focusedRowIndex];t.classList.add("ln-row-focused"),t.setAttribute("tabindex","0"),t.focus(),t.scrollIntoView({block:"nearest"})}},a.prototype._openFilterDropdown=function(e,t,n){this._closeFilterDropdown();const l=E(this.dom,this.name+"-column-filter","ln-data-table")||E(this.dom,"column-filter","ln-data-table");if(!l)return;const i=l.firstElementChild;if(!i)return;const s=this._getUniqueValues(e),c=i.querySelector("[data-ln-filter-options]"),d=i.querySelector("[data-ln-filter-search]"),f=this.currentFilters[e]||[],p=this;if(d&&s.length<=8&&d.classList.add("hidden"),c){const v=c.querySelector("[data-ln-filter-reset]");v&&(v.checked=f.length===0);const w=E(i,this.name+"-column-filter-item","ln-data-table")||E(i,"column-filter-item","ln-data-table");if(w)for(let h=0;h<s.length;h++){const b=s[h],k=w.cloneNode(!0);D(k,{value:b});const L=k.querySelector('input[type="checkbox"]');L&&(L.value=b,L.checked=f.length>0&&f.indexOf(b)!==-1),c.appendChild(k)}c.addEventListener("change",function(h){h.target.type==="checkbox"&&(p._applyFilterMutualExclusion(h.target,c),p._onFilterChange(e,c))})}d&&d.addEventListener("input",function(){const v=d.value.toLowerCase(),w=c.querySelectorAll("li");for(let h=0;h<w.length;h++){const b=w[h].textContent.toLowerCase();w[h].classList.toggle("hidden",v&&b.indexOf(v)===-1)}});const A=i.querySelector("[data-ln-filter-clear]");A&&A.addEventListener("click",function(){delete p.currentFilters[e],p._closeFilterDropdown(),p._updateFilterIndicators(),m(p.dom,"ln-data-table:filter",{table:p.name,field:e,values:[]}),p._requestData()}),t.appendChild(i),this._activeDropdown={field:e,th:t,el:i},i.addEventListener("click",function(v){v.stopPropagation()})},a.prototype._closeFilterDropdown=function(){this._activeDropdown&&(this._activeDropdown.el&&this._activeDropdown.el.parentNode&&this._activeDropdown.el.parentNode.removeChild(this._activeDropdown.el),this._activeDropdown=null)},a.prototype._applyFilterMutualExclusion=function(e,t){const n=e.hasAttribute("data-ln-filter-reset"),l=t.querySelector("[data-ln-filter-reset]"),i=t.querySelectorAll('input[type="checkbox"]:not([data-ln-filter-reset])');if(n){e.checked=!0;for(let s=0;s<i.length;s++)i[s].checked=!1}else if(e.checked)l&&(l.checked=!1);else{let s=!1;for(let c=0;c<i.length;c++)if(i[c].checked){s=!0;break}!s&&l&&(l.checked=!0)}},a.prototype._onFilterChange=function(e,t){const n=t.querySelector("[data-ln-filter-reset]"),l=t.querySelectorAll('input[type="checkbox"]:not([data-ln-filter-reset])'),i=[];for(let c=0;c<l.length;c++)l[c].checked&&i.push(l[c].value);const s=n&&n.checked||i.length===0;s?delete this.currentFilters[e]:this.currentFilters[e]=i,this._updateFilterIndicators(),m(this.dom,"ln-data-table:filter",{table:this.name,field:e,values:s?[]:i}),this._requestData()},a.prototype._updateFilterOptions=function(e){if(e!==null&&typeof e=="object"&&!Array.isArray(e)){const t=Object.keys(e);for(let n=0;n<t.length;n++){const l=t[n],i=e[l];if(!Array.isArray(i))continue;const s={},c=[];for(let d=0;d<i.length;d++){const f=String(i[d]);s[f]||(s[f]=!0,c.push(f))}this._filterOptions[l]=c.sort()}}else{const t=this._filterableFields,n=this._data;for(let l=0;l<t.length;l++){const i=t[l];this._filterOptions[i]||(this._filterOptions[i]=[]);const s=this._filterOptions[i],c={};for(let d=0;d<s.length;d++)c[s[d]]=!0;for(let d=0;d<n.length;d++){const f=n[d][i];if(f!=null){const p=String(f);c[p]||(c[p]=!0,s.push(p))}}s.sort()}}},a.prototype._getUniqueValues=function(e){return(this._filterOptions[e]||[]).slice().sort()},a.prototype._updateFilterIndicators=function(){const e=this.ths;for(let t=0;t<e.length;t++){const n=e[t],l=n.getAttribute("data-ln-col");if(!l)continue;const i=n.querySelector("[data-ln-col-filter]");if(!i)continue;const s=this.currentFilters[l]&&this.currentFilters[l].length>0;i.classList.toggle("ln-filter-active",!!s)}},a.prototype._renderRows=function(){if(!this.tbody)return;const e=this._data,t=this._lastTotal,n=this._lastFiltered;if(t===0){this._disableVirtualScroll(),this._showEmptyState(this.name+"-empty");return}if(e.length===0||n===0){this._disableVirtualScroll(),this._showEmptyState(this.name+"-empty-filtered");return}e.length>200?(this._enableVirtualScroll(),this._renderVirtual()):(this._disableVirtualScroll(),this._renderAll())},a.prototype._renderAll=function(){const e=this._data,t=document.createDocumentFragment();for(let n=0;n<e.length;n++){const l=this._buildRow(e[n]);if(!l)break;t.appendChild(l)}this.tbody.textContent="",this.tbody.appendChild(t),this._selectable&&this._updateSelectAll()},a.prototype._buildRow=function(e){const t=E(this.dom,this.name+"-row","ln-data-table");if(!t)return null;const n=t.querySelector("[data-ln-row]")||t.firstElementChild;if(!n)return null;if(this._fillRow(n,e),n._lnRecord=e,e.id!=null&&n.setAttribute("data-ln-row-id",e.id),this._selectable&&e.id!=null&&this.selectedIds.has(String(e.id))){n.classList.add("ln-row-selected");const l=n.querySelector("[data-ln-row-select]");l&&(l.checked=!0)}return n},a.prototype._enableVirtualScroll=function(){if(this._virtual)return;this._virtual=!0,this._vStart=-1,this._vEnd=-1;const e=this;if(!this._rowHeight){const n=this._buildRow(this._data[0]);n&&(this.tbody.textContent="",this.tbody.appendChild(n),this._rowHeight=n.offsetHeight||40,this.tbody.textContent="")}this._scrollContainer=u(this.dom);const t=this._scrollContainer||window;this._scrollHandler=function(){e._rafId||(e._rafId=requestAnimationFrame(function(){e._rafId=null,e._renderVirtual()}))},t.addEventListener("scroll",this._scrollHandler,{passive:!0}),window.addEventListener("resize",this._scrollHandler,{passive:!0})},a.prototype._disableVirtualScroll=function(){this._virtual&&(this._virtual=!1,this._scrollHandler&&((this._scrollContainer||window).removeEventListener("scroll",this._scrollHandler),window.removeEventListener("resize",this._scrollHandler),this._scrollHandler=null),this._scrollContainer=null,this._rafId&&(cancelAnimationFrame(this._rafId),this._rafId=null),this._vStart=-1,this._vEnd=-1)},a.prototype._renderVirtual=function(){const e=this._data,t=e.length,n=this._rowHeight;if(!n||!t)return;const l=this.thead?this.thead.offsetHeight:0,i=this._scrollContainer;let s,c;if(i){const h=this.table.getBoundingClientRect(),b=i.getBoundingClientRect(),k=h.top-b.top+i.scrollTop+l;s=i.scrollTop-k,c=i.clientHeight}else{const k=this.table.getBoundingClientRect().top+window.scrollY+l;s=window.scrollY-k,c=window.innerHeight}let d=Math.max(0,Math.floor(s/n)-15);d=Math.min(d,t);const f=Math.min(d+Math.ceil(c/n)+30,t);if(d===this._vStart&&f===this._vEnd)return;this._vStart=d,this._vEnd=f;const p=this.ths.length||1,A=d*n,v=(t-f)*n,w=document.createDocumentFragment();if(A>0){const h=document.createElement("tr");h.className="ln-data-table__spacer",h.setAttribute("aria-hidden","true");const b=document.createElement("td");b.setAttribute("colspan",p),b.style.height=A+"px",h.appendChild(b),w.appendChild(h)}for(let h=d;h<f;h++){const b=this._buildRow(e[h]);b&&w.appendChild(b)}if(v>0){const h=document.createElement("tr");h.className="ln-data-table__spacer",h.setAttribute("aria-hidden","true");const b=document.createElement("td");b.setAttribute("colspan",p),b.style.height=v+"px",h.appendChild(b),w.appendChild(h)}this.tbody.textContent="",this.tbody.appendChild(w),this._selectable&&this._updateSelectAll()},a.prototype._fillRow=function(e,t){T(e,t);const n=e.querySelectorAll("[data-ln-cell-attr]");for(let l=0;l<n.length;l++){const i=n[l],s=i.getAttribute("data-ln-cell-attr").split(",");for(let c=0;c<s.length;c++){const d=s[c].trim().split(":");if(d.length!==2)continue;const f=d[0].trim(),p=d[1].trim();t[f]!=null&&i.setAttribute(p,t[f])}}},a.prototype._showEmptyState=function(e){const t=E(this.dom,e,"ln-data-table");this.tbody.textContent="",t&&this.tbody.appendChild(t)},a.prototype._updateFooter=function(){const e=this._lastTotal,t=this._lastFiltered,n=t<e;if(this._totalSpan&&(this._totalSpan.textContent=S(e)),this._filteredSpan&&(this._filteredSpan.textContent=n?S(t):""),this._filteredWrap&&this._filteredWrap.classList.toggle("hidden",!n),this._selectedSpan){const l=this.selectedIds.size;this._selectedSpan.textContent=l>0?S(l):"",this._selectedWrap&&this._selectedWrap.classList.toggle("hidden",l===0)}},a.prototype.destroy=function(){this.dom[r]&&(this.dom.removeEventListener("ln-data-table:set-data",this._onSetData),this.dom.removeEventListener("ln-data-table:set-loading",this._onSetLoading),this.thead&&(this.thead.removeEventListener("click",this._onSortClick),this.thead.removeEventListener("click",this._onFilterClick)),document.removeEventListener("click",this._onDocClick),document.removeEventListener("keydown",this._onKeydown),this._searchInput&&this._searchInput.removeEventListener("input",this._onSearchInput),this.tbody&&(this.tbody.removeEventListener("click",this._onRowClick),this.tbody.removeEventListener("click",this._onRowAction)),this._onSelectionChange&&this.tbody&&this.tbody.removeEventListener("change",this._onSelectionChange),this._selectAllCheckbox&&this._onSelectAll&&this._selectAllCheckbox.removeEventListener("change",this._onSelectAll),this.dom.removeEventListener("click",this._onClearAll),this._closeFilterDropdown(),this._disableVirtualScroll(),this._data=[],delete this.dom[r])};function g(e,t){const n=e[r];if(n&&t==="data-ln-data-table-selectable"){const l=e.hasAttribute("data-ln-data-table-selectable");l!==n._selectable&&(n._selectable=l,l?n._enableSelection():n._disableSelection())}}O(o,r,a,"ln-data-table",{extraAttributes:["data-ln-data-table-selectable"],onAttributeChange:g})})()})();
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// ── JS state: data table loading ──
|
|
2
|
-
// Loading-class added by JS while async data fetches; visual stays here
|
|
3
|
-
// because it's a transient JS-controlled state transition.
|
|
4
|
-
|
|
5
|
-
.ln-data-table--loading {
|
|
6
|
-
tbody {
|
|
7
|
-
opacity: 0.5;
|
|
8
|
-
pointer-events: none;
|
|
9
|
-
}
|
|
10
|
-
}
|