@claralight-design/react 0.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 (45) hide show
  1. package/dist/index.d.ts +12 -0
  2. package/dist/index.js +12 -0
  3. package/dist/lib/anchored.d.ts +152 -0
  4. package/dist/lib/anchored.js +821 -0
  5. package/dist/lib/anchored.js.map +1 -0
  6. package/dist/lib/morph.js +484 -0
  7. package/dist/lib/morph.js.map +1 -0
  8. package/dist/lib/squircle.d.ts +95 -0
  9. package/dist/lib/squircle.js +220 -0
  10. package/dist/lib/squircle.js.map +1 -0
  11. package/dist/lib/utils.d.ts +30 -0
  12. package/dist/lib/utils.js +76 -0
  13. package/dist/lib/utils.js.map +1 -0
  14. package/dist/ui/button.d.ts +40 -0
  15. package/dist/ui/button.js +104 -0
  16. package/dist/ui/button.js.map +1 -0
  17. package/dist/ui/card.d.ts +54 -0
  18. package/dist/ui/card.js +82 -0
  19. package/dist/ui/card.js.map +1 -0
  20. package/dist/ui/dialog.d.ts +82 -0
  21. package/dist/ui/dialog.js +129 -0
  22. package/dist/ui/dialog.js.map +1 -0
  23. package/dist/ui/input.d.ts +34 -0
  24. package/dist/ui/input.js +60 -0
  25. package/dist/ui/input.js.map +1 -0
  26. package/dist/ui/popover.d.ts +67 -0
  27. package/dist/ui/popover.js +93 -0
  28. package/dist/ui/popover.js.map +1 -0
  29. package/dist/ui/scroll-area.d.ts +110 -0
  30. package/dist/ui/scroll-area.js +125 -0
  31. package/dist/ui/scroll-area.js.map +1 -0
  32. package/dist/ui/select.d.ts +113 -0
  33. package/dist/ui/select.js +213 -0
  34. package/dist/ui/select.js.map +1 -0
  35. package/dist/ui/tooltip.d.ts +108 -0
  36. package/dist/ui/tooltip.js +142 -0
  37. package/dist/ui/tooltip.js.map +1 -0
  38. package/package.json +72 -0
  39. package/styles/anchored.css +115 -0
  40. package/styles/base.css +309 -0
  41. package/styles/fonts/README.md +63 -0
  42. package/styles/index.css +28 -0
  43. package/styles/scroll-area.css +299 -0
  44. package/styles/theme.css +540 -0
  45. package/styles/tooltip.css +156 -0
