mnfst 0.5.228 → 0.5.230

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  (function () {
4
4
 
5
- const MANIFEST_BUILD_VERSION = '0.5.228';
5
+ const MANIFEST_BUILD_VERSION = '0.5.230';
6
6
 
7
7
  /* Manifest Data Sources - Appwrite Integration */
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  (function () {
4
4
 
5
- const MANIFEST_BUILD_VERSION = '0.5.228';
5
+ const MANIFEST_BUILD_VERSION = '0.5.230';
6
6
 
7
7
  /* Manifest Data Sources - Configuration */
8
8
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest.appwrite.auth.js": "sha384-dsIWnH0qCAGSzAXMGrd8fvOrVl4tOIE6j5tC35JPTrQXZ56qLD36ARyvhR7vi3Id",
3
- "manifest.appwrite.data.js": "sha384-KZ8iQZ7C8DRx64IK49o+sqXFxHhIK7GKm8cRj4gvEy1MYmVWpnCmznPCWztFI5g3",
3
+ "manifest.appwrite.data.js": "sha384-Mpd1w3Weo2ioajbPvtsMQQtT/VhPJAGWCyjvN7IpSW2ZbGxsvWYj5FxxUxBOfITx",
4
4
  "manifest.appwrite.presences.js": "sha384-JyVDWFT69b7Svq8J8p9tNWe2v9PZNQBY5UyhtOl1vnuHFAX0CRQ3MA9SiKq5wzNh",
5
5
  "manifest.bindings.js": "sha384-lPtMf8Ykaic9gNVZKq8Scia1881ZeMAyxer3WCIkUNwwrgzGBWto1OXADUwjvORF",
6
6
  "manifest.charts.js": "sha384-gEAv/98+29RbhvNkiNWTNyBPbLTFr2Ld15wLu29FLCL57j1cwGChRrL9Pfk7dBtT",
@@ -11,7 +11,7 @@
11
11
  "manifest.combobox.js": "sha384-MILTkrgsTzsYUjGo4ZuADqV85Xs4GmfB4xexfe9vbJMIoQTZ42W4zs+DTaVSPEsx",
12
12
  "manifest.components.js": "sha384-4bc3HgPvF9DHMiOG08w+nWXI7Hho01RuAPAUL9xyLxOiS2igeZpulCVcvr5aT9v6",
13
13
  "manifest.computed.js": "sha384-GYML/e81gQfN+iDbqhPUgny8bINCyL+SrbTofoGk4hlCnLLjv51mCv42JMqq+ku5",
14
- "manifest.data.js": "sha384-kaByNpTzaPcQiJeIDl7CTnXale/otGrq4BG9dfv+Fhw+s95z4A7YhgvtAZmMKLIa",
14
+ "manifest.data.js": "sha384-SjwWBJN06ct4ON/VFx3aVoZ141p1fn9oW8S8tMyzKz5fY2mx3/T5GWnwDids2qCx",
15
15
  "manifest.datepicker.js": "sha384-XnbeURni2X91ozVzatQcSjYYIS4MoW12dBRJnYAGBr0nCQ624heH5s+xtQSpLZX6",
16
16
  "manifest.defer.js": "sha384-WcCf8YQ1bKIXCLSZ24a0bJwepbYntYc8TzQM50hklo5VMIH8AtzDnwl6WU4prRv1",
17
17
  "manifest.device.js": "sha384-g+txmrEszYtuOvRelTp/c1wSNR2AtllVI9rx5NPPD7DzhVUnMNughonZykv2xlBW",
@@ -27,12 +27,12 @@
27
27
  "manifest.slides.js": "sha384-3uRTkyK9XPLmnxI2+igZlpi4EyPlU/7IHj5j3BZJJ2KN455vXyk99fiXV3feO/XY",
28
28
  "manifest.status.js": "sha384-MBO345ab7H6Uq1X2dZLt4Ge1Gcra+Z2qYApvlAeIV8CJhDDJrz2FPXpp+Kcp8zcM",
29
29
  "manifest.svg.js": "sha384-qr/8H9+2cIhSXNbRWRtIdrDlTOxKlNJqwEefHvCYoiBNW/kKhPTFa109Orv/EBnb",
30
- "manifest.sw.js": "sha384-r3vBPbaW3PRru8sBETOY01m0hg7bV5IgEptsEmnZReTHSIfKWoFgrV6GivNkphuK",
30
+ "manifest.sw.js": "sha384-2+0QTucW8JqeS8aOImj9rehXkkQ6ZADpD4PAvt3k72woRiZIhYTJpQNgAm/Ra3/i",
31
31
  "manifest.tabs.js": "sha384-OIIcyaQnGS0eNYk4zgAFEDboNYect7THvUd9D0V6nqCeDOxQcoiqLrBEmmWVTTet",
32
32
  "manifest.tailwind.js": "sha384-r/Jvqb+Piz21jUts10BbVAJoKkShOdJRVFpywyi4HPIi/OfOJq5CtPyWAPbdkMgt",
33
33
  "manifest.text.edit.js": "sha384-RzOvLQE8GbmI6gntAwiotDewYT/08OHcd7sJ5hLon8e8u1Xbq1D7VfEGuaRVd2CE",
34
- "manifest.toasts.js": "sha384-/OV32LLMJl0Iw8NoNQJ+5lgntLxjIJq/YNj5JAKS/+nUhVx4MMB9h1FOqP7zuj2M",
35
- "manifest.tooltips.js": "sha384-uXVVQADl6pY2Pj9i/UaSclZN7dzbKhLkmevv7Ad0+wXR8LgqodALNFrc5jZJjlwm",
34
+ "manifest.toasts.js": "sha384-3zkWxzw693pxg3QDFsoYCA3CqYaLKmBaMArULXODD66Utolpewl0OAeTB92aWUVv",
35
+ "manifest.tooltips.js": "sha384-4b24PH5WsfFsewGea5SMWLwmrhC4kD6eDP/vvjNyjXYnQXXFGi4nLdojrIOwzG8M",
36
36
  "manifest.url.parameters.js": "sha384-J2aSVBOPsoqsbafHndrWLHEDpKb4AKJAoQnVmKA4gZh5P/8HHjFWHO/lkusmG84l",
37
37
  "manifest.utilities.js": "sha384-L5uXMLFBIF6LUM1haRjd4eGjHSWuqsCYSpPZRPYosNfJsMC5U5TnmjBxIhrZRe2d",
38
38
  "manifest.virtual.js": "sha384-ZDNoF9QVhVcVpkjIK6NH15S6I5c6OBshiJpXSOYjNsIB+298I0a7g3aFO+jyq4Vb",
@@ -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.228';
19
+ const BUILD_VERSION = '0.5.230';
20
20
  const CACHE_PREFIX = 'mnfst-sw:';
21
21
  const META_CACHE = CACHE_PREFIX + 'meta';
22
22
  // Sized to hold a full precache.json warm-up (PRECACHE_MAX_ENTRIES server-side)
@@ -3,6 +3,57 @@
3
3
  (function () {
4
4
 
5
5
 
6
+ // mnfst:expressions:start — synced by the build from scripts/snippets/manifest.expressions.js; edit there
7
+ // Directive values: any JS expression evaluates; text that isn't one stays verbatim.
8
+
9
+ const EXPR_BARE_IDENTIFIER = /^[\p{ID_Start}$_][\p{ID_Continue}$]*$/u;
10
+ // No name, string or template: numbers, dates, ratios ("24/7", "2026-10-13") stay text
11
+ const EXPR_HAS_TOKEN = /[\p{L}$_'"`]/u;
12
+
13
+ function exprParses(src) {
14
+ try { new Function('return (' + src + '\n)'); return true; } catch { return false; }
15
+ }
16
+
17
+ function exprInScope(el, name) {
18
+ try { return name in Alpine.$data(el); } catch { return false; }
19
+ }
20
+
21
+ // Errors come back as values: unresolved names read as plain text
22
+ // ("Re-run", "Hello, world"); other errors warn against the authored expression
23
+ const exprGuarded = (src) =>
24
+ '(() => { try { return (' + src + '\n) } catch (e) { return { __exprError: e } } })()';
25
+
26
+ function exprUnwrap(v, el, src) {
27
+ const err = v && typeof v === 'object' && v.__exprError;
28
+ if (!(err instanceof Error)) return v;
29
+ if (err instanceof ReferenceError) return undefined;
30
+ console.warn(`Alpine Expression Error: ${err.message}\n\nExpression: "${src}"\n\n`, el);
31
+ return null;
32
+ }
33
+
34
+ // null for static text; else (cb) => cb(value, asText), asText meaning the
35
+ // authored text shows instead (unresolved name, undefined, NaN)
36
+ function expressionResolver(el, src, evaluateLater) {
37
+ if (src.startsWith('$x.')) {
38
+ const getValue = evaluateLater(src);
39
+ return (cb) => getValue(v => cb(v, false));
40
+ }
41
+ if (!EXPR_HAS_TOKEN.test(src) || !exprParses(src)) return null;
42
+ let getValue;
43
+ if (EXPR_BARE_IDENTIFIER.test(src)) {
44
+ // Single word: a scope value or magic, else text (never a global like Image or close)
45
+ const getWord = evaluateLater(exprGuarded(src));
46
+ getValue = (cb) => (src.startsWith('$') || exprInScope(el, src)) ? getWord(cb) : cb(undefined);
47
+ } else {
48
+ getValue = evaluateLater(exprGuarded(src));
49
+ }
50
+ return (cb) => getValue(raw => {
51
+ const v = exprUnwrap(raw, el, src);
52
+ cb(v, v === undefined || Number.isNaN(v));
53
+ });
54
+ }
55
+ // mnfst:expressions:end
56
+
6
57
  const TOAST_DURATION = 3000; // Default duration in ms
7
58
 
8
59
  function initializeToastPlugin() {
@@ -127,7 +178,7 @@ function initializeToastPlugin() {
127
178
  };
128
179
 
129
180
  // Add toast directive
130
- Alpine.directive('toast', (el, { modifiers, expression }, { evaluate }) => {
181
+ Alpine.directive('toast', (el, { modifiers, expression }, { evaluateLater }) => {
131
182
  // Parse options from modifiers
132
183
  const options = {
133
184
  type: modifiers.includes('brand') ? 'brand' :
@@ -146,32 +197,11 @@ function initializeToastPlugin() {
146
197
  options.duration = modifiers.includes('long') ? TOAST_DURATION * 2 : TOAST_DURATION;
147
198
  }
148
199
 
149
- // Handle both static and dynamic expressions
150
- let message;
151
- try {
152
- // Check if expression starts with $x (data sources)
153
- if (expression.startsWith('$x.')) {
154
- // Use evaluate for $x expressions to access collections
155
- message = evaluate(expression);
156
- } else if (expression.includes('<') && expression.includes('>')) {
157
- // Treat as literal HTML string - preserve spaces and formatting
158
- // Escape quotes to prevent syntax errors, but keep the HTML intact
159
- const escapedExpression = expression.replace(/'/g, "\\'");
160
- message = evaluate(`'${escapedExpression}'`);
161
- } else if (expression.includes('+') || expression.includes('`') || expression.includes('${')) {
162
- // Try to evaluate as a dynamic expression
163
- message = evaluate(expression);
164
- } else {
165
- // Use as static string
166
- message = expression;
167
- }
168
- } catch (e) {
169
- // If evaluation fails, use the expression as a static string
170
- message = expression;
171
- }
172
-
173
- // Store the toast options on the element
174
- el._toastOptions = { message, options };
200
+ // Static text (author HTML included) shows as written; expressions
201
+ // evaluate on every click. Empty results (null, false, '') show nothing.
202
+ const src = expression.trim();
203
+ const evaluate = expressionResolver(el, src, evaluateLater);
204
+ if (evaluate && src.startsWith('$x.')) evaluate(() => {}); // starts the source loading
175
205
 
176
206
  // Add click handler that works with other handlers
177
207
  const originalClick = el.onclick;
@@ -181,7 +211,13 @@ function initializeToastPlugin() {
181
211
  originalClick.call(el, e);
182
212
  }
183
213
  // Show toast after original handler
184
- showToast(message, options);
214
+ if (!evaluate) { showToast(expression, options); return; }
215
+ // After the element's other click listeners, so state they change shows
216
+ setTimeout(() => evaluate((v, asText) => {
217
+ if (asText) { showToast(expression, options); return; }
218
+ const message = v == null || v === false ? '' : String(v);
219
+ if (message !== '') showToast(message, options);
220
+ }));
185
221
  };
186
222
  });
187
223
 
@@ -3,6 +3,57 @@
3
3
  (function () {
4
4
 
5
5
 
6
+ // mnfst:expressions:start — synced by the build from scripts/snippets/manifest.expressions.js; edit there
7
+ // Directive values: any JS expression evaluates; text that isn't one stays verbatim.
8
+
9
+ const EXPR_BARE_IDENTIFIER = /^[\p{ID_Start}$_][\p{ID_Continue}$]*$/u;
10
+ // No name, string or template: numbers, dates, ratios ("24/7", "2026-10-13") stay text
11
+ const EXPR_HAS_TOKEN = /[\p{L}$_'"`]/u;
12
+
13
+ function exprParses(src) {
14
+ try { new Function('return (' + src + '\n)'); return true; } catch { return false; }
15
+ }
16
+
17
+ function exprInScope(el, name) {
18
+ try { return name in Alpine.$data(el); } catch { return false; }
19
+ }
20
+
21
+ // Errors come back as values: unresolved names read as plain text
22
+ // ("Re-run", "Hello, world"); other errors warn against the authored expression
23
+ const exprGuarded = (src) =>
24
+ '(() => { try { return (' + src + '\n) } catch (e) { return { __exprError: e } } })()';
25
+
26
+ function exprUnwrap(v, el, src) {
27
+ const err = v && typeof v === 'object' && v.__exprError;
28
+ if (!(err instanceof Error)) return v;
29
+ if (err instanceof ReferenceError) return undefined;
30
+ console.warn(`Alpine Expression Error: ${err.message}\n\nExpression: "${src}"\n\n`, el);
31
+ return null;
32
+ }
33
+
34
+ // null for static text; else (cb) => cb(value, asText), asText meaning the
35
+ // authored text shows instead (unresolved name, undefined, NaN)
36
+ function expressionResolver(el, src, evaluateLater) {
37
+ if (src.startsWith('$x.')) {
38
+ const getValue = evaluateLater(src);
39
+ return (cb) => getValue(v => cb(v, false));
40
+ }
41
+ if (!EXPR_HAS_TOKEN.test(src) || !exprParses(src)) return null;
42
+ let getValue;
43
+ if (EXPR_BARE_IDENTIFIER.test(src)) {
44
+ // Single word: a scope value or magic, else text (never a global like Image or close)
45
+ const getWord = evaluateLater(exprGuarded(src));
46
+ getValue = (cb) => (src.startsWith('$') || exprInScope(el, src)) ? getWord(cb) : cb(undefined);
47
+ } else {
48
+ getValue = evaluateLater(exprGuarded(src));
49
+ }
50
+ return (cb) => getValue(raw => {
51
+ const v = exprUnwrap(raw, el, src);
52
+ cb(v, v === undefined || Number.isNaN(v));
53
+ });
54
+ }
55
+ // mnfst:expressions:end
56
+
6
57
  // Hover delay from CSS var (with time-unit parsing). Defaults to 500ms.
7
58
  function getTooltipHoverDelay(element) {
8
59
  let computedStyle = getComputedStyle(element);
@@ -157,55 +208,42 @@ function initializeTooltipPlugin() {
157
208
  if (wasOpen) markTooltipHidden();
158
209
  }
159
210
 
211
+ const looksLikeHtml = (s) => s.includes('<') && s.includes('>');
212
+
160
213
  // ---- Directive ----
161
214
 
162
215
  Alpine.directive('tooltip', (el, { modifiers, expression }, { effect, evaluateLater }) => {
163
216
 
164
- // --- Content evaluator ---
165
- let getContent;
166
- const isDynamic =
167
- expression.startsWith('$x.') ||
168
- (expression.includes('+') || expression.includes('`') || expression.includes('${'));
217
+ // --- Content ---
218
+ // Escape by default; author literal HTML or .html/.safe opts in.
219
+ const htmlOptIn = modifiers.includes('html') || modifiers.includes('safe');
220
+ const literal = expression ? { text: expression, html: htmlOptIn || looksLikeHtml(expression) } : null;
221
+ const src = expression.trim();
222
+ const evaluate = expressionResolver(el, src, evaluateLater);
169
223
 
170
- // Render as HTML? Default false (escape); author literal HTML or .html/.safe opts in.
171
- let allowHtml = modifiers.includes('html') || modifiers.includes('safe');
172
-
173
- if (expression.startsWith('$x.')) {
174
- const path = expression.substring(3);
175
- const [contentType] = path.split('.');
176
- getContent = evaluateLater(expression);
224
+ if (src.startsWith('$x.')) {
225
+ const [contentType] = src.substring(3).split('.');
177
226
  effect(() => {
178
227
  const store = Alpine.store('collections');
179
228
  if (store && typeof store.loadCollection === 'function' && !store[contentType]) {
180
229
  store.loadCollection(contentType);
181
230
  }
182
231
  });
183
- } else if (expression.includes('<') && expression.includes('>')) {
184
- // Literal HTML in the attribute — author-authored, trusted as the template.
185
- allowHtml = true;
186
- const escaped = expression.replace(/'/g, "\\'");
187
- getContent = evaluateLater(`'${escaped}'`);
188
- } else if (expression.includes('+') || expression.includes('`') || expression.includes('${')) {
189
- getContent = evaluateLater(expression);
190
- } else {
191
- // Static literal — wrap in quotes so evaluateLater returns it verbatim
192
- getContent = evaluateLater(`'${expression}'`);
193
232
  }
194
233
 
195
234
  // --- Positioning modifiers ---
196
235
  const validPositions = ['top', 'bottom', 'start', 'end', 'center', 'corner'];
197
236
  const positions = modifiers.filter(m => validPositions.includes(m));
198
237
 
199
- // For non-dynamic content, cache once to avoid re-evaluating every show.
200
- let cachedContent = null;
201
- if (!isDynamic) {
202
- getContent(v => { cachedContent = v; });
203
- }
204
-
205
- // Resolves the content to show, calling the provided callback with the HTML string.
238
+ // Static text resolves once; expressions re-evaluate on every show.
239
+ // Empty results (null, false, '') show nothing.
206
240
  const resolveContent = (cb) => {
207
- if (!isDynamic && cachedContent != null) { cb(cachedContent); return; }
208
- getContent(v => cb(v));
241
+ if (!evaluate) { cb(literal); return; }
242
+ evaluate((v, asText) => {
243
+ if (asText) { cb(literal); return; }
244
+ const text = v == null || v === false ? '' : String(v);
245
+ cb(text === '' ? null : { text, html: htmlOptIn });
246
+ });
209
247
  };
210
248
 
211
249
  // --- Event handlers ---
@@ -225,8 +263,9 @@ function initializeTooltipPlugin() {
225
263
  const t = document.getElementById(triggerTargetId);
226
264
  if (t && t.matches && t.matches(':popover-open')) return;
227
265
  }
228
- resolveContent(html => {
229
- showSingletonFor(el, html, positions, allowHtml);
266
+ resolveContent(content => {
267
+ if (content) showSingletonFor(el, content.text, positions, content.html);
268
+ else hideAnySingleton();
230
269
  });
231
270
  }, delay);
232
271
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst",
3
- "version": "0.5.228",
3
+ "version": "0.5.230",
4
4
  "private": false,
5
5
  "workspaces": [
6
6
  "templates/starter",