@stacksjs/stx 0.2.97 → 0.2.99
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/cli.js +519 -481
- package/dist/component-library.js +30 -8
- package/dist/dev-server/crosswind.d.ts +5 -5
- package/dist/dev-server/crosswind.js +2 -3
- package/dist/pwa.js +240 -240
- package/dist/screenshot.js +20 -7
- package/dist/ssg.js +200 -200
- package/dist/template-tag-balance.js +1 -1
- package/dist/web-components.js +37 -21
- package/package.json +6 -6
|
@@ -197,6 +197,17 @@ const serialize = (value, type) => {
|
|
|
197
197
|
return String(value);
|
|
198
198
|
};
|
|
199
199
|
|
|
200
|
+
const cloneDefault = (value, type) => {
|
|
201
|
+
if (value == null || (type !== 'object' && type !== 'array')) return value;
|
|
202
|
+
if (typeof structuredClone === 'function') return structuredClone(value);
|
|
203
|
+
return JSON.parse(JSON.stringify(value));
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const defaultFor = property => cloneDefault(
|
|
207
|
+
property.default ?? ({ string: '', number: 0, boolean: false, object: {}, array: [] })[property.type],
|
|
208
|
+
property.type,
|
|
209
|
+
);
|
|
210
|
+
|
|
200
211
|
export class StxElement extends HTMLElementBase {
|
|
201
212
|
static definition = {};
|
|
202
213
|
static get observedAttributes() { return this.definition.observedAttributes || []; }
|
|
@@ -206,11 +217,13 @@ export class StxElement extends HTMLElementBase {
|
|
|
206
217
|
this._values = Object.create(null);
|
|
207
218
|
this._reflecting = false;
|
|
208
219
|
this._connected = false;
|
|
220
|
+
this._hasConnected = false;
|
|
221
|
+
this._initializing = false;
|
|
209
222
|
this._updatePending = false;
|
|
210
223
|
this._listeners = new Map();
|
|
211
224
|
const definition = this.constructor.definition;
|
|
212
225
|
for (const [name, property] of Object.entries(definition.properties || {})) {
|
|
213
|
-
this._values[name] = property
|
|
226
|
+
this._values[name] = defaultFor(property);
|
|
214
227
|
}
|
|
215
228
|
if (definition.shadowMode && this.attachShadow && !this.shadowRoot) {
|
|
216
229
|
this._closedRoot = this.attachShadow({ mode: definition.shadowMode });
|
|
@@ -223,19 +236,28 @@ export class StxElement extends HTMLElementBase {
|
|
|
223
236
|
connectedCallback() {
|
|
224
237
|
if (this._connected) return;
|
|
225
238
|
this._connected = true;
|
|
239
|
+
this._initializing = true;
|
|
226
240
|
const definition = this.constructor.definition;
|
|
227
|
-
for (const name of Object.keys(definition.properties || {})) this._upgradeProperty(name);
|
|
228
241
|
for (const [name, property] of Object.entries(definition.properties || {})) {
|
|
229
242
|
const attribute = property.attribute === false ? null : (property.attribute || name.replace(/[A-Z]/g, letter => '-' + letter.toLowerCase()));
|
|
230
|
-
if (attribute && this.hasAttribute?.(attribute)) this._values[name] = deserialize(this.getAttribute(attribute), property.type,
|
|
243
|
+
if (attribute && this.hasAttribute?.(attribute)) this._values[name] = deserialize(this.getAttribute(attribute), property.type, defaultFor(property));
|
|
231
244
|
}
|
|
245
|
+
// Properties assigned before customElements.define() become own properties.
|
|
246
|
+
// Upgrade them after attributes so imperative state wins, matching the
|
|
247
|
+
// platform's property-first custom-element initialization convention.
|
|
248
|
+
for (const name of Object.keys(definition.properties || {})) this._upgradeProperty(name);
|
|
249
|
+
this._initializing = false;
|
|
232
250
|
const root = this.renderRoot;
|
|
233
251
|
const hasMarkup = [...(root.childNodes || [])].some(node => node.nodeType !== 3 || node.textContent.trim());
|
|
234
|
-
|
|
252
|
+
const firstConnection = !this._hasConnected;
|
|
253
|
+
if (!(firstConnection && definition.progressive && hasMarkup)) this._render();
|
|
235
254
|
else this._upgradeDeclarativeEvents();
|
|
236
255
|
this._bindEvents();
|
|
237
|
-
|
|
238
|
-
|
|
256
|
+
if (firstConnection) {
|
|
257
|
+
this._hasConnected = true;
|
|
258
|
+
this.setAttribute?.('hydrated', '');
|
|
259
|
+
this.dispatchEvent?.(new CustomEvent('stx:hydrated', { bubbles: true, composed: true }));
|
|
260
|
+
}
|
|
239
261
|
}
|
|
240
262
|
|
|
241
263
|
disconnectedCallback() {
|
|
@@ -250,7 +272,7 @@ export class StxElement extends HTMLElementBase {
|
|
|
250
272
|
const name = definition.attributeToProperty?.[attribute];
|
|
251
273
|
if (!name) return;
|
|
252
274
|
const property = definition.properties[name];
|
|
253
|
-
const value = deserialize(newValue, property.type, property
|
|
275
|
+
const value = deserialize(newValue, property.type, defaultFor(property));
|
|
254
276
|
if (!Object.is(this._values[name], value)) {
|
|
255
277
|
this._values[name] = value;
|
|
256
278
|
this.requestUpdate();
|
|
@@ -258,7 +280,7 @@ export class StxElement extends HTMLElementBase {
|
|
|
258
280
|
}
|
|
259
281
|
|
|
260
282
|
requestUpdate() {
|
|
261
|
-
if (!this._connected || this._updatePending) return this.updateComplete;
|
|
283
|
+
if (!this._connected || this._initializing || this._updatePending) return this.updateComplete;
|
|
262
284
|
this._updatePending = true;
|
|
263
285
|
this._updateComplete = new Promise((resolve) => {
|
|
264
286
|
queueMicrotask(() => {
|
|
@@ -15,8 +15,8 @@ export declare function resetCrosswindCache(): void;
|
|
|
15
15
|
* `stx.config.ts` and other stacks configs — a single source of truth for
|
|
16
16
|
* config loading across the stack.
|
|
17
17
|
*
|
|
18
|
-
* Pre-check:
|
|
19
|
-
*
|
|
18
|
+
* Pre-check: bunfig's lightweight discovery entry point confirms a matching
|
|
19
|
+
* project-local config exists before we load its full configuration pipeline. When
|
|
20
20
|
* stx is run from a parent repo root (e.g. running an example from the
|
|
21
21
|
* monorepo root, or a page rendered before the app dir is known) bunfig's
|
|
22
22
|
* built-in search would span 250+ paths up the tree and, on miss, log a
|
|
@@ -25,9 +25,9 @@ export declare function resetCrosswindCache(): void;
|
|
|
25
25
|
*/
|
|
26
26
|
/**
|
|
27
27
|
* Load the user's crosswind config via bunfig — our shared config loader.
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* `hasLocalConfig` uses the same filename, extension, alias, custom-directory,
|
|
29
|
+
* and resolution-priority rules as bunfig's loader, so this integration never
|
|
30
|
+
* maintains a parallel list of paths. Returns `null`
|
|
31
31
|
* when no config file is present, so callers can fall through to defaults
|
|
32
32
|
* without surfacing a "not found" warning to the user.
|
|
33
33
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
1
|
import path from "node:path";
|
|
2
|
+
import { hasLocalConfig } from "bunfig/discovery";
|
|
3
3
|
import { colors } from "./terminal-colors.js";
|
|
4
4
|
let crosswindModule = null, crosswindLoadAttempted = !1, cachedConfig = null, cachedCSS = "", isBuilding = !1;
|
|
5
5
|
const MAX_CACHE = 256, cssByClassSet = new Map;
|
|
@@ -126,8 +126,7 @@ export function resetCrosswindCache() {
|
|
|
126
126
|
}
|
|
127
127
|
export async function loadCrosswindConfig(cwd) {
|
|
128
128
|
try {
|
|
129
|
-
|
|
130
|
-
if (!configDirectories.flatMap((directory) => configNames.flatMap((name) => configExtensions.map((extension) => path.join(directory, `${name}${extension}`)))).some((candidate) => fs.existsSync(path.join(cwd, candidate))))
|
|
129
|
+
if (!hasLocalConfig({ name: "crosswind", cwd }))
|
|
131
130
|
return null;
|
|
132
131
|
const { loadConfigWithResult } = await import("bunfig"), result = await loadConfigWithResult({
|
|
133
132
|
name: "crosswind",
|