@stacksjs/stx 0.2.118 → 0.2.120
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/builtins/attrs.d.ts +16 -0
- package/dist/builtins/attrs.js +16 -0
- package/dist/builtins/safe-image.js +2 -9
- package/dist/builtins/stx-image.js +2 -9
- package/dist/builtins/stx-link.js +2 -9
- package/dist/cli.js +1869 -824
- package/dist/client-script-bundler.d.ts +0 -11
- package/dist/client-script-bundler.js +26 -4
- package/dist/client-script.d.ts +24 -0
- package/dist/client-script.js +59 -5
- package/dist/component-registry.d.ts +1 -0
- package/dist/component-renderer.js +13 -5
- package/dist/composables/index.d.ts +1 -0
- package/dist/composables/index.js +1 -0
- package/dist/composables/use-scroll-lock.d.ts +13 -0
- package/dist/composables/use-scroll-lock.js +55 -0
- package/dist/composables/use-timer.d.ts +1 -1
- package/dist/composables/use-timer.js +13 -3
- package/dist/composition-api.d.ts +1 -1
- package/dist/composition-api.js +13 -4
- package/dist/craft-bridge.d.ts +80 -1
- package/dist/craft-bridge.js +80 -1
- package/dist/craft-components.d.ts +77 -3
- package/dist/craft-components.js +138 -9
- package/dist/craft.js +481 -73
- package/dist/dev-server/crosswind.d.ts +15 -1
- package/dist/dev-server/crosswind.js +12 -3
- package/dist/dev-server/serve-app.js +3 -3
- package/dist/document-shell.d.ts +17 -0
- package/dist/document-shell.js +72 -2
- package/dist/expressions.js +14 -7
- package/dist/head.d.ts +8 -0
- package/dist/head.js +11 -8
- package/dist/html-masking.d.ts +12 -0
- package/dist/html-masking.js +50 -15
- package/dist/index.d.ts +9 -1
- package/dist/index.js +9 -1
- package/dist/process.js +11 -3
- package/dist/pwa.js +1172 -431
- package/dist/runtime-globals.d.ts +7 -4
- package/dist/runtime-globals.js +10 -2
- package/dist/runtime-injection.js +15 -1
- package/dist/signal-processing.js +19 -28
- package/dist/signals-api.d.ts +2 -0
- package/dist/signals-api.js +9 -0
- package/dist/signals.js +802 -62
- package/dist/ssg.js +1161 -420
- package/dist/state-management.d.ts +1 -1
- package/dist/state-management.js +1 -1
- package/dist/strict-lint.d.ts +1 -1
- package/dist/strict-lint.js +1 -1
- package/dist/stx.d.ts +6 -0
- package/dist/style-scoping.js +10 -0
- package/dist/utils.js +5 -3
- package/dist/variable-extractor.js +14 -22
- package/dist/vue-template.js +3 -2
- package/dist/x-element.d.ts +2 -2
- package/dist/x-element.js +9 -8
- package/package.json +5 -5
- package/stx.d.ts +6 -0
|
@@ -225,7 +225,7 @@ export declare function transformStoreImports(code: string): string;
|
|
|
225
225
|
* }
|
|
226
226
|
* ```
|
|
227
227
|
*/
|
|
228
|
-
export declare function registerStoresClient(stores: Record<string,
|
|
228
|
+
export declare function registerStoresClient(stores: Record<string, object>): void;
|
|
229
229
|
/** Store options */
|
|
230
230
|
export declare interface StoreOptions<T> {
|
|
231
231
|
name?: string
|
package/dist/state-management.js
CHANGED
|
@@ -495,7 +495,7 @@ export function generateStoreImportRuntime() {
|
|
|
495
495
|
resolve(store);
|
|
496
496
|
}
|
|
497
497
|
else if (Date.now() - start > timeout) {
|
|
498
|
-
reject(new Error('Timeout waiting for store: '
|
|
498
|
+
reject(new Error('Timeout waiting for store: '.concat(storeName)));
|
|
499
499
|
}
|
|
500
500
|
else {
|
|
501
501
|
requestAnimationFrame(check);
|
package/dist/strict-lint.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export declare interface StxStrictDiagnostic {
|
|
|
18
18
|
}
|
|
19
19
|
export declare interface StxStrictOptions {
|
|
20
20
|
filePath?: string
|
|
21
|
-
fileKind?: 'view' | 'component'
|
|
21
|
+
fileKind?: 'view' | 'component' | 'layout'
|
|
22
22
|
rules?: Partial<Record<StxStrictRuleId, boolean>>
|
|
23
23
|
}
|
|
24
24
|
/**
|
package/dist/strict-lint.js
CHANGED
|
@@ -265,7 +265,7 @@ function isRuleOn(rules, id) {
|
|
|
265
265
|
return rules?.[id] !== !1;
|
|
266
266
|
}
|
|
267
267
|
export function lintStxStrict(source, options = {}) {
|
|
268
|
-
const out = [], spans = rawTextSpans(source), filePath = (options.filePath ?? "").replace(/\\/g, "/"), fileKind = options.fileKind ?? (/\/components?\//i.test(filePath) ? "component" : "view");
|
|
268
|
+
const out = [], spans = rawTextSpans(source), filePath = (options.filePath ?? "").replace(/\\/g, "/"), fileKind = options.fileKind ?? (/\/components?\//i.test(filePath) ? "component" : /\/layouts?\//i.test(filePath) ? "layout" : "view");
|
|
269
269
|
if (isRuleOn(options.rules, "stx/no-bare-function-ref-in-event"))
|
|
270
270
|
ruleBareFunctionRef(source, spans, out);
|
|
271
271
|
if (isRuleOn(options.rules, "stx/no-view-level-script-client"))
|
package/dist/stx.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ declare module '*.md' {
|
|
|
38
38
|
|
|
39
39
|
interface StxSignal<T> {
|
|
40
40
|
(): T
|
|
41
|
+
value: T
|
|
41
42
|
set: (value: T) => void
|
|
42
43
|
update: (fn: (current: T) => T) => void
|
|
43
44
|
subscribe: (cb: (value: T) => void) => () => void
|
|
@@ -46,6 +47,7 @@ interface StxSignal<T> {
|
|
|
46
47
|
|
|
47
48
|
interface StxDerivedSignal<T> {
|
|
48
49
|
(): T
|
|
50
|
+
readonly value: T
|
|
49
51
|
// Derived signals carry `_isDerived: true` (distinguishes them from state
|
|
50
52
|
// signals, which carry `_isSignal: true`). The two branches are exposed
|
|
51
53
|
// separately as `isSignal()` / `isDerived()`. Surfaced by the dual-impl
|
|
@@ -155,6 +157,9 @@ declare function useEventListener(
|
|
|
155
157
|
_handler: (event: Event) => void,
|
|
156
158
|
_options?: boolean | AddEventListenerOptions,
|
|
157
159
|
): StxCleanup
|
|
160
|
+
declare function useScrollLock(
|
|
161
|
+
_target?: HTMLElement | null | { current?: HTMLElement | null, value?: HTMLElement | null } | (() => HTMLElement | null | undefined),
|
|
162
|
+
): StxSignal<boolean>
|
|
158
163
|
declare function useMeta(_meta: Record<string, string>): void
|
|
159
164
|
declare function useClickOutside(_target: HTMLElement | StxRef<HTMLElement | null> | string | null, _handler: (event: MouseEvent) => void): StxCleanup
|
|
160
165
|
declare function useFocus(_target: HTMLElement | StxRef<HTMLElement | null> | string | null): { focused: StxSignal<boolean>, focus: () => void, blur: () => void }
|
|
@@ -496,6 +501,7 @@ interface StxRuntimeRegistry {
|
|
|
496
501
|
useAsync: typeof useAsync
|
|
497
502
|
useLocalStorage: typeof useLocalStorage
|
|
498
503
|
useEventListener: typeof useEventListener
|
|
504
|
+
useScrollLock: typeof useScrollLock
|
|
499
505
|
useWebSocket: typeof useWebSocket
|
|
500
506
|
useColorMode: typeof useColorMode
|
|
501
507
|
useDark: typeof useDark
|
package/dist/style-scoping.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { maskAtElementPosition, matchScriptElement, matchStyleElement } from "./html-masking.js";
|
|
1
2
|
import { generateComponentId, scopeCss } from "./web-components/css-scoping.js";
|
|
2
3
|
const SCOPED_STYLE_ATTR = String.raw`(?<![\w-])scoped(?![\w-])`, SCOPED_STYLE_PROBE = new RegExp(`<style\\s+[^>]*${SCOPED_STYLE_ATTR}`, "i");
|
|
3
4
|
export function processScopedStyles(template, filePath) {
|
|
@@ -20,7 +21,16 @@ export function processScopedStyles(template, filePath) {
|
|
|
20
21
|
function scopeCssWithAttribute(css, scopeAttr) {
|
|
21
22
|
return scopeCss(css, "__SCOPE_PLACEHOLDER__", { preserveHost: !1 }).replace(/\.(__SCOPE_PLACEHOLDER__) /g, `[${scopeAttr}] `).replace(/\.(__SCOPE_PLACEHOLDER__)/g, `[${scopeAttr}]`);
|
|
22
23
|
}
|
|
24
|
+
const MASK_TOKEN = (index) => `\x00stx-scope-mask-${index}\x00`, MASK_TOKEN_PATTERN = /\u0000stx-scope-mask-(\d+)\u0000/g;
|
|
23
25
|
function addScopeAttribute(html, scopeAttr) {
|
|
26
|
+
const masked = maskAtElementPosition(html, (source, index) => {
|
|
27
|
+
const script = matchScriptElement(source, index);
|
|
28
|
+
return script > index ? script : matchStyleElement(source, index);
|
|
29
|
+
}, (_token, index) => MASK_TOKEN(index)), injected = injectScopeAttribute(masked.output, scopeAttr);
|
|
30
|
+
MASK_TOKEN_PATTERN.lastIndex = 0;
|
|
31
|
+
return injected.replace(MASK_TOKEN_PATTERN, (_match, index) => masked.tokens[Number(index)]);
|
|
32
|
+
}
|
|
33
|
+
function injectScopeAttribute(html, scopeAttr) {
|
|
24
34
|
const skipTags = new Set([
|
|
25
35
|
"script",
|
|
26
36
|
"style",
|
package/dist/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { extractAndStripCssImports, extractBridgeData, processClientScript, renderVendorStyleTags } from "./client-script.js";
|
|
3
|
+
import { extractAndStripCssImports, extractBridgeData, injectBrowserCoreAutoImports, processClientScript, renderVendorStyleTags } from "./client-script.js";
|
|
4
4
|
import { interpolateScriptExpressions, processExpressions, unescapeHtml } from "./expressions.js";
|
|
5
5
|
import { COMPONENT_SCOPE_LOCAL_GLOBALS, buildRuntimeGlobalsDestructure } from "./runtime-globals.js";
|
|
6
6
|
import { transformStoreImports } from "./store-imports.js";
|
|
@@ -629,7 +629,9 @@ ${triedPaths.map((p) => ` - ${p}`).join(`
|
|
|
629
629
|
projectRoot: process.cwd()
|
|
630
630
|
});
|
|
631
631
|
let bundledContent = cssExtraction.code;
|
|
632
|
-
const vendorStyleTags = renderVendorStyleTags(cssExtraction.styles)
|
|
632
|
+
const vendorStyleTags = renderVendorStyleTags(cssExtraction.styles);
|
|
633
|
+
bundledContent = injectBrowserCoreAutoImports(bundledContent).code;
|
|
634
|
+
const { hasUserImports, bundleClientScript } = await import("./client-script-bundler.js");
|
|
633
635
|
if (hasUserImports(bundledContent))
|
|
634
636
|
bundledContent = await bundleClientScript(bundledContent, componentFilePath, {
|
|
635
637
|
projectRoot: process.cwd(),
|
|
@@ -639,7 +641,7 @@ ${triedPaths.map((p) => ` - ${p}`).join(`
|
|
|
639
641
|
bundledContent = bundledContent.replace(/^\s*import\s+(?:type\s+)?\{([^}]*)\}\s+from\s+['"](?:stx|@stacksjs\/stx|@stacksjs\/browser)['"]\s*;?\s*$/gm, (_match, specifiers) => rewriteStxImportSpecifiers(specifiers));
|
|
640
642
|
const content = transformStoreImports(bundledContent), componentLocalNames = extractVariableNames(content), wrappedContent = `
|
|
641
643
|
(function() {
|
|
642
|
-
${buildRuntimeGlobalsDestructure("const", [...COMPONENT_SCOPE_LOCAL_GLOBALS, ...componentLocalNames])}
|
|
644
|
+
${buildRuntimeGlobalsDestructure("const", [...COMPONENT_SCOPE_LOCAL_GLOBALS, ...componentLocalNames], content)}
|
|
643
645
|
const __scope = window.stx._scopes = window.stx._scopes || {};
|
|
644
646
|
const __scopeVars = __scope['${scopeId}'] = __scope['${scopeId}'] || {};
|
|
645
647
|
const __previousCurrentElement = window.__STX_CURRENT_ELEMENT__;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var {require}=import.meta;import path from "node:path";
|
|
2
2
|
import process from "node:process";
|
|
3
3
|
import { findMatchingDelimiter } from "./parser/tokenizer.js";
|
|
4
|
-
import {
|
|
4
|
+
import { mergeHeadConfigs, seoMetaToHeadConfig } from "./head.js";
|
|
5
5
|
import { getPublicEnvDefine } from "./public-env.js";
|
|
6
6
|
import { safeEvaluate } from "./safe-evaluator.js";
|
|
7
7
|
function extractDeclaredVariableNames(script) {
|
|
@@ -261,6 +261,13 @@ export async function extractVariables(scriptContent, context, filePath, options
|
|
|
261
261
|
};
|
|
262
262
|
for (const [key, value] of Object.entries(propsObj))
|
|
263
263
|
Object.defineProperty($props, key, { value, enumerable: !0, configurable: !0, writable: !0 });
|
|
264
|
+
for (const shadowed of ["name", "length", "caller", "arguments"]) {
|
|
265
|
+
if (Object.prototype.hasOwnProperty.call(propsObj, shadowed))
|
|
266
|
+
continue;
|
|
267
|
+
try {
|
|
268
|
+
Object.defineProperty($props, shadowed, { value: void 0, enumerable: !1, configurable: !0, writable: !0 });
|
|
269
|
+
} catch {}
|
|
270
|
+
}
|
|
264
271
|
const defineProps = (definitions) => {
|
|
265
272
|
if (!definitions)
|
|
266
273
|
return propsObj;
|
|
@@ -309,26 +316,11 @@ export async function extractVariables(scriptContent, context, filePath, options
|
|
|
309
316
|
matched: []
|
|
310
317
|
};
|
|
311
318
|
}, useRouter = () => ({ push: (_to) => {}, replace: (_to) => {}, back: () => {}, forward: () => {}, go: (_n) => {} }), useHead = (head) => {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
context.__stx_runtime_head = {
|
|
315
|
-
...existing,
|
|
316
|
-
...incoming.title && { title: incoming.title },
|
|
317
|
-
meta: [...existing.meta || [], ...incoming.meta || []],
|
|
318
|
-
link: [...existing.link || [], ...incoming.link || []],
|
|
319
|
-
script: [...existing.script || [], ...incoming.script || []],
|
|
320
|
-
htmlAttrs: { ...existing.htmlAttrs || {}, ...incoming.htmlAttrs || {} },
|
|
321
|
-
bodyAttrs: { ...existing.bodyAttrs || {}, ...incoming.bodyAttrs || {} }
|
|
322
|
-
};
|
|
319
|
+
const existing = context.__stx_runtime_head || {};
|
|
320
|
+
context.__stx_runtime_head = mergeHeadConfigs(existing, head || {});
|
|
323
321
|
}, useSeoMeta = (meta) => {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
context.__stx_runtime_head = {
|
|
327
|
-
...context.__stx_runtime_head || {},
|
|
328
|
-
...head.title && { title: head.title },
|
|
329
|
-
meta: head.meta ? [...head.meta] : []
|
|
330
|
-
};
|
|
331
|
-
}, ref = (val) => ({ value: val }), reactive = (obj) => obj, computed = (fn) => ({ value: typeof fn === "function" ? fn() : fn }), watch = (_source, _cb) => {}, onMounted = (_fn) => {}, onUnmounted = (_fn) => {}, nextTick = (fn) => fn ? fn() : Promise.resolve(), defineEmits = (_events) => (_event, ..._args) => {}, defineExpose = (_exposed) => {}, provide = (_key, _value) => {}, inject = (_key, defaultValue) => defaultValue, useColorMode = () => ({ value: "light" }), useDark = () => state(!1), useMediaQuery = (_query) => state(!1), usePreferredDark = () => useMediaQuery("(prefers-color-scheme: dark)"), usePreferredLight = () => useMediaQuery("(prefers-color-scheme: light)"), usePreferredReducedMotion = () => useMediaQuery("(prefers-reduced-motion: reduce)"), usePreferredContrast = () => useMediaQuery("(prefers-contrast: more)"), mockWindow = {
|
|
322
|
+
useHead(seoMetaToHeadConfig(meta || {}));
|
|
323
|
+
}, ref = (val) => ({ value: val }), reactive = (obj) => obj, computed = (fn) => ({ value: typeof fn === "function" ? fn() : fn }), watch = (_source, _cb) => {}, onMounted = (_fn) => {}, onUnmounted = (_fn) => {}, nextTick = (fn) => fn ? fn() : Promise.resolve(), defineEmits = (_events) => (_event, ..._args) => {}, defineExpose = (_exposed) => {}, provide = (_key, _value) => {}, inject = (_key, defaultValue) => defaultValue, useColorMode = () => ({ value: "light" }), useDark = () => state(!1), useMediaQuery = (_query) => state(!1), useScrollLock = () => state(!1), usePreferredDark = () => useMediaQuery("(prefers-color-scheme: dark)"), usePreferredLight = () => useMediaQuery("(prefers-color-scheme: light)"), usePreferredReducedMotion = () => useMediaQuery("(prefers-reduced-motion: reduce)"), usePreferredContrast = () => useMediaQuery("(prefers-contrast: more)"), mockWindow = {
|
|
332
324
|
siteId: void 0,
|
|
333
325
|
API_ENDPOINT: "",
|
|
334
326
|
ANALYTICS_SITE_ID: void 0,
|
|
@@ -463,11 +455,11 @@ export async function extractVariables(scriptContent, context, filePath, options
|
|
|
463
455
|
scriptContextKeys.push(filteredContextKeys[i]);
|
|
464
456
|
scriptContextValues.push(filteredContextValues[i]);
|
|
465
457
|
}
|
|
466
|
-
const result = await Function("module", "exports", "require", "props", "$props", "defineProps", "withDefaults", "state", "derived", "effect", "batch", "onMount", "onDestroy", "definePageMeta", "useRoute", "useRouter", "useHead", "useSeoMeta", "ref", "reactive", "computed", "watch", "onMounted", "onUnmounted", "nextTick", "defineEmits", "defineExpose", "defineSlots", "provide", "inject", "useColorMode", "useDark", "useMediaQuery", "usePreferredDark", "usePreferredLight", "usePreferredReducedMotion", "usePreferredContrast", "window", "document", "console", "confirm", "alert", "fetch", "params", ...propArgNames, ...scriptContextKeys, `return (async () => {
|
|
458
|
+
const result = await Function("module", "exports", "require", "props", "$props", "defineProps", "withDefaults", "state", "derived", "effect", "batch", "onMount", "onDestroy", "definePageMeta", "useRoute", "useRouter", "useHead", "useSeoMeta", "ref", "reactive", "computed", "watch", "onMounted", "onUnmounted", "nextTick", "defineEmits", "defineExpose", "defineSlots", "provide", "inject", "useColorMode", "useDark", "useMediaQuery", "useScrollLock", "usePreferredDark", "usePreferredLight", "usePreferredReducedMotion", "usePreferredContrast", "window", "document", "console", "confirm", "alert", "fetch", "params", ...propArgNames, ...scriptContextKeys, `return (async () => {
|
|
467
459
|
${convertedScript}
|
|
468
460
|
${reSyncCode}
|
|
469
461
|
return module.exports
|
|
470
|
-
})()`)(module, exports, requireFn, propsObj, $props, defineProps, withDefaults, state, derived, effect, batch, onMount, onDestroy, definePageMeta, useRoute, useRouter, useHead, useSeoMeta, ref, reactive, computed, watch, onMounted, onUnmounted, nextTick, defineEmits, defineExpose, defineSlots, provide, inject, useColorMode, useDark, useMediaQuery, usePreferredDark, usePreferredLight, usePreferredReducedMotion, usePreferredContrast, windowProxy, mockDocument, mockConsole, mockWindow.confirm, mockWindow.alert, mockWindow.fetch, paramsObj, ...propArgValues, ...scriptContextValues);
|
|
462
|
+
})()`)(module, exports, requireFn, propsObj, $props, defineProps, withDefaults, state, derived, effect, batch, onMount, onDestroy, definePageMeta, useRoute, useRouter, useHead, useSeoMeta, ref, reactive, computed, watch, onMounted, onUnmounted, nextTick, defineEmits, defineExpose, defineSlots, provide, inject, useColorMode, useDark, useMediaQuery, useScrollLock, usePreferredDark, usePreferredLight, usePreferredReducedMotion, usePreferredContrast, windowProxy, mockDocument, mockConsole, mockWindow.confirm, mockWindow.alert, mockWindow.fetch, paramsObj, ...propArgValues, ...scriptContextValues);
|
|
471
463
|
if (options.preserveExisting) {
|
|
472
464
|
for (const [key, value] of Object.entries(result))
|
|
473
465
|
if (!(key in context) || context[key] === void 0)
|
package/dist/vue-template.js
CHANGED
|
@@ -134,11 +134,12 @@ function findNextOpenTag(html, startFrom) {
|
|
|
134
134
|
const match = tagRegex.exec(html);
|
|
135
135
|
if (!match)
|
|
136
136
|
return null;
|
|
137
|
+
const selfClosing = /\/\s*>$/.test(match[0]) || VOID_ELEMENTS.has(match[1].toLowerCase()), attrs = selfClosing ? match[2].replace(/\/\s*$/, "") : match[2];
|
|
137
138
|
return {
|
|
138
139
|
full: match[0],
|
|
139
140
|
tag: match[1],
|
|
140
|
-
attrs
|
|
141
|
-
selfClosing
|
|
141
|
+
attrs,
|
|
142
|
+
selfClosing,
|
|
142
143
|
start: match.index,
|
|
143
144
|
end: match.index + match[0].length
|
|
144
145
|
};
|
package/dist/x-element.d.ts
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
*/
|
|
30
30
|
/**
|
|
31
31
|
* Generate the x-element runtime script
|
|
32
|
-
* This is injected once per page that
|
|
32
|
+
* This is injected once per page that declares an x-data scope
|
|
33
33
|
*/
|
|
34
34
|
export declare function generateXElementRuntime(): string;
|
|
35
35
|
/**
|
|
@@ -38,6 +38,6 @@ export declare function generateXElementRuntime(): string;
|
|
|
38
38
|
export declare function hasXElementDirectives(template: string): boolean;
|
|
39
39
|
/**
|
|
40
40
|
* Process x-element directives in template
|
|
41
|
-
* Injects
|
|
41
|
+
* Injects one runtime if an x-data scope is found
|
|
42
42
|
*/
|
|
43
43
|
export declare function processXElementDirectives(template: string): string;
|
package/dist/x-element.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export function generateXElementRuntime() {
|
|
2
|
-
return `<script data-stx-scoped>
|
|
2
|
+
return `<script data-stx-scoped data-stx-x-element-runtime>
|
|
3
3
|
(function() {
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
@@ -286,15 +286,16 @@ else {
|
|
|
286
286
|
</script>`;
|
|
287
287
|
}
|
|
288
288
|
export function hasXElementDirectives(template) {
|
|
289
|
-
return /\bx-
|
|
289
|
+
return /\bx-data(?:\s|=)/.test(template);
|
|
290
290
|
}
|
|
291
291
|
export function processXElementDirectives(template) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
292
|
+
const runtimePattern = /<script\b(?=[^>]*\bdata-stx-x-element-runtime\b)[^>]*>[\s\S]*?<\/script>\s*/gi, existingRuntimes = template.match(runtimePattern) || [], withoutRuntimes = existingRuntimes.length > 0 ? template.replace(runtimePattern, "") : template;
|
|
293
|
+
if (!hasXElementDirectives(withoutRuntimes))
|
|
294
|
+
return withoutRuntimes;
|
|
295
|
+
const runtime = existingRuntimes[0]?.trim() || generateXElementRuntime(), bodyCloseIdx = withoutRuntimes.lastIndexOf("</body>");
|
|
295
296
|
if (bodyCloseIdx !== -1)
|
|
296
|
-
return
|
|
297
|
-
` +
|
|
298
|
-
return
|
|
297
|
+
return withoutRuntimes.slice(0, bodyCloseIdx) + runtime + `
|
|
298
|
+
` + withoutRuntimes.slice(bodyCloseIdx);
|
|
299
|
+
return withoutRuntimes + `
|
|
299
300
|
` + runtime;
|
|
300
301
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/stx",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.120",
|
|
5
5
|
"description": "A performant UI Framework. Powered by Bun.",
|
|
6
6
|
"author": "Chris Breuer <chris@stacksjs.org>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -117,12 +117,12 @@
|
|
|
117
117
|
"dependencies": {
|
|
118
118
|
"@cwcss/crosswind": "^0.2.12",
|
|
119
119
|
"@stacksjs/clapp": "^0.2.0",
|
|
120
|
-
"@stacksjs/desktop": "0.2.
|
|
121
|
-
"@stacksjs/sanitizer": "0.2.
|
|
120
|
+
"@stacksjs/desktop": "0.2.120",
|
|
121
|
+
"@stacksjs/sanitizer": "0.2.120",
|
|
122
122
|
"@stacksjs/ts-i18n": "^0.1.11",
|
|
123
|
-
"bun-plugin-stx": "0.2.
|
|
123
|
+
"bun-plugin-stx": "0.2.120",
|
|
124
124
|
"bunfig": "^0.15.15",
|
|
125
|
-
"stx-router": "0.2.
|
|
125
|
+
"stx-router": "0.2.120",
|
|
126
126
|
"ts-broadcasting": "^0.0.9",
|
|
127
127
|
"ts-images": "^0.1.9",
|
|
128
128
|
"ts-syntax-highlighter": "^0.2.1"
|
package/stx.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ declare module '*.md' {
|
|
|
38
38
|
|
|
39
39
|
interface StxSignal<T> {
|
|
40
40
|
(): T
|
|
41
|
+
value: T
|
|
41
42
|
set: (value: T) => void
|
|
42
43
|
update: (fn: (current: T) => T) => void
|
|
43
44
|
subscribe: (cb: (value: T) => void) => () => void
|
|
@@ -46,6 +47,7 @@ interface StxSignal<T> {
|
|
|
46
47
|
|
|
47
48
|
interface StxDerivedSignal<T> {
|
|
48
49
|
(): T
|
|
50
|
+
readonly value: T
|
|
49
51
|
// Derived signals carry `_isDerived: true` (distinguishes them from state
|
|
50
52
|
// signals, which carry `_isSignal: true`). The two branches are exposed
|
|
51
53
|
// separately as `isSignal()` / `isDerived()`. Surfaced by the dual-impl
|
|
@@ -155,6 +157,9 @@ declare function useEventListener(
|
|
|
155
157
|
_handler: (event: Event) => void,
|
|
156
158
|
_options?: boolean | AddEventListenerOptions,
|
|
157
159
|
): StxCleanup
|
|
160
|
+
declare function useScrollLock(
|
|
161
|
+
_target?: HTMLElement | null | { current?: HTMLElement | null, value?: HTMLElement | null } | (() => HTMLElement | null | undefined),
|
|
162
|
+
): StxSignal<boolean>
|
|
158
163
|
declare function useMeta(_meta: Record<string, string>): void
|
|
159
164
|
declare function useClickOutside(_target: HTMLElement | StxRef<HTMLElement | null> | string | null, _handler: (event: MouseEvent) => void): StxCleanup
|
|
160
165
|
declare function useFocus(_target: HTMLElement | StxRef<HTMLElement | null> | string | null): { focused: StxSignal<boolean>, focus: () => void, blur: () => void }
|
|
@@ -496,6 +501,7 @@ interface StxRuntimeRegistry {
|
|
|
496
501
|
useAsync: typeof useAsync
|
|
497
502
|
useLocalStorage: typeof useLocalStorage
|
|
498
503
|
useEventListener: typeof useEventListener
|
|
504
|
+
useScrollLock: typeof useScrollLock
|
|
499
505
|
useWebSocket: typeof useWebSocket
|
|
500
506
|
useColorMode: typeof useColorMode
|
|
501
507
|
useDark: typeof useDark
|