@@ -0,0 +1,104 @@
1
+ "use client";
2
+ import { cn } from "../lib/utils.js";
3
+ import { Squircle } from "../lib/squircle.js";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { Button } from "@base-ui/react/button";
6
+ import { cva } from "class-variance-authority";
7
+ //#region src/ui/button.tsx
8
+ /**
9
+ * ClaraLight button variants.
10
+ *
11
+ * `secondary` is the default because ClaraLight is a tool-like design
12
+ * language: most buttons in a real screen are neutral glass controls, and the
13
+ * accent should mark one primary action per view, not every button.
14
+ */
15
+ const buttonVariants = cva([
16
+ "inline-flex select-none items-center justify-center gap-2",
17
+ "border font-sans whitespace-nowrap",
18
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0",
19
+ "data-[disabled]:pointer-events-none data-[disabled]:cursor-not-allowed"
20
+ ], {
21
+ variants: {
22
+ /**
23
+ * Filled variants use the theme's perceptual hover mix. `ghost` instead
24
+ * reveals a fill, because lifting nothing is still nothing.
25
+ *
26
+ * Disabled behaviour is deliberate and differs per variant: neutral
27
+ * controls keep their glass layer, and semantic actions keep their
28
+ * identity — except `danger`, which drops its colour so a destructive
29
+ * action never reads as available.
30
+ */
31
+ variant: {
32
+ primary: [
33
+ "border-outline bg-accent text-on-accent",
34
+ "hover:bg-accent-hover",
35
+ "data-[disabled]:text-foreground-disabled"
36
+ ],
37
+ secondary: [
38
+ "border-outline bg-floating text-on-floating backdrop-blur-frost",
39
+ "hover:bg-floating-hover",
40
+ "data-[disabled]:text-foreground-disabled"
41
+ ],
42
+ ghost: [
43
+ "border-transparent bg-transparent text-foreground",
44
+ "hover:bg-control-highlight",
45
+ "data-[disabled]:text-foreground-disabled"
46
+ ],
47
+ danger: [
48
+ "border-outline bg-danger text-on-danger",
49
+ "hover:bg-danger-hover",
50
+ "data-[disabled]:border-transparent data-[disabled]:bg-control",
51
+ "data-[disabled]:text-foreground-disabled"
52
+ ]
53
+ },
54
+ /**
55
+ * Heights, icon geometry, press travel and label typography come from
56
+ * theme tokens. Smaller controls travel further in relative terms.
57
+ */
58
+ size: {
59
+ sm: ["h-control-sm gap-1.5 px-3 text-label", "[&_svg]:size-icon-sm"],
60
+ md: ["h-control-md gap-2 px-4 text-label", "[&_svg]:size-icon-md"],
61
+ lg: ["h-control-lg gap-2 px-4 text-button", "[&_svg]:size-icon-lg"]
62
+ }
63
+ },
64
+ defaultVariants: {
65
+ variant: "secondary",
66
+ size: "lg"
67
+ }
68
+ });
69
+ const pressScales = {
70
+ sm: "[--cl-press-scale:var(--cl-press-scale-sm)]",
71
+ md: "[--cl-press-scale:var(--cl-press-scale-md)]",
72
+ lg: "[--cl-press-scale:var(--cl-press-scale-lg)]"
73
+ };
74
+ /**
75
+ * A ClaraLight capsule button.
76
+ *
77
+ * Wraps Base UI's `Button` rather than rendering a bare `<button>`: that gives
78
+ * the `render` prop for polymorphism (rendering an `<a>` while keeping button
79
+ * semantics), and correct disabled behaviour for non-native elements, which a
80
+ * plain `disabled` attribute cannot express.
81
+ *
82
+ * @example
83
+ * <Button variant="primary">Upload</Button>
84
+ * <Button render={<a href="/docs" />}>Docs</Button>
85
+ */
86
+ function Button$1({ className, wrapperClassName, variant, size, ...props }) {
87
+ return /* @__PURE__ */ jsx(Squircle, {
88
+ asChild: true,
89
+ radius: "capsule",
90
+ ring: true,
91
+ wrapperClassName: cn("cl-press inline-flex shrink-0", pressScales[size ?? "lg"], wrapperClassName),
92
+ children: /* @__PURE__ */ jsx(Button, {
93
+ className: cn(buttonVariants({
94
+ variant,
95
+ size
96
+ }), className),
97
+ ...props
98
+ })
99
+ });
100
+ }
101
+ //#endregion
102
+ export { Button$1 as Button, buttonVariants };
103
+
104
+ //# sourceMappingURL=button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button.js","names":["Button","BaseButton"],"sources":["../../src/ui/button.tsx"],"sourcesContent":["\"use client\";\n\nimport { Button as BaseButton } from \"@base-ui/react/button\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ComponentProps } from \"react\";\nimport { Squircle } from \"@/lib/squircle\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * ClaraLight button variants.\n *\n * `secondary` is the default because ClaraLight is a tool-like design\n * language: most buttons in a real screen are neutral glass controls, and the\n * accent should mark one primary action per view, not every button.\n */\nexport const buttonVariants = cva(\n [\n \"inline-flex select-none items-center justify-center gap-2\",\n \"border font-sans whitespace-nowrap\",\n // Icons inherit the variant's foreground through currentColor.\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0\",\n \"data-[disabled]:pointer-events-none data-[disabled]:cursor-not-allowed\",\n ],\n {\n variants: {\n /**\n * Filled variants use the theme's perceptual hover mix. `ghost` instead\n * reveals a fill, because lifting nothing is still nothing.\n *\n * Disabled behaviour is deliberate and differs per variant: neutral\n * controls keep their glass layer, and semantic actions keep their\n * identity — except `danger`, which drops its colour so a destructive\n * action never reads as available.\n */\n variant: {\n primary: [\n \"border-outline bg-accent text-on-accent\",\n \"hover:bg-accent-hover\",\n \"data-[disabled]:text-foreground-disabled\",\n ],\n secondary: [\n \"border-outline bg-floating text-on-floating backdrop-blur-frost\",\n \"hover:bg-floating-hover\",\n \"data-[disabled]:text-foreground-disabled\",\n ],\n ghost: [\n \"border-transparent bg-transparent text-foreground\",\n \"hover:bg-control-highlight\",\n \"data-[disabled]:text-foreground-disabled\",\n ],\n danger: [\n \"border-outline bg-danger text-on-danger\",\n \"hover:bg-danger-hover\",\n \"data-[disabled]:border-transparent data-[disabled]:bg-control\",\n \"data-[disabled]:text-foreground-disabled\",\n ],\n },\n /**\n * Heights, icon geometry, press travel and label typography come from\n * theme tokens. Smaller controls travel further in relative terms.\n */\n size: {\n sm: [\"h-control-sm gap-1.5 px-3 text-label\", \"[&_svg]:size-icon-sm\"],\n md: [\"h-control-md gap-2 px-4 text-label\", \"[&_svg]:size-icon-md\"],\n lg: [\"h-control-lg gap-2 px-4 text-button\", \"[&_svg]:size-icon-lg\"],\n },\n },\n defaultVariants: { variant: \"secondary\", size: \"lg\" },\n },\n);\n\nconst pressScales = {\n sm: \"[--cl-press-scale:var(--cl-press-scale-sm)]\",\n md: \"[--cl-press-scale:var(--cl-press-scale-md)]\",\n lg: \"[--cl-press-scale:var(--cl-press-scale-lg)]\",\n} as const;\n\nexport type ButtonProps = Omit<ComponentProps<typeof BaseButton>, \"className\"> &\n VariantProps<typeof buttonVariants> & {\n /** Applied to the clipped element: fill, border, label. */\n className?: string;\n /**\n * Applied to the wrapper, which is what a caller's flex or grid lays out —\n * put width, margin and placement here.\n */\n wrapperClassName?: string;\n };\n\n/**\n * A ClaraLight capsule button.\n *\n * Wraps Base UI's `Button` rather than rendering a bare `<button>`: that gives\n * the `render` prop for polymorphism (rendering an `<a>` while keeping button\n * semantics), and correct disabled behaviour for non-native elements, which a\n * plain `disabled` attribute cannot express.\n *\n * @example\n * <Button variant=\"primary\">Upload</Button>\n * <Button render={<a href=\"/docs\" />}>Docs</Button>\n */\nexport function Button({ className, wrapperClassName, variant, size, ...props }: ButtonProps) {\n return (\n /*\n * `.cl-press` sits on the wrapper so the press scale moves fill, border and\n * shadow together — the SVG overlays are siblings of the shape, so scaling\n * the shape alone would tear the 1px border off the edge. `:active`\n * propagates to ancestors, so the wrapper sees the press with no JS.\n *\n * `ring` puts the focus indicator on the same element, because `clip-path`\n * crops `outline` to nothing on the shape.\n */\n <Squircle\n asChild\n radius=\"capsule\"\n ring\n wrapperClassName={cn(\n \"cl-press inline-flex shrink-0\",\n pressScales[size ?? \"lg\"],\n wrapperClassName,\n )}\n >\n <BaseButton className={cn(buttonVariants({ variant, size }), className)} {...props} />\n </Squircle>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,MAAa,iBAAiB,IAC5B;CACE;CACA;CAEA;CACA;AACF,GACA;CACE,UAAU;;;;;;;;;;EAUR,SAAS;GACP,SAAS;IACP;IACA;IACA;GACF;GACA,WAAW;IACT;IACA;IACA;GACF;GACA,OAAO;IACL;IACA;IACA;GACF;GACA,QAAQ;IACN;IACA;IACA;IACA;GACF;EACF;;;;;EAKA,MAAM;GACJ,IAAI,CAAC,wCAAwC,sBAAsB;GACnE,IAAI,CAAC,sCAAsC,sBAAsB;GACjE,IAAI,CAAC,uCAAuC,sBAAsB;EACpE;CACF;CACA,iBAAiB;EAAE,SAAS;EAAa,MAAM;CAAK;AACtD,CACF;AAEA,MAAM,cAAc;CAClB,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;;;;;;;;;;;;;AAyBA,SAAgBA,SAAO,EAAE,WAAW,kBAAkB,SAAS,MAAM,GAAG,SAAsB;CAC5F,OAUE,oBAAC,UAAD;EACE,SAAA;EACA,QAAO;EACP,MAAA;EACA,kBAAkB,GAChB,iCACA,YAAY,QAAQ,OACpB,gBACF;EAEA,UAAA,oBAACC,QAAD;GAAY,WAAW,GAAG,eAAe;IAAE;IAAS;GAAK,CAAC,GAAG,SAAS;GAAG,GAAI;EAAQ,CAAA;CAC7E,CAAA;AAEd"}
@@ -0,0 +1,54 @@
1
+ import { RadiusToken } from "../lib/squircle.js";
2
+ import { ComponentProps, ReactNode } from "react";
3
+ import { VariantProps } from "class-variance-authority";
4
+ //#region src/ui/card.d.ts
5
+ /**
6
+ * Card surfaces, mapped onto the ClaraLight layer stack.
7
+ *
8
+ * `panel` is a container sitting on the window background (the default).
9
+ * `control` puts the card *inside* a panel, where the translucent overlay
10
+ * reads correctly over `--color-panel`.
11
+ * `frost` is for cards that float over arbitrary content and need a backdrop
12
+ * blur.
13
+ *
14
+ * The corner shape itself is not here: `Squircle` owns it, and renders these
15
+ * classes onto the clipped element while the SVG border and shadow overlays go
16
+ * on its wrapper. So `border-*` and `shadow-*` below are declarations Lisse
17
+ * reads and re-renders as squircle-shaped SVG, not declarations that paint.
18
+ */
19
+ export declare const cardVariants: (props?: ({
20
+ variant?: "control" | "frost" | "panel" | null | undefined;
21
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
22
+ export interface CardProps extends ComponentProps<"div">, VariantProps<typeof cardVariants> {
23
+ /** Applied to the clipped element: fill, padding, grid placement inside the card. */
24
+ className?: string;
25
+ /**
26
+ * Applied to the layout wrapper, which is the element the caller's grid or
27
+ * flex actually lays out. Put span and size classes here —
28
+ * `wrapperClassName="sm:col-span-2"`, not `className`.
29
+ */
30
+ wrapperClassName?: string;
31
+ /** Which `--radius-*` token shapes the corners. */
32
+ radius?: RadiusToken;
33
+ /** Figma's `xi`; see `Squircle`. */
34
+ smoothing?: number;
35
+ children?: ReactNode;
36
+ }
37
+ /** A ClaraLight surface. Compose with the parts below, or use it bare. */
38
+ export declare function Card({ className, wrapperClassName, variant, radius, smoothing, children, ...props }: CardProps): import("react").JSX.Element;
39
+ export type CardHeaderProps = ComponentProps<"div">;
40
+ export declare function CardHeader({ className, ...props }: CardHeaderProps): import("react").JSX.Element;
41
+ export type CardTitleProps = ComponentProps<"h3">;
42
+ /**
43
+ * `headline` (18/24 bold, tightened to -0.55px) rather than `title`, so a card
44
+ * title outranks the row text it contains.
45
+ */
46
+ export declare function CardTitle({ className, ...props }: CardTitleProps): import("react").JSX.Element;
47
+ export type CardDescriptionProps = ComponentProps<"p">;
48
+ export declare function CardDescription({ className, ...props }: CardDescriptionProps): import("react").JSX.Element;
49
+ export type CardContentProps = ComponentProps<"div">;
50
+ export declare function CardContent({ className, ...props }: CardContentProps): import("react").JSX.Element;
51
+ export type CardFooterProps = ComponentProps<"div">;
52
+ export declare function CardFooter({ className, ...props }: CardFooterProps): import("react").JSX.Element;
53
+ //#endregion
54
+ //# sourceMappingURL=card.d.ts.map
@@ -0,0 +1,82 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { Squircle } from "../lib/squircle.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { cva } from "class-variance-authority";
5
+ //#region src/ui/card.tsx
6
+ /**
7
+ * Card surfaces, mapped onto the ClaraLight layer stack.
8
+ *
9
+ * `panel` is a container sitting on the window background (the default).
10
+ * `control` puts the card *inside* a panel, where the translucent overlay
11
+ * reads correctly over `--color-panel`.
12
+ * `frost` is for cards that float over arbitrary content and need a backdrop
13
+ * blur.
14
+ *
15
+ * The corner shape itself is not here: `Squircle` owns it, and renders these
16
+ * classes onto the clipped element while the SVG border and shadow overlays go
17
+ * on its wrapper. So `border-*` and `shadow-*` below are declarations Lisse
18
+ * reads and re-renders as squircle-shaped SVG, not declarations that paint.
19
+ */
20
+ const cardVariants = cva(["text-foreground", "[&_svg]:shrink-0"], {
21
+ variants: { variant: {
22
+ panel: "border border-outline bg-panel shadow-panel",
23
+ control: "border border-outline bg-control",
24
+ frost: "cl-frost"
25
+ } },
26
+ defaultVariants: { variant: "panel" }
27
+ });
28
+ /** A ClaraLight surface. Compose with the parts below, or use it bare. */
29
+ function Card({ className, wrapperClassName, variant, radius = "medium", smoothing, children, ...props }) {
30
+ return /* @__PURE__ */ jsx(Squircle, {
31
+ radius,
32
+ smoothing,
33
+ wrapperClassName,
34
+ className: cn(cardVariants({ variant }), className),
35
+ "data-cl-slot": "card",
36
+ ...props,
37
+ children
38
+ });
39
+ }
40
+ function CardHeader({ className, ...props }) {
41
+ return /* @__PURE__ */ jsx("div", {
42
+ "data-cl-slot": "card-header",
43
+ className: cn("flex flex-col gap-1 p-4", className),
44
+ ...props
45
+ });
46
+ }
47
+ /**
48
+ * `headline` (18/24 bold, tightened to -0.55px) rather than `title`, so a card
49
+ * title outranks the row text it contains.
50
+ */
51
+ function CardTitle({ className, ...props }) {
52
+ return /* @__PURE__ */ jsx("h3", {
53
+ "data-cl-slot": "card-title",
54
+ className: cn("text-headline text-foreground", className),
55
+ ...props
56
+ });
57
+ }
58
+ function CardDescription({ className, ...props }) {
59
+ return /* @__PURE__ */ jsx("p", {
60
+ "data-cl-slot": "card-description",
61
+ className: cn("text-caption text-foreground-tertiary", className),
62
+ ...props
63
+ });
64
+ }
65
+ function CardContent({ className, ...props }) {
66
+ return /* @__PURE__ */ jsx("div", {
67
+ "data-cl-slot": "card-content",
68
+ className: cn("px-4 pb-4 [&:first-child]:pt-4", className),
69
+ ...props
70
+ });
71
+ }
72
+ function CardFooter({ className, ...props }) {
73
+ return /* @__PURE__ */ jsx("div", {
74
+ "data-cl-slot": "card-footer",
75
+ className: cn("flex items-center gap-2 px-4 pb-4", className),
76
+ ...props
77
+ });
78
+ }
79
+ //#endregion
80
+ export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, cardVariants };
81
+
82
+ //# sourceMappingURL=card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card.js","names":[],"sources":["../../src/ui/card.tsx"],"sourcesContent":["import { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { type RadiusToken, Squircle } from \"@/lib/squircle\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * Card surfaces, mapped onto the ClaraLight layer stack.\n *\n * `panel` is a container sitting on the window background (the default).\n * `control` puts the card *inside* a panel, where the translucent overlay\n * reads correctly over `--color-panel`.\n * `frost` is for cards that float over arbitrary content and need a backdrop\n * blur.\n *\n * The corner shape itself is not here: `Squircle` owns it, and renders these\n * classes onto the clipped element while the SVG border and shadow overlays go\n * on its wrapper. So `border-*` and `shadow-*` below are declarations Lisse\n * reads and re-renders as squircle-shaped SVG, not declarations that paint.\n */\nexport const cardVariants = cva([\"text-foreground\", \"[&_svg]:shrink-0\"], {\n variants: {\n variant: {\n panel: \"border border-outline bg-panel shadow-panel\",\n control: \"border border-outline bg-control\",\n frost: \"cl-frost\",\n },\n },\n defaultVariants: { variant: \"panel\" },\n});\n\nexport interface CardProps extends ComponentProps<\"div\">, VariantProps<typeof cardVariants> {\n /** Applied to the clipped element: fill, padding, grid placement inside the card. */\n className?: string;\n /**\n * Applied to the layout wrapper, which is the element the caller's grid or\n * flex actually lays out. Put span and size classes here —\n * `wrapperClassName=\"sm:col-span-2\"`, not `className`.\n */\n wrapperClassName?: string;\n /** Which `--radius-*` token shapes the corners. */\n radius?: RadiusToken;\n /** Figma's `xi`; see `Squircle`. */\n smoothing?: number;\n children?: ReactNode;\n}\n\n/** A ClaraLight surface. Compose with the parts below, or use it bare. */\nexport function Card({\n className,\n wrapperClassName,\n variant,\n radius = \"medium\",\n smoothing,\n children,\n ...props\n}: CardProps) {\n return (\n <Squircle\n radius={radius}\n smoothing={smoothing}\n wrapperClassName={wrapperClassName}\n className={cn(cardVariants({ variant }), className)}\n data-cl-slot=\"card\"\n {...props}\n >\n {children}\n </Squircle>\n );\n}\n\nexport type CardHeaderProps = ComponentProps<\"div\">;\nexport function CardHeader({ className, ...props }: CardHeaderProps) {\n return (\n <div\n data-cl-slot=\"card-header\"\n className={cn(\"flex flex-col gap-1 p-4\", className)}\n {...props}\n />\n );\n}\n\nexport type CardTitleProps = ComponentProps<\"h3\">;\n\n/**\n * `headline` (18/24 bold, tightened to -0.55px) rather than `title`, so a card\n * title outranks the row text it contains.\n */\nexport function CardTitle({ className, ...props }: CardTitleProps) {\n return (\n <h3\n data-cl-slot=\"card-title\"\n className={cn(\"text-headline text-foreground\", className)}\n {...props}\n />\n );\n}\n\nexport type CardDescriptionProps = ComponentProps<\"p\">;\n\nexport function CardDescription({ className, ...props }: CardDescriptionProps) {\n return (\n <p\n data-cl-slot=\"card-description\"\n className={cn(\"text-caption text-foreground-tertiary\", className)}\n {...props}\n />\n );\n}\n\nexport type CardContentProps = ComponentProps<\"div\">;\n\nexport function CardContent({ className, ...props }: CardContentProps) {\n return (\n <div\n data-cl-slot=\"card-content\"\n className={cn(\"px-4 pb-4 [&:first-child]:pt-4\", className)}\n {...props}\n />\n );\n}\n\nexport type CardFooterProps = ComponentProps<\"div\">;\n\nexport function CardFooter({ className, ...props }: CardFooterProps) {\n return (\n <div\n data-cl-slot=\"card-footer\"\n className={cn(\"flex items-center gap-2 px-4 pb-4\", className)}\n {...props}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAmBA,MAAa,eAAe,IAAI,CAAC,mBAAmB,kBAAkB,GAAG;CACvE,UAAU,EACR,SAAS;EACP,OAAO;EACP,SAAS;EACT,OAAO;CACT,EACF;CACA,iBAAiB,EAAE,SAAS,QAAQ;AACtC,CAAC;;AAmBD,SAAgB,KAAK,EACnB,WACA,kBACA,SACA,SAAS,UACT,WACA,UACA,GAAG,SACS;CACZ,OACE,oBAAC,UAAD;EACU;EACG;EACO;EAClB,WAAW,GAAG,aAAa,EAAE,QAAQ,CAAC,GAAG,SAAS;EAClD,gBAAa;EACb,GAAI;EAEH;CACO,CAAA;AAEd;AAGA,SAAgB,WAAW,EAAE,WAAW,GAAG,SAA0B;CACnE,OACE,oBAAC,OAAD;EACE,gBAAa;EACb,WAAW,GAAG,2BAA2B,SAAS;EAClD,GAAI;CACL,CAAA;AAEL;;;;;AAQA,SAAgB,UAAU,EAAE,WAAW,GAAG,SAAyB;CACjE,OACE,oBAAC,MAAD;EACE,gBAAa;EACb,WAAW,GAAG,iCAAiC,SAAS;EACxD,GAAI;CACL,CAAA;AAEL;AAIA,SAAgB,gBAAgB,EAAE,WAAW,GAAG,SAA+B;CAC7E,OACE,oBAAC,KAAD;EACE,gBAAa;EACb,WAAW,GAAG,yCAAyC,SAAS;EAChE,GAAI;CACL,CAAA;AAEL;AAIA,SAAgB,YAAY,EAAE,WAAW,GAAG,SAA2B;CACrE,OACE,oBAAC,OAAD;EACE,gBAAa;EACb,WAAW,GAAG,kCAAkC,SAAS;EACzD,GAAI;CACL,CAAA;AAEL;AAIA,SAAgB,WAAW,EAAE,WAAW,GAAG,SAA0B;CACnE,OACE,oBAAC,OAAD;EACE,gBAAa;EACb,WAAW,GAAG,qCAAqC,SAAS;EAC5D,GAAI;CACL,CAAA;AAEL"}
@@ -0,0 +1,82 @@
1
+ import { ComponentProps, ReactNode } from "react";
2
+ import { Dialog } from "@base-ui/react/dialog";
3
+ //#region src/ui/dialog.d.ts
4
+ export type DialogProps<Payload = unknown> = Dialog.Root.Props<Payload>;
5
+ /**
6
+ * The modal root, which also remembers where it was opened from.
7
+ *
8
+ * `Dialog.Popup` grows out of the trigger's rectangle, so the two have to know
9
+ * about each other; passing the anchor between siblings is what this component
10
+ * exists for. It is the same provider the select will use, so both surfaces
11
+ * morph with one implementation.
12
+ *
13
+ * The open state is mirrored here — not invented here. `open` still wins when it
14
+ * is controlled, and `onOpenChange` still fires for every change, so a consumer's
15
+ * own state stays the single source of truth; the mirror only exists because the
16
+ * popup, which is a *sibling* of the trigger, has to know when a dismissal began
17
+ * in order to reverse the morph before Base UI unmounts it.
18
+ */ declare function Dialog$1<Payload = unknown>({ open, defaultOpen, onOpenChange, ...props }: DialogProps<Payload>): import("react").JSX.Element;
19
+ export type DialogTriggerProps = Omit<ComponentProps<typeof Dialog.Trigger>, "className"> & {
20
+ className?: string;
21
+ };
22
+ export declare function DialogTrigger({ className, ref, ...props }: DialogTriggerProps): import("react").JSX.Element;
23
+ export type DialogBackdropProps = Omit<ComponentProps<typeof Dialog.Backdrop>, "className"> & {
24
+ className?: string;
25
+ };
26
+ /**
27
+ * The barrier behind the dialog. Fades on one duration only, so it lands fast
28
+ * enough that the page behind never feels stuck.
29
+ */
30
+ export declare function DialogBackdrop({ className, ...props }: DialogBackdropProps): import("react").JSX.Element;
31
+ export type DialogPopupProps = Omit<ComponentProps<typeof Dialog.Popup>, "className"> & {
32
+ /** Applied to the clipped element: the frost, padding and text. */
33
+ className?: string;
34
+ /** Applied to the wrapper, which is what gets positioned and animated. */
35
+ wrapperClassName?: string;
36
+ /** Rendered inside the popup, above the body. */
37
+ children?: ReactNode;
38
+ };
39
+ /**
40
+ * The frosted modal surface.
41
+ *
42
+ * Base UI marks the popup with `data-starting-style` and `data-ending-style`
43
+ * and waits for animations on the popup element before calling `forceUnmount`.
44
+ * The visible transition belongs to the wrapper, so `cl-exit-sentinel` adds a
45
+ * non-visual custom-property animation to the popup; Base UI can then wait for
46
+ * the wrapper's exit duration without moving the clipped surface separately.
47
+ *
48
+ * The positioning and the entrance live on the **wrapper**, not the popup. The
49
+ * popup is the clipped element and the SVG border and shadow overlays are its
50
+ * siblings, so scaling the popup alone would leave the 1px border and the shadow
51
+ * at their final size — 5% of a 512px dialog is 25px, plainly visible over the
52
+ * 250ms entrance. `.cl-enter-root` lifts Base UI's transition state onto the
53
+ * wrapper with `:has()`, so fill, border and shadow move as one object.
54
+ *
55
+ * The wrapper is also what `useSurfaceMorph` transforms: the dialog is laid out
56
+ * at its final size and carried from the trigger's rectangle onto itself, which
57
+ * is the one entrance the whole language shares. The geometry drives the
58
+ * content's opacity with it, so the layer is still visible while it collapses
59
+ * back into its trigger.
60
+ *
61
+ * **No shadow**, unlike every other floating layer. A modal is separated from the
62
+ * page by its scrim, and `--shadow-frost` under a 45% scrim is two depth cues
63
+ * claiming the same edge, which reads as a halo rather than as distance. A dialog
64
+ * that has no scrim — `modal={false}`, or one laid over its own artwork — asks for
65
+ * it back with `shadow-dialog`, which is what that token is for.
66
+ */
67
+ export declare function DialogPopup({ className, wrapperClassName, ...props }: DialogPopupProps): import("react").JSX.Element;
68
+ export type DialogTitleProps = Omit<ComponentProps<typeof Dialog.Title>, "className"> & {
69
+ className?: string;
70
+ };
71
+ export declare function DialogTitle({ className, ...props }: DialogTitleProps): import("react").JSX.Element;
72
+ export type DialogDescriptionProps = Omit<ComponentProps<typeof Dialog.Description>, "className"> & {
73
+ className?: string;
74
+ };
75
+ export declare function DialogDescription({ className, ...props }: DialogDescriptionProps): import("react").JSX.Element;
76
+ export type DialogCloseProps = Omit<ComponentProps<typeof Dialog.Close>, "className"> & {
77
+ className?: string;
78
+ };
79
+ export declare function DialogClose({ className, ...props }: DialogCloseProps): import("react").JSX.Element;
80
+ //#endregion
81
+ export { Dialog$1 as Dialog };
82
+ //# sourceMappingURL=dialog.d.ts.map
@@ -0,0 +1,129 @@
1
+ "use client";
2
+ import { cn } from "../lib/utils.js";
3
+ import { Squircle, composeRefs } from "../lib/squircle.js";
4
+ import { MorphSourceProvider, useMorphAnchor, useMorphSource, useSurfaceMorph } from "../lib/morph.js";
5
+ import { useCallback, useMemo, useState } from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { Dialog } from "@base-ui/react/dialog";
8
+ //#region src/ui/dialog.tsx
9
+ /**
10
+ * The modal root, which also remembers where it was opened from.
11
+ *
12
+ * `Dialog.Popup` grows out of the trigger's rectangle, so the two have to know
13
+ * about each other; passing the anchor between siblings is what this component
14
+ * exists for. It is the same provider the select will use, so both surfaces
15
+ * morph with one implementation.
16
+ *
17
+ * The open state is mirrored here — not invented here. `open` still wins when it
18
+ * is controlled, and `onOpenChange` still fires for every change, so a consumer's
19
+ * own state stays the single source of truth; the mirror only exists because the
20
+ * popup, which is a *sibling* of the trigger, has to know when a dismissal began
21
+ * in order to reverse the morph before Base UI unmounts it.
22
+ */ function Dialog$1({ open, defaultOpen, onOpenChange, ...props }) {
23
+ const [uncontrolled, setUncontrolled] = useState(defaultOpen ?? false);
24
+ const handleOpenChange = useCallback((next, details) => {
25
+ setUncontrolled(next);
26
+ onOpenChange?.(next, details);
27
+ }, [onOpenChange]);
28
+ return /* @__PURE__ */ jsx(MorphSourceProvider, {
29
+ open: open ?? uncontrolled,
30
+ children: /* @__PURE__ */ jsx(Dialog.Root, {
31
+ open,
32
+ defaultOpen: open === void 0 ? defaultOpen : void 0,
33
+ onOpenChange: handleOpenChange,
34
+ ...props
35
+ })
36
+ });
37
+ }
38
+ function DialogTrigger({ className, ref, ...props }) {
39
+ const anchor = useMorphAnchor();
40
+ const mergedRef = useMemo(() => composeRefs(anchor ?? void 0, ref), [anchor, ref]);
41
+ return /* @__PURE__ */ jsx(Dialog.Trigger, {
42
+ ref: mergedRef,
43
+ className,
44
+ ...props
45
+ });
46
+ }
47
+ /**
48
+ * The barrier behind the dialog. Fades on one duration only, so it lands fast
49
+ * enough that the page behind never feels stuck.
50
+ */
51
+ function DialogBackdrop({ className, ...props }) {
52
+ return /* @__PURE__ */ jsx(Dialog.Backdrop, {
53
+ "data-cl-slot": "dialog-backdrop",
54
+ className: cn("fixed inset-0 z-50 bg-scrim", "transition-opacity duration-(--cl-duration-surface) ease-cl-out", "data-[starting-style]:opacity-0 data-[ending-style]:opacity-0", className),
55
+ ...props
56
+ });
57
+ }
58
+ /**
59
+ * The frosted modal surface.
60
+ *
61
+ * Base UI marks the popup with `data-starting-style` and `data-ending-style`
62
+ * and waits for animations on the popup element before calling `forceUnmount`.
63
+ * The visible transition belongs to the wrapper, so `cl-exit-sentinel` adds a
64
+ * non-visual custom-property animation to the popup; Base UI can then wait for
65
+ * the wrapper's exit duration without moving the clipped surface separately.
66
+ *
67
+ * The positioning and the entrance live on the **wrapper**, not the popup. The
68
+ * popup is the clipped element and the SVG border and shadow overlays are its
69
+ * siblings, so scaling the popup alone would leave the 1px border and the shadow
70
+ * at their final size — 5% of a 512px dialog is 25px, plainly visible over the
71
+ * 250ms entrance. `.cl-enter-root` lifts Base UI's transition state onto the
72
+ * wrapper with `:has()`, so fill, border and shadow move as one object.
73
+ *
74
+ * The wrapper is also what `useSurfaceMorph` transforms: the dialog is laid out
75
+ * at its final size and carried from the trigger's rectangle onto itself, which
76
+ * is the one entrance the whole language shares. The geometry drives the
77
+ * content's opacity with it, so the layer is still visible while it collapses
78
+ * back into its trigger.
79
+ *
80
+ * **No shadow**, unlike every other floating layer. A modal is separated from the
81
+ * page by its scrim, and `--shadow-frost` under a 45% scrim is two depth cues
82
+ * claiming the same edge, which reads as a halo rather than as distance. A dialog
83
+ * that has no scrim — `modal={false}`, or one laid over its own artwork — asks for
84
+ * it back with `shadow-dialog`, which is what that token is for.
85
+ */
86
+ function DialogPopup({ className, wrapperClassName, ...props }) {
87
+ const source = useMorphSource();
88
+ const [surface, setSurface] = useState(null);
89
+ useSurfaceMorph({
90
+ surface,
91
+ anchor: source?.anchor,
92
+ open: source?.open ?? true
93
+ });
94
+ return /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(DialogBackdrop, {}), /* @__PURE__ */ jsx(Squircle, {
95
+ asChild: true,
96
+ radius: "dialog",
97
+ wrapperRef: setSurface,
98
+ wrapperClassName: cn("cl-enter-root cl-morph fixed top-1/2 left-1/2 z-50 w-full max-w-lg", "-translate-x-1/2 -translate-y-1/2", wrapperClassName),
99
+ children: /* @__PURE__ */ jsx(Dialog.Popup, {
100
+ "data-cl-slot": "dialog-popup",
101
+ className: cn("cl-exit-sentinel cl-frost p-6 font-sans text-foreground shadow-none", className),
102
+ ...props
103
+ })
104
+ })] });
105
+ }
106
+ function DialogTitle({ className, ...props }) {
107
+ return /* @__PURE__ */ jsx(Dialog.Title, {
108
+ "data-cl-slot": "dialog-title",
109
+ className: cn("text-headline text-foreground", className),
110
+ ...props
111
+ });
112
+ }
113
+ function DialogDescription({ className, ...props }) {
114
+ return /* @__PURE__ */ jsx(Dialog.Description, {
115
+ "data-cl-slot": "dialog-description",
116
+ className: cn("text-caption text-foreground-tertiary", className),
117
+ ...props
118
+ });
119
+ }
120
+ function DialogClose({ className, ...props }) {
121
+ return /* @__PURE__ */ jsx(Dialog.Close, {
122
+ className,
123
+ ...props
124
+ });
125
+ }
126
+ //#endregion
127
+ export { Dialog$1 as Dialog, DialogBackdrop, DialogClose, DialogDescription, DialogPopup, DialogTitle, DialogTrigger };
128
+
129
+ //# sourceMappingURL=dialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialog.js","names":["Dialog","BaseDialog"],"sources":["../../src/ui/dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Dialog as BaseDialog } from \"@base-ui/react/dialog\";\nimport { type ComponentProps, type ReactNode, useCallback, useMemo, useState } from \"react\";\nimport { MorphSourceProvider, useMorphAnchor, useMorphSource, useSurfaceMorph } from \"@/lib/morph\";\nimport { composeRefs, Squircle } from \"@/lib/squircle\";\nimport { cn } from \"@/lib/utils\";\n\nexport type DialogProps<Payload = unknown> = BaseDialog.Root.Props<Payload>;\n\n/**\n * The modal root, which also remembers where it was opened from.\n *\n * `Dialog.Popup` grows out of the trigger's rectangle, so the two have to know\n * about each other; passing the anchor between siblings is what this component\n * exists for. It is the same provider the select will use, so both surfaces\n * morph with one implementation.\n *\n * The open state is mirrored here — not invented here. `open` still wins when it\n * is controlled, and `onOpenChange` still fires for every change, so a consumer's\n * own state stays the single source of truth; the mirror only exists because the\n * popup, which is a *sibling* of the trigger, has to know when a dismissal began\n * in order to reverse the morph before Base UI unmounts it.\n */ export function Dialog<Payload = unknown>({\n open,\n defaultOpen,\n onOpenChange,\n ...props\n}: DialogProps<Payload>) {\n const [uncontrolled, setUncontrolled] = useState(defaultOpen ?? false);\n const handleOpenChange = useCallback(\n (next: boolean, details: BaseDialog.Root.ChangeEventDetails) => {\n setUncontrolled(next);\n onOpenChange?.(next, details);\n },\n [onOpenChange],\n );\n\n return (\n <MorphSourceProvider open={open ?? uncontrolled}>\n <BaseDialog.Root\n open={open}\n defaultOpen={open === undefined ? defaultOpen : undefined}\n onOpenChange={handleOpenChange}\n {...props}\n />\n </MorphSourceProvider>\n );\n}\n\nexport type DialogTriggerProps = Omit<ComponentProps<typeof BaseDialog.Trigger>, \"className\"> & {\n className?: string;\n};\n\nexport function DialogTrigger({ className, ref, ...props }: DialogTriggerProps) {\n const anchor = useMorphAnchor();\n const mergedRef = useMemo(() => composeRefs(anchor ?? undefined, ref), [anchor, ref]);\n return <BaseDialog.Trigger ref={mergedRef} className={className} {...props} />;\n}\n\nexport type DialogBackdropProps = Omit<ComponentProps<typeof BaseDialog.Backdrop>, \"className\"> & {\n className?: string;\n};\n\n/**\n * The barrier behind the dialog. Fades on one duration only, so it lands fast\n * enough that the page behind never feels stuck.\n */\nexport function DialogBackdrop({ className, ...props }: DialogBackdropProps) {\n return (\n <BaseDialog.Backdrop\n data-cl-slot=\"dialog-backdrop\"\n className={cn(\n \"fixed inset-0 z-50 bg-scrim\",\n \"transition-opacity duration-(--cl-duration-surface) ease-cl-out\",\n \"data-[starting-style]:opacity-0 data-[ending-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport type DialogPopupProps = Omit<ComponentProps<typeof BaseDialog.Popup>, \"className\"> & {\n /** Applied to the clipped element: the frost, padding and text. */\n className?: string;\n /** Applied to the wrapper, which is what gets positioned and animated. */\n wrapperClassName?: string;\n /** Rendered inside the popup, above the body. */\n children?: ReactNode;\n};\n\n/**\n * The frosted modal surface.\n *\n * Base UI marks the popup with `data-starting-style` and `data-ending-style`\n * and waits for animations on the popup element before calling `forceUnmount`.\n * The visible transition belongs to the wrapper, so `cl-exit-sentinel` adds a\n * non-visual custom-property animation to the popup; Base UI can then wait for\n * the wrapper's exit duration without moving the clipped surface separately.\n *\n * The positioning and the entrance live on the **wrapper**, not the popup. The\n * popup is the clipped element and the SVG border and shadow overlays are its\n * siblings, so scaling the popup alone would leave the 1px border and the shadow\n * at their final size — 5% of a 512px dialog is 25px, plainly visible over the\n * 250ms entrance. `.cl-enter-root` lifts Base UI's transition state onto the\n * wrapper with `:has()`, so fill, border and shadow move as one object.\n *\n * The wrapper is also what `useSurfaceMorph` transforms: the dialog is laid out\n * at its final size and carried from the trigger's rectangle onto itself, which\n * is the one entrance the whole language shares. The geometry drives the\n * content's opacity with it, so the layer is still visible while it collapses\n * back into its trigger.\n *\n * **No shadow**, unlike every other floating layer. A modal is separated from the\n * page by its scrim, and `--shadow-frost` under a 45% scrim is two depth cues\n * claiming the same edge, which reads as a halo rather than as distance. A dialog\n * that has no scrim — `modal={false}`, or one laid over its own artwork — asks for\n * it back with `shadow-dialog`, which is what that token is for.\n */\nexport function DialogPopup({ className, wrapperClassName, ...props }: DialogPopupProps) {\n const source = useMorphSource();\n const [surface, setSurface] = useState<HTMLDivElement | null>(null);\n useSurfaceMorph({ surface, anchor: source?.anchor, open: source?.open ?? true });\n\n return (\n <BaseDialog.Portal>\n <DialogBackdrop />\n <Squircle\n asChild\n radius=\"dialog\"\n wrapperRef={setSurface}\n wrapperClassName={cn(\n \"cl-enter-root cl-morph fixed top-1/2 left-1/2 z-50 w-full max-w-lg\",\n \"-translate-x-1/2 -translate-y-1/2\",\n wrapperClassName,\n )}\n >\n <BaseDialog.Popup\n data-cl-slot=\"dialog-popup\"\n className={cn(\n \"cl-exit-sentinel cl-frost p-6 font-sans text-foreground shadow-none\",\n className,\n )}\n {...props}\n />\n </Squircle>\n </BaseDialog.Portal>\n );\n}\n\nexport type DialogTitleProps = Omit<ComponentProps<typeof BaseDialog.Title>, \"className\"> & {\n className?: string;\n};\n\nexport function DialogTitle({ className, ...props }: DialogTitleProps) {\n return (\n <BaseDialog.Title\n data-cl-slot=\"dialog-title\"\n className={cn(\"text-headline text-foreground\", className)}\n {...props}\n />\n );\n}\n\nexport type DialogDescriptionProps = Omit<\n ComponentProps<typeof BaseDialog.Description>,\n \"className\"\n> & { className?: string };\n\nexport function DialogDescription({ className, ...props }: DialogDescriptionProps) {\n return (\n <BaseDialog.Description\n data-cl-slot=\"dialog-description\"\n className={cn(\"text-caption text-foreground-tertiary\", className)}\n {...props}\n />\n );\n}\n\nexport type DialogCloseProps = Omit<ComponentProps<typeof BaseDialog.Close>, \"className\"> & {\n className?: string;\n};\n\nexport function DialogClose({ className, ...props }: DialogCloseProps) {\n return <BaseDialog.Close className={className} {...props} />;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;GAuBI,SAAgBA,SAA0B,EAC5C,MACA,aACA,cACA,GAAG,SACoB;CACvB,MAAM,CAAC,cAAc,mBAAmB,SAAS,eAAe,KAAK;CACrE,MAAM,mBAAmB,aACtB,MAAe,YAAgD;EAC9D,gBAAgB,IAAI;EACpB,eAAe,MAAM,OAAO;CAC9B,GACA,CAAC,YAAY,CACf;CAEA,OACE,oBAAC,qBAAD;EAAqB,MAAM,QAAQ;EACjC,UAAA,oBAACC,OAAW,MAAZ;GACQ;GACN,aAAa,SAAS,KAAA,IAAY,cAAc,KAAA;GAChD,cAAc;GACd,GAAI;EACL,CAAA;CACkB,CAAA;AAEzB;AAMA,SAAgB,cAAc,EAAE,WAAW,KAAK,GAAG,SAA6B;CAC9E,MAAM,SAAS,eAAe;CAC9B,MAAM,YAAY,cAAc,YAAY,UAAU,KAAA,GAAW,GAAG,GAAG,CAAC,QAAQ,GAAG,CAAC;CACpF,OAAO,oBAACA,OAAW,SAAZ;EAAoB,KAAK;EAAsB;EAAW,GAAI;CAAQ,CAAA;AAC/E;;;;;AAUA,SAAgB,eAAe,EAAE,WAAW,GAAG,SAA8B;CAC3E,OACE,oBAACA,OAAW,UAAZ;EACE,gBAAa;EACb,WAAW,GACT,+BACA,mEACA,iEACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,SAAgB,YAAY,EAAE,WAAW,kBAAkB,GAAG,SAA2B;CACvF,MAAM,SAAS,eAAe;CAC9B,MAAM,CAAC,SAAS,cAAc,SAAgC,IAAI;CAClE,gBAAgB;EAAE;EAAS,QAAQ,QAAQ;EAAQ,MAAM,QAAQ,QAAQ;CAAK,CAAC;CAE/E,OACE,qBAACA,OAAW,QAAZ,EAAA,UAAA,CACE,oBAAC,gBAAD,CAAiB,CAAA,GACjB,oBAAC,UAAD;EACE,SAAA;EACA,QAAO;EACP,YAAY;EACZ,kBAAkB,GAChB,sEACA,qCACA,gBACF;EAEA,UAAA,oBAACA,OAAW,OAAZ;GACE,gBAAa;GACb,WAAW,GACT,uEACA,SACF;GACA,GAAI;EACL,CAAA;CACO,CAAA,CACO,EAAA,CAAA;AAEvB;AAMA,SAAgB,YAAY,EAAE,WAAW,GAAG,SAA2B;CACrE,OACE,oBAACA,OAAW,OAAZ;EACE,gBAAa;EACb,WAAW,GAAG,iCAAiC,SAAS;EACxD,GAAI;CACL,CAAA;AAEL;AAOA,SAAgB,kBAAkB,EAAE,WAAW,GAAG,SAAiC;CACjF,OACE,oBAACA,OAAW,aAAZ;EACE,gBAAa;EACb,WAAW,GAAG,yCAAyC,SAAS;EAChE,GAAI;CACL,CAAA;AAEL;AAMA,SAAgB,YAAY,EAAE,WAAW,GAAG,SAA2B;CACrE,OAAO,oBAACA,OAAW,OAAZ;EAA6B;EAAW,GAAI;CAAQ,CAAA;AAC7D"}
@@ -0,0 +1,34 @@
1
+ import { ComponentProps } from "react";
2
+ import { VariantProps } from "class-variance-authority";
3
+ import { Input } from "@base-ui/react/input";
4
+ //#region src/ui/input.d.ts
5
+ /**
6
+ * ClaraLight text field.
7
+ *
8
+ * The fill is `control` — a translucent overlay rather than an opaque colour —
9
+ * so the same field reads correctly whether it sits on `background` or on a
10
+ * `panel`. That is the core trick of the layered surface stack and it is why
11
+ * this component must not hard-code a background.
12
+ */
13
+ export declare const inputVariants: (props?: ({
14
+ size?: "lg" | "md" | "sm" | null | undefined;
15
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
16
+ export type InputProps = Omit<ComponentProps<typeof Input>, "className" | "size"> & VariantProps<typeof inputVariants> & {
17
+ className?: string;
18
+ /** Applied to the wrapper, which is what a caller's layout sizes. */
19
+ wrapperClassName?: string;
20
+ };
21
+ /**
22
+ * A ClaraLight text field.
23
+ *
24
+ * `sm` uses caption, `md` uses callout, and `lg` uses body typography.
25
+ * Dense inspector rows stay legible without shrinking the hit target.
26
+ *
27
+ * Note the `size` in `InputProps` is the ClaraLight density step, not the
28
+ * native `<input size>` character-width hint — the native attribute is omitted
29
+ * above, because the two collide and an intersection would make both unusable.
30
+ */
31
+ declare function Input$1({ className, wrapperClassName, size, ...props }: InputProps): import("react").JSX.Element;
32
+ //#endregion
33
+ export { Input$1 as Input };
34
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1,60 @@
1
+ "use client";
2
+ import { cn } from "../lib/utils.js";
3
+ import { Squircle } from "../lib/squircle.js";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { cva } from "class-variance-authority";
6
+ import { Input } from "@base-ui/react/input";
7
+ //#region src/ui/input.tsx
8
+ /**
9
+ * ClaraLight text field.
10
+ *
11
+ * The fill is `control` — a translucent overlay rather than an opaque colour —
12
+ * so the same field reads correctly whether it sits on `background` or on a
13
+ * `panel`. That is the core trick of the layered surface stack and it is why
14
+ * this component must not hard-code a background.
15
+ */
16
+ const inputVariants = cva([
17
+ "w-full border border-outline",
18
+ "bg-control font-sans text-foreground",
19
+ "placeholder:text-foreground-hint",
20
+ "transition-[background-color,border-color,color] duration-(--cl-duration-fast) ease-cl-out",
21
+ "hover:bg-control-highlight",
22
+ "data-[disabled]:pointer-events-none",
23
+ "data-[disabled]:text-foreground-disabled data-[disabled]:placeholder:text-foreground-disabled",
24
+ "data-[invalid]:border-danger"
25
+ ], {
26
+ variants: {
27
+ /** Shared control geometry; typography follows density. */
28
+ size: {
29
+ sm: "h-control-sm px-2 text-caption",
30
+ md: "h-control-md px-3 text-callout",
31
+ lg: "h-control-lg px-4 text-body"
32
+ } },
33
+ defaultVariants: { size: "md" }
34
+ });
35
+ /**
36
+ * A ClaraLight text field.
37
+ *
38
+ * `sm` uses caption, `md` uses callout, and `lg` uses body typography.
39
+ * Dense inspector rows stay legible without shrinking the hit target.
40
+ *
41
+ * Note the `size` in `InputProps` is the ClaraLight density step, not the
42
+ * native `<input size>` character-width hint — the native attribute is omitted
43
+ * above, because the two collide and an intersection would make both unusable.
44
+ */
45
+ function Input$1({ className, wrapperClassName, size, ...props }) {
46
+ return /* @__PURE__ */ jsx(Squircle, {
47
+ asChild: true,
48
+ radius: "control",
49
+ ring: "field",
50
+ wrapperClassName: cn("block w-full", wrapperClassName),
51
+ children: /* @__PURE__ */ jsx(Input, {
52
+ className: cn(inputVariants({ size }), className),
53
+ ...props
54
+ })
55
+ });
56
+ }
57
+ //#endregion
58
+ export { Input$1 as Input, inputVariants };
59
+
60
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","names":["Input","BaseInput"],"sources":["../../src/ui/input.tsx"],"sourcesContent":["\"use client\";\n\nimport { Input as BaseInput } from \"@base-ui/react/input\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ComponentProps } from \"react\";\nimport { Squircle } from \"@/lib/squircle\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * ClaraLight text field.\n *\n * The fill is `control` — a translucent overlay rather than an opaque colour —\n * so the same field reads correctly whether it sits on `background` or on a\n * `panel`. That is the core trick of the layered surface stack and it is why\n * this component must not hard-code a background.\n */\nexport const inputVariants = cva(\n [\n \"w-full border border-outline\",\n \"bg-control font-sans text-foreground\",\n \"placeholder:text-foreground-hint\",\n \"transition-[background-color,border-color,color] duration-(--cl-duration-fast) ease-cl-out\",\n \"hover:bg-control-highlight\",\n \"data-[disabled]:pointer-events-none\",\n \"data-[disabled]:text-foreground-disabled data-[disabled]:placeholder:text-foreground-disabled\",\n // Set by Base UI when the field sits inside a Field.Root.\n \"data-[invalid]:border-danger\",\n ],\n {\n variants: {\n /** Shared control geometry; typography follows density. */\n size: {\n sm: \"h-control-sm px-2 text-caption\",\n md: \"h-control-md px-3 text-callout\",\n lg: \"h-control-lg px-4 text-body\",\n },\n },\n defaultVariants: { size: \"md\" },\n },\n);\n\nexport type InputProps = Omit<ComponentProps<typeof BaseInput>, \"className\" | \"size\"> &\n VariantProps<typeof inputVariants> & {\n className?: string;\n /** Applied to the wrapper, which is what a caller's layout sizes. */\n wrapperClassName?: string;\n };\n\n/**\n * A ClaraLight text field.\n *\n * `sm` uses caption, `md` uses callout, and `lg` uses body typography.\n * Dense inspector rows stay legible without shrinking the hit target.\n *\n * Note the `size` in `InputProps` is the ClaraLight density step, not the\n * native `<input size>` character-width hint — the native attribute is omitted\n * above, because the two collide and an intersection would make both unusable.\n */\nexport function Input({ className, wrapperClassName, size, ...props }: InputProps) {\n return (\n <Squircle\n asChild\n radius=\"control\"\n ring=\"field\"\n wrapperClassName={cn(\"block w-full\", wrapperClassName)}\n >\n <BaseInput className={cn(inputVariants({ size }), className)} {...props} />\n </Squircle>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,MAAa,gBAAgB,IAC3B;CACE;CACA;CACA;CACA;CACA;CACA;CACA;CAEA;AACF,GACA;CACE,UAAU;;AAER,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN,EACF;CACA,iBAAiB,EAAE,MAAM,KAAK;AAChC,CACF;;;;;;;;;;;AAmBA,SAAgBA,QAAM,EAAE,WAAW,kBAAkB,MAAM,GAAG,SAAqB;CACjF,OACE,oBAAC,UAAD;EACE,SAAA;EACA,QAAO;EACP,MAAK;EACL,kBAAkB,GAAG,gBAAgB,gBAAgB;EAErD,UAAA,oBAACC,OAAD;GAAW,WAAW,GAAG,cAAc,EAAE,KAAK,CAAC,GAAG,SAAS;GAAG,GAAI;EAAQ,CAAA;CAClE,CAAA;AAEd"}