@caqophony/ui 0.5.1 → 0.6.0

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.
@@ -92,6 +92,20 @@ interface ArtPoly extends ArtFilled {
92
92
  el: 'polygon' | 'polyline';
93
93
  points: ReadonlyArray<readonly [number, number]>;
94
94
  }
95
+ /**
96
+ * #5998 — a ground: the author states where it sits in its frame (`y`) and its
97
+ * tone, and the code runs it the scene's full width and down past its foot
98
+ * (`GROUND_BLEED`), as the approved ports drew theirs by hand (x -4000 to
99
+ * 8000). It stands in a frame's own `nodes` only (the format's check names one
100
+ * in a group or a motif), so no transform moves its bleed. A `HeroScene` clips
101
+ * the sides, and the next band paints over the foot.
102
+ */
103
+ interface ArtGround {
104
+ el: 'ground';
105
+ y: number;
106
+ fill?: ArtPaint;
107
+ opacity?: number;
108
+ }
95
109
  interface ArtText extends ArtFilled {
96
110
  el: 'text';
97
111
  x: number;
@@ -102,7 +116,7 @@ interface ArtText extends ArtFilled {
102
116
  /** Words on the page, apart from the drawing: step 5 holds them to the Brief. */
103
117
  copy: string;
104
118
  }
105
- type ArtNode = ArtGroup | ArtPath | ArtRect | ArtCircle | ArtEllipse | ArtLine | ArtPoly | ArtText;
119
+ type ArtNode = ArtGroup | ArtPath | ArtRect | ArtCircle | ArtEllipse | ArtLine | ArtPoly | ArtText | ArtGround;
106
120
  /** Where a frame stays when its box has another shape. */
107
121
  type ArtAnchor = 'top' | 'center' | 'bottom' | 'right';
108
122
  /** `cover` fills the box and may cut the frame; `contain` keeps all of it. */
@@ -127,11 +141,30 @@ interface ArtTree {
127
141
  }
128
142
  /** The one writer of how a frame sits in its box, for `Art` and `SkyField`. */
129
143
  declare const preserveOf: (anchor: ArtAnchor, fit?: ArtFit) => string;
144
+ /**
145
+ * #6002 — how an `Art` frame sits in its box. A frame whose own `nodes` hold a
146
+ * `ground` stands on its box's foot (`YMax`) whatever its `anchor`, whose
147
+ * horizontal part it keeps: a hero's side frame is `contain`ed in a column
148
+ * taller than it, and a centred one put its ground at the copy's height
149
+ * (blind check 9, jobpilot-a: `y` 840 of 1000 under the CTAs from 1024 up).
150
+ * The objects standing on the ground are in the same frame units, so the whole
151
+ * frame moves, never the ground alone. Every other frame, and `SkyField`, keep
152
+ * `preserveOf`.
153
+ */
154
+ declare const framePreserveOf: (frame: Pick<ArtFrame, "anchor" | "fit" | "nodes">) => string;
130
155
  /** The one writer of where frames are cut, for `Art` and `SkyField`. */
131
156
  declare const frameClass: (only: ArtOnly | undefined) => string;
157
+ /**
158
+ * #5998 — how far a ground runs past its frame, each way and down, in the
159
+ * frame's larger side. Measured on the gencheck-8 answers and the three ports
160
+ * at every gate width: the scene runs past a frame's drawn content by at most
161
+ * 1.09 of that side (1600px wide), and from `lg` up the side draws at 750px
162
+ * or more, so 8 covers a scene about 6,600px wide.
163
+ */
164
+ declare const GROUND_BLEED = 8;
132
165
  /** Draws a piece of art, for a `Figure`'s slot or a mark. */
133
166
  declare function Art({ tree }: {
134
167
  tree: ArtTree;
135
168
  }): ReactElement;
136
169
 
137
- export { Art, type ArtAnchor, type ArtCircle, type ArtDrawing, type ArtEllipse, type ArtFilled, type ArtFit, type ArtFrame, type ArtGroup, type ArtLine, type ArtNode, type ArtOnly, type ArtPaint, type ArtPath, type ArtPoly, type ArtRect, type ArtText, type ArtTransform, type ArtTree, frameClass, preserveOf };
170
+ export { Art, type ArtAnchor, type ArtCircle, type ArtDrawing, type ArtEllipse, type ArtFilled, type ArtFit, type ArtFrame, type ArtGround, type ArtGroup, type ArtLine, type ArtNode, type ArtOnly, type ArtPaint, type ArtPath, type ArtPoly, type ArtRect, type ArtText, type ArtTransform, type ArtTree, GROUND_BLEED, frameClass, framePreserveOf, preserveOf };
@@ -48,7 +48,15 @@ var ANCHOR = {
48
48
  bottom: "xMidYMax",
49
49
  right: "xMaxYMid"
50
50
  };
51
- var preserveOf = (anchor, fit = "cover") => `${ANCHOR[anchor]} ${fit === "contain" ? "meet" : "slice"}`;
51
+ var FIT = { contain: "meet", cover: "slice" };
52
+ var preserveOf = (anchor, fit = "cover") => `${ANCHOR[anchor]} ${FIT[fit]}`;
53
+ var ANCHOR_X = {
54
+ top: "xMid",
55
+ center: "xMid",
56
+ bottom: "xMid",
57
+ right: "xMax"
58
+ };
59
+ var framePreserveOf = (frame) => frame.nodes.some((node) => node.el === "ground") ? `${ANCHOR_X[frame.anchor]}YMax ${FIT[frame.fit ?? "cover"]}` : preserveOf(frame.anchor, frame.fit);
52
60
  var SHOWN = {
53
61
  phone: "size-full md:hidden",
54
62
  desktop: "hidden size-full md:block",
@@ -96,10 +104,14 @@ function drawn(node) {
96
104
  transform: node.transform?.map(transformOf).join(" ")
97
105
  };
98
106
  }
99
- function render(node, key) {
107
+ var GROUND_BLEED = 8;
108
+ function render(frame) {
109
+ return (node, key) => drawNode(node, key, frame);
110
+ }
111
+ function drawNode(node, key, frame) {
100
112
  switch (node.el) {
101
113
  case "g":
102
- return /* @__PURE__ */ jsx("g", { ...drawn(node), children: node.children.map(render) }, key);
114
+ return /* @__PURE__ */ jsx("g", { ...drawn(node), children: node.children.map(render(frame)) }, key);
103
115
  case "path":
104
116
  return /* @__PURE__ */ jsx("path", { d: node.d, ...drawn(node) }, key);
105
117
  case "rect":
@@ -169,6 +181,22 @@ function render(node, key) {
169
181
  },
170
182
  key
171
183
  );
184
+ case "ground": {
185
+ const bleed = GROUND_BLEED * Math.max(frame.width, frame.height);
186
+ return /* @__PURE__ */ jsx(
187
+ "rect",
188
+ {
189
+ "data-art-ground": "",
190
+ x: -bleed,
191
+ y: node.y,
192
+ width: frame.width + 2 * bleed,
193
+ height: Math.max(frame.height - node.y, 0) + bleed,
194
+ opacity: node.opacity,
195
+ ...painted(node)
196
+ },
197
+ key
198
+ );
199
+ }
172
200
  case "text":
173
201
  return /* @__PURE__ */ jsx(
174
202
  "text",
@@ -195,16 +223,19 @@ function Art({ tree }) {
195
223
  "svg",
196
224
  {
197
225
  viewBox: `0 0 ${frame.width} ${frame.height}`,
198
- preserveAspectRatio: preserveOf(frame.anchor, frame.fit),
226
+ preserveAspectRatio: framePreserveOf(frame),
227
+ "data-art-only": frame.only,
199
228
  "aria-hidden": "true",
200
229
  className: frameClass(frame.only),
201
- children: frame.nodes.map(render)
230
+ children: frame.nodes.map(render(frame))
202
231
  },
203
232
  i
204
233
  )) });
205
234
  }
