mnfst 0.5.80 → 0.5.82

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.
Files changed (42) hide show
  1. package/LICENSE +1 -1
  2. package/lib/manifest.accordion.css +4 -4
  3. package/lib/manifest.appwrite.auth.js +66 -33
  4. package/lib/manifest.avatar.css +8 -8
  5. package/lib/manifest.button.css +7 -7
  6. package/lib/manifest.checkbox.css +5 -5
  7. package/lib/manifest.code.css +152 -193
  8. package/lib/manifest.code.js +841 -881
  9. package/lib/manifest.code.min.css +1 -1
  10. package/lib/manifest.colorpicker.css +11 -11
  11. package/lib/manifest.components.js +25 -155
  12. package/lib/manifest.css +278 -230
  13. package/lib/manifest.data.js +46 -2
  14. package/lib/manifest.dialog.css +2 -2
  15. package/lib/manifest.divider.css +2 -2
  16. package/lib/manifest.dropdown.css +9 -9
  17. package/lib/manifest.form.css +10 -10
  18. package/lib/manifest.input.css +9 -9
  19. package/lib/manifest.integrity.json +26 -0
  20. package/lib/manifest.js +60 -5
  21. package/lib/manifest.markdown.js +192 -79
  22. package/lib/manifest.min.css +1 -1
  23. package/lib/manifest.radio.css +1 -1
  24. package/lib/manifest.range.css +7 -7
  25. package/lib/manifest.resize.css +1 -1
  26. package/lib/manifest.router.js +49 -76
  27. package/lib/manifest.schema.json +1 -1
  28. package/lib/manifest.sidebar.css +5 -6
  29. package/lib/manifest.slides.css +5 -5
  30. package/lib/manifest.svg.js +75 -5
  31. package/lib/manifest.switch.css +4 -4
  32. package/lib/manifest.table.css +4 -4
  33. package/lib/manifest.theme.css +46 -41
  34. package/lib/manifest.toast.css +7 -7
  35. package/lib/manifest.tooltip.css +3 -3
  36. package/lib/manifest.tooltips.js +41 -0
  37. package/lib/manifest.typography.css +124 -69
  38. package/lib/manifest.utilities.css +48 -54
  39. package/lib/manifest.utilities.js +9 -29
  40. package/package.json +4 -7
  41. package/lib/manifest.export.js +0 -535
  42. package/lib/manifest.virtual.js +0 -319
