@stasho/ds 0.15.3 → 0.15.5
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/package.json
CHANGED
|
@@ -273,11 +273,25 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
273
273
|
return null;
|
|
274
274
|
})();
|
|
275
275
|
|
|
276
|
+
// asChild lends the chassis to the child element (an anchor, usually), so
|
|
277
|
+
// the label to wrap is the child's children, not the child itself.
|
|
278
|
+
const label =
|
|
279
|
+
asChild && isValidElement(children)
|
|
280
|
+
? (children.props as { children?: ReactNode }).children
|
|
281
|
+
: children;
|
|
282
|
+
|
|
276
283
|
const content = (
|
|
277
284
|
<>
|
|
278
285
|
{leadingSlot}
|
|
279
|
-
|
|
280
|
-
|
|
286
|
+
{/* Height parity by construction: empirically (consuming app), both
|
|
287
|
+
button and anchor roots compute line-height 1.5, and a bare text
|
|
288
|
+
node renders a ~6px taller line box than this leading-none wrapper.
|
|
289
|
+
[gap:inherit] passes the root's per-size flex gap through to
|
|
290
|
+
multi-child labels (text + inline icon); single-child labels are
|
|
291
|
+
unaffected — same wrapper serves both the <button> and asChild
|
|
292
|
+
paths. */}
|
|
293
|
+
<span className="inline-flex items-center leading-none [gap:inherit]">
|
|
294
|
+
{label}
|
|
281
295
|
</span>
|
|
282
296
|
{!loading && iconRight ? (
|
|
283
297
|
<span
|
|
@@ -294,11 +308,20 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
294
308
|
);
|
|
295
309
|
|
|
296
310
|
if (asChild && isValidElement(children)) {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
311
|
+
// Same inner structure as the <button> path (LED + label wrapper), so an
|
|
312
|
+
// asChild button is pixel-identical to its siblings — previously the raw
|
|
313
|
+
// child children rendered without either, making asChild buttons ~6px
|
|
314
|
+
// taller and LED-less.
|
|
315
|
+
return cloneElement(
|
|
316
|
+
children as ReactElement<Record<string, unknown>>,
|
|
317
|
+
{
|
|
318
|
+
className: classes,
|
|
319
|
+
ref,
|
|
320
|
+
"aria-busy": loading || undefined,
|
|
321
|
+
...rest,
|
|
322
|
+
},
|
|
323
|
+
content,
|
|
324
|
+
);
|
|
302
325
|
}
|
|
303
326
|
|
|
304
327
|
return (
|
|
@@ -67,14 +67,30 @@ LogoFull.displayName = "LogoFull";
|
|
|
67
67
|
/**
|
|
68
68
|
* stasho wordmark only, no icon (placeholder logotype, rebrand still deferred).
|
|
69
69
|
* Set in Anybody 800 italic to match the brand headings; the consuming app must
|
|
70
|
-
* load Anybody or it falls back to sans-serif.
|
|
71
|
-
*
|
|
70
|
+
* load Anybody or it falls back to sans-serif. Inherits color from parent via
|
|
71
|
+
* `currentColor`.
|
|
72
|
+
*
|
|
73
|
+
* The wordmark is live `<text>`, so its width is decided by whichever faces the
|
|
74
|
+
* consuming app actually loaded — not by anything this component controls. The
|
|
75
|
+
* viewBox must therefore clear the WIDEST realistic rendering: overflow clips a
|
|
76
|
+
* glyph, while underflow only leaves benign trailing space. Measured at
|
|
77
|
+
* font-size 200, `font-stretch: normal` (Chromium, 2026-08-21): Anybody 800/900
|
|
78
|
+
* italic 848.9, Anybody 800 upright 833.1, Anybody 700 italic 777.6, generic
|
|
79
|
+
* sans-serif fallback ~650. 880 clears the widest with headroom.
|
|
80
|
+
*
|
|
81
|
+
* Two known ways past 880, both requiring a consumer to opt in: Anybody ships a
|
|
82
|
+
* `wdth` 75..125 axis, and `font-stretch` inherits into SVG `<text>` — at
|
|
83
|
+
* `wdth` 125 this measures 1046. Nothing sets it today; the numbers above
|
|
84
|
+
* assume `wdth` 100.
|
|
85
|
+
*
|
|
86
|
+
* The previous 654 was fitted to the generic sans-serif FALLBACK, not to
|
|
87
|
+
* Anybody, and clipped the trailing "o" by ~30% wherever Anybody loaded.
|
|
72
88
|
*/
|
|
73
89
|
const LogoWordmark = forwardRef<SVGSVGElement, LogoProps>(
|
|
74
90
|
({ className, ...rest }, ref) => (
|
|
75
91
|
<svg
|
|
76
92
|
ref={ref}
|
|
77
|
-
viewBox="0 0
|
|
93
|
+
viewBox="0 0 880 229"
|
|
78
94
|
xmlns="http://www.w3.org/2000/svg"
|
|
79
95
|
fill="currentColor"
|
|
80
96
|
className={cn("shrink-0", className)}
|
|
@@ -102,12 +118,17 @@ LogoWordmark.displayName = "LogoWordmark";
|
|
|
102
118
|
* logotype, rebrand still deferred). Set in Anybody 800 italic to match the
|
|
103
119
|
* brand headings; the consuming app must load Anybody or it falls back to
|
|
104
120
|
* sans-serif. Inherits color from parent via `currentColor`.
|
|
121
|
+
*
|
|
122
|
+
* Same live-`<text>` sizing rule as LogoWordmark above — the viewBox clears the
|
|
123
|
+
* widest realistic rendering. Measured at font-size 200 (Chromium, 2026-08-21):
|
|
124
|
+
* Anybody 800/900 italic "s" 157.9. 164 clears it with ~3.9% headroom. The
|
|
125
|
+
* previous 119 clipped the single glyph by ~33%.
|
|
105
126
|
*/
|
|
106
127
|
const LogoLetter = forwardRef<SVGSVGElement, LogoProps>(
|
|
107
128
|
({ className, ...rest }, ref) => (
|
|
108
129
|
<svg
|
|
109
130
|
ref={ref}
|
|
110
|
-
viewBox="0 0
|
|
131
|
+
viewBox="0 0 164 229"
|
|
111
132
|
xmlns="http://www.w3.org/2000/svg"
|
|
112
133
|
fill="currentColor"
|
|
113
134
|
className={cn("shrink-0", className)}
|