206
235
  export {
207
236
  Art,
237
+ GROUND_BLEED,
208
238
  frameClass,
239
+ framePreserveOf,
209
240
  preserveOf
210
241
  };
package/dist/material.js CHANGED
@@ -89,7 +89,8 @@ var ANCHOR = {
89
89
  bottom: "xMidYMax",
90
90
  right: "xMaxYMid"
91
91
  };
92
- var preserveOf = (anchor, fit = "cover") => `${ANCHOR[anchor]} ${fit === "contain" ? "meet" : "slice"}`;
92
+ var FIT = { contain: "meet", cover: "slice" };
93
+ var preserveOf = (anchor, fit = "cover") => `${ANCHOR[anchor]} ${FIT[fit]}`;
93
94
  var SHOWN = {
94
95
  phone: "size-full md:hidden",
95
96
  desktop: "hidden size-full md:block",
@@ -780,6 +781,7 @@ var HEIGHT2 = {
780
781
  tall: "lg:min-h-[46rem]"
781
782
  };
782
783
  var CLIP_ABOVE = "[clip-path:inset(0_0_-100vh_0)]";
784
+ var COPY_CONTAINER = "lg:[container-type:inline-size] lg:[container-name:hero-copy]";
783
785
  function HeroScene({
784
786
  height,
785
787
  subject,
@@ -800,6 +802,7 @@ function HeroScene({
800
802
  "data-hero-copy": "",
801
803
  className: cn(
802
804
  "relative z-10 flex min-w-0 flex-col items-start justify-center gap-6 py-10 md:py-14",
805
+ COPY_CONTAINER,
803
806
  CONTENT_GUTTER,
804
807
  copySide === "end" && "lg:order-2"
805
808
  ),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caqophony/ui",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Generic, optional React UI reuse library (Gossamer tokens). Centrally maintained by Caqophony.",
5
5
  "license": "MIT",
6
6
  "author": "Caqophony",
package/styles.css CHANGED
@@ -289,6 +289,12 @@
289
289
  line-height: 1.5;
290
290
  }
291
291
 
292
+ @container hero-copy (width > 0px) {
293
+ .text-display-poster {
294
+ font-size: min(clamp(3rem, 1.05rem + 8vw, 7rem), calc(100cqi * 7 / 33.5));
295
+ }
296
+ }
297
+
292
298
  [data-page-surface='marketing'] {
293
299
  --page-bg: var(--background);
294
300
  --section-band: color-mix(in srgb, hsl(var(--foreground)) 8%, hsl(var(--background)));