@livenetworks/ashlar 2.0.6 → 2.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +641 -641
- package/components/COMPONENTS.md +1116 -1116
- package/components/index.js +81 -81
- package/components/ln-accordion/ln-accordion-dev.scss +8 -8
- package/components/ln-accordion/ln-accordion.js +1 -1
- package/components/ln-accordion/ln-accordion.schema.json +30 -30
- package/components/ln-accordion/src/ln-accordion.js +1 -0
- package/components/ln-ajax/ln-ajax-dev.scss +8 -8
- package/components/ln-ajax/ln-ajax.js +1 -1
- package/components/ln-ajax/ln-ajax.schema.json +30 -30
- package/components/ln-api-connector/ln-api-connector.js +1 -1
- package/components/ln-api-connector/ln-api-connector.schema.json +96 -96
- package/components/ln-api-connector/src/ln-api-connector.js +1 -0
- package/components/ln-api-queue/ln-api-queue.js +1 -1
- package/components/ln-api-queue/ln-api-queue.schema.json +34 -34
- package/components/ln-api-queue/src/ln-api-queue.js +3 -13
- package/components/ln-autoresize/ln-autoresize-dev.scss +8 -8
- package/components/ln-autoresize/ln-autoresize.js +1 -1
- package/components/ln-autoresize/ln-autoresize.schema.json +22 -22
- package/components/ln-autosave/ln-autosave-dev.scss +13 -13
- package/components/ln-autosave/ln-autosave.js +1 -1
- package/components/ln-autosave/ln-autosave.schema.json +48 -48
- package/components/ln-autosave/src/autosave-model.js +34 -34
- package/components/ln-chart/ln-chart.js +1 -1
- package/components/ln-chart/ln-chart.schema.json +146 -146
- package/components/ln-chart/src/chart-model.js +154 -154
- package/components/ln-circular-progress/ln-circular-progress.js +1 -1
- package/components/ln-circular-progress/ln-circular-progress.schema.json +42 -42
- package/components/ln-confirm/ln-confirm-dev.scss +24 -24
- package/components/ln-confirm/ln-confirm.js +1 -1
- package/components/ln-confirm/ln-confirm.schema.json +66 -66
- package/components/ln-confirm/src/ln-confirm.js +178 -178
- package/components/ln-core/crypto.js +286 -265
- package/components/ln-core/dom.js +115 -115
- package/components/ln-core/form.js +136 -136
- package/components/ln-core/helpers.js +33 -33
- package/components/ln-core/http.js +48 -48
- package/components/ln-core/index.js +1 -1
- package/components/ln-core/ln-core.schema.json +109 -109
- package/components/ln-core/locale.js +55 -55
- package/components/ln-core/matching.js +78 -78
- package/components/ln-core/number.js +125 -125
- package/components/ln-core/template.js +206 -206
- package/components/ln-couchdb-connector/README.md +4 -0
- package/components/ln-couchdb-connector/ln-couchdb-connector.js +1 -1
- package/components/ln-couchdb-connector/ln-couchdb-connector.schema.json +50 -50
- package/components/ln-couchdb-connector/src/ln-couchdb-connector.js +19 -1
- package/components/ln-data-coordinator/README.md +9 -38
- package/components/ln-data-coordinator/ln-data-coordinator-dev.scss +8 -8
- package/components/ln-data-coordinator/ln-data-coordinator.js +1 -1
- package/components/ln-data-coordinator/ln-data-coordinator.schema.json +16 -16
- package/components/ln-data-coordinator/src/data-read-policy.js +0 -7
- package/components/ln-data-coordinator/src/ln-data-coordinator.js +428 -1299
- package/components/ln-data-store/README.md +3 -2
- package/components/ln-data-store/ln-data-store-dev.scss +13 -13
- package/components/ln-data-store/ln-data-store.js +1 -1
- package/components/ln-data-store/ln-data-store.schema.json +84 -84
- package/components/ln-data-store/src/data-store-model.js +184 -155
- package/components/ln-data-store/src/ln-data-store.js +58 -11
- package/components/ln-date/README.md +4 -0
- package/components/ln-date/ln-date.js +1 -1
- package/components/ln-date/ln-date.schema.json +92 -92
- package/components/ln-date/src/date-model.js +186 -186
- package/components/ln-date/src/ln-date.js +3 -3
- package/components/ln-debug/ln-debug.js +1 -1
- package/components/ln-debug/ln-debug.schema.json +28 -28
- package/components/ln-debug/src/console-sink.js +19 -19
- package/components/ln-debug/src/gate.js +95 -95
- package/components/ln-debug/src/generated-attributes.js +2 -2
- package/components/ln-dropdown/ln-dropdown-dev.scss +13 -13
- package/components/ln-dropdown/ln-dropdown.js +1 -1
- package/components/ln-dropdown/ln-dropdown.schema.json +90 -90
- package/components/ln-editor/ln-editor.js +1 -1
- package/components/ln-editor/ln-editor.schema.json +58 -58
- package/components/ln-external-links/ln-external-links.js +1 -1
- package/components/ln-external-links/ln-external-links.schema.json +18 -18
- package/components/ln-fill/ln-fill.js +1 -1
- package/components/ln-fill/ln-fill.schema.json +23 -23
- package/components/ln-filter/ln-filter.js +1 -1
- package/components/ln-filter/ln-filter.schema.json +153 -153
- package/components/ln-filter/src/filter-model.js +185 -185
- package/components/ln-form/ln-form-dev.scss +8 -8
- package/components/ln-form/ln-form.js +1 -1
- package/components/ln-form/ln-form.schema.json +45 -45
- package/components/ln-http/ln-http.js +1 -1
- package/components/ln-http/ln-http.schema.json +6 -6
- package/components/ln-icon/ln-icon.schema.json +6 -6
- package/components/ln-include/ln-include.js +1 -1
- package/components/ln-include/ln-include.schema.json +23 -23
- package/components/ln-key/ln-key-dev.scss +18 -18
- package/components/ln-key/ln-key.js +1 -1
- package/components/ln-key/ln-key.schema.json +56 -56
- package/components/ln-key/src/ln-key.js +10 -10
- package/components/ln-link/ln-link-dev.scss +8 -8
- package/components/ln-link/ln-link.js +1 -1
- package/components/ln-link/ln-link.schema.json +22 -22
- package/components/ln-list/README.md +152 -152
- package/components/ln-list/ln-list-dev.scss +8 -8
- package/components/ln-list/ln-list.js +1 -1
- package/components/ln-list/ln-list.schema.json +166 -166
- package/components/ln-list/src/ln-list.js +4 -4
- package/components/ln-modal/README.md +4 -6
- package/components/ln-modal/ln-modal.js +1 -1
- package/components/ln-modal/ln-modal.schema.json +65 -65
- package/components/ln-modal/src/ln-modal.js +28 -8
- package/components/ln-nav/ln-nav.js +1 -1
- package/components/ln-nav/ln-nav.schema.json +25 -25
- package/components/ln-number/ln-number.js +1 -1
- package/components/ln-number/ln-number.schema.json +63 -63
- package/components/ln-number/src/number-model.js +31 -31
- package/components/ln-obfuscator/README.md +60 -60
- package/components/ln-obfuscator/ln-obfuscator.js +1 -1
- package/components/ln-obfuscator/ln-obfuscator.schema.json +49 -49
- package/components/ln-obfuscator/src/ln-obfuscator.js +159 -159
- package/components/ln-obfuscator/src/obfuscator-model.js +250 -250
- package/components/ln-options/ln-options.js +1 -1
- package/components/ln-options/ln-options.schema.json +41 -41
- package/components/ln-options/src/ln-options.js +1 -0
- package/components/ln-persist/README.md +151 -151
- package/components/ln-persist/ln-persist.js +1 -1
- package/components/ln-persist/ln-persist.schema.json +28 -28
- package/components/ln-persist/src/ln-persist.js +83 -83
- package/components/ln-picklist/README.md +230 -230
- package/components/ln-picklist/ln-picklist-dev.scss +22 -22
- package/components/ln-picklist/ln-picklist.js +1 -1
- package/components/ln-picklist/ln-picklist.schema.json +49 -49
- package/components/ln-picklist/src/ln-picklist.js +228 -228
- package/components/ln-popover/README.md +4 -0
- package/components/ln-popover/ln-popover-dev.scss +13 -13
- package/components/ln-popover/ln-popover.js +1 -1
- package/components/ln-popover/ln-popover.schema.json +82 -82
- package/components/ln-popover/src/ln-popover.js +9 -0
- package/components/ln-progress/ln-progress-dev.scss +8 -8
- package/components/ln-progress/ln-progress.js +1 -1
- package/components/ln-progress/ln-progress.schema.json +40 -40
- package/components/ln-router/ln-router.js +1 -1
- package/components/ln-router/ln-router.schema.json +76 -76
- package/components/ln-scroll/README.md +45 -45
- package/components/ln-scroll/ln-scroll.js +1 -1
- package/components/ln-scroll/ln-scroll.schema.json +85 -85
- package/components/ln-scroll/src/ln-scroll.js +150 -150
- package/components/ln-search/README.md +188 -188
- package/components/ln-search/ln-search.js +1 -1
- package/components/ln-search/ln-search.schema.json +103 -103
- package/components/ln-slug/ln-slug.js +1 -1
- package/components/ln-slug/ln-slug.schema.json +23 -23
- package/components/ln-sort/ln-sort.js +1 -1
- package/components/ln-sort/ln-sort.schema.json +104 -104
- package/components/ln-sort/src/ln-sort.js +321 -321
- package/components/ln-sort/src/sort-model.js +117 -117
- package/components/ln-sortable/ln-sortable-dev.scss +13 -13
- package/components/ln-sortable/ln-sortable.js +1 -1
- package/components/ln-sortable/ln-sortable.schema.json +36 -36
- package/components/ln-stat/ln-stat-dev.scss +8 -8
- package/components/ln-stat/ln-stat.js +1 -1
- package/components/ln-stat/ln-stat.schema.json +32 -32
- package/components/ln-stat/src/stat-model.js +28 -28
- package/components/ln-table/ln-table.js +1 -1
- package/components/ln-table/ln-table.schema.json +211 -211
- package/components/ln-table/src/ln-table.js +2 -0
- package/components/ln-table/src/table-model.js +98 -98
- package/components/ln-table-coordinator/ln-table-coordinator.js +1 -1
- package/components/ln-table-coordinator/ln-table-coordinator.schema.json +93 -93
- package/components/ln-table-coordinator/src/ln-table-coordinator.js +3 -3
- package/components/ln-tabs/README.md +2 -2
- package/components/ln-tabs/ln-tabs.js +1 -1
- package/components/ln-tabs/ln-tabs.schema.json +75 -75
- package/components/ln-tabs/src/ln-tabs.js +208 -207
- package/components/ln-tabs/src/tabs-model.js +82 -82
- package/components/ln-time/ln-time-dev.scss +13 -13
- package/components/ln-time/ln-time.js +1 -1
- package/components/ln-time/ln-time.schema.json +38 -38
- package/components/ln-toast/ln-toast.js +1 -1
- package/components/ln-toast/ln-toast.schema.json +65 -65
- package/components/ln-toggle/ln-toggle.js +1 -1
- package/components/ln-toggle/ln-toggle.schema.json +52 -52
- package/components/ln-tooltip/ln-tooltip.js +1 -1
- package/components/ln-tooltip/ln-tooltip.schema.json +86 -86
- package/components/ln-translations/ln-translations.js +1 -1
- package/components/ln-translations/ln-translations.schema.json +120 -120
- package/components/ln-ui-coordinator/README.md +62 -62
- package/components/ln-ui-coordinator/ln-ui-coordinator.js +1 -1
- package/components/ln-ui-coordinator/ln-ui-coordinator.schema.json +28 -28
- package/components/ln-ui-coordinator/src/ln-ui-coordinator.js +140 -140
- package/components/ln-upload/ln-upload.js +1 -1
- package/components/ln-upload/ln-upload.schema.json +193 -193
- package/components/ln-upload/src/upload-model.js +78 -78
- package/components/ln-validate/ln-validate.js +1 -1
- package/components/ln-validate/ln-validate.schema.json +50 -50
- package/components/ln-validate/src/validate-model.js +64 -64
- package/components/ln-websocket-connector/README.md +166 -166
- package/components/ln-websocket-connector/ln-websocket-connector.js +1 -1
- package/components/ln-websocket-connector/ln-websocket-connector.schema.json +29 -29
- package/components/ln-websocket-connector/src/ln-websocket-connector.js +283 -279
- package/ln-ashlar.html-data.json +7 -8
- package/package.json +84 -84
- package/theme/brand.css +73 -73
- package/theme/components/_confirm.scss +6 -6
- package/theme/components/_picklist.scss +3 -3
- package/theme/config/_palette.scss +274 -274
- package/theme/config/_theme.scss +292 -292
- package/theme/config/_tokens.scss +285 -285
- package/theme/config/mixins/_index.scss +62 -62
- package/theme/config/mixins/_picklist.scss +66 -66
- package/theme/ln-ashlar-dev.scss +66 -66
- package/theme/ln-ashlar-landing.scss +56 -56
- package/theme/ln-ashlar-theme.scss +63 -63
- package/theme/presentation/_bento.scss +151 -151
- package/theme/presentation/_cta.scss +111 -111
- package/theme/presentation/_effects.scss +216 -216
- package/theme/presentation/_features.scss +108 -108
- package/theme/presentation/_footer.scss +129 -129
- package/theme/presentation/_hero.scss +158 -158
- package/theme/presentation/_layout.scss +170 -170
- package/theme/presentation/_navbar.scss +140 -140
- package/theme/presentation/_pricing.scss +262 -262
- package/theme/presentation/_stats.scss +87 -87
- package/theme/presentation/_testimonials.scss +124 -124
- package/theme/presentation/_tokens.scss +39 -39
- package/theme/presentation/_typography.scss +163 -163
- package/web-types.json +12 -12
|
@@ -1,228 +1,228 @@
|
|
|
1
|
-
import { registerComponent, dispatch, dispatchCancelable } from '../../ln-core';
|
|
2
|
-
|
|
3
|
-
(function () {
|
|
4
|
-
'use strict';
|
|
5
|
-
|
|
6
|
-
const DOM_SELECTOR = 'data-ln-picklist';
|
|
7
|
-
const DOM_ATTRIBUTE = 'lnPicklist';
|
|
8
|
-
const LIST_ATTR = 'data-ln-picklist-list';
|
|
9
|
-
const MAX_ATTR = 'data-ln-picklist-max';
|
|
10
|
-
|
|
11
|
-
if (window[DOM_ATTRIBUTE] !== undefined) return;
|
|
12
|
-
|
|
13
|
-
// ─── Attribute Contract (SSOT) ──────────────────────────
|
|
14
|
-
const ATTRIBUTES = {
|
|
15
|
-
'data-ln-picklist': { type: 'enum', values: ['enabled', 'disabled'], fallback: 'enabled', effect: _syncEnabled, description: 'Controls enabled/disabled state of the dual-list picklist' },
|
|
16
|
-
'data-ln-picklist-max': { type: 'integer', fallback: Infinity, min: 1, effect: _syncMax, description: 'Maximum selectable items in the selected list' },
|
|
17
|
-
'data-ln-picklist-list': { type: 'enum', values: ['available', 'selected'], description: 'Role marker for available or selected picklist columns' }
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
// ─── Component ─────────────────────────────────────────────
|
|
21
|
-
//
|
|
22
|
-
// The checkbox IS the state. Its `checked` property and the list the item
|
|
23
|
-
// currently sits in are the same fact, and `name`/`value` carry the
|
|
24
|
-
// selection to the server natively — unchecked boxes are not submitted.
|
|
25
|
-
// Hence no hidden inputs, no state attribute and no JS mirror.
|
|
26
|
-
|
|
27
|
-
function _component(dom) {
|
|
28
|
-
this.dom = dom;
|
|
29
|
-
this.isEnabled = dom.getAttribute(DOM_SELECTOR) !== 'disabled';
|
|
30
|
-
this.max = _readMax(dom);
|
|
31
|
-
|
|
32
|
-
this.available = dom.querySelector('[' + LIST_ATTR + '="available"]');
|
|
33
|
-
this.selected = dom.querySelector('[' + LIST_ATTR + '="selected"]');
|
|
34
|
-
|
|
35
|
-
// Report the gap rather than failing on the first click.
|
|
36
|
-
if (!this.available || !this.selected) {
|
|
37
|
-
console.warn('[ln-picklist] requires both [' + LIST_ATTR + '="available"] and [' + LIST_ATTR + '="selected"]', dom);
|
|
38
|
-
return this;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Bound once so destroy() can detach the same reference.
|
|
42
|
-
this._onChange = this._onChange.bind(this);
|
|
43
|
-
dom.addEventListener('change', this._onChange);
|
|
44
|
-
|
|
45
|
-
// Snapshot the authored items in document order.
|
|
46
|
-
this._initial = [];
|
|
47
|
-
for (const list of [this.available, this.selected]) {
|
|
48
|
-
for (const item of list.children) {
|
|
49
|
-
this._initial.push(item);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Initial sync: transfer checked items to selected, unchecked to available.
|
|
54
|
-
this.sync();
|
|
55
|
-
|
|
56
|
-
this._form = dom.closest('form');
|
|
57
|
-
if (this._form) {
|
|
58
|
-
this._onFormReset = this._onFormReset.bind(this);
|
|
59
|
-
this._form.addEventListener('reset', this._onFormReset);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return this;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ─── Lifecycle ─────────────────────────────────────────────
|
|
66
|
-
|
|
67
|
-
_component.prototype.destroy = function () {
|
|
68
|
-
if (!this.dom[DOM_ATTRIBUTE]) return;
|
|
69
|
-
this._destroyed = true;
|
|
70
|
-
if (this._onChange) this.dom.removeEventListener('change', this._onChange);
|
|
71
|
-
if (this._form) this._form.removeEventListener('reset', this._onFormReset);
|
|
72
|
-
delete this.dom[DOM_ATTRIBUTE];
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
// ─── Instance API ──────────────────────────────────────────
|
|
76
|
-
|
|
77
|
-
_component.prototype.enable = function () {
|
|
78
|
-
this.dom.setAttribute(DOM_SELECTOR, '');
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
_component.prototype.disable = function () {
|
|
82
|
-
this.dom.setAttribute(DOM_SELECTOR, 'disabled');
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
_component.prototype.sync = function () {
|
|
86
|
-
if (!this.available || !this.selected) return;
|
|
87
|
-
|
|
88
|
-
// Include any dynamically added items not yet tracked
|
|
89
|
-
const currentItems = Array.from(this.available.children).concat(Array.from(this.selected.children));
|
|
90
|
-
for (let i = 0; i < currentItems.length; i++) {
|
|
91
|
-
if (!this._initial.includes(currentItems[i])) {
|
|
92
|
-
this._initial.push(currentItems[i]);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
let selectedCount = 0;
|
|
97
|
-
for (let i = 0; i < this._initial.length; i++) {
|
|
98
|
-
const item = this._initial[i];
|
|
99
|
-
if (!item.isConnected) continue;
|
|
100
|
-
const checkbox = item.querySelector('input[type="checkbox"]');
|
|
101
|
-
if (!checkbox) continue;
|
|
102
|
-
|
|
103
|
-
let targetList;
|
|
104
|
-
if (checkbox.checked) {
|
|
105
|
-
if (this.max === null || selectedCount < this.max) {
|
|
106
|
-
targetList = this.selected;
|
|
107
|
-
selectedCount++;
|
|
108
|
-
} else {
|
|
109
|
-
checkbox.checked = false;
|
|
110
|
-
targetList = this.available;
|
|
111
|
-
}
|
|
112
|
-
} else {
|
|
113
|
-
targetList = this.available;
|
|
114
|
-
}
|
|
115
|
-
targetList.appendChild(item);
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// ─── Form Reset ────────────────────────────────────────────
|
|
120
|
-
//
|
|
121
|
-
// Resetting a form restores every control to its default SILENTLY — the
|
|
122
|
-
// spec fires no `change` and no `input` for them, only `reset` on the form
|
|
123
|
-
// itself. Re-syncing in recorded order rebuilds both lists according to
|
|
124
|
-
// defaultChecked.
|
|
125
|
-
|
|
126
|
-
_component.prototype._onFormReset = function (e) {
|
|
127
|
-
const self = this;
|
|
128
|
-
|
|
129
|
-
// `reset` fires BEFORE the controls are restored, and it is cancelable,
|
|
130
|
-
// so the work is deferred and re-checked — the same shape ln-editor
|
|
131
|
-
// uses to re-read its textarea.
|
|
132
|
-
setTimeout(function () {
|
|
133
|
-
if (self._destroyed || e.defaultPrevented) return;
|
|
134
|
-
self.sync();
|
|
135
|
-
}, 0);
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
// ─── Change Handler ────────────────────────────────────────
|
|
139
|
-
|
|
140
|
-
_component.prototype._onChange = function (e) {
|
|
141
|
-
// `change` bubbles, so anything the author composes inside the root —
|
|
142
|
-
// an ln-search input, a select — reaches this listener. Filter hard.
|
|
143
|
-
const checkbox = e.target.closest('input[type="checkbox"]');
|
|
144
|
-
if (!checkbox) return;
|
|
145
|
-
|
|
146
|
-
const item = checkbox.closest('li');
|
|
147
|
-
if (!item) return;
|
|
148
|
-
|
|
149
|
-
const from = item.parentElement;
|
|
150
|
-
if (from !== this.available && from !== this.selected) return;
|
|
151
|
-
|
|
152
|
-
// The browser has already toggled the box by the time this runs, so a
|
|
153
|
-
// bare return would leave it checked while the item stays put — which
|
|
154
|
-
// is exactly the contradiction this component exists to avoid.
|
|
155
|
-
if (!this.isEnabled) {
|
|
156
|
-
checkbox.checked = !checkbox.checked;
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const to = checkbox.checked ? this.selected : this.available;
|
|
161
|
-
|
|
162
|
-
// Inconsistent authored markup (a checked item rendered on the left),
|
|
163
|
-
// or a synthetic change that did not flip the box, would otherwise
|
|
164
|
-
// re-append in place and emit a move that never happened.
|
|
165
|
-
if (from === to) return;
|
|
166
|
-
|
|
167
|
-
// Enforce maximum selection limit if configured
|
|
168
|
-
if (to === this.selected && this.max !== null && this.selected.children.length >= this.max) {
|
|
169
|
-
checkbox.checked = !checkbox.checked;
|
|
170
|
-
dispatch(this.dom, 'ln-picklist:max-reached', {
|
|
171
|
-
max: this.max,
|
|
172
|
-
item: item,
|
|
173
|
-
checkbox: checkbox,
|
|
174
|
-
count: this.selected.children.length
|
|
175
|
-
});
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// One record, both events — they describe the same move.
|
|
180
|
-
const detail = { item: item, from: from, to: to, checkbox: checkbox };
|
|
181
|
-
|
|
182
|
-
if (dispatchCancelable(this.dom, 'ln-picklist:before-move', detail).defaultPrevented) {
|
|
183
|
-
checkbox.checked = !checkbox.checked;
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Re-parenting a node that holds focus blurs it to <body> in Chromium.
|
|
188
|
-
// Only restore when the focus really was here: a synthetic change from
|
|
189
|
-
// a script must not steal focus away from whatever the user is using.
|
|
190
|
-
const hadFocus = document.activeElement === checkbox;
|
|
191
|
-
|
|
192
|
-
to.appendChild(item);
|
|
193
|
-
|
|
194
|
-
if (hadFocus) checkbox.focus();
|
|
195
|
-
|
|
196
|
-
dispatch(this.dom, 'ln-picklist:move', detail);
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
// ─── Attribute Sync ────────────────────────────────────────
|
|
200
|
-
|
|
201
|
-
function _readMax(el) {
|
|
202
|
-
const raw = el.getAttribute(MAX_ATTR);
|
|
203
|
-
if (raw === null || raw === '') return null;
|
|
204
|
-
const parsed = parseInt(raw, 10);
|
|
205
|
-
return isNaN(parsed) || parsed < 0 ? null : parsed;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function _syncEnabled(el) {
|
|
209
|
-
const instance = el[DOM_ATTRIBUTE];
|
|
210
|
-
if (!instance) return;
|
|
211
|
-
const shouldBeEnabled = el.getAttribute(DOM_SELECTOR) !== 'disabled';
|
|
212
|
-
if (shouldBeEnabled === instance.isEnabled) return;
|
|
213
|
-
instance.isEnabled = shouldBeEnabled;
|
|
214
|
-
dispatch(el, shouldBeEnabled ? 'ln-picklist:enabled' : 'ln-picklist:disabled', { target: el });
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
function _syncMax(el) {
|
|
218
|
-
const instance = el[DOM_ATTRIBUTE];
|
|
219
|
-
if (!instance) return;
|
|
220
|
-
instance.max = _readMax(el);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// ─── Init ──────────────────────────────────────────────────
|
|
224
|
-
|
|
225
|
-
registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-picklist', {
|
|
226
|
-
attributes: ATTRIBUTES
|
|
227
|
-
});
|
|
228
|
-
})();
|
|
1
|
+
import { registerComponent, dispatch, dispatchCancelable } from '../../ln-core';
|
|
2
|
+
|
|
3
|
+
(function () {
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
const DOM_SELECTOR = 'data-ln-picklist';
|
|
7
|
+
const DOM_ATTRIBUTE = 'lnPicklist';
|
|
8
|
+
const LIST_ATTR = 'data-ln-picklist-list';
|
|
9
|
+
const MAX_ATTR = 'data-ln-picklist-max';
|
|
10
|
+
|
|
11
|
+
if (window[DOM_ATTRIBUTE] !== undefined) return;
|
|
12
|
+
|
|
13
|
+
// ─── Attribute Contract (SSOT) ──────────────────────────
|
|
14
|
+
const ATTRIBUTES = {
|
|
15
|
+
'data-ln-picklist': { type: 'enum', values: ['enabled', 'disabled'], fallback: 'enabled', effect: _syncEnabled, description: 'Controls enabled/disabled state of the dual-list picklist' },
|
|
16
|
+
'data-ln-picklist-max': { type: 'integer', fallback: Infinity, min: 1, effect: _syncMax, description: 'Maximum selectable items in the selected list' },
|
|
17
|
+
'data-ln-picklist-list': { type: 'enum', values: ['available', 'selected'], description: 'Role marker for available or selected picklist columns' }
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// ─── Component ─────────────────────────────────────────────
|
|
21
|
+
//
|
|
22
|
+
// The checkbox IS the state. Its `checked` property and the list the item
|
|
23
|
+
// currently sits in are the same fact, and `name`/`value` carry the
|
|
24
|
+
// selection to the server natively — unchecked boxes are not submitted.
|
|
25
|
+
// Hence no hidden inputs, no state attribute and no JS mirror.
|
|
26
|
+
|
|
27
|
+
function _component(dom) {
|
|
28
|
+
this.dom = dom;
|
|
29
|
+
this.isEnabled = dom.getAttribute(DOM_SELECTOR) !== 'disabled';
|
|
30
|
+
this.max = _readMax(dom);
|
|
31
|
+
|
|
32
|
+
this.available = dom.querySelector('[' + LIST_ATTR + '="available"]');
|
|
33
|
+
this.selected = dom.querySelector('[' + LIST_ATTR + '="selected"]');
|
|
34
|
+
|
|
35
|
+
// Report the gap rather than failing on the first click.
|
|
36
|
+
if (!this.available || !this.selected) {
|
|
37
|
+
console.warn('[ln-picklist] requires both [' + LIST_ATTR + '="available"] and [' + LIST_ATTR + '="selected"]', dom);
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Bound once so destroy() can detach the same reference.
|
|
42
|
+
this._onChange = this._onChange.bind(this);
|
|
43
|
+
dom.addEventListener('change', this._onChange);
|
|
44
|
+
|
|
45
|
+
// Snapshot the authored items in document order.
|
|
46
|
+
this._initial = [];
|
|
47
|
+
for (const list of [this.available, this.selected]) {
|
|
48
|
+
for (const item of list.children) {
|
|
49
|
+
this._initial.push(item);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Initial sync: transfer checked items to selected, unchecked to available.
|
|
54
|
+
this.sync();
|
|
55
|
+
|
|
56
|
+
this._form = dom.closest('form');
|
|
57
|
+
if (this._form) {
|
|
58
|
+
this._onFormReset = this._onFormReset.bind(this);
|
|
59
|
+
this._form.addEventListener('reset', this._onFormReset);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ─── Lifecycle ─────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
_component.prototype.destroy = function () {
|
|
68
|
+
if (!this.dom[DOM_ATTRIBUTE]) return;
|
|
69
|
+
this._destroyed = true;
|
|
70
|
+
if (this._onChange) this.dom.removeEventListener('change', this._onChange);
|
|
71
|
+
if (this._form) this._form.removeEventListener('reset', this._onFormReset);
|
|
72
|
+
delete this.dom[DOM_ATTRIBUTE];
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// ─── Instance API ──────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
_component.prototype.enable = function () {
|
|
78
|
+
this.dom.setAttribute(DOM_SELECTOR, '');
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
_component.prototype.disable = function () {
|
|
82
|
+
this.dom.setAttribute(DOM_SELECTOR, 'disabled');
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
_component.prototype.sync = function () {
|
|
86
|
+
if (!this.available || !this.selected) return;
|
|
87
|
+
|
|
88
|
+
// Include any dynamically added items not yet tracked
|
|
89
|
+
const currentItems = Array.from(this.available.children).concat(Array.from(this.selected.children));
|
|
90
|
+
for (let i = 0; i < currentItems.length; i++) {
|
|
91
|
+
if (!this._initial.includes(currentItems[i])) {
|
|
92
|
+
this._initial.push(currentItems[i]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let selectedCount = 0;
|
|
97
|
+
for (let i = 0; i < this._initial.length; i++) {
|
|
98
|
+
const item = this._initial[i];
|
|
99
|
+
if (!item.isConnected) continue;
|
|
100
|
+
const checkbox = item.querySelector('input[type="checkbox"]');
|
|
101
|
+
if (!checkbox) continue;
|
|
102
|
+
|
|
103
|
+
let targetList;
|
|
104
|
+
if (checkbox.checked) {
|
|
105
|
+
if (this.max === null || selectedCount < this.max) {
|
|
106
|
+
targetList = this.selected;
|
|
107
|
+
selectedCount++;
|
|
108
|
+
} else {
|
|
109
|
+
checkbox.checked = false;
|
|
110
|
+
targetList = this.available;
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
targetList = this.available;
|
|
114
|
+
}
|
|
115
|
+
targetList.appendChild(item);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// ─── Form Reset ────────────────────────────────────────────
|
|
120
|
+
//
|
|
121
|
+
// Resetting a form restores every control to its default SILENTLY — the
|
|
122
|
+
// spec fires no `change` and no `input` for them, only `reset` on the form
|
|
123
|
+
// itself. Re-syncing in recorded order rebuilds both lists according to
|
|
124
|
+
// defaultChecked.
|
|
125
|
+
|
|
126
|
+
_component.prototype._onFormReset = function (e) {
|
|
127
|
+
const self = this;
|
|
128
|
+
|
|
129
|
+
// `reset` fires BEFORE the controls are restored, and it is cancelable,
|
|
130
|
+
// so the work is deferred and re-checked — the same shape ln-editor
|
|
131
|
+
// uses to re-read its textarea.
|
|
132
|
+
setTimeout(function () {
|
|
133
|
+
if (self._destroyed || e.defaultPrevented) return;
|
|
134
|
+
self.sync();
|
|
135
|
+
}, 0);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// ─── Change Handler ────────────────────────────────────────
|
|
139
|
+
|
|
140
|
+
_component.prototype._onChange = function (e) {
|
|
141
|
+
// `change` bubbles, so anything the author composes inside the root —
|
|
142
|
+
// an ln-search input, a select — reaches this listener. Filter hard.
|
|
143
|
+
const checkbox = e.target.closest('input[type="checkbox"]');
|
|
144
|
+
if (!checkbox) return;
|
|
145
|
+
|
|
146
|
+
const item = checkbox.closest('li');
|
|
147
|
+
if (!item) return;
|
|
148
|
+
|
|
149
|
+
const from = item.parentElement;
|
|
150
|
+
if (from !== this.available && from !== this.selected) return;
|
|
151
|
+
|
|
152
|
+
// The browser has already toggled the box by the time this runs, so a
|
|
153
|
+
// bare return would leave it checked while the item stays put — which
|
|
154
|
+
// is exactly the contradiction this component exists to avoid.
|
|
155
|
+
if (!this.isEnabled) {
|
|
156
|
+
checkbox.checked = !checkbox.checked;
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const to = checkbox.checked ? this.selected : this.available;
|
|
161
|
+
|
|
162
|
+
// Inconsistent authored markup (a checked item rendered on the left),
|
|
163
|
+
// or a synthetic change that did not flip the box, would otherwise
|
|
164
|
+
// re-append in place and emit a move that never happened.
|
|
165
|
+
if (from === to) return;
|
|
166
|
+
|
|
167
|
+
// Enforce maximum selection limit if configured
|
|
168
|
+
if (to === this.selected && this.max !== null && this.selected.children.length >= this.max) {
|
|
169
|
+
checkbox.checked = !checkbox.checked;
|
|
170
|
+
dispatch(this.dom, 'ln-picklist:max-reached', {
|
|
171
|
+
max: this.max,
|
|
172
|
+
item: item,
|
|
173
|
+
checkbox: checkbox,
|
|
174
|
+
count: this.selected.children.length
|
|
175
|
+
});
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// One record, both events — they describe the same move.
|
|
180
|
+
const detail = { item: item, from: from, to: to, checkbox: checkbox };
|
|
181
|
+
|
|
182
|
+
if (dispatchCancelable(this.dom, 'ln-picklist:before-move', detail).defaultPrevented) {
|
|
183
|
+
checkbox.checked = !checkbox.checked;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Re-parenting a node that holds focus blurs it to <body> in Chromium.
|
|
188
|
+
// Only restore when the focus really was here: a synthetic change from
|
|
189
|
+
// a script must not steal focus away from whatever the user is using.
|
|
190
|
+
const hadFocus = document.activeElement === checkbox;
|
|
191
|
+
|
|
192
|
+
to.appendChild(item);
|
|
193
|
+
|
|
194
|
+
if (hadFocus) checkbox.focus();
|
|
195
|
+
|
|
196
|
+
dispatch(this.dom, 'ln-picklist:move', detail);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// ─── Attribute Sync ────────────────────────────────────────
|
|
200
|
+
|
|
201
|
+
function _readMax(el) {
|
|
202
|
+
const raw = el.getAttribute(MAX_ATTR);
|
|
203
|
+
if (raw === null || raw === '') return null;
|
|
204
|
+
const parsed = parseInt(raw, 10);
|
|
205
|
+
return isNaN(parsed) || parsed < 0 ? null : parsed;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function _syncEnabled(el) {
|
|
209
|
+
const instance = el[DOM_ATTRIBUTE];
|
|
210
|
+
if (!instance) return;
|
|
211
|
+
const shouldBeEnabled = el.getAttribute(DOM_SELECTOR) !== 'disabled';
|
|
212
|
+
if (shouldBeEnabled === instance.isEnabled) return;
|
|
213
|
+
instance.isEnabled = shouldBeEnabled;
|
|
214
|
+
dispatch(el, shouldBeEnabled ? 'ln-picklist:enabled' : 'ln-picklist:disabled', { target: el });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function _syncMax(el) {
|
|
218
|
+
const instance = el[DOM_ATTRIBUTE];
|
|
219
|
+
if (!instance) return;
|
|
220
|
+
instance.max = _readMax(el);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ─── Init ──────────────────────────────────────────────────
|
|
224
|
+
|
|
225
|
+
registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-picklist', {
|
|
226
|
+
attributes: ATTRIBUTES
|
|
227
|
+
});
|
|
228
|
+
})();
|
|
@@ -149,6 +149,10 @@ Set `isOpen = true`, store `trigger` (`null` if opened via direct attribute muta
|
|
|
149
149
|
|
|
150
150
|
Clears `isOpen`, removes the outside-click/scroll/resize listeners, clears inline `top`/`left` and the placement attribute, sets `aria-expanded="false"`, exits the top layer via `hidePopover()`, splices itself from `openStack` (removing the ESC listener if the stack is now empty), then restores focus to the trigger **only if** the trigger was the previously-focused element (click→Escape, click→programmatic close) or `activeElement === document.body` (Escape from inside the popover, outside-click on inert whitespace) — an outside-click landing on another focusable element keeps that element's focus. Dispatches `ln-popover:close`.
|
|
151
151
|
|
|
152
|
+
### Native Popover API Light Dismiss Synchronization
|
|
153
|
+
|
|
154
|
+
The component attaches a native `toggle` event listener to the popover element. When the browser closes the popover via native light dismiss (`e.newState === 'closed'`), `ln-popover` detects this change and immediately runs `_applyClose()` and updates `data-ln-popover="closed"`. This prevents state desynchronization without firing an impossible cancelable `before-close` event (the browser has already completed the closing operation).
|
|
155
|
+
|
|
152
156
|
### Focus management
|
|
153
157
|
|
|
154
158
|
A disclosure pattern, not a modal — no Tab trap. Because the popover is promoted to the top layer purely for rendering, it remains in its authored DOM position, so Tab order follows the markup rather than jumping to the end of `<body>`. `tabindex="-1"` and `role="dialog"` are set automatically at construction so the container itself is a valid focus target when there's no focusable child.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
@use '../../theme/config/mixins' as *;
|
|
2
|
-
|
|
3
|
-
[data-ln-debug] {
|
|
4
|
-
// 1. Popover Missing ID: popovers controlled by data-ln-popover must have an id for trigger linking
|
|
5
|
-
[data-ln-popover]:not([id]) {
|
|
6
|
-
@include dev-dom-error("[data-ln-popover] is missing a required 'id' attribute for trigger linking.");
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
// 2. Popover Trigger Empty ID: trigger elements must point to a target popover ID
|
|
10
|
-
[data-ln-popover-for=""] {
|
|
11
|
-
@include dev-inline-error("data-ln-popover-for target ID cannot be empty");
|
|
12
|
-
}
|
|
13
|
-
}
|
|
1
|
+
@use '../../theme/config/mixins' as *;
|
|
2
|
+
|
|
3
|
+
[data-ln-debug] {
|
|
4
|
+
// 1. Popover Missing ID: popovers controlled by data-ln-popover must have an id for trigger linking
|
|
5
|
+
[data-ln-popover]:not([id]) {
|
|
6
|
+
@include dev-dom-error("[data-ln-popover] is missing a required 'id' attribute for trigger linking.");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// 2. Popover Trigger Empty ID: trigger elements must point to a target popover ID
|
|
10
|
+
[data-ln-popover-for=""] {
|
|
11
|
+
@include dev-inline-error("data-ln-popover-for target ID cannot be empty");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(){"use strict";function D(){return typeof window>"u"?!1:window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink?!0:typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null:!1}function k(e){if(typeof window>"u")return!1;if(window.lnDebug===!0)return!0;if(window.lnCore&&window.lnCore._debugIsContained)return e?window.lnCore._debugIsContained(e):window.lnCore._debugSink!==null;if(e&&e.closest){const t=e.closest("[data-ln-debug]");return!(!t||typeof document<"u"&&t===document.documentElement)}return typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug"):!1}if(typeof window<"u"&&(window.lnCore=window.lnCore||{},!window.lnCore._warnBound)){window.lnCore._warnBound=!0;const e=console.warn;console.warn=function(...t){if(typeof t[0]=="string"&&(t[0].startsWith("[ln-")||t[0].startsWith("[lnCore"))){let o=null;for(let s=1;s<t.length;s++)if(t[s]&&t[s].nodeType===1){o=t[s];break}if(!k(o))return}e.apply(console,t)}}function O(e,t,n){const o=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,o),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:o}))}function R(e,t,n){const o=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,o);const s=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:o});return e.dispatchEvent(s),s}function A(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){A(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}function U(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)}const I={};function Q(e,t){I[e]=t}function G(e){return I[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=Q,window.lnCore.getDataMapper=G);function z(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,A(function(){new MutationObserver(function(){O(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const $={};function J(e,t){if(!e||typeof t!="object")return;const n=e.toLowerCase().split("-")[0];$[n]=t}function X(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return $[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=J,window.lnCore.getLocaleFallback=X,window.lnCore.ensureLocaleObserver=z);const E={};function Y(e,t){E[e]||(E[e]=document.querySelector('[data-ln-template="'+e+'"]'));const n=E[e];return n?n.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function F(e,t){if(!e||!t)return e;const n=e.querySelectorAll("[data-ln-field]");for(let r=0;r<n.length;r++){const u=n[r],l=u.getAttribute("data-ln-field");t[l]!=null&&(u.textContent=t[l])}const o=e.querySelectorAll("[data-ln-attr]");for(let r=0;r<o.length;r++){const u=o[r],l=u.getAttribute("data-ln-attr").split(",");for(let d=0;d<l.length;d++){const p=l[d].trim().split(":");if(p.length!==2)continue;const f=p[0].trim(),c=p[1].trim();t[c]!=null&&u.setAttribute(f,t[c])}}const s=e.querySelectorAll("[data-ln-show]");for(let r=0;r<s.length;r++){const u=s[r],l=u.getAttribute("data-ln-show");l in t&&u.classList.toggle("hidden",!t[l])}const i=e.querySelectorAll("[data-ln-class]");for(let r=0;r<i.length;r++){const u=i[r],l=u.getAttribute("data-ln-class").split(",");for(let d=0;d<l.length;d++){const p=l[d].trim().split(":");if(p.length!==2)continue;const f=p[0].trim(),c=p[1].trim();c in t&&u.classList.toggle(f,!!t[c])}}return e}function Z(e,t){e.matches&&e.matches("[data-ln-form], [data-ln-fillable]")&&(window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",e,t??null),e.dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0})));const n=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let o=0;o<n.length;o++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",n[o],t??null),n[o].dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0}));return e}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(e){if(!(!e.target.matches||!e.target.matches("[data-ln-fillable]")))if(e.detail)F(e.target,e.detail);else{const t=e.target.querySelectorAll("[data-ln-field]");for(let n=0;n<t.length;n++)t[n].textContent=""}})));function B(e,t){if(!e||!t)return e;const n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;n.nextNode();){const i=n.currentNode;i.textContent.indexOf("{{")!==-1&&(i.textContent=i.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(r,u){return t[u]!==void 0?t[u]:""}))}const o=function(i,r){return t[r]!==void 0?t[r]:""},s=Array.from(e.querySelectorAll("*"));e.nodeType===1&&s.push(e);for(let i=0;i<s.length;i++){const r=s[i],u=r.attributes;for(let l=0;l<u.length;l++){const d=u[l];d.value.indexOf("{{")!==-1&&r.setAttribute(d.name,d.value.replace(/\{\{\s*(\w+)\s*\}\}/g,o))}}return e}function ee(e,t,n,o,s,i){const r={};for(let l=0;l<e.children.length;l++){const d=e.children[l],p=d.getAttribute("data-ln-render-key");p&&(r[p]=d)}const u=document.createDocumentFragment();for(let l=0;l<t.length;l++){const d=t[l],p=String(o(d));let f=r[p];if(f)s(f,d,l);else{const c=Y(n,i);if(!c||(B(c,d),f=c.firstElementChild,!f))continue;f.setAttribute("data-ln-render-key",p),s(f,d,l)}u.appendChild(f)}e.textContent="",e.appendChild(u)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=B,window.lnCore.fill=F,window.lnCore.lnFill=Z,window.lnCore.renderList=ee);function M(e,t,n,o,s){if(!e||t===null)return!0;const i=o||"ln-component",r=e.type;if(r==="trigger"||r==="marker"||r==="string"||r==="list"||!r||t===""&&e.fallback!==void 0)return!0;const u=l=>{s?console.warn(l,s):console.warn(l)};if(r==="boolean"){const l=t.trim().toLowerCase();return l!==""&&l!=="true"&&l!=="false"&&l!=="1"&&l!=="0"?(u(`[${i}] Invalid value "${t}" for boolean attribute "${n}". Allowed: "true", "false", or presence-only.`),!1):!0}if(r==="enum"){const l=e.values||[];return l.includes(t)?!0:(u(`[${i}] Invalid value "${t}" for attribute "${n}". Allowed: ${l.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(r==="integer"){if(!/^-?\d+$/.test(t))return u(`[${i}] Invalid integer "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1;const l=parseInt(t,10);return e.min!==void 0&&l<e.min?(u(`[${i}] Value ${l} for attribute "${n}" is less than min (${e.min}).`),!1):e.max!==void 0&&l>e.max?(u(`[${i}] Value ${l} for attribute "${n}" is greater than max (${e.max}).`),!1):!0}if(r==="float")return isNaN(Number(t))?(u(`[${i}] Invalid float "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1):!0;if(r==="json")try{return JSON.parse(t),!0}catch(l){return u(`[${i}] Invalid JSON for attribute "${n}": ${l.message}. Fallback: ${e.fallback}.`),!1}return!0}function te(e){const t={};for(const n in e){const o=e[n];o&&o.effect&&(t[n]=o.effect)}return Object.keys(t).length?t:null}function ne(e){if(e.onAttrChange&&!e.declared)return null;const t=new Set;if(e.effects)for(const n in e.effects)t.add(n);if(e.onAttrChange&&e.declared)for(const n of e.declared)t.add(n);return t}function S(e,t,n,o){if(e.nodeType!==1)return;const i=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",r=Array.from(e.querySelectorAll(i));e.matches&&e.matches(i)&&r.push(e);for(const u of r)if(!u[n]){window.lnCore._persistSink&&u.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(u,t);try{u[n]=new o(u)}catch(l){console.error("["+n+"] init failed",u,l)}}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function oe(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function ie(e){typeof window<"u"?(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[],window.lnCore._bootHolds>0?window.lnCore._bootQueue.push(e):setTimeout(e,0)):e()}function W(){window.lnCore=window.lnCore||{};const e=window.lnCore._attrRegistry=window.lnCore._attrRegistry||{byAttr:new Map,reactive:[],persist:[]};return e.byReactive=e.byReactive||new Map,e.reactiveWildcard=e.reactiveWildcard||[],e}function re(e){const t=W(),n=e.observed||[];for(let o=0;o<n.length;o++){const s=n[o];t.byAttr.has(s)||t.byAttr.set(s,[]),t.byAttr.get(s).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const o in e.attributes){t.byDeclaredAttr.has(o)||t.byDeclaredAttr.set(o,[]);const s=t.byDeclaredAttr.get(o);s.some(i=>i.componentTag===e.componentTag)||s.push({spec:e.attributes[o],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const o=ne(e);if(o===null)t.reactiveWildcard.push(e);else for(const s of o)t.byReactive.has(s)||t.byReactive.set(s,[]),t.byReactive.get(s).push(e)}e.persist&&t.persist.push(e)}function j(e,t,n,o){for(let s=0;s<e.length;s++){const i=e[s];if(!t[i.attribute])continue;const r=i.effects&&i.effects[n];r?r(t,n,o):i.onAttrChange&&(!i.declared||i.declared.has(n))&&i.onAttrChange(t,n,o)}}function se(e){const t=e.target,n=e.attributeName;if(e.oldValue===t.getAttribute(n))return;const o=W(),s=o.byAttr.get(n);if(D()&&o.byDeclaredAttr&&o.byDeclaredAttr.has(n)&&k(t)){const i=o.byDeclaredAttr.get(n),r=t.getAttribute(n);for(let u=0;u<i.length;u++)M(i[u].spec,r,n,i[u].componentTag,t)}if(window.lnCore._debugSink&&(n.indexOf("data-ln-")===0||s)&&window.lnCore._debugSink("attr",n,t,{oldValue:e.oldValue,newValue:t.getAttribute(n)}),n.indexOf("data-ln-")===0){const i=o.byReactive.get(n);i&&j(i,t,n,e.oldValue),o.reactiveWildcard.length&&j(o.reactiveWildcard,t,n,e.oldValue)}if(s)for(let i=0;i<s.length;i++){const r=s[i];if(r.handler){r.handler(t,n,e.oldValue);continue}r.onAttributeChange&&t[r.attribute]?r.onAttributeChange(t,n):(S(t,r.selector,r.attribute,r.ComponentFn),r.onInit&&r.onInit(t))}}function le(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,A(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++)try{se(t[n])}catch(o){console.error("[ln-core] mutation handler failed",t[n].target,o)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function H(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function ue(e){const t=H();if(t.length){if(e.target)for(let n=0;n<t.length;n++){const o=t[n];if(o.onSubtreeChange){const s=o.query,i=e.target.nodeType===1?e.target.matches(s)?e.target:e.target.closest(s):e.target.parentElement?e.target.parentElement.closest(s):null;i&&o.onSubtreeChange(i,e)}}for(let n=0;n<e.addedNodes.length;n++){const o=e.addedNodes[n];if(o.nodeType===1)for(let s=0;s<t.length;s++){const i=t[s];S(o,i.selector,i.attribute,i.ComponentFn),i.onInit&&i.onInit(o)}}for(let n=0;n<e.removedNodes.length;n++){const o=e.removedNodes[n];if(o.nodeType===1)for(let s=0;s<t.length;s++){const i=t[s],r=i.query,u=Array.from(o.querySelectorAll(r));o.matches&&o.matches(r)&&u.push(o);for(let l=0;l<u.length;l++){const d=u[l];if(!document.contains(d)){const p=d[i.attribute];if(p&&typeof p.destroy=="function")try{p.destroy()}catch(f){console.error("["+i.attribute+"] destroy failed",d,f)}delete d[i.attribute]}}}}}}function ce(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,A(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++){const o=t[n];if(o.type==="childList")try{ue(o)}catch(s){console.error("[ln-core] lifecycle handler failed",o.target,s)}}}).observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function N(e,t,n,o,s={}){const i=s.extraAttributes||[],r=s.onAttributeChange||null,u=s.onSubtreeChange||null,l=s.onInit||null,d=s.onAttrChange||null,p=s.effects||null,f=s.attributes||null,c=f?te(f):p,g=f?new Set(Object.keys(f)):null,w=s.persist||null;function b(m){const C=m||document.body;if(S(C,e,t,n),f&&D())for(const _ in f){const me=f[_],L=Array.from(C.querySelectorAll("["+_+"]"));C.matches&&C.matches("["+_+"]")&&L.push(C);for(let T=0;T<L.length;T++){const q=L[T];k(q)&&M(me,q.getAttribute(_),_,o,q)}}l&&l(C)}const a=[];if(e.indexOf("[")!==-1){const m=/\[([\w-]+)/g;let C;for(;(C=m.exec(e))!==null;)a.push(C[1])}else a.push(e);re({selector:e,attribute:t,componentTag:o,attributes:f,ComponentFn:n,onInit:l,observed:a.concat(i),onAttributeChange:r,onAttrChange:d,effects:c,declared:g,persist:w}),le();const v=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]";H().push({selector:e,attribute:t,ComponentFn:n,onInit:l,onSubtreeChange:u,query:v}),ce(),window[t]=b;function h(){oe()>0?ie(function(){b(document.body)}):b(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",h):h(),b}function P(e){return(e||"").replace(/^#/,"")}function x(e){const t=e===void 0?location.hash:e,n={},o=P(t);if(!o)return n;const s=o.split("&");for(let i=0;i<s.length;i++){const r=s[i];if(!r)continue;const u=r.indexOf(":"),l=u>-1?r.slice(0,u):r,d=u>-1?r.slice(u+1):"";if(l)try{n[l]=decodeURIComponent(d)}catch{n[l]=d}}return n}function de(e){if(!e)return null;const t=x();return e in t?t[e]:null}function fe(e,t){if(!e)return;const n=x();t==null?delete n[e]:n[e]=String(t);const s=Object.keys(n).map(function(i){const r=n[i];return r===""?i:i+":"+encodeURIComponent(r)}).join("&");P(location.hash)!==s&&(location.hash=s)}function ae(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function pe(e,t){if(!e||!e.hasAttribute("data-ln-hash"))return null;const n=e.getAttribute("data-ln-hash");if(n&&n.trim()!=="")return n.trim();const o=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return o?t?o+"-"+t:o:t||null}function he(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function ge(e){return!e||typeof e!="string"?null:e.endsWith(".asc")?{fieldOrColumn:e.slice(0,-4),direction:"asc"}:e.endsWith(".desc")?{fieldOrColumn:e.slice(0,-5),direction:"desc"}:null}function be(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function we(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const n=e.slice(0,t),o=e.slice(t+1),s=o?o.split(",").map(function(i){try{return decodeURIComponent(i)}catch{return i}}).filter(Boolean):[];return{key:n,values:s}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=x,window.lnCore.hashGet=de,window.lnCore.hashSet=fe,window.lnCore.hashLinkClick=ae,window.lnCore.resolveHashNamespace=pe,window.lnCore.hashSortEncode=he,window.lnCore.hashSortDecode=ge,window.lnCore.hashFilterEncode=be,window.lnCore.hashFilterDecode=we);function V(e,t,n,o){const s=o,i=window.innerWidth,r=window.innerHeight,u=t.width,l=t.height,d=(n||"bottom").split("-"),p=d[0],f=d[1]==="start"||d[1]==="end"?d[1]:"center",c={top:["top","bottom","right","left"],bottom:["bottom","top","right","left"],left:["left","right","top","bottom"],right:["right","left","top","bottom"]},g=c[p]||c.bottom;function w(h){return h==="top"||h==="bottom"?f==="start"?e.left:f==="end"?e.right-u:e.left+(e.width-u)/2:f==="start"?e.top:f==="end"?e.bottom-l:e.top+(e.height-l)/2}function b(h){let m,C,_=!0;return h==="top"?(m=e.top-s-l,C=w(h),m<0&&(_=!1)):h==="bottom"?(m=e.bottom+s,C=w(h),m+l>r&&(_=!1)):h==="left"?(m=w(h),C=e.left-s-u,C<0&&(_=!1)):(m=w(h),C=e.right+s,C+u>i&&(_=!1)),{top:m,left:C,side:h,fits:_}}let a=null;for(let h=0;h<g.length;h++){const m=b(g[h]);if(m.fits){a=m;break}}a||(a=b(g[0]));let y=a.top,v=a.left;return u>=i?v=0:(v<0&&(v=0),v+u>i&&(v=i-u)),l>=r?y=0:(y<0&&(y=0),y+l>r&&(y=r-l)),{top:y,left:v,placement:a.side}}function K(e){if(!e)return{width:0,height:0};const t=e.style,n=t.visibility,o=t.display,s=t.position;t.visibility="hidden",t.display="block",t.position="fixed";const i=e.offsetWidth,r=e.offsetHeight;return t.visibility=n,t.display=o,t.position=s,{width:i,height:r}}(function(){const e="data-ln-popover",t="lnPopover",n="data-ln-popover-for",o="data-ln-popover-position";if(window[t]!==void 0)return;const s={"data-ln-popover":{type:"enum",values:["open","close"],fallback:"close",effect:f,description:"Control state of the popover"},"data-ln-popover-for":{type:"string",description:"Target element ID that this trigger controls"},"data-ln-popover-position":{type:"enum",values:["top","top-start","top-end","bottom","bottom-start","bottom-end","left","left-start","left-end","right","right-start","right-end"],fallback:"bottom",description:"Preferred positioning anchor"},"data-ln-popover-placement":{type:"enum",values:["top","top-start","top-end","bottom","bottom-start","bottom-end","left","left-start","left-end","right","right-start","right-end"],description:"Active calculated placement applied at runtime"}},i=[];let r=null;function u(){r||(r=function(c){if(c.key!=="Escape"||i.length===0)return;i[i.length-1].close()},document.addEventListener("keydown",r))}function l(){i.length>0||r&&(document.removeEventListener("keydown",r),r=null)}function d(c){this.dom=c,this.isOpen=c.getAttribute(e)==="open",this.trigger=null,this._previousFocus=null,this._boundDocClick=null,this._docClickTimeout=null,this._boundReposition=null;const g=this;return this._onRequestOpen=function(w){const b=w.detail&&w.detail.trigger?w.detail.trigger:null;g.open(b)},this._onRequestClose=function(){g.close()},this._onRequestToggle=function(w){const b=w.detail&&w.detail.trigger?w.detail.trigger:null;g.toggle(b)},c.addEventListener("ln-popover:request-open",this._onRequestOpen),c.addEventListener("ln-popover:request-close",this._onRequestClose),c.addEventListener("ln-popover:request-toggle",this._onRequestToggle),c.hasAttribute("tabindex")||c.setAttribute("tabindex","-1"),c.hasAttribute("role")||c.setAttribute("role","dialog"),c.hasAttribute("popover")||c.setAttribute("popover","manual"),this.isOpen&&this._applyOpen(null),this}d.prototype.open=function(c){this.isOpen||(this.trigger=c||null,this.dom.setAttribute(e,"open"))},d.prototype.close=function(){this.isOpen&&this.dom.setAttribute(e,"closed")},d.prototype.toggle=function(c){this.isOpen?this.close():this.open(c)},d.prototype._applyOpen=function(c){this.isOpen=!0,c&&(this.trigger=c),this._previousFocus=document.activeElement,typeof this.dom.showPopover=="function"&&this.dom.showPopover();const g=K(this.dom);if(this.trigger){const y=this.trigger.getBoundingClientRect(),v=this.dom.getAttribute(o)||"bottom",h=V(y,g,v,8);this.dom.style.top=h.top+"px",this.dom.style.left=h.left+"px",this.dom.setAttribute("data-ln-popover-placement",h.placement),this.trigger.setAttribute("aria-expanded","true")}const w=this.dom.querySelectorAll('a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'),b=Array.prototype.find.call(w,U);b?b.focus():this.dom.focus();const a=this;this._boundDocClick=function(y){a.dom.contains(y.target)||a.trigger&&a.trigger.contains(y.target)||a.close()},a._docClickTimeout=setTimeout(function(){a._docClickTimeout=null,document.addEventListener("click",a._boundDocClick)},0),this._boundReposition=function(){if(!a.trigger)return;const y=a.trigger.getBoundingClientRect(),v=K(a.dom),h=a.dom.getAttribute(o)||"bottom",m=V(y,v,h,8);a.dom.style.top=m.top+"px",a.dom.style.left=m.left+"px",a.dom.setAttribute("data-ln-popover-placement",m.placement)},window.addEventListener("scroll",this._boundReposition,{passive:!0,capture:!0}),window.addEventListener("resize",this._boundReposition),i.push(this),u(),O(this.dom,"ln-popover:open",{popoverId:this.dom.id,target:this.dom,trigger:this.trigger})},d.prototype._applyClose=function(){this.isOpen=!1,this._docClickTimeout&&(clearTimeout(this._docClickTimeout),this._docClickTimeout=null),this._boundDocClick&&(document.removeEventListener("click",this._boundDocClick),this._boundDocClick=null),this._boundReposition&&(window.removeEventListener("scroll",this._boundReposition,{capture:!0}),window.removeEventListener("resize",this._boundReposition),this._boundReposition=null),this.dom.style.top="",this.dom.style.left="",this.dom.removeAttribute("data-ln-popover-placement"),this.trigger&&this.trigger.setAttribute("aria-expanded","false"),typeof this.dom.hidePopover=="function"&&this.dom.matches(":popover-open")&&this.dom.hidePopover();const c=i.indexOf(this);c!==-1&&i.splice(c,1),l(),this._previousFocus&&this.trigger&&this._previousFocus===this.trigger?this.trigger.focus():this.trigger&&document.activeElement===document.body&&this.trigger.focus(),this._previousFocus=null,O(this.dom,"ln-popover:close",{popoverId:this.dom.id,target:this.dom,trigger:this.trigger}),this.trigger=null},d.prototype.destroy=function(){this.dom[t]&&(this.dom.removeEventListener("ln-popover:request-open",this._onRequestOpen),this.dom.removeEventListener("ln-popover:request-close",this._onRequestClose),this.dom.removeEventListener("ln-popover:request-toggle",this._onRequestToggle),this.isOpen&&this._applyClose(),delete this.dom[t])};function p(c){this.dom=c;const g=c.getAttribute(n);return c.setAttribute("aria-haspopup","dialog"),c.setAttribute("aria-expanded","false"),c.setAttribute("aria-controls",g),this._onClick=function(w){if(w.ctrlKey||w.metaKey||w.button===1)return;w.preventDefault();const b=document.getElementById(g);if(!b)return;b[t]&&(b[t].trigger=c);const a=b.getAttribute(e);b.setAttribute(e,a==="open"?"closed":"open")},c.addEventListener("click",this._onClick),this}p.prototype.destroy=function(){this.dom.removeEventListener("click",this._onClick),delete this.dom[t+"Trigger"]};function f(c){const g=c[t];if(!g)return;const b=c.getAttribute(e)==="open";if(b!==g.isOpen)if(b){if(R(c,"ln-popover:before-open",{popoverId:c.id,target:c,trigger:g.trigger}).defaultPrevented){c.setAttribute(e,"closed");return}g._applyOpen(g.trigger)}else{if(R(c,"ln-popover:before-close",{popoverId:c.id,target:c,trigger:g.trigger}).defaultPrevented){c.setAttribute(e,"open");return}g._applyClose()}}N(e,t,d,"ln-popover",{attributes:s}),N(n,t+"Trigger",p,"ln-popover-trigger")})()})();
|
|
1
|
+
(function(){"use strict";function q(){return typeof window>"u"?!1:window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink?!0:typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null:!1}function x(e){if(typeof window>"u")return!1;if(window.lnDebug===!0)return!0;if(window.lnCore&&window.lnCore._debugIsContained)return e?window.lnCore._debugIsContained(e):window.lnCore._debugSink!==null;if(e&&e.closest){const t=e.closest("[data-ln-debug]");return!(!t||typeof document<"u"&&t===document.documentElement)}return typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug"):!1}if(typeof window<"u"&&(window.lnCore=window.lnCore||{},!window.lnCore._warnBound)){window.lnCore._warnBound=!0;const e=console.warn;console.warn=function(...t){if(typeof t[0]=="string"&&(t[0].startsWith("[ln-")||t[0].startsWith("[lnCore"))){let o=null;for(let s=1;s<t.length;s++)if(t[s]&&t[s].nodeType===1){o=t[s];break}if(!x(o))return}e.apply(console,t)}}function k(e,t,n){const o=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,o),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:o}))}function I(e,t,n){const o=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,o);const s=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:o});return e.dispatchEvent(s),s}function A(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){A(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}function K(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)}const R={};function Q(e,t){R[e]=t}function G(e){return R[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=Q,window.lnCore.getDataMapper=G);function z(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,A(function(){new MutationObserver(function(){k(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const $={};function J(e,t){if(!e||typeof t!="object")return;const n=e.toLowerCase().split("-")[0];$[n]=t}function X(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return $[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=J,window.lnCore.getLocaleFallback=X,window.lnCore.ensureLocaleObserver=z);const O={};function Y(e,t){O[e]||(O[e]=document.querySelector('[data-ln-template="'+e+'"]'));const n=O[e];return n?n.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function F(e,t){if(!e||!t)return e;const n=e.querySelectorAll("[data-ln-field]");for(let r=0;r<n.length;r++){const u=n[r],l=u.getAttribute("data-ln-field");t[l]!=null&&(u.textContent=t[l])}const o=e.querySelectorAll("[data-ln-attr]");for(let r=0;r<o.length;r++){const u=o[r],l=u.getAttribute("data-ln-attr").split(",");for(let d=0;d<l.length;d++){const h=l[d].trim().split(":");if(h.length!==2)continue;const f=h[0].trim(),c=h[1].trim();t[c]!=null&&u.setAttribute(f,t[c])}}const s=e.querySelectorAll("[data-ln-show]");for(let r=0;r<s.length;r++){const u=s[r],l=u.getAttribute("data-ln-show");l in t&&u.classList.toggle("hidden",!t[l])}const i=e.querySelectorAll("[data-ln-class]");for(let r=0;r<i.length;r++){const u=i[r],l=u.getAttribute("data-ln-class").split(",");for(let d=0;d<l.length;d++){const h=l[d].trim().split(":");if(h.length!==2)continue;const f=h[0].trim(),c=h[1].trim();c in t&&u.classList.toggle(f,!!t[c])}}return e}function Z(e,t){e.matches&&e.matches("[data-ln-form], [data-ln-fillable]")&&(window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",e,t??null),e.dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0})));const n=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let o=0;o<n.length;o++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",n[o],t??null),n[o].dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0}));return e}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(e){if(!(!e.target.matches||!e.target.matches("[data-ln-fillable]")))if(e.detail)F(e.target,e.detail);else{const t=e.target.querySelectorAll("[data-ln-field]");for(let n=0;n<t.length;n++)t[n].textContent=""}})));function B(e,t){if(!e||!t)return e;const n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;n.nextNode();){const i=n.currentNode;i.textContent.indexOf("{{")!==-1&&(i.textContent=i.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(r,u){return t[u]!==void 0?t[u]:""}))}const o=function(i,r){return t[r]!==void 0?t[r]:""},s=Array.from(e.querySelectorAll("*"));e.nodeType===1&&s.push(e);for(let i=0;i<s.length;i++){const r=s[i],u=r.attributes;for(let l=0;l<u.length;l++){const d=u[l];d.value.indexOf("{{")!==-1&&r.setAttribute(d.name,d.value.replace(/\{\{\s*(\w+)\s*\}\}/g,o))}}return e}function ee(e,t,n,o,s,i){const r={};for(let l=0;l<e.children.length;l++){const d=e.children[l],h=d.getAttribute("data-ln-render-key");h&&(r[h]=d)}const u=document.createDocumentFragment();for(let l=0;l<t.length;l++){const d=t[l],h=String(o(d));let f=r[h];if(f)s(f,d,l);else{const c=Y(n,i);if(!c||(B(c,d),f=c.firstElementChild,!f))continue;f.setAttribute("data-ln-render-key",h),s(f,d,l)}u.appendChild(f)}e.textContent="",e.appendChild(u)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=B,window.lnCore.fill=F,window.lnCore.lnFill=Z,window.lnCore.renderList=ee);function M(e,t,n,o,s){if(!e||t===null)return!0;const i=o||"ln-component",r=e.type;if(r==="trigger"||r==="marker"||r==="string"||r==="list"||!r||t===""&&e.fallback!==void 0)return!0;const u=l=>{s?console.warn(l,s):console.warn(l)};if(r==="boolean"){const l=t.trim().toLowerCase();return l!==""&&l!=="true"&&l!=="false"&&l!=="1"&&l!=="0"?(u(`[${i}] Invalid value "${t}" for boolean attribute "${n}". Allowed: "true", "false", or presence-only.`),!1):!0}if(r==="enum"){const l=e.values||[];return l.includes(t)?!0:(u(`[${i}] Invalid value "${t}" for attribute "${n}". Allowed: ${l.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(r==="integer"){if(!/^-?\d+$/.test(t))return u(`[${i}] Invalid integer "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1;const l=parseInt(t,10);return e.min!==void 0&&l<e.min?(u(`[${i}] Value ${l} for attribute "${n}" is less than min (${e.min}).`),!1):e.max!==void 0&&l>e.max?(u(`[${i}] Value ${l} for attribute "${n}" is greater than max (${e.max}).`),!1):!0}if(r==="float")return isNaN(Number(t))?(u(`[${i}] Invalid float "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1):!0;if(r==="json")try{return JSON.parse(t),!0}catch(l){return u(`[${i}] Invalid JSON for attribute "${n}": ${l.message}. Fallback: ${e.fallback}.`),!1}return!0}function te(e){const t={};for(const n in e){const o=e[n];o&&o.effect&&(t[n]=o.effect)}return Object.keys(t).length?t:null}function ne(e){if(e.onAttrChange&&!e.declared)return null;const t=new Set;if(e.effects)for(const n in e.effects)t.add(n);if(e.onAttrChange&&e.declared)for(const n of e.declared)t.add(n);return t}function E(e,t,n,o){if(e.nodeType!==1)return;const i=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",r=Array.from(e.querySelectorAll(i));e.matches&&e.matches(i)&&r.push(e);for(const u of r)if(!u[n]){window.lnCore._persistSink&&u.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(u,t);try{u[n]=new o(u)}catch(l){console.error("["+n+"] init failed",u,l)}}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function oe(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function ie(e){typeof window<"u"?(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[],window.lnCore._bootHolds>0?window.lnCore._bootQueue.push(e):setTimeout(e,0)):e()}function W(){window.lnCore=window.lnCore||{};const e=window.lnCore._attrRegistry=window.lnCore._attrRegistry||{byAttr:new Map,reactive:[],persist:[]};return e.byReactive=e.byReactive||new Map,e.reactiveWildcard=e.reactiveWildcard||[],e}function re(e){const t=W(),n=e.observed||[];for(let o=0;o<n.length;o++){const s=n[o];t.byAttr.has(s)||t.byAttr.set(s,[]),t.byAttr.get(s).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const o in e.attributes){t.byDeclaredAttr.has(o)||t.byDeclaredAttr.set(o,[]);const s=t.byDeclaredAttr.get(o);s.some(i=>i.componentTag===e.componentTag)||s.push({spec:e.attributes[o],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const o=ne(e);if(o===null)t.reactiveWildcard.push(e);else for(const s of o)t.byReactive.has(s)||t.byReactive.set(s,[]),t.byReactive.get(s).push(e)}e.persist&&t.persist.push(e)}function N(e,t,n,o){for(let s=0;s<e.length;s++){const i=e[s];if(!t[i.attribute])continue;const r=i.effects&&i.effects[n];r?r(t,n,o):i.onAttrChange&&(!i.declared||i.declared.has(n))&&i.onAttrChange(t,n,o)}}function se(e){const t=e.target,n=e.attributeName;if(e.oldValue===t.getAttribute(n))return;const o=W(),s=o.byAttr.get(n);if(q()&&o.byDeclaredAttr&&o.byDeclaredAttr.has(n)&&x(t)){const i=o.byDeclaredAttr.get(n),r=t.getAttribute(n);for(let u=0;u<i.length;u++)M(i[u].spec,r,n,i[u].componentTag,t)}if(window.lnCore._debugSink&&(n.indexOf("data-ln-")===0||s)&&window.lnCore._debugSink("attr",n,t,{oldValue:e.oldValue,newValue:t.getAttribute(n)}),n.indexOf("data-ln-")===0){const i=o.byReactive.get(n);i&&N(i,t,n,e.oldValue),o.reactiveWildcard.length&&N(o.reactiveWildcard,t,n,e.oldValue)}if(s)for(let i=0;i<s.length;i++){const r=s[i];if(r.handler){r.handler(t,n,e.oldValue);continue}r.onAttributeChange&&t[r.attribute]?r.onAttributeChange(t,n):(E(t,r.selector,r.attribute,r.ComponentFn),r.onInit&&r.onInit(t))}}function le(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,A(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++)try{se(t[n])}catch(o){console.error("[ln-core] mutation handler failed",t[n].target,o)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function j(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function ue(e){const t=j();if(t.length){if(e.target)for(let n=0;n<t.length;n++){const o=t[n];if(o.onSubtreeChange){const s=o.query,i=e.target.nodeType===1?e.target.matches(s)?e.target:e.target.closest(s):e.target.parentElement?e.target.parentElement.closest(s):null;i&&o.onSubtreeChange(i,e)}}for(let n=0;n<e.addedNodes.length;n++){const o=e.addedNodes[n];if(o.nodeType===1)for(let s=0;s<t.length;s++){const i=t[s];E(o,i.selector,i.attribute,i.ComponentFn),i.onInit&&i.onInit(o)}}for(let n=0;n<e.removedNodes.length;n++){const o=e.removedNodes[n];if(o.nodeType===1)for(let s=0;s<t.length;s++){const i=t[s],r=i.query,u=Array.from(o.querySelectorAll(r));o.matches&&o.matches(r)&&u.push(o);for(let l=0;l<u.length;l++){const d=u[l];if(!document.contains(d)){const h=d[i.attribute];if(h&&typeof h.destroy=="function")try{h.destroy()}catch(f){console.error("["+i.attribute+"] destroy failed",d,f)}delete d[i.attribute]}}}}}}function ce(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,A(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++){const o=t[n];if(o.type==="childList")try{ue(o)}catch(s){console.error("[ln-core] lifecycle handler failed",o.target,s)}}}).observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function H(e,t,n,o,s={}){const i=s.extraAttributes||[],r=s.onAttributeChange||null,u=s.onSubtreeChange||null,l=s.onInit||null,d=s.onAttrChange||null,h=s.effects||null,f=s.attributes||null,c=f?te(f):h,p=f?new Set(Object.keys(f)):null,g=s.persist||null;function w(m){const C=m||document.body;if(E(C,e,t,n),f&&q())for(const _ in f){const Ce=f[_],L=Array.from(C.querySelectorAll("["+_+"]"));C.matches&&C.matches("["+_+"]")&&L.push(C);for(let T=0;T<L.length;T++){const D=L[T];x(D)&&M(Ce,D.getAttribute(_),_,o,D)}}l&&l(C)}const a=[];if(e.indexOf("[")!==-1){const m=/\[([\w-]+)/g;let C;for(;(C=m.exec(e))!==null;)a.push(C[1])}else a.push(e);re({selector:e,attribute:t,componentTag:o,attributes:f,ComponentFn:n,onInit:l,observed:a.concat(i),onAttributeChange:r,onAttrChange:d,effects:c,declared:p,persist:g}),le();const v=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]";j().push({selector:e,attribute:t,ComponentFn:n,onInit:l,onSubtreeChange:u,query:v}),ce(),window[t]=w;function b(){oe()>0?ie(function(){w(document.body)}):w(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",b):b(),w}function P(e){return(e||"").replace(/^#/,"")}function S(e){const t=e===void 0?location.hash:e,n={},o=P(t);if(!o)return n;const s=o.split("&");for(let i=0;i<s.length;i++){const r=s[i];if(!r)continue;const u=r.indexOf(":"),l=u>-1?r.slice(0,u):r,d=u>-1?r.slice(u+1):"";if(l)try{n[l]=decodeURIComponent(d)}catch{n[l]=d}}return n}function de(e){if(!e)return null;const t=S();return e in t?t[e]:null}function fe(e,t){if(!e)return;const n=S();t==null?delete n[e]:n[e]=String(t);const s=Object.keys(n).map(function(i){const r=n[i];return r===""?i:i+":"+encodeURIComponent(r)}).join("&");P(location.hash)!==s&&(location.hash=s)}function ae(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function pe(e,t){if(!e||!e.hasAttribute("data-ln-hash"))return null;const n=e.getAttribute("data-ln-hash");if(n&&n.trim()!=="")return n.trim();const o=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return o?t?o+"-"+t:o:t||null}function he(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function ge(e){return!e||typeof e!="string"?null:e.endsWith(".asc")?{fieldOrColumn:e.slice(0,-4),direction:"asc"}:e.endsWith(".desc")?{fieldOrColumn:e.slice(0,-5),direction:"desc"}:null}function be(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function we(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const n=e.slice(0,t),o=e.slice(t+1),s=o?o.split(",").map(function(i){try{return decodeURIComponent(i)}catch{return i}}).filter(Boolean):[];return{key:n,values:s}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=S,window.lnCore.hashGet=de,window.lnCore.hashSet=fe,window.lnCore.hashLinkClick=ae,window.lnCore.resolveHashNamespace=pe,window.lnCore.hashSortEncode=he,window.lnCore.hashSortDecode=ge,window.lnCore.hashFilterEncode=be,window.lnCore.hashFilterDecode=we);function V(e,t,n,o){const s=o,i=window.innerWidth,r=window.innerHeight,u=t.width,l=t.height,d=(n||"bottom").split("-"),h=d[0],f=d[1]==="start"||d[1]==="end"?d[1]:"center",c={top:["top","bottom","right","left"],bottom:["bottom","top","right","left"],left:["left","right","top","bottom"],right:["right","left","top","bottom"]},p=c[h]||c.bottom;function g(b){return b==="top"||b==="bottom"?f==="start"?e.left:f==="end"?e.right-u:e.left+(e.width-u)/2:f==="start"?e.top:f==="end"?e.bottom-l:e.top+(e.height-l)/2}function w(b){let m,C,_=!0;return b==="top"?(m=e.top-s-l,C=g(b),m<0&&(_=!1)):b==="bottom"?(m=e.bottom+s,C=g(b),m+l>r&&(_=!1)):b==="left"?(m=g(b),C=e.left-s-u,C<0&&(_=!1)):(m=g(b),C=e.right+s,C+u>i&&(_=!1)),{top:m,left:C,side:b,fits:_}}let a=null;for(let b=0;b<p.length;b++){const m=w(p[b]);if(m.fits){a=m;break}}a||(a=w(p[0]));let y=a.top,v=a.left;return u>=i?v=0:(v<0&&(v=0),v+u>i&&(v=i-u)),l>=r?y=0:(y<0&&(y=0),y+l>r&&(y=r-l)),{top:y,left:v,placement:a.side}}function U(e){if(!e)return{width:0,height:0};const t=e.style,n=t.visibility,o=t.display,s=t.position;t.visibility="hidden",t.display="block",t.position="fixed";const i=e.offsetWidth,r=e.offsetHeight;return t.visibility=n,t.display=o,t.position=s,{width:i,height:r}}function me(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.uuid=me),(function(){const e="data-ln-popover",t="lnPopover",n="data-ln-popover-for",o="data-ln-popover-position";if(window[t]!==void 0)return;const s={"data-ln-popover":{type:"enum",values:["open","close"],fallback:"close",effect:f,description:"Control state of the popover"},"data-ln-popover-for":{type:"string",description:"Target element ID that this trigger controls"},"data-ln-popover-position":{type:"enum",values:["top","top-start","top-end","bottom","bottom-start","bottom-end","left","left-start","left-end","right","right-start","right-end"],fallback:"bottom",description:"Preferred positioning anchor"},"data-ln-popover-placement":{type:"enum",values:["top","top-start","top-end","bottom","bottom-start","bottom-end","left","left-start","left-end","right","right-start","right-end"],description:"Active calculated placement applied at runtime"}},i=[];let r=null;function u(){r||(r=function(c){if(c.key!=="Escape"||i.length===0)return;i[i.length-1].close()},document.addEventListener("keydown",r))}function l(){i.length>0||r&&(document.removeEventListener("keydown",r),r=null)}function d(c){this.dom=c,this.isOpen=c.getAttribute(e)==="open",this.trigger=null,this._previousFocus=null,this._boundDocClick=null,this._docClickTimeout=null,this._boundReposition=null;const p=this;return this._onRequestOpen=function(g){const w=g.detail&&g.detail.trigger?g.detail.trigger:null;p.open(w)},this._onRequestClose=function(){p.close()},this._onRequestToggle=function(g){const w=g.detail&&g.detail.trigger?g.detail.trigger:null;p.toggle(w)},this._onNativeToggle=function(g){g.newState==="closed"&&p.isOpen&&(p._applyClose(),p.dom.setAttribute(e,"closed"))},c.addEventListener("ln-popover:request-open",this._onRequestOpen),c.addEventListener("ln-popover:request-close",this._onRequestClose),c.addEventListener("ln-popover:request-toggle",this._onRequestToggle),c.addEventListener("toggle",this._onNativeToggle),c.hasAttribute("tabindex")||c.setAttribute("tabindex","-1"),c.hasAttribute("role")||c.setAttribute("role","dialog"),c.hasAttribute("popover")||c.setAttribute("popover","manual"),this.isOpen&&this._applyOpen(null),this}d.prototype.open=function(c){this.isOpen||(this.trigger=c||null,this.dom.setAttribute(e,"open"))},d.prototype.close=function(){this.isOpen&&this.dom.setAttribute(e,"closed")},d.prototype.toggle=function(c){this.isOpen?this.close():this.open(c)},d.prototype._applyOpen=function(c){this.isOpen=!0,c&&(this.trigger=c),this._previousFocus=document.activeElement,typeof this.dom.showPopover=="function"&&this.dom.showPopover();const p=U(this.dom);if(this.trigger){const y=this.trigger.getBoundingClientRect(),v=this.dom.getAttribute(o)||"bottom",b=V(y,p,v,8);this.dom.style.top=b.top+"px",this.dom.style.left=b.left+"px",this.dom.setAttribute("data-ln-popover-placement",b.placement),this.trigger.setAttribute("aria-expanded","true")}const g=this.dom.querySelectorAll('a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'),w=Array.prototype.find.call(g,K);w?w.focus():this.dom.focus();const a=this;this._boundDocClick=function(y){a.dom.contains(y.target)||a.trigger&&a.trigger.contains(y.target)||a.close()},a._docClickTimeout=setTimeout(function(){a._docClickTimeout=null,document.addEventListener("click",a._boundDocClick)},0),this._boundReposition=function(){if(!a.trigger)return;const y=a.trigger.getBoundingClientRect(),v=U(a.dom),b=a.dom.getAttribute(o)||"bottom",m=V(y,v,b,8);a.dom.style.top=m.top+"px",a.dom.style.left=m.left+"px",a.dom.setAttribute("data-ln-popover-placement",m.placement)},window.addEventListener("scroll",this._boundReposition,{passive:!0,capture:!0}),window.addEventListener("resize",this._boundReposition),i.push(this),u(),k(this.dom,"ln-popover:open",{popoverId:this.dom.id,target:this.dom,trigger:this.trigger})},d.prototype._applyClose=function(){this.isOpen=!1,this._docClickTimeout&&(clearTimeout(this._docClickTimeout),this._docClickTimeout=null),this._boundDocClick&&(document.removeEventListener("click",this._boundDocClick),this._boundDocClick=null),this._boundReposition&&(window.removeEventListener("scroll",this._boundReposition,{capture:!0}),window.removeEventListener("resize",this._boundReposition),this._boundReposition=null),this.dom.style.top="",this.dom.style.left="",this.dom.removeAttribute("data-ln-popover-placement"),this.trigger&&this.trigger.setAttribute("aria-expanded","false"),typeof this.dom.hidePopover=="function"&&this.dom.matches(":popover-open")&&this.dom.hidePopover();const c=i.indexOf(this);c!==-1&&i.splice(c,1),l(),this._previousFocus&&this.trigger&&this._previousFocus===this.trigger?this.trigger.focus():this.trigger&&document.activeElement===document.body&&this.trigger.focus(),this._previousFocus=null,k(this.dom,"ln-popover:close",{popoverId:this.dom.id,target:this.dom,trigger:this.trigger}),this.trigger=null},d.prototype.destroy=function(){this.dom[t]&&(this.dom.removeEventListener("ln-popover:request-open",this._onRequestOpen),this.dom.removeEventListener("ln-popover:request-close",this._onRequestClose),this.dom.removeEventListener("ln-popover:request-toggle",this._onRequestToggle),this.dom.removeEventListener("toggle",this._onNativeToggle),this.isOpen&&this._applyClose(),delete this.dom[t])};function h(c){this.dom=c;const p=c.getAttribute(n);return c.setAttribute("aria-haspopup","dialog"),c.setAttribute("aria-expanded","false"),c.setAttribute("aria-controls",p),this._onClick=function(g){if(g.ctrlKey||g.metaKey||g.button===1)return;g.preventDefault();const w=document.getElementById(p);if(!w)return;w[t]&&(w[t].trigger=c);const a=w.getAttribute(e);w.setAttribute(e,a==="open"?"closed":"open")},c.addEventListener("click",this._onClick),this}h.prototype.destroy=function(){this.dom.removeEventListener("click",this._onClick),delete this.dom[t+"Trigger"]};function f(c){const p=c[t];if(!p)return;const w=c.getAttribute(e)==="open";if(w!==p.isOpen)if(w){if(I(c,"ln-popover:before-open",{popoverId:c.id,target:c,trigger:p.trigger}).defaultPrevented){c.setAttribute(e,"closed");return}p._applyOpen(p.trigger)}else{if(I(c,"ln-popover:before-close",{popoverId:c.id,target:c,trigger:p.trigger}).defaultPrevented){c.setAttribute(e,"open");return}p._applyClose()}}H(e,t,d,"ln-popover",{attributes:s}),H(n,t+"Trigger",h,"ln-popover-trigger")})()})();
|