@@ -1,319 +0,0 @@
1
- /* Manifest Virtual — variable-height list virtualization for Alpine.
2
- *
3
- * Renders only the rows visible in the scroll viewport (plus an overscan
4
- * buffer), so a list of tens of thousands of rows can scroll smoothly with
5
- * a low DOM count. Row heights are measured on render and the spacer
6
- * recalculates, so authors aren't bound to a fixed row height.
7
- *
8
- * Usage — wrap an x-for template with x-virtual on the scrolling container:
9
- *
10
- * <div x-virtual style="height: 600px; overflow: auto">
11
- * <template x-for="row in $x.customers" :key="row.id">
12
- * <div class="row">
13
- * <span x-text="row.name"></span>
14
- * </div>
15
- * </template>
16
- * </div>
17
- *
18
- * Options (object expression on the directive):
19
- *
20
- * <div x-virtual="{ estimate: 48, overscan: 5 }" style="height: 600px">
21
- *
22
- * estimate Initial per-row height in px (default 50). Used for rows
23
- * that haven't been measured yet. Closer estimates mean
24
- * less scroll-position drift on first render.
25
- * overscan Rows to render above/below the visible window (default 3).
26
- * Higher = smoother scroll, more DOM.
27
- *
28
- * Notes:
29
- *
30
- * - Only one template child is supported. It must have x-for and :key.
31
- * - The container element must have a bounded height (CSS height /
32
- * max-height) and scroll. The plugin sets overflow: auto + position:
33
- * relative if not already set.
34
- * - Heights are remeasured automatically if a row's content changes.
35
- */
36
-
37
- function initializeVirtualPlugin() {
38
-
39
- Alpine.directive('virtual', (el, { expression }, { effect, evaluate, evaluateLater, cleanup }) => {
40
-
41
- // --- Find and parse the template ---
42
- const template = el.querySelector(':scope > template');
43
- if (!template) {
44
- console.warn('[x-virtual] expects a child <template> with x-for, e.g. <template x-for="row in $x.items" :key="row.id">…');
45
- return;
46
- }
47
- const forExpr = template.getAttribute('x-for');
48
- if (!forExpr) {
49
- console.warn('[x-virtual] child <template> must have x-for');
50
- return;
51
- }
52
- const m = /^\s*(\S+|\(\s*\S+\s*,\s*\S+\s*\))\s+(?:in|of)\s+(.+?)\s*$/.exec(forExpr);
53
- if (!m) {
54
- console.warn('[x-virtual] could not parse x-for expression: ' + forExpr);
55
- return;
56
- }
57
- const itemName = m[1].trim();
58
- const sourceExpr = m[2].trim();
59
- const keyExpr =
60
- template.getAttribute(':key') ||
61
- template.getAttribute('x-bind:key') ||
62
- `${itemName}.id`;
63
-
64
- // Remove x-for/:key so Alpine doesn't try to render the full list, but
65
- // KEEP the template in the DOM as our render source. We'll clone its
66
- // contents per visible row.
67
- template.removeAttribute('x-for');
68
- template.removeAttribute(':key');
69
- template.removeAttribute('x-bind:key');
70
-
71
- // --- Options ---
72
- const options = expression ? evaluate(expression) || {} : {};
73
- const initialEstimate = Number(options.estimate) > 0 ? Number(options.estimate) : 50;
74
- const overscan = Number.isFinite(options.overscan) && options.overscan >= 0 ? Number(options.overscan) : 3;
75
-
76
- // --- Container setup ---
77
- const cs = getComputedStyle(el);
78
- if (cs.overflow === 'visible' && cs.overflowY === 'visible') el.style.overflow = 'auto';
79
- if (cs.position === 'static') el.style.position = 'relative';
80
-
81
- // The spacer holds the rendered (absolutely positioned) rows and sizes
82
- // itself to the total virtual height so the scrollbar is correct.
83
- const spacer = document.createElement('div');
84
- spacer.dataset.virtualSpacer = '';
85
- spacer.style.position = 'relative';
86
- spacer.style.width = '100%';
87
- spacer.style.height = '0px';
88
- el.appendChild(spacer);
89
-
90
- // --- State ---
91
- // heights: key -> measured pixel height (only for rows that have been
92
- // mounted at least once and measured).
93
- const heights = new Map();
94
- let measuredSum = 0;
95
- let measuredCount = 0;
96
- // rendered: key -> wrapper element currently in the DOM
97
- const rendered = new Map();
98
- // data: latest snapshot of the source array
99
- let data = [];
100
- // Cached cumulative offsets — index i holds the sum of heights of rows
101
- // 0..(i-1). Length is data.length + 1; final entry is total height.
102
- let cumulative = new Float64Array(1);
103
-
104
- const getAvg = () => (measuredCount > 0 ? measuredSum / measuredCount : initialEstimate);
105
- const rowHeightFor = (key) => heights.get(key) ?? getAvg();
106
-
107
- // Evaluate the key expression against an item without going through
108
- // Alpine — `new Function` is fast and isolates from the surrounding
109
- // scope. Expression usually looks like `row.id` or `row.$id`.
110
- const keyFn = buildKeyFn(itemName, keyExpr);
111
-
112
- function rebuildCumulative() {
113
- const n = data.length;
114
- cumulative = new Float64Array(n + 1);
115
- let y = 0;
116
- for (let i = 0; i < n; i++) {
117
- cumulative[i] = y;
118
- const k = keyFn(data[i]);
119
- y += rowHeightFor(k);
120
- }
121
- cumulative[n] = y;
122
- spacer.style.height = y + 'px';
123
- }
124
-
125
- // Find the first index whose offset is >= scrollTop. Cumulative is
126
- // monotonic so binary search works.
127
- function findStartIndex(scrollTop) {
128
- let lo = 0, hi = data.length;
129
- while (lo < hi) {
130
- const mid = (lo + hi) >>> 1;
131
- if (cumulative[mid + 1] <= scrollTop) lo = mid + 1;
132
- else hi = mid;
133
- }
134
- return Math.max(0, lo - overscan);
135
- }
136
-
137
- function findEndIndex(scrollBottom, startHint) {
138
- let i = startHint;
139
- const n = data.length;
140
- while (i < n && cumulative[i] < scrollBottom) i++;
141
- return Math.min(n, i + overscan);
142
- }
143
-
144
- function renderVisible() {
145
- if (!data.length) {
146
- for (const [, node] of rendered) node.remove();
147
- rendered.clear();
148
- return;
149
- }
150
- const scrollTop = el.scrollTop;
151
- const viewportHeight = el.clientHeight;
152
- const start = findStartIndex(scrollTop);
153
- const end = findEndIndex(scrollTop + viewportHeight, start);
154
-
155
- // Track which keys remain visible
156
- const stillVisible = new Set();
157
- for (let i = start; i < end; i++) {
158
- const item = data[i];
159
- if (item == null) continue;
160
- const key = keyFn(item);
161
- if (key == null) continue; // skip un-keyable rows
162
- stillVisible.add(key);
163
-
164
- let node = rendered.get(key);
165
- if (!node) {
166
- node = mountRow(i);
167
- if (!node) continue;
168
- rendered.set(key, node);
169
- spacer.appendChild(node);
170
- // x-data on the row needs the parent scope (where the
171
- // source array lives) to resolve, so we MUST init after
172
- // append, not before.
173
- Alpine.initTree(node);
174
- // Measure on next frame so Alpine has bound everything.
175
- requestAnimationFrame(() => measureRow(key, node));
176
- }
177
- node.style.top = cumulative[i] + 'px';
178
- node.dataset.virtualIndex = i;
179
- }
180
-
181
- // Remove rows no longer in the window
182
- for (const [key, node] of rendered) {
183
- if (!stillVisible.has(key)) {
184
- node.remove();
185
- rendered.delete(key);
186
- }
187
- }
188
- }
189
-
190
- function mountRow(index) {
191
- const tplChild = template.content.firstElementChild;
192
- if (!tplChild) return null;
193
- const node = tplChild.cloneNode(true);
194
- node.style.position = 'absolute';
195
- node.style.left = '0';
196
- node.style.right = '0';
197
- // Inject a per-row Alpine scope. Because we reference the source
198
- // expression with the index baked in via a getter, Alpine tracks
199
- // the dependency and re-renders this row when its data updates.
200
- const scopeExpr = `{ get ${itemName}() { return (${sourceExpr})[${index}]; } }`;
201
- // Merge with any existing x-data on the cloned root.
202
- const existing = node.getAttribute('x-data');
203
- node.setAttribute('x-data', existing ? `Object.assign({}, ${scopeExpr}, ${existing})` : scopeExpr);
204
- // Note: caller must Alpine.initTree(node) AFTER appending to the
205
- // DOM, otherwise the scope can't resolve identifiers (e.g. the
206
- // source array) from outer x-data contexts.
207
- return node;
208
- }
209
-
210
- function measureRow(key, node) {
211
- if (!node.isConnected) return;
212
- const h = node.offsetHeight;
213
- if (!h) return;
214
- const prev = heights.get(key);
215
- if (prev === h) return;
216
- if (prev !== undefined) measuredSum -= prev;
217
- else measuredCount++;
218
- measuredSum += h;
219
- heights.set(key, h);
220
- // Recompute cumulative offsets and re-render so positions reflect
221
- // the new heights AND any rows now in/out of the visible window.
222
- rebuildCumulative();
223
- renderVisible();
224
- }
225
-
226
- // --- Reactive data source subscription ---
227
- const sourceGetter = evaluateLater(sourceExpr);
228
- effect(() => {
229
- sourceGetter((value) => {
230
- data = Array.isArray(value) ? value : (value ? Array.from(value) : []);
231
- // When the data identity or length changes, drop any rendered
232
- // rows whose keys no longer exist in the new data.
233
- const validKeys = new Set();
234
- for (const item of data) {
235
- if (item != null) validKeys.add(keyFn(item));
236
- }
237
- for (const [key, node] of rendered) {
238
- if (!validKeys.has(key)) {
239
- node.remove();
240
- rendered.delete(key);
241
- }
242
- }
243
- rebuildCumulative();
244
- renderVisible();
245
- });
246
- });
247
-
248
- // --- Scroll + resize handlers ---
249
- let scrollScheduled = false;
250
- const onScroll = () => {
251
- if (scrollScheduled) return;
252
- scrollScheduled = true;
253
- requestAnimationFrame(() => {
254
- scrollScheduled = false;
255
- renderVisible();
256
- });
257
- };
258
- el.addEventListener('scroll', onScroll, { passive: true });
259
-
260
- const ro = new ResizeObserver(() => renderVisible());
261
- ro.observe(el);
262
-
263
- cleanup(() => {
264
- el.removeEventListener('scroll', onScroll);
265
- ro.disconnect();
266
- for (const [, node] of rendered) node.remove();
267
- rendered.clear();
268
- spacer.remove();
269
- });
270
- });
271
-
272
- }
273
-
274
- // Build a key-evaluator function for a given itemName + keyExpr.
275
- // `keyFn(item)` returns the row's key. Falls back to identity if it fails.
276
- function buildKeyFn(itemName, keyExpr) {
277
- try {
278
- // eslint-disable-next-line no-new-func
279
- const fn = new Function(itemName, `return (${keyExpr});`);
280
- return (item) => {
281
- try { return fn(item); } catch { return item; }
282
- };
283
- } catch {
284
- return (item) => item;
285
- }
286
- }
287
-
288
- // Track initialization to prevent duplicates
289
- let virtualPluginInitialized = false;
290
-
291
- function ensureVirtualPluginInitialized() {
292
- if (virtualPluginInitialized) return;
293
- if (!window.Alpine || typeof window.Alpine.directive !== 'function') return;
294
- virtualPluginInitialized = true;
295
- initializeVirtualPlugin();
296
- }
297
-
298
- // Expose on window for loader to call if needed
299
- window.ensureVirtualPluginInitialized = ensureVirtualPluginInitialized;
300
-
301
- // Handle both DOMContentLoaded and alpine:init
302
- if (document.readyState === 'loading') {
303
- document.addEventListener('DOMContentLoaded', ensureVirtualPluginInitialized);
304
- }
305
-
306
- document.addEventListener('alpine:init', ensureVirtualPluginInitialized);
307
-
308
- // If Alpine is already initialized when this script loads, initialize immediately
309
- if (window.Alpine && typeof window.Alpine.directive === 'function') {
310
- setTimeout(ensureVirtualPluginInitialized, 0);
311
- } else {
312
- const checkAlpine = setInterval(() => {
313
- if (window.Alpine && typeof window.Alpine.directive === 'function') {
314
- clearInterval(checkAlpine);
315
- ensureVirtualPluginInitialized();
316
- }
317
- }, 10);
318
- setTimeout(() => clearInterval(checkAlpine), 5000);
319
- }