@stacksjs/stx 0.2.175 → 0.2.177
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 +72 -2
- package/dist/a11y.js +25 -10
- package/dist/builtins/attrs.d.ts +19 -0
- package/dist/builtins/attrs.js +18 -0
- package/dist/builtins/safe-image.js +2 -1
- package/dist/builtins/stx-image.js +2 -1
- package/dist/builtins/stx-link.js +2 -1
- package/dist/cli-flags.d.ts +34 -0
- package/dist/cli-flags.js +20 -0
- package/dist/cli.js +1132 -895
- package/dist/client-script.js +2 -1
- package/dist/component-registry.d.ts +9 -0
- package/dist/component-renderer.js +20 -1
- package/dist/composables/use-fetch.d.ts +6 -1
- package/dist/composables/use-fetch.js +40 -18
- package/dist/composables/use-query.d.ts +7 -2
- package/dist/cookie-serialize.d.ts +40 -0
- package/dist/cookie-serialize.js +18 -0
- package/dist/craft.js +670 -442
- package/dist/crosswind-config.d.ts +13 -0
- package/dist/crosswind-config.js +6 -2
- package/dist/dev-server/crosswind.js +2 -1
- package/dist/edge-runtime.d.ts +2 -9
- package/dist/edge-runtime.js +2 -16
- package/dist/includes.js +8 -4
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/page-action.d.ts +10 -20
- package/dist/page-action.js +33 -9
- package/dist/process.js +2 -1
- package/dist/production-server.js +8 -7
- package/dist/props.d.ts +51 -8
- package/dist/pwa.js +637 -409
- package/dist/reactive.js +2 -2
- package/dist/resolve-stx-targets.d.ts +49 -0
- package/dist/resolve-stx-targets.js +38 -0
- package/dist/runtime-globals.d.ts +24 -0
- package/dist/runtime-globals.js +16 -0
- package/dist/runtime-injection.d.ts +36 -0
- package/dist/runtime-injection.js +14 -0
- package/dist/server-bindings.js +3 -0
- package/dist/signal-processing.js +38 -7
- package/dist/signals.js +157 -35
- package/dist/ssg.d.ts +23 -0
- package/dist/ssg.js +615 -383
- package/dist/ssr.js +2 -16
- package/dist/stx-virtual-ts.d.ts +72 -4
- package/dist/stx-virtual-ts.js +111 -5
- package/dist/stx.d.ts +66 -7
- package/dist/template-hydrator.d.ts +1 -1
- package/dist/template-hydrator.js +6 -6
- package/dist/theme-tokens.d.ts +88 -0
- package/dist/theme-tokens.js +71 -0
- package/dist/typecheck.d.ts +6 -1
- package/dist/typecheck.js +102 -67
- package/dist/types/config-types.d.ts +24 -0
- package/dist/utils.js +5 -4
- package/package.json +5 -5
- package/stx.d.ts +66 -7
package/dist/client-script.js
CHANGED
|
@@ -171,7 +171,8 @@ const BROWSER_CORE_IMPORTS = [
|
|
|
171
171
|
"readableSize",
|
|
172
172
|
"useActiveElement",
|
|
173
173
|
"useDocumentVisibility",
|
|
174
|
-
"useIntervalFn"
|
|
174
|
+
"useIntervalFn",
|
|
175
|
+
"useTimeoutFn"
|
|
175
176
|
];
|
|
176
177
|
export function injectBrowserCoreAutoImports(code) {
|
|
177
178
|
const searchable = stripCommentsAndLiterals(code), explicitlyImported = new Set;
|
|
@@ -47,6 +47,15 @@ export interface ResolvedProps {
|
|
|
47
47
|
staticNames: Record<string, string>;
|
|
48
48
|
/** Server-side dynamic bindings — e.g. :count="items.length" (evaluated at compile time) */
|
|
49
49
|
serverDynamic: Record<string, unknown>;
|
|
50
|
+
/**
|
|
51
|
+
* Original attribute spelling for any `serverDynamic` key that was camelized.
|
|
52
|
+
*
|
|
53
|
+
* Same reason as {@link ResolvedProps.staticNames}: a builtin forwarding an
|
|
54
|
+
* unconsumed binding onto real markup must spell it the way the author wrote
|
|
55
|
+
* it, or `:some-attr="x"` goes out as `someAttr` and the browser sees an
|
|
56
|
+
* attribute it does not know.
|
|
57
|
+
*/
|
|
58
|
+
serverDynamicNames?: Record<string, string>;
|
|
50
59
|
/** Client-side reactive bindings — expression string preserved for signals */
|
|
51
60
|
clientReactive: Record<string, string>;
|
|
52
61
|
/** Event handler bindings — e.g. @click="handler()" */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { registry } from "./component-registry.js";
|
|
2
|
+
import { processConditionals } from "./conditionals.js";
|
|
2
3
|
import { registerBuiltins } from "./builtins/index.js";
|
|
3
4
|
import { decodeAttributeEntities, decodeStxProp, findComponentTags, parseMultilineAttributes, pascalToKebab, restoreStashedScripts, stashScriptElements } from "./component-processing.js";
|
|
4
5
|
import { maskAtElementPosition, matchHtmlComment } from "./html-masking.js";
|
|
@@ -182,6 +183,7 @@ function parseComponentProps(rawProps, context, options) {
|
|
|
182
183
|
static: {},
|
|
183
184
|
staticNames: {},
|
|
184
185
|
serverDynamic: {},
|
|
186
|
+
serverDynamicNames: {},
|
|
185
187
|
clientReactive: {},
|
|
186
188
|
events: {}
|
|
187
189
|
}, clientSignalNames = new Set(Array.isArray(context.__stx_client_signal_names) ? context.__stx_client_signal_names : []), referencesClientSignal = (expression) => {
|
|
@@ -245,6 +247,8 @@ function parseComponentProps(rawProps, context, options) {
|
|
|
245
247
|
}
|
|
246
248
|
}
|
|
247
249
|
resolved.serverDynamic[propName] = evaluated;
|
|
250
|
+
if (propName !== attrName.slice(1) && resolved.serverDynamicNames)
|
|
251
|
+
resolved.serverDynamicNames[propName] = attrName.slice(1);
|
|
248
252
|
} catch {
|
|
249
253
|
resolved.clientReactive[propName] = expression;
|
|
250
254
|
}
|
|
@@ -294,6 +298,21 @@ function parseComponentProps(rawProps, context, options) {
|
|
|
294
298
|
}
|
|
295
299
|
return resolved;
|
|
296
300
|
}
|
|
301
|
+
const TAG_CONDITIONAL_PAIRS = [
|
|
302
|
+
[/@if\s*\(/, "@endif"],
|
|
303
|
+
[/@unless\s*\(/, "@endunless"]
|
|
304
|
+
];
|
|
305
|
+
function resolveTagConditionals(attributesStr, context, filePath) {
|
|
306
|
+
if (!attributesStr.includes("@"))
|
|
307
|
+
return attributesStr;
|
|
308
|
+
if (!TAG_CONDITIONAL_PAIRS.some(([open, close]) => open.test(attributesStr) && attributesStr.includes(close)))
|
|
309
|
+
return attributesStr;
|
|
310
|
+
try {
|
|
311
|
+
return processConditionals(attributesStr, context, filePath);
|
|
312
|
+
} catch {
|
|
313
|
+
return attributesStr;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
297
316
|
function parseAllAttributes(attributesStr) {
|
|
298
317
|
const props = {};
|
|
299
318
|
let pos = 0;
|
|
@@ -611,7 +630,7 @@ async function processCustomElementTags(template, context, filePath, options, de
|
|
|
611
630
|
let result = html;
|
|
612
631
|
const tags = findComponentTags(result, tagPattern, skipTags);
|
|
613
632
|
for (let i = tags.length - 1;i >= 0; i--) {
|
|
614
|
-
const tag = tags[i], componentPath = isPascalCase ? pascalToKebab(tag.tagName) : tag.tagName, rawProps = parseAllAttributes(tag.attributes), resolvedProps = parseComponentProps(rawProps, context, options), builtinDef = registry.getBuiltin(tag.tagName), overriddenByUser = builtinDef ? await userComponentFileExists(componentPath, componentsDir, context, filePath, options) : !1;
|
|
633
|
+
const tag = tags[i], componentPath = isPascalCase ? pascalToKebab(tag.tagName) : tag.tagName, rawProps = parseAllAttributes(resolveTagConditionals(tag.attributes, context, filePath)), resolvedProps = parseComponentProps(rawProps, context, options), builtinDef = registry.getBuiltin(tag.tagName), overriddenByUser = builtinDef ? await userComponentFileExists(componentPath, componentsDir, context, filePath, options) : !1;
|
|
615
634
|
if (builtinDef && !overriddenByUser) {
|
|
616
635
|
const renderCtx = {
|
|
617
636
|
context,
|
|
@@ -41,14 +41,19 @@ export declare interface FetchOptions<T = unknown> extends Omit<RequestInit, 'bo
|
|
|
41
41
|
refetchInterval?: number
|
|
42
42
|
initialData?: T | null
|
|
43
43
|
}
|
|
44
|
+
/** How one run of the request should behave. */
|
|
45
|
+
export declare interface RefetchOptions {
|
|
46
|
+
background?: boolean
|
|
47
|
+
}
|
|
44
48
|
/** Signal-shaped fetch result. Matches the runtime's `useFetch` return. */
|
|
45
49
|
export declare interface FetchRef<T> {
|
|
46
50
|
data: Signal<T | null>
|
|
47
51
|
loading: Signal<boolean>
|
|
52
|
+
isFetching: Signal<boolean>
|
|
48
53
|
error: Signal<Error | null>
|
|
49
54
|
status: Signal<number | null>
|
|
50
55
|
statusText: Signal<string | null>
|
|
51
|
-
refetch: () => Promise<void>
|
|
56
|
+
refetch: (_options?: RefetchOptions) => Promise<void>
|
|
52
57
|
execute: () => Promise<void>
|
|
53
58
|
abort: () => void
|
|
54
59
|
}
|
|
@@ -30,7 +30,7 @@ export function useFetch(url, options = {}) {
|
|
|
30
30
|
query,
|
|
31
31
|
body,
|
|
32
32
|
...fetchOptions
|
|
33
|
-
} = options, data = state(initialData), loading = state(!1), error = state(null), status = state(null), statusText = state(null);
|
|
33
|
+
} = options, data = state(initialData), loading = state(!1), isFetching = state(!1), error = state(null), status = state(null), statusText = state(null);
|
|
34
34
|
let abortController = null, focusHandler = null, intervalId = null;
|
|
35
35
|
const getURL = () => {
|
|
36
36
|
const rawURL = typeof url === "function" ? url() : url;
|
|
@@ -45,19 +45,23 @@ export function useFetch(url, options = {}) {
|
|
|
45
45
|
}, setCache = (value) => {
|
|
46
46
|
if (cacheTime > 0)
|
|
47
47
|
fetchCache.set(getCacheKey(), { data: value, timestamp: Date.now() });
|
|
48
|
-
}, doFetch = async (attempt = 0) => {
|
|
48
|
+
}, doFetch = async (attempt = 0, background = !1) => {
|
|
49
49
|
const cached = getFromCache();
|
|
50
50
|
if (cached !== null) {
|
|
51
51
|
data.set(cached);
|
|
52
52
|
loading.set(!1);
|
|
53
|
+
isFetching.set(!1);
|
|
53
54
|
error.set(null);
|
|
54
55
|
return;
|
|
55
56
|
}
|
|
56
57
|
if (abortController)
|
|
57
58
|
abortController.abort();
|
|
58
59
|
abortController = new AbortController;
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
if (!background)
|
|
61
|
+
loading.set(!0);
|
|
62
|
+
isFetching.set(!0);
|
|
63
|
+
if (!background)
|
|
64
|
+
error.set(null);
|
|
61
65
|
const timeoutId = setTimeout(() => abortController?.abort(), timeout);
|
|
62
66
|
try {
|
|
63
67
|
let requestBody;
|
|
@@ -113,30 +117,36 @@ export function useFetch(url, options = {}) {
|
|
|
113
117
|
payload = transform(payload);
|
|
114
118
|
setCache(payload);
|
|
115
119
|
data.set(payload);
|
|
116
|
-
|
|
120
|
+
if (background)
|
|
121
|
+
error.set(null);
|
|
122
|
+
if (!background)
|
|
123
|
+
loading.set(!1);
|
|
124
|
+
isFetching.set(!1);
|
|
117
125
|
} catch (err) {
|
|
118
126
|
clearTimeout(timeoutId);
|
|
119
127
|
if (err instanceof Error && err.name === "AbortError")
|
|
120
128
|
return;
|
|
121
129
|
if (attempt < retry) {
|
|
122
130
|
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
123
|
-
return doFetch(attempt + 1);
|
|
131
|
+
return doFetch(attempt + 1, background);
|
|
124
132
|
}
|
|
125
133
|
error.set(err instanceof Error ? err : Error(String(err)));
|
|
126
|
-
|
|
134
|
+
if (!background)
|
|
135
|
+
loading.set(!1);
|
|
136
|
+
isFetching.set(!1);
|
|
127
137
|
}
|
|
128
138
|
}, setupRefetchOnFocus = () => {
|
|
129
139
|
if (!refetchOnFocus || typeof window > "u")
|
|
130
140
|
return;
|
|
131
141
|
focusHandler = () => {
|
|
132
142
|
if (document.visibilityState === "visible")
|
|
133
|
-
doFetch();
|
|
143
|
+
doFetch(0, !0);
|
|
134
144
|
};
|
|
135
145
|
document.addEventListener("visibilitychange", focusHandler);
|
|
136
146
|
}, setupRefetchInterval = () => {
|
|
137
147
|
if (!refetchInterval || typeof window > "u")
|
|
138
148
|
return;
|
|
139
|
-
intervalId = setInterval(() => void doFetch(), refetchInterval);
|
|
149
|
+
intervalId = setInterval(() => void doFetch(0, !0), refetchInterval);
|
|
140
150
|
};
|
|
141
151
|
if (immediate) {
|
|
142
152
|
doFetch();
|
|
@@ -146,10 +156,11 @@ export function useFetch(url, options = {}) {
|
|
|
146
156
|
return {
|
|
147
157
|
data,
|
|
148
158
|
loading,
|
|
159
|
+
isFetching,
|
|
149
160
|
error,
|
|
150
161
|
status,
|
|
151
162
|
statusText,
|
|
152
|
-
refetch: () => doFetch(),
|
|
163
|
+
refetch: (refetchOptions) => doFetch(0, !!refetchOptions?.background),
|
|
153
164
|
execute: async () => {
|
|
154
165
|
await doFetch();
|
|
155
166
|
setupRefetchOnFocus();
|
|
@@ -176,7 +187,7 @@ export function useAsyncData(fetcher, options = {}) {
|
|
|
176
187
|
initialData = null,
|
|
177
188
|
key,
|
|
178
189
|
cacheTime = 0
|
|
179
|
-
} = options, data = state(initialData), loading = state(!1), error = state(null), status = state(null), statusText = state(null), getCacheKey = () => key || fetcher.toString(), getFromCache = () => {
|
|
190
|
+
} = options, data = state(initialData), loading = state(!1), isFetching = state(!1), error = state(null), status = state(null), statusText = state(null), getCacheKey = () => key || fetcher.toString(), getFromCache = () => {
|
|
180
191
|
if (cacheTime <= 0)
|
|
181
192
|
return null;
|
|
182
193
|
const cached = fetchCache.get(getCacheKey());
|
|
@@ -186,26 +197,36 @@ export function useAsyncData(fetcher, options = {}) {
|
|
|
186
197
|
}, setCache = (value) => {
|
|
187
198
|
if (cacheTime > 0)
|
|
188
199
|
fetchCache.set(getCacheKey(), { data: value, timestamp: Date.now() });
|
|
189
|
-
}, doFetch = async () => {
|
|
200
|
+
}, doFetch = async (background = !1) => {
|
|
190
201
|
const cached = getFromCache();
|
|
191
202
|
if (cached !== null) {
|
|
192
203
|
data.set(cached);
|
|
193
204
|
loading.set(!1);
|
|
205
|
+
isFetching.set(!1);
|
|
194
206
|
error.set(null);
|
|
195
207
|
return;
|
|
196
208
|
}
|
|
197
|
-
|
|
198
|
-
|
|
209
|
+
if (!background)
|
|
210
|
+
loading.set(!0);
|
|
211
|
+
isFetching.set(!0);
|
|
212
|
+
if (!background)
|
|
213
|
+
error.set(null);
|
|
199
214
|
try {
|
|
200
215
|
let payload = await fetcher();
|
|
201
216
|
if (transform)
|
|
202
217
|
payload = transform(payload);
|
|
203
218
|
setCache(payload);
|
|
204
219
|
data.set(payload);
|
|
205
|
-
|
|
220
|
+
if (background)
|
|
221
|
+
error.set(null);
|
|
222
|
+
if (!background)
|
|
223
|
+
loading.set(!1);
|
|
224
|
+
isFetching.set(!1);
|
|
206
225
|
} catch (err) {
|
|
207
226
|
error.set(err instanceof Error ? err : Error(String(err)));
|
|
208
|
-
|
|
227
|
+
if (!background)
|
|
228
|
+
loading.set(!1);
|
|
229
|
+
isFetching.set(!1);
|
|
209
230
|
}
|
|
210
231
|
};
|
|
211
232
|
if (immediate)
|
|
@@ -213,11 +234,12 @@ export function useAsyncData(fetcher, options = {}) {
|
|
|
213
234
|
return {
|
|
214
235
|
data,
|
|
215
236
|
loading,
|
|
237
|
+
isFetching,
|
|
216
238
|
error,
|
|
217
239
|
status,
|
|
218
240
|
statusText,
|
|
219
|
-
refetch: doFetch,
|
|
220
|
-
execute: doFetch,
|
|
241
|
+
refetch: (refetchOptions) => doFetch(!!refetchOptions?.background),
|
|
242
|
+
execute: () => doFetch(),
|
|
221
243
|
abort: () => {}
|
|
222
244
|
};
|
|
223
245
|
}
|
|
@@ -17,13 +17,18 @@ export declare interface UseQueryOptions<T = unknown> {
|
|
|
17
17
|
onSuccess?: (data: T) => void
|
|
18
18
|
onError?: (error: Error) => void
|
|
19
19
|
}
|
|
20
|
+
/** How one run of a request should behave. */
|
|
21
|
+
export declare interface QueryRefetchOptions {
|
|
22
|
+
background?: boolean
|
|
23
|
+
}
|
|
20
24
|
export declare interface UseQueryResult<T = unknown> {
|
|
21
25
|
data: { (): T | null, set: (v: T | null) => void }
|
|
22
26
|
loading: { (): boolean, set: (v: boolean) => void }
|
|
27
|
+
isFetching: { (): boolean, set: (v: boolean) => void }
|
|
23
28
|
error: { (): string | null, set: (v: string | null) => void }
|
|
24
29
|
isStale: { (): boolean, set: (v: boolean) => void }
|
|
25
|
-
refetch: () => Promise<void>
|
|
26
|
-
invalidate: () => Promise<void>
|
|
30
|
+
refetch: (options?: QueryRefetchOptions) => Promise<void>
|
|
31
|
+
invalidate: (options?: QueryRefetchOptions) => Promise<void>
|
|
27
32
|
}
|
|
28
33
|
export declare interface UseMutationOptions<T = unknown> {
|
|
29
34
|
method?: 'POST' | 'PUT' | 'PATCH' | 'DELETE'
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build one `Set-Cookie` header value.
|
|
3
|
+
*
|
|
4
|
+
* Name and value are percent-encoded, so a session token containing `;` or `=`
|
|
5
|
+
* cannot terminate the cookie early or invent an attribute.
|
|
6
|
+
*
|
|
7
|
+
* `maxAge` is compared against `undefined` rather than tested for truthiness:
|
|
8
|
+
* `Max-Age=0` is how a cookie is DELETED, and a truthiness check drops exactly
|
|
9
|
+
* that case — leaving the cookie in place while the caller believes it cleared
|
|
10
|
+
* it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function serializeSetCookie(name: string, value: string, options?: SetCookieOptions): string;
|
|
13
|
+
/**
|
|
14
|
+
* One `Set-Cookie` serializer.
|
|
15
|
+
*
|
|
16
|
+
* There were three, byte-identical in behaviour and separately maintained:
|
|
17
|
+
* `ssr.ts` (private), `edge-runtime.ts` (`createCookie`, exported) and
|
|
18
|
+
* `composables/use-cookie.ts` (client-side, writes `document.cookie`). Page
|
|
19
|
+
* actions needed a fourth (stacksjs/stx#1927), which is the point at which
|
|
20
|
+
* copying it again stops being cheaper than sharing it — the way a set of
|
|
21
|
+
* duplicated implementations goes wrong is by drifting, and an attribute that
|
|
22
|
+
* one of them emits and another does not is a cookie that works on one code
|
|
23
|
+
* path and silently does not on the next.
|
|
24
|
+
*
|
|
25
|
+
* The client-side one in `use-cookie.ts` is deliberately left alone: it runs in
|
|
26
|
+
* a browser against `document.cookie`, where `HttpOnly` is meaningless and the
|
|
27
|
+
* encoding rules differ.
|
|
28
|
+
*
|
|
29
|
+
* @module cookie-serialize
|
|
30
|
+
*/
|
|
31
|
+
/** Attributes of a `Set-Cookie` header. */
|
|
32
|
+
export declare interface SetCookieOptions {
|
|
33
|
+
maxAge?: number
|
|
34
|
+
expires?: Date
|
|
35
|
+
path?: string
|
|
36
|
+
domain?: string
|
|
37
|
+
secure?: boolean
|
|
38
|
+
httpOnly?: boolean
|
|
39
|
+
sameSite?: 'Strict' | 'Lax' | 'None'
|
|
40
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function serializeSetCookie(name, value, options = {}) {
|
|
2
|
+
let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
|
|
3
|
+
if (options.maxAge !== void 0)
|
|
4
|
+
cookie += `; Max-Age=${options.maxAge}`;
|
|
5
|
+
if (options.expires)
|
|
6
|
+
cookie += `; Expires=${options.expires.toUTCString()}`;
|
|
7
|
+
if (options.path)
|
|
8
|
+
cookie += `; Path=${options.path}`;
|
|
9
|
+
if (options.domain)
|
|
10
|
+
cookie += `; Domain=${options.domain}`;
|
|
11
|
+
if (options.secure)
|
|
12
|
+
cookie += "; Secure";
|
|
13
|
+
if (options.httpOnly)
|
|
14
|
+
cookie += "; HttpOnly";
|
|
15
|
+
if (options.sameSite)
|
|
16
|
+
cookie += `; SameSite=${options.sameSite}`;
|
|
17
|
+
return cookie;
|
|
18
|
+
}
|