@candor-ui/react 2.2.0 → 2.4.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.
Files changed (65) hide show
  1. package/README.md +3 -3
  2. package/dist/adapters/use-ag-ui.d.ts +1 -1
  3. package/dist/adapters/use-candor-chat.d.ts +1 -1
  4. package/dist/adapters/use-claude-agent.d.ts +1 -1
  5. package/dist/blocks/copy-field.js +4 -1
  6. package/dist/blocks/degraded-panel.js +3 -1
  7. package/dist/blocks/locked.js +23 -2
  8. package/dist/blocks/relative-time.js +1 -1
  9. package/dist/blocks/status-dot.d.ts +14 -3
  10. package/dist/blocks/status-dot.js +17 -22
  11. package/dist/blocks/step-list.d.ts +2 -1
  12. package/dist/blocks/step-list.js +19 -27
  13. package/dist/blocks/streaming-text.js +3 -1
  14. package/dist/blocks/surface.d.ts +1 -1
  15. package/dist/chat/attachment-preview.d.ts +6 -1
  16. package/dist/chat/attachment-preview.js +9 -3
  17. package/dist/chat/card-registry.js +6 -4
  18. package/dist/chat/citation.js +3 -3
  19. package/dist/chat/composer.js +19 -53
  20. package/dist/chat/context-meter.d.ts +5 -0
  21. package/dist/chat/context-meter.js +15 -1
  22. package/dist/chat/entity-chip.d.ts +3 -1
  23. package/dist/chat/entity-chip.js +2 -2
  24. package/dist/chat/folded-turns.js +3 -1
  25. package/dist/chat/message-actions.js +5 -2
  26. package/dist/chat/message.js +9 -5
  27. package/dist/chat/payload.js +1 -1
  28. package/dist/chat/permission-prompt.d.ts +5 -0
  29. package/dist/chat/permission-prompt.js +36 -2
  30. package/dist/chat/prompt-suggestions.js +4 -1
  31. package/dist/chat/reasoning.js +6 -1
  32. package/dist/chat/thread.js +37 -9
  33. package/dist/chat/tool-call.js +6 -2
  34. package/dist/index.d.ts +9 -0
  35. package/dist/index.js +9 -0
  36. package/dist/lib/motion.d.ts +466 -0
  37. package/dist/lib/motion.js +380 -0
  38. package/dist/lib/sound.d.ts +44 -0
  39. package/dist/lib/sound.js +63 -0
  40. package/dist/styles.css +562 -45
  41. package/dist/ui/accordion.d.ts +23 -0
  42. package/dist/ui/accordion.js +45 -0
  43. package/dist/ui/alert.d.ts +22 -0
  44. package/dist/ui/alert.js +59 -0
  45. package/dist/ui/button.d.ts +1 -1
  46. package/dist/ui/button.js +5 -3
  47. package/dist/ui/checkbox.d.ts +14 -0
  48. package/dist/ui/checkbox.js +32 -0
  49. package/dist/ui/collapsible.d.ts +3 -2
  50. package/dist/ui/collapsible.js +6 -3
  51. package/dist/ui/label.d.ts +10 -0
  52. package/dist/ui/label.js +16 -0
  53. package/dist/ui/popover.d.ts +1 -1
  54. package/dist/ui/popover.js +4 -2
  55. package/dist/ui/progress.d.ts +29 -0
  56. package/dist/ui/progress.js +27 -0
  57. package/dist/ui/skeleton.d.ts +1 -1
  58. package/dist/ui/skeleton.js +5 -2
  59. package/dist/ui/slider.d.ts +28 -0
  60. package/dist/ui/slider.js +41 -0
  61. package/dist/ui/switch.d.ts +14 -0
  62. package/dist/ui/switch.js +23 -0
  63. package/dist/ui/tooltip.d.ts +1 -1
  64. package/dist/ui/tooltip.js +4 -2
  65. package/package.json +2 -3
