@stacksjs/stx 0.2.155 → 0.2.157
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/dist/a11y.d.ts +87 -46
- package/dist/animation.d.ts +96 -42
- package/dist/appearance-bootstrap.d.ts +49 -15
- package/dist/asset-roots.d.ts +32 -0
- package/dist/asset-roots.js +7 -0
- package/dist/assets.d.ts +9 -7
- package/dist/async-components.d.ts +78 -56
- package/dist/auth.d.ts +3 -0
- package/dist/build-externalize.d.ts +40 -0
- package/dist/build-externalize.js +63 -0
- package/dist/build-id.d.ts +22 -22
- package/dist/build-message.d.ts +73 -2
- package/dist/build-message.js +47 -8
- package/dist/builtins/attrs.d.ts +14 -0
- package/dist/builtins/drawer.d.ts +22 -0
- package/dist/builtins/icon.d.ts +16 -2
- package/dist/builtins/index.d.ts +5 -15
- package/dist/builtins/modal.d.ts +24 -0
- package/dist/builtins/safe-image.d.ts +42 -0
- package/dist/builtins/stx-image.d.ts +27 -0
- package/dist/builtins/stx-link.d.ts +9 -0
- package/dist/builtins/stx-loading-indicator.d.ts +11 -0
- package/dist/builtins/suspense.d.ts +28 -0
- package/dist/builtins/toast.d.ts +17 -0
- package/dist/builtins/transition-group.d.ts +25 -0
- package/dist/caching.d.ts +12 -15
- package/dist/cli.js +1798 -908
- package/dist/client/directive.d.ts +7 -0
- package/dist/client/index.d.ts +0 -1
- package/dist/client-script-bundler.d.ts +63 -5
- package/dist/client-script-bundler.js +30 -2
- package/dist/client-script.d.ts +102 -47
- package/dist/client-script.js +15 -3
- package/dist/codemod.d.ts +56 -0
- package/dist/codemod.js +192 -0
- package/dist/color-mode-boot.d.ts +83 -65
- package/dist/component-client-factories.d.ts +1 -6
- package/dist/component-processing.d.ts +58 -49
- package/dist/component-processing.js +1 -1
- package/dist/component-registry.d.ts +94 -31
- package/dist/component-renderer.d.ts +18 -0
- package/dist/composable-loader.d.ts +24 -0
- package/dist/composable-loader.js +12 -9
- package/dist/composables/index.d.ts +7 -0
- package/dist/composables/index.js +1 -0
- package/dist/composables/use-fetch.js +30 -2
- package/dist/composables/use-form.d.ts +91 -0
- package/dist/composables/use-form.js +112 -0
- package/dist/composables.d.ts +64 -60
- package/dist/computed.d.ts +86 -92
- package/dist/conditionals.d.ts +24 -8
- package/dist/conditionals.js +16 -0
- package/dist/config.d.ts +34 -21
- package/dist/config.js +35 -14
- package/dist/craft.js +1476 -768
- package/dist/crosswind-config.d.ts +58 -0
- package/dist/crosswind-config.js +40 -0
- package/dist/csp.d.ts +107 -41
- package/dist/defer.d.ts +24 -0
- package/dist/dev-server/crosswind.d.ts +35 -26
- package/dist/dev-server/crosswind.js +2 -18
- package/dist/dev-server/serve-app.js +4 -3
- package/dist/dev-server/terminal-colors.d.ts +32 -32
- package/dist/directive-api.d.ts +86 -43
- package/dist/document-shell.d.ts +54 -41
- package/dist/dynamic-components.d.ts +9 -0
- package/dist/error-boundaries.d.ts +47 -41
- package/dist/error-handling.d.ts +1 -1
- package/dist/errors/codes.d.ts +51 -43
- package/dist/errors/formatter.d.ts +58 -38
- package/dist/errors/index.d.ts +5 -61
- package/dist/errors/logger.d.ts +114 -40
- package/dist/errors/sanitizer.d.ts +53 -23
- package/dist/errors/types.d.ts +44 -31
- package/dist/events.d.ts +86 -25
- package/dist/expressions.d.ts +50 -42
- package/dist/forms-validation.d.ts +138 -123
- package/dist/forms-validation.js +1 -90
- package/dist/forms.d.ts +120 -66
- package/dist/forms.js +31 -11
- package/dist/fragment-container.d.ts +57 -0
- package/dist/fragment-container.js +109 -0
- package/dist/framework-composables.d.ts +32 -0
- package/dist/head.d.ts +156 -114
- package/dist/heatmap.d.ts +152 -72
- package/dist/html-masking.d.ts +40 -34
- package/dist/hydration-runtime.d.ts +20 -24
- package/dist/i18n.d.ts +93 -32
- package/dist/image-optimization/auto-sibling.d.ts +32 -4
- package/dist/includes.d.ts +69 -7
- package/dist/index.d.ts +66 -0
- package/dist/index.js +23 -0
- package/dist/internal-markdown.d.ts +12 -8
- package/dist/island-chunking.d.ts +30 -13
- package/dist/keep-alive.d.ts +72 -52
- package/dist/layout-types.d.ts +45 -0
- package/dist/layout-types.js +56 -0
- package/dist/lazy-module.d.ts +10 -0
- package/dist/loops.d.ts +66 -0
- package/dist/loops.js +47 -6
- package/dist/markdown.d.ts +0 -1
- package/dist/media/image/component.d.ts +25 -9
- package/dist/media/image/directive.d.ts +15 -1
- package/dist/media/image/placeholder.d.ts +20 -9
- package/dist/media/image/processor/cache.d.ts +40 -18
- package/dist/media/image/processor/index.d.ts +1 -10
- package/dist/media/image/processor/optimizer.d.ts +12 -1
- package/dist/media/image/processor/responsive.d.ts +16 -6
- package/dist/media/image/srcset.d.ts +47 -50
- package/dist/media/shared/cache.d.ts +51 -31
- package/dist/media/shared/hash.d.ts +7 -0
- package/dist/media/types.d.ts +1235 -754
- package/dist/media/video/directive.d.ts +15 -1
- package/dist/media/video/index.d.ts +39 -17
- package/dist/media/video/processor/cache.d.ts +42 -19
- package/dist/media/video/processor/index.d.ts +1 -18
- package/dist/media/video/processor/streaming.d.ts +17 -10
- package/dist/media/video/processor/thumbnail.d.ts +21 -15
- package/dist/media/video/processor/transcoder.d.ts +11 -1
- package/dist/method-spoofing.d.ts +7 -0
- package/dist/middleware.d.ts +60 -0
- package/dist/owned-routes.d.ts +42 -0
- package/dist/owned-routes.js +26 -0
- package/dist/page-meta.d.ts +38 -0
- package/dist/page-meta.js +16 -0
- package/dist/parser/directive-parser.d.ts +57 -45
- package/dist/parser/expression-parser.d.ts +33 -35
- package/dist/parser/index.d.ts +4 -39
- package/dist/parser/tokenizer.d.ts +61 -49
- package/dist/partial-hydration.d.ts +82 -50
- package/dist/performance-utils.d.ts +217 -124
- package/dist/placeholder.d.ts +18 -9
- package/dist/plugin-system.d.ts +264 -115
- package/dist/process.d.ts +11 -6
- package/dist/process.js +21 -4
- package/dist/production-builder.js +7 -0
- package/dist/prop-sentinels.d.ts +11 -11
- package/dist/public-env.d.ts +14 -0
- package/dist/pwa/directives.d.ts +12 -3
- package/dist/pwa/inject.d.ts +10 -0
- package/dist/pwa/precache.d.ts +22 -16
- package/dist/pwa/service-worker.d.ts +12 -0
- package/dist/pwa.js +1318 -610
- package/dist/reactive-bindings.d.ts +34 -11
- package/dist/reactive.d.ts +58 -30
- package/dist/reactive.js +56 -31
- package/dist/render.d.ts +0 -14
- package/dist/render.js +17 -0
- package/dist/route-middleware.d.ts +2 -35
- package/dist/route-types.d.ts +134 -0
- package/dist/route-types.js +24 -0
- package/dist/router.d.ts +5 -7
- package/dist/routes.d.ts +1 -3
- package/dist/runtime-globals.d.ts +147 -24
- package/dist/runtime-globals.js +16 -1
- package/dist/runtime-injection.d.ts +8 -0
- package/dist/runtime-injection.js +33 -24
- package/dist/script-emit.d.ts +30 -0
- package/dist/script-json.d.ts +36 -0
- package/dist/script-json.js +6 -0
- package/dist/script-validation.d.ts +21 -4
- package/dist/seo.d.ts +118 -47
- package/dist/server-bindings.d.ts +21 -0
- package/dist/sfc-template.d.ts +8 -8
- package/dist/signal-processing.d.ts +35 -15
- package/dist/signals-api.d.ts +117 -58
- package/dist/signals-api.js +7 -4
- package/dist/signals.d.ts +24 -17
- package/dist/signals.js +765 -60
- package/dist/site-builder/build.js +8 -0
- package/dist/site-url.d.ts +46 -0
- package/dist/site-url.js +70 -0
- package/dist/slots.d.ts +86 -20
- package/dist/source-signature.d.ts +45 -0
- package/dist/source-signature.js +20 -0
- package/dist/ssg.d.ts +285 -142
- package/dist/ssg.js +1268 -556
- package/dist/state-dir.d.ts +4 -4
- package/dist/state-management.d.ts +0 -12
- package/dist/state-management.js +8 -25
- package/dist/store-imports.d.ts +23 -0
- package/dist/store-imports.js +3 -0
- package/dist/store-loader.d.ts +10 -0
- package/dist/store-loader.js +10 -9
- package/dist/story/analytics.d.ts +138 -60
- package/dist/story/bookmarks.d.ts +87 -34
- package/dist/story/cli.d.ts +123 -69
- package/dist/story/collect/scanner.d.ts +4 -0
- package/dist/story/collect/tree.d.ts +8 -1
- package/dist/story/commands/build.d.ts +11 -6
- package/dist/story/commands/dev.d.ts +15 -8
- package/dist/story/commands/preview.d.ts +13 -7
- package/dist/story/config-watcher.d.ts +20 -13
- package/dist/story/config.d.ts +11 -8
- package/dist/story/context.d.ts +14 -8
- package/dist/story/hmr.d.ts +24 -26
- package/dist/story/hot-swap.d.ts +34 -23
- package/dist/story/keyboard-shortcuts.d.ts +23 -18
- package/dist/story/output.d.ts +46 -44
- package/dist/story/performance.d.ts +107 -45
- package/dist/story/presets.d.ts +107 -41
- package/dist/story/renderer.d.ts +41 -27
- package/dist/story/search.d.ts +23 -12
- package/dist/story/server.d.ts +21 -11
- package/dist/story/setup.d.ts +23 -15
- package/dist/story/testing.d.ts +65 -40
- package/dist/story/types.d.ts +262 -160
- package/dist/streaming.d.ts +119 -57
- package/dist/stx-virtual-ts.d.ts +165 -0
- package/dist/stx-virtual-ts.js +372 -0
- package/dist/stx.d.ts +78 -1
- package/dist/style-scoping.d.ts +17 -4
- package/dist/suspense.d.ts +67 -52
- package/dist/teleport.d.ts +22 -0
- package/dist/template-tag-balance.d.ts +22 -6
- package/dist/transitions.d.ts +66 -55
- package/dist/typecheck.d.ts +77 -0
- package/dist/typecheck.js +156 -0
- package/dist/types/component-types.d.ts +187 -122
- package/dist/types/config-types.d.ts +758 -297
- package/dist/types/context-types.d.ts +46 -24
- package/dist/types/csp-types.d.ts +70 -66
- package/dist/types/directive-types.d.ts +211 -155
- package/dist/types/index.d.ts +6 -109
- package/dist/types/pwa-types.d.ts +273 -148
- package/dist/types.d.ts +0 -1
- package/dist/typescript-templates.d.ts +11 -0
- package/dist/unresolved-identifiers.d.ts +24 -22
- package/dist/unresolved-identifiers.js +2 -0
- package/dist/utils.d.ts +24 -21
- package/dist/validator.d.ts +28 -26
- package/dist/variable-extractor.d.ts +48 -13
- package/dist/variable-extractor.js +27 -4
- package/dist/view-composers.d.ts +80 -81
- package/dist/virtual-scrolling.d.ts +101 -81
- package/dist/vue-template.d.ts +23 -0
- package/dist/web-components/css-scoping.d.ts +21 -11
- package/dist/web-components.d.ts +81 -58
- package/dist/x-element.d.ts +0 -1
- package/package.json +5 -5
- package/stx.d.ts +78 -1
package/dist/forms.js
CHANGED
|
@@ -20,6 +20,24 @@ function buildClassString(existingClass, defaultClass, hasError, errorClass) {
|
|
|
20
20
|
const baseClass = existingClass || defaultClass;
|
|
21
21
|
return hasError ? `${baseClass} ${errorClass}` : baseClass;
|
|
22
22
|
}
|
|
23
|
+
function fieldId(name) {
|
|
24
|
+
return String(name).replace(/\[\]$/, "").replace(/[^\w.:-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
25
|
+
}
|
|
26
|
+
function idAttr(attrs, fallbackId) {
|
|
27
|
+
if (/\bid\s*=/i.test(attrs))
|
|
28
|
+
return "";
|
|
29
|
+
return ` id="${escapeAttr(fallbackId)}"`;
|
|
30
|
+
}
|
|
31
|
+
function errorAria(name, hasError, attrs) {
|
|
32
|
+
if (!hasError)
|
|
33
|
+
return "";
|
|
34
|
+
let out = "";
|
|
35
|
+
if (!/\baria-invalid\s*=/i.test(attrs))
|
|
36
|
+
out += ' aria-invalid="true"';
|
|
37
|
+
if (!/\baria-describedby\s*=/i.test(attrs))
|
|
38
|
+
out += ` aria-describedby="${escapeAttr(`${fieldId(name)}-error`)}"`;
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
23
41
|
function genId() {
|
|
24
42
|
return crypto.randomUUID();
|
|
25
43
|
}
|
|
@@ -70,11 +88,11 @@ export function processFormInputDirectives(template, context, classes = defaultF
|
|
|
70
88
|
const name = singleQuoteName || doubleQuoteName || "", value = singleQuoteValue || doubleQuoteValue || "", attrs = parseAttributes(attributes), rawOldValue = getOldValue(name, context), oldValue = rawOldValue !== void 0 && rawOldValue !== null ? rawOldValue : value || "", typeMatch = attrs.match(/type=['"]([^'"]+)['"]/i), type = typeMatch ? typeMatch[1] : "text", hasError = hasFieldError(name, context), classMatch = attrs.match(/class=['"]([^'"]+)['"]/i), className = buildClassString(classMatch ? classMatch[1] : "", classes.input, hasError, classes.inputError);
|
|
71
89
|
let attrsWithoutClassAndType = attrs.replace(/class=['"][^'"]+['"]/i, "");
|
|
72
90
|
attrsWithoutClassAndType = attrsWithoutClassAndType.replace(/type=['"][^'"]+['"]/i, "");
|
|
73
|
-
return `<input type="${escapeAttr(type)}" name="${escapeAttr(name)}" value="${escapeAttr(oldValue)}" class="${className}"${attrsWithoutClassAndType ? ` ${attrsWithoutClassAndType}` : ""}>`;
|
|
91
|
+
return `<input type="${escapeAttr(type)}" name="${escapeAttr(name)}"${idAttr(attrs, fieldId(name))} value="${escapeAttr(oldValue)}" class="${className}"${errorAria(name, hasError, attrs)}${attrsWithoutClassAndType ? ` ${attrsWithoutClassAndType}` : ""}>`;
|
|
74
92
|
});
|
|
75
93
|
result = result.replace(/@textarea\(\s*['"]([^'"]+)['"]\s*(?:,\s*\{([^}]+)\})?\)([\s\S]*?)@endtextarea/g, (_match, name, attributes = "", content = "") => {
|
|
76
94
|
const attrs = parseAttributes(attributes), oldValue = getOldValue(name, context) || content.trim(), hasError = hasFieldError(name, context), classMatch = attrs.match(/class=['"]([^'"]+)['"]/i), className = buildClassString(classMatch ? classMatch[1] : "", classes.input, hasError, classes.inputError), attrsWithoutClass = attrs.replace(/class=['"][^'"]+['"]/i, "");
|
|
77
|
-
return `<textarea name="${escapeAttr(name)}" class="${className}"${attrsWithoutClass ? ` ${attrsWithoutClass}` : ""}>${escapeAttr(oldValue)}</textarea>`;
|
|
95
|
+
return `<textarea name="${escapeAttr(name)}"${idAttr(attrs, fieldId(name))} class="${className}"${errorAria(name, hasError, attrs)}${attrsWithoutClass ? ` ${attrsWithoutClass}` : ""}>${escapeAttr(oldValue)}</textarea>`;
|
|
78
96
|
});
|
|
79
97
|
result = result.replace(/@select\(\s*['"]([^'"]+)['"]\s*(?:,\s*\{([^}]+)\})?\)([\s\S]*?)@endselect/g, (_match, name, attributes = "", content) => {
|
|
80
98
|
const attrs = parseAttributes(attributes), oldValue = getOldValue(name, context), hasError = hasFieldError(name, context), classMatch = attrs.match(/class=['"]([^'"]+)['"]/i), className = buildClassString(classMatch ? classMatch[1] : "", classes.input, hasError, classes.inputError), attrsWithoutClass = attrs.replace(/class=['"][^'"]+['"]/i, "");
|
|
@@ -85,19 +103,19 @@ export function processFormInputDirectives(template, context, classes = defaultF
|
|
|
85
103
|
return optionTag.replace(/(<option)/, "$1 selected");
|
|
86
104
|
return optionMatch;
|
|
87
105
|
});
|
|
88
|
-
return `<select name="${escapeAttr(name)}" class="${className}"${attrsWithoutClass ? ` ${attrsWithoutClass}` : ""}>${processedContent}</select>`;
|
|
106
|
+
return `<select name="${escapeAttr(name)}"${idAttr(attrs, fieldId(name))} class="${className}"${errorAria(name, hasError, attrs)}${attrsWithoutClass ? ` ${attrsWithoutClass}` : ""}>${processedContent}</select>`;
|
|
89
107
|
});
|
|
90
|
-
result = result.replace(/@checkbox\(\s*['"]([^'"]+)['"]\s*(?:,\s*['"]([^'"]+)['"]\s*)?(?:,\s*\{([^}]+)\})?\)/g, (_match, name,
|
|
91
|
-
const attrs = parseAttributes(attributes), oldValues = getOldValue(name, context), isChecked = oldValues !== void 0 && (Array.isArray(oldValues) ? oldValues.some((v) => String(v) === value) : oldValues === !0 || String(oldValues) === value), classMatch = attrs.match(/class=['"]([^'"]+)['"]/i), className = classMatch ? classMatch[1] : classes.checkInput, attrsWithoutClass = attrs.replace(/class=['"][^'"]+['"]/i, "");
|
|
92
|
-
return `<input type="checkbox" name="${escapeAttr(name)}" value="${escapeAttr(value)}" class="${className}"${isChecked ? " checked" : ""}${attrsWithoutClass ? ` ${attrsWithoutClass}` : ""}>`;
|
|
108
|
+
result = result.replace(/@checkbox\(\s*['"]([^'"]+)['"]\s*(?:,\s*['"]([^'"]+)['"]\s*)?(?:,\s*\{([^}]+)\})?\)/g, (_match, name, rawValue, attributes = "") => {
|
|
109
|
+
const value = rawValue === void 0 ? "1" : rawValue, controlId = rawValue === void 0 ? fieldId(name) : `${fieldId(name)}-${fieldId(value)}`, attrs = parseAttributes(attributes), oldValues = getOldValue(name, context), isChecked = oldValues !== void 0 && (Array.isArray(oldValues) ? oldValues.some((v) => String(v) === value) : oldValues === !0 || String(oldValues) === value), classMatch = attrs.match(/class=['"]([^'"]+)['"]/i), className = classMatch ? classMatch[1] : classes.checkInput, attrsWithoutClass = attrs.replace(/class=['"][^'"]+['"]/i, "");
|
|
110
|
+
return `<input type="checkbox" name="${escapeAttr(name)}"${idAttr(attrs, controlId)} value="${escapeAttr(value)}" class="${className}"${isChecked ? " checked" : ""}${attrsWithoutClass ? ` ${attrsWithoutClass}` : ""}>`;
|
|
93
111
|
});
|
|
94
112
|
result = result.replace(/@radio\(\s*['"]([^'"]+)['"]\s*,\s*['"]([^'"]+)['"]\s*(?:,\s*\{([^}]+)\})?\)/g, (_match, name, value, attributes = "") => {
|
|
95
113
|
const attrs = parseAttributes(attributes), oldValue = getOldValue(name, context), isChecked = oldValue !== void 0 && oldValue === value, classMatch = attrs.match(/class=['"]([^'"]+)['"]/i), className = classMatch ? classMatch[1] : classes.checkInput, attrsWithoutClass = attrs.replace(/class=['"][^'"]+['"]/i, "");
|
|
96
|
-
return `<input type="radio" name="${escapeAttr(name)}" value="${escapeAttr(value)}" class="${className}"${isChecked ? " checked" : ""}${attrsWithoutClass ? ` ${attrsWithoutClass}` : ""}>`;
|
|
114
|
+
return `<input type="radio" name="${escapeAttr(name)}"${idAttr(attrs, `${fieldId(name)}-${fieldId(value)}`)} value="${escapeAttr(value)}" class="${className}"${isChecked ? " checked" : ""}${attrsWithoutClass ? ` ${attrsWithoutClass}` : ""}>`;
|
|
97
115
|
});
|
|
98
116
|
result = result.replace(/@file\(\s*['"]([^'"]+)['"]\s*(?:,\s*\{([^}]+)\})?\)/g, (_match, name, attributes = "") => {
|
|
99
117
|
const attrs = parseAttributes(attributes), acceptMatch = attrs.match(/accept=['"]([^'"]+)['"]/i), accept = acceptMatch ? acceptMatch[1] : "", isMultiple = attrs.includes("multiple"), hasError = hasFieldError(name, context), classMatch = attrs.match(/class=['"]([^'"]+)['"]/i), className = buildClassString(classMatch ? classMatch[1] : "", classes.input, hasError, classes.inputError), attrsWithoutHandled = attrs.replace(/class=['"][^'"]+['"]/gi, "").replace(/accept=['"][^'"]+['"]/gi, "").replace(/\bmultiple\b/gi, "").trim(), parts = [
|
|
100
|
-
`<input type="file" name="${escapeAttr(name)}"`,
|
|
118
|
+
`<input type="file" name="${escapeAttr(name)}"${idAttr(attrs, fieldId(name))}`,
|
|
101
119
|
`class="${className}"`
|
|
102
120
|
];
|
|
103
121
|
if (accept)
|
|
@@ -110,15 +128,15 @@ export function processFormInputDirectives(template, context, classes = defaultF
|
|
|
110
128
|
});
|
|
111
129
|
result = result.replace(/@label\(\s*['"]([^'"]+)['"]\s*(?:,\s*\{([^}]+)\})?\)([\s\S]*?)@endlabel/g, (_match, forAttr, attributes = "", content) => {
|
|
112
130
|
const attrs = parseAttributes(attributes), classMatch = attrs.match(/class=['"]([^'"]+)['"]/i), className = classMatch ? classMatch[1] : classes.label, attrsWithoutClass = attrs.replace(/class=['"][^'"]+['"]/i, "");
|
|
113
|
-
return `<label for="${escapeAttr(forAttr)}" class="${className}"${attrsWithoutClass ? ` ${attrsWithoutClass}` : ""}>${content}</label>`;
|
|
131
|
+
return `<label for="${escapeAttr(fieldId(forAttr))}" class="${className}"${attrsWithoutClass ? ` ${attrsWithoutClass}` : ""}>${content}</label>`;
|
|
114
132
|
});
|
|
115
133
|
return result;
|
|
116
134
|
}
|
|
117
135
|
export function processErrorDirective(template, context, _classes = defaultFormClasses) {
|
|
118
136
|
return template.replace(/@error\(['"]([^'"]+)['"]\)([\s\S]*?)@enderror/g, (match, field, content) => {
|
|
119
137
|
try {
|
|
120
|
-
if (hasFieldError(field, context))
|
|
121
|
-
|
|
138
|
+
if (hasFieldError(field, context)) {
|
|
139
|
+
const rendered = content.replace(/\{\{([^}]+)\}\}/g, (_, expr) => {
|
|
122
140
|
try {
|
|
123
141
|
if (expr.trim() === "$message" || expr.trim() === "message")
|
|
124
142
|
return getErrorMessage(field, context);
|
|
@@ -137,6 +155,8 @@ export function processErrorDirective(template, context, _classes = defaultFormC
|
|
|
137
155
|
return expr;
|
|
138
156
|
}
|
|
139
157
|
});
|
|
158
|
+
return `<div id="${escapeAttr(`${fieldId(field)}-error`)}" role="alert">${rendered}</div>`;
|
|
159
|
+
}
|
|
140
160
|
return "";
|
|
141
161
|
} catch (error) {
|
|
142
162
|
console.error("Error processing @error directive:", error);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse the supported subset of CSS selector syntax.
|
|
3
|
+
*
|
|
4
|
+
* Returns null for anything unsupported (descendant combinators, `:has()`,
|
|
5
|
+
* comma lists) rather than guessing — a wrong container is worse than a
|
|
6
|
+
* reported one.
|
|
7
|
+
*/
|
|
8
|
+
export declare function parseContainerSelector(selector: string): ParsedSelector | null;
|
|
9
|
+
/**
|
|
10
|
+
* Find the region of `html` occupied by the first element matching `selector`.
|
|
11
|
+
*
|
|
12
|
+
* The closing tag is found by depth counting over same-named tags, so a
|
|
13
|
+
* container that contains another element of the same name — or a page that has
|
|
14
|
+
* two of them — resolves to the container's OWN close rather than the last one
|
|
15
|
+
* in the document.
|
|
16
|
+
*/
|
|
17
|
+
export declare function findContainerRegion(html: string, selector?: string): ContainerRegion | null;
|
|
18
|
+
/**
|
|
19
|
+
* Locating the SPA swap container in rendered HTML.
|
|
20
|
+
*
|
|
21
|
+
* The client resolves the container with a CSS selector (`router.container`,
|
|
22
|
+
* falling back to `[data-stx-content]` then `main`). The server used to ignore
|
|
23
|
+
* that entirely and string-slice from the first `<main …>` to the LAST
|
|
24
|
+
* `</main>`, which produced three separate failures:
|
|
25
|
+
*
|
|
26
|
+
* - configuring `router: { container: '[data-stx-content]' }` still produced a
|
|
27
|
+
* `<main>`-shaped fragment, which the client then injected into a different
|
|
28
|
+
* element, duplicating the page chrome;
|
|
29
|
+
* - a page with two `<main>` elements swapped everything between the first open
|
|
30
|
+
* and the last close, i.e. the wrong span;
|
|
31
|
+
* - a page with no `<main>` shipped its whole body as the "fragment", silently
|
|
32
|
+
* disabling SPA navigation for every link on it, at HTTP 200.
|
|
33
|
+
*
|
|
34
|
+
* This module resolves the same selector the client uses and finds the container's
|
|
35
|
+
* OWN matching close tag by depth counting, so nesting and repetition behave.
|
|
36
|
+
*
|
|
37
|
+
* It is deliberately a small matcher, not a CSS engine: it covers the selector
|
|
38
|
+
* shapes a swap container realistically uses — a tag name, an attribute, an id,
|
|
39
|
+
* a class, and a tag qualified by one of those. Anything else returns null, and
|
|
40
|
+
* the caller is expected to say so rather than silently ship the whole body.
|
|
41
|
+
*
|
|
42
|
+
* @module fragment-container
|
|
43
|
+
*/
|
|
44
|
+
export declare interface ContainerRegion {
|
|
45
|
+
openTag: string
|
|
46
|
+
openIndex: number
|
|
47
|
+
start: number
|
|
48
|
+
end: number
|
|
49
|
+
tagName: string
|
|
50
|
+
}
|
|
51
|
+
declare interface ParsedSelector {
|
|
52
|
+
tag?: string
|
|
53
|
+
attr?: string
|
|
54
|
+
attrValue?: string
|
|
55
|
+
id?: string
|
|
56
|
+
className?: string
|
|
57
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const VOID_ELEMENTS = new Set([
|
|
2
|
+
"area",
|
|
3
|
+
"base",
|
|
4
|
+
"br",
|
|
5
|
+
"col",
|
|
6
|
+
"embed",
|
|
7
|
+
"hr",
|
|
8
|
+
"img",
|
|
9
|
+
"input",
|
|
10
|
+
"link",
|
|
11
|
+
"meta",
|
|
12
|
+
"param",
|
|
13
|
+
"source",
|
|
14
|
+
"track",
|
|
15
|
+
"wbr"
|
|
16
|
+
]);
|
|
17
|
+
export function parseContainerSelector(selector) {
|
|
18
|
+
const trimmed = (selector || "").trim();
|
|
19
|
+
if (!trimmed)
|
|
20
|
+
return null;
|
|
21
|
+
if (/[\s>+~,:]/.test(trimmed))
|
|
22
|
+
return null;
|
|
23
|
+
const parsed = {};
|
|
24
|
+
let rest = trimmed;
|
|
25
|
+
const tagMatch = rest.match(/^[a-z][\w-]*/i);
|
|
26
|
+
if (tagMatch) {
|
|
27
|
+
parsed.tag = tagMatch[0].toLowerCase();
|
|
28
|
+
rest = rest.slice(tagMatch[0].length);
|
|
29
|
+
}
|
|
30
|
+
while (rest.length > 0) {
|
|
31
|
+
const attr = rest.match(/^\[([\w-]+)(?:=(["']?)([^\]"']*)\2)?\]/);
|
|
32
|
+
if (attr) {
|
|
33
|
+
parsed.attr = attr[1];
|
|
34
|
+
if (attr[3] !== void 0 && attr[3] !== "")
|
|
35
|
+
parsed.attrValue = attr[3];
|
|
36
|
+
rest = rest.slice(attr[0].length);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const id = rest.match(/^#([\w-]+)/);
|
|
40
|
+
if (id) {
|
|
41
|
+
parsed.id = id[1];
|
|
42
|
+
rest = rest.slice(id[0].length);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const cls = rest.match(/^\.([\w-]+)/);
|
|
46
|
+
if (cls) {
|
|
47
|
+
parsed.className = cls[1];
|
|
48
|
+
rest = rest.slice(cls[0].length);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
if (!parsed.tag && !parsed.attr && !parsed.id && !parsed.className)
|
|
54
|
+
return null;
|
|
55
|
+
return parsed;
|
|
56
|
+
}
|
|
57
|
+
function attributesMatch(attrs, parsed) {
|
|
58
|
+
if (parsed.attr) {
|
|
59
|
+
if (!(parsed.attrValue === void 0 ? new RegExp(`\\b${parsed.attr}(?=[\\s=>/]|$)`, "i") : new RegExp(`\\b${parsed.attr}\\s*=\\s*(["'])\\s*${parsed.attrValue}\\s*\\1`, "i")).test(attrs))
|
|
60
|
+
return !1;
|
|
61
|
+
}
|
|
62
|
+
if (parsed.id) {
|
|
63
|
+
if (!new RegExp(`\\bid\\s*=\\s*(["'])\\s*${parsed.id}\\s*\\1`, "i").test(attrs))
|
|
64
|
+
return !1;
|
|
65
|
+
}
|
|
66
|
+
if (parsed.className) {
|
|
67
|
+
const classMatch = attrs.match(/\bclass\s*=\s*(["'])([\s\S]*?)\1/i);
|
|
68
|
+
if (!classMatch)
|
|
69
|
+
return !1;
|
|
70
|
+
if (!classMatch[2].split(/\s+/).includes(parsed.className))
|
|
71
|
+
return !1;
|
|
72
|
+
}
|
|
73
|
+
return !0;
|
|
74
|
+
}
|
|
75
|
+
export function findContainerRegion(html, selector = "main") {
|
|
76
|
+
const parsed = parseContainerSelector(selector);
|
|
77
|
+
if (!parsed)
|
|
78
|
+
return null;
|
|
79
|
+
const openRe = /<([a-z][\w-]*)\b([^>]*)>/gi;
|
|
80
|
+
let match;
|
|
81
|
+
while ((match = openRe.exec(html)) !== null) {
|
|
82
|
+
const tagName = match[1].toLowerCase(), attrs = match[2] || "";
|
|
83
|
+
if (attrs.trimEnd().endsWith("/") || VOID_ELEMENTS.has(tagName))
|
|
84
|
+
continue;
|
|
85
|
+
if (parsed.tag && parsed.tag !== tagName)
|
|
86
|
+
continue;
|
|
87
|
+
if (!attributesMatch(attrs, parsed))
|
|
88
|
+
continue;
|
|
89
|
+
const openTag = match[0], contentStart = match.index + openTag.length, pairRe = new RegExp(`<(/?)${tagName}\\b([^>]*)>`, "gi");
|
|
90
|
+
pairRe.lastIndex = contentStart;
|
|
91
|
+
let depth = 1, pair;
|
|
92
|
+
while ((pair = pairRe.exec(html)) !== null) {
|
|
93
|
+
const isClose = pair[1] === "/";
|
|
94
|
+
if (!isClose && (pair[2] || "").trimEnd().endsWith("/"))
|
|
95
|
+
continue;
|
|
96
|
+
depth += isClose ? -1 : 1;
|
|
97
|
+
if (depth === 0)
|
|
98
|
+
return {
|
|
99
|
+
openTag,
|
|
100
|
+
openIndex: match.index,
|
|
101
|
+
start: contentStart,
|
|
102
|
+
end: pair.index,
|
|
103
|
+
tagName
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
@@ -1,3 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ship the framework's own browser-only composables to the client
|
|
3
|
+
* (stacksjs/stx#1805).
|
|
4
|
+
*
|
|
5
|
+
* `src/composables/` exports 149 functions; 120 of them have no counterpart in
|
|
6
|
+
* the client runtime. They are exported from the package, they type-check, they
|
|
7
|
+
* autocomplete — and they are unreachable from the only environment where their
|
|
8
|
+
* underlying API exists. `useClipboard`, `useGeolocation`, `useFullscreen`,
|
|
9
|
+
* `useBattery` and the observer family all wrap browser APIs and all threw
|
|
10
|
+
* `ReferenceError` when called from a `<script client>` block.
|
|
11
|
+
*
|
|
12
|
+
* There are two ways to close that gap. Hand-porting each one into the runtime's
|
|
13
|
+
* template literal duplicates 120 implementations that already exist and would
|
|
14
|
+
* drift the same way the auto-import list did (#1804). Instead this bundles the
|
|
15
|
+
* real modules — one source of truth — and merges them onto `window.stx`.
|
|
16
|
+
*
|
|
17
|
+
* DEMAND-DRIVEN: only composables the page actually references are emitted, so
|
|
18
|
+
* a page calling `useClipboard` ships a couple of KB rather than the whole tree.
|
|
19
|
+
*
|
|
20
|
+
* SKIP, NEVER CLOBBER: a name the runtime already provides wins. The runtime
|
|
21
|
+
* versions are the signal-based ones that #1710/#1726/#1797 unified; replacing
|
|
22
|
+
* them with the module versions would be a regression, not a fix.
|
|
23
|
+
*
|
|
24
|
+
* KNOWN LIMITATION, and it is why this is a bridge rather than the end state:
|
|
25
|
+
* these are pre-unification shapes — a getter plus `subscribe()` plus a manual
|
|
26
|
+
* `stop()`, not signals. So `useClipboard().copy(text)` works, `subscribe()`
|
|
27
|
+
* works, and imperative use is correct; but reading `.copied` in a template does
|
|
28
|
+
* not re-render on its own. Converting them to the Signal contract is the real
|
|
29
|
+
* fix and is tracked separately.
|
|
30
|
+
*
|
|
31
|
+
* @module framework-composables
|
|
32
|
+
*/
|
|
1
33
|
/** Clear the cache. Dev HMR calls this when composables change on disk. */
|
|
2
34
|
export declare function clearFrameworkComposableCache(): void;
|
|
3
35
|
/**
|
package/dist/head.d.ts
CHANGED
|
@@ -1,3 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* STX Head Management
|
|
3
|
+
*
|
|
4
|
+
* Manage document head (title, meta, links, scripts) with a simple API.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { useHead, useSeoMeta, definePageMeta } from 'stx'
|
|
9
|
+
*
|
|
10
|
+
* // Full control
|
|
11
|
+
* useHead({
|
|
12
|
+
* title: 'My Page',
|
|
13
|
+
* meta: [{ name: 'description', content: '...' }]
|
|
14
|
+
* })
|
|
15
|
+
*
|
|
16
|
+
* // SEO shorthand
|
|
17
|
+
* useSeoMeta({
|
|
18
|
+
* title: 'My Page',
|
|
19
|
+
* description: 'Page description',
|
|
20
|
+
* ogImage: '/og.png'
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* // Page configuration
|
|
24
|
+
* definePageMeta({
|
|
25
|
+
* title: 'My Page',
|
|
26
|
+
* layout: 'default'
|
|
27
|
+
* })
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export interface MetaTag {
|
|
31
|
+
name?: string;
|
|
32
|
+
property?: string;
|
|
33
|
+
content: string;
|
|
34
|
+
httpEquiv?: string;
|
|
35
|
+
charset?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface LinkTag {
|
|
38
|
+
rel: string;
|
|
39
|
+
href: string;
|
|
40
|
+
type?: string;
|
|
41
|
+
sizes?: string;
|
|
42
|
+
crossorigin?: string;
|
|
43
|
+
as?: string;
|
|
44
|
+
media?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface ScriptTag {
|
|
47
|
+
src?: string;
|
|
48
|
+
type?: string;
|
|
49
|
+
async?: boolean;
|
|
50
|
+
defer?: boolean;
|
|
51
|
+
content?: string;
|
|
52
|
+
id?: string;
|
|
53
|
+
}
|
|
54
|
+
export interface HeadConfig {
|
|
55
|
+
title?: string;
|
|
56
|
+
titleTemplate?: string | ((title: string) => string);
|
|
57
|
+
base?: {
|
|
58
|
+
href?: string;
|
|
59
|
+
target?: string;
|
|
60
|
+
};
|
|
61
|
+
meta?: MetaTag[];
|
|
62
|
+
link?: LinkTag[];
|
|
63
|
+
script?: ScriptTag[];
|
|
64
|
+
style?: {
|
|
65
|
+
content: string;
|
|
66
|
+
type?: string;
|
|
67
|
+
}[];
|
|
68
|
+
htmlAttrs?: Record<string, string>;
|
|
69
|
+
bodyAttrs?: Record<string, string>;
|
|
70
|
+
}
|
|
71
|
+
export interface SeoMeta {
|
|
72
|
+
title?: string;
|
|
73
|
+
titleTemplate?: string;
|
|
74
|
+
description?: string;
|
|
75
|
+
keywords?: string | string[];
|
|
76
|
+
author?: string;
|
|
77
|
+
robots?: string;
|
|
78
|
+
canonical?: string;
|
|
79
|
+
ogTitle?: string;
|
|
80
|
+
ogDescription?: string;
|
|
81
|
+
ogImage?: string;
|
|
82
|
+
ogUrl?: string;
|
|
83
|
+
ogType?: string;
|
|
84
|
+
ogSiteName?: string;
|
|
85
|
+
ogLocale?: string;
|
|
86
|
+
twitterCard?: 'summary' | 'summary_large_image' | 'app' | 'player';
|
|
87
|
+
twitterTitle?: string;
|
|
88
|
+
twitterDescription?: string;
|
|
89
|
+
twitterImage?: string;
|
|
90
|
+
twitterSite?: string;
|
|
91
|
+
twitterCreator?: string;
|
|
92
|
+
articleAuthor?: string;
|
|
93
|
+
articlePublishedTime?: string;
|
|
94
|
+
articleModifiedTime?: string;
|
|
95
|
+
articleSection?: string;
|
|
96
|
+
articleTags?: string[];
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Layouts that exist on disk, augmented by the generated
|
|
100
|
+
* `<state-dir>/layout-types.d.ts` (stacksjs/stx#1879).
|
|
101
|
+
*
|
|
102
|
+
* Empty here on purpose. A project that has not generated the declaration —
|
|
103
|
+
* or has not added the state directory to its tsconfig — keeps `layout` typed
|
|
104
|
+
* as `string`, so nothing breaks; a project that has gets a type error for a
|
|
105
|
+
* name with no layout behind it.
|
|
106
|
+
*/
|
|
107
|
+
export interface KnownLayouts {
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* A layout name: the generated union when one is available, otherwise any
|
|
111
|
+
* string.
|
|
112
|
+
*
|
|
113
|
+
* `keyof KnownLayouts` is `never` while the interface is empty, which is what
|
|
114
|
+
* makes the fallback work.
|
|
115
|
+
*/
|
|
116
|
+
export type LayoutName = keyof KnownLayouts extends never ? string : keyof KnownLayouts;
|
|
117
|
+
export interface PageMeta {
|
|
118
|
+
title?: string;
|
|
119
|
+
description?: string;
|
|
120
|
+
/** Static HTTP response status for this page. */
|
|
121
|
+
status?: number;
|
|
122
|
+
/**
|
|
123
|
+
* Layout for this page, by name (`'app'` → `<layoutsDir>/app.stx`), or
|
|
124
|
+
* `false` for none — the same as `@nolayout`.
|
|
125
|
+
*
|
|
126
|
+
* Precedence: `@extends`/`@layout` in the template wins, then this, then an
|
|
127
|
+
* auto-discovered `_layout.stx`, then `defaultLayout`.
|
|
128
|
+
*
|
|
129
|
+
* Do NOT hand-write `<meta name="stx-layout" content="…">` instead. That tag
|
|
130
|
+
* is stx *output*: the router reads it to decide between a fragment swap and
|
|
131
|
+
* a full-document swap, and a page asserting a group it does not belong to
|
|
132
|
+
* mis-routes rather than mis-styles. This field is the authoring surface; the
|
|
133
|
+
* meta tag is derived from the layout that actually resolved (#1879).
|
|
134
|
+
*
|
|
135
|
+
* Typed as the union of layouts on disk when the generated
|
|
136
|
+
* `<state-dir>/layout-types.d.ts` is in scope, so a typo is a type error
|
|
137
|
+
* rather than an unlayouted page.
|
|
138
|
+
*/
|
|
139
|
+
layout?: LayoutName | false;
|
|
140
|
+
middleware?: string | string[];
|
|
141
|
+
transition?: string | {
|
|
142
|
+
name: string;
|
|
143
|
+
mode?: string;
|
|
144
|
+
};
|
|
145
|
+
keepAlive?: boolean;
|
|
146
|
+
key?: string | ((route: unknown) => string);
|
|
147
|
+
validate?: (route: {
|
|
148
|
+
params: Record<string, string>;
|
|
149
|
+
}) => boolean | Promise<boolean>;
|
|
150
|
+
[key: string]: unknown;
|
|
151
|
+
}
|
|
1
152
|
/**
|
|
2
153
|
* Get the current accumulated head config.
|
|
3
154
|
*/
|
|
@@ -104,7 +255,10 @@ export declare function applyHead(config?: HeadConfig): void;
|
|
|
104
255
|
* @endhead
|
|
105
256
|
* ```
|
|
106
257
|
*/
|
|
107
|
-
export declare function processHeadDirective(content: string): {
|
|
258
|
+
export declare function processHeadDirective(content: string): {
|
|
259
|
+
content: string;
|
|
260
|
+
headContent: string;
|
|
261
|
+
};
|
|
108
262
|
/**
|
|
109
263
|
* Process @title directive.
|
|
110
264
|
*
|
|
@@ -125,116 +279,4 @@ export declare function processTitleDirective(content: string, context: Record<s
|
|
|
125
279
|
* ```
|
|
126
280
|
*/
|
|
127
281
|
export declare function processMetaDirective(content: string, context: Record<string, unknown>): string;
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* STX Head Management
|
|
131
|
-
*
|
|
132
|
-
* Manage document head (title, meta, links, scripts) with a simple API.
|
|
133
|
-
*
|
|
134
|
-
* @example
|
|
135
|
-
* ```typescript
|
|
136
|
-
* import { useHead, useSeoMeta, definePageMeta } from 'stx'
|
|
137
|
-
*
|
|
138
|
-
* // Full control
|
|
139
|
-
* useHead({
|
|
140
|
-
* title: 'My Page',
|
|
141
|
-
* meta: [{ name: 'description', content: '...' }]
|
|
142
|
-
* })
|
|
143
|
-
*
|
|
144
|
-
* // SEO shorthand
|
|
145
|
-
* useSeoMeta({
|
|
146
|
-
* title: 'My Page',
|
|
147
|
-
* description: 'Page description',
|
|
148
|
-
* ogImage: '/og.png'
|
|
149
|
-
* })
|
|
150
|
-
*
|
|
151
|
-
* // Page configuration
|
|
152
|
-
* definePageMeta({
|
|
153
|
-
* title: 'My Page',
|
|
154
|
-
* layout: 'default'
|
|
155
|
-
* })
|
|
156
|
-
* ```
|
|
157
|
-
*/
|
|
158
|
-
// =============================================================================
|
|
159
|
-
// Types
|
|
160
|
-
// =============================================================================
|
|
161
|
-
export declare interface MetaTag {
|
|
162
|
-
name?: string
|
|
163
|
-
property?: string
|
|
164
|
-
content: string
|
|
165
|
-
httpEquiv?: string
|
|
166
|
-
charset?: string
|
|
167
|
-
}
|
|
168
|
-
export declare interface LinkTag {
|
|
169
|
-
rel: string
|
|
170
|
-
href: string
|
|
171
|
-
type?: string
|
|
172
|
-
sizes?: string
|
|
173
|
-
crossorigin?: string
|
|
174
|
-
as?: string
|
|
175
|
-
media?: string
|
|
176
|
-
}
|
|
177
|
-
export declare interface ScriptTag {
|
|
178
|
-
src?: string
|
|
179
|
-
type?: string
|
|
180
|
-
async?: boolean
|
|
181
|
-
defer?: boolean
|
|
182
|
-
content?: string
|
|
183
|
-
id?: string
|
|
184
|
-
}
|
|
185
|
-
export declare interface HeadConfig {
|
|
186
|
-
title?: string
|
|
187
|
-
titleTemplate?: string | ((title: string) => string)
|
|
188
|
-
base?: { href?: string; target?: string }
|
|
189
|
-
meta?: MetaTag[]
|
|
190
|
-
link?: LinkTag[]
|
|
191
|
-
script?: ScriptTag[]
|
|
192
|
-
style?: { content: string; type?: string }[]
|
|
193
|
-
htmlAttrs?: Record<string, string>
|
|
194
|
-
bodyAttrs?: Record<string, string>
|
|
195
|
-
}
|
|
196
|
-
export declare interface SeoMeta {
|
|
197
|
-
title?: string
|
|
198
|
-
titleTemplate?: string
|
|
199
|
-
description?: string
|
|
200
|
-
keywords?: string | string[]
|
|
201
|
-
author?: string
|
|
202
|
-
robots?: string
|
|
203
|
-
canonical?: string
|
|
204
|
-
ogTitle?: string
|
|
205
|
-
ogDescription?: string
|
|
206
|
-
ogImage?: string
|
|
207
|
-
ogUrl?: string
|
|
208
|
-
ogType?: string
|
|
209
|
-
ogSiteName?: string
|
|
210
|
-
ogLocale?: string
|
|
211
|
-
twitterCard?: 'summary' | 'summary_large_image' | 'app' | 'player'
|
|
212
|
-
twitterTitle?: string
|
|
213
|
-
twitterDescription?: string
|
|
214
|
-
twitterImage?: string
|
|
215
|
-
twitterSite?: string
|
|
216
|
-
twitterCreator?: string
|
|
217
|
-
articleAuthor?: string
|
|
218
|
-
articlePublishedTime?: string
|
|
219
|
-
articleModifiedTime?: string
|
|
220
|
-
articleSection?: string
|
|
221
|
-
articleTags?: string[]
|
|
222
|
-
}
|
|
223
|
-
export declare interface PageMeta {
|
|
224
|
-
title?: string
|
|
225
|
-
description?: string
|
|
226
|
-
status?: number
|
|
227
|
-
layout?: string | false
|
|
228
|
-
middleware?: string | string[]
|
|
229
|
-
transition?: string | { name: string; mode?: string }
|
|
230
|
-
keepAlive?: boolean
|
|
231
|
-
key?: string | ((route: unknown) => string)
|
|
232
|
-
validate?: (route: { params: Record<string, string> }) => boolean | Promise<boolean>
|
|
233
|
-
[key: string]: unknown
|
|
234
|
-
}
|
|
235
|
-
// =============================================================================
|
|
236
|
-
// Exports
|
|
237
|
-
// =============================================================================
|
|
238
|
-
export {
|
|
239
|
-
usePageTitle as useTitle
|
|
240
|
-
};
|
|
282
|
+
export { usePageTitle as useTitle };
|