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.
- package/LICENSE +1 -1
- package/lib/manifest.accordion.css +4 -4
- package/lib/manifest.appwrite.auth.js +66 -33
- package/lib/manifest.avatar.css +8 -8
- package/lib/manifest.button.css +7 -7
- package/lib/manifest.checkbox.css +5 -5
- package/lib/manifest.code.css +152 -193
- package/lib/manifest.code.js +841 -881
- package/lib/manifest.code.min.css +1 -1
- package/lib/manifest.colorpicker.css +11 -11
- package/lib/manifest.components.js +25 -155
- package/lib/manifest.css +278 -230
- package/lib/manifest.data.js +46 -2
- package/lib/manifest.dialog.css +2 -2
- package/lib/manifest.divider.css +2 -2
- package/lib/manifest.dropdown.css +9 -9
- package/lib/manifest.form.css +10 -10
- package/lib/manifest.input.css +9 -9
- package/lib/manifest.integrity.json +26 -0
- package/lib/manifest.js +60 -5
- package/lib/manifest.markdown.js +192 -79
- package/lib/manifest.min.css +1 -1
- package/lib/manifest.radio.css +1 -1
- package/lib/manifest.range.css +7 -7
- package/lib/manifest.resize.css +1 -1
- package/lib/manifest.router.js +49 -76
- package/lib/manifest.schema.json +1 -1
- package/lib/manifest.sidebar.css +5 -6
- package/lib/manifest.slides.css +5 -5
- package/lib/manifest.svg.js +75 -5
- package/lib/manifest.switch.css +4 -4
- package/lib/manifest.table.css +4 -4
- package/lib/manifest.theme.css +46 -41
- package/lib/manifest.toast.css +7 -7
- package/lib/manifest.tooltip.css +3 -3
- package/lib/manifest.tooltips.js +41 -0
- package/lib/manifest.typography.css +124 -69
- package/lib/manifest.utilities.css +48 -54
- package/lib/manifest.utilities.js +9 -29
- package/package.json +4 -7
- package/lib/manifest.export.js +0 -535
- package/lib/manifest.virtual.js +0 -319
|
@@ -1 +1 @@
|
|
|
1
|
-
@import url("https://fonts.googleapis.com/css2?family=
|
|
1
|
+
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap");:root{--icon-code-copy:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='14' height='14' x='8' y='8' rx='2' ry='2'/%3E%3Cpath d='M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2'/%3E%3C/g%3E%3C/svg%3E");--icon-code-copied:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyIiBjbGFzcz0ibHVjaWRlIGx1Y2lkZS1jb3B5LWNoZWNrLWljb24gbHVjaWRlLWNvcHktY2hlY2siIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0ibTEyIDE1IDIgMiA0LTQiLz48cmVjdCB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHg9IjgiIHk9IjgiIHJ4PSIyIiByeT0iMiIvPjxwYXRoIGQ9Ik00IDE2Yy0xLjEgMC0yLS45LTItMlY0YzAtMS4xLjktMiAyLTJoMTBjMS4xIDAgMiAuOSAyIDIiLz48L3N2Zz4=");--icon-code-expand:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m6 9 6 6 6-6'/%3E%3C/svg%3E");--color-code-keyword:#b8860b;--color-code-string:#8b4513;--color-code-comment:gray;--color-code-function:peru;--color-code-number:sienna;--color-code-operator:#2f4f4f;--color-code-class-name:#daa520;--color-code-tag:#4682b4;--color-code-attr-name:#ff8c00;--color-code-attr-value:#8b4513;--color-code-property:sienna;--color-code-selector:#4682b4;--color-code-punctuation:#2f4f4f;--color-code-builtin:#b8860b;--color-code-constant:sienna;--color-code-boolean:sienna;--color-code-regex:#8b4513;--color-code-symbol:#daa520;--color-code-entity:#daa520;--color-code-url:sienna;--color-code-atrule:#b8860b;--color-code-rule:#4682b4;--color-code-doctype:gray;--color-code-cdata:gray;--color-code-prolog:gray;--color-code-namespace:gray;--color-code-important:#b8860b;--color-code-inserted:#228b22;--color-code-deleted:#dc143c;--color-code-char:#8b4513}.dark{--color-code-keyword:#f4a460;--color-code-string:#deb887;--color-code-comment:#8b8b8b;--color-code-function:#daa520;--color-code-number:tan;--color-code-operator:wheat;--color-code-class-name:peru;--color-code-tag:#87ceeb;--color-code-attr-name:gold;--color-code-attr-value:#deb887;--color-code-property:tan;--color-code-selector:#87ceeb;--color-code-punctuation:wheat;--color-code-builtin:#f4a460;--color-code-constant:tan;--color-code-boolean:tan;--color-code-regex:#deb887;--color-code-symbol:peru;--color-code-entity:peru;--color-code-url:tan;--color-code-atrule:#f4a460;--color-code-rule:#98fb98;--color-code-doctype:#8b8b8b;--color-code-cdata:#8b8b8b;--color-code-prolog:#8b8b8b;--color-code-namespace:#8b8b8b;--color-code-important:#f4a460;--color-code-inserted:#98fb98;--color-code-deleted:#f08080;--color-code-char:#deb887}@layer utilities{.hljs-comment{color:var(--color-code-comment)!important}.hljs-keyword{color:var(--color-code-keyword)!important}.hljs-string{color:var(--color-code-string)!important}.hljs-number{color:var(--color-code-number)!important}.hljs-literal{color:var(--color-code-constant)!important}.hljs-type{color:var(--color-code-class-name)!important}.hljs-variable{color:var(--color-code-property)!important}.hljs-variable.language_{color:var(--color-code-keyword)!important}.hljs-variable.constant_{color:var(--color-code-constant)!important}.hljs-title{color:var(--color-code-function)!important}.hljs-title.class_.inherited__{color:var(--color-code-class-name)!important}.hljs-title.function_.invoke__{color:var(--color-code-function)!important}.hljs-params{color:var(--color-code-property)!important}.hljs-doctag{color:var(--color-code-keyword)!important;font-weight:600!important}.hljs-meta{color:var(--color-code-comment)!important}.hljs-meta.keyword_,.hljs-meta.prompt_{color:var(--color-code-keyword)!important}.hljs-meta.string_{color:var(--color-code-string)!important}.hljs-section{color:var(--color-code-keyword)!important;font-weight:600!important}.hljs-name{color:var(--color-code-tag)!important}.hljs-attribute{color:var(--color-code-attr-name)!important}.hljs-bullet{color:var(--color-code-punctuation)!important}.hljs-code{color:var(--color-code-property)!important}.hljs-formula{color:var(--color-code-number)!important}.hljs-quote{color:var(--color-code-string)!important}.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo{color:var(--color-code-selector)!important}.hljs-template-tag{color:var(--color-code-tag)!important}.hljs-template-variable{color:var(--color-code-property)!important}.hljs-subst{color:var(--color-code-string)!important}}@layer components{:where(code[role=button]){height:fit-content}:where(.code-copied-icon){background-color:currentColor;display:inline-block;height:1em;mask-image:var(--icon-code-copied);mask-position:center;mask-repeat:no-repeat;mask-size:contain;width:1em}:where([x-code],[x-code-group]):not(.unstyle){position:relative;:where(header){align-items:center;background-color:color-mix(in oklch,var(--color-content-stark,#2f4f4f) 8%,transparent);color:var(--color-content-neutral,gray);display:flex;flex-direction:row;font-family:var(--font-sans,sans-serif);font-size:inherit;min-height:var(--spacing-field-height,2.25rem);padding-inline-end:var(--spacing-field-height);padding-inline-start:calc(var(--spacing, .25rem)*4);width:100%;&:has(button[role=tab]){padding-inline-start:calc(var(--spacing, .25rem)*2)}& [role=tablist]{display:flex;flex-direction:row;overflow-x:auto;-ms-overflow-style:none;scrollbar-width:none;& button[role=tab]{background:transparent;border:0;color:inherit;flex-shrink:0;font-family:inherit;font-size:inherit;height:fit-content;justify-content:start;&:hover{background-color:var(--color-field-surface,color-mix(#2f4f4f 10%,transparent));color:var(--color-content-stark,#2f4f4f)}&[aria-selected=true]{color:var(--color-brand-content,#daa520);pointer-events:none;position:relative}}}}& button.copy{background-color:transparent;font-size:75%;inset-inline-end:0;position:absolute;top:0;&:hover{background-color:transparent;&:after{background-color:var(--color-field-inverse,#2f4f4f)}}&:after{background-color:var(--color-content-neutral,gray);content:"";display:block;height:.8125rem;mask-image:var(--icon-code-copy);mask-repeat:no-repeat;mask-size:contain;width:.8125rem}&.copied:after{mask-image:var(--icon-code-copied)}}:where(header)::-webkit-scrollbar{display:none}& .lines{color:var(--color-content-subtle,#a9a9a9);display:inline-flex;flex-direction:column;font-family:inherit;font-size:inherit;inset-inline-start:0;line-height:inherit;padding:calc(var(--spacing, .25rem)*4) 0 calc(var(--spacing, .25rem)*4) calc(var(--spacing, .25rem)*4);pointer-events:none;position:absolute;text-align:end;user-select:none}&:has(.lines) code{padding-inline-start:calc(var(--spacing, .25rem)*6 + 2ch)}:where(code){display:block;flex:1 1 100%;min-width:0;white-space:pre;white-space-collapse:preserve}& button.expand{align-items:center;background:transparent;border:0;border-radius:0;color:var(--color-content-subtle,#a9a9a9);cursor:pointer;display:flex;font-family:var(--font-sans,sans-serif);font-size:inherit;height:var(--spacing-field-height,2.25rem);justify-content:center;order:99;padding:0 calc(var(--spacing, .25rem)*2);transition:var(--transition,all .05s ease-in-out);width:100%;&:hover{background:color-mix(in oklch,var(--color-content-stark,#2f4f4f) 8%,transparent);color:var(--color-content-neutral,gray)}}&[data-collapsed] .lines,&[data-collapsed] code{mask-image:linear-gradient(180deg,#000 0,#000 calc(100% - 3em),transparent calc(100% - .75em),transparent);max-height:calc(var(--collapse-lines, 20)*1.7em + var(--spacing, .25rem)*8);overflow:hidden}:where(aside.frame){border:0;order:1;white-space:normal;white-space-collapse:collapse}}:where([x-code-group]){flex-flow:column;:where([x-code]){background:transparent;border:0;border-radius:0}}:where([x-code]):has(>header){& .lines{top:var(--spacing-field-height,2.25rem)}}}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* Manifest Color Picker */
|
|
2
2
|
|
|
3
3
|
:root {
|
|
4
|
-
--color-picker-swatch: var(--color-line);
|
|
4
|
+
--color-picker-swatch: var(--color-line, color-mix(darkslategray 10%, transparent));
|
|
5
5
|
--icon-color-solid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='lucide lucide-paint-roller-icon lucide-paint-roller'%3E%3Crect width='16' height='6' x='2' y='2' rx='2'/%3E%3Cpath d='M10 16v-2a2 2 0 0 1 2-2h8a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2'/%3E%3Crect width='4' height='6' x='8' y='16' rx='1'/%3E%3C/svg%3E");
|
|
6
6
|
--icon-color-gradient: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='lucide lucide-blend-icon lucide-blend'%3E%3Ccircle cx='9' cy='9' r='7'/%3E%3Ccircle cx='15' cy='15' r='7'/%3E%3C/svg%3E");
|
|
7
7
|
--icon-color-library: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='lucide lucide-swatch-book-icon lucide-swatch-book'%3E%3Cpath d='M11 17a4 4 0 0 1-8 0V5a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2Z'/%3E%3Cpath d='M16.7 13H19a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2H7'/%3E%3Cpath d='M 7 17h.01'/%3E%3Cpath d='m11 8 2.3-2.3a2.4 2.4 0 0 1 3.404.004L18.6 7.6a2.4 2.4 0 0 1 .026 3.434L9.9 19.8'/%3E%3C/svg%3E");
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
border-radius: var(--radius, 0.5rem);
|
|
47
47
|
cursor: pointer;
|
|
48
48
|
overflow: hidden;
|
|
49
|
-
transition: var(--transition);
|
|
49
|
+
transition: var(--transition, all .05s ease-in-out);
|
|
50
50
|
|
|
51
51
|
&:hover,
|
|
52
52
|
&:active,
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
display: flex;
|
|
84
84
|
width: 100%;
|
|
85
85
|
padding: 2px;
|
|
86
|
-
border-bottom: 1px solid var(--color-line,
|
|
86
|
+
border-bottom: 1px solid var(--color-line, color-mix(darkslategray 10%, transparent));
|
|
87
87
|
|
|
88
88
|
/* Distribute button widths equally */
|
|
89
89
|
& button {
|
|
@@ -258,7 +258,7 @@
|
|
|
258
258
|
|
|
259
259
|
/* Gradient layers */
|
|
260
260
|
& :where(.layer-options-wrapper) {
|
|
261
|
-
border-bottom: 1px solid var(--color-line, color-mix(
|
|
261
|
+
border-bottom: 1px solid var(--color-line, color-mix(darkslategray 10%, transparent));
|
|
262
262
|
|
|
263
263
|
/* Layer options inputs */
|
|
264
264
|
& :where(.layer-options-inputs) {
|
|
@@ -295,7 +295,7 @@
|
|
|
295
295
|
position: absolute;
|
|
296
296
|
top: 0;
|
|
297
297
|
right: 0.25rem;
|
|
298
|
-
color: var(--color-content-neutral,
|
|
298
|
+
color: var(--color-content-neutral, gray)
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
301
|
|
|
@@ -308,7 +308,7 @@
|
|
|
308
308
|
margin-inline-end: 0.5rem;
|
|
309
309
|
border-radius: 1rem;
|
|
310
310
|
cursor: pointer;
|
|
311
|
-
background: var(--color-field-surface,
|
|
311
|
+
background: var(--color-field-surface, color-mix(darkslategray 10%, transparent));
|
|
312
312
|
|
|
313
313
|
/* Stop handle */
|
|
314
314
|
& :where(.stop-handle) {
|
|
@@ -400,7 +400,7 @@
|
|
|
400
400
|
|
|
401
401
|
/* Only apply border to all except last library-group */
|
|
402
402
|
&:not(:last-child) {
|
|
403
|
-
border-bottom: 1px solid var(--color-line, color-mix(
|
|
403
|
+
border-bottom: 1px solid var(--color-line, color-mix(darkslategray 10%, transparent));
|
|
404
404
|
}
|
|
405
405
|
|
|
406
406
|
/* Palette wrapper */
|
|
@@ -441,7 +441,7 @@
|
|
|
441
441
|
padding: 0;
|
|
442
442
|
|
|
443
443
|
& .tabs-wrapper button {
|
|
444
|
-
border: 1px solid var(--color-popover-surface,
|
|
444
|
+
border: 1px solid var(--color-popover-surface, white)
|
|
445
445
|
}
|
|
446
446
|
}
|
|
447
447
|
|
|
@@ -490,17 +490,17 @@
|
|
|
490
490
|
}
|
|
491
491
|
|
|
492
492
|
.gradient-layer-icon-linear {
|
|
493
|
-
background: linear-gradient(to right, var(--color-content-neutral,
|
|
493
|
+
background: linear-gradient(to right, var(--color-content-neutral, gray), color-mix(in oklch, var(--color-content-neutral, gray) 0%, transparent 100%));
|
|
494
494
|
border-radius: 50%
|
|
495
495
|
}
|
|
496
496
|
|
|
497
497
|
.gradient-layer-icon-radial {
|
|
498
|
-
background: radial-gradient(var(--color-content-neutral,
|
|
498
|
+
background: radial-gradient(var(--color-content-neutral, gray), color-mix(in oklch, var(--color-content-neutral, gray) 0%, transparent 100%));
|
|
499
499
|
border-radius: 50%
|
|
500
500
|
}
|
|
501
501
|
|
|
502
502
|
.gradient-layer-icon-conic {
|
|
503
|
-
background: conic-gradient(var(--color-content-neutral,
|
|
503
|
+
background: conic-gradient(var(--color-content-neutral, gray), color-mix(in oklch, var(--color-content-neutral, gray) 0%, transparent 100%));
|
|
504
504
|
border-radius: 50%
|
|
505
505
|
}
|
|
506
506
|
}
|
|
@@ -8,7 +8,7 @@ window.getManifestBase = function getManifestBase() {
|
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
// Absolute pathname prefix for the app root (e.g. "/src/dist"). Used by router for links and route matching.
|
|
11
|
-
// Prerender injects <meta name="manifest:router-base" content="/path"> from manifest.
|
|
11
|
+
// Prerender injects <meta name="manifest:router-base" content="/path"> from manifest.render.routerBase or root+output. If present, use it; else fall back to depth or manifest link.
|
|
12
12
|
window.getManifestBasePath = function getManifestBasePath() {
|
|
13
13
|
const baseMeta = document.querySelector('meta[name="manifest:router-base"]');
|
|
14
14
|
const content = baseMeta?.getAttribute('content');
|
|
@@ -149,6 +149,28 @@ window.ManifestComponentsLoader = {
|
|
|
149
149
|
};
|
|
150
150
|
|
|
151
151
|
// Components processor
|
|
152
|
+
|
|
153
|
+
// Escape a string so it's safe to interpolate inside a single-quoted JS
|
|
154
|
+
// string AND inside backtick template literals. The original escape covered
|
|
155
|
+
// the single-quote + whitespace cases but missed three vectors that matter
|
|
156
|
+
// when component templates use backtick literals (e.g. x-text="`Hi $modify('n')`"):
|
|
157
|
+
// - `\` → a trailing backslash would escape the closing quote
|
|
158
|
+
// - `` ` `` → terminates a backtick template literal
|
|
159
|
+
// - `${` → opens an interpolation that Alpine evaluates as JS
|
|
160
|
+
// Without escaping those, a bound value like `${alert(1)}` from a data
|
|
161
|
+
// source becomes code execution inside the wrapping template literal.
|
|
162
|
+
// Backslash must be escaped FIRST so the other replacements don't compound.
|
|
163
|
+
function escapeForSingleQuotedJsString(s) {
|
|
164
|
+
return String(s)
|
|
165
|
+
.replace(/\\/g, '\\\\')
|
|
166
|
+
.replace(/'/g, "\\'")
|
|
167
|
+
.replace(/`/g, '\\`')
|
|
168
|
+
.replace(/\$\{/g, '\\${')
|
|
169
|
+
.replace(/\r/g, '\\r')
|
|
170
|
+
.replace(/\n/g, '\\n')
|
|
171
|
+
.replace(/\t/g, '\\t');
|
|
172
|
+
}
|
|
173
|
+
|
|
152
174
|
window.ManifestComponentsProcessor = {
|
|
153
175
|
async processComponent(element, instanceId) {
|
|
154
176
|
const name = element.tagName.toLowerCase().replace('x-', '');
|
|
@@ -295,7 +317,7 @@ window.ManifestComponentsProcessor = {
|
|
|
295
317
|
return val;
|
|
296
318
|
}
|
|
297
319
|
// Always quote string values to ensure they're treated as strings, not variables
|
|
298
|
-
return `'${val
|
|
320
|
+
return `'${escapeForSingleQuotedJsString(val)}'`;
|
|
299
321
|
}
|
|
300
322
|
);
|
|
301
323
|
el.setAttribute(attr.name, newValue);
|
|
@@ -310,7 +332,7 @@ window.ManifestComponentsProcessor = {
|
|
|
310
332
|
el.setAttribute(attr.name, propValue);
|
|
311
333
|
} else {
|
|
312
334
|
// Always quote string values and escape special characters
|
|
313
|
-
const quotedValue = `'${propValue
|
|
335
|
+
const quotedValue = `'${escapeForSingleQuotedJsString(propValue)}'`;
|
|
314
336
|
el.setAttribute(attr.name, quotedValue);
|
|
315
337
|
}
|
|
316
338
|
}
|
|
@@ -776,158 +798,6 @@ window.ManifestComponentsMutation = {
|
|
|
776
798
|
}
|
|
777
799
|
};
|
|
778
800
|
|
|
779
|
-
// Components — route-level prefetch.
|
|
780
|
-
//
|
|
781
|
-
// Two enhancements that run on top of the existing on-encounter loader:
|
|
782
|
-
//
|
|
783
|
-
// 1. Parallel batch on route change. When manifest:route-change fires,
|
|
784
|
-
// scan the [x-route] subtrees that match the new route and call
|
|
785
|
-
// loadComponent() on every <x-*> tag inside them. The loader
|
|
786
|
-
// deduplicates fetches, so calling it for components that the
|
|
787
|
-
// regular swapping logic is already mounting is harmless — but
|
|
788
|
-
// pre-issuing in parallel saves 50–200 ms vs. one-by-one fetches.
|
|
789
|
-
//
|
|
790
|
-
// 2. Prefetch on hover. When the pointer enters an internal <a href>,
|
|
791
|
-
// derive the target pathname, find the [x-route] subtree(s) that
|
|
792
|
-
// would match it, and prefetch their components. By the time the
|
|
793
|
-
// user clicks the link, the components are warm in the loader's
|
|
794
|
-
// cache and navigation feels instant.
|
|
795
|
-
//
|
|
796
|
-
// Both phases require zero author configuration. Manifest auto-discovers
|
|
797
|
-
// what to prefetch from the existing [x-route] DOM structure.
|
|
798
|
-
|
|
799
|
-
(function () {
|
|
800
|
-
'use strict';
|
|
801
|
-
|
|
802
|
-
// <x-*> tag pattern — lowercase, hyphenated.
|
|
803
|
-
const TAG_RE = /^x-[a-z][a-z0-9-]*$/;
|
|
804
|
-
|
|
805
|
-
// Framework-provided web components (registered by Manifest plugins
|
|
806
|
-
// themselves, not as project components in manifest.json). Skip these
|
|
807
|
-
// when scanning for project components to prefetch.
|
|
808
|
-
const FRAMEWORK_TAGS = new Set(['code', 'code-group']);
|
|
809
|
-
|
|
810
|
-
// Anchors we've already issued a hover-prefetch for. WeakSet so DOM
|
|
811
|
-
// garbage-collects naturally as elements leave the tree.
|
|
812
|
-
const prefetchedAnchors = new WeakSet();
|
|
813
|
-
|
|
814
|
-
function loader() { return window.ManifestComponentsLoader; }
|
|
815
|
-
|
|
816
|
-
// Match a single route pattern against a normalized pathname (no
|
|
817
|
-
// leading/trailing slashes, '/' represented as '/'). Mirrors the
|
|
818
|
-
// router visibility logic so prefetch targets the same subtrees.
|
|
819
|
-
function routeMatches(routeValue, pathname) {
|
|
820
|
-
const pieces = String(routeValue || '').split(',').map((s) => s.trim()).filter(Boolean);
|
|
821
|
-
let matched = false;
|
|
822
|
-
let negated = false;
|
|
823
|
-
for (const piece of pieces) {
|
|
824
|
-
if (piece === '!*') continue; // catch-all only handled by visibility plugin
|
|
825
|
-
if (piece.startsWith('!')) {
|
|
826
|
-
if (piece.slice(1) === pathname) negated = true;
|
|
827
|
-
continue;
|
|
828
|
-
}
|
|
829
|
-
if (piece.startsWith('=')) {
|
|
830
|
-
if (piece.slice(1) === pathname) matched = true;
|
|
831
|
-
continue;
|
|
832
|
-
}
|
|
833
|
-
if (piece.endsWith('/*')) {
|
|
834
|
-
const prefix = piece.slice(0, -2);
|
|
835
|
-
if (pathname === prefix || pathname.startsWith(prefix + '/')) matched = true;
|
|
836
|
-
continue;
|
|
837
|
-
}
|
|
838
|
-
if (piece === pathname) { matched = true; continue; }
|
|
839
|
-
if (pathname.startsWith(piece + '/')) matched = true;
|
|
840
|
-
}
|
|
841
|
-
return matched && !negated;
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
function findRouteSubtrees(pathname) {
|
|
845
|
-
const normalized = (pathname || '/') === '/' ? '/' : pathname.replace(/^\/|\/$/g, '');
|
|
846
|
-
const out = [];
|
|
847
|
-
document.querySelectorAll('[x-route]').forEach((el) => {
|
|
848
|
-
const value = el.getAttribute('x-route') || '';
|
|
849
|
-
if (routeMatches(value, normalized)) out.push(el);
|
|
850
|
-
});
|
|
851
|
-
return out;
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
function discoverComponentNames(root) {
|
|
855
|
-
const names = new Set();
|
|
856
|
-
if (!root || !root.querySelectorAll) return names;
|
|
857
|
-
// querySelectorAll('*') is the fastest path for "every descendant".
|
|
858
|
-
// We filter by tag name in JS — there's no CSS selector for "tag
|
|
859
|
-
// name starts with x-". A page typically has a few thousand nodes,
|
|
860
|
-
// which scans in well under a millisecond.
|
|
861
|
-
root.querySelectorAll('*').forEach((el) => {
|
|
862
|
-
const tag = el.tagName.toLowerCase();
|
|
863
|
-
if (!tag.startsWith('x-') || !TAG_RE.test(tag)) return;
|
|
864
|
-
const name = tag.slice(2);
|
|
865
|
-
if (!FRAMEWORK_TAGS.has(name)) names.add(name);
|
|
866
|
-
});
|
|
867
|
-
return names;
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
function prefetchForRoute(pathname) {
|
|
871
|
-
const L = loader();
|
|
872
|
-
if (!L || typeof L.loadComponent !== 'function') return;
|
|
873
|
-
const subtrees = findRouteSubtrees(pathname);
|
|
874
|
-
if (!subtrees.length) return;
|
|
875
|
-
const names = new Set();
|
|
876
|
-
for (const subtree of subtrees) {
|
|
877
|
-
discoverComponentNames(subtree).forEach((n) => names.add(n));
|
|
878
|
-
}
|
|
879
|
-
names.forEach((name) => {
|
|
880
|
-
try { L.loadComponent(name); } catch { /* swallow — dedup is internal */ }
|
|
881
|
-
});
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
function hrefToPathname(href) {
|
|
885
|
-
if (!href) return null;
|
|
886
|
-
if (/^(#|mailto:|tel:|javascript:)/i.test(href)) return null;
|
|
887
|
-
try {
|
|
888
|
-
const url = new URL(href, window.location.href);
|
|
889
|
-
if (url.origin !== window.location.origin) return null;
|
|
890
|
-
return url.pathname || '/';
|
|
891
|
-
} catch {
|
|
892
|
-
return null;
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
function initialize() {
|
|
897
|
-
// 1) Parallel batch on route change.
|
|
898
|
-
window.addEventListener('manifest:route-change', (event) => {
|
|
899
|
-
const detail = (event && event.detail) || {};
|
|
900
|
-
const path = detail.normalizedPath || detail.to || '/';
|
|
901
|
-
const pathname = String(path).startsWith('/') ? String(path) : '/' + String(path);
|
|
902
|
-
prefetchForRoute(pathname);
|
|
903
|
-
});
|
|
904
|
-
|
|
905
|
-
// 2) Hover prefetch. Use pointerover (bubbles) and check the closest
|
|
906
|
-
// anchor on each event so we get a single trigger per anchor entry
|
|
907
|
-
// without needing pointerenter (which doesn't bubble). Dedup via
|
|
908
|
-
// a WeakSet so repeat moves within the anchor don't re-scan.
|
|
909
|
-
document.addEventListener('pointerover', (e) => {
|
|
910
|
-
if (!e.target || !e.target.closest) return;
|
|
911
|
-
const a = e.target.closest('a[href]');
|
|
912
|
-
if (!a || prefetchedAnchors.has(a)) return;
|
|
913
|
-
// Author opt-out: `data-no-prefetch` skips this anchor.
|
|
914
|
-
if (a.hasAttribute('data-no-prefetch')) return;
|
|
915
|
-
const href = a.getAttribute('href');
|
|
916
|
-
const pathname = hrefToPathname(href);
|
|
917
|
-
if (!pathname) return;
|
|
918
|
-
prefetchedAnchors.add(a);
|
|
919
|
-
prefetchForRoute(pathname);
|
|
920
|
-
});
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
if (document.readyState === 'loading') {
|
|
924
|
-
document.addEventListener('DOMContentLoaded', initialize);
|
|
925
|
-
} else {
|
|
926
|
-
initialize();
|
|
927
|
-
}
|
|
928
|
-
})();
|
|
929
|
-
|
|
930
|
-
|
|
931
801
|
// Main initialization for Manifest Components
|
|
932
802
|
function initializeComponents() {
|
|
933
803
|
if (window.ManifestComponentsRegistry) window.ManifestComponentsRegistry.initialize();
|