mnfst 0.5.62 → 0.5.64
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.colorpicker.js +3033 -0
- package/lib/manifest.dropdowns.js +1 -1
- package/lib/manifest.icons.js +1 -1
- package/lib/manifest.js +8 -11
- package/lib/manifest.localization.js +1 -1
- package/lib/manifest.markdown.js +21 -1
- package/lib/manifest.resize.js +1 -1
- package/lib/manifest.slides.js +1 -1
- package/lib/manifest.themes.js +1 -1
- package/lib/manifest.toasts.js +1 -1
- package/lib/manifest.tooltips.js +1 -1
- package/lib/manifest.url.parameters.js +236 -0
- package/package.json +3 -2
|
@@ -404,7 +404,7 @@ document.addEventListener('alpine:init', ensureDropdownPluginInitialized);
|
|
|
404
404
|
// If Alpine is already initialized when this script loads, initialize immediately
|
|
405
405
|
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
|
406
406
|
setTimeout(ensureDropdownPluginInitialized, 0);
|
|
407
|
-
} else
|
|
407
|
+
} else {
|
|
408
408
|
// If document is already loaded but Alpine isn't ready yet, wait for it
|
|
409
409
|
const checkAlpine = setInterval(() => {
|
|
410
410
|
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
package/lib/manifest.icons.js
CHANGED
|
@@ -154,7 +154,7 @@ document.addEventListener('alpine:init', ensureIconPluginInitialized);
|
|
|
154
154
|
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
|
155
155
|
// Small delay to ensure Alpine is fully initialized
|
|
156
156
|
setTimeout(ensureIconPluginInitialized, 0);
|
|
157
|
-
} else
|
|
157
|
+
} else {
|
|
158
158
|
// If document is already loaded but Alpine isn't ready yet, wait for it
|
|
159
159
|
const checkAlpine = setInterval(() => {
|
|
160
160
|
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
package/lib/manifest.js
CHANGED
|
@@ -198,7 +198,8 @@
|
|
|
198
198
|
'tabs',
|
|
199
199
|
'slides',
|
|
200
200
|
'resize',
|
|
201
|
-
'colorpicker'
|
|
201
|
+
'colorpicker',
|
|
202
|
+
'url-parameters'
|
|
202
203
|
];
|
|
203
204
|
|
|
204
205
|
// Appwrite integration plugins (opt-in only, never auto-loaded)
|
|
@@ -248,20 +249,16 @@
|
|
|
248
249
|
let _pluginBase = null;
|
|
249
250
|
function setPluginBase(b) { _pluginBase = b || null; }
|
|
250
251
|
function getPluginUrl(pluginName, version = DEFAULT_VERSION) {
|
|
252
|
+
// Map hyphenated plugin API names to their dotted file names.
|
|
253
|
+
// `appwrite-auth` → `manifest.appwrite.auth.js`
|
|
254
|
+
// `url-parameters` → `manifest.url.parameters.js`
|
|
255
|
+
const fileName = pluginName.replace(/-/g, '.');
|
|
251
256
|
if (_pluginBase) {
|
|
252
257
|
const base = _pluginBase.replace(/\/$/, '');
|
|
253
|
-
|
|
254
|
-
const appwriteName = pluginName.replace('appwrite-', 'appwrite.');
|
|
255
|
-
return `${base}/manifest.${appwriteName}.js`;
|
|
256
|
-
}
|
|
257
|
-
return `${base}/manifest.${pluginName}.js`;
|
|
258
|
+
return `${base}/manifest.${fileName}.js`;
|
|
258
259
|
}
|
|
259
260
|
const base = getBaseUrl(version);
|
|
260
|
-
|
|
261
|
-
const appwriteName = pluginName.replace('appwrite-', 'appwrite.');
|
|
262
|
-
return `${base}/manifest.${appwriteName}.min.js`;
|
|
263
|
-
}
|
|
264
|
-
return `${base}/manifest.${pluginName}.min.js`;
|
|
261
|
+
return `${base}/manifest.${fileName}.min.js`;
|
|
265
262
|
}
|
|
266
263
|
|
|
267
264
|
// Resolve Alpine CDN URL from a data-alpine value (version tag or full URL)
|
|
@@ -696,7 +696,7 @@ if (document.readyState === 'loading') {
|
|
|
696
696
|
// If Alpine is already initialized when this script loads, initialize immediately
|
|
697
697
|
if (window.Alpine && typeof window.Alpine.magic === 'function') {
|
|
698
698
|
setTimeout(ensureLocalizationPluginInitialized, 0);
|
|
699
|
-
} else
|
|
699
|
+
} else {
|
|
700
700
|
const checkAlpine = setInterval(() => {
|
|
701
701
|
if (window.Alpine && typeof window.Alpine.magic === 'function') {
|
|
702
702
|
clearInterval(checkAlpine);
|
package/lib/manifest.markdown.js
CHANGED
|
@@ -6,6 +6,17 @@ let markedPromise = null;
|
|
|
6
6
|
// Cache for fetched markdown files to prevent duplicate requests
|
|
7
7
|
const markdownCache = new Map();
|
|
8
8
|
|
|
9
|
+
// Invalidate the markdown fetch cache when mnfst-run signals a data file
|
|
10
|
+
// changed on disk. Without this, a saved .md file is re-read by the data
|
|
11
|
+
// plugin but x-markdown still serves the old content from cache; combined
|
|
12
|
+
// with the lastProcessedContent short-circuit in the directive's effect,
|
|
13
|
+
// the article appears blank until the user manually reloads.
|
|
14
|
+
if (typeof window !== 'undefined') {
|
|
15
|
+
window.addEventListener('manifest:dev-reload', () => {
|
|
16
|
+
markdownCache.clear();
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
9
20
|
// Load marked.js from CDN
|
|
10
21
|
async function loadMarkedJS() {
|
|
11
22
|
if (typeof marked !== 'undefined') {
|
|
@@ -527,8 +538,17 @@ async function initializeMarkdownPlugin() {
|
|
|
527
538
|
}
|
|
528
539
|
}
|
|
529
540
|
|
|
530
|
-
// Skip if content hasn't changed
|
|
541
|
+
// Skip re-render if content hasn't changed, but still restore
|
|
542
|
+
// visibility — during a dev-reload the data plugin briefly
|
|
543
|
+
// clears its source cache, which makes the expression
|
|
544
|
+
// resolve to undefined and pushes opacity to 0; if we
|
|
545
|
+
// early-return here without restoring it, the article stays
|
|
546
|
+
// hidden even though innerHTML is intact.
|
|
531
547
|
if (markdownContent === lastProcessedContent) {
|
|
548
|
+
if (el.innerHTML && el.innerHTML.trim() !== '') {
|
|
549
|
+
hasContent = true;
|
|
550
|
+
el.style.opacity = '1';
|
|
551
|
+
}
|
|
532
552
|
return;
|
|
533
553
|
}
|
|
534
554
|
lastProcessedContent = markdownContent;
|
package/lib/manifest.resize.js
CHANGED
|
@@ -431,7 +431,7 @@ document.addEventListener('alpine:init', ensureResizePluginInitialized);
|
|
|
431
431
|
// If Alpine is already initialized when this script loads, initialize immediately
|
|
432
432
|
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
|
433
433
|
setTimeout(ensureResizePluginInitialized, 0);
|
|
434
|
-
} else
|
|
434
|
+
} else {
|
|
435
435
|
const checkAlpine = setInterval(() => {
|
|
436
436
|
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
|
437
437
|
clearInterval(checkAlpine);
|
package/lib/manifest.slides.js
CHANGED
|
@@ -162,7 +162,7 @@ document.addEventListener('alpine:init', ensureSlidesPluginInitialized);
|
|
|
162
162
|
// If Alpine is already initialized when this script loads, initialize immediately
|
|
163
163
|
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
|
164
164
|
setTimeout(ensureSlidesPluginInitialized, 0);
|
|
165
|
-
} else
|
|
165
|
+
} else {
|
|
166
166
|
const checkAlpine = setInterval(() => {
|
|
167
167
|
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
|
168
168
|
clearInterval(checkAlpine);
|
package/lib/manifest.themes.js
CHANGED
|
@@ -97,7 +97,7 @@ document.addEventListener('alpine:init', ensureThemePluginInitialized);
|
|
|
97
97
|
// If Alpine is already initialized when this script loads, initialize immediately
|
|
98
98
|
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
|
99
99
|
setTimeout(ensureThemePluginInitialized, 0);
|
|
100
|
-
} else
|
|
100
|
+
} else {
|
|
101
101
|
// If document is already loaded but Alpine isn't ready yet, wait for it
|
|
102
102
|
const checkAlpine = setInterval(() => {
|
|
103
103
|
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
package/lib/manifest.toasts.js
CHANGED
|
@@ -273,7 +273,7 @@ document.addEventListener('alpine:init', ensureToastPluginInitialized);
|
|
|
273
273
|
// If Alpine is already initialized when this script loads, initialize immediately
|
|
274
274
|
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
|
275
275
|
setTimeout(ensureToastPluginInitialized, 0);
|
|
276
|
-
} else
|
|
276
|
+
} else {
|
|
277
277
|
// If document is already loaded but Alpine isn't ready yet, wait for it
|
|
278
278
|
const checkAlpine = setInterval(() => {
|
|
279
279
|
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
package/lib/manifest.tooltips.js
CHANGED
|
@@ -300,7 +300,7 @@ document.addEventListener('alpine:init', ensureTooltipPluginInitialized);
|
|
|
300
300
|
|
|
301
301
|
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
|
302
302
|
setTimeout(ensureTooltipPluginInitialized, 0);
|
|
303
|
-
} else
|
|
303
|
+
} else {
|
|
304
304
|
const checkAlpine = setInterval(() => {
|
|
305
305
|
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
|
306
306
|
clearInterval(checkAlpine);
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/* Manifest URL Parameters */
|
|
2
|
+
|
|
3
|
+
function initializeUrlParametersPlugin() {
|
|
4
|
+
// Initialize empty parameters store
|
|
5
|
+
Alpine.store('urlParams', {
|
|
6
|
+
current: {},
|
|
7
|
+
_initialized: false
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
// Cache for debounced updates
|
|
11
|
+
const updateTimeouts = new Map();
|
|
12
|
+
const DEBOUNCE_DELAY = 300;
|
|
13
|
+
|
|
14
|
+
// Helper to parse query string
|
|
15
|
+
function parseQueryString(queryString) {
|
|
16
|
+
const params = new URLSearchParams(queryString);
|
|
17
|
+
const result = {};
|
|
18
|
+
|
|
19
|
+
for (const [key, value] of params.entries()) {
|
|
20
|
+
// Handle array values (comma-separated)
|
|
21
|
+
if (value.includes(',')) {
|
|
22
|
+
result[key] = value.split(',').filter(Boolean);
|
|
23
|
+
} else {
|
|
24
|
+
result[key] = value;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Helper to stringify query object
|
|
32
|
+
function stringifyQueryObject(query) {
|
|
33
|
+
const params = new URLSearchParams();
|
|
34
|
+
|
|
35
|
+
for (const [key, value] of Object.entries(query)) {
|
|
36
|
+
if (Array.isArray(value)) {
|
|
37
|
+
params.set(key, value.filter(Boolean).join(','));
|
|
38
|
+
} else if (value != null && value !== '') {
|
|
39
|
+
params.set(key, value);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return params.toString();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Helper to ensure value is in array format
|
|
47
|
+
function ensureArray(value) {
|
|
48
|
+
if (Array.isArray(value)) return value;
|
|
49
|
+
if (value == null || value === '') return [];
|
|
50
|
+
return [value];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Update URL with new query parameters
|
|
54
|
+
async function updateURL(updates, action = 'set') {
|
|
55
|
+
|
|
56
|
+
const url = new URL(window.location.href);
|
|
57
|
+
const currentParams = parseQueryString(url.search);
|
|
58
|
+
|
|
59
|
+
// Apply updates based on action
|
|
60
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
61
|
+
switch (action) {
|
|
62
|
+
case 'add':
|
|
63
|
+
const currentAdd = ensureArray(currentParams[key]);
|
|
64
|
+
const newValues = ensureArray(value);
|
|
65
|
+
currentParams[key] = [...new Set([...currentAdd, ...newValues])];
|
|
66
|
+
break;
|
|
67
|
+
|
|
68
|
+
case 'remove':
|
|
69
|
+
const currentRemove = ensureArray(currentParams[key]);
|
|
70
|
+
const removeValue = ensureArray(value)[0]; // Take first value to remove
|
|
71
|
+
currentParams[key] = currentRemove.filter(v => v !== removeValue);
|
|
72
|
+
if (currentParams[key].length === 0) {
|
|
73
|
+
delete currentParams[key];
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
|
|
77
|
+
case 'set':
|
|
78
|
+
default:
|
|
79
|
+
if (value == null || value === '') {
|
|
80
|
+
delete currentParams[key];
|
|
81
|
+
} else {
|
|
82
|
+
currentParams[key] = value;
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Update URL
|
|
89
|
+
const newQueryString = stringifyQueryObject(currentParams);
|
|
90
|
+
url.search = newQueryString ? `?${newQueryString}` : '';
|
|
91
|
+
|
|
92
|
+
// Update URL using pushState to ensure changes are visible
|
|
93
|
+
window.history.pushState({}, '', url.toString());
|
|
94
|
+
|
|
95
|
+
// Update store
|
|
96
|
+
Alpine.store('urlParams', {
|
|
97
|
+
current: currentParams,
|
|
98
|
+
_initialized: true
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Dispatch event
|
|
102
|
+
document.dispatchEvent(new CustomEvent('url-updated', {
|
|
103
|
+
detail: { updates, action }
|
|
104
|
+
}));
|
|
105
|
+
|
|
106
|
+
return currentParams;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Add $url magic method
|
|
110
|
+
Alpine.magic('url', () => {
|
|
111
|
+
const store = Alpine.store('urlParams');
|
|
112
|
+
|
|
113
|
+
return new Proxy({}, {
|
|
114
|
+
get(target, prop) {
|
|
115
|
+
// Handle special keys
|
|
116
|
+
if (prop === Symbol.iterator || prop === 'then' || prop === 'catch' || prop === 'finally') {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Get current value
|
|
121
|
+
const value = store.current[prop];
|
|
122
|
+
|
|
123
|
+
// Return a proxy for the value
|
|
124
|
+
return new Proxy({}, {
|
|
125
|
+
get(target, key) {
|
|
126
|
+
if (key === 'value') {
|
|
127
|
+
// Ensure arrays are returned as arrays, not strings
|
|
128
|
+
if (Array.isArray(value)) return value;
|
|
129
|
+
if (typeof value === 'string' && value.includes(',')) {
|
|
130
|
+
return value.split(',').filter(Boolean);
|
|
131
|
+
}
|
|
132
|
+
// Return undefined/null values as they are (for proper falsy checks)
|
|
133
|
+
return value;
|
|
134
|
+
}
|
|
135
|
+
if (key === 'set') return (newValue) => {
|
|
136
|
+
clearTimeout(updateTimeouts.get(prop));
|
|
137
|
+
const timeout = setTimeout(() => {
|
|
138
|
+
updateURL({ [prop]: newValue }, 'set');
|
|
139
|
+
}, DEBOUNCE_DELAY);
|
|
140
|
+
updateTimeouts.set(prop, timeout);
|
|
141
|
+
};
|
|
142
|
+
if (key === 'add') return (newValue) => {
|
|
143
|
+
clearTimeout(updateTimeouts.get(prop));
|
|
144
|
+
const timeout = setTimeout(() => {
|
|
145
|
+
updateURL({ [prop]: newValue }, 'add');
|
|
146
|
+
}, DEBOUNCE_DELAY);
|
|
147
|
+
updateTimeouts.set(prop, timeout);
|
|
148
|
+
};
|
|
149
|
+
if (key === 'remove') return (value) => {
|
|
150
|
+
clearTimeout(updateTimeouts.get(prop));
|
|
151
|
+
const timeout = setTimeout(() => {
|
|
152
|
+
updateURL({ [prop]: value }, 'remove');
|
|
153
|
+
}, DEBOUNCE_DELAY);
|
|
154
|
+
updateTimeouts.set(prop, timeout);
|
|
155
|
+
};
|
|
156
|
+
if (key === 'clear') return () => {
|
|
157
|
+
clearTimeout(updateTimeouts.get(prop));
|
|
158
|
+
const timeout = setTimeout(() => {
|
|
159
|
+
updateURL({ [prop]: null }, 'set');
|
|
160
|
+
}, DEBOUNCE_DELAY);
|
|
161
|
+
updateTimeouts.set(prop, timeout);
|
|
162
|
+
};
|
|
163
|
+
return undefined;
|
|
164
|
+
},
|
|
165
|
+
set(target, key, newValue) {
|
|
166
|
+
if (key === 'value') {
|
|
167
|
+
// Make value settable for x-model compatibility
|
|
168
|
+
clearTimeout(updateTimeouts.get(prop));
|
|
169
|
+
const timeout = setTimeout(() => {
|
|
170
|
+
updateURL({ [prop]: newValue }, 'set');
|
|
171
|
+
}, DEBOUNCE_DELAY);
|
|
172
|
+
updateTimeouts.set(prop, timeout);
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Initialize with current URL parameters
|
|
183
|
+
const initialParams = parseQueryString(window.location.search);
|
|
184
|
+
Alpine.store('urlParams', {
|
|
185
|
+
current: initialParams,
|
|
186
|
+
_initialized: true
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Listen for popstate events
|
|
190
|
+
window.addEventListener('popstate', () => {
|
|
191
|
+
const params = parseQueryString(window.location.search);
|
|
192
|
+
Alpine.store('urlParams', {
|
|
193
|
+
current: params,
|
|
194
|
+
_initialized: true
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Track initialization to prevent duplicates
|
|
200
|
+
let urlParametersPluginInitialized = false;
|
|
201
|
+
|
|
202
|
+
function ensureUrlParametersPluginInitialized() {
|
|
203
|
+
if (urlParametersPluginInitialized) return;
|
|
204
|
+
if (!window.Alpine || typeof window.Alpine.directive !== 'function') return;
|
|
205
|
+
|
|
206
|
+
urlParametersPluginInitialized = true;
|
|
207
|
+
initializeUrlParametersPlugin();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Expose on window for loader to call if needed
|
|
211
|
+
window.ensureUrlParametersPluginInitialized = ensureUrlParametersPluginInitialized;
|
|
212
|
+
|
|
213
|
+
// Handle both DOMContentLoaded and alpine:init
|
|
214
|
+
if (document.readyState === 'loading') {
|
|
215
|
+
document.addEventListener('DOMContentLoaded', ensureUrlParametersPluginInitialized);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
document.addEventListener('alpine:init', ensureUrlParametersPluginInitialized);
|
|
219
|
+
|
|
220
|
+
// If Alpine is already initialized when this script loads, initialize immediately.
|
|
221
|
+
// Otherwise ALWAYS poll until Alpine is available — the previous logic gated the
|
|
222
|
+
// polling on `document.readyState === 'complete'`, which produced a dead window
|
|
223
|
+
// when the loader injected this plugin script after DOMContentLoaded but before
|
|
224
|
+
// document complete: alpine:init had already fired, the readyState gate failed,
|
|
225
|
+
// and the plugin sat unregistered for the lifetime of the page.
|
|
226
|
+
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
|
227
|
+
setTimeout(ensureUrlParametersPluginInitialized, 0);
|
|
228
|
+
} else {
|
|
229
|
+
const checkAlpine = setInterval(() => {
|
|
230
|
+
if (window.Alpine && typeof window.Alpine.directive === 'function') {
|
|
231
|
+
clearInterval(checkAlpine);
|
|
232
|
+
ensureUrlParametersPluginInitialized();
|
|
233
|
+
}
|
|
234
|
+
}, 10);
|
|
235
|
+
setTimeout(() => clearInterval(checkAlpine), 5000);
|
|
236
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mnfst",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.64",
|
|
4
4
|
"private": false,
|
|
5
5
|
"workspaces": [
|
|
6
6
|
"templates/starter",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"publish:starter": "cd packages/create-starter && npm publish --auth-type=web",
|
|
29
29
|
"publish:run": "cd packages/run && npm publish --auth-type=web",
|
|
30
30
|
"publish:render": "cd packages/render && npm publish --auth-type=web",
|
|
31
|
+
"publish:claude": "cd packages/create-claude && npm publish --auth-type=web",
|
|
31
32
|
"prepublishOnly": "npm run build",
|
|
32
33
|
"test": "vitest run",
|
|
33
34
|
"lint": "echo 'No linting configured'"
|
|
@@ -66,4 +67,4 @@
|
|
|
66
67
|
"bugs": {
|
|
67
68
|
"url": "https://github.com/andrewmatlock/manifest/issues"
|
|
68
69
|
}
|
|
69
|
-
}
|
|
70
|
+
}
|