@livenetworks/ashlar 2.0.3 → 2.0.5
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/components/ln-debug/ln-debug.js +1 -1
- package/components/ln-debug/src/generated-attributes.js +0 -1
- package/components/ln-modal/README.md +5 -5
- package/components/ln-modal/ln-modal.js +1 -1
- package/components/ln-modal/ln-modal.schema.json +9 -5
- package/components/ln-modal/ln-modal.scss +1 -1
- package/components/ln-modal/src/ln-modal.js +47 -2
- package/components/ln-toast/ln-toast.js +1 -1
- package/components/ln-toast/ln-toast.scss +5 -1
- package/components/ln-toast/src/ln-toast.js +1 -1
- package/components/ln-ui-coordinator/README.md +62 -101
- package/components/ln-ui-coordinator/ln-ui-coordinator.js +1 -1
- package/components/ln-ui-coordinator/ln-ui-coordinator.schema.json +1 -33
- package/components/ln-ui-coordinator/src/ln-ui-coordinator.js +140 -403
- package/ln-ashlar.html-data.json +1 -5
- package/package.json +1 -1
- package/web-types.json +2 -9
|
@@ -1,403 +1,140 @@
|
|
|
1
|
-
import { registerComponent, dispatch, hashGet, hashSet, hashParse, hashLinkClick
|
|
2
|
-
|
|
3
|
-
(function () {
|
|
4
|
-
const DOM_SELECTOR = 'data-ln-ui-coordinator';
|
|
5
|
-
const DOM_ATTRIBUTE = 'lnUiCoordinator';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
} else {
|
|
142
|
-
// Restore per-open hash-write (pre-extraction invariant): every
|
|
143
|
-
// open leaves a URL segment so _syncHashModals never closes it.
|
|
144
|
-
if (target.id) {
|
|
145
|
-
hashSet(target.id, _hashParamForOpen(target.dataset.lnModalMode, trigger));
|
|
146
|
-
}
|
|
147
|
-
dispatch(target, 'ln-modal:request-open', {});
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// 2. Handle hash anchor click <a href="#modalId"> / <a href="#modalId:param">
|
|
154
|
-
const hashAnchor = e.target.closest('a[href^="#"]');
|
|
155
|
-
if (hashAnchor) {
|
|
156
|
-
const map = hashParse(hashAnchor.getAttribute('href'));
|
|
157
|
-
for (const ns in map) {
|
|
158
|
-
const el = document.getElementById(ns);
|
|
159
|
-
if (el && el.lnModal) {
|
|
160
|
-
if (!hashLinkClick(e)) return;
|
|
161
|
-
hashSet(ns, map[ns]);
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
// ─── Before Open Reset Gate ────────────────────────────
|
|
169
|
-
|
|
170
|
-
document.addEventListener('ln-modal:before-open', function (e) {
|
|
171
|
-
const modal = e.target;
|
|
172
|
-
if (!modal || !modal.lnModal) return;
|
|
173
|
-
|
|
174
|
-
const mode = modal.dataset.lnModalMode || 'new';
|
|
175
|
-
if (mode === 'new') {
|
|
176
|
-
_resetModalForm(modal);
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
// ─── Open Event Fill Dispatcher ───────────────────────
|
|
181
|
-
|
|
182
|
-
document.addEventListener('ln-modal:open', function (e) {
|
|
183
|
-
const modal = e.target;
|
|
184
|
-
if (!modal || !modal.lnModal || !modal.id) return;
|
|
185
|
-
|
|
186
|
-
let param = hashGet(modal.id);
|
|
187
|
-
|
|
188
|
-
// Non-trigger opens (programmatic / SSR-via-mutation) reach here with no
|
|
189
|
-
// segment — adopt one so foreign hashchanges never close the modal.
|
|
190
|
-
// Trigger opens already wrote their segment, so this is skipped for them.
|
|
191
|
-
if (param === null) {
|
|
192
|
-
param = _hashParamForOpen(modal.dataset.lnModalMode, null);
|
|
193
|
-
hashSet(modal.id, param);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (param) {
|
|
197
|
-
modal.dataset.lnModalMode = 'edit';
|
|
198
|
-
dispatch(modal, 'ln-fill:request', { id: param });
|
|
199
|
-
} else {
|
|
200
|
-
modal.dataset.lnModalMode = 'new';
|
|
201
|
-
_resetModalForm(modal);
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
// ─── Hash Sync Listener & Modal Route State ────────────
|
|
206
|
-
|
|
207
|
-
let _inSync = false;
|
|
208
|
-
function _syncHashModals() {
|
|
209
|
-
if (_inSync) return;
|
|
210
|
-
_inSync = true;
|
|
211
|
-
try {
|
|
212
|
-
const modals = document.querySelectorAll('[data-ln-modal][id]');
|
|
213
|
-
for (let i = 0; i < modals.length; i++) {
|
|
214
|
-
const modal = modals[i];
|
|
215
|
-
if (!modal.lnModal) continue;
|
|
216
|
-
const hashNs = modal.id;
|
|
217
|
-
|
|
218
|
-
const param = hashGet(hashNs);
|
|
219
|
-
const present = param !== null;
|
|
220
|
-
const isOpen = modal.lnModal.isOpen;
|
|
221
|
-
|
|
222
|
-
if (present) {
|
|
223
|
-
const mode = param ? 'edit' : 'new';
|
|
224
|
-
modal.dataset.lnModalMode = mode;
|
|
225
|
-
if (!isOpen) {
|
|
226
|
-
dispatch(modal, 'ln-modal:request-open', {});
|
|
227
|
-
} else {
|
|
228
|
-
// Modal is already open, but hash param changed dynamically (e.g. #modal:42 -> #modal:5)
|
|
229
|
-
if (param) {
|
|
230
|
-
dispatch(modal, 'ln-fill:request', { id: param });
|
|
231
|
-
} else {
|
|
232
|
-
_resetModalForm(modal);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
} else if (isOpen) {
|
|
236
|
-
dispatch(modal, 'ln-modal:request-close', {});
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
} finally {
|
|
240
|
-
_inSync = false;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// SSR modals authored data-ln-modal="open" never pass through a trigger or
|
|
245
|
-
// hash anchor, so they carry no URL segment. Adopt them into the hash BEFORE
|
|
246
|
-
// the first sync, so _syncHashModals sees them present and keeps them open
|
|
247
|
-
// instead of closing them as a phantom back-navigation. Skips modals that
|
|
248
|
-
// already have a segment (e.g. an SSR deep-link URL).
|
|
249
|
-
function _adoptOpenModals() {
|
|
250
|
-
const openModals = document.querySelectorAll('[data-ln-modal="open"][id]');
|
|
251
|
-
for (let i = 0; i < openModals.length; i++) {
|
|
252
|
-
const modal = openModals[i];
|
|
253
|
-
if (!modal.lnModal) continue;
|
|
254
|
-
if (hashGet(modal.id) !== null) continue;
|
|
255
|
-
hashSet(modal.id, _hashParamForOpen(modal.dataset.lnModalMode, null));
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
window.addEventListener('hashchange', _syncHashModals);
|
|
260
|
-
|
|
261
|
-
function _bootSync() {
|
|
262
|
-
_adoptOpenModals();
|
|
263
|
-
_syncHashModals();
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
if (document.readyState === 'loading') {
|
|
267
|
-
document.addEventListener('DOMContentLoaded', function () {
|
|
268
|
-
queueBoot(_bootSync);
|
|
269
|
-
});
|
|
270
|
-
} else {
|
|
271
|
-
queueBoot(_bootSync);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// ─── AJAX Submission Mediation & Toast Routing ──────────
|
|
275
|
-
|
|
276
|
-
function _handleAjaxSuccess(e) {
|
|
277
|
-
const detail = e.detail || {};
|
|
278
|
-
const data = detail.data;
|
|
279
|
-
|
|
280
|
-
// 1. Dispatch UI toast notification if response envelope contains a message
|
|
281
|
-
if (data && data.message) {
|
|
282
|
-
const msg = data.message;
|
|
283
|
-
dispatch(window, 'ln-toast:enqueue', {
|
|
284
|
-
type: msg.type || 'success',
|
|
285
|
-
title: msg.title || '',
|
|
286
|
-
message: msg.body || ''
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// 2. Auto-close modal and clean up if the submitting element was inside a modal
|
|
291
|
-
const modal = e.target.closest('[data-ln-modal]');
|
|
292
|
-
if (modal && modal.lnModal) {
|
|
293
|
-
if (modal.id) {
|
|
294
|
-
hashSet(modal.id, null);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
dispatch(modal, 'ln-modal:request-close', {});
|
|
298
|
-
_resetModalForm(modal);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
function _handleAjaxError(e) {
|
|
303
|
-
const detail = e.detail || {};
|
|
304
|
-
const data = detail.data;
|
|
305
|
-
const status = detail.status || 0;
|
|
306
|
-
const dict = _getCoordinatorDict(e.target);
|
|
307
|
-
|
|
308
|
-
// 1. If server returned structured error message, toast it
|
|
309
|
-
if (data && data.message) {
|
|
310
|
-
const msg = data.message;
|
|
311
|
-
dispatch(window, 'ln-toast:enqueue', {
|
|
312
|
-
type: msg.type || 'error',
|
|
313
|
-
title: msg.title || '',
|
|
314
|
-
message: msg.body || ''
|
|
315
|
-
});
|
|
316
|
-
} else if (status === 0) {
|
|
317
|
-
// 2. Genuine network failure (DNS / offline / abort / connection dropped)
|
|
318
|
-
dispatch(window, 'ln-toast:enqueue', {
|
|
319
|
-
type: 'error',
|
|
320
|
-
title: dict['network-error-title'] || '',
|
|
321
|
-
message: dict['network-error'] || 'Network error'
|
|
322
|
-
});
|
|
323
|
-
} else {
|
|
324
|
-
// 3. Server HTTP error (status >= 400 or HTML error page) without structured JSON message
|
|
325
|
-
dispatch(window, 'ln-toast:enqueue', {
|
|
326
|
-
type: 'error',
|
|
327
|
-
title: dict['server-error-title'] || '',
|
|
328
|
-
message: dict['server-error'] || 'Server error'
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// Note: We deliberately do NOT close the modal on error so form validation feedback remains visible
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
document.addEventListener('ln-ajax:success', _handleAjaxSuccess);
|
|
336
|
-
document.addEventListener('ln-ajax:error', _handleAjaxError);
|
|
337
|
-
|
|
338
|
-
// ─── Upload Feedback Mediation ──────────────────────────
|
|
339
|
-
|
|
340
|
-
function _handleUploadInvalid(e) {
|
|
341
|
-
const detail = e.detail || {};
|
|
342
|
-
const dict = _getCoordinatorDict(e.target);
|
|
343
|
-
const message = detail.message || (detail.reason === 'max-size' ? dict['upload-max-size'] || 'File is too large' : (detail.reason === 'max-files' ? dict['upload-max-files'] || 'Maximum file count exceeded' : dict['upload-invalid-type'] || 'This file type is not allowed'));
|
|
344
|
-
const title = dict['upload-invalid-title'] || 'Invalid File';
|
|
345
|
-
|
|
346
|
-
dispatch(window, 'ln-toast:enqueue', {
|
|
347
|
-
type: 'error',
|
|
348
|
-
title: title,
|
|
349
|
-
message: message
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
function _handleUploadError(e) {
|
|
354
|
-
const detail = e.detail || {};
|
|
355
|
-
const dict = _getCoordinatorDict(e.target);
|
|
356
|
-
const message = detail.message || dict['upload-failed'] || 'Failed to upload file';
|
|
357
|
-
const title = dict['upload-error-title'] || 'Upload Error';
|
|
358
|
-
|
|
359
|
-
dispatch(window, 'ln-toast:enqueue', {
|
|
360
|
-
type: 'error',
|
|
361
|
-
title: title,
|
|
362
|
-
message: message
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
document.addEventListener('ln-upload:invalid', _handleUploadInvalid);
|
|
367
|
-
document.addEventListener('ln-upload:error', _handleUploadError);
|
|
368
|
-
|
|
369
|
-
// ─── Hash Cleanup & Reset on Modal Close ───────────────
|
|
370
|
-
|
|
371
|
-
document.addEventListener('ln-modal:close', function (e) {
|
|
372
|
-
const modal = e.target;
|
|
373
|
-
if (!modal || !modal.lnModal) return;
|
|
374
|
-
|
|
375
|
-
if (modal.id) {
|
|
376
|
-
if (hashGet(modal.id) !== null) {
|
|
377
|
-
hashSet(modal.id, null);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
if (modal.dataset.lnModalMode === 'new') {
|
|
382
|
-
_resetModalForm(modal);
|
|
383
|
-
}
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
// ─── Component Constructor & Registration ────────────
|
|
387
|
-
|
|
388
|
-
function _component(dom) {
|
|
389
|
-
this.dom = dom;
|
|
390
|
-
this.dict = buildDict(dom, DICT_SELECTOR);
|
|
391
|
-
return this;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
_component.prototype.destroy = function () {
|
|
395
|
-
if (!this.dom[DOM_ATTRIBUTE]) return;
|
|
396
|
-
this.dict = {};
|
|
397
|
-
delete this.dom[DOM_ATTRIBUTE];
|
|
398
|
-
};
|
|
399
|
-
|
|
400
|
-
registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-ui-coordinator', {
|
|
401
|
-
attributes: ATTRIBUTES
|
|
402
|
-
});
|
|
403
|
-
})();
|
|
1
|
+
import { registerComponent, dispatch, hashGet, hashSet, hashParse, hashLinkClick } from '../../ln-core';
|
|
2
|
+
|
|
3
|
+
(function () {
|
|
4
|
+
const DOM_SELECTOR = 'data-ln-ui-coordinator';
|
|
5
|
+
const DOM_ATTRIBUTE = 'lnUiCoordinator';
|
|
6
|
+
|
|
7
|
+
if (window[DOM_ATTRIBUTE] !== undefined) return;
|
|
8
|
+
|
|
9
|
+
// ─── Attribute Contract (SSOT) ──────────────────────────
|
|
10
|
+
const ATTRIBUTES = {
|
|
11
|
+
'data-ln-ui-coordinator': {
|
|
12
|
+
type: 'marker',
|
|
13
|
+
description: 'Mounts UI coordinator mediating global hash-routing, modals, and toasts'
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// ─── Hash Navigation (Anchors & hashchange) ─────────────
|
|
18
|
+
|
|
19
|
+
document.addEventListener('click', function (e) {
|
|
20
|
+
if (e.ctrlKey || e.metaKey || e.button === 1) return;
|
|
21
|
+
|
|
22
|
+
const hashAnchor = e.target.closest('a[href^="#"]');
|
|
23
|
+
if (!hashAnchor) return;
|
|
24
|
+
|
|
25
|
+
const rawHref = hashAnchor.getAttribute('href');
|
|
26
|
+
const map = hashParse(rawHref);
|
|
27
|
+
|
|
28
|
+
for (const ns in map) {
|
|
29
|
+
const modal = document.getElementById(ns);
|
|
30
|
+
if (modal && modal.lnModal) {
|
|
31
|
+
if (!hashLinkClick(e)) return;
|
|
32
|
+
hashSet(ns, map[ns]);
|
|
33
|
+
if (!modal.lnModal.isOpen) {
|
|
34
|
+
dispatch(modal, 'ln-modal:request-open', {});
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
function _syncHashModals() {
|
|
42
|
+
const hash = location.hash;
|
|
43
|
+
if (!hash) return;
|
|
44
|
+
|
|
45
|
+
const map = hashParse(hash);
|
|
46
|
+
for (const ns in map) {
|
|
47
|
+
const modal = document.getElementById(ns);
|
|
48
|
+
if (modal && modal.lnModal && !modal.lnModal.isOpen) {
|
|
49
|
+
dispatch(modal, 'ln-modal:request-open', {});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
window.addEventListener('hashchange', _syncHashModals);
|
|
55
|
+
|
|
56
|
+
if (document.readyState === 'loading') {
|
|
57
|
+
document.addEventListener('DOMContentLoaded', _syncHashModals);
|
|
58
|
+
} else {
|
|
59
|
+
_syncHashModals();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ─── Modal Close Hash Cleanup ───────────────────────────
|
|
63
|
+
|
|
64
|
+
document.addEventListener('ln-modal:close', function (e) {
|
|
65
|
+
const modal = e.target;
|
|
66
|
+
if (modal && modal.id && hashGet(modal.id) !== null) {
|
|
67
|
+
hashSet(modal.id, null);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// ─── AJAX Toast & Modal Auto-Close Mediation ───────────
|
|
72
|
+
|
|
73
|
+
document.addEventListener('ln-ajax:success', function (e) {
|
|
74
|
+
const detail = e.detail || {};
|
|
75
|
+
const data = detail.data;
|
|
76
|
+
|
|
77
|
+
// 1. Dispatch toast if server returned a message
|
|
78
|
+
if (data && data.message) {
|
|
79
|
+
const msg = data.message;
|
|
80
|
+
dispatch(window, 'ln-toast:enqueue', {
|
|
81
|
+
type: msg.type || 'success',
|
|
82
|
+
title: msg.title || '',
|
|
83
|
+
message: typeof msg === 'string' ? msg : (msg.body || '')
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 2. If submitted inside a modal, close modal and clear URL hash
|
|
88
|
+
const modal = e.target.closest('[data-ln-modal]');
|
|
89
|
+
if (modal && modal.lnModal) {
|
|
90
|
+
if (modal.id && hashGet(modal.id) !== null) {
|
|
91
|
+
hashSet(modal.id, null);
|
|
92
|
+
}
|
|
93
|
+
dispatch(modal, 'ln-modal:request-close', {});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
document.addEventListener('ln-ajax:error', function (e) {
|
|
98
|
+
const detail = e.detail || {};
|
|
99
|
+
const data = detail.data;
|
|
100
|
+
|
|
101
|
+
// Dispatch toast if server returned an error message
|
|
102
|
+
if (data && data.message) {
|
|
103
|
+
const msg = data.message;
|
|
104
|
+
dispatch(window, 'ln-toast:enqueue', {
|
|
105
|
+
type: msg.type || 'error',
|
|
106
|
+
title: msg.title || '',
|
|
107
|
+
message: typeof msg === 'string' ? msg : (msg.body || '')
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// ─── Upload Toast Mediation ─────────────────────────────
|
|
113
|
+
|
|
114
|
+
document.addEventListener('ln-upload:error', function (e) {
|
|
115
|
+
const detail = e.detail || {};
|
|
116
|
+
if (detail.message) {
|
|
117
|
+
dispatch(window, 'ln-toast:enqueue', {
|
|
118
|
+
type: 'error',
|
|
119
|
+
title: '',
|
|
120
|
+
message: detail.message
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
// ─── Component Constructor & Registration ──────────────
|
|
127
|
+
|
|
128
|
+
function _component(dom) {
|
|
129
|
+
this.dom = dom;
|
|
130
|
+
return this;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
_component.prototype.destroy = function () {
|
|
134
|
+
delete this.dom[DOM_ATTRIBUTE];
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-ui-coordinator', {
|
|
138
|
+
attributes: ATTRIBUTES
|
|
139
|
+
});
|
|
140
|
+
})();
|
package/ln-ashlar.html-data.json
CHANGED
|
@@ -791,7 +791,7 @@
|
|
|
791
791
|
},
|
|
792
792
|
{
|
|
793
793
|
"name": "data-ln-modal-for",
|
|
794
|
-
"description": "
|
|
794
|
+
"description": "Target modal ID to open on trigger click"
|
|
795
795
|
},
|
|
796
796
|
{
|
|
797
797
|
"name": "data-ln-modal-mode",
|
|
@@ -1655,10 +1655,6 @@
|
|
|
1655
1655
|
"description": "Mounts UI coordinator mediating global hash-routing, modals, and toasts",
|
|
1656
1656
|
"valueSet": "v"
|
|
1657
1657
|
},
|
|
1658
|
-
{
|
|
1659
|
-
"name": "data-ln-ui-coordinator-dict",
|
|
1660
|
-
"description": "Dictionary key prefix mapping for translatable UI coordinator messages"
|
|
1661
|
-
},
|
|
1662
1658
|
{
|
|
1663
1659
|
"name": "data-ln-upload",
|
|
1664
1660
|
"description": "Endpoint URL for file uploads"
|
package/package.json
CHANGED
package/web-types.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/web-types",
|
|
3
3
|
"name": "@livenetworks/ashlar",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.5",
|
|
5
5
|
"framework": "html",
|
|
6
6
|
"contributions": {
|
|
7
7
|
"html": {
|
|
@@ -1054,7 +1054,7 @@
|
|
|
1054
1054
|
},
|
|
1055
1055
|
{
|
|
1056
1056
|
"name": "data-ln-modal-for",
|
|
1057
|
-
"description": "
|
|
1057
|
+
"description": "Target modal ID to open on trigger click",
|
|
1058
1058
|
"value": {
|
|
1059
1059
|
"type": "string"
|
|
1060
1060
|
}
|
|
@@ -2122,13 +2122,6 @@
|
|
|
2122
2122
|
"type": "boolean"
|
|
2123
2123
|
}
|
|
2124
2124
|
},
|
|
2125
|
-
{
|
|
2126
|
-
"name": "data-ln-ui-coordinator-dict",
|
|
2127
|
-
"description": "Dictionary key prefix mapping for translatable UI coordinator messages",
|
|
2128
|
-
"value": {
|
|
2129
|
-
"type": "string"
|
|
2130
|
-
}
|
|
2131
|
-
},
|
|
2132
2125
|
{
|
|
2133
2126
|
"name": "data-ln-upload",
|
|
2134
2127
|
"description": "Endpoint URL for file uploads",
|