mnfst 0.5.210 → 0.5.211
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.
|
@@ -182,9 +182,11 @@ window.ManifestComponentsProcessor = {
|
|
|
182
182
|
const registry = window.ManifestComponentsRegistry;
|
|
183
183
|
const loader = window.ManifestComponentsLoader;
|
|
184
184
|
if (!registry || !loader) {
|
|
185
|
+
console.debug('[Manifest Components] skipped: registry or loader unavailable', element);
|
|
185
186
|
return;
|
|
186
187
|
}
|
|
187
188
|
if (!registry.registered.has(name)) {
|
|
189
|
+
console.debug('[Manifest Components] skipped: component not registered', element);
|
|
188
190
|
return;
|
|
189
191
|
}
|
|
190
192
|
if (element.hasAttribute('data-pre-rendered') || element.hasAttribute('data-processed')) {
|
|
@@ -192,10 +194,12 @@ window.ManifestComponentsProcessor = {
|
|
|
192
194
|
if (element.hasAttribute('data-pre-rendered') && window.Alpine && typeof window.Alpine.initTree === 'function') {
|
|
193
195
|
try { window.Alpine.initTree(element); } catch (e) { /* graceful */ }
|
|
194
196
|
}
|
|
197
|
+
console.debug('[Manifest Components] skipped: already pre-rendered/processed', element);
|
|
195
198
|
return;
|
|
196
199
|
}
|
|
197
200
|
const content = await loader.loadComponent(name);
|
|
198
201
|
if (!content) {
|
|
202
|
+
console.debug('[Manifest Components] skipped: failed to load component', element);
|
|
199
203
|
element.replaceWith(document.createComment(` Failed to load component: ${name} `));
|
|
200
204
|
return;
|
|
201
205
|
}
|
|
@@ -203,6 +207,7 @@ window.ManifestComponentsProcessor = {
|
|
|
203
207
|
container.innerHTML = content.trim();
|
|
204
208
|
const topLevelElements = Array.from(container.children);
|
|
205
209
|
if (topLevelElements.length === 0) {
|
|
210
|
+
console.debug('[Manifest Components] skipped: empty component template', element);
|
|
206
211
|
element.replaceWith(document.createComment(` Empty component: ${name} `));
|
|
207
212
|
return;
|
|
208
213
|
}
|
|
@@ -415,6 +420,7 @@ window.ManifestComponentsProcessor = {
|
|
|
415
420
|
}
|
|
416
421
|
const parent = element.parentElement;
|
|
417
422
|
if (!parent || !document.contains(element)) {
|
|
423
|
+
console.debug('[Manifest Components] skipped: element detached before swap', element);
|
|
418
424
|
return;
|
|
419
425
|
}
|
|
420
426
|
// Replace the placeholder element with the component content
|
|
@@ -494,11 +500,21 @@ window.ManifestComponentsProcessor = {
|
|
|
494
500
|
|
|
495
501
|
// Components swapping
|
|
496
502
|
(function () {
|
|
503
|
+
// Never reset — ids must stay unique for the life of the page so overlapping
|
|
504
|
+
// processAll runs can't mint a colliding id for a live instance.
|
|
497
505
|
let componentInstanceCounters = {};
|
|
498
506
|
const swappedInstances = new Set();
|
|
499
507
|
const instanceRouteMap = new Map();
|
|
500
508
|
const placeholderMap = new Map();
|
|
501
509
|
|
|
510
|
+
// Serialises processAll: a call while one is in flight coalesces into a
|
|
511
|
+
// single trailing re-run (latest path wins) instead of interleaving.
|
|
512
|
+
let activeRun = null;
|
|
513
|
+
let trailingRun = null;
|
|
514
|
+
let trailingPath = null;
|
|
515
|
+
let hasTrailing = false;
|
|
516
|
+
let trailingSettlers = null;
|
|
517
|
+
|
|
502
518
|
function getComponentInstanceId(name) {
|
|
503
519
|
if (!componentInstanceCounters[name]) componentInstanceCounters[name] = 1;
|
|
504
520
|
else componentInstanceCounters[name]++;
|
|
@@ -513,9 +529,15 @@ window.ManifestComponentsProcessor = {
|
|
|
513
529
|
window.ManifestComponentsSwapping = {
|
|
514
530
|
// Swap in source code for a placeholder
|
|
515
531
|
async swapIn(placeholder) {
|
|
516
|
-
if (placeholder.hasAttribute('data-swapped'))
|
|
532
|
+
if (placeholder.hasAttribute('data-swapped')) {
|
|
533
|
+
console.debug('[Manifest Components] skipped swapIn: already marked data-swapped', placeholder);
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
517
536
|
const processor = window.ManifestComponentsProcessor;
|
|
518
|
-
if (!processor)
|
|
537
|
+
if (!processor) {
|
|
538
|
+
console.debug('[Manifest Components] skipped swapIn: processor unavailable', placeholder);
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
519
541
|
const name = placeholder.tagName.toLowerCase().replace('x-', '');
|
|
520
542
|
let instanceId = placeholder.getAttribute('data-component');
|
|
521
543
|
if (!instanceId) {
|
|
@@ -542,10 +564,16 @@ window.ManifestComponentsProcessor = {
|
|
|
542
564
|
},
|
|
543
565
|
// Revert to placeholder
|
|
544
566
|
revert(instanceId) {
|
|
545
|
-
if (!swappedInstances.has(instanceId))
|
|
567
|
+
if (!swappedInstances.has(instanceId)) {
|
|
568
|
+
console.debug('[Manifest Components] skipped revert: instance not tracked', instanceId);
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
546
571
|
// Remove all elements with data-component=instanceId
|
|
547
572
|
const rendered = Array.from(document.querySelectorAll(`[data-component="${instanceId}"]`));
|
|
548
|
-
if (rendered.length === 0)
|
|
573
|
+
if (rendered.length === 0) {
|
|
574
|
+
console.debug('[Manifest Components] skipped revert: no rendered elements found', instanceId);
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
549
577
|
const first = rendered[0];
|
|
550
578
|
const parent = first.parentNode;
|
|
551
579
|
// Retrieve the original placeholder from the map
|
|
@@ -585,11 +613,14 @@ window.ManifestComponentsProcessor = {
|
|
|
585
613
|
// Log after revert
|
|
586
614
|
logSiblings(parent, `After revert for ${instanceId}`);
|
|
587
615
|
},
|
|
588
|
-
// Main swapping logic
|
|
589
|
-
|
|
590
|
-
|
|
616
|
+
// Main swapping logic — single pass. Call via processAll(), not directly:
|
|
617
|
+
// this has no re-entrancy guard of its own.
|
|
618
|
+
async _runProcessAll(normalizedPathFromEvent) {
|
|
591
619
|
const registry = window.ManifestComponentsRegistry;
|
|
592
|
-
if (!registry)
|
|
620
|
+
if (!registry) {
|
|
621
|
+
console.debug('[Manifest Components] skipped processAll: registry unavailable');
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
593
624
|
const routing = window.ManifestRouting;
|
|
594
625
|
|
|
595
626
|
// Use normalized path from event if provided, otherwise compute from window.location
|
|
@@ -676,6 +707,40 @@ window.ManifestComponentsProcessor = {
|
|
|
676
707
|
}
|
|
677
708
|
}
|
|
678
709
|
},
|
|
710
|
+
// Public entry point. Coalesces overlapping calls: while a run is active,
|
|
711
|
+
// later calls don't start their own interleaved run — they queue exactly
|
|
712
|
+
// one trailing re-run (latest path wins) and resolve when it finishes.
|
|
713
|
+
async processAll(normalizedPathFromEvent = null) {
|
|
714
|
+
if (activeRun) {
|
|
715
|
+
hasTrailing = true;
|
|
716
|
+
trailingPath = normalizedPathFromEvent;
|
|
717
|
+
if (!trailingRun) {
|
|
718
|
+
trailingRun = new Promise((resolve, reject) => {
|
|
719
|
+
trailingSettlers = { resolve, reject };
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
return trailingRun;
|
|
723
|
+
}
|
|
724
|
+
activeRun = this._runProcessAll(normalizedPathFromEvent);
|
|
725
|
+
let error = null;
|
|
726
|
+
try {
|
|
727
|
+
await activeRun;
|
|
728
|
+
} catch (e) {
|
|
729
|
+
error = e;
|
|
730
|
+
} finally {
|
|
731
|
+
activeRun = null;
|
|
732
|
+
}
|
|
733
|
+
if (hasTrailing) {
|
|
734
|
+
hasTrailing = false;
|
|
735
|
+
const path = trailingPath;
|
|
736
|
+
const settlers = trailingSettlers;
|
|
737
|
+
trailingRun = null;
|
|
738
|
+
trailingSettlers = null;
|
|
739
|
+
trailingPath = null;
|
|
740
|
+
this.processAll(path).then(settlers.resolve, settlers.reject);
|
|
741
|
+
}
|
|
742
|
+
if (error) throw error;
|
|
743
|
+
},
|
|
679
744
|
initialize() {
|
|
680
745
|
// On init, process all
|
|
681
746
|
this.processAll().then(() => {
|
package/lib/manifest.data.js
CHANGED
|
@@ -274,6 +274,37 @@ function initializeDropdownPlugin() {
|
|
|
274
274
|
if (menu.matches(':popover-open')) menu.hidePopover();
|
|
275
275
|
};
|
|
276
276
|
|
|
277
|
+
// How long after a long-press open to ignore a follow-up native
|
|
278
|
+
// contextmenu (Android) or synthetic click.
|
|
279
|
+
const LONG_PRESS_DUPE_WINDOW_MS = 750;
|
|
280
|
+
|
|
281
|
+
// Shared positioning: place the menu at (x, y), overriding anchor
|
|
282
|
+
// positioning. Used by both the contextmenu (mouse) path and the
|
|
283
|
+
// touch long-press path below.
|
|
284
|
+
const openContextMenuAt = (triggerTarget, x, y) => {
|
|
285
|
+
// Stash the actual right-clicked element so menu items can act on it.
|
|
286
|
+
// (triggerTarget is the deepest hit; el is the directive-bearing ancestor.)
|
|
287
|
+
menu._triggerEl = triggerTarget.closest('[data-cp-value], [x-data]') || el;
|
|
288
|
+
menu._triggerHost = el;
|
|
289
|
+
|
|
290
|
+
menu.style.position = 'fixed';
|
|
291
|
+
menu.style.positionAnchor = 'unset';
|
|
292
|
+
menu.style.positionArea = 'unset';
|
|
293
|
+
menu.style.inset = 'auto';
|
|
294
|
+
menu.style.left = x + 'px';
|
|
295
|
+
menu.style.top = y + 'px';
|
|
296
|
+
menu.style.margin = '0';
|
|
297
|
+
|
|
298
|
+
if (!menu.matches(':popover-open')) menu.showPopover();
|
|
299
|
+
|
|
300
|
+
// Adjust if menu overflows viewport
|
|
301
|
+
requestAnimationFrame(() => {
|
|
302
|
+
const rect = menu.getBoundingClientRect();
|
|
303
|
+
if (rect.right > window.innerWidth) menu.style.left = (window.innerWidth - rect.width) + 'px';
|
|
304
|
+
if (rect.bottom > window.innerHeight) menu.style.top = (window.innerHeight - rect.height) + 'px';
|
|
305
|
+
});
|
|
306
|
+
};
|
|
307
|
+
|
|
277
308
|
// Bind once per element (reprocessing would stack duplicates).
|
|
278
309
|
if (!el.__mnfstContextTriggerBound) {
|
|
279
310
|
el.__mnfstContextTriggerBound = true;
|
|
@@ -281,29 +312,68 @@ function initializeDropdownPlugin() {
|
|
|
281
312
|
e.preventDefault();
|
|
282
313
|
e.stopPropagation();
|
|
283
314
|
|
|
284
|
-
//
|
|
285
|
-
//
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
// Position at cursor, overriding anchor positioning
|
|
290
|
-
menu.style.position = 'fixed';
|
|
291
|
-
menu.style.positionAnchor = 'unset';
|
|
292
|
-
menu.style.positionArea = 'unset';
|
|
293
|
-
menu.style.inset = 'auto';
|
|
294
|
-
menu.style.left = e.clientX + 'px';
|
|
295
|
-
menu.style.top = e.clientY + 'px';
|
|
296
|
-
menu.style.margin = '0';
|
|
297
|
-
|
|
298
|
-
if (!menu.matches(':popover-open')) menu.showPopover();
|
|
299
|
-
|
|
300
|
-
// Adjust if menu overflows viewport
|
|
301
|
-
requestAnimationFrame(() => {
|
|
302
|
-
const rect = menu.getBoundingClientRect();
|
|
303
|
-
if (rect.right > window.innerWidth) menu.style.left = (window.innerWidth - rect.width) + 'px';
|
|
304
|
-
if (rect.bottom > window.innerHeight) menu.style.top = (window.innerHeight - rect.height) + 'px';
|
|
305
|
-
});
|
|
315
|
+
// Android fires a real contextmenu after a touch long-press too —
|
|
316
|
+
// our pointer path already opened the menu, so ignore the dupe.
|
|
317
|
+
if (el.__mnfstLongPressOpenedAt && Date.now() - el.__mnfstLongPressOpenedAt < LONG_PRESS_DUPE_WINDOW_MS) return;
|
|
318
|
+
|
|
319
|
+
openContextMenuAt(e.target, e.clientX, e.clientY);
|
|
306
320
|
});
|
|
321
|
+
|
|
322
|
+
// iOS Safari never fires `contextmenu` for a touch long-press (Android
|
|
323
|
+
// does). Drive the same open from pointer events instead — touch/pen
|
|
324
|
+
// only, mouse keeps native contextmenu semantics.
|
|
325
|
+
const LONG_PRESS_MS = 500;
|
|
326
|
+
const MOVE_SLOP_PX = 10;
|
|
327
|
+
let pressTimer = null;
|
|
328
|
+
let startX = 0, startY = 0;
|
|
329
|
+
let pressTarget = null;
|
|
330
|
+
|
|
331
|
+
const suppressCallout = () => {
|
|
332
|
+
el.style.setProperty('-webkit-touch-callout', 'none');
|
|
333
|
+
el.style.setProperty('-webkit-user-select', 'none');
|
|
334
|
+
el.style.setProperty('user-select', 'none');
|
|
335
|
+
};
|
|
336
|
+
const restoreCallout = () => {
|
|
337
|
+
el.style.removeProperty('-webkit-touch-callout');
|
|
338
|
+
el.style.removeProperty('-webkit-user-select');
|
|
339
|
+
el.style.removeProperty('user-select');
|
|
340
|
+
};
|
|
341
|
+
const cancelPress = () => {
|
|
342
|
+
if (pressTimer) clearTimeout(pressTimer);
|
|
343
|
+
pressTimer = null;
|
|
344
|
+
restoreCallout();
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
el.addEventListener('pointerdown', (e) => {
|
|
348
|
+
if (e.pointerType !== 'touch' && e.pointerType !== 'pen') return;
|
|
349
|
+
cancelPress();
|
|
350
|
+
startX = e.clientX;
|
|
351
|
+
startY = e.clientY;
|
|
352
|
+
pressTarget = e.target;
|
|
353
|
+
suppressCallout();
|
|
354
|
+
pressTimer = setTimeout(() => {
|
|
355
|
+
pressTimer = null;
|
|
356
|
+
restoreCallout();
|
|
357
|
+
el.__mnfstLongPressOpenedAt = Date.now();
|
|
358
|
+
openContextMenuAt(pressTarget, startX, startY);
|
|
359
|
+
}, LONG_PRESS_MS);
|
|
360
|
+
});
|
|
361
|
+
el.addEventListener('pointermove', (e) => {
|
|
362
|
+
if (!pressTimer) return;
|
|
363
|
+
if (Math.abs(e.clientX - startX) > MOVE_SLOP_PX || Math.abs(e.clientY - startY) > MOVE_SLOP_PX) cancelPress();
|
|
364
|
+
});
|
|
365
|
+
el.addEventListener('pointerup', cancelPress);
|
|
366
|
+
el.addEventListener('pointercancel', cancelPress);
|
|
367
|
+
el.addEventListener('scroll', cancelPress, true);
|
|
368
|
+
|
|
369
|
+
// Suppress the synthetic click that follows the touch sequence which
|
|
370
|
+
// opened the menu, so it doesn't also activate/navigate the trigger.
|
|
371
|
+
el.addEventListener('click', (e) => {
|
|
372
|
+
if (el.__mnfstLongPressOpenedAt && Date.now() - el.__mnfstLongPressOpenedAt < LONG_PRESS_DUPE_WINDOW_MS) {
|
|
373
|
+
e.preventDefault();
|
|
374
|
+
e.stopPropagation();
|
|
375
|
+
}
|
|
376
|
+
}, true);
|
|
307
377
|
}
|
|
308
378
|
|
|
309
379
|
// Document-level dismiss listeners are global — bind once per
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest.appwrite.auth.js": "sha384-HMJmRXnvdDBWyuteXL+DTxWM2llSCdjl4EDamEI7iHNAVlqeOCE4GDTm8ZHipPRj",
|
|
3
|
-
"manifest.appwrite.data.js": "sha384-
|
|
3
|
+
"manifest.appwrite.data.js": "sha384-ZneCr1Vg7lAvz8wb8HipzJCF0KdZpPg2e3UK7kJdfECqcHbeXGfOJ9C8/rONj0Vg",
|
|
4
4
|
"manifest.appwrite.presences.js": "sha384-JyVDWFT69b7Svq8J8p9tNWe2v9PZNQBY5UyhtOl1vnuHFAX0CRQ3MA9SiKq5wzNh",
|
|
5
5
|
"manifest.bindings.js": "sha384-lPtMf8Ykaic9gNVZKq8Scia1881ZeMAyxer3WCIkUNwwrgzGBWto1OXADUwjvORF",
|
|
6
6
|
"manifest.charts.js": "sha384-WE0pnHK4LBAkFyTw4+R6gheB9NFVJg81ZAG9GwMnbKI5gY3zlJIKM5neMlBUhTso",
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
"manifest.color.js": "sha384-6Rv3LxyTcZNjrhtayQfqRdCx0uSZ4BiEbgEI98I62eTvp8Aw7LBIoNJ0Je1oktwL",
|
|
10
10
|
"manifest.colorpicker.js": "sha384-1+ZV5Hhjf7WnGP7b71Cqa5h3BKW8UgGT5V14i8Q+aF5zH8Xxwowt/ibSUVsiIHSm",
|
|
11
11
|
"manifest.combobox.js": "sha384-5DaKDWkWF7zxS80h7G1AcZG9hr+uGqJ1+B09aaVIVF+z0Qn4j8+9KEg7gys/ABQG",
|
|
12
|
-
"manifest.components.js": "sha384-
|
|
12
|
+
"manifest.components.js": "sha384-458gCDrUIZts3WE1WZ/UA8Y1XcV6PaF+5k3Wf/Jr2iIY5EM/FisjwbLzpON8I25s",
|
|
13
13
|
"manifest.computed.js": "sha384-GYML/e81gQfN+iDbqhPUgny8bINCyL+SrbTofoGk4hlCnLLjv51mCv42JMqq+ku5",
|
|
14
|
-
"manifest.data.js": "sha384-
|
|
14
|
+
"manifest.data.js": "sha384-iNF6nYPeG0TL3FTl0h2ZUN6oqwuDKiOGOTPPKV6+AImN74Dku3Y+zqC0qGQVv/QM",
|
|
15
15
|
"manifest.datepicker.js": "sha384-8vTJYkLqqvgXgm1w1becuaRR/jUEpiLBjBJ6RsRbUr+ZkypvspD6EsssuDrX4SQq",
|
|
16
16
|
"manifest.defer.js": "sha384-wXa60M2OHigi5rBurXQ7Oa8eyr5WTKs7EUn2GOru62KMdfs/LDyNegxCc9MNJFSe",
|
|
17
17
|
"manifest.device.js": "sha384-g+txmrEszYtuOvRelTp/c1wSNR2AtllVI9rx5NPPD7DzhVUnMNughonZykv2xlBW",
|
|
18
|
-
"manifest.dropdowns.js": "sha384-
|
|
18
|
+
"manifest.dropdowns.js": "sha384-LrPBmAx92pwcr68agp1wByt6ZjqlRyVygQiMbcOj0mbmnv3l/RgWwYhwhkgN/txC",
|
|
19
19
|
"manifest.edit.js": "sha384-oLsrH7/UkJ/KEl3UO77hexcf2rYCGgzXZd0fe2EMq3hKRE7aUqLiEnLJhSV7zTaY",
|
|
20
20
|
"manifest.export.js": "sha384-HCy3n6ifrcAGIyzTRgZ5JIRvSX9q9/8ykMKRSbt1QTnhXz6PgYlV0AE2N2Yi2re+",
|
|
21
21
|
"manifest.icons.js": "sha384-kKOINpX70YzNO3FvkV6umrmO3f0KIu0DNbwB+ej55a7y/lhU7v/myQtXL0bwCTbt",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"manifest.slides.js": "sha384-3uRTkyK9XPLmnxI2+igZlpi4EyPlU/7IHj5j3BZJJ2KN455vXyk99fiXV3feO/XY",
|
|
29
29
|
"manifest.status.js": "sha384-nwvUSbT+gpRMqhYx6MeBYswUMH72rY92mjgxv0vrSG7Ht7l83XYpEB6fCTbXjjfK",
|
|
30
30
|
"manifest.svg.js": "sha384-qr/8H9+2cIhSXNbRWRtIdrDlTOxKlNJqwEefHvCYoiBNW/kKhPTFa109Orv/EBnb",
|
|
31
|
-
"manifest.sw.js": "sha384-
|
|
31
|
+
"manifest.sw.js": "sha384-9PKF6DREUWpXcP6EXSjpcruKQqbMuZCo7hez8hGpBthPrIky6LOUscB0bdf9IB46",
|
|
32
32
|
"manifest.tabs.js": "sha384-OIIcyaQnGS0eNYk4zgAFEDboNYect7THvUd9D0V6nqCeDOxQcoiqLrBEmmWVTTet",
|
|
33
33
|
"manifest.tailwind.js": "sha384-r/Jvqb+Piz21jUts10BbVAJoKkShOdJRVFpywyi4HPIi/OfOJq5CtPyWAPbdkMgt",
|
|
34
34
|
"manifest.text.edit.js": "sha384-pfhc4IPKNJokj6ldlgD+KwGLN4UoM21CNeVf2sVq/34X1Un2PUhEuyTg5itmtsXS",
|
package/lib/manifest.sw.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
// Build stamps the published version here; unstamped (dev) falls back to the
|
|
18
18
|
// registration URL's `v`, then 'dev'.
|
|
19
|
-
const BUILD_VERSION = '0.5.
|
|
19
|
+
const BUILD_VERSION = '0.5.211';
|
|
20
20
|
const CACHE_PREFIX = 'mnfst-sw:';
|
|
21
21
|
const META_CACHE = CACHE_PREFIX + 'meta';
|
|
22
22
|
const SWR_CAP = 200;
|