mnfst 0.5.208 → 0.5.210
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/lib/manifest.charts.js
CHANGED
|
@@ -124,6 +124,11 @@
|
|
|
124
124
|
const _registry = Alpine.reactive ? Alpine.reactive({}) : {};
|
|
125
125
|
let _uid = 0;
|
|
126
126
|
|
|
127
|
+
const isDevelopment = window.location.hostname === 'localhost' ||
|
|
128
|
+
window.location.hostname === '127.0.0.1' ||
|
|
129
|
+
window.location.hostname.includes('dev') ||
|
|
130
|
+
window.location.search.includes('debug=true');
|
|
131
|
+
|
|
127
132
|
const _nullApi = { type: '', series: [], update() { }, redraw() { }, toString() { return ''; }, valueOf() { return ''; } };
|
|
128
133
|
|
|
129
134
|
function findAncestorState(el) { let n = el; while (n) { if (n._chartState) return n._chartState; n = n.parentElement; } return null; }
|
|
@@ -228,6 +233,30 @@
|
|
|
228
233
|
return cfg;
|
|
229
234
|
}
|
|
230
235
|
|
|
236
|
+
// Deterministic structural signature of a normalized config, for the redraw
|
|
237
|
+
// short-circuit below: sorted object keys (key order doesn't matter), arrays
|
|
238
|
+
// keep position, Dates by epoch ms, typed arrays by value. Functions are
|
|
239
|
+
// omitted — identity isn't a meaningful "value" for a config comparison and
|
|
240
|
+
// authors sometimes pass fresh closures that are behaviorally identical.
|
|
241
|
+
function stableStringify(v, seen) {
|
|
242
|
+
if (v === null || typeof v !== 'object') return typeof v === 'function' ? undefined : JSON.stringify(v);
|
|
243
|
+
if (v instanceof Date) return String(v.getTime());
|
|
244
|
+
if (ArrayBuffer.isView(v)) return '[' + Array.prototype.join.call(v, ',') + ']';
|
|
245
|
+
seen = seen || new Set();
|
|
246
|
+
if (seen.has(v)) return '"[Circular]"'; // config is author data; don't trust it's acyclic
|
|
247
|
+
seen.add(v);
|
|
248
|
+
let out;
|
|
249
|
+
if (Array.isArray(v)) {
|
|
250
|
+
out = '[' + v.map(x => { const s = stableStringify(x, seen); return s === undefined ? 'null' : s; }).join(',') + ']';
|
|
251
|
+
} else {
|
|
252
|
+
const parts = [];
|
|
253
|
+
Object.keys(v).sort().forEach(k => { const s = stableStringify(v[k], seen); if (s !== undefined) parts.push(JSON.stringify(k) + ':' + s); });
|
|
254
|
+
out = '{' + parts.join(',') + '}';
|
|
255
|
+
}
|
|
256
|
+
seen.delete(v);
|
|
257
|
+
return out;
|
|
258
|
+
}
|
|
259
|
+
|
|
231
260
|
/* ---- SVG helpers -------------------------------------------- */
|
|
232
261
|
function svg(tag, attrs, parent) {
|
|
233
262
|
const node = document.createElementNS(SVGNS, tag);
|
|
@@ -287,7 +316,7 @@
|
|
|
287
316
|
return {
|
|
288
317
|
get type() { return self.config ? self.config.type : ''; },
|
|
289
318
|
get series() { return self.config ? self.config.series : []; },
|
|
290
|
-
update(cfg) { self.
|
|
319
|
+
update(cfg) { if (self.applyConfig(normalize(cfg, self.el, self.typeFromModifier))) self.draw(); },
|
|
291
320
|
redraw() { self.draw(); },
|
|
292
321
|
toString() { return self.config ? self.config.type : ''; }
|
|
293
322
|
};
|
|
@@ -306,10 +335,17 @@
|
|
|
306
335
|
Alpine.effect(() => {
|
|
307
336
|
// Subscribe to the data store heartbeat so $x loads/locale reloads re-run.
|
|
308
337
|
try { void Alpine.store('data')?._dataVersion; } catch (_) { }
|
|
309
|
-
|
|
310
|
-
|
|
338
|
+
// Every effect fire re-evaluates the expression (it may read live reactive
|
|
339
|
+
// state — realtime rows, presence, staged $x hydration — that changes far
|
|
340
|
+
// more often than the resulting config). applyConfig() short-circuits a
|
|
341
|
+
// schedule() when the normalized result is value-identical to last time;
|
|
342
|
+
// the first call always applies (self._sig starts undefined).
|
|
343
|
+
if (getCfg) getCfg(raw => { if (self.applyConfig(normalize(raw, self.el, self.typeFromModifier))) self.schedule(); });
|
|
344
|
+
else if (self.applyConfig(normalize(configFromDom(self.el), self.el, self.typeFromModifier))) self.schedule();
|
|
311
345
|
});
|
|
312
|
-
// Re-render on locale (axis number/date formatting) and container resize
|
|
346
|
+
// Re-render on locale (axis number/date formatting) and container resize —
|
|
347
|
+
// these change rendering without changing the config, so they bypass the
|
|
348
|
+
// signature check and always schedule.
|
|
313
349
|
self._onLocale = () => self.schedule();
|
|
314
350
|
window.addEventListener('localechange', self._onLocale);
|
|
315
351
|
self._ro = new ResizeObserver(() => self.schedule());
|
|
@@ -317,9 +353,35 @@
|
|
|
317
353
|
if (self.el.id) _registry[self.el.id] = self.api;
|
|
318
354
|
},
|
|
319
355
|
|
|
356
|
+
// Applies a normalized config, returning whether it actually changed (by
|
|
357
|
+
// structural signature, not reference) — see stableStringify. Always
|
|
358
|
+
// "changes" the first time (this._sig starts undefined) so the first draw
|
|
359
|
+
// is unconditional.
|
|
360
|
+
applyConfig(next) {
|
|
361
|
+
const sig = stableStringify(next);
|
|
362
|
+
const changed = this._sig === undefined || sig !== this._sig;
|
|
363
|
+
if (changed) { this._sig = sig; this.config = next; }
|
|
364
|
+
return changed;
|
|
365
|
+
},
|
|
366
|
+
|
|
320
367
|
// One draw per tick. setTimeout (not rAF) so backgrounded tabs still draw;
|
|
321
368
|
// doesn't reset a pending timer, so a high-frequency trigger can't starve it.
|
|
322
|
-
schedule() {
|
|
369
|
+
schedule() {
|
|
370
|
+
if (this._t) return;
|
|
371
|
+
// Runaway-redraw guard: a chart that schedules dozens of times a second
|
|
372
|
+
// (usually a config-signature miss, or a map's heavy geometry rebuild —
|
|
373
|
+
// see drawMap) pegs the main thread and shows up to the user as a hung
|
|
374
|
+
// tab, not a chart bug. Warn once per element so it's self-diagnosing.
|
|
375
|
+
if (isDevelopment && !this._warnedRedraw) {
|
|
376
|
+
const now = Date.now();
|
|
377
|
+
if (!this._scheduleWindowStart || now - this._scheduleWindowStart > 1000) { this._scheduleWindowStart = now; this._scheduleWindowCount = 0; }
|
|
378
|
+
if (++this._scheduleWindowCount > 20) {
|
|
379
|
+
this._warnedRedraw = true;
|
|
380
|
+
try { console.warn('[Manifest Charts] "' + (this.el.id || this.expression || 'chart') + '" redrew ' + this._scheduleWindowCount + '+ times within one second — likely a reactive dependency changing on every read (or, for a map, a legitimately busy data feed hitting its per-draw geometry cost).'); } catch (_) { }
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
this._t = setTimeout(() => { this._t = null; this.draw(); }, 0);
|
|
384
|
+
},
|
|
323
385
|
|
|
324
386
|
renderError(msg) { this.el.innerHTML = ''; const d = document.createElement('small'); d.textContent = msg; this.el.appendChild(d); },
|
|
325
387
|
|
|
@@ -921,9 +983,18 @@
|
|
|
921
983
|
// (numeric values → heat ramp) or categorically (string values → palette).
|
|
922
984
|
function drawMap(state, root, width, height, geo) {
|
|
923
985
|
const cfg = state.config;
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
986
|
+
// The feature collection, fitted projection, and path generator depend only
|
|
987
|
+
// on the atlas (`geo`) and the element's [width, height] — not on cfg.data —
|
|
988
|
+
// so a data-only redraw (the common case: realtime values ticking in) reuses
|
|
989
|
+
// them instead of re-running topojson.feature/fitSize over ~175 polygons.
|
|
990
|
+
// Cached per element, invalidated when the atlas or size changes.
|
|
991
|
+
let geom = state._mapGeom;
|
|
992
|
+
if (!geom || geom.geo !== geo || geom.width !== width || geom.height !== height) {
|
|
993
|
+
const fc = geo.topojson.feature(geo.world, geo.world.objects.countries);
|
|
994
|
+
const projection = geo.geoNaturalEarth1().fitSize([width, height], fc);
|
|
995
|
+
geom = state._mapGeom = { geo, width, height, fc, projection, path: geo.geoPath(projection) };
|
|
996
|
+
}
|
|
997
|
+
const { fc, projection, path } = geom;
|
|
927
998
|
|
|
928
999
|
// Author data: an object { key: value } or an array of { id|code|name, value } / [key, value].
|
|
929
1000
|
let entries = [];
|
package/lib/manifest.combobox.js
CHANGED
|
@@ -168,8 +168,41 @@ function initializeComboboxPlugin() {
|
|
|
168
168
|
setTimeout(() => build(el, modifiers, expression || '', cleanup), 0);
|
|
169
169
|
});
|
|
170
170
|
|
|
171
|
+
// Resolve the menu's owning top-layer context fresh, every time — never cache it.
|
|
172
|
+
// A [popover]/dialog ancestor can be mid-restash (manifest.defer's idle prewarm/evict
|
|
173
|
+
// cycle moving a still-closed container's subtree back into its <template> stash)
|
|
174
|
+
// at any point after build(), so the target must be re-read at each attach, not
|
|
175
|
+
// assumed stable from build time.
|
|
176
|
+
// The menu belongs in its field's top-layer context, but that ancestor can be
|
|
177
|
+
// mid-restash (defer moving a closed container's subtree back into its <template>),
|
|
178
|
+
// so re-resolve at every attach — and never attach into a detached tree, or
|
|
179
|
+
// showPopover() throws InvalidStateError and leaves the field dead.
|
|
180
|
+
let warnedDetached = false;
|
|
181
|
+
const attachTarget = (el) => {
|
|
182
|
+
const owner = el.closest('[popover]');
|
|
183
|
+
if (owner && owner.isConnected) return owner;
|
|
184
|
+
if (owner && !warnedDetached) {
|
|
185
|
+
warnedDetached = true;
|
|
186
|
+
console.warn('[Manifest Combobox] the field\'s popover ancestor was detached when its menu was attached; ' +
|
|
187
|
+
'using document.body so the field keeps working. Please report this with the field id:', el.id || el);
|
|
188
|
+
}
|
|
189
|
+
return document.body;
|
|
190
|
+
};
|
|
191
|
+
const reattach = (el, menu) => {
|
|
192
|
+
const target = attachTarget(el);
|
|
193
|
+
if (menu.parentNode !== target) target.appendChild(menu);
|
|
194
|
+
};
|
|
195
|
+
|
|
171
196
|
function build(el, modifiers, expression, cleanup) {
|
|
172
|
-
if (el.__mnfstCombobox)
|
|
197
|
+
if (el.__mnfstCombobox) {
|
|
198
|
+
// Already built. If manifest.defer's idle prewarm/evict cycle raced this very
|
|
199
|
+
// build (stashing the owning [popover] between directive init and the setTimeout
|
|
200
|
+
// below), the generated menu was appended into a since-detached tree — reattach
|
|
201
|
+
// it into wherever the owner lives now. Harmless no-op otherwise.
|
|
202
|
+
const m = el.__mnfstComboboxMenu;
|
|
203
|
+
if (m) reattach(el, m);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
173
206
|
el.__mnfstCombobox = true;
|
|
174
207
|
|
|
175
208
|
// If a mount path bypassed the strip (x-if/x-for via Alpine's internal initTree)
|
|
@@ -409,8 +442,10 @@ function initializeComboboxPlugin() {
|
|
|
409
442
|
}
|
|
410
443
|
// Nearest popover host, so an outer auto popover isn't light-dismissed
|
|
411
444
|
// by listbox clicks; body otherwise (out of overflow contexts either way).
|
|
412
|
-
(
|
|
445
|
+
// Re-resolved (not just attached once) at every open — see reattach().
|
|
446
|
+
reattach(el, menu);
|
|
413
447
|
generatedMenu = menu; // tracked so cleanup() can remove it on re-render
|
|
448
|
+
el.__mnfstComboboxMenu = menu; // tracked so a re-entrant build() can reattach it
|
|
414
449
|
if (src) src.style.setProperty('display', 'none', 'important');
|
|
415
450
|
menu.setAttribute('popover', 'manual');
|
|
416
451
|
menu.setAttribute('x-defer.off', ''); // options are built here, not by directives
|
|
@@ -459,8 +494,22 @@ function initializeComboboxPlugin() {
|
|
|
459
494
|
if (!menu || menu.matches(':popover-open') || atCap()) return;
|
|
460
495
|
// Re-stashed since build (x-defer.discard) — re-hydrate before showing.
|
|
461
496
|
if (src && window.ManifestDefer?.isPending(src)) { options = readOptions(src); setOptions(options); }
|
|
497
|
+
// Lazy re-resolve: the owning [popover]/dialog may have been (re-)stashed and
|
|
498
|
+
// rendered since build(), or build() itself raced a defer restash and attached
|
|
499
|
+
// into a tree that's since gone disconnected. A real open only ever happens
|
|
500
|
+
// once the field itself is genuinely connected/visible, so this always has a
|
|
501
|
+
// valid target.
|
|
502
|
+
reattach(el, menu);
|
|
462
503
|
menu.style.minWidth = wrap.offsetWidth + 'px';
|
|
463
|
-
|
|
504
|
+
try {
|
|
505
|
+
menu.showPopover();
|
|
506
|
+
} catch (_) {
|
|
507
|
+
// Belt-and-suspenders: resolve once more and retry, then give up quietly —
|
|
508
|
+
// an uncaught error here would abort whatever handler called openMenu() and
|
|
509
|
+
// can strand the containing dialog's own dismiss handling mid-flight.
|
|
510
|
+
reattach(el, menu);
|
|
511
|
+
try { menu.showPopover(); } catch (_) { return; }
|
|
512
|
+
}
|
|
464
513
|
el.setAttribute('aria-expanded', 'true');
|
|
465
514
|
}
|
|
466
515
|
function closeMenu() {
|
package/lib/manifest.data.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest.appwrite.auth.js": "sha384-HMJmRXnvdDBWyuteXL+DTxWM2llSCdjl4EDamEI7iHNAVlqeOCE4GDTm8ZHipPRj",
|
|
3
|
-
"manifest.appwrite.data.js": "sha384-
|
|
3
|
+
"manifest.appwrite.data.js": "sha384-kmsw1sYLqTxnkRfh7dt0urLSFU+LOkgHofsL1jYGndFvCizo7wsbQix6vV022/ov",
|
|
4
4
|
"manifest.appwrite.presences.js": "sha384-JyVDWFT69b7Svq8J8p9tNWe2v9PZNQBY5UyhtOl1vnuHFAX0CRQ3MA9SiKq5wzNh",
|
|
5
5
|
"manifest.bindings.js": "sha384-lPtMf8Ykaic9gNVZKq8Scia1881ZeMAyxer3WCIkUNwwrgzGBWto1OXADUwjvORF",
|
|
6
|
-
"manifest.charts.js": "sha384-
|
|
6
|
+
"manifest.charts.js": "sha384-WE0pnHK4LBAkFyTw4+R6gheB9NFVJg81ZAG9GwMnbKI5gY3zlJIKM5neMlBUhTso",
|
|
7
7
|
"manifest.chat.js": "sha384-88DfMfJLoi2oxclVD2iIMDkIGAExMXq5k47mekUredlicLaP3oZY5bwtwqs+TqDF",
|
|
8
8
|
"manifest.code.js": "sha384-aoQ4E26vrhNe/+tL7K0h90c8/0ies7e8oIR6Ay92he2X3dnWZ+OPcn2Dna8fmc+c",
|
|
9
9
|
"manifest.color.js": "sha384-6Rv3LxyTcZNjrhtayQfqRdCx0uSZ4BiEbgEI98I62eTvp8Aw7LBIoNJ0Je1oktwL",
|
|
10
10
|
"manifest.colorpicker.js": "sha384-1+ZV5Hhjf7WnGP7b71Cqa5h3BKW8UgGT5V14i8Q+aF5zH8Xxwowt/ibSUVsiIHSm",
|
|
11
|
-
"manifest.combobox.js": "sha384-
|
|
11
|
+
"manifest.combobox.js": "sha384-5DaKDWkWF7zxS80h7G1AcZG9hr+uGqJ1+B09aaVIVF+z0Qn4j8+9KEg7gys/ABQG",
|
|
12
12
|
"manifest.components.js": "sha384-DLGSqCbnGkS87AWJ8GpKoAFP4nCosgC5SFSg6C10hH/nWu/MxI+0ntHlnFEfs++u",
|
|
13
13
|
"manifest.computed.js": "sha384-GYML/e81gQfN+iDbqhPUgny8bINCyL+SrbTofoGk4hlCnLLjv51mCv42JMqq+ku5",
|
|
14
|
-
"manifest.data.js": "sha384-
|
|
14
|
+
"manifest.data.js": "sha384-U4/sSXZI/DL0X7ymE9KrwAKhIv31pJoEo0YnZBgJTAhHYwUZxhaC7nrhWVj/5a/q",
|
|
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",
|
|
@@ -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-uUl8PEc1B0HXLOMpjQqF0w+4ybSeyHAAOSXmWQkHH4eO7ZiyU43yIlnEWKpsXlgb",
|
|
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.210';
|
|
20
20
|
const CACHE_PREFIX = 'mnfst-sw:';
|
|
21
21
|
const META_CACHE = CACHE_PREFIX + 'meta';
|
|
22
22
|
const SWR_CAP = 200;
|