@@ -0,0 +1,23 @@
1
+ import * as React from "react";
2
+ import { Accordion as AccordionPrimitive } from "radix-ui";
3
+ import { type RenderProp } from "../lib/render-prop.js";
4
+ /**
5
+ * A stack of headings that each open to reveal more. Pass `type="single"` (one open at a time; add `collapsible` so the
6
+ * open one can be closed) or `type="multiple"`. Everything is closed until the person opens it, unless the app names
7
+ * what starts open with `defaultValue` or `value`. Arrow keys move between headings, Home and End go to the first
8
+ * and last, Space or Enter opens and closes.
9
+ */
10
+ declare function Accordion(allProps: React.ComponentProps<typeof AccordionPrimitive.Root> & RenderProp): React.JSX.Element;
11
+ /** One heading and its panel. Give it a `value` that is unique in the accordion. */
12
+ declare function AccordionItem(allProps: React.ComponentProps<typeof AccordionPrimitive.Item> & RenderProp): React.JSX.Element;
13
+ /** The heading that opens and closes its panel, with a chevron that turns over when open. Its children are the heading's text. */
14
+ declare function AccordionTrigger(allProps: React.ComponentProps<typeof AccordionPrimitive.Trigger> & RenderProp): React.JSX.Element;
15
+ /**
16
+ * The panel. It opens and closes to the height Radix measured, so a change is seen settling rather than snapping;
17
+ * data-motion="none" and the OS's reduced-motion setting make it snap.
18
+ *
19
+ * @motion reveal:open The panel grows to its measured height when opened and shrinks back when closed, in the base
20
+ * duration. Content the app puts in it is not animated.
21
+ */
22
+ declare function AccordionContent(allProps: React.ComponentProps<typeof AccordionPrimitive.Content> & RenderProp): React.JSX.Element;
23
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
@@ -0,0 +1,45 @@
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { ChevronDown } from "lucide-react";
5
+ import { Accordion as AccordionPrimitive } from "radix-ui";
6
+ import { withRender } from "../lib/render-prop.js";
7
+ import { cn } from "../lib/utils.js";
8
+ import { motion } from "../lib/motion.js";
9
+ const openMotion = motion("accordion", "open", "reveal");
10
+ /**
11
+ * A stack of headings that each open to reveal more. Pass `type="single"` (one open at a time; add `collapsible` so the
12
+ * open one can be closed) or `type="multiple"`. Everything is closed until the person opens it, unless the app names
13
+ * what starts open with `defaultValue` or `value`. Arrow keys move between headings, Home and End go to the first
14
+ * and last, Space or Enter opens and closes.
15
+ */
16
+ function Accordion(allProps) {
17
+ const props = withRender(allProps);
18
+ return _jsx(AccordionPrimitive.Root, { "data-slot": "accordion", ...props });
19
+ }
20
+ /** One heading and its panel. Give it a `value` that is unique in the accordion. */
21
+ function AccordionItem(allProps) {
22
+ const { className, ...props } = withRender(allProps);
23
+ return _jsx(AccordionPrimitive.Item, { "data-slot": "accordion-item", className: cn("border-b border-border last:border-b-0", className), ...props });
24
+ }
25
+ /** The heading that opens and closes its panel, with a chevron that turns over when open. Its children are the heading's text. */
26
+ function AccordionTrigger(allProps) {
27
+ const { className, children, render, nativeButton: _nativeButton, ...props } = allProps;
28
+ const heading = (_jsxs(_Fragment, { children: [children, _jsx(ChevronDown, { "aria-hidden": true, style: openMotion, className: "pointer-events-none mt-0.5 size-4 shrink-0 text-muted-foreground cd-reveal-turn" })] }));
29
+ return (_jsx(AccordionPrimitive.Header, { className: "flex", children: _jsx(AccordionPrimitive.Trigger, { "data-slot": "accordion-trigger", className: cn("flex flex-1 items-start justify-between gap-4 rounded-md py-3 text-start text-sm font-medium outline-none cd-tint hover:underline focus-visible:ring-[3px] focus-visible:ring-ring/80 disabled:pointer-events-none disabled:opacity-45 data-[locked]:cursor-not-allowed data-[locked]:opacity-45 [&[data-state=open]>svg]:rotate-180", className), ...props, ...(render ? { asChild: true } : null), children: render ? React.cloneElement(render, undefined, heading) : heading }) }));
30
+ }
31
+ /**
32
+ * The panel. It opens and closes to the height Radix measured, so a change is seen settling rather than snapping;
33
+ * data-motion="none" and the OS's reduced-motion setting make it snap.
34
+ *
35
+ * @motion reveal:open The panel grows to its measured height when opened and shrinks back when closed, in the base
36
+ * duration. Content the app puts in it is not animated.
37
+ */
38
+ function AccordionContent(allProps) {
39
+ const { className, children, render, nativeButton: _nativeButton, style, ...props } = allProps;
40
+ const inner = _jsx("div", { className: cn("pt-0 pb-4", className), children: children });
41
+ return (_jsx(AccordionPrimitive.Content, { "data-slot": "accordion-content",
42
+ // cd-reveal reads Radix's collapsible height, then the accordion's own.
43
+ style: { ...openMotion, ...style }, className: "overflow-hidden text-sm data-[state=open]:cd-reveal data-[state=closed]:cd-reveal-out", ...props, ...(render ? { asChild: true } : null), children: render ? React.cloneElement(render, undefined, inner) : inner }));
44
+ }
45
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
@@ -0,0 +1,22 @@
1
+ import * as React from "react";
2
+ /**
3
+ * A message about the page or the work that stays where it is until it no longer applies: a warning before a
4
+ * change, a note that something failed, a fact the person should know. Put an icon first, then `AlertTitle` and
5
+ * `AlertDescription`. Its text is plain text from the app, never HTML. An `Alert` is read out when it appears if
6
+ * its variant is `destructive` (role "alert"); the other variants are polite (role "status"). Pass `role` to change that.
7
+ * For a short notice that goes away by itself use a toast; an Alert doesn't dismiss itself.
8
+ *
9
+ * @motion arrive:enter An Alert that appears after the page has drawn rises in over a quarter of a second. One that is
10
+ * there when the page first draws, or when it is rendered on the server, is simply there. "After the page has drawn" is
11
+ * counted from when the page loaded, not from the route: after a client-side navigation, an Alert on the new route
12
+ * rises in.
13
+ */
14
+ declare function Alert({ className, variant, role, style, ...props }: React.ComponentProps<"div"> & {
15
+ /** The kind of message. `destructive` is for a failure or something that can't be undone; `warning` for care before acting; `attention` for something waiting on the person; `success` for a confirmed result. Defaults to a plain card. */
16
+ variant?: "default" | "success" | "warning" | "attention" | "destructive" | null | undefined;
17
+ }): React.JSX.Element;
18
+ /** The alert's headline: what happened or what to know, in a few words. */
19
+ declare function AlertTitle({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
20
+ /** The detail under the title: what it affects and what the person can do. Plain text or any elements; links and buttons keep their own styles. */
21
+ declare function AlertDescription({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
22
+ export { Alert, AlertTitle, AlertDescription };
@@ -0,0 +1,59 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cva } from "class-variance-authority";
5
+ import { cn } from "../lib/utils.js";
6
+ import { motion } from "../lib/motion.js";
7
+ const enterMotion = motion("alert", "enter", "arrive");
8
+ // Set one frame after this file loads in the browser, which is when the page's first draw is done; an Alert that mounts
9
+ // after that has arrived. It is per page load, not per route: after a client-side route change, an Alert on the new route
10
+ // rises in, because it arrived after the page drew. An Alert in the first render, or on the server, is simply there.
11
+ let pageDrawn = false;
12
+ if (typeof window !== "undefined") {
13
+ const frame = typeof window.requestAnimationFrame === "function" ? window.requestAnimationFrame.bind(window) : (cb) => window.setTimeout(cb, 0);
14
+ frame(() => {
15
+ pageDrawn = true;
16
+ });
17
+ }
18
+ const subscribeNever = () => () => { };
19
+ const alertVariants = cva("relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", {
20
+ variants: {
21
+ variant: {
22
+ default: "border-border bg-card text-card-foreground",
23
+ success: "border-success/40 bg-success-weak/60 text-foreground [&>svg]:text-success-text",
24
+ warning: "border-warning/40 bg-warning-weak/60 text-foreground [&>svg]:text-warning-text",
25
+ attention: "border-attention/40 bg-attention-weak/60 text-foreground [&>svg]:text-attention-text",
26
+ destructive: "border-destructive/40 bg-destructive-weak/60 text-foreground [&>svg]:text-destructive-text",
27
+ },
28
+ },
29
+ defaultVariants: { variant: "default" },
30
+ });
31
+ /**
32
+ * A message about the page or the work that stays where it is until it no longer applies: a warning before a
33
+ * change, a note that something failed, a fact the person should know. Put an icon first, then `AlertTitle` and
34
+ * `AlertDescription`. Its text is plain text from the app, never HTML. An `Alert` is read out when it appears if
35
+ * its variant is `destructive` (role "alert"); the other variants are polite (role "status"). Pass `role` to change that.
36
+ * For a short notice that goes away by itself use a toast; an Alert doesn't dismiss itself.
37
+ *
38
+ * @motion arrive:enter An Alert that appears after the page has drawn rises in over a quarter of a second. One that is
39
+ * there when the page first draws, or when it is rendered on the server, is simply there. "After the page has drawn" is
40
+ * counted from when the page loaded, not from the route: after a client-side navigation, an Alert on the new route
41
+ * rises in.
42
+ */
43
+ function Alert({ className, variant, role, style, ...props }) {
44
+ // Whether this Alert mounted after the page's first draw. The server and the hydrating render answer no, so what
45
+ // the server sent is what hydrates; an Alert the browser creates later answers from the page. Decided once, so a
46
+ // re-render doesn't replay it.
47
+ const drawn = React.useSyncExternalStore(subscribeNever, () => pageDrawn, () => false);
48
+ const [arrived] = React.useState(drawn);
49
+ return (_jsx("div", { "data-slot": "alert", "data-variant": variant ?? "default", role: role ?? (variant === "destructive" ? "alert" : "status"), style: { ...enterMotion, ...style }, className: cn(alertVariants({ variant }), arrived && "cd-arrive", className), ...props }));
50
+ }
51
+ /** The alert's headline: what happened or what to know, in a few words. */
52
+ function AlertTitle({ className, ...props }) {
53
+ return _jsx("div", { "data-slot": "alert-title", className: cn("col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight", className), ...props });
54
+ }
55
+ /** The detail under the title: what it affects and what the person can do. Plain text or any elements; links and buttons keep their own styles. */
56
+ function AlertDescription({ className, ...props }) {
57
+ return (_jsx("div", { "data-slot": "alert-description", className: cn("col-start-2 grid justify-items-start gap-1 text-sm text-muted-foreground [&_p]:leading-relaxed", className), ...props }));
58
+ }
59
+ export { Alert, AlertTitle, AlertDescription };
@@ -3,7 +3,7 @@ import { type VariantProps } from "class-variance-authority";
3
3
  import { type RenderProp } from "../lib/render-prop.js";
4
4
  declare const buttonVariants: (props?: ({
5
5
  variant?: "link" | "outline" | "secondary" | "destructive" | "default" | "ghost" | null | undefined;
6
- size?: "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
6
+ size?: "default" | "icon" | "xs" | "sm" | "lg" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
7
7
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
8
  declare function Button(allProps: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
9
9
  /** Render the child element (a link, say) with the button's styles instead of a <button>. */
package/dist/ui/button.js CHANGED
@@ -5,9 +5,11 @@ import { cva } from "class-variance-authority";
5
5
  import { Slot } from "radix-ui";
6
6
  import { withRender } from "../lib/render-prop.js";
7
7
  import { cn } from "../lib/utils.js";
8
+ import { motion } from "../lib/motion.js";
9
+ const pressMotion = motion("button", "press", "press");
8
10
  // The accent fills the one primary act, the radius is the theme's
9
11
  // --cd-radius-button, and buttons press down slightly on :active.
10
- const buttonVariants = cva("inline-flex shrink-0 items-center justify-center gap-2 rounded-button text-sm font-medium whitespace-nowrap outline-none select-none transition-[background-color,color,border-color,box-shadow,transform,opacity] duration-150 ease-standard active:scale-[0.98] focus-visible:ring-[3px] focus-visible:ring-ring/80 disabled:pointer-events-none disabled:opacity-45 data-[locked]:cursor-not-allowed data-[locked]:opacity-45 data-[locked]:active:scale-100 aria-invalid:ring-destructive/25 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
12
+ const buttonVariants = cva("inline-flex shrink-0 items-center justify-center gap-2 rounded-button text-sm font-medium whitespace-nowrap outline-none select-none cd-press focus-visible:ring-[3px] focus-visible:ring-ring/80 disabled:pointer-events-none disabled:opacity-45 data-[locked]:cursor-not-allowed data-[locked]:opacity-45 data-[locked]:active:scale-100 aria-invalid:ring-destructive/25 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
11
13
  variants: {
12
14
  variant: {
13
15
  default: "bg-primary text-primary-foreground hover:bg-primary-hover",
@@ -34,8 +36,8 @@ const buttonVariants = cva("inline-flex shrink-0 items-center justify-center gap
34
36
  },
35
37
  });
36
38
  function Button(allProps) {
37
- const { className, variant = "default", size = "default", asChild = false, ...props } = withRender(allProps);
39
+ const { className, style, variant = "default", size = "default", asChild = false, ...props } = withRender(allProps);
38
40
  const Comp = asChild ? Slot.Root : "button";
39
- return (_jsx(Comp, { "data-slot": "button", "data-variant": variant, "data-size": size, className: cn(buttonVariants({ variant, size, className })), ...props }));
41
+ return (_jsx(Comp, { "data-slot": "button", "data-variant": variant, "data-size": size, style: { ...pressMotion, ...style }, className: cn(buttonVariants({ variant, size, className })), ...props }));
40
42
  }
41
43
  export { Button, buttonVariants };
@@ -0,0 +1,14 @@
1
+ import * as React from "react";
2
+ import { Checkbox as CheckboxPrimitive } from "radix-ui";
3
+ import { type RenderProp } from "../lib/render-prop.js";
4
+ /**
5
+ * A box the person ticks. Nothing is checked until the person checks it or the app says so with `checked` or
6
+ * `defaultChecked`; a choice that decides something is left empty, never pre-ticked. `checked="indeterminate"` shows a
7
+ * dash for a parent whose children are only partly ticked. Pair it with a `Label` (`htmlFor` and `id`), or wrap both
8
+ * in a <label>. To lock it, wrap it in `Locked` with a reason: it stays focusable, says why, and doesn't change.
9
+ *
10
+ * @motion mark:tick The tick draws along its path when the person checks the box. A box that is already checked when it
11
+ * appears, or that the app changes, shows its tick at once: nothing is drawn for a change the person didn't make.
12
+ */
13
+ declare function Checkbox(allProps: React.ComponentProps<typeof CheckboxPrimitive.Root> & RenderProp): React.JSX.Element;
14
+ export { Checkbox };
@@ -0,0 +1,32 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Checkbox as CheckboxPrimitive } from "radix-ui";
5
+ import {} from "../lib/render-prop.js";
6
+ import { cn } from "../lib/utils.js";
7
+ import { motion } from "../lib/motion.js";
8
+ const tickMotion = motion("checkbox", "tick", "mark");
9
+ /**
10
+ * A box the person ticks. Nothing is checked until the person checks it or the app says so with `checked` or
11
+ * `defaultChecked`; a choice that decides something is left empty, never pre-ticked. `checked="indeterminate"` shows a
12
+ * dash for a parent whose children are only partly ticked. Pair it with a `Label` (`htmlFor` and `id`), or wrap both
13
+ * in a <label>. To lock it, wrap it in `Locked` with a reason: it stays focusable, says why, and doesn't change.
14
+ *
15
+ * @motion mark:tick The tick draws along its path when the person checks the box. A box that is already checked when it
16
+ * appears, or that the app changes, shows its tick at once: nothing is drawn for a change the person didn't make.
17
+ */
18
+ function Checkbox(allProps) {
19
+ const { className, onCheckedChange, render, nativeButton: _nativeButton, children, ...props } = allProps;
20
+ // The tick is drawn only for the state the person just set. An app-driven `checked` that differs retires it, so a later
21
+ // app change (even to the same value) shows the tick at once.
22
+ const [personSet, setPersonSet] = React.useState(undefined);
23
+ if (personSet !== undefined && props.checked !== undefined && props.checked !== personSet)
24
+ setPersonSet(undefined);
25
+ const byPerson = personSet !== undefined && (props.checked === undefined || props.checked === personSet);
26
+ const mark = children ?? (_jsxs(CheckboxPrimitive.Indicator, { "data-slot": "checkbox-indicator", className: "group/mark grid place-content-center text-current", children: [_jsx("svg", { "aria-hidden": true, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", className: "size-3.5 group-data-[state=indeterminate]/mark:hidden", children: _jsx("path", { d: "M3.5 8.5 6.75 11.5 12.5 4.75", pathLength: 1, strokeDasharray: 1, style: tickMotion, className: cn(byPerson && "cd-mark") }) }), _jsx("svg", { "aria-hidden": true, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", className: "hidden size-3.5 group-data-[state=indeterminate]/mark:block", children: _jsx("path", { d: "M4 8h8" }) })] }));
27
+ return (_jsx(CheckboxPrimitive.Root, { "data-slot": "checkbox", onCheckedChange: (checked) => {
28
+ setPersonSet(checked);
29
+ onCheckedChange?.(checked);
30
+ }, className: cn("peer relative after:absolute after:-inset-1 grid size-4 shrink-0 place-content-center rounded-xs border border-input bg-card text-primary-foreground shadow-xs cd-tint outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/80 disabled:cursor-not-allowed disabled:opacity-45 data-[locked]:cursor-not-allowed data-[locked]:opacity-45 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary aria-invalid:border-destructive aria-invalid:ring-destructive/25 dark:bg-input/30", className), ...props, ...(render ? { asChild: true } : null), children: render ? React.cloneElement(render, undefined, mark) : mark }));
31
+ }
32
+ export { Checkbox };
@@ -4,7 +4,8 @@ declare function Collapsible({ ...props }: React.ComponentProps<typeof Collapsib
4
4
  declare function CollapsibleTrigger(allProps: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger> & RenderProp): import("react").JSX.Element;
5
5
  /**
6
6
  * The content opens and closes to the height Radix measured (--radix-collapsible-content-height), so a change of
7
- * state is seen settling rather than snapping; data-motion="none" and the OS's reduced-motion setting make it snap.
7
+ * state is seen settling rather than snapping (the reveal family); data-motion="none" and the calm level make it snap.
8
+ * An item can pass its own moment's chain as `style` (`motion("tool-call", "open", "reveal")`).
8
9
  */
9
- declare function CollapsibleContent({ className, ...props }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>): import("react").JSX.Element;
10
+ declare function CollapsibleContent({ className, style, ...props }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>): import("react").JSX.Element;
10
11
  export { Collapsible, CollapsibleTrigger, CollapsibleContent };
@@ -3,6 +3,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { Collapsible as CollapsiblePrimitive } from "radix-ui";
4
4
  import { cn } from "../lib/utils.js";
5
5
  import { withRender } from "../lib/render-prop.js";
6
+ import { motion } from "../lib/motion.js";
7
+ const openMotion = motion("collapsible", "open", "reveal");
6
8
  function Collapsible({ ...props }) {
7
9
  return _jsx(CollapsiblePrimitive.Root, { "data-slot": "collapsible", ...props });
8
10
  }
@@ -12,9 +14,10 @@ function CollapsibleTrigger(allProps) {
12
14
  }
13
15
  /**
14
16
  * The content opens and closes to the height Radix measured (--radix-collapsible-content-height), so a change of
15
- * state is seen settling rather than snapping; data-motion="none" and the OS's reduced-motion setting make it snap.
17
+ * state is seen settling rather than snapping (the reveal family); data-motion="none" and the calm level make it snap.
18
+ * An item can pass its own moment's chain as `style` (`motion("tool-call", "open", "reveal")`).
16
19
  */
17
- function CollapsibleContent({ className, ...props }) {
18
- return (_jsx(CollapsiblePrimitive.CollapsibleContent, { "data-slot": "collapsible-content", className: cn("data-[state=open]:animate-collapse-down data-[state=closed]:animate-collapse-up", className), ...props }));
20
+ function CollapsibleContent({ className, style, ...props }) {
21
+ return (_jsx(CollapsiblePrimitive.CollapsibleContent, { "data-slot": "collapsible-content", style: { ...openMotion, ...style }, className: cn("data-[state=open]:cd-reveal data-[state=closed]:cd-reveal-out", className), ...props }));
19
22
  }
20
23
  export { Collapsible, CollapsibleTrigger, CollapsibleContent };
@@ -0,0 +1,10 @@
1
+ import * as React from "react";
2
+ import { Label as LabelPrimitive } from "radix-ui";
3
+ import { type RenderProp } from "../lib/render-prop.js";
4
+ /**
5
+ * The name of a control. Point it at the control with `htmlFor` and the control's `id`, or wrap both in it. Clicking
6
+ * it focuses or toggles the control. It dims with the control beside it (a `peer`) when that control is disabled or
7
+ * locked, so keep it directly after the control in the markup, or set `data-disabled` on a wrapping `group`.
8
+ */
9
+ declare function Label(allProps: React.ComponentProps<typeof LabelPrimitive.Root> & RenderProp): React.JSX.Element;
10
+ export { Label };
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Label as LabelPrimitive } from "radix-ui";
5
+ import { withRender } from "../lib/render-prop.js";
6
+ import { cn } from "../lib/utils.js";
7
+ /**
8
+ * The name of a control. Point it at the control with `htmlFor` and the control's `id`, or wrap both in it. Clicking
9
+ * it focuses or toggles the control. It dims with the control beside it (a `peer`) when that control is disabled or
10
+ * locked, so keep it directly after the control in the markup, or set `data-disabled` on a wrapping `group`.
11
+ */
12
+ function Label(allProps) {
13
+ const { className, ...props } = withRender(allProps);
14
+ return (_jsx(LabelPrimitive.Root, { "data-slot": "label", className: cn("flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-45 peer-disabled:cursor-not-allowed peer-disabled:opacity-45 peer-data-[locked]:cursor-not-allowed peer-data-[locked]:opacity-45", className), ...props }));
15
+ }
16
+ export { Label };
@@ -3,7 +3,7 @@ import { Popover as PopoverPrimitive } from "radix-ui";
3
3
  import { type RenderProp } from "../lib/render-prop.js";
4
4
  declare function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>): React.JSX.Element;
5
5
  declare function PopoverTrigger(allProps: React.ComponentProps<typeof PopoverPrimitive.Trigger> & RenderProp): React.JSX.Element;
6
- declare function PopoverContent({ className, align, sideOffset, ...props }: React.ComponentProps<typeof PopoverPrimitive.Content>): React.JSX.Element;
6
+ declare function PopoverContent({ className, style, align, sideOffset, ...props }: React.ComponentProps<typeof PopoverPrimitive.Content>): React.JSX.Element;
7
7
  declare function PopoverAnchor({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Anchor>): React.JSX.Element;
8
8
  declare function PopoverHeader({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
9
9
  declare function PopoverTitle({ className, ...props }: React.ComponentProps<"h2">): React.JSX.Element;
@@ -4,6 +4,8 @@ import * as React from "react";
4
4
  import { cn } from "../lib/utils.js";
5
5
  import { Popover as PopoverPrimitive } from "radix-ui";
6
6
  import { withRender } from "../lib/render-prop.js";
7
+ import { motion } from "../lib/motion.js";
8
+ const openMotion = motion("popover", "open", "overlay");
7
9
  function Popover({ ...props }) {
8
10
  return _jsx(PopoverPrimitive.Root, { "data-slot": "popover", ...props });
9
11
  }
@@ -11,8 +13,8 @@ function PopoverTrigger(allProps) {
11
13
  const props = withRender(allProps);
12
14
  return _jsx(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
13
15
  }
14
- function PopoverContent({ className, align = "center", sideOffset = 4, ...props }) {
15
- return (_jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { "data-slot": "popover-content", align: align, sideOffset: sideOffset, className: cn("z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", className), ...props }) }));
16
+ function PopoverContent({ className, style, align = "center", sideOffset = 4, ...props }) {
17
+ return (_jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { "data-slot": "popover-content", align: align, sideOffset: sideOffset, style: { ...openMotion, ...style }, className: cn("z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[state=open]:cd-overlay data-[state=closed]:cd-overlay-out", className), ...props }) }));
16
18
  }
17
19
  function PopoverAnchor({ ...props }) {
18
20
  return _jsx(PopoverPrimitive.Anchor, { "data-slot": "popover-anchor", ...props });
@@ -0,0 +1,29 @@
1
+ import * as React from "react";
2
+ import { Progress as ProgressPrimitive } from "radix-ui";
3
+ import { type RenderProp } from "../lib/render-prop.js";
4
+ /**
5
+ * A bar for work whose progress is measured: an upload, an import, an index. It moves only between values the service
6
+ * reported, and it starts at the first value it is given rather than filling from empty. With no `value` it is
7
+ * indeterminate: a pulsing bar and the `label` as text, and never a made-up percentage.
8
+ *
9
+ * @motion fill:value The filled part moves to each new measured value in the slow duration, and not on first draw.
10
+ * @motion live:indeterminate While the total is unknown, the bar pulses (the live family's pulse) and the label shimmers
11
+ * with it; it runs only while that state lasts, and stops the moment a value arrives.
12
+ */
13
+ declare function Progress(allProps: ProgressProps): React.JSX.Element;
14
+ type ProgressProps = Omit<React.ComponentProps<typeof ProgressPrimitive.Root>, "value" | "max"> & RenderProp & {
15
+ /**
16
+ * How far along the work is, from `0` to `max`, as the service reported it. Leave it out (or pass `null`) when the
17
+ * total isn't known: the bar then shows no fraction, only that work is going on, with the `label`. A bar is a claim
18
+ * about a fraction, so the app never estimates one.
19
+ */
20
+ value?: number | null | undefined;
21
+ /** The value that means finished. Defaults to 100. */
22
+ max?: number | undefined;
23
+ /**
24
+ * What is progressing, in the app's words and language ("Indexing 12 files", "Uploading report.pdf"). It names the
25
+ * bar for assistive technology, and when `value` is unknown it is printed under the bar as the word that says so.
26
+ */
27
+ label?: string | undefined;
28
+ };
29
+ export { Progress };
@@ -0,0 +1,27 @@
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Progress as ProgressPrimitive } from "radix-ui";
5
+ import {} from "../lib/render-prop.js";
6
+ import { cn } from "../lib/utils.js";
7
+ import { motion } from "../lib/motion.js";
8
+ const valueMotion = motion("progress", "value", "fill");
9
+ const indeterminateMotion = motion("progress", "indeterminate", "live");
10
+ /**
11
+ * A bar for work whose progress is measured: an upload, an import, an index. It moves only between values the service
12
+ * reported, and it starts at the first value it is given rather than filling from empty. With no `value` it is
13
+ * indeterminate: a pulsing bar and the `label` as text, and never a made-up percentage.
14
+ *
15
+ * @motion fill:value The filled part moves to each new measured value in the slow duration, and not on first draw.
16
+ * @motion live:indeterminate While the total is unknown, the bar pulses (the live family's pulse) and the label shimmers
17
+ * with it; it runs only while that state lasts, and stops the moment a value arrives.
18
+ */
19
+ function Progress(allProps) {
20
+ const { className, value, max = 100, label, render, nativeButton: _nativeButton, children, ...props } = allProps;
21
+ const known = typeof value === "number" && Number.isFinite(value) && max > 0;
22
+ const percent = known ? Math.min(100, Math.max(0, (value / max) * 100)) : 0;
23
+ const indicator = children ??
24
+ (known ? (_jsx(ProgressPrimitive.Indicator, { "data-slot": "progress-indicator", className: "h-full w-[calc(100%+var(--cd-progress))] rounded-full bg-primary cd-fill", style: { ...valueMotion, "--cd-progress": `-${100 - percent}%` } }, "value")) : (_jsx(ProgressPrimitive.Indicator, { "data-slot": "progress-indicator", style: indeterminateMotion, className: "size-full cd-live-pulse bg-[linear-gradient(90deg,var(--muted)_0%,var(--primary)_50%,var(--muted)_100%)] opacity-60" }, "unknown")));
25
+ return (_jsxs(_Fragment, { children: [_jsx(ProgressPrimitive.Root, { "data-slot": "progress", value: known ? value : null, max: max, "aria-label": label, className: cn("relative h-2 w-full overflow-hidden rounded-full bg-muted", className), ...props, ...(render ? { asChild: true } : null), children: render ? React.cloneElement(render, undefined, indicator) : indicator }), !known && label ? (_jsx("span", { "data-slot": "progress-label", "aria-hidden": true, style: indeterminateMotion, className: "shimmer-text mt-1.5 block text-xs", children: label })) : null] }));
26
+ }
27
+ export { Progress };
@@ -1,2 +1,2 @@
1
- declare function Skeleton({ className, ...props }: React.ComponentProps<"div">): import("react").JSX.Element;
1
+ declare function Skeleton({ className, style, ...props }: React.ComponentProps<"div">): import("react").JSX.Element;
2
2
  export { Skeleton };
@@ -1,6 +1,9 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { cn } from "../lib/utils.js";
3
- function Skeleton({ className, ...props }) {
4
- return (_jsx("div", { "data-slot": "skeleton", className: cn("animate-pulse rounded-md bg-accent", className), ...props }));
3
+ import { motion } from "../lib/motion.js";
4
+ /** Pulses while the content it stands in for is being fetched; still at level 0 and under calm. */
5
+ const loadingMotion = motion("skeleton", "loading", "live", { dur: 2000 });
6
+ function Skeleton({ className, style, ...props }) {
7
+ return (_jsx("div", { "data-slot": "skeleton", style: { ...loadingMotion, ...style }, className: cn("cd-live-pulse rounded-md bg-accent", className), ...props }));
5
8
  }
6
9
  export { Skeleton };
@@ -0,0 +1,28 @@
1
+ import * as React from "react";
2
+ import { Slider as SliderPrimitive } from "radix-ui";
3
+ import { type RenderProp } from "../lib/render-prop.js";
4
+ /**
5
+ * A control for a value in a range, with one thumb or, when the value has two numbers, a range. Pass `aria-label` (or
6
+ * `aria-labelledby`) to name a single thumb, or `thumbLabels` for each thumb of a range. Arrow keys step, Page keys and
7
+ * Home/End jump. The thumb starts at `min` unless the app gives `defaultValue`; leave it there for a choice the person
8
+ * hasn't made, and show the value beside the slider, since a position alone isn't a number.
9
+ *
10
+ * @motion clock:drag The thumb and the filled range follow the pointer exactly, with no easing: what moves is the
11
+ * person's hand, not an animation.
12
+ * @motion tint:focus The thumb's ring grows in on hover and keyboard focus.
13
+ */
14
+ declare function Slider(allProps: SliderProps): React.JSX.Element;
15
+ type SliderProps = React.ComponentProps<typeof SliderPrimitive.Root> & RenderProp & {
16
+ /**
17
+ * Why the slider can't be changed. With a reason it stays focusable but the pointer and arrow keys do nothing, it is
18
+ * marked `aria-disabled` and described by the reason, and the reason is printed under it. Without one the slider is
19
+ * normal. Use this rather than `disabled`, which takes the slider out of the tab order and says nothing.
20
+ */
21
+ locked?: string | undefined;
22
+ /**
23
+ * A name for each thumb, in order (a range has two: "Lowest price", "Highest price"). A thumb without one takes
24
+ * `aria-label`, then Radix's English "Minimum" and "Maximum" on a range, so give them in the app's language.
25
+ */
26
+ thumbLabels?: string[] | undefined;
27
+ };
28
+ export { Slider };
@@ -0,0 +1,41 @@
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { LockKeyhole } from "lucide-react";
5
+ import { Slider as SliderPrimitive } from "radix-ui";
6
+ import {} from "../lib/render-prop.js";
7
+ import { cn } from "../lib/utils.js";
8
+ const lockedKeys = new Set(["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End", "PageUp", "PageDown"]);
9
+ /**
10
+ * A control for a value in a range, with one thumb or, when the value has two numbers, a range. Pass `aria-label` (or
11
+ * `aria-labelledby`) to name a single thumb, or `thumbLabels` for each thumb of a range. Arrow keys step, Page keys and
12
+ * Home/End jump. The thumb starts at `min` unless the app gives `defaultValue`; leave it there for a choice the person
13
+ * hasn't made, and show the value beside the slider, since a position alone isn't a number.
14
+ *
15
+ * @motion clock:drag The thumb and the filled range follow the pointer exactly, with no easing: what moves is the
16
+ * person's hand, not an animation.
17
+ * @motion tint:focus The thumb's ring grows in on hover and keyboard focus.
18
+ */
19
+ function Slider(allProps) {
20
+ const { className, locked, thumbLabels, value, defaultValue, min = 0, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, onPointerDownCapture, onKeyDownCapture, render, nativeButton: _nativeButton, children, ...props } = allProps;
21
+ const reasonId = React.useId();
22
+ const count = Array.isArray(value) ? value.length : Array.isArray(defaultValue) ? defaultValue.length : 1;
23
+ const isLocked = Boolean(locked);
24
+ const parts = children ?? (_jsxs(_Fragment, { children: [_jsx(SliderPrimitive.Track, { "data-slot": "slider-track", className: "relative grow overflow-hidden rounded-full bg-muted data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5", children: _jsx(SliderPrimitive.Range, { "data-slot": "slider-range", className: "absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full" }) }), Array.from({ length: count }, (_, i) => (_jsx(SliderPrimitive.Thumb, { "data-slot": "slider-thumb", "data-locked": isLocked ? "" : undefined, "aria-label": thumbLabels?.[i] ?? ariaLabel, "aria-labelledby": thumbLabels?.[i] ? undefined : ariaLabelledby, "aria-disabled": isLocked ? true : undefined, "aria-describedby": isLocked ? reasonId : undefined, className: "relative after:absolute after:-inset-2 block size-4 shrink-0 rounded-full border border-primary bg-card shadow-sm ring-ring/40 cd-tint outline-none hover:ring-[3px] focus-visible:ring-[3px] focus-visible:ring-ring/80 data-[locked]:cursor-not-allowed data-[locked]:hover:ring-0" }, i)))] }));
25
+ return (_jsxs(_Fragment, { children: [_jsx(SliderPrimitive.Root, { "data-slot": "slider", "data-locked": isLocked ? "" : undefined, value: value, defaultValue: defaultValue, min: min, onPointerDownCapture: (e) => {
26
+ onPointerDownCapture?.(e);
27
+ if (!isLocked)
28
+ return;
29
+ // Keep Radix from starting a drag, but let the thumb take focus so the reason is reachable.
30
+ e.preventDefault();
31
+ e.stopPropagation();
32
+ e.target.closest('[role="slider"]')?.focus();
33
+ }, onKeyDownCapture: (e) => {
34
+ onKeyDownCapture?.(e);
35
+ if (isLocked && lockedKeys.has(e.key)) {
36
+ e.preventDefault();
37
+ e.stopPropagation();
38
+ }
39
+ }, className: cn("relative flex w-full touch-none items-center select-none data-[locked]:cursor-not-allowed data-[locked]:opacity-45 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col data-[disabled]:cursor-not-allowed data-[disabled]:opacity-45", className), ...props, ...(render ? { asChild: true } : null), children: render ? React.cloneElement(render, undefined, parts) : parts }), isLocked ? (_jsxs("p", { id: reasonId, "data-slot": "slider-reason", className: "mt-1.5 inline-flex items-center gap-1 text-xs text-muted-foreground", children: [_jsx(LockKeyhole, { "aria-hidden": true, className: "size-3" }), locked] })) : null] }));
40
+ }
41
+ export { Slider };
@@ -0,0 +1,14 @@
1
+ import * as React from "react";
2
+ import { Switch as SwitchPrimitive } from "radix-ui";
3
+ import { type RenderProp } from "../lib/render-prop.js";
4
+ /**
5
+ * A setting that is on or off. It is off until the person turns it on or the app says so with `checked` or
6
+ * `defaultChecked`. Space or Enter flips it. Pair it with a `Label`. To lock it, wrap it in `Locked` with a reason: it
7
+ * stays focusable, says why, and doesn't flip. Use a switch for a setting that takes effect at once; a choice the
8
+ * person confirms belongs in a `Checkbox` or `RadioGroup` with a button.
9
+ *
10
+ * @motion move:thumb The thumb slides to the other end when the state changes, over the move family's 200 ms. It follows the
11
+ * reading direction, so it slides the other way in right-to-left text.
12
+ */
13
+ declare function Switch(allProps: React.ComponentProps<typeof SwitchPrimitive.Root> & RenderProp): React.JSX.Element;
14
+ export { Switch };
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Switch as SwitchPrimitive } from "radix-ui";
5
+ import {} from "../lib/render-prop.js";
6
+ import { cn } from "../lib/utils.js";
7
+ import { motion } from "../lib/motion.js";
8
+ const thumbMotion = motion("switch", "thumb", "move");
9
+ /**
10
+ * A setting that is on or off. It is off until the person turns it on or the app says so with `checked` or
11
+ * `defaultChecked`. Space or Enter flips it. Pair it with a `Label`. To lock it, wrap it in `Locked` with a reason: it
12
+ * stays focusable, says why, and doesn't flip. Use a switch for a setting that takes effect at once; a choice the
13
+ * person confirms belongs in a `Checkbox` or `RadioGroup` with a button.
14
+ *
15
+ * @motion move:thumb The thumb slides to the other end when the state changes, over the move family's 200 ms. It follows the
16
+ * reading direction, so it slides the other way in right-to-left text.
17
+ */
18
+ function Switch(allProps) {
19
+ const { className, render, nativeButton: _nativeButton, children, ...props } = allProps;
20
+ const thumb = children ?? (_jsx(SwitchPrimitive.Thumb, { "data-slot": "switch-thumb", style: thumbMotion, className: "pointer-events-none block size-4 rounded-full bg-card shadow-sm ring-0 cd-move data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=checked]:bg-primary-foreground data-[state=unchecked]:translate-x-0 rtl:data-[state=checked]:-translate-x-[calc(100%-2px)]" }));
21
+ return (_jsx(SwitchPrimitive.Root, { "data-slot": "switch", className: cn("peer relative after:absolute after:-inset-1 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent bg-input shadow-xs cd-tint outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/80 disabled:cursor-not-allowed disabled:opacity-45 data-[locked]:cursor-not-allowed data-[locked]:opacity-45 data-[state=checked]:bg-primary aria-invalid:ring-destructive/25", className), ...props, ...(render ? { asChild: true } : null), children: render ? React.cloneElement(render, undefined, thumb) : thumb }));
22
+ }
23
+ export { Switch };
@@ -5,5 +5,5 @@ declare function TooltipProvider({ delayDuration, ...props }: React.ComponentPro
5
5
  /** Works with or without a TooltipProvider above; an app-level one sets the delay for all. */
6
6
  declare function Tooltip({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Root>): React.JSX.Element;
7
7
  declare function TooltipTrigger(allProps: React.ComponentProps<typeof TooltipPrimitive.Trigger> & RenderProp): React.JSX.Element;
8
- declare function TooltipContent({ className, sideOffset, children, ...props }: React.ComponentProps<typeof TooltipPrimitive.Content>): React.JSX.Element;
8
+ declare function TooltipContent({ className, style, sideOffset, children, ...props }: React.ComponentProps<typeof TooltipPrimitive.Content>): React.JSX.Element;
9
9
  export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
@@ -4,6 +4,8 @@ import * as React from "react";
4
4
  import { cn } from "../lib/utils.js";
5
5
  import { Tooltip as TooltipPrimitive } from "radix-ui";
6
6
  import { withRender } from "../lib/render-prop.js";
7
+ import { motion } from "../lib/motion.js";
8
+ const openMotion = motion("tooltip", "open", "overlay");
7
9
  // Whether a TooltipProvider is above, so a lone Tooltip can supply its own.
8
10
  const HasProvider = React.createContext(false);
9
11
  function TooltipProvider({ delayDuration = 0, ...props }) {
@@ -18,7 +20,7 @@ function TooltipTrigger(allProps) {
18
20
  const props = withRender(allProps);
19
21
  return _jsx(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
20
22
  }
21
- function TooltipContent({ className, sideOffset = 0, children, ...props }) {
22
- return (_jsx(TooltipPrimitive.Portal, { children: _jsxs(TooltipPrimitive.Content, { "data-slot": "tooltip-content", sideOffset: sideOffset, className: cn("z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in rounded-md bg-foreground px-3 py-1.5 text-xs text-balance text-background fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95", className), ...props, children: [children, _jsx(TooltipPrimitive.Arrow, { className: "z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" })] }) }));
23
+ function TooltipContent({ className, style, sideOffset = 0, children, ...props }) {
24
+ return (_jsx(TooltipPrimitive.Portal, { children: _jsxs(TooltipPrimitive.Content, { "data-slot": "tooltip-content", sideOffset: sideOffset, style: { ...openMotion, ...style }, className: cn("z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md bg-foreground px-3 py-1.5 text-xs text-balance text-background cd-overlay data-[state=closed]:cd-overlay-out", className), ...props, children: [children, _jsx(TooltipPrimitive.Arrow, { className: "z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" })] }) }));
23
25
  }
24
26
  export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@candor-ui/react",
3
- "version": "2.2.0",
3
+ "version": "2.4.0",
4
4
  "description": "Candor UI's free tier as an npm package: React components for agents that do real work, on shadcn/ui and Tailwind 4.",
5
5
  "license": "MIT",
6
6
  "author": "Methodic LLC",
@@ -50,8 +50,7 @@
50
50
  "clsx": "^2.1.1",
51
51
  "lucide-react": "^1.67.0",
52
52
  "radix-ui": "^1.8.1",
53
- "tailwind-merge": "^3.7.0",
54
- "tw-animate-css": "^1.4.0"
53
+ "tailwind-merge": "^3.7.0"
55
54
  },
56
55
  "peerDependencies": {
57
56
  "@ag-ui/client": "^1.0.3",