@stasho/ds 0.15.2 → 0.15.4

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stasho/ds",
3
- "version": "0.15.2",
3
+ "version": "0.15.4",
4
4
  "description": "stasho design system",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -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
- <span className="inline-flex items-center leading-none">
280
- {children}
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
- return cloneElement(children as ReactElement<Record<string, unknown>>, {
298
- className: classes,
299
- ref,
300
- ...rest,
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 (
@@ -178,6 +178,7 @@ const ProjectSwitcher = forwardRef<HTMLButtonElement, ProjectSwitcherProps>(
178
178
  value={query}
179
179
  onValueChange={setQuery}
180
180
  placeholder={searchPlaceholder}
181
+ aria-label={searchPlaceholder}
181
182
  className={cn(
182
183
  "w-full border-b border-edge bg-transparent px-4 py-2.5",
183
184
  "text-sm text-foreground placeholder:text-muted-foreground",
@@ -160,9 +160,12 @@ export function SidebarNav({
160
160
  return (
161
161
  <nav
162
162
  aria-label={ariaLabel}
163
- className={cn("flex-1 overflow-y-auto p-2", className)}
163
+ className={cn(
164
+ "flex flex-1 flex-col gap-1 overflow-y-auto p-2",
165
+ className,
166
+ )}
164
167
  >
165
- <ul className="flex flex-col gap-1">{children}</ul>
168
+ {children}
166
169
  </nav>
167
170
  );
168
171
  }