@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/signals.js
CHANGED
|
@@ -1065,6 +1065,10 @@ finally {
|
|
|
1065
1065
|
// case where a template is most likely driving a spinner off it (#1818).
|
|
1066
1066
|
const immediate = options.immediate !== false;
|
|
1067
1067
|
const loading = state(immediate);
|
|
1068
|
+
// Any request in flight, background ones included. loading answers "is
|
|
1069
|
+
// there nothing to show yet"; isFetching answers "is a request open" \u2014 and
|
|
1070
|
+
// a background refresh is the case where those two stop agreeing (#1929).
|
|
1071
|
+
const isFetching = state(immediate);
|
|
1068
1072
|
const error = state(null);
|
|
1069
1073
|
if (options.suspense) registerSuspense(loading, error);
|
|
1070
1074
|
|
|
@@ -1074,17 +1078,24 @@ finally {
|
|
|
1074
1078
|
// last in-flight one. State writes are guarded on signal.aborted (#1871).
|
|
1075
1079
|
let __stxAbort = null;
|
|
1076
1080
|
|
|
1077
|
-
|
|
1081
|
+
// runOptions: { background: true } refreshes data WITHOUT touching loading
|
|
1082
|
+
// or clearing the current error, so a poll cannot flash a spinner or blank
|
|
1083
|
+
// an error message that is still true. Everything already on screen stays
|
|
1084
|
+
// there until the new response actually lands (#1929).
|
|
1085
|
+
const fetchData = async (runOptions) => {
|
|
1086
|
+
const background = !!(runOptions && runOptions.background);
|
|
1078
1087
|
if (__stxAbort) __stxAbort.abort();
|
|
1079
1088
|
__stxAbort = (typeof AbortController !== 'undefined') ? new AbortController() : null;
|
|
1080
1089
|
const __signal = __stxAbort ? __stxAbort.signal : undefined;
|
|
1081
|
-
loading.set(true);
|
|
1082
|
-
|
|
1090
|
+
if (!background) loading.set(true);
|
|
1091
|
+
isFetching.set(true);
|
|
1092
|
+
if (!background) error.set(null);
|
|
1083
1093
|
|
|
1084
1094
|
try {
|
|
1085
1095
|
const url = typeof urlOrFn === 'function' ? urlOrFn() : urlOrFn;
|
|
1086
1096
|
if (!url) {
|
|
1087
|
-
loading.set(false);
|
|
1097
|
+
if (!background) loading.set(false);
|
|
1098
|
+
isFetching.set(false);
|
|
1088
1099
|
return;
|
|
1089
1100
|
}
|
|
1090
1101
|
|
|
@@ -1114,6 +1125,10 @@ finally {
|
|
|
1114
1125
|
// Apply transform if provided
|
|
1115
1126
|
const transformed = options.transform ? options.transform(result) : result;
|
|
1116
1127
|
data.set(transformed);
|
|
1128
|
+
// A background run did not clear the error up front, so a recovery has
|
|
1129
|
+
// to clear it here \u2014 otherwise the first failed poll would leave the
|
|
1130
|
+
// message on screen for the life of the page.
|
|
1131
|
+
if (background) error.set(null);
|
|
1117
1132
|
}
|
|
1118
1133
|
catch (e) {
|
|
1119
1134
|
// A superseded/unmounted request rejects with AbortError \u2014 expected,
|
|
@@ -1128,7 +1143,10 @@ catch (e) {
|
|
|
1128
1143
|
}
|
|
1129
1144
|
finally {
|
|
1130
1145
|
// If a newer run (or onDestroy) aborted this one, that run owns loading.
|
|
1131
|
-
if (!__signal || !__signal.aborted)
|
|
1146
|
+
if (!__signal || !__signal.aborted) {
|
|
1147
|
+
if (!background) loading.set(false);
|
|
1148
|
+
isFetching.set(false);
|
|
1149
|
+
}
|
|
1132
1150
|
}
|
|
1133
1151
|
};
|
|
1134
1152
|
|
|
@@ -1161,6 +1179,7 @@ else if (immediate) {
|
|
|
1161
1179
|
return {
|
|
1162
1180
|
data,
|
|
1163
1181
|
loading,
|
|
1182
|
+
isFetching,
|
|
1164
1183
|
error,
|
|
1165
1184
|
refetch: fetchData,
|
|
1166
1185
|
// Convenience getters
|
|
@@ -1411,6 +1430,10 @@ else if (immediate) {
|
|
|
1411
1430
|
var cacheKey = options.cacheKey || (typeof url === 'function' ? null : url);
|
|
1412
1431
|
var data = state(options.initialData || null);
|
|
1413
1432
|
var loading = state(true);
|
|
1433
|
+
// See useFetch: loading means "nothing to show yet", isFetching means "a
|
|
1434
|
+
// request is open" \u2014 including a background refresh, which is the case that
|
|
1435
|
+
// makes the distinction necessary (#1929).
|
|
1436
|
+
var isFetching = state(true);
|
|
1414
1437
|
var error = state(null);
|
|
1415
1438
|
var isStale = state(false);
|
|
1416
1439
|
if (options.suspense) registerSuspense(loading, error);
|
|
@@ -1429,16 +1452,21 @@ else if (immediate) {
|
|
|
1429
1452
|
// can release its claim without cancelling a request someone else joined.
|
|
1430
1453
|
var __joined = null;
|
|
1431
1454
|
|
|
1432
|
-
|
|
1455
|
+
// runOptions: { background: true } refreshes without touching loading or
|
|
1456
|
+
// clearing the current error. A poll must not flash a spinner over data
|
|
1457
|
+
// that is already on screen (#1929).
|
|
1458
|
+
var fetchData = async function(runOptions) {
|
|
1459
|
+
var background = !!(runOptions && runOptions.background);
|
|
1433
1460
|
var resolvedUrl = typeof url === 'function' ? url() : url;
|
|
1434
|
-
if (!resolvedUrl) { loading.set(false); return; }
|
|
1461
|
+
if (!resolvedUrl) { if (!background) loading.set(false); isFetching.set(false); return; }
|
|
1435
1462
|
var key = cacheKey || resolvedUrl;
|
|
1436
1463
|
|
|
1437
1464
|
// Check cache
|
|
1438
1465
|
var cached = _queryCache[key];
|
|
1439
1466
|
if (cached && (Date.now() - cached.timestamp < staleTime)) {
|
|
1440
1467
|
data.set(cached.data);
|
|
1441
|
-
loading.set(false);
|
|
1468
|
+
if (!background) loading.set(false);
|
|
1469
|
+
isFetching.set(false);
|
|
1442
1470
|
isStale.set(false);
|
|
1443
1471
|
if (options.onSuccess) options.onSuccess(cached.data);
|
|
1444
1472
|
return;
|
|
@@ -1458,12 +1486,14 @@ else if (immediate) {
|
|
|
1458
1486
|
if (shared && shared.owner !== __instanceId) {
|
|
1459
1487
|
shared.refs++;
|
|
1460
1488
|
__joined = shared;
|
|
1461
|
-
loading.set(true);
|
|
1462
|
-
|
|
1489
|
+
if (!background) loading.set(true);
|
|
1490
|
+
isFetching.set(true);
|
|
1491
|
+
if (!background) error.set(null);
|
|
1463
1492
|
try {
|
|
1464
1493
|
var joinedResult = await shared.promise;
|
|
1465
1494
|
var joinedTransformed = options.transform ? options.transform(joinedResult) : joinedResult;
|
|
1466
1495
|
data.set(joinedTransformed);
|
|
1496
|
+
if (background) error.set(null);
|
|
1467
1497
|
isStale.set(false);
|
|
1468
1498
|
if (options.onSuccess) options.onSuccess(joinedTransformed);
|
|
1469
1499
|
}
|
|
@@ -1475,7 +1505,8 @@ else if (immediate) {
|
|
|
1475
1505
|
finally {
|
|
1476
1506
|
shared.refs--;
|
|
1477
1507
|
if (__joined === shared) __joined = null;
|
|
1478
|
-
loading.set(false);
|
|
1508
|
+
if (!background) loading.set(false);
|
|
1509
|
+
isFetching.set(false);
|
|
1479
1510
|
}
|
|
1480
1511
|
return;
|
|
1481
1512
|
}
|
|
@@ -1490,8 +1521,9 @@ else if (immediate) {
|
|
|
1490
1521
|
__joined = null;
|
|
1491
1522
|
__stxAbort = (typeof AbortController !== 'undefined') ? new AbortController() : null;
|
|
1492
1523
|
var __signal = __stxAbort ? __stxAbort.signal : undefined;
|
|
1493
|
-
loading.set(true);
|
|
1494
|
-
|
|
1524
|
+
if (!background) loading.set(true);
|
|
1525
|
+
isFetching.set(true);
|
|
1526
|
+
if (!background) error.set(null);
|
|
1495
1527
|
try {
|
|
1496
1528
|
var fetchOpts = { method: 'GET', headers: { 'Content-Type': 'application/json', ...__stxHeaders(options.headers) }, signal: __signal };
|
|
1497
1529
|
// Published BEFORE it is awaited, so a caller starting in the same tick
|
|
@@ -1515,6 +1547,7 @@ else if (immediate) {
|
|
|
1515
1547
|
if (__signal && __signal.aborted) return;
|
|
1516
1548
|
var transformed = options.transform ? options.transform(result) : result;
|
|
1517
1549
|
data.set(transformed);
|
|
1550
|
+
if (background) error.set(null);
|
|
1518
1551
|
isStale.set(false);
|
|
1519
1552
|
_queryCache[key] = { data: transformed, timestamp: Date.now() };
|
|
1520
1553
|
if (options.onSuccess) options.onSuccess(transformed);
|
|
@@ -1529,7 +1562,10 @@ catch (e) {
|
|
|
1529
1562
|
if (options.onError) options.onError(e);
|
|
1530
1563
|
}
|
|
1531
1564
|
finally {
|
|
1532
|
-
if (!__signal || !__signal.aborted)
|
|
1565
|
+
if (!__signal || !__signal.aborted) {
|
|
1566
|
+
if (!background) loading.set(false);
|
|
1567
|
+
isFetching.set(false);
|
|
1568
|
+
}
|
|
1533
1569
|
}
|
|
1534
1570
|
};
|
|
1535
1571
|
|
|
@@ -1537,13 +1573,20 @@ finally {
|
|
|
1537
1573
|
onMount(fetchData);
|
|
1538
1574
|
}
|
|
1539
1575
|
|
|
1576
|
+
// A refetch nobody asked for does not set loading. Both of these refresh
|
|
1577
|
+
// data that is ALREADY on screen, so driving the first-load state from them
|
|
1578
|
+
// put a spinner over a populated view once a minute, forever \u2014 the reason a
|
|
1579
|
+
// polling view could not use this composable at all (#1929). Bind
|
|
1580
|
+
// isFetching for a subtle in-flight indicator.
|
|
1581
|
+
var backgroundRun = { background: true };
|
|
1582
|
+
|
|
1540
1583
|
// refetchOnFocus \u2014 removed on destroy, like refetchInterval right below.
|
|
1541
1584
|
// It used to add a listener and never remove it, so every instance leaked
|
|
1542
1585
|
// one for the life of the page and each SPA navigation added more; every
|
|
1543
1586
|
// stale listener still fired, refetching for components long gone (#1818).
|
|
1544
1587
|
if (options.refetchOnFocus) {
|
|
1545
1588
|
var onVisibility = function() {
|
|
1546
|
-
if (!document.hidden) fetchData();
|
|
1589
|
+
if (!document.hidden) fetchData(backgroundRun);
|
|
1547
1590
|
};
|
|
1548
1591
|
document.addEventListener('visibilitychange', onVisibility);
|
|
1549
1592
|
onDestroy(function() { document.removeEventListener('visibilitychange', onVisibility); });
|
|
@@ -1557,7 +1600,7 @@ finally {
|
|
|
1557
1600
|
if (typeof document !== 'undefined' && document.hidden) return;
|
|
1558
1601
|
var en = options.enabled;
|
|
1559
1602
|
if (typeof en === 'function' ? !en() : en === false) return;
|
|
1560
|
-
var p = fetchData();
|
|
1603
|
+
var p = fetchData(backgroundRun);
|
|
1561
1604
|
if (options.stopOnError && p && typeof p.then === 'function') {
|
|
1562
1605
|
p.then(function() { if (error()) clearInterval(intervalId); });
|
|
1563
1606
|
}
|
|
@@ -1571,13 +1614,14 @@ finally {
|
|
|
1571
1614
|
return {
|
|
1572
1615
|
data: data,
|
|
1573
1616
|
loading: loading,
|
|
1617
|
+
isFetching: isFetching,
|
|
1574
1618
|
error: error,
|
|
1575
1619
|
isStale: isStale,
|
|
1576
1620
|
refetch: fetchData,
|
|
1577
|
-
invalidate: function() {
|
|
1621
|
+
invalidate: function(runOptions) {
|
|
1578
1622
|
var key = cacheKey || (typeof url === 'function' ? url() : url);
|
|
1579
1623
|
delete _queryCache[key];
|
|
1580
|
-
return fetchData();
|
|
1624
|
+
return fetchData(runOptions);
|
|
1581
1625
|
}
|
|
1582
1626
|
};
|
|
1583
1627
|
}
|
|
@@ -2145,11 +2189,18 @@ catch (e) {
|
|
|
2145
2189
|
if (!el || !el.getAttribute || value === undefined) return;
|
|
2146
2190
|
var scopeId = el.getAttribute('data-stx-scope');
|
|
2147
2191
|
var scopeVars = scopeId && window.stx._scopes && window.stx._scopes[scopeId];
|
|
2148
|
-
if (!scopeVars) return;
|
|
2149
2192
|
var camelName = name.replace(/-([a-z0-9])/g, function(_, character) {
|
|
2150
2193
|
return character.toUpperCase();
|
|
2151
2194
|
});
|
|
2152
|
-
|
|
2195
|
+
// useReactiveProp signals are often intentionally aliased inside the
|
|
2196
|
+
// child, for example liveClosable = useReactiveProp('closable', true).
|
|
2197
|
+
// The public prop name therefore cannot be inferred from the variable
|
|
2198
|
+
// name exported by the component scope. Keep an element-owned registry as
|
|
2199
|
+
// the canonical bridge, with the scope lookup retained for older output.
|
|
2200
|
+
var propSignals = el.__stx_reactive_prop_signals;
|
|
2201
|
+
var propSignal = propSignals && (propSignals[name] || propSignals[camelName]);
|
|
2202
|
+
if (!propSignal && scopeVars)
|
|
2203
|
+
propSignal = scopeVars[name] || scopeVars[camelName];
|
|
2153
2204
|
if (!propSignal || !propSignal._isSignal || typeof propSignal.set !== 'function') return;
|
|
2154
2205
|
var directValues = el.__stx_direct_prop_values || (el.__stx_direct_prop_values = {});
|
|
2155
2206
|
var directValue = {
|
|
@@ -2477,13 +2528,12 @@ else if (part) {
|
|
|
2477
2528
|
}
|
|
2478
2529
|
|
|
2479
2530
|
// x-else / x-else-if are owned by their preceding x-if chain (#1734).
|
|
2480
|
-
//
|
|
2481
|
-
// iteration must be skipped
|
|
2482
|
-
//
|
|
2483
|
-
//
|
|
2484
|
-
//
|
|
2485
|
-
|
|
2486
|
-
if (el.__stx_chain_member && !el.isConnected) return;
|
|
2531
|
+
// An inactive chain member reached via the parent's snapshot child-
|
|
2532
|
+
// iteration must be skipped. Connectivity cannot identify inactivity:
|
|
2533
|
+
// an active inner branch is also disconnected while an outer conditional
|
|
2534
|
+
// temporarily detaches its parent. bindIfChain owns explicit branch state
|
|
2535
|
+
// so nested structural effects can still hydrate active detached subtrees.
|
|
2536
|
+
if (el.__stx_chain_member && !el.__stx_chain_active) return;
|
|
2487
2537
|
|
|
2488
2538
|
// An else/else-if with no preceding if is an orphan. Match Vue: warn,
|
|
2489
2539
|
// strip the attribute, and render it as a plain element (fall through).
|
|
@@ -2769,12 +2819,16 @@ else if (name === 'ref' || name === ':ref' || name === 'x-ref' || name === 'data
|
|
|
2769
2819
|
? event.detail
|
|
2770
2820
|
: event;
|
|
2771
2821
|
|
|
2772
|
-
// Skip
|
|
2773
|
-
//
|
|
2822
|
+
// Skip an opener click that reaches UI which just became visible in
|
|
2823
|
+
// this frame. A click whose target is inside the revealed subtree is
|
|
2824
|
+
// a real interaction and must not be discarded, especially for
|
|
2825
|
+
// async lists whose controls are usable as soon as they render.
|
|
2774
2826
|
if (eventName === 'click') {
|
|
2775
2827
|
var ancestor = el;
|
|
2776
2828
|
while (ancestor) {
|
|
2777
|
-
if (ancestor.__stx_shown_at
|
|
2829
|
+
if (ancestor.__stx_shown_at
|
|
2830
|
+
&& (performance.now() - ancestor.__stx_shown_at) < 50
|
|
2831
|
+
&& !(ancestor.contains && ancestor.contains(event.target))) return;
|
|
2778
2832
|
ancestor = ancestor.parentElement;
|
|
2779
2833
|
}
|
|
2780
2834
|
}
|
|
@@ -4171,6 +4225,7 @@ catch (e) {
|
|
|
4171
4225
|
preserveConditionalComponentScopes(b.el, capturedComponentScope);
|
|
4172
4226
|
b.el.__stx_if_bound = true;
|
|
4173
4227
|
b.el.__stx_chain_member = true;
|
|
4228
|
+
b.el.__stx_chain_active = false;
|
|
4174
4229
|
b.capturedElementScope = findElementScope(b.el);
|
|
4175
4230
|
b.placeholder = document.createComment('stx-if-chain');
|
|
4176
4231
|
parent.insertBefore(b.placeholder, b.el);
|
|
@@ -4270,12 +4325,14 @@ catch (e2) {
|
|
|
4270
4325
|
// components under reactive conditionals (#1737). Permanent disposal is
|
|
4271
4326
|
// still handled by bindFor (item removal) and cleanupContainer (SPA nav).
|
|
4272
4327
|
if (currentIdx !== -1) {
|
|
4328
|
+
chain[currentIdx].el.__stx_chain_active = false;
|
|
4273
4329
|
chain[currentIdx].nodes.forEach(function (n) { if (n.parentNode) n.parentNode.removeChild(n); });
|
|
4274
4330
|
}
|
|
4275
4331
|
|
|
4276
4332
|
// Insert + process the newly-picked branch.
|
|
4277
4333
|
if (pickedIdx !== -1) {
|
|
4278
4334
|
var pick = chain[pickedIdx];
|
|
4335
|
+
pick.el.__stx_chain_active = true;
|
|
4279
4336
|
// Insert this branch's node(s) before the placeholder's next sibling.
|
|
4280
4337
|
// The anchor is captured once so the nodes stack in source order.
|
|
4281
4338
|
var anchor = pick.placeholder.nextSibling;
|
|
@@ -5474,6 +5531,11 @@ catch (e) {} }
|
|
|
5474
5531
|
}
|
|
5475
5532
|
var s = state(initial);
|
|
5476
5533
|
if (!root) return s;
|
|
5534
|
+
var propSignals = root.__stx_reactive_prop_signals
|
|
5535
|
+
|| (root.__stx_reactive_prop_signals = {});
|
|
5536
|
+
propSignals[name] = s;
|
|
5537
|
+
propSignals[kebabName] = s;
|
|
5538
|
+
propSignals[lowerName] = s;
|
|
5477
5539
|
var observer = new MutationObserver(function() {
|
|
5478
5540
|
var attribute = readAttribute();
|
|
5479
5541
|
var hasAttr = attribute.has;
|
|
@@ -5496,7 +5558,12 @@ catch (e) {} }
|
|
|
5496
5558
|
if (next !== s()) s.set(next);
|
|
5497
5559
|
});
|
|
5498
5560
|
observer.observe(root, { attributes: true, attributeFilter: attributeNames });
|
|
5499
|
-
onDestroy(function() {
|
|
5561
|
+
onDestroy(function() {
|
|
5562
|
+
observer.disconnect();
|
|
5563
|
+
attributeNames.forEach(function(attributeName) {
|
|
5564
|
+
if (propSignals[attributeName] === s) delete propSignals[attributeName];
|
|
5565
|
+
});
|
|
5566
|
+
});
|
|
5500
5567
|
return s;
|
|
5501
5568
|
}
|
|
5502
5569
|
|
|
@@ -7152,6 +7219,49 @@ else {
|
|
|
7152
7219
|
});
|
|
7153
7220
|
var pageScopeSnapshot = { ...componentScope };
|
|
7154
7221
|
|
|
7222
|
+
/*
|
|
7223
|
+
* Any x-data scope the reactive bridge did not reach, initialized here.
|
|
7224
|
+
*
|
|
7225
|
+
* The bridge script addresses each scope by a selector it generated, and
|
|
7226
|
+
* that numbering restarts per render - so a page carrying three component
|
|
7227
|
+
* islands emits three scripts all looking for the same scope id, and two of
|
|
7228
|
+
* the three scopes are never initialized at all. The symptom is the
|
|
7229
|
+
* quietest one available: the markup is there, every binding shows its
|
|
7230
|
+
* initial value, and whatever x-init was meant to start never starts.
|
|
7231
|
+
*
|
|
7232
|
+
* Registered scopes are skipped, so the bridge stays authoritative where it
|
|
7233
|
+
* did run and this only picks up what it missed. The init expression is
|
|
7234
|
+
* read from data-stx-xinit, which the server preserves for exactly this.
|
|
7235
|
+
*
|
|
7236
|
+
* No backticks in this comment, deliberately: it lives inside the runtime
|
|
7237
|
+
* source that is embedded as a template literal, and one would end the
|
|
7238
|
+
* literal and take the whole file's syntax with it.
|
|
7239
|
+
*/
|
|
7240
|
+
if (window.__stx_reactive && window.__stx_reactive.initScope) {
|
|
7241
|
+
document.querySelectorAll('[data-stx-xdata]').forEach(function(el) {
|
|
7242
|
+
var scopeId = el.getAttribute('data-stx-scope');
|
|
7243
|
+
if (scopeId && window.stx._scopes && window.stx._scopes[scopeId]) return;
|
|
7244
|
+
if (el.__stx_scope_initialized) return;
|
|
7245
|
+
|
|
7246
|
+
var xdata = el.getAttribute('data-stx-xdata');
|
|
7247
|
+
if (!xdata) return;
|
|
7248
|
+
|
|
7249
|
+
if (!scopeId) {
|
|
7250
|
+
scopeId = '__stx_scope_island_' + (++window.stx._scopeCounter);
|
|
7251
|
+
el.setAttribute('data-stx-scope', scopeId);
|
|
7252
|
+
}
|
|
7253
|
+
|
|
7254
|
+
el.__stx_scope_initialized = true;
|
|
7255
|
+
|
|
7256
|
+
try {
|
|
7257
|
+
window.__stx_reactive.initScope(el, xdata, [], {}, el.getAttribute('data-stx-xinit') || null);
|
|
7258
|
+
}
|
|
7259
|
+
catch (e) {
|
|
7260
|
+
console.error('[stx] island scope init error:', e);
|
|
7261
|
+
}
|
|
7262
|
+
});
|
|
7263
|
+
}
|
|
7264
|
+
|
|
7155
7265
|
// Process mount queue (from stx.mount() calls during loading) only after
|
|
7156
7266
|
// caller setup is available for Vue-style projected slot ownership.
|
|
7157
7267
|
mountQueue.forEach(function(fn) { fn(); });
|
|
@@ -7516,7 +7626,11 @@ catch (e) {
|
|
|
7516
7626
|
var walker = document.createTreeWalker(root, showText, null);
|
|
7517
7627
|
var node;
|
|
7518
7628
|
while ((node = walker.nextNode())) {
|
|
7519
|
-
|
|
7629
|
+
// Browsers expose Text.nodeValue as a string, while lightweight DOM and
|
|
7630
|
+
// native embedding shims can preserve an assigned number. Diagnostics
|
|
7631
|
+
// must normalize the boundary instead of aborting the entire audit on a
|
|
7632
|
+
// missing String#indexOf method.
|
|
7633
|
+
var text = node.nodeValue == null ? '' : String(node.nodeValue);
|
|
7520
7634
|
if (text.indexOf('{{') === -1 || text.indexOf('}}') === -1) continue;
|
|
7521
7635
|
if (auditSkipped(node)) continue;
|
|
7522
7636
|
found.push(text.trim().slice(0, 80));
|
|
@@ -7772,8 +7886,14 @@ catch (e) { console.warn('[stx] destroy callback error:', e); }
|
|
|
7772
7886
|
scopeId = '__stx_scope_spa_' + (++window.stx._scopeCounter);
|
|
7773
7887
|
el.setAttribute('data-stx-scope', scopeId);
|
|
7774
7888
|
}
|
|
7889
|
+
// The init expression, which used to be dropped here. A scope
|
|
7890
|
+
// re-initialized with its data and none of its setup renders every
|
|
7891
|
+
// binding at its initial value and starts nothing - a live region
|
|
7892
|
+
// showing its empty state forever, which is indistinguishable from one
|
|
7893
|
+
// where nothing has happened yet.
|
|
7894
|
+
var xinit = el.getAttribute('data-stx-xinit');
|
|
7775
7895
|
console.log('[stx:load] initializing x-data scope:', scopeId, xdata.substring(0, 40));
|
|
7776
|
-
window.__stx_reactive.initScope(el, xdata, [], {}, null);
|
|
7896
|
+
window.__stx_reactive.initScope(el, xdata, [], {}, xinit || null);
|
|
7777
7897
|
});
|
|
7778
7898
|
}
|
|
7779
7899
|
|
|
@@ -7864,8 +7984,10 @@ catch (e) { console.warn('[stx] destroy callback error:', e); }
|
|
|
7864
7984
|
if (el.nodeType !== Node.ELEMENT_NODE) return;
|
|
7865
7985
|
// Skip scoped elements - they were already processed
|
|
7866
7986
|
if (el.hasAttribute && el.hasAttribute('data-stx-scope')) return;
|
|
7867
|
-
//
|
|
7868
|
-
|
|
7987
|
+
// Inactive chain members are owned by bindIfChain. Use explicit branch
|
|
7988
|
+
// state because an active nested branch can live under a detached outer
|
|
7989
|
+
// conditional while its reactive effects continue to run.
|
|
7990
|
+
if (el.__stx_chain_member && !el.__stx_chain_active) return;
|
|
7869
7991
|
// Process this element's directives without recursing into children
|
|
7870
7992
|
// (we'll handle children manually to skip scoped ones)
|
|
7871
7993
|
const hasFor = el.hasAttribute && (el.hasAttribute('@for') || el.hasAttribute(':for') || el.hasAttribute('x-for'));
|
package/dist/ssg.d.ts
CHANGED
|
@@ -46,6 +46,29 @@
|
|
|
46
46
|
export interface SSGConfig {
|
|
47
47
|
/** Directory containing pages (default: 'pages') */
|
|
48
48
|
pagesDir?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Directory `@include` resolves against. Defaults to the config's
|
|
51
|
+
* `partialsDir`.
|
|
52
|
+
*
|
|
53
|
+
* `pagesDir`, `publicDir` and `outputDir` were all overridable here and these
|
|
54
|
+
* two were not, so a caller could point the build at one directory layout and
|
|
55
|
+
* silently get another for its partials (stacksjs/stx#1921).
|
|
56
|
+
*/
|
|
57
|
+
partialsDir?: string;
|
|
58
|
+
/** Directory components resolve against. Defaults to the config's `componentsDir`. */
|
|
59
|
+
componentsDir?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Fail the build when an `@include` cannot be resolved (default: true).
|
|
62
|
+
*
|
|
63
|
+
* A failed include renders the error into the page and, before this, left the
|
|
64
|
+
* build reporting `Failed: 0` with exit 0 — so the only way to find it was to
|
|
65
|
+
* read the emitted HTML, which is exactly what nobody does when the build says
|
|
66
|
+
* success. An unresolvable include is not a recoverable condition in a build:
|
|
67
|
+
* it produces a file you would never knowingly deploy.
|
|
68
|
+
*
|
|
69
|
+
* Set `false` for the old behaviour.
|
|
70
|
+
*/
|
|
71
|
+
failOnIncludeError?: boolean;
|
|
49
72
|
/** Output directory for generated files (default: 'dist') */
|
|
50
73
|
outputDir?: string;
|
|
51
74
|
/** Base URL for the site (default: '/') */
|