mnfst 0.5.163 → 0.5.165
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.appwrite.auth.js +107 -199
- package/lib/manifest.appwrite.data.js +1 -3
- package/lib/manifest.appwrite.presences.js +292 -0
- package/lib/manifest.charts.js +34 -79
- package/lib/manifest.chat.js +515 -0
- package/lib/manifest.code.js +110 -340
- package/lib/manifest.colorpicker.js +252 -551
- package/lib/manifest.combobox.js +73 -91
- package/lib/manifest.components.js +34 -95
- package/lib/manifest.css +0 -132
- package/lib/manifest.data.js +189 -562
- package/lib/manifest.datepicker.js +43 -128
- package/lib/manifest.dropdowns.js +18 -39
- package/lib/manifest.export.js +29 -147
- package/lib/manifest.icons.js +9 -24
- package/lib/manifest.integrity.json +24 -23
- package/lib/manifest.js +65 -129
- package/lib/manifest.localization.js +67 -200
- package/lib/manifest.markdown.js +65 -174
- package/lib/manifest.min.css +1 -1
- package/lib/manifest.payments.js +40 -139
- package/lib/manifest.router.js +24 -73
- package/lib/manifest.status.js +20 -56
- package/lib/manifest.svg.js +12 -30
- package/lib/manifest.tooltips.js +28 -65
- package/lib/manifest.utilities.js +40 -107
- package/lib/manifest.virtual.js +15 -53
- package/package.json +1 -1
- package/lib/manifest.appwrite.presence.js +0 -1650
package/lib/manifest.js
CHANGED
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
/* By Andrew Matlock under MIT license
|
|
3
3
|
/* https://manifestx.dev
|
|
4
4
|
/*
|
|
5
|
-
/*
|
|
6
|
-
/*
|
|
7
|
-
/*
|
|
8
|
-
/* Some plugins use Manifest CSS styles.
|
|
5
|
+
/* Loader: pulls Alpine.js and Manifest plugins from the jsDelivr CDN — all
|
|
6
|
+
/* plugins by default, or a subset if specified.
|
|
9
7
|
*/
|
|
10
8
|
|
|
11
9
|
(function () {
|
|
@@ -14,23 +12,16 @@
|
|
|
14
12
|
/*
|
|
15
13
|
* Hydration contract runtime
|
|
16
14
|
* --------------------------
|
|
17
|
-
* Prerendered MPA pages carry a
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* it walks the contract, restores source state, and removes its own
|
|
23
|
-
* markers. Every downstream plugin (colors, router, data, markdown,
|
|
24
|
-
* icons, …) then sees exactly the DOM the user authored, exactly as it
|
|
25
|
-
* would in a live SPA. No plugin needs a "prerender mode" branch.
|
|
15
|
+
* Prerendered MPA pages carry a `#__manifest_hydrate__` JSON blob of the
|
|
16
|
+
* source-authored attributes (and, for `data-hydrate` subtrees, innerHTML)
|
|
17
|
+
* of each element needing hydration. Runs once BEFORE any plugin or Alpine
|
|
18
|
+
* so every downstream plugin sees the authored DOM, as in a live SPA — no
|
|
19
|
+
* plugin needs a "prerender mode" branch.
|
|
26
20
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* - The contract is a compact diff: only attributes whose values drifted
|
|
32
|
-
* from source during prerender appear. An entry's `attrs` object maps
|
|
33
|
-
* attribute name -> source value, or null to mean "remove".
|
|
21
|
+
* - Attributes are set via a temp-div HTML parse, not setAttribute, which
|
|
22
|
+
* throws on Alpine special names like `@click`; the parser accepts them.
|
|
23
|
+
* - The contract is a compact diff: `attrs` maps name -> source value, or
|
|
24
|
+
* null to remove; only values that drifted during prerender appear.
|
|
34
25
|
*/
|
|
35
26
|
function hydratePrerenderedPage() {
|
|
36
27
|
if (typeof document === 'undefined' || !document.querySelector) return;
|
|
@@ -55,9 +46,7 @@
|
|
|
55
46
|
.replace(/"/g, '"');
|
|
56
47
|
const voidEls = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
|
|
57
48
|
|
|
58
|
-
//
|
|
59
|
-
// its children have already been restored and their source state is what
|
|
60
|
-
// the ancestor captures.
|
|
49
|
+
// Deepest-first: a rebuilt ancestor then captures already-restored children.
|
|
61
50
|
const items = [];
|
|
62
51
|
for (const entry of entries) {
|
|
63
52
|
const el = document.querySelector('[data-hydrate-id="' + entry.id + '"]');
|
|
@@ -72,13 +61,12 @@
|
|
|
72
61
|
const el = document.querySelector('[data-hydrate-id="' + entry.id + '"]') || initialEl;
|
|
73
62
|
if (!el || !el.parentNode) continue;
|
|
74
63
|
|
|
75
|
-
// Case 1: explicit subtree restoration (entry.html present)
|
|
76
|
-
//
|
|
77
|
-
// entire subtree mirrors the authored source.
|
|
64
|
+
// Case 1: explicit subtree restoration (entry.html present) —
|
|
65
|
+
// rebuild via outerHTML so the whole subtree mirrors source.
|
|
78
66
|
if (typeof entry.html === 'string') {
|
|
79
67
|
const tag = el.tagName.toLowerCase();
|
|
80
68
|
const finalAttrs = {};
|
|
81
|
-
//
|
|
69
|
+
// Current attrs, then the contract diff.
|
|
82
70
|
const cur = el.attributes;
|
|
83
71
|
for (let i = 0; i < cur.length; i++) {
|
|
84
72
|
if (cur[i].name !== 'data-hydrate-id') finalAttrs[cur[i].name] = cur[i].value;
|
|
@@ -106,9 +94,8 @@
|
|
|
106
94
|
continue;
|
|
107
95
|
}
|
|
108
96
|
|
|
109
|
-
// Case 2: attribute-only diff.
|
|
110
|
-
//
|
|
111
|
-
// special-name attributes like @click work. Preserve innerHTML.
|
|
97
|
+
// Case 2: attribute-only diff. Reparse with merged attrs (so
|
|
98
|
+
// special names like @click work); innerHTML preserved.
|
|
112
99
|
if (!entry.attrs) continue;
|
|
113
100
|
const tag = el.tagName.toLowerCase();
|
|
114
101
|
const finalAttrs = {};
|
|
@@ -141,25 +128,19 @@
|
|
|
141
128
|
}
|
|
142
129
|
|
|
143
130
|
/*
|
|
144
|
-
* Reconcile baked x-for/x-if clones the prerender kept for crawlers.
|
|
145
|
-
* <template> is still live, so
|
|
146
|
-
* copy on boot (a duplicate). data-hydrate islands keep their baked DOM.
|
|
131
|
+
* Reconcile baked x-for/x-if clones the prerender kept for crawlers. Their
|
|
132
|
+
* <template> is still live, so Alpine would render a duplicate on boot.
|
|
147
133
|
*
|
|
148
|
-
* - x-if clones are ADOPTED:
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
* x-
|
|
152
|
-
* and re-rendered — flashing raw text and re-fetching $x data — even
|
|
153
|
-
* though the prerendered output is already correct. A genuine
|
|
134
|
+
* - x-if clones are ADOPTED: point the template's `_x_currentIfEl` at the
|
|
135
|
+
* baked element so Alpine treats the condition as already-rendered and
|
|
136
|
+
* leaves it in place — avoids tearing down heavy content (e.g. an
|
|
137
|
+
* x-markdown article) only to re-render identical output. A real
|
|
154
138
|
* route/condition change later still re-renders normally.
|
|
155
|
-
* - x-for clones are REMOVED: lists are light
|
|
156
|
-
*
|
|
157
|
-
* dropped to avoid a duplicate.
|
|
139
|
+
* - x-for clones are REMOVED: lists are light and re-render from the live
|
|
140
|
+
* template, so the baked copies are dropped to avoid a duplicate.
|
|
158
141
|
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* executed but BEFORE it walks the DOM. If Alpine never arrives (CDN
|
|
162
|
-
* failure, offline), the listener never fires and the page keeps its
|
|
142
|
+
* Runs on `alpine:init` (after Alpine's script, before it walks the DOM),
|
|
143
|
+
* not in hydratePrerenderedPage: if Alpine never arrives the page keeps its
|
|
163
144
|
* complete baked content.
|
|
164
145
|
*/
|
|
165
146
|
function reconcilePrerenderClones() {
|
|
@@ -169,8 +150,7 @@
|
|
|
169
150
|
el.removeAttribute('data-mnfst-prerender-clone');
|
|
170
151
|
const tpl = el.previousElementSibling;
|
|
171
152
|
if (tpl && tpl.tagName === 'TEMPLATE' && tpl.hasAttribute('x-if')) {
|
|
172
|
-
//
|
|
173
|
-
// is set, so the baked element stays and is not re-rendered.
|
|
153
|
+
// Alpine's x-if show() returns early when _x_currentIfEl is set.
|
|
174
154
|
tpl._x_currentIfEl = el;
|
|
175
155
|
} else {
|
|
176
156
|
el.remove();
|
|
@@ -181,25 +161,18 @@
|
|
|
181
161
|
document.addEventListener('alpine:init', reconcilePrerenderClones, { once: true });
|
|
182
162
|
}
|
|
183
163
|
|
|
184
|
-
// Run hydration BEFORE Alpine's deferred script executes
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
//
|
|
188
|
-
//
|
|
189
|
-
// our `replaceChild`-based restore would destroy the Alpine-bound nodes.
|
|
190
|
-
//
|
|
191
|
-
// The only earlier hook is `readystatechange → 'interactive'`, which is
|
|
192
|
-
// dispatched the moment the parser finishes and BEFORE deferred scripts run.
|
|
193
|
-
// We also run synchronously if readyState is already 'interactive' or later
|
|
194
|
-
// (e.g. if manifest.js was injected dynamically after page load).
|
|
164
|
+
// Run hydration BEFORE Alpine's deferred script executes: DOMContentLoaded
|
|
165
|
+
// is too late (Alpine has already bound the nodes our replaceChild would
|
|
166
|
+
// destroy). The earlier `readystatechange → 'interactive'` fires the moment
|
|
167
|
+
// parsing finishes, before deferred scripts. Run synchronously if already
|
|
168
|
+
// past 'loading' (e.g. manifest.js injected after load).
|
|
195
169
|
function tryHydrate() {
|
|
196
170
|
try { hydratePrerenderedPage(); } catch (e) { /* graceful */ }
|
|
197
171
|
}
|
|
198
172
|
if (typeof document !== 'undefined') {
|
|
199
173
|
if (document.readyState === 'loading') {
|
|
200
|
-
//
|
|
201
|
-
//
|
|
202
|
-
// but deferred scripts haven't run yet.
|
|
174
|
+
// Still parsing: 'interactive' is the earliest hook where body exists
|
|
175
|
+
// but deferred scripts haven't run.
|
|
203
176
|
let hydrated = false;
|
|
204
177
|
document.addEventListener('readystatechange', () => {
|
|
205
178
|
if (!hydrated && document.readyState !== 'loading') {
|
|
@@ -208,7 +181,7 @@
|
|
|
208
181
|
}
|
|
209
182
|
});
|
|
210
183
|
} else {
|
|
211
|
-
// Parser already done
|
|
184
|
+
// Parser already done — hydrate immediately.
|
|
212
185
|
tryHydrate();
|
|
213
186
|
}
|
|
214
187
|
}
|
|
@@ -268,13 +241,13 @@
|
|
|
268
241
|
const APPWRITE_PLUGINS = [
|
|
269
242
|
'appwrite-auth',
|
|
270
243
|
'appwrite-data',
|
|
271
|
-
'appwrite-
|
|
244
|
+
'appwrite-presences'
|
|
272
245
|
];
|
|
273
246
|
|
|
274
247
|
// Plugin dependencies: plugins that require other plugins to be loaded first
|
|
275
248
|
const PLUGIN_DEPENDENCIES = {
|
|
276
249
|
'appwrite-data': ['data'],
|
|
277
|
-
'appwrite-
|
|
250
|
+
'appwrite-presences': ['data', 'appwrite-auth']
|
|
278
251
|
};
|
|
279
252
|
|
|
280
253
|
// Derive default plugin list from manifest (only load data/localization/components when manifest needs them)
|
|
@@ -306,16 +279,12 @@
|
|
|
306
279
|
});
|
|
307
280
|
}
|
|
308
281
|
|
|
309
|
-
//
|
|
310
|
-
//
|
|
311
|
-
// absolute URL), plugins are loaded from that base as unminified `.js`
|
|
312
|
-
// files. Otherwise they come from the jsDelivr CDN as `.min.js`.
|
|
282
|
+
// Plugin URL: `data-plugin-base` override → unminified `.js`; else the
|
|
283
|
+
// jsDelivr CDN as `.min.js`.
|
|
313
284
|
let _pluginBase = null;
|
|
314
285
|
function setPluginBase(b) { _pluginBase = b || null; }
|
|
315
286
|
function getPluginUrl(pluginName, version = DEFAULT_VERSION) {
|
|
316
|
-
//
|
|
317
|
-
// `appwrite-auth` → `manifest.appwrite.auth.js`
|
|
318
|
-
// `url-parameters` → `manifest.url.parameters.js`
|
|
287
|
+
// Hyphenated API name → dotted file name (`appwrite-auth` → appwrite.auth).
|
|
319
288
|
const fileName = pluginName.replace(/-/g, '.');
|
|
320
289
|
if (_pluginBase) {
|
|
321
290
|
const base = _pluginBase.replace(/\/$/, '');
|
|
@@ -332,10 +301,8 @@
|
|
|
332
301
|
return `https://cdn.jsdelivr.net/npm/alpinejs@${dataAlpine}/dist/cdn.min.js`;
|
|
333
302
|
}
|
|
334
303
|
|
|
335
|
-
// Has DOMContentLoaded
|
|
336
|
-
//
|
|
337
|
-
// and "DCL done, subresources still loading". Disambiguate via the
|
|
338
|
-
// navigation timing entry, which records the event the moment it runs.
|
|
304
|
+
// Has DOMContentLoaded fired? readyState can't tell ('interactive' spans
|
|
305
|
+
// both DCL-pending and DCL-done); the navigation timing entry disambiguates.
|
|
339
306
|
function domContentLoadedFired() {
|
|
340
307
|
if (document.readyState === 'complete') return true;
|
|
341
308
|
if (document.readyState === 'loading') return false;
|
|
@@ -346,9 +313,8 @@
|
|
|
346
313
|
return false;
|
|
347
314
|
}
|
|
348
315
|
|
|
349
|
-
// Run fn
|
|
350
|
-
//
|
|
351
|
-
// braces fallback for environments where the navigation entry is missing.
|
|
316
|
+
// Run fn at or after DOMContentLoaded; 'load' is a fallback when the
|
|
317
|
+
// navigation entry is missing.
|
|
352
318
|
function whenDomReady(fn) {
|
|
353
319
|
if (domContentLoadedFired()) {
|
|
354
320
|
fn();
|
|
@@ -360,28 +326,18 @@
|
|
|
360
326
|
window.addEventListener('load', run, { once: true });
|
|
361
327
|
}
|
|
362
328
|
|
|
363
|
-
// Load Alpine
|
|
364
|
-
//
|
|
365
|
-
//
|
|
366
|
-
//
|
|
367
|
-
//
|
|
368
|
-
// spins the event loop while a script is still in flight — so on a warm
|
|
369
|
-
// cache an injected Alpine script can load and EXECUTE between two
|
|
370
|
-
// deferred scripts, firing `alpine:init` before the page's registrations
|
|
371
|
-
// exist. Waiting for DCL (which fires only after every deferred script
|
|
372
|
-
// has run) makes the ordering deterministic. In the common cold-cache
|
|
373
|
-
// case DCL has long passed by the time the plugin loads settle, so the
|
|
374
|
-
// gate adds no delay.
|
|
329
|
+
// Load Alpine, called after all plugins have registered. Gated on DCL: a
|
|
330
|
+
// warm-cache Alpine could otherwise execute between two deferred scripts and
|
|
331
|
+
// fire `alpine:init` before the page's registrations exist. DCL fires only
|
|
332
|
+
// after every deferred script runs, making the order deterministic (and cold
|
|
333
|
+
// cache is already past DCL, so no added delay).
|
|
375
334
|
function loadAlpine(alpineUrl = ALPINE_CDN_URL) {
|
|
376
335
|
whenDomReady(() => {
|
|
377
|
-
// Fast check: Alpine already initialized
|
|
378
336
|
if (window.Alpine) {
|
|
379
337
|
return;
|
|
380
338
|
}
|
|
381
339
|
|
|
382
|
-
//
|
|
383
|
-
// (e.g. the fixture explicitly added one), wait for it — don't inject
|
|
384
|
-
// a second copy.
|
|
340
|
+
// Don't inject a second copy if an Alpine <script> is already present.
|
|
385
341
|
const existingAlpine = document.querySelector('script[src*="alpinejs"]');
|
|
386
342
|
if (existingAlpine) {
|
|
387
343
|
return;
|
|
@@ -389,8 +345,7 @@
|
|
|
389
345
|
|
|
390
346
|
const script = document.createElement('script');
|
|
391
347
|
script.src = alpineUrl;
|
|
392
|
-
// No `defer` —
|
|
393
|
-
// Alpine should load and execute as soon as it arrives.
|
|
348
|
+
// No `defer` — past DCL, so execute as soon as it arrives.
|
|
394
349
|
document.head.appendChild(script);
|
|
395
350
|
});
|
|
396
351
|
}
|
|
@@ -423,11 +378,9 @@
|
|
|
423
378
|
const resolved = [];
|
|
424
379
|
const added = new Set();
|
|
425
380
|
|
|
426
|
-
// Helper to add a plugin and its dependencies in correct order
|
|
427
381
|
function addPluginWithDeps(plugin) {
|
|
428
382
|
if (added.has(plugin)) return;
|
|
429
383
|
|
|
430
|
-
// First, add all dependencies
|
|
431
384
|
const deps = PLUGIN_DEPENDENCIES[plugin];
|
|
432
385
|
if (deps) {
|
|
433
386
|
for (const dep of deps) {
|
|
@@ -437,12 +390,10 @@
|
|
|
437
390
|
}
|
|
438
391
|
}
|
|
439
392
|
|
|
440
|
-
// Then add the plugin itself
|
|
441
393
|
resolved.push(plugin);
|
|
442
394
|
added.add(plugin);
|
|
443
395
|
}
|
|
444
396
|
|
|
445
|
-
// Process all plugins in order, ensuring dependencies come first
|
|
446
397
|
for (const plugin of pluginList) {
|
|
447
398
|
addPluginWithDeps(plugin);
|
|
448
399
|
}
|
|
@@ -470,8 +421,8 @@
|
|
|
470
421
|
))) {
|
|
471
422
|
plugins.push('appwrite-data');
|
|
472
423
|
}
|
|
473
|
-
if (manifest.
|
|
474
|
-
plugins.push('appwrite-
|
|
424
|
+
if (manifest.appwrite?.presence) {
|
|
425
|
+
plugins.push('appwrite-presences');
|
|
475
426
|
}
|
|
476
427
|
return plugins;
|
|
477
428
|
}
|
|
@@ -501,11 +452,8 @@
|
|
|
501
452
|
const tailwind = script.getAttribute('data-tailwind') !== null;
|
|
502
453
|
const version = script.getAttribute('data-version') || DEFAULT_VERSION;
|
|
503
454
|
const alpine = script.getAttribute('data-alpine');
|
|
504
|
-
//
|
|
505
|
-
//
|
|
506
|
-
// and for the e2e harness which needs to load locally-built plugins.
|
|
507
|
-
// The base should point at a directory that serves `manifest.<name>.js`
|
|
508
|
-
// files. It can be relative (e.g. "/scripts") or absolute.
|
|
455
|
+
// Override: resolve plugin URLs against this base (dir serving
|
|
456
|
+
// `manifest.<name>.js`, relative or absolute) instead of the CDN.
|
|
509
457
|
const pluginBase = script.getAttribute('data-plugin-base');
|
|
510
458
|
|
|
511
459
|
let pluginList = [];
|
|
@@ -593,25 +541,16 @@
|
|
|
593
541
|
|
|
594
542
|
const MANIFEST_DEPENDENT_PLUGINS = [
|
|
595
543
|
'data', 'localization', 'components',
|
|
596
|
-
'appwrite-auth', 'appwrite-data', 'appwrite-
|
|
544
|
+
'appwrite-auth', 'appwrite-data', 'appwrite-presences', 'payments'
|
|
597
545
|
];
|
|
598
546
|
const manifestUrl = (document.querySelector('link[rel="manifest"]')?.getAttribute('href')) || '/manifest.json';
|
|
599
547
|
|
|
600
|
-
// Substitute ${VAR} placeholders against window.env in
|
|
601
|
-
//
|
|
602
|
-
//
|
|
603
|
-
//
|
|
604
|
-
//
|
|
605
|
-
//
|
|
606
|
-
// point we cache the manifest. window.env is populated by either
|
|
607
|
-
// the mnfst-run dev server (which reads PUBLIC_-prefixed vars from
|
|
608
|
-
// .env at startup) or a developer-supplied
|
|
609
|
-
// <script>window.env = {…}</script> block.
|
|
610
|
-
//
|
|
611
|
-
// Misses are warned, not silently dropped: a missing var almost
|
|
612
|
-
// always means the dev forgot the PUBLIC_ prefix or hasn't set the
|
|
613
|
-
// var at all, and an empty substitution downstream (e.g. an empty
|
|
614
|
-
// API URL) tends to fail far from the cause.
|
|
548
|
+
// Substitute ${VAR} placeholders against window.env in-place, once,
|
|
549
|
+
// before caching the manifest so every consumer sees resolved values.
|
|
550
|
+
// Inlined (not borrowed from the data plugin, which may not have run
|
|
551
|
+
// yet). window.env comes from mnfst-run (.env PUBLIC_ vars) or an
|
|
552
|
+
// author <script>window.env = {…}</script>. Misses are warned, not
|
|
553
|
+
// dropped — an empty substitution tends to fail far from the cause.
|
|
615
554
|
const warnedMissingEnv = new Set();
|
|
616
555
|
const interpolateManifestEnv = (obj) => {
|
|
617
556
|
if (obj === null || typeof obj !== 'object') return;
|
|
@@ -687,11 +626,8 @@
|
|
|
687
626
|
manifest = await manifestPromise;
|
|
688
627
|
}
|
|
689
628
|
if (manifest && typeof window !== 'undefined') {
|
|
690
|
-
// Resolve ${VAR}
|
|
691
|
-
//
|
|
692
|
-
// appwrite-auth read window.__manifestLoaded directly and
|
|
693
|
-
// would otherwise see literal `${APPWRITE_DEV_KEY}` strings
|
|
694
|
-
// even when window.env is populated.
|
|
629
|
+
// Resolve ${VAR} before any plugin reads the cached manifest —
|
|
630
|
+
// appwrite-auth etc. read window.__manifestLoaded directly.
|
|
695
631
|
interpolateManifestEnv(manifest);
|
|
696
632
|
window.__manifestLoaded = manifest;
|
|
697
633
|
if (window.ManifestComponentsRegistry) {
|