@usetheo/ui 0.35.2 → 0.35.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.
@@ -1,14 +1,45 @@
1
- import type { ButtonHTMLAttributes, ElementType, HTMLAttributes, ReactNode } from "react";
1
+ import type { AnchorHTMLAttributes, ButtonHTMLAttributes, ElementType, HTMLAttributes, ReactNode } from "react";
2
2
  interface SectionProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
3
3
  title?: ReactNode;
4
4
  }
5
- interface ItemProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "type"> {
5
+ interface ItemBaseProps {
6
6
  icon?: ElementType;
7
7
  active?: boolean;
8
8
  count?: number | string;
9
- as?: "button" | "a";
10
- href?: string;
11
9
  }
10
+ /**
11
+ * The `<button>` arm. `type` is owned by the component, so it is not offered.
12
+ *
13
+ * `href?: never` is what makes the union discriminate on a mistake rather than on the `as` alone:
14
+ * `<Sidebar.Item href="/x">` without `as="a"` renders a button that ignores the href, and used to
15
+ * type-check.
16
+ */
17
+ type ItemButtonProps = ItemBaseProps & Omit<ButtonHTMLAttributes<HTMLButtonElement>, "type"> & {
18
+ as?: "button";
19
+ href?: never;
20
+ };
21
+ /**
22
+ * The `<a>` arm — anchor attributes, and `href` REQUIRED.
23
+ *
24
+ * The requirement is not pedantry: an anchor without `href` is not keyboard focusable and not
25
+ * announced as a link, so `as="a"` with the href forgotten produced a nav row that a keyboard user
26
+ * could not reach. It type-checked before, because both fields were optional on one shape.
27
+ */
28
+ type ItemAnchorProps = ItemBaseProps & AnchorHTMLAttributes<HTMLAnchorElement> & {
29
+ as: "a";
30
+ href: string;
31
+ };
32
+ /**
33
+ * Props of `Sidebar.Item`.
34
+ *
35
+ * A discriminated union rather than one shape with `as?: "button" | "a"`, because the runtime has
36
+ * always branched on `as` — it casts to `AnchorHTMLAttributes` in the anchor path — while the type
37
+ * described a button in both. The consequence was that no anchor attribute could be passed:
38
+ * `target`, `rel`, `download`, `hrefLang` all failed to compile on an element that renders them
39
+ * fine. A sidebar link to another site, which almost always wants `target="_blank" rel="noreferrer"`,
40
+ * could not be written with this component at all (usetheodev/usetheo-ui#27).
41
+ */
42
+ type ItemProps = ItemButtonProps | ItemAnchorProps;
12
43
  declare const Sidebar: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & import("react").RefAttributes<HTMLElement>> & {
13
44
  Header: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<HTMLDivElement>>;
14
45
  Section: import("react").ForwardRefExoticComponent<SectionProps & import("react").RefAttributes<HTMLDivElement>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usetheo/ui",
3
- "version": "0.35.2",
3
+ "version": "0.35.4",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "description": "Violet Forge design system — generic React components + primitives (the non-AI foundation of @theokit/ui).",
@@ -74,7 +74,7 @@
74
74
  },
75
75
  "devDependencies": {
76
76
  "@biomejs/biome": "^1.9.4",
77
- "@changesets/cli": "^3.0.1",
77
+ "@changesets/cli": "^2.31.1",
78
78
  "@ladle/react": "^4.1.2",
79
79
  "@tailwindcss/vite": "^4.3.2",
80
80
  "@testing-library/jest-dom": "^6.6.3",