@jxsuite/site 2.0.0 → 2.0.1

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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/site-style.ts +37 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jxsuite/site",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "What a Jx project's page at a route consists of — routing, layout, context, head and the document that boots it",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -31,7 +31,7 @@
31
31
  "test:coverage": "bun test --isolate --coverage"
32
32
  },
33
33
  "dependencies": {
34
- "@jxsuite/runtime": "^4.0.0",
34
+ "@jxsuite/runtime": "^4.0.1",
35
35
  "@jxsuite/schema": "^2.2.0"
36
36
  }
37
37
  }
package/src/site-style.ts CHANGED
@@ -17,10 +17,16 @@
17
17
  * `@media` inside a selector inside an `@supports` means.
18
18
  *
19
19
  * The sheet is the build's. `compileStyles` (`@jxsuite/compiler`, `src/shared.ts`) writes the same
20
- * project block into every built page's `<style>`, and this builder emits the same rules in the
21
- * same order for the same block — `site-style.test.ts` holds the two byte-for-byte — because a host
22
- * that shows a page is showing what the build will ship. The one place the two were allowed to
23
- * differ was a nested element key, on the belief that "the document's own style pass covers page
20
+ * project block into every built page's `<style>`, and it does so BY CALLING THIS BUILDER — the
21
+ * compiler depends on the site package, so its project half is this function with an identity
22
+ * transposer and a resolver that records what a static build drops. A host that shows a page is
23
+ * showing what the build will ship because the two are one emitter, not because a test says so;
24
+ * `site-style.test.ts` still holds them byte-for-byte, as the guard that keeps the delegation from
25
+ * being undone. It used to be a second copy of the `:root` / `body` / selector / `@`-block split,
26
+ * and the copies disagreed twice: the compiler passed a top-level `&[...]` key through as a raw `&`
27
+ * selector, which no engine matches, and routed a top-level `colorScheme` to `body`, where
28
+ * `light-dark()` on the root cannot see it (#329). The one place the two were DELIBERATELY allowed
29
+ * to differ was a nested element key, on the belief that "the document's own style pass covers page
24
30
  * content": nothing else reads `project.json#/style`, so the canvas simply dropped a site's
25
31
  * typography and link rules while the build kept them (#296).
26
32
  */
@@ -33,11 +39,27 @@ import {
33
39
  isNestedSelectorKey,
34
40
  pureSchemeOf,
35
41
  } from "@jxsuite/runtime/css";
36
- import type { JxStyle } from "@jxsuite/schema/types";
42
+ import type { JxRef, JxStyle } from "@jxsuite/schema/types";
37
43
 
38
44
  /** Id of the injected site-style tag (replace-in-place, never accumulate). */
39
45
  export const SITE_STYLE_ID = "jx-site-style";
40
46
 
47
+ /**
48
+ * Resolve a reactive declaration — a `${…}` template or a `{ $ref }` — to what the sheet should
49
+ * say, or `null` to emit no declaration. `selector` is the rule it would have landed on (`:root`,
50
+ * `body`, a selector key, or `null` for an unscoped at-rule), which is what a report of a dropped
51
+ * declaration needs to name.
52
+ *
53
+ * The hosts omit it: a canvas or a preview tab has no scope to evaluate a project-level template
54
+ * against, so a reactive project declaration is dropped. The compiler passes a recorder so the same
55
+ * drop is REPORTED by the build (`takeDroppedReactiveStyles`) rather than silent.
56
+ */
57
+ export type SiteStyleValueResolver = (
58
+ property: string,
59
+ value: string | JxRef,
60
+ selector: string | null,
61
+ ) => string | null;
62
+
41
63
  /**
42
64
  * Build the site-style sheet text: custom properties on `:root`, plain properties on `body`,
43
65
  * selector-keyed blocks (`"h1, h2"`, `a`, `.card`) as rules of their own, `&`-keyed blocks as
@@ -59,6 +81,8 @@ export const SITE_STYLE_ID = "jx-site-style";
59
81
  * @param {Record<string, unknown>} siteStyle
60
82
  * @param {Record<string, string>} mediaQueries
61
83
  * @param {(value: string) => string} transpose - Unit transposer (canvas vh→cqh etc.)
84
+ * @param {SiteStyleValueResolver} [resolveValue] - What a reactive declaration becomes; absent, it
85
+ * is dropped, which is what every host does
62
86
  * @returns {string}
63
87
  * @docs studio/interface/canvas
64
88
  */
@@ -66,6 +90,7 @@ export function buildSiteStyleCSS(
66
90
  siteStyle: Record<string, unknown>,
67
91
  mediaQueries: Record<string, string>,
68
92
  transpose: (value: string) => string,
93
+ resolveValue?: SiteStyleValueResolver,
69
94
  ): string {
70
95
  const rules: string[] = [];
71
96
  const push = (style: JxStyle, selector: string | null) => {
@@ -73,6 +98,13 @@ export function buildSiteStyleCSS(
73
98
  mediaQueries,
74
99
  scope: selector,
75
100
  transposeValue: transpose,
101
+ /* The selector is closed over here rather than threaded through `buildStyleRules`, whose own
102
+ hook sees a rule TARGET (self / descendant / unscoped) and not the selector it hangs off;
103
+ the compiler's report names the selector, so this is where it is known. Conditionally
104
+ spread: `exactOptionalPropertyTypes` refuses an explicit `undefined` for an optional hook. */
105
+ ...(resolveValue
106
+ ? { resolveValue: (property, value) => resolveValue(property, value, selector) }
107
+ : {}),
76
108
  })) {
77
109
  rules.push(rule.text);
78
